r334239 - [MS] Re-add support for the ARM interlocked bittest intrinscs

Reid Kleckner via cfe-commits cfe-commits at lists.llvm.org
Thu Jun 7 14:39:05 PDT 2018


Author: rnk
Date: Thu Jun  7 14:39:04 2018
New Revision: 334239

URL: http://llvm.org/viewvc/llvm-project?rev=334239&view=rev
Log:
[MS] Re-add support for the ARM interlocked bittest intrinscs

Adds support for these intrinsics, which are ARM and ARM64 only:
  _interlockedbittestandreset_acq
  _interlockedbittestandreset_rel
  _interlockedbittestandreset_nf
  _interlockedbittestandset_acq
  _interlockedbittestandset_rel
  _interlockedbittestandset_nf

Refactor the bittest intrinsic handling to decompose each intrinsic into
its action, its width, and its atomicity.

Added:
    cfe/trunk/test/Sema/bittest-intrinsics.c
Modified:
    cfe/trunk/include/clang/Basic/Builtins.def
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/lib/CodeGen/CGBuiltin.cpp
    cfe/trunk/lib/Headers/intrin.h
    cfe/trunk/lib/Sema/SemaChecking.cpp
    cfe/trunk/test/CodeGen/bittest-intrin.c

Modified: cfe/trunk/include/clang/Basic/Builtins.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Builtins.def?rev=334239&r1=334238&r2=334239&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/Builtins.def (original)
+++ cfe/trunk/include/clang/Basic/Builtins.def Thu Jun  7 14:39:04 2018
@@ -791,10 +791,16 @@ LANGBUILTIN(_InterlockedOr,   "NiNiD*Ni"
 LANGBUILTIN(_InterlockedXor8,  "ccD*c",       "n", ALL_MS_LANGUAGES)
 LANGBUILTIN(_InterlockedXor16, "ssD*s",       "n", ALL_MS_LANGUAGES)
 LANGBUILTIN(_InterlockedXor,   "NiNiD*Ni",    "n", ALL_MS_LANGUAGES)
-LANGBUILTIN(_interlockedbittestandreset,   "UcNiD*Ni", "n", ALL_MS_LANGUAGES)
-LANGBUILTIN(_interlockedbittestandreset64, "UcWiD*Wi", "n", ALL_MS_LANGUAGES)
-LANGBUILTIN(_interlockedbittestandset,   "UcNiD*Ni", "n", ALL_MS_LANGUAGES)
-LANGBUILTIN(_interlockedbittestandset64, "UcWiD*Wi", "n", ALL_MS_LANGUAGES)
+LANGBUILTIN(_interlockedbittestandreset,     "UcNiD*Ni", "n", ALL_MS_LANGUAGES)
+LANGBUILTIN(_interlockedbittestandreset64,   "UcWiD*Wi", "n", ALL_MS_LANGUAGES)
+LANGBUILTIN(_interlockedbittestandreset_acq, "UcNiD*Ni", "n", ALL_MS_LANGUAGES)
+LANGBUILTIN(_interlockedbittestandreset_nf,  "UcNiD*Ni", "n", ALL_MS_LANGUAGES)
+LANGBUILTIN(_interlockedbittestandreset_rel, "UcNiD*Ni", "n", ALL_MS_LANGUAGES)
+LANGBUILTIN(_interlockedbittestandset,       "UcNiD*Ni", "n", ALL_MS_LANGUAGES)
+LANGBUILTIN(_interlockedbittestandset64,     "UcWiD*Wi", "n", ALL_MS_LANGUAGES)
+LANGBUILTIN(_interlockedbittestandset_acq,   "UcNiD*Ni", "n", ALL_MS_LANGUAGES)
+LANGBUILTIN(_interlockedbittestandset_nf,    "UcNiD*Ni", "n", ALL_MS_LANGUAGES)
+LANGBUILTIN(_interlockedbittestandset_rel,   "UcNiD*Ni", "n", ALL_MS_LANGUAGES)
 LANGBUILTIN(__noop,           "i.",  "n", ALL_MS_LANGUAGES)
 LANGBUILTIN(__popcnt16, "UsUs",     "nc", ALL_MS_LANGUAGES)
 LANGBUILTIN(__popcnt,   "UiUi",     "nc", ALL_MS_LANGUAGES)

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=334239&r1=334238&r2=334239&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Thu Jun  7 14:39:04 2018
@@ -8154,6 +8154,8 @@ def err_x86_builtin_invalid_rounding : E
   "invalid rounding argument">;
 def err_x86_builtin_invalid_scale : Error<
   "scale argument must be 1, 2, 4, or 8">;
+def err_builtin_target_unsupported : Error<
+  "builtin is not supported on this target">;
 
 def err_builtin_longjmp_unsupported : Error<
   "__builtin_longjmp is not supported for the current target">;

Modified: cfe/trunk/lib/CodeGen/CGBuiltin.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGBuiltin.cpp?rev=334239&r1=334238&r2=334239&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGBuiltin.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGBuiltin.cpp Thu Jun  7 14:39:04 2018
@@ -484,58 +484,99 @@ CodeGenFunction::emitBuiltinObjectSize(c
   return Builder.CreateCall(F, {Ptr, Min, NullIsUnknown});
 }
 
-// Get properties of an X86 BT* assembly instruction. The first returned value
-// is the action character code, which can be for complement, reset, or set. The
-// second is the size suffix which our assembler needs. The last is whether to
-// add the lock prefix.
-static std::tuple<char, char, bool>
-getBitTestActionSizeAndLocking(unsigned BuiltinID) {
+namespace {
+/// A struct to generically desribe a bit test intrinsic.
+struct BitTest {
+  enum ActionKind : uint8_t { TestOnly, Complement, Reset, Set };
+  enum InterlockingKind : uint8_t {
+    Unlocked,
+    Sequential,
+    Acquire,
+    Release,
+    NoFence
+  };
+
+  ActionKind Action;
+  InterlockingKind Interlocking;
+  bool Is64Bit;
+
+  static BitTest decodeBitTestBuiltin(unsigned BuiltinID);
+};
+} // namespace
+
+BitTest BitTest::decodeBitTestBuiltin(unsigned BuiltinID) {
   switch (BuiltinID) {
+    // Main portable variants.
   case Builtin::BI_bittest:
-    return std::make_tuple('\0', 'l', false);
+    return {TestOnly, Unlocked, false};
   case Builtin::BI_bittestandcomplement:
-    return std::make_tuple('c', 'l', false);
+    return {Complement, Unlocked, false};
   case Builtin::BI_bittestandreset:
-    return std::make_tuple('r', 'l', false);
+    return {Reset, Unlocked, false};
   case Builtin::BI_bittestandset:
-    return std::make_tuple('s', 'l', false);
+    return {Set, Unlocked, false};
   case Builtin::BI_interlockedbittestandreset:
-    return std::make_tuple('r', 'l', /*Locked=*/true);
+    return {Reset, Sequential, false};
   case Builtin::BI_interlockedbittestandset:
-    return std::make_tuple('s', 'l', /*Locked=*/true);
+    return {Set, Sequential, false};
 
+    // X86-specific 64-bit variants.
   case Builtin::BI_bittest64:
-    return std::make_tuple('\0', 'q', false);
+    return {TestOnly, Unlocked, true};
   case Builtin::BI_bittestandcomplement64:
-    return std::make_tuple('c', 'q', false);
+    return {Complement, Unlocked, true};
   case Builtin::BI_bittestandreset64:
-    return std::make_tuple('r', 'q', false);
+    return {Reset, Unlocked, true};
   case Builtin::BI_bittestandset64:
-    return std::make_tuple('s', 'q', false);
+    return {Set, Unlocked, true};
   case Builtin::BI_interlockedbittestandreset64:
-    return std::make_tuple('r', 'q', /*Locked=*/true);
+    return {Reset, Sequential, true};
   case Builtin::BI_interlockedbittestandset64:
-    return std::make_tuple('s', 'q', /*Locked=*/true);
+    return {Set, Sequential, true};
+
+    // ARM/AArch64-specific ordering variants.
+  case Builtin::BI_interlockedbittestandset_acq:
+    return {Set, Acquire, false};
+  case Builtin::BI_interlockedbittestandset_rel:
+    return {Set, Release, false};
+  case Builtin::BI_interlockedbittestandset_nf:
+    return {Set, NoFence, false};
+  case Builtin::BI_interlockedbittestandreset_acq:
+    return {Reset, Acquire, false};
+  case Builtin::BI_interlockedbittestandreset_rel:
+    return {Reset, Release, false};
+  case Builtin::BI_interlockedbittestandreset_nf:
+    return {Reset, NoFence, false};
+  }
+  llvm_unreachable("expected only bittest intrinsics");
+}
+
+static char bitActionToX86BTCode(BitTest::ActionKind A) {
+  switch (A) {
+  case BitTest::TestOnly:   return '\0';
+  case BitTest::Complement: return 'c';
+  case BitTest::Reset:      return 'r';
+  case BitTest::Set:        return 's';
   }
-  llvm_unreachable("expected only bittest builtins");
+  llvm_unreachable("invalid action");
 }
 
-static RValue EmitX86BitTestIntrinsic(CodeGenFunction &CGF, unsigned BuiltinID,
-                                      const CallExpr *E, Value *BitBase,
-                                      Value *BitPos) {
-  char Action, Size;
-  bool Locked;
-  std::tie(Action, Size, Locked) = getBitTestActionSizeAndLocking(BuiltinID);
+static llvm::Value *EmitX86BitTestIntrinsic(CodeGenFunction &CGF,
+                                            BitTest BT,
+                                            const CallExpr *E, Value *BitBase,
+                                            Value *BitPos) {
+  char Action = bitActionToX86BTCode(BT.Action);
+  char SizeSuffix = BT.Is64Bit ? 'q' : 'l';
 
   // Build the assembly.
   SmallString<64> Asm;
   raw_svector_ostream AsmOS(Asm);
-  if (Locked)
+  if (BT.Interlocking != BitTest::Unlocked)
     AsmOS << "lock ";
   AsmOS << "bt";
   if (Action)
     AsmOS << Action;
-  AsmOS << Size << " $2, ($1)\n\tsetc ${0:b}";
+  AsmOS << SizeSuffix << " $2, ($1)\n\tsetc ${0:b}";
 
   // Build the constraints. FIXME: We should support immediates when possible.
   std::string Constraints = "=r,r,r,~{cc},~{flags},~{fpsr}";
@@ -548,24 +589,38 @@ static RValue EmitX86BitTestIntrinsic(Co
 
   llvm::InlineAsm *IA =
       llvm::InlineAsm::get(FTy, Asm, Constraints, /*SideEffects=*/true);
-  CallSite CS = CGF.Builder.CreateCall(IA, {BitBase, BitPos});
-  return RValue::get(CS.getInstruction());
+  return CGF.Builder.CreateCall(IA, {BitBase, BitPos});
+}
+
+static llvm::AtomicOrdering
+getBitTestAtomicOrdering(BitTest::InterlockingKind I) {
+  switch (I) {
+  case BitTest::Unlocked:   return llvm::AtomicOrdering::NotAtomic;
+  case BitTest::Sequential: return llvm::AtomicOrdering::SequentiallyConsistent;
+  case BitTest::Acquire:    return llvm::AtomicOrdering::Acquire;
+  case BitTest::Release:    return llvm::AtomicOrdering::Release;
+  case BitTest::NoFence:    return llvm::AtomicOrdering::Monotonic;
+  }
+  llvm_unreachable("invalid interlocking");
 }
 
 /// Emit a _bittest* intrinsic. These intrinsics take a pointer to an array of
 /// bits and a bit position and read and optionally modify the bit at that
 /// position. The position index can be arbitrarily large, i.e. it can be larger
 /// than 31 or 63, so we need an indexed load in the general case.
-static RValue EmitBitTestIntrinsic(CodeGenFunction &CGF, unsigned BuiltinID,
-                                   const CallExpr *E) {
+static llvm::Value *EmitBitTestIntrinsic(CodeGenFunction &CGF,
+                                         unsigned BuiltinID,
+                                         const CallExpr *E) {
   Value *BitBase = CGF.EmitScalarExpr(E->getArg(0));
   Value *BitPos = CGF.EmitScalarExpr(E->getArg(1));
 
+  BitTest BT = BitTest::decodeBitTestBuiltin(BuiltinID);
+
   // X86 has special BT, BTC, BTR, and BTS instructions that handle the array
   // indexing operation internally. Use them if possible.
   llvm::Triple::ArchType Arch = CGF.getTarget().getTriple().getArch();
   if (Arch == llvm::Triple::x86 || Arch == llvm::Triple::x86_64)
-    return EmitX86BitTestIntrinsic(CGF, BuiltinID, E, BitBase, BitPos);
+    return EmitX86BitTestIntrinsic(CGF, BT, E, BitBase, BitPos);
 
   // Otherwise, use generic code to load one byte and test the bit. Use all but
   // the bottom three bits as the array index, and the bottom three bits to form
@@ -583,54 +638,42 @@ static RValue EmitBitTestIntrinsic(CodeG
 
   // The updating instructions will need a mask.
   Value *Mask = nullptr;
-  if (BuiltinID != Builtin::BI_bittest && BuiltinID != Builtin::BI_bittest64) {
+  if (BT.Action != BitTest::TestOnly) {
     Mask = CGF.Builder.CreateShl(llvm::ConstantInt::get(CGF.Int8Ty, 1), PosLow,
                                  "bittest.mask");
   }
 
-  // Emit a combined atomicrmw load/store operation for the interlocked
-  // intrinsics.
-  Value *OldByte = nullptr;
-  switch (BuiltinID) {
-  case Builtin::BI_interlockedbittestandreset:
-  case Builtin::BI_interlockedbittestandreset64:
-    OldByte = CGF.Builder.CreateAtomicRMW(
-        AtomicRMWInst::And, ByteAddr.getPointer(), CGF.Builder.CreateNot(Mask),
-        llvm::AtomicOrdering::SequentiallyConsistent);
-    break;
-  case Builtin::BI_interlockedbittestandset:
-  case Builtin::BI_interlockedbittestandset64:
-    OldByte = CGF.Builder.CreateAtomicRMW(
-        AtomicRMWInst::Or, ByteAddr.getPointer(), Mask,
-        llvm::AtomicOrdering::SequentiallyConsistent);
-    break;
-  default:
-    break;
-  }
+  // Check the action and ordering of the interlocked intrinsics.
+  llvm::AtomicOrdering Ordering = getBitTestAtomicOrdering(BT.Interlocking);
 
-  // Emit a plain load for the non-interlocked intrinsics.
-  if (!OldByte) {
+  Value *OldByte = nullptr;
+  if (Ordering != llvm::AtomicOrdering::NotAtomic) {
+    // Emit a combined atomicrmw load/store operation for the interlocked
+    // intrinsics.
+    llvm::AtomicRMWInst::BinOp RMWOp = llvm::AtomicRMWInst::Or;
+    if (BT.Action == BitTest::Reset) {
+      Mask = CGF.Builder.CreateNot(Mask);
+      RMWOp = llvm::AtomicRMWInst::And;
+    }
+    OldByte = CGF.Builder.CreateAtomicRMW(RMWOp, ByteAddr.getPointer(), Mask,
+                                          Ordering);
+  } else {
+    // Emit a plain load for the non-interlocked intrinsics.
     OldByte = CGF.Builder.CreateLoad(ByteAddr, "bittest.byte");
     Value *NewByte = nullptr;
-    switch (BuiltinID) {
-    case Builtin::BI_bittest:
-    case Builtin::BI_bittest64:
+    switch (BT.Action) {
+    case BitTest::TestOnly:
       // Don't store anything.
       break;
-    case Builtin::BI_bittestandcomplement:
-    case Builtin::BI_bittestandcomplement64:
+    case BitTest::Complement:
       NewByte = CGF.Builder.CreateXor(OldByte, Mask);
       break;
-    case Builtin::BI_bittestandreset:
-    case Builtin::BI_bittestandreset64:
+    case BitTest::Reset:
       NewByte = CGF.Builder.CreateAnd(OldByte, CGF.Builder.CreateNot(Mask));
       break;
-    case Builtin::BI_bittestandset:
-    case Builtin::BI_bittestandset64:
+    case BitTest::Set:
       NewByte = CGF.Builder.CreateOr(OldByte, Mask);
       break;
-    default:
-      llvm_unreachable("non bittest family builtin");
     }
     if (NewByte)
       CGF.Builder.CreateStore(NewByte, ByteAddr);
@@ -639,8 +682,8 @@ static RValue EmitBitTestIntrinsic(CodeG
   // However we loaded the old byte, either by plain load or atomicrmw, shift
   // the bit into the low position and mask it to 0 or 1.
   Value *ShiftedByte = CGF.Builder.CreateLShr(OldByte, PosLow, "bittest.shr");
-  return RValue::get(CGF.Builder.CreateAnd(
-      ShiftedByte, llvm::ConstantInt::get(CGF.Int8Ty, 1), "bittest.res"));
+  return CGF.Builder.CreateAnd(
+      ShiftedByte, llvm::ConstantInt::get(CGF.Int8Ty, 1), "bittest.res");
 }
 
 namespace {
@@ -2992,7 +3035,13 @@ RValue CodeGenFunction::EmitBuiltinExpr(
   case Builtin::BI_interlockedbittestandreset64:
   case Builtin::BI_interlockedbittestandset64:
   case Builtin::BI_interlockedbittestandset:
-    return EmitBitTestIntrinsic(*this, BuiltinID, E);
+  case Builtin::BI_interlockedbittestandset_acq:
+  case Builtin::BI_interlockedbittestandset_rel:
+  case Builtin::BI_interlockedbittestandset_nf:
+  case Builtin::BI_interlockedbittestandreset_acq:
+  case Builtin::BI_interlockedbittestandreset_rel:
+  case Builtin::BI_interlockedbittestandreset_nf:
+    return RValue::get(EmitBitTestIntrinsic(*this, BuiltinID, E));
 
   case Builtin::BI__exception_code:
   case Builtin::BI_exception_code:

Modified: cfe/trunk/lib/Headers/intrin.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Headers/intrin.h?rev=334239&r1=334238&r2=334239&view=diff
==============================================================================
--- cfe/trunk/lib/Headers/intrin.h (original)
+++ cfe/trunk/lib/Headers/intrin.h Thu Jun  7 14:39:04 2018
@@ -521,6 +521,23 @@ _InterlockedAnd64_rel(__int64 volatile *
 }
 #endif
 /*----------------------------------------------------------------------------*\
+|* Bit Counting and Testing
+\*----------------------------------------------------------------------------*/
+#if defined(__arm__) || defined(__aarch64__)
+unsigned char _interlockedbittestandset_acq(long volatile *_BitBase,
+                                            long _BitPos);
+unsigned char _interlockedbittestandset_nf(long volatile *_BitBase,
+                                           long _BitPos);
+unsigned char _interlockedbittestandset_rel(long volatile *_BitBase,
+                                            long _BitPos);
+unsigned char _interlockedbittestandreset_acq(long volatile *_BitBase,
+                                              long _BitPos);
+unsigned char _interlockedbittestandreset_nf(long volatile *_BitBase,
+                                             long _BitPos);
+unsigned char _interlockedbittestandreset_rel(long volatile *_BitBase,
+                                              long _BitPos);
+#endif
+/*----------------------------------------------------------------------------*\
 |* Interlocked Or
 \*----------------------------------------------------------------------------*/
 #if defined(__arm__) || defined(__aarch64__)

Modified: cfe/trunk/lib/Sema/SemaChecking.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaChecking.cpp?rev=334239&r1=334238&r2=334239&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaChecking.cpp (original)
+++ cfe/trunk/lib/Sema/SemaChecking.cpp Thu Jun  7 14:39:04 2018
@@ -851,6 +851,20 @@ static bool SemaOpenCLBuiltinToAddr(Sema
   return false;
 }
 
+// Emit an error and return true if the current architecture is not in the list
+// of supported architectures.
+static bool
+CheckBuiltinTargetSupport(Sema &S, unsigned BuiltinID, CallExpr *TheCall,
+                          ArrayRef<llvm::Triple::ArchType> SupportedArchs) {
+  llvm::Triple::ArchType CurArch =
+      S.getASTContext().getTargetInfo().getTriple().getArch();
+  if (llvm::is_contained(SupportedArchs, CurArch))
+    return false;
+  S.Diag(TheCall->getLocStart(), diag::err_builtin_target_unsupported)
+      << TheCall->getSourceRange();
+  return true;
+}
+
 ExprResult
 Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
                                CallExpr *TheCall) {
@@ -901,6 +915,33 @@ Sema::CheckBuiltinFunctionCall(FunctionD
     }
     break;
   }
+
+  // The acquire, release, and no fence variants are ARM and AArch64 only.
+  case Builtin::BI_interlockedbittestandset_acq:
+  case Builtin::BI_interlockedbittestandset_rel:
+  case Builtin::BI_interlockedbittestandset_nf:
+  case Builtin::BI_interlockedbittestandreset_acq:
+  case Builtin::BI_interlockedbittestandreset_rel:
+  case Builtin::BI_interlockedbittestandreset_nf:
+    if (CheckBuiltinTargetSupport(
+            *this, BuiltinID, TheCall,
+            {llvm::Triple::arm, llvm::Triple::thumb, llvm::Triple::aarch64}))
+      return ExprError();
+    break;
+
+  // The 64-bit bittest variants are x64, ARM, and AArch64 only.
+  case Builtin::BI_bittest64:
+  case Builtin::BI_bittestandcomplement64:
+  case Builtin::BI_bittestandreset64:
+  case Builtin::BI_bittestandset64:
+  case Builtin::BI_interlockedbittestandreset64:
+  case Builtin::BI_interlockedbittestandset64:
+    if (CheckBuiltinTargetSupport(*this, BuiltinID, TheCall,
+                                  {llvm::Triple::x86_64, llvm::Triple::arm,
+                                   llvm::Triple::thumb, llvm::Triple::aarch64}))
+      return ExprError();
+    break;
+
   case Builtin::BI__builtin_isgreater:
   case Builtin::BI__builtin_isgreaterequal:
   case Builtin::BI__builtin_isless:

Modified: cfe/trunk/test/CodeGen/bittest-intrin.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/bittest-intrin.c?rev=334239&r1=334238&r2=334239&view=diff
==============================================================================
--- cfe/trunk/test/CodeGen/bittest-intrin.c (original)
+++ cfe/trunk/test/CodeGen/bittest-intrin.c Thu Jun  7 14:39:04 2018
@@ -10,7 +10,9 @@ void test32(long *base, long idx) {
   sink = _bittestandset(base, idx);
   sink = _interlockedbittestandreset(base, idx);
   sink = _interlockedbittestandset(base, idx);
+  sink = _interlockedbittestandset(base, idx);
 }
+
 void test64(__int64 *base, __int64 idx) {
   sink = _bittest64(base, idx);
   sink = _bittestandcomplement64(base, idx);
@@ -20,6 +22,17 @@ void test64(__int64 *base, __int64 idx)
   sink = _interlockedbittestandset64(base, idx);
 }
 
+#if defined(_M_ARM) || defined(_M_ARM64)
+void test_arm(long *base, long idx) {
+  sink = _interlockedbittestandreset_acq(base, idx);
+  sink = _interlockedbittestandreset_rel(base, idx);
+  sink = _interlockedbittestandreset_nf(base, idx);
+  sink = _interlockedbittestandset_acq(base, idx);
+  sink = _interlockedbittestandset_rel(base, idx);
+  sink = _interlockedbittestandset_nf(base, idx);
+}
+#endif
+
 // X64-LABEL: define dso_local void @test32(i32* %base, i32 %idx)
 // X64: call i8 asm sideeffect "btl $2, ($1)\0A\09setc ${0:b}", "=r,r,r,~{{.*}}"(i32* %{{.*}}, i32 {{.*}})
 // X64: call i8 asm sideeffect "btcl $2, ($1)\0A\09setc ${0:b}", "=r,r,r,~{{.*}}"(i32* %{{.*}}, i32 {{.*}})
@@ -110,15 +123,13 @@ void test64(__int64 *base, __int64 idx)
 // ARM: %[[RES:[^ ]*]] = and i8 %[[BYTESHR]], 1
 // ARM: store volatile i8 %[[RES]], i8* @sink, align 1
 
-// ARM-LABEL: define dso_local {{.*}}void @test64(i64* %base, i64 %idx)
-// ARM: %[[IDXHI:[^ ]*]] = ashr i64 %{{.*}}, 3
-// ARM: %[[BASE:[^ ]*]] = bitcast i64* %{{.*}} to i8*
-// ARM: %[[BYTEADDR:[^ ]*]] = getelementptr inbounds i8, i8* %[[BASE]], i64 %[[IDXHI]]
-// ARM: %[[IDX8:[^ ]*]] = trunc i64 %{{.*}} to i8
-// ARM: %[[IDXLO:[^ ]*]] = and i8 %[[IDX8]], 7
-// ARM: %[[BYTE:[^ ]*]] = load i8, i8* %[[BYTEADDR]], align 1
-// ARM: %[[BYTESHR:[^ ]*]] = lshr i8 %[[BYTE]], %[[IDXLO]]
-// ARM: %[[RES:[^ ]*]] = and i8 %[[BYTESHR]], 1
-// ARM: store volatile i8 %[[RES]], i8* @sink, align 1
 
-// ... the rest is the same, but with i64 instead of i32.
+// Just look for the atomicrmw instructions.
+
+// ARM-LABEL: define dso_local {{.*}}void @test_arm(i32* %base, i32 %idx)
+// ARM: atomicrmw and i8* %{{.*}}, i8 {{.*}} acquire
+// ARM: atomicrmw and i8* %{{.*}}, i8 {{.*}} release
+// ARM: atomicrmw and i8* %{{.*}}, i8 {{.*}} monotonic
+// ARM: atomicrmw or i8* %{{.*}}, i8 {{.*}} acquire
+// ARM: atomicrmw or i8* %{{.*}}, i8 {{.*}} release
+// ARM: atomicrmw or i8* %{{.*}}, i8 {{.*}} monotonic

Added: cfe/trunk/test/Sema/bittest-intrinsics.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/bittest-intrinsics.c?rev=334239&view=auto
==============================================================================
--- cfe/trunk/test/Sema/bittest-intrinsics.c (added)
+++ cfe/trunk/test/Sema/bittest-intrinsics.c Thu Jun  7 14:39:04 2018
@@ -0,0 +1,84 @@
+// RUN: %clang_cc1 -ffreestanding -fms-compatibility -fms-compatibility-version=19 -verify %s -triple i686-windows-msvc -fms-extensions -DTEST_X86
+// RUN: %clang_cc1 -ffreestanding -fms-compatibility -fms-compatibility-version=19 -verify %s -triple x86_64-windows-msvc -fms-extensions -DTEST_X64
+// RUN: %clang_cc1 -ffreestanding -fms-compatibility -fms-compatibility-version=19 -verify %s -triple arm-windows-msvc -fms-extensions -DTEST_ARM
+// RUN: %clang_cc1 -ffreestanding -fms-compatibility -fms-compatibility-version=19 -verify %s -triple thumbv7-windows-msvc -fms-extensions -DTEST_ARM
+// RUN: %clang_cc1 -ffreestanding -fms-compatibility -fms-compatibility-version=19 -verify %s -triple aarch64-windows-msvc -fms-extensions -DTEST_ARM
+
+#include <intrin.h>
+extern unsigned char sink;
+
+#ifdef TEST_X86
+void x86(long *bits, __int64 *bits64, long bitidx) {
+  sink = _bittest(bits, bitidx);
+  sink = _bittestandcomplement(bits, bitidx);
+  sink = _bittestandreset(bits, bitidx);
+  sink = _bittestandset(bits, bitidx);
+  sink = _interlockedbittestandreset(bits, bitidx);
+  sink = _interlockedbittestandset(bits, bitidx);
+
+  sink = _bittest64(bits64, bitidx); // expected-error {{builtin is not supported on this target}}
+  sink = _bittestandcomplement64(bits64, bitidx); // expected-error {{builtin is not supported on this target}}
+  sink = _bittestandreset64(bits64, bitidx); // expected-error {{builtin is not supported on this target}}
+  sink = _bittestandset64(bits64, bitidx); // expected-error {{builtin is not supported on this target}}
+  sink = _interlockedbittestandreset64(bits64, bitidx); // expected-error {{builtin is not supported on this target}}
+  sink = _interlockedbittestandset64(bits64, bitidx); // expected-error {{builtin is not supported on this target}}
+
+  sink = _interlockedbittestandreset_acq(bits, bitidx); // expected-error {{builtin is not supported on this target}}
+  sink = _interlockedbittestandreset_rel(bits, bitidx); // expected-error {{builtin is not supported on this target}}
+  sink = _interlockedbittestandreset_nf(bits, bitidx); // expected-error {{builtin is not supported on this target}}
+  sink = _interlockedbittestandset_acq(bits, bitidx); // expected-error {{builtin is not supported on this target}}
+  sink = _interlockedbittestandset_rel(bits, bitidx); // expected-error {{builtin is not supported on this target}}
+  sink = _interlockedbittestandset_nf(bits, bitidx); // expected-error {{builtin is not supported on this target}}
+}
+#endif
+
+#ifdef TEST_X64
+void x64(long *bits, __int64 *bits64, long bitidx) {
+  sink = _bittest(bits, bitidx);
+  sink = _bittestandcomplement(bits, bitidx);
+  sink = _bittestandreset(bits, bitidx);
+  sink = _bittestandset(bits, bitidx);
+  sink = _interlockedbittestandreset(bits, bitidx);
+  sink = _interlockedbittestandset(bits, bitidx);
+
+  sink = _bittest64(bits64, bitidx);
+  sink = _bittestandcomplement64(bits64, bitidx);
+  sink = _bittestandreset64(bits64, bitidx);
+  sink = _bittestandset64(bits64, bitidx);
+  sink = _interlockedbittestandreset64(bits64, bitidx);
+  sink = _interlockedbittestandset64(bits64, bitidx);
+
+  sink = _interlockedbittestandreset_acq(bits, bitidx); // expected-error {{builtin is not supported on this target}}
+  sink = _interlockedbittestandreset_rel(bits, bitidx); // expected-error {{builtin is not supported on this target}}
+  sink = _interlockedbittestandreset_nf(bits, bitidx); // expected-error {{builtin is not supported on this target}}
+  sink = _interlockedbittestandset_acq(bits, bitidx); // expected-error {{builtin is not supported on this target}}
+  sink = _interlockedbittestandset_rel(bits, bitidx); // expected-error {{builtin is not supported on this target}}
+  sink = _interlockedbittestandset_nf(bits, bitidx); // expected-error {{builtin is not supported on this target}}
+}
+#endif
+
+#ifdef TEST_ARM
+// expected-no-diagnostics
+void arm(long *bits, __int64 *bits64, long bitidx) {
+  sink = _bittest(bits, bitidx);
+  sink = _bittestandcomplement(bits, bitidx);
+  sink = _bittestandreset(bits, bitidx);
+  sink = _bittestandset(bits, bitidx);
+  sink = _interlockedbittestandreset(bits, bitidx);
+  sink = _interlockedbittestandset(bits, bitidx);
+
+  sink = _bittest64(bits64, bitidx);
+  sink = _bittestandcomplement64(bits64, bitidx);
+  sink = _bittestandreset64(bits64, bitidx);
+  sink = _bittestandset64(bits64, bitidx);
+  sink = _interlockedbittestandreset64(bits64, bitidx);
+  sink = _interlockedbittestandset64(bits64, bitidx);
+
+  sink = _interlockedbittestandreset_acq(bits, bitidx);
+  sink = _interlockedbittestandreset_rel(bits, bitidx);
+  sink = _interlockedbittestandreset_nf(bits, bitidx);
+  sink = _interlockedbittestandset_acq(bits, bitidx);
+  sink = _interlockedbittestandset_rel(bits, bitidx);
+  sink = _interlockedbittestandset_nf(bits, bitidx);
+}
+#endif




More information about the cfe-commits mailing list