  Over the years, several memory models have been proposed to capture the
subtle concurrency semantics of C/C++.One of the most fundamental problems
associated with a memory model M is consistency checking: given an execution X,
is X consistent with M? This problem lies at the heart of numerous
applications, including specification testing and litmus tests, stateless model
checking, and dynamic analyses. As such, it has been explored extensively and
its complexity is well-understood for traditional models like SC and TSO.
However, less is known for the numerous model variants of C/C++, for which the
problem becomes challenging due to the intricacies of their concurrency
primitives. In this work we study the problem of consistency checking for
popular variants of the C11 memory model, in particular, the RC20 model, its
release-acquire (RA) fragment, the strong and weak variants of RA (SRA and
WRA), as well as the Relaxed fragment of RC20. Motivated by applications in
testing and model checking, we focus on reads-from consistency checking. The
input is an execution X specifying a set of events, their program order and
their reads-from relation, and the task is to decide the existence of a
modification order on the writes of X that makes X consistent in a memory
model. We draw a rich complexity landscape for this problem; our results
include (i)~nearly-linear-time algorithms for certain variants, which improve
over prior results, (ii)~fine-grained optimality results, as well as
(iii)~matching upper and lower bounds (NP-hardness) for other variants. To our
knowledge, this is the first work to characterize the complexity of consistency
checking for C11 memory models. We have implemented our algorithms inside the
TruSt model checker and the C11Tester testing tool. Experiments on standard
benchmarks show that our new algorithms improve consistency checking, often by
a significant margin.
