Here is the patch against clang, 0001-Add-target-flags-support-for-atomic-ops.patch
Yours - Michael On Tue, 2013-02-19 at 14:07 -0800, Michael Liao wrote: > Hi All, > > I'd like to add HLE support in LLVM/clang consistent to GCC's style [1]. > HLE from Intel TSX [2] is legacy compatible instruction set extension to > specify transactional region by adding XACQUIRE and XRELEASE prefixes. > To support that, GCC chooses the approach by extending the memory order > flag in __atomic_* builtins with target-specific memory model in high > bits (bit 31-16 for target-specific memory model, bit 15-0 for the > general memory model.) To follow the similar approach, I propose to > change LLVM/clang by adding: > > + a metadata 'targetflags' in LLVM atomic IR to pass this > target-specific memory model hint > > + one extra target flag in AtomicSDNode & MemIntrinsicSDNode to specify > XACQUIRE or XRELEASE hints > This extra target flag is embedded into the SubclassData fields. The > following is rationale how such target flags are embedded into > SubclassData in SDNode > > here is the current SDNode class hierarchy of memory related nodes > > SDNode -> MemSDNode -> LSBaseNode -> LoadSDNode > | + -> StoreSDNode > + -> AtomicSDNode > + -> MemIntrinsicSDNode > > here is the current SubclassData definitions: > > bit 0~1 : extension type used in LoadSDNode > bit 0 : truncating store in StoreSDNode > bit 2~4 : addressing mode in LSBaseNode > bit 5 : volatile bit in MemSDNode > bit 6 : non-temporal bit in MemSDNode > bit 7 : invariant bit in MemSDNode > bit 8~11: memory order in AtomicSDNode > bit 12 : synch scope in AtomicSDNode > > Considering the class hierarchy, we could safely reused bit 0~1 as the > target flags in AtomicSDNode/MemIntrinsicNode > > + X86 backend is modified to generate additional XACQUIRE/XRELEASE > prefix based on the specified target flag > > > The following are details of each patch: > > * 0001-Add-targetflags-in-AtomicSDNode-MemIntrinsicSDNode.patch > > This patch adds 'targetflags' support in AtomicSDNode and > MemIntrinsicSDNode. It will check metadata 'targetflags' and embedded > its value into SubclassData. Currently, only two bits are defined. > > * 0002-Add-HLE-target-feature.patch > > This patch adds HLE feature and auto-detection support > > * 0003-Add-XACQ-XREL-prefix-and-encoding-asm-printer-suppor.patch > > This patch adds XACQUIRE/XRELEASE prefix and its assembler/encoding > support > > * 0004-Enable-HLE-code-generation.patch > > This patch enables HLE code generation by extending the current logic to > handle 'targetflags'. > > * 0001-Add-target-flags-support-for-atomic-ops.patch > > This patch adds target flags support in __atomic_* builtins. It splits > the whole 32-bit order word into high and low 16-bit parts. The low > 16-bit is the original memory order and the high 16-bit will be > re-defined as target-specific flags and passed through 'targetflags' > metadata. > > * 0002-Add-mhle-option-support-and-populate-pre-defined-mac.patch > > It adds '-m[no]hle' option to turn on HLE feature or not. Once HLE > feature is turned on, two more macros (__ATOMIC_HLE_ACQUIRE and > __ATOMIC_HLE_RELEASE) are defined for developers to mark atomic > builtins. > > Thanks for your time to review! > > Yours > - Michael > --- > [1] http://gcc.gnu.org/ml/gcc-patches/2012-04/msg01073.html > [2] http://software.intel.com/sites/default/files/319433-014.pdf >
>From 1ca5090753a8b82b9a9da33a176b89b1145c904b Mon Sep 17 00:00:00 2001 From: Michael Liao <[email protected]> Date: Sun, 1 Jul 2012 00:22:15 -0700 Subject: [PATCH 1/2] Add target flags support for atomic ops --- lib/CodeGen/CGBuiltin.cpp | 40 ++++--- lib/CodeGen/CGExpr.cpp | 44 +++++--- test/CodeGen/atomic-ops-targetflags.c | 193 +++++++++++++++++++++++++++++++++ 3 files changed, 251 insertions(+), 26 deletions(-) create mode 100644 test/CodeGen/atomic-ops-targetflags.c diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp index 9e09131..2633e28 100644 --- a/lib/CodeGen/CGBuiltin.cpp +++ b/lib/CodeGen/CGBuiltin.cpp @@ -1075,7 +1075,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, Value *NewVal = Builder.getInt8(1); Value *Order = EmitScalarExpr(E->getArg(1)); if (isa<llvm::ConstantInt>(Order)) { - int ord = cast<llvm::ConstantInt>(Order)->getZExtValue(); + unsigned ord = cast<llvm::ConstantInt>(Order)->getZExtValue(); + unsigned flags = ord >> 16; + ord = ord & 0xFFFF; // Mask off target flags. AtomicRMWInst *Result = 0; switch (ord) { case 0: // memory_order_relaxed @@ -1107,6 +1109,11 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, break; } Result->setVolatile(Volatile); + if (flags) { + llvm::MDNode *TargetFlags = llvm::MDNode::get(getLLVMContext(), + Builder.getInt32(flags)); + Result->setMetadata("targetflags", TargetFlags); + } return RValue::get(Builder.CreateIsNotNull(Result, "tobool")); } @@ -1124,7 +1131,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, llvm::AcquireRelease, llvm::SequentiallyConsistent }; - Order = Builder.CreateIntCast(Order, Builder.getInt32Ty(), false); + Order = Builder.CreateIntCast(Order, Builder.getInt16Ty(), false); llvm::SwitchInst *SI = Builder.CreateSwitch(Order, BBs[0]); Builder.SetInsertPoint(ContBB); @@ -1139,12 +1146,12 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, Builder.CreateBr(ContBB); } - SI->addCase(Builder.getInt32(0), BBs[0]); - SI->addCase(Builder.getInt32(1), BBs[1]); - SI->addCase(Builder.getInt32(2), BBs[1]); - SI->addCase(Builder.getInt32(3), BBs[2]); - SI->addCase(Builder.getInt32(4), BBs[3]); - SI->addCase(Builder.getInt32(5), BBs[4]); + SI->addCase(Builder.getInt16(0), BBs[0]); + SI->addCase(Builder.getInt16(1), BBs[1]); + SI->addCase(Builder.getInt16(2), BBs[1]); + SI->addCase(Builder.getInt16(3), BBs[2]); + SI->addCase(Builder.getInt16(4), BBs[3]); + SI->addCase(Builder.getInt16(5), BBs[4]); Builder.SetInsertPoint(ContBB); return RValue::get(Builder.CreateIsNotNull(Result, "tobool")); @@ -1161,7 +1168,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, Value *NewVal = Builder.getInt8(0); Value *Order = EmitScalarExpr(E->getArg(1)); if (isa<llvm::ConstantInt>(Order)) { - int ord = cast<llvm::ConstantInt>(Order)->getZExtValue(); + unsigned ord = cast<llvm::ConstantInt>(Order)->getZExtValue(); + unsigned flags = ord >> 16; + ord = ord & 0xFFFF; // Mask off target flags. StoreInst *Store = Builder.CreateStore(NewVal, Ptr, Volatile); Store->setAlignment(1); switch (ord) { @@ -1176,6 +1185,11 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, Store->setOrdering(llvm::SequentiallyConsistent); break; } + if (flags) { + llvm::MDNode *TargetFlags = llvm::MDNode::get(getLLVMContext(), + Builder.getInt32(flags)); + Store->setMetadata("targetflags", TargetFlags); + } return RValue::get(0); } @@ -1190,7 +1204,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, llvm::Monotonic, llvm::Release, llvm::SequentiallyConsistent }; - Order = Builder.CreateIntCast(Order, Builder.getInt32Ty(), false); + Order = Builder.CreateIntCast(Order, Builder.getInt16Ty(), false); llvm::SwitchInst *SI = Builder.CreateSwitch(Order, BBs[0]); for (unsigned i = 0; i < 3; ++i) { @@ -1201,9 +1215,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, Builder.CreateBr(ContBB); } - SI->addCase(Builder.getInt32(0), BBs[0]); - SI->addCase(Builder.getInt32(3), BBs[1]); - SI->addCase(Builder.getInt32(5), BBs[2]); + SI->addCase(Builder.getInt16(0), BBs[0]); + SI->addCase(Builder.getInt16(3), BBs[1]); + SI->addCase(Builder.getInt16(5), BBs[2]); Builder.SetInsertPoint(ContBB); return RValue::get(0); diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp index ba400b8..e9853bc 100644 --- a/lib/CodeGen/CGExpr.cpp +++ b/lib/CodeGen/CGExpr.cpp @@ -3045,7 +3045,8 @@ EmitPointerToDataMemberBinaryExpr(const BinaryOperator *E) { static void EmitAtomicOp(CodeGenFunction &CGF, AtomicExpr *E, llvm::Value *Dest, llvm::Value *Ptr, llvm::Value *Val1, llvm::Value *Val2, - uint64_t Size, unsigned Align, llvm::AtomicOrdering Order) { + uint64_t Size, unsigned Align, llvm::AtomicOrdering Order, + llvm::MDNode *TargetFlags = 0) { llvm::AtomicRMWInst::BinOp Op = llvm::AtomicRMWInst::Add; llvm::Instruction::BinaryOps PostOp = (llvm::Instruction::BinaryOps)0; @@ -3066,6 +3067,8 @@ EmitAtomicOp(CodeGenFunction &CGF, AtomicExpr *E, llvm::Value *Dest, llvm::AtomicCmpXchgInst *CXI = CGF.Builder.CreateAtomicCmpXchg(Ptr, LoadVal1, LoadVal2, Order); CXI->setVolatile(E->isVolatile()); + if (TargetFlags) + CXI->setMetadata("targetflags", TargetFlags); llvm::StoreInst *StoreVal1 = CGF.Builder.CreateStore(CXI, Val1); StoreVal1->setAlignment(Align); llvm::Value *Cmp = CGF.Builder.CreateICmpEQ(CXI, LoadVal1); @@ -3080,6 +3083,8 @@ EmitAtomicOp(CodeGenFunction &CGF, AtomicExpr *E, llvm::Value *Dest, Load->setAtomic(Order); Load->setAlignment(Size); Load->setVolatile(E->isVolatile()); + if (TargetFlags) + Load->setMetadata("targetflags", TargetFlags); llvm::StoreInst *StoreDest = CGF.Builder.CreateStore(Load, Dest); StoreDest->setAlignment(Align); return; @@ -3095,6 +3100,8 @@ EmitAtomicOp(CodeGenFunction &CGF, AtomicExpr *E, llvm::Value *Dest, Store->setAtomic(Order); Store->setAlignment(Size); Store->setVolatile(E->isVolatile()); + if (TargetFlags) + Store->setMetadata("targetflags", TargetFlags); return; } @@ -3157,6 +3164,8 @@ EmitAtomicOp(CodeGenFunction &CGF, AtomicExpr *E, llvm::Value *Dest, llvm::AtomicRMWInst *RMWI = CGF.Builder.CreateAtomicRMW(Op, Ptr, LoadVal1, Order); RMWI->setVolatile(E->isVolatile()); + if (TargetFlags) + RMWI->setMetadata("targetflags", TargetFlags); // For __atomic_*_fetch operations, perform the operation again to // determine the value which was written. @@ -3412,34 +3421,40 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E, llvm::Value *Dest) { if (Dest && !E->isCmpXChg()) Dest = Builder.CreateBitCast(Dest, IPtrTy); if (isa<llvm::ConstantInt>(Order)) { - int ord = cast<llvm::ConstantInt>(Order)->getZExtValue(); + unsigned ord = cast<llvm::ConstantInt>(Order)->getZExtValue(); + unsigned flags = ord >> 16; + ord = ord & 0xFFFF; // Mask off target flags. + llvm::MDNode *TargetFlags = 0; + if (flags) + TargetFlags = llvm::MDNode::get(getLLVMContext(), + Builder.getInt32(flags)); switch (ord) { case 0: // memory_order_relaxed EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align, - llvm::Monotonic); + llvm::Monotonic, TargetFlags); break; case 1: // memory_order_consume case 2: // memory_order_acquire if (IsStore) break; // Avoid crashing on code with undefined behavior EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align, - llvm::Acquire); + llvm::Acquire, TargetFlags); break; case 3: // memory_order_release if (IsLoad) break; // Avoid crashing on code with undefined behavior EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align, - llvm::Release); + llvm::Release, TargetFlags); break; case 4: // memory_order_acq_rel if (IsLoad || IsStore) break; // Avoid crashing on code with undefined behavior EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align, - llvm::AcquireRelease); + llvm::AcquireRelease, TargetFlags); break; case 5: // memory_order_seq_cst EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align, - llvm::SequentiallyConsistent); + llvm::SequentiallyConsistent, TargetFlags); break; default: // invalid order // We should not ever get here normally, but it's hard to @@ -3470,7 +3485,10 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E, llvm::Value *Dest) { // MonotonicBB is arbitrarily chosen as the default case; in practice, this // doesn't matter unless someone is crazy enough to use something that // doesn't fold to a constant for the ordering. - Order = Builder.CreateIntCast(Order, Builder.getInt32Ty(), false); + // + // Cast to i16 to mask off the target flags. So far, if order cannot be + // folded into a constant, target flags are ignored. + Order = Builder.CreateIntCast(Order, Builder.getInt16Ty(), false); llvm::SwitchInst *SI = Builder.CreateSwitch(Order, MonotonicBB); // Emit all the different atomics @@ -3483,28 +3501,28 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E, llvm::Value *Dest) { EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align, llvm::Acquire); Builder.CreateBr(ContBB); - SI->addCase(Builder.getInt32(1), AcquireBB); - SI->addCase(Builder.getInt32(2), AcquireBB); + SI->addCase(Builder.getInt16(1), AcquireBB); + SI->addCase(Builder.getInt16(2), AcquireBB); } if (!IsLoad) { Builder.SetInsertPoint(ReleaseBB); EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align, llvm::Release); Builder.CreateBr(ContBB); - SI->addCase(Builder.getInt32(3), ReleaseBB); + SI->addCase(Builder.getInt16(3), ReleaseBB); } if (!IsLoad && !IsStore) { Builder.SetInsertPoint(AcqRelBB); EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align, llvm::AcquireRelease); Builder.CreateBr(ContBB); - SI->addCase(Builder.getInt32(4), AcqRelBB); + SI->addCase(Builder.getInt16(4), AcqRelBB); } Builder.SetInsertPoint(SeqCstBB); EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align, llvm::SequentiallyConsistent); Builder.CreateBr(ContBB); - SI->addCase(Builder.getInt32(5), SeqCstBB); + SI->addCase(Builder.getInt16(5), SeqCstBB); // Cleanup and return Builder.SetInsertPoint(ContBB); diff --git a/test/CodeGen/atomic-ops-targetflags.c b/test/CodeGen/atomic-ops-targetflags.c new file mode 100644 index 0000000..82f211f --- /dev/null +++ b/test/CodeGen/atomic-ops-targetflags.c @@ -0,0 +1,193 @@ +// RUN: %clang_cc1 %s -emit-llvm -o - -triple=i686-apple-darwin9 | FileCheck %s + +// Also test serialization of atomic operations here, to avoid duplicating the +// test. +// RUN: %clang_cc1 %s -emit-pch -o %t -triple=i686-apple-darwin9 +// RUN: %clang_cc1 %s -include-pch %t -triple=i686-apple-darwin9 -emit-llvm -o - | FileCheck %s +#ifndef ALREADY_INCLUDED +#define ALREADY_INCLUDED + +// Basic IRGen tests for __c11_atomic_* and GNU __atomic_* + +typedef enum memory_order { + memory_order_relaxed, memory_order_consume, memory_order_acquire, + memory_order_release, memory_order_acq_rel, memory_order_seq_cst +} memory_order; + +#define TFLAG (1 << 16) + +int fi1(_Atomic(int) *i) { + // CHECK: @fi1 + // CHECK: load atomic i32* {{.*}} seq_cst, {{.*}}, !targetflags !{{[0-9]+}} + return __c11_atomic_load(i, memory_order_seq_cst | TFLAG); +} + +int fi1a(int *i) { + // CHECK: @fi1a + // CHECK: load atomic i32* {{.*}} seq_cst, {{.*}}, !targetflags !{{[0-9]+}} + int v; + __atomic_load(i, &v, memory_order_seq_cst | TFLAG); + return v; +} + +int fi1b(int *i) { + // CHECK: @fi1b + // CHECK: load atomic i32* {{.*}} seq_cst, {{.*}}, !targetflags !{{[0-9]+}} + return __atomic_load_n(i, memory_order_seq_cst | TFLAG); +} + +void fi2(_Atomic(int) *i) { + // CHECK: @fi2 + // CHECK: store atomic i32 {{.*}} seq_cst, {{.*}}, !targetflags !{{[0-9]+}} + __c11_atomic_store(i, 1, memory_order_seq_cst | TFLAG); +} + +void fi2a(int *i) { + // CHECK: @fi2a + // CHECK: store atomic i32 {{.*}} seq_cst, {{.*}}, !targetflags !{{[0-9]+}} + int v = 1; + __atomic_store(i, &v, memory_order_seq_cst | TFLAG); +} + +void fi2b(int *i) { + // CHECK: @fi2b + // CHECK: store atomic i32 {{.*}} seq_cst, {{.*}}, !targetflags !{{[0-9]+}} + __atomic_store_n(i, 1, memory_order_seq_cst | TFLAG); +} + +int fi3(_Atomic(int) *i) { + // CHECK: @fi3 + // CHECK: atomicrmw and {{.*}}, {{.*}}, !targetflags !{{[0-9]+}} + // CHECK-NOT: and + return __c11_atomic_fetch_and(i, 1, memory_order_seq_cst | TFLAG); +} + +int fi3a(int *i) { + // CHECK: @fi3a + // CHECK: atomicrmw xor {{.*}}, {{.*}}, !targetflags !{{[0-9]+}} + // CHECK-NOT: xor + return __atomic_fetch_xor(i, 1, memory_order_seq_cst | TFLAG); +} + +int fi3b(int *i) { + // CHECK: @fi3b + // CHECK: atomicrmw add {{.*}}, {{.*}}, !targetflags !{{[0-9]+}} + // CHECK: add + return __atomic_add_fetch(i, 1, memory_order_seq_cst | TFLAG); +} + +int fi3c(int *i) { + // CHECK: @fi3c + // CHECK: atomicrmw nand {{.*}}, {{.*}}, !targetflags !{{[0-9]+}} + // CHECK-NOT: and + return __atomic_fetch_nand(i, 1, memory_order_seq_cst | TFLAG); +} + +int fi3d(int *i) { + // CHECK: @fi3d + // CHECK: atomicrmw nand {{.*}}, {{.*}}, !targetflags !{{[0-9]+}} + // CHECK: and + // CHECK: xor + return __atomic_nand_fetch(i, 1, memory_order_seq_cst | TFLAG); +} + +_Bool fi4(_Atomic(int) *i) { + // CHECK: @fi4 + // CHECK: cmpxchg i32* %{{.*}}, {{.*}}, {{.*}}, !targetflags !{{[0-9]+}} + int cmp = 0; + return __c11_atomic_compare_exchange_strong(i, &cmp, 1, memory_order_acquire | TFLAG, memory_order_acquire); +} + +_Bool fi4a(int *i) { + // CHECK: @fi4 + // CHECK: cmpxchg i32* %{{.*}}, {{.*}}, {{.*}}, !targetflags !{{[0-9]+}} + int cmp = 0; + int desired = 1; + return __atomic_compare_exchange(i, &cmp, &desired, 0, memory_order_acquire | TFLAG, memory_order_acquire); +} + +_Bool fi4b(int *i) { + // CHECK: @fi4 + // CHECK: cmpxchg i32* %{{.*}}, {{.*}}, {{.*}}, !targetflags !{{[0-9]+}} + int cmp = 0; + return __atomic_compare_exchange_n(i, &cmp, 1, 1, memory_order_acquire | TFLAG, memory_order_acquire); +} + +float ff1(_Atomic(float) *d) { + // CHECK: @ff1 + // CHECK: load atomic i32* {{.*}} monotonic, {{.*}}, !targetflags !{{[0-9]+}} + return __c11_atomic_load(d, memory_order_relaxed | TFLAG); +} + +void ff2(_Atomic(float) *d) { + // CHECK: @ff2 + // CHECK: store atomic i32 {{.*}} release, {{.*}}, !targetflags !{{[0-9]+}} + __c11_atomic_store(d, 1, memory_order_release | TFLAG); +} + +float ff3(_Atomic(float) *d) { + return __c11_atomic_exchange(d, 2, memory_order_seq_cst | TFLAG); +} + +int* fp1(_Atomic(int*) *p) { + // CHECK: @fp1 + // CHECK: load atomic i32* {{.*}} seq_cst, {{.*}}, !targetflags !{{[0-9]+}} + return __c11_atomic_load(p, memory_order_seq_cst | TFLAG); +} + +int* fp2(_Atomic(int*) *p) { + // CHECK: @fp2 + // CHECK: store i32 4 + // CHECK: atomicrmw add {{.*}} monotonic, !targetflags !{{[0-9]+}} + return __c11_atomic_fetch_add(p, 1, memory_order_relaxed | TFLAG); +} + +int *fp2a(int **p) { + // CHECK: @fp2a + // CHECK: store i32 4 + // CHECK: atomicrmw sub {{.*}} monotonic, !targetflags !{{[0-9]+}} + // Note, the GNU builtins do not multiply by sizeof(T)! + return __atomic_fetch_sub(p, 4, memory_order_relaxed | TFLAG); +} + +_Complex float fc(_Atomic(_Complex float) *c) { + // CHECK: @fc + // CHECK: atomicrmw xchg i64* %{{.*}}, {{.*}}, !targetflags !{{[0-9]+}} + return __c11_atomic_exchange(c, 2, memory_order_seq_cst | TFLAG); +} + +typedef struct X { int x; } X; +X fs(_Atomic(X) *c) { + // CHECK: @fs + // CHECK: atomicrmw xchg i32* %{{.*}}, {{.*}}, !targetflags !{{[0-9]+}} + return __c11_atomic_exchange(c, (X){2}, memory_order_seq_cst | TFLAG); +} + +X fsa(X *c, X *d) { + // CHECK: @fsa + // CHECK: atomicrmw xchg i32* %{{.*}}, {{.*}}, !targetflags !{{[0-9]+}} + X ret; + __atomic_exchange(c, d, &ret, memory_order_seq_cst | TFLAG); + return ret; +} + +_Bool fsb(_Bool *c) { + // CHECK: @fsb + // CHECK: atomicrmw xchg i8* %{{.*}}, {{.*}}, !targetflags !{{[0-9]+}} + return __atomic_exchange_n(c, 1, memory_order_seq_cst | TFLAG); +} + +char flag1; +volatile char flag2; +void test_and_set() { + // CHECK: atomicrmw xchg i8* @flag1, i8 1 seq_cst, !targetflags !{{[0-9]+}} + __atomic_test_and_set(&flag1, memory_order_seq_cst | TFLAG); + // CHECK: atomicrmw volatile xchg i8* @flag2, i8 1 acquire, !targetflags !{{[0-9]+}} + __atomic_test_and_set(&flag2, memory_order_acquire | TFLAG); + // CHECK: store atomic volatile i8 0, i8* @flag2 release, {{.*}}, !targetflags !{{[0-9]+}} + __atomic_clear(&flag2, memory_order_release | TFLAG); + // CHECK: store atomic i8 0, i8* @flag1 seq_cst, {{.*}}, !targetflags !{{[0-9]+}} + __atomic_clear(&flag1, memory_order_seq_cst | TFLAG); +} + +#endif -- 1.7.9.5
_______________________________________________ cfe-commits mailing list [email protected] http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
