Index: lib/Analysis/NaCl/PNaClABIVerifyFunctions.cpp |
diff --git a/lib/Analysis/NaCl/PNaClABIVerifyFunctions.cpp b/lib/Analysis/NaCl/PNaClABIVerifyFunctions.cpp |
index c3d8ab75bffb95747f838add2f2ad39bb2bfa40f..cd4d87e0703dc4cde28875af6926c02d33133303 100644 |
--- a/lib/Analysis/NaCl/PNaClABIVerifyFunctions.cpp |
+++ b/lib/Analysis/NaCl/PNaClABIVerifyFunctions.cpp |
@@ -145,29 +145,87 @@ static bool hasAllowedAtomicRMWOperation( |
return true; |
} |
-static bool hasAllowedAtomicMemoryOrder( |
- const NaCl::AtomicIntrinsics::AtomicIntrinsic *I, const CallInst *Call) { |
+static bool |
+hasAllowedAtomicMemoryOrder(const NaCl::AtomicIntrinsics::AtomicIntrinsic *I, |
+ const CallInst *Call) { |
+ NaCl::MemoryOrder PreviousOrder = NaCl::MemoryOrderInvalid; |
+ |
for (size_t P = 0; P != I->NumParams; ++P) { |
if (I->ParamType[P] != NaCl::AtomicIntrinsics::Mem) |
continue; |
- const Value *MemoryOrder = Call->getOperand(P); |
- if (!MemoryOrder) |
- return false; |
- const Constant *C = dyn_cast<Constant>(MemoryOrder); |
- if (!C) |
- return false; |
- const APInt &I = C->getUniqueInteger(); |
- if (I.ule(NaCl::MemoryOrderInvalid) || I.uge(NaCl::MemoryOrderNum)) |
+ NaCl::MemoryOrder Order = NaCl::MemoryOrderInvalid; |
+ if (const Value *MemoryOrderOperand = Call->getOperand(P)) |
+ if (const Constant *C = dyn_cast<Constant>(MemoryOrderOperand)) { |
+ const APInt &I = C->getUniqueInteger(); |
+ if (I.ugt(NaCl::MemoryOrderInvalid) && I.ult(NaCl::MemoryOrderNum)) |
+ Order = static_cast<NaCl::MemoryOrder>(I.getLimitedValue()); |
+ } |
+ if (Order == NaCl::MemoryOrderInvalid) |
return false; |
- // TODO For now only sequential consistency is allowed. When more |
- // are allowed we need to validate that the memory order is |
- // allowed on the specific atomic operation (e.g. no store |
- // acquire, and relationship between success/failure memory |
- // order on compare exchange). |
- if (I != NaCl::MemoryOrderSequentiallyConsistent) |
+ |
+ // Validate PNaCl restrictions. |
+ switch (Order) { |
+ case NaCl::MemoryOrderInvalid: |
+ case NaCl::MemoryOrderNum: |
+ llvm_unreachable("Invalid memory order"); |
+ case NaCl::MemoryOrderRelaxed: |
+ case NaCl::MemoryOrderConsume: |
+ // TODO(jfb) PNaCl doesn't allow relaxed or consume memory ordering. |
return false; |
+ case NaCl::MemoryOrderAcquire: |
+ case NaCl::MemoryOrderRelease: |
+ case NaCl::MemoryOrderAcquireRelease: |
+ case NaCl::MemoryOrderSequentiallyConsistent: |
+ break; // Allowed by PNaCl. |
+ } |
+ |
+ // Validate conformance to the C++11 memory model. |
+ switch (I->ID) { |
+ default: |
+ llvm_unreachable("unexpected atomic operation"); |
+ case Intrinsic::nacl_atomic_load: |
+ // C++11 [atomics.types.operations.req]: The order argument shall not be |
+ // release nor acq_rel. |
+ if (Order == NaCl::MemoryOrderRelease || |
+ Order == NaCl::MemoryOrderAcquireRelease) |
+ return false; |
+ break; |
+ case Intrinsic::nacl_atomic_store: |
+ // C++11 [atomics.types.operations.req]: The order argument shall not be |
+ // consume, acquire, nor acq_rel. |
+ if (Order == NaCl::MemoryOrderConsume || |
+ Order == NaCl::MemoryOrderAcquire || |
+ Order == NaCl::MemoryOrderAcquireRelease) |
+ return false; |
+ break; |
+ case Intrinsic::nacl_atomic_rmw: |
+ break; // No restriction. |
+ case Intrinsic::nacl_atomic_cmpxchg: |
+ // C++11 [atomics.types.operations.req]: The failure argument shall not be |
+ // release nor acq_rel. The failure argument shall be no stronger than the |
+ // success argument. |
+ // Where the partial ordering is: |
+ // relaxed < consume < acquire < acq_rel < seq_cst |
+ // relaxed < release < acq_rel < seq_cst |
+ if (PreviousOrder != NaCl::MemoryOrderInvalid) { // Failure ordering. |
+ NaCl::MemoryOrder Success = PreviousOrder, Failure = Order; |
+ if (Failure == NaCl::MemoryOrderRelease || |
+ Failure == NaCl::MemoryOrderAcquireRelease) |
+ return false; |
+ if ((Success < Failure) || (Success == NaCl::MemoryOrderRelease && |
+ Failure != NaCl::MemoryOrderRelaxed)) |
+ return false; |
+ } |
+ break; // Success ordering has no restriction. |
+ case Intrinsic::nacl_atomic_fence: |
+ case Intrinsic::nacl_atomic_fence_all: |
+ break; // No restrictions. |
+ } |
+ |
+ PreviousOrder = Order; |
} |
+ |
return true; |
} |