]> granicus.if.org Git - clang/commitdiff
Misc fixes for atomics. Biggest fix is doing alignment correctly for _Atomic types.
authorEli Friedman <eli.friedman@gmail.com>
Fri, 14 Oct 2011 20:59:01 +0000 (20:59 +0000)
committerEli Friedman <eli.friedman@gmail.com>
Fri, 14 Oct 2011 20:59:01 +0000 (20:59 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@142002 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/Builtins.def
include/clang/Basic/TargetInfo.h
lib/AST/ASTContext.cpp
lib/AST/StmtProfile.cpp
lib/Basic/TargetInfo.cpp
lib/Basic/Targets.cpp
lib/CodeGen/CGExpr.cpp
test/CodeGen/atomic-ops.c

index 4f89f81341b6d9e1626ecff29abb6f35366ad851..f73065272b45854fb386869d4dbb3323f6fbb627 100644 (file)
@@ -596,8 +596,8 @@ BUILTIN(__atomic_fetch_sub, "v.", "t")
 BUILTIN(__atomic_fetch_and, "v.", "t")
 BUILTIN(__atomic_fetch_or, "v.", "t")
 BUILTIN(__atomic_fetch_xor, "v.", "t")
-BUILTIN(__atomic_thread_fence, "vi", "t")
-BUILTIN(__atomic_signal_fence, "vi", "t")
+BUILTIN(__atomic_thread_fence, "vi", "n")
+BUILTIN(__atomic_signal_fence, "vi", "n")
 
 // Non-overloaded atomic builtins.
 BUILTIN(__sync_synchronize, "v.", "n")
index e5a732a4cceb72cf3f8373d93bb5ec1233617d70..0a7d2f1ea081d9f839262fd72aae18bc02e72acb 100644 (file)
@@ -75,6 +75,7 @@ protected:
   unsigned char LargeArrayMinWidth, LargeArrayAlign;
   unsigned char LongWidth, LongAlign;
   unsigned char LongLongWidth, LongLongAlign;
+  unsigned char MaxAtomicPromoteWidth, MaxAtomicInlineWidth;
   const char *DescriptionString;
   const char *UserLabelPrefix;
   const char *MCountName;
@@ -246,6 +247,14 @@ public:
   unsigned getLargeArrayMinWidth() const { return LargeArrayMinWidth; }
   unsigned getLargeArrayAlign() const { return LargeArrayAlign; }
 
+  /// getMaxAtomicPromoteWidth - Return the maximum width lock-free atomic
+  /// operation which will ever be supported for the given target
+  unsigned getMaxAtomicPromoteWidth() const { return MaxAtomicPromoteWidth; }
+  /// getMaxAtomicInlineWidth - Return the maximum width lock-free atomic
+  /// operation which can be inlined given the supported features of the
+  /// given target.
+  unsigned getMaxAtomicInlineWidth() const { return MaxAtomicInlineWidth; }
+
   /// getIntMaxTWidth - Return the size of intmax_t and uintmax_t for this
   /// target, in bits.
   unsigned getIntMaxTWidth() const {
index b625655e45f94514aba8b365a388b10c3e7344c8..ae96dfd14816fd4a4a0138f05516f801c13fdf1d 100644 (file)
@@ -1064,13 +1064,25 @@ ASTContext::getTypeInfo(const Type *T) const {
   }
 
   case Type::Atomic: {
-    // FIXME: The alignment needs to be "fixed".
-    return getTypeInfo(cast<AtomicType>(T)->getValueType());
+    std::pair<uint64_t, unsigned> Info
+      = getTypeInfo(cast<AtomicType>(T)->getValueType());
+    Width = Info.first;
+    Align = Info.second;
+    if (Width != 0 && Width <= Target->getMaxAtomicPromoteWidth() &&
+        llvm::isPowerOf2_64(Width)) {
+      // We can potentially perform lock-free atomic operations for this
+      // type; promote the alignment appropriately.
+      // FIXME: We could potentially promote the width here as well...
+      // is that worthwhile?  (Non-struct atomic types generally have
+      // power-of-two size anyway, but structs might not.  Requires a bit
+      // of implementation work to make sure we zero out the extra bits.)
+      Align = static_cast<unsigned>(Width);
+    }
   }
 
   }
 
-  assert(Align && (Align & (Align-1)) == 0 && "Alignment must be power of 2");
+  assert(llvm::isPowerOf2_32(Align) && "Alignment must be power of 2");
   return std::make_pair(Width, Align);
 }
 
index df49e843f9692594b914232a10769410033bc0cb..214378a974a6b4b49fab7586f73596de093a854b 100644 (file)
@@ -470,6 +470,7 @@ void StmtProfiler::VisitGenericSelectionExpr(const GenericSelectionExpr *S) {
 
 void StmtProfiler::VisitAtomicExpr(const AtomicExpr *S) {
   VisitExpr(S);
+  ID.AddInteger(S->getOp());
 }
 
 static Stmt::StmtClass DecodeOperatorCall(const CXXOperatorCallExpr *S,
index d5dcf066754bb72bbe178fd62a12783b92cd39ad..a9285e6e2dbd641376ba11a15f92ce99f5751db3 100644 (file)
@@ -42,6 +42,7 @@ TargetInfo::TargetInfo(const std::string &T) : Triple(T) {
   LongDoubleAlign = 64;
   LargeArrayMinWidth = 0;
   LargeArrayAlign = 0;
+  MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 0;
   SizeType = UnsignedLong;
   PtrDiffType = SignedLong;
   IntMaxType = SignedLongLong;
index 648ed73f0fff8588b75929ae6cb3291503cfd03d..889518bb2a993b63141d40ccd3de0c07485fe8f6 100644 (file)
@@ -1984,6 +1984,11 @@ public:
     RealTypeUsesObjCFPRet = ((1 << TargetInfo::Float) |
                              (1 << TargetInfo::Double) |
                              (1 << TargetInfo::LongDouble));
+
+    // 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;
   }
   virtual const char *getVAListDeclaration() const {
     return "typedef char* __builtin_va_list;";
@@ -2219,6 +2224,12 @@ public:
 
     // Use fpret only for long double.
     RealTypeUsesObjCFPRet = (1 << TargetInfo::LongDouble);
+
+    // x86-64 has atomics up to 16 bytes.
+    // FIXME: Once the backend is fixed, increase MaxAtomicInlineWidth to 128
+    // on CPUs with cmpxchg16b
+    MaxAtomicPromoteWidth = 128;
+    MaxAtomicInlineWidth = 64;
   }
   virtual const char *getVAListDeclaration() const {
     return "typedef struct __va_list_tag {"
@@ -2391,6 +2402,10 @@ public:
 
     // ARM targets default to using the ARM C++ ABI.
     CXXABI = CXXABI_ARM;
+
+    // ARM has atomics up to 8 bytes
+    // FIXME: Set MaxAtomicInlineWidth if we have the feature v6e
+    MaxAtomicPromoteWidth = 64;
   }
   virtual const char *getABI() const { return ABI.c_str(); }
   virtual bool setABI(const std::string &Name) {
@@ -2708,6 +2723,9 @@ public:
   DarwinARMTargetInfo(const std::string& triple)
     : DarwinTargetInfo<ARMTargetInfo>(triple) {
     HasAlignMac68kSupport = true;
+    // iOS always has 64-bit atomic instructions.
+    // FIXME: This should be based off of the target features in ARMTargetInfo.
+    MaxAtomicInlineWidth = 64;
   }
 };
 } // end anonymous namespace.
index ad27506d56eafb067792750f5c741155f2904213..bd4e553991b33ed0ffff5f09a34fb90f5beff6f1 100644 (file)
@@ -2567,9 +2567,9 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E, llvm::Value *Dest) {
   uint64_t Size = sizeChars.getQuantity();
   CharUnits alignChars = getContext().getTypeAlignInChars(AtomicTy);
   unsigned Align = alignChars.getQuantity();
-  // FIXME: Bound on Size should not be hardcoded.
-  bool UseLibcall = (sizeChars != alignChars || !llvm::isPowerOf2_64(Size) ||
-                     Size > 8);
+  unsigned MaxInlineWidth =
+      getContext().getTargetInfo().getMaxAtomicInlineWidth();
+  bool UseLibcall = (Size != Align || Size > MaxInlineWidth);
 
   llvm::Value *Ptr, *Order, *OrderFail = 0, *Val1 = 0, *Val2 = 0;
   Ptr = EmitScalarExpr(E->getPtr());
@@ -2585,11 +2585,9 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E, llvm::Value *Dest) {
     // is not the same as adding 1 to a uintptr_t.
     QualType Val1Ty = E->getVal1()->getType();
     llvm::Value *Val1Scalar = EmitScalarExpr(E->getVal1());
-    uint64_t PointeeIncAmt =
-        getContext().getTypeSizeInChars(MemTy->getPointeeType()).getQuantity();
-    llvm::Value *PointeeIncAmtVal =
-        llvm::ConstantInt::get(Val1Scalar->getType(), PointeeIncAmt);
-    Val1Scalar = Builder.CreateMul(Val1Scalar, PointeeIncAmtVal);
+    CharUnits PointeeIncAmt =
+        getContext().getTypeSizeInChars(MemTy->getPointeeType());
+    Val1Scalar = Builder.CreateMul(Val1Scalar, CGM.getSize(PointeeIncAmt));
     Val1 = CreateMemTemp(Val1Ty, ".atomictmp");
     EmitStoreOfScalar(Val1Scalar, MakeAddrLValue(Val1, Val1Ty));
   } else if (E->getOp() != AtomicExpr::Load) {
index cb3a868b8089174682d5ede33657e8426bb0cbb8..e2904cf10e8113cb611a664295b65ac98ff08f76 100644 (file)
@@ -63,9 +63,7 @@ int* fp2(_Atomic(int*) *p) {
   return __atomic_fetch_add(p, 1, memory_order_relaxed);
 }
 
-// FIXME: Alignment specification shouldn't be necessary
-typedef _Complex float ComplexAligned __attribute((aligned(8)));
-_Complex float fc(_Atomic(ComplexAligned) *c) {
+_Complex float fc(_Atomic(_Complex float) *c) {
   // CHECK: @fc
   // CHECK: atomicrmw xchg i64*
   return __atomic_exchange(c, 2, memory_order_seq_cst);