diff --git a/clang/include/clang/Basic/Builtins.def b/clang/include/clang/Basic/Builtins.def index e5690c123393..63de4e5a75d2 100644 --- a/clang/include/clang/Basic/Builtins.def +++ b/clang/include/clang/Basic/Builtins.def @@ -598,6 +598,7 @@ BUILTIN(__atomic_fetch_or, "v.", "t") BUILTIN(__atomic_fetch_xor, "v.", "t") BUILTIN(__atomic_thread_fence, "vi", "n") BUILTIN(__atomic_signal_fence, "vi", "n") +BUILTIN(__atomic_is_lock_free, "iz", "n") // Non-overloaded atomic builtins. BUILTIN(__sync_synchronize, "v.", "n") diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 3c21dc4472a0..c3cc78e053cc 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -1344,6 +1344,50 @@ bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) { } return Error(E->getLocStart(), diag::note_invalid_subexpr_in_ice, E); + + case Builtin::BI__atomic_is_lock_free: { + APSInt SizeVal; + if (!EvaluateInteger(E->getArg(0), SizeVal, Info)) + return false; + + // For __atomic_is_lock_free(sizeof(_Atomic(T))), if the size is a power + // of two less than the maximum inline atomic width, we know it is + // lock-free. If the size isn't a power of two, or greater than the + // maximum alignment where we promote atomics, we know it is not lock-free + // (at least not in the sense of atomic_is_lock_free). Otherwise, + // the answer can only be determined at runtime; for example, 16-byte + // atomics have lock-free implementations on some, but not all, + // x86-64 processors. + + // Check power-of-two. + CharUnits Size = CharUnits::fromQuantity(SizeVal.getZExtValue()); + if (!Size.isPowerOfTwo()) +#if 0 + // FIXME: Suppress this folding until the ABI for the promotion width + // settles. + return Success(0, E); +#else + return Error(E->getLocStart(), diag::note_invalid_subexpr_in_ice, E); +#endif + +#if 0 + // Check against promotion width. + // FIXME: Suppress this folding until the ABI for the promotion width + // settles. + unsigned PromoteWidthBits = + Info.Ctx.getTargetInfo().getMaxAtomicPromoteWidth(); + if (Size > Info.Ctx.toCharUnitsFromBits(PromoteWidthBits)) + return Success(0, E); +#endif + + // Check against inlining width. + unsigned InlineWidthBits = + Info.Ctx.getTargetInfo().getMaxAtomicInlineWidth(); + if (Size <= Info.Ctx.toCharUnitsFromBits(InlineWidthBits)) + return Success(1, E); + + return Error(E->getLocStart(), diag::note_invalid_subexpr_in_ice, E); + } } } diff --git a/clang/test/CodeGen/atomic-ops.c b/clang/test/CodeGen/atomic-ops.c index e2904cf10e81..0ae70b1b3701 100644 --- a/clang/test/CodeGen/atomic-ops.c +++ b/clang/test/CodeGen/atomic-ops.c @@ -75,3 +75,9 @@ X fs(_Atomic(X) *c) { // CHECK: atomicrmw xchg i32* return __atomic_exchange(c, (X){2}, memory_order_seq_cst); } + +int lock_free() { + // CHECK: @lock_free + // CHECK: ret i32 1 + return __atomic_is_lock_free(sizeof(_Atomic(int))); +} \ No newline at end of file