Index: include/clang/Basic/TargetInfo.h =================================================================== --- include/clang/Basic/TargetInfo.h +++ include/clang/Basic/TargetInfo.h @@ -74,6 +74,7 @@ unsigned char DefaultAlignForAttributeAligned; unsigned char MinGlobalAlign; unsigned char MaxAtomicPromoteWidth, MaxAtomicInlineWidth; + unsigned char MinAtomicLockFreeWidth, MaxAtomicLockFreeWidth; unsigned short MaxVectorAlign; unsigned short MaxTLSAlign; unsigned short SimdDefaultAlign; @@ -429,10 +430,16 @@ /// \brief Return the maximum width lock-free atomic operation which will /// ever be supported for the given target unsigned getMaxAtomicPromoteWidth() const { return MaxAtomicPromoteWidth; } - /// \brief Return the maximum width lock-free atomic operation which can be - /// inlined given the supported features of the given target. + /// \brief Return the maximum width atomic operation which can be inlined + /// given the supported features of the given target. unsigned getMaxAtomicInlineWidth() const { return MaxAtomicInlineWidth; } - /// \brief Returns true if the given target supports lock-free atomic + /// \brief Return the minimum width lock-free atomic operation which can be + /// supported given the supported features of the given target. + unsigned getMinAtomicLockFreeWidth() const { return MinAtomicLockFreeWidth; } + /// \brief Return the maximum width lock-free atomic operation which can be + /// supported given the supported features of the given target. + unsigned getMaxAtomicLockFreeWidth() const { return MaxAtomicLockFreeWidth; } + /// \brief Returns true if the given target supports inline atomic /// operations at the specified width and alignment. virtual bool hasBuiltinAtomic(uint64_t AtomicSizeInBits, uint64_t AlignmentInBits) const { Index: lib/AST/ExprConstant.cpp =================================================================== --- lib/AST/ExprConstant.cpp +++ lib/AST/ExprConstant.cpp @@ -7828,7 +7828,7 @@ 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 + // of two less than the maximum lock-free 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, @@ -7839,23 +7839,26 @@ // Check power-of-two. CharUnits Size = CharUnits::fromQuantity(SizeVal.getZExtValue()); if (Size.isPowerOfTwo()) { - // Check against inlining width. - unsigned InlineWidthBits = - Info.Ctx.getTargetInfo().getMaxAtomicInlineWidth(); - if (Size <= Info.Ctx.toCharUnitsFromBits(InlineWidthBits)) { + // Check against lock-free width. + unsigned MinLockFreeWidthBits = + Info.Ctx.getTargetInfo().getMinAtomicLockFreeWidth(); + unsigned MaxLockFreeWidthBits = + Info.Ctx.getTargetInfo().getMaxAtomicLockFreeWidth(); + if (Size >= Info.Ctx.toCharUnitsFromBits(MinLockFreeWidthBits) && + Size <= Info.Ctx.toCharUnitsFromBits(MaxLockFreeWidthBits)) { if (BuiltinOp == Builtin::BI__c11_atomic_is_lock_free || Size == CharUnits::One() || E->getArg(1)->isNullPointerConstant(Info.Ctx, Expr::NPC_NeverValueDependent)) - // OK, we will inline appropriately-aligned operations of this size, - // and _Atomic(T) is appropriately-aligned. + // OK, appropriately-aligned operations of this size will be + // lock-free, and _Atomic(T) is appropriately-aligned. return Success(1, E); QualType PointeeType = E->getArg(1)->IgnoreImpCasts()->getType()-> castAs()->getPointeeType(); if (!PointeeType->isIncompleteType() && Info.Ctx.getTypeAlignInChars(PointeeType) >= Size) { - // OK, we will inline operations on this object. + // OK, operations on this object will be lock-free. return Success(1, E); } } Index: lib/Basic/TargetInfo.cpp =================================================================== --- lib/Basic/TargetInfo.cpp +++ lib/Basic/TargetInfo.cpp @@ -58,6 +58,7 @@ LargeArrayMinWidth = 0; LargeArrayAlign = 0; MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 0; + MinAtomicLockFreeWidth = MaxAtomicLockFreeWidth = 0; MaxVectorAlign = 0; MaxTLSAlign = 0; SimdDefaultAlign = 0; Index: lib/Basic/Targets.cpp =================================================================== --- lib/Basic/Targets.cpp +++ lib/Basic/Targets.cpp @@ -1696,7 +1696,7 @@ } // PPC32 supports atomics up to 4 bytes. - MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 32; + MaxAtomicPromoteWidth = MaxAtomicInlineWidth = MaxAtomicLockFreeWidth = 32; } BuiltinVaListKind getBuiltinVaListKind() const override { @@ -1737,7 +1737,7 @@ } // PPC64 supports atomics up to 8 bytes. - MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64; + MaxAtomicPromoteWidth = MaxAtomicInlineWidth = MaxAtomicLockFreeWidth = 64; } BuiltinVaListKind getBuiltinVaListKind() const override { return TargetInfo::CharPtrBuiltinVaList; @@ -1885,6 +1885,8 @@ // other things) they affect which standard library classes are defined, and // we need all classes to be defined on both the host and device. MaxAtomicInlineWidth = HostTarget->getMaxAtomicInlineWidth(); + MinAtomicLockFreeWidth = HostTarget->getMinAtomicLockFreeWidth(); + MaxAtomicLockFreeWidth = HostTarget->getMaxAtomicLockFreeWidth(); // Properties intentionally not copied from host: // - LargeArrayMinWidth, LargeArrayAlign: Not visible across the @@ -4371,7 +4373,7 @@ // x86-32 has atomics up to 8 bytes // FIXME: Check that we actually have cmpxchg8b before setting // MaxAtomicInlineWidth. (cmpxchg8b is an i586 instruction.) - MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64; + MaxAtomicPromoteWidth = MaxAtomicInlineWidth = MaxAtomicLockFreeWidth = 64; } BuiltinVaListKind getBuiltinVaListKind() const override { return TargetInfo::CharPtrBuiltinVaList; @@ -4711,6 +4713,7 @@ // x86-64 has atomics up to 16 bytes. MaxAtomicPromoteWidth = 128; MaxAtomicInlineWidth = 128; + MaxAtomicLockFreeWidth = 128; } BuiltinVaListKind getBuiltinVaListKind() const override { return TargetInfo::X86_64ABIBuiltinVaList; @@ -5135,12 +5138,12 @@ if (ArchProfile == llvm::ARM::PK_M) { MaxAtomicPromoteWidth = 32; if (ShouldUseInlineAtomic) - MaxAtomicInlineWidth = 32; + MaxAtomicInlineWidth = MaxAtomicLockFreeWidth = 32; } else { MaxAtomicPromoteWidth = 64; if (ShouldUseInlineAtomic) - MaxAtomicInlineWidth = 64; + MaxAtomicInlineWidth = MaxAtomicLockFreeWidth = 64; } } @@ -6008,7 +6011,7 @@ // iOS always has 64-bit atomic instructions. // FIXME: This should be based off of the target features in // ARMleTargetInfo. - MaxAtomicInlineWidth = 64; + MaxAtomicInlineWidth = MaxAtomicLockFreeWidth = 64; if (Triple.isWatchABI()) { // Darwin on iOS uses a variant of the ARM C++ ABI. @@ -6066,6 +6069,7 @@ MaxVectorAlign = 128; MaxAtomicInlineWidth = 128; MaxAtomicPromoteWidth = 128; + MaxAtomicLockFreeWidth = 128; LongDoubleWidth = LongDoubleAlign = SuitableAlign = 128; LongDoubleFormat = &llvm::APFloat::IEEEquad(); @@ -7031,6 +7035,7 @@ // on up to 64 bits. MaxAtomicPromoteWidth = 64; MaxAtomicInlineWidth = 32; + MaxAtomicLockFreeWidth = 32; } void getTargetDefines(const LangOptions &Opts, @@ -7111,7 +7116,7 @@ LongDoubleWidth = 128; LongDoubleAlign = 128; LongDoubleFormat = &llvm::APFloat::IEEEquad(); - MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64; + MaxAtomicPromoteWidth = MaxAtomicInlineWidth = MaxAtomicLockFreeWidth = 64; } void getTargetDefines(const LangOptions &Opts, @@ -7157,7 +7162,7 @@ DefaultAlignForAttributeAligned = 64; MinGlobalAlign = 16; resetDataLayout("E-m:e-i1:8:16-i8:8:16-i64:64-f128:64-a:8:16-n32:64"); - MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64; + MaxAtomicPromoteWidth = MaxAtomicInlineWidth = MaxAtomicLockFreeWidth = 64; } void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { @@ -7518,6 +7523,7 @@ } MaxAtomicPromoteWidth = 64; MaxAtomicInlineWidth = 64; + MaxAtomicLockFreeWidth = 64; TLSSupported = false; } void getTargetDefines(const LangOptions &Opts, @@ -7661,7 +7667,7 @@ LongDoubleFormat = &llvm::APFloat::IEEEdouble(); LongDoubleWidth = LongDoubleAlign = 64; LongWidth = LongAlign = 32; - MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 32; + MaxAtomicPromoteWidth = MaxAtomicInlineWidth = MaxAtomicLockFreeWidth = 32; PointerWidth = PointerAlign = 32; PtrDiffType = SignedInt; SizeType = UnsignedInt; @@ -7675,7 +7681,7 @@ LongDoubleWidth = LongDoubleAlign = 64; LongDoubleFormat = &llvm::APFloat::IEEEdouble(); } - MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64; + MaxAtomicPromoteWidth = MaxAtomicInlineWidth = MaxAtomicLockFreeWidth = 64; SuitableAlign = 128; } @@ -8181,7 +8187,7 @@ : TargetInfo(Triple) { NoAsmVariants = true; LongWidth = LongAlign = PointerWidth = PointerAlign = 64; - MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64; + MaxAtomicPromoteWidth = MaxAtomicInlineWidth = MaxAtomicLockFreeWidth = 64; resetDataLayout("e-m:e-v128:32-v16:16-v32:32-v96:32-n8:16:32:64-S128"); } @@ -8333,7 +8339,12 @@ explicit WebAssembly32TargetInfo(const llvm::Triple &T, const TargetOptions &Opts) : WebAssemblyTargetInfo(T, Opts) { - MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 32; + MaxAtomicPromoteWidth = MaxAtomicInlineWidth = MaxAtomicLockFreeWidth = 32; + + // WebAssembly only guarantees that 32-bit atomics are lock free, and not + // other sizes (including smaller sizes). + MinAtomicLockFreeWidth = 32; + resetDataLayout("e-m:e-p:32:32-i64:64-n32:64-S128"); } @@ -8352,7 +8363,12 @@ : WebAssemblyTargetInfo(T, Opts) { LongAlign = LongWidth = 64; PointerAlign = PointerWidth = 64; - MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64; + MaxAtomicPromoteWidth = MaxAtomicInlineWidth = MaxAtomicLockFreeWidth = 64; + + // WebAssembly only guarantees that 32-bit atomics are lock free, and not + // other sizes (including smaller sizes). + MinAtomicLockFreeWidth = 32; + SizeType = UnsignedLong; PtrDiffType = SignedLong; IntPtrType = SignedLong; Index: lib/Frontend/InitPreprocessor.cpp =================================================================== --- lib/Frontend/InitPreprocessor.cpp +++ lib/Frontend/InitPreprocessor.cpp @@ -287,11 +287,12 @@ /// Get the value the ATOMIC_*_LOCK_FREE macro should have for a type with /// the specified properties. static const char *getLockFreeValue(unsigned TypeWidth, unsigned TypeAlign, - unsigned InlineWidth) { - // Fully-aligned, power-of-2 sizes no larger than the inline + unsigned MinLockFreeWidth, + unsigned MaxLockFreeWidth) { + // Fully-aligned, power-of-2 sizes no larger than the lock-free // width will be inlined as lock-free operations. if (TypeWidth == TypeAlign && (TypeWidth & (TypeWidth - 1)) == 0 && - TypeWidth <= InlineWidth) + TypeWidth >= MinLockFreeWidth && TypeWidth <= MaxLockFreeWidth) return "2"; // "always lock free" // We cannot be certain what operations the lib calls might be // able to implement as lock-free on future processors. @@ -884,12 +885,14 @@ Builder.defineMacro("__GCC_ATOMIC_TEST_AND_SET_TRUEVAL", "1"); // Used by libc++ and libstdc++ to implement ATOMIC__LOCK_FREE. - unsigned InlineWidthBits = TI.getMaxAtomicInlineWidth(); + unsigned MaxLockFreeWidthBits = TI.getMaxAtomicLockFreeWidth(); + unsigned MinLockFreeWidthBits = TI.getMinAtomicLockFreeWidth(); #define DEFINE_LOCK_FREE_MACRO(TYPE, Type) \ Builder.defineMacro("__GCC_ATOMIC_" #TYPE "_LOCK_FREE", \ getLockFreeValue(TI.get##Type##Width(), \ TI.get##Type##Align(), \ - InlineWidthBits)); + MinLockFreeWidthBits, \ + MaxLockFreeWidthBits)); DEFINE_LOCK_FREE_MACRO(BOOL, Bool); DEFINE_LOCK_FREE_MACRO(CHAR, Char); DEFINE_LOCK_FREE_MACRO(CHAR16_T, Char16); @@ -902,7 +905,8 @@ Builder.defineMacro("__GCC_ATOMIC_POINTER_LOCK_FREE", getLockFreeValue(TI.getPointerWidth(0), TI.getPointerAlign(0), - InlineWidthBits)); + MinLockFreeWidthBits, + MaxLockFreeWidthBits)); #undef DEFINE_LOCK_FREE_MACRO } Index: test/Preprocessor/init.c =================================================================== --- test/Preprocessor/init.c +++ test/Preprocessor/init.c @@ -8877,15 +8877,15 @@ // WEBASSEMBLY32-NEXT:#define __FLT_MIN_EXP__ (-125) // WEBASSEMBLY32-NEXT:#define __FLT_MIN__ 1.17549435e-38F // WEBASSEMBLY32-NEXT:#define __FLT_RADIX__ 2 -// WEBASSEMBLY32-NEXT:#define __GCC_ATOMIC_BOOL_LOCK_FREE 2 -// WEBASSEMBLY32-NEXT:#define __GCC_ATOMIC_CHAR16_T_LOCK_FREE 2 +// WEBASSEMBLY32-NEXT:#define __GCC_ATOMIC_BOOL_LOCK_FREE 1 +// WEBASSEMBLY32-NEXT:#define __GCC_ATOMIC_CHAR16_T_LOCK_FREE 1 // WEBASSEMBLY32-NEXT:#define __GCC_ATOMIC_CHAR32_T_LOCK_FREE 2 -// WEBASSEMBLY32-NEXT:#define __GCC_ATOMIC_CHAR_LOCK_FREE 2 +// WEBASSEMBLY32-NEXT:#define __GCC_ATOMIC_CHAR_LOCK_FREE 1 // WEBASSEMBLY32-NEXT:#define __GCC_ATOMIC_INT_LOCK_FREE 2 // WEBASSEMBLY32-NEXT:#define __GCC_ATOMIC_LLONG_LOCK_FREE 1 // WEBASSEMBLY32-NEXT:#define __GCC_ATOMIC_LONG_LOCK_FREE 2 // WEBASSEMBLY32-NEXT:#define __GCC_ATOMIC_POINTER_LOCK_FREE 2 -// WEBASSEMBLY32-NEXT:#define __GCC_ATOMIC_SHORT_LOCK_FREE 2 +// WEBASSEMBLY32-NEXT:#define __GCC_ATOMIC_SHORT_LOCK_FREE 1 // WEBASSEMBLY32-NEXT:#define __GCC_ATOMIC_TEST_AND_SET_TRUEVAL 1 // WEBASSEMBLY32-NEXT:#define __GCC_ATOMIC_WCHAR_T_LOCK_FREE 2 // WEBASSEMBLY32-NEXT:#define __GNUC_MINOR__ {{.*}} @@ -9193,15 +9193,15 @@ // WEBASSEMBLY64-NEXT:#define __FLT_MIN_EXP__ (-125) // WEBASSEMBLY64-NEXT:#define __FLT_MIN__ 1.17549435e-38F // WEBASSEMBLY64-NEXT:#define __FLT_RADIX__ 2 -// WEBASSEMBLY64-NEXT:#define __GCC_ATOMIC_BOOL_LOCK_FREE 2 -// WEBASSEMBLY64-NEXT:#define __GCC_ATOMIC_CHAR16_T_LOCK_FREE 2 +// WEBASSEMBLY64-NEXT:#define __GCC_ATOMIC_BOOL_LOCK_FREE 1 +// WEBASSEMBLY64-NEXT:#define __GCC_ATOMIC_CHAR16_T_LOCK_FREE 1 // WEBASSEMBLY64-NEXT:#define __GCC_ATOMIC_CHAR32_T_LOCK_FREE 2 -// WEBASSEMBLY64-NEXT:#define __GCC_ATOMIC_CHAR_LOCK_FREE 2 +// WEBASSEMBLY64-NEXT:#define __GCC_ATOMIC_CHAR_LOCK_FREE 1 // WEBASSEMBLY64-NEXT:#define __GCC_ATOMIC_INT_LOCK_FREE 2 // WEBASSEMBLY64-NEXT:#define __GCC_ATOMIC_LLONG_LOCK_FREE 2 // WEBASSEMBLY64-NEXT:#define __GCC_ATOMIC_LONG_LOCK_FREE 2 // WEBASSEMBLY64-NEXT:#define __GCC_ATOMIC_POINTER_LOCK_FREE 2 -// WEBASSEMBLY64-NEXT:#define __GCC_ATOMIC_SHORT_LOCK_FREE 2 +// WEBASSEMBLY64-NEXT:#define __GCC_ATOMIC_SHORT_LOCK_FREE 1 // WEBASSEMBLY64-NEXT:#define __GCC_ATOMIC_TEST_AND_SET_TRUEVAL 1 // WEBASSEMBLY64-NEXT:#define __GCC_ATOMIC_WCHAR_T_LOCK_FREE 2 // WEBASSEMBLY64-NEXT:#define __GNUC_MINOR__ {{.*}}