Index: include/llvm/Bitcode/LLVMBitCodes.h =================================================================== --- include/llvm/Bitcode/LLVMBitCodes.h +++ include/llvm/Bitcode/LLVMBitCodes.h @@ -370,9 +370,15 @@ }; /// Encoded SynchronizationScope values. -enum AtomicSynchScopeCodes { +enum AtomicSynchScopeCodes : unsigned { + /// Encoded value for SingleThread synchronization scope. SYNCHSCOPE_SINGLETHREAD = 0, - SYNCHSCOPE_CROSSTHREAD = 1 + + /// Encoded value for CrossThread synchronization scope. + SYNCHSCOPE_CROSSTHREAD = 1, + + /// First encoded value for target specific synchronization scope. + SYNCHSCOPE_FIRSTTARGETSPECIFIC = 2 }; /// Markers and flags for call instruction. Index: include/llvm/CodeGen/SelectionDAGNodes.h =================================================================== --- include/llvm/CodeGen/SelectionDAGNodes.h +++ include/llvm/CodeGen/SelectionDAGNodes.h @@ -1017,6 +1017,11 @@ /// Memory reference information. MachineMemOperand *MMO; + /// The synchronization scope of this atomic operation. Not quite enough room + /// in SubclassData for everything, so synchronization scope gets its own + /// field. + SynchronizationScope SynchScope; + public: MemSDNode(unsigned Opc, unsigned Order, const DebugLoc &dl, SDVTList VTs, EVT MemoryVT, MachineMemOperand *MMO); @@ -1045,11 +1050,14 @@ bool isNonTemporal() const { return (SubclassData >> 6) & 1; } bool isInvariant() const { return (SubclassData >> 7) & 1; } + /// Returns the ordering of this atomic operation. AtomicOrdering getOrdering() const { return AtomicOrdering((SubclassData >> 8) & 15); } + + /// Returns the synchronization scope of this atomic operation. SynchronizationScope getSynchScope() const { - return SynchronizationScope((SubclassData >> 12) & 1); + return SynchScope; } // Returns the offset from the location of the access. @@ -1123,8 +1131,9 @@ /// This is an SDNode representing atomic operations. class AtomicSDNode : public MemSDNode { - /// For cmpxchg instructions, the ordering requirements when a store does not - /// occur. + /// For cmpxchg operations, the ordering requirements when a store does not + /// occur. Not quite enough room in SubclassData for everything, so failure + /// gets its own field. AtomicOrdering FailureOrdering; void InitAtomic(AtomicOrdering SuccessOrdering, @@ -1137,11 +1146,9 @@ assert((AtomicOrdering)((unsigned)FailureOrdering & 15) == FailureOrdering && "Ordering may not require more than 4 bits!"); - assert((SynchScope & 1) == SynchScope && - "SynchScope may not require more than 1 bit!"); SubclassData |= (unsigned)SuccessOrdering << 8; - SubclassData |= SynchScope << 12; this->FailureOrdering = FailureOrdering; + this->SynchScope = SynchScope; assert(getSuccessOrdering() == SuccessOrdering && "Ordering encoding error!"); assert(getFailureOrdering() == FailureOrdering && @@ -1161,12 +1168,14 @@ const SDValue &getBasePtr() const { return getOperand(1); } const SDValue &getVal() const { return getOperand(2); } + /// For cmpxchg operations, returns the ordering requirements when store + /// occurs. AtomicOrdering getSuccessOrdering() const { return getOrdering(); } - // Not quite enough room in SubclassData for everything, so failure gets its - // own field. + /// For cmpxchg operations, returns the ordering requirements when store does + /// not occur. AtomicOrdering getFailureOrdering() const { return FailureOrdering; } Index: include/llvm/IR/Instructions.h =================================================================== --- include/llvm/IR/Instructions.h +++ include/llvm/IR/Instructions.h @@ -37,9 +37,16 @@ class DataLayout; class LLVMContext; -enum SynchronizationScope { +/// Prededined synchronization scopes. +enum SynchronizationScope : unsigned { + /// Synchronized with respect to signal handlers executing in the same thread. SingleThread = 0, - CrossThread = 1 + + /// Synchronized with respect to all concurrently executing threads. + CrossThread = 1, + + /// First target specific synchronization scope. + SynchronizationScopeFirstTargetSpecific = 2 }; //===----------------------------------------------------------------------===// @@ -219,30 +226,30 @@ void setAlignment(unsigned Align); - /// Returns the ordering effect of this fence. + /// Returns the ordering constraint of this load instruction. AtomicOrdering getOrdering() const { return AtomicOrdering((getSubclassDataFromInstruction() >> 7) & 7); } - /// Set the ordering constraint on this load. May not be Release or - /// AcquireRelease. + /// Sets the ordering constraint on this load instruction. May not be Release + /// or AcquireRelease. void setOrdering(AtomicOrdering Ordering) { setInstructionSubclassData((getSubclassDataFromInstruction() & ~(7 << 7)) | ((unsigned)Ordering << 7)); } + /// Returns the synchronization scope of this load instruction. SynchronizationScope getSynchScope() const { - return SynchronizationScope((getSubclassDataFromInstruction() >> 6) & 1); + return SynchScope; } - /// Specify whether this load is ordered with respect to all - /// concurrently executing threads, or only with respect to signal handlers - /// executing in the same thread. - void setSynchScope(SynchronizationScope xthread) { - setInstructionSubclassData((getSubclassDataFromInstruction() & ~(1 << 6)) | - (xthread << 6)); + /// Sets the synchronization scope on this load instruction. + void setSynchScope(SynchronizationScope SynchScope) { + this->SynchScope = SynchScope; } + /// Sets the ordering constraint and synchronization scope on this load + /// instruction. void setAtomic(AtomicOrdering Ordering, SynchronizationScope SynchScope = CrossThread) { setOrdering(Ordering); @@ -279,6 +286,11 @@ void setInstructionSubclassData(unsigned short D) { Instruction::setInstructionSubclassData(D); } + + /// The synchronization scope of this load instruction. Not quite enough room + /// in SubClassData for everything, so synchronization scope gets its own + /// field. + SynchronizationScope SynchScope; }; //===----------------------------------------------------------------------===// @@ -337,30 +349,30 @@ void setAlignment(unsigned Align); - /// Returns the ordering effect of this store. + /// Returns the ordering constraint of this store instruction. AtomicOrdering getOrdering() const { return AtomicOrdering((getSubclassDataFromInstruction() >> 7) & 7); } - /// Set the ordering constraint on this store. May not be Acquire or - /// AcquireRelease. + /// Sets the ordering constraint on this store instruction. May not be Acquire + /// or AcquireRelease. void setOrdering(AtomicOrdering Ordering) { setInstructionSubclassData((getSubclassDataFromInstruction() & ~(7 << 7)) | ((unsigned)Ordering << 7)); } + /// Returns the synchronization scope of this store instruction. SynchronizationScope getSynchScope() const { - return SynchronizationScope((getSubclassDataFromInstruction() >> 6) & 1); + return SynchScope; } - /// Specify whether this store instruction is ordered with respect to all - /// concurrently executing threads, or only with respect to signal handlers - /// executing in the same thread. - void setSynchScope(SynchronizationScope xthread) { - setInstructionSubclassData((getSubclassDataFromInstruction() & ~(1 << 6)) | - (xthread << 6)); + /// Sets the synchronization scope on this store instruction. + void setSynchScope(SynchronizationScope SynchScope) { + this->SynchScope = SynchScope; } + /// Sets the ordering constraint and synchronization scope on this store + /// instruction. void setAtomic(AtomicOrdering Ordering, SynchronizationScope SynchScope = CrossThread) { setOrdering(Ordering); @@ -400,6 +412,11 @@ void setInstructionSubclassData(unsigned short D) { Instruction::setInstructionSubclassData(D); } + + /// The synchronization scope of this store instruction. Not quite enough room + /// in SubClassData for everything, so synchronization scope gets its own + /// field. + SynchronizationScope SynchScope; }; template <> @@ -437,28 +454,26 @@ SynchronizationScope SynchScope, BasicBlock *InsertAtEnd); - /// Returns the ordering effect of this fence. + /// Returns the ordering constraint of this fence instruction. AtomicOrdering getOrdering() const { return AtomicOrdering(getSubclassDataFromInstruction() >> 1); } - /// Set the ordering constraint on this fence. May only be Acquire, Release, - /// AcquireRelease, or SequentiallyConsistent. + /// Sets the ordering constraint on this fence instruction. May only be + /// Acquire, Release, AcquireRelease, or SequentiallyConsistent. void setOrdering(AtomicOrdering Ordering) { setInstructionSubclassData((getSubclassDataFromInstruction() & 1) | ((unsigned)Ordering << 1)); } + /// Returns the synchronization scope of this fence instruction. SynchronizationScope getSynchScope() const { - return SynchronizationScope(getSubclassDataFromInstruction() & 1); + return SynchScope; } - /// Specify whether this fence orders other operations with respect to all - /// concurrently executing threads, or only with respect to signal handlers - /// executing in the same thread. - void setSynchScope(SynchronizationScope xthread) { - setInstructionSubclassData((getSubclassDataFromInstruction() & ~1) | - xthread); + /// Sets the synchronization scope on this fence instruction. + void setSynchScope(SynchronizationScope SynchScope) { + this->SynchScope = SynchScope; } // Methods for support type inquiry through isa, cast, and dyn_cast: @@ -475,6 +490,11 @@ void setInstructionSubclassData(unsigned short D) { Instruction::setInstructionSubclassData(D); } + + /// The synchronization scope of this fence instruction. Not quite enough room + /// in SubClassData for everything, so synchronization scope gets its own + /// field. + SynchronizationScope SynchScope; }; //===----------------------------------------------------------------------===// @@ -539,7 +559,14 @@ /// Transparently provide more efficient getOperand methods. DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); - /// Set the ordering constraint on this cmpxchg. + /// Returns the ordering constraint of this cmpxchg instruction when store + /// occurs. + AtomicOrdering getSuccessOrdering() const { + return AtomicOrdering((getSubclassDataFromInstruction() >> 2) & 7); + } + + /// Sets the ordering constraint on this cmpxchg instruction when store + /// occurs. void setSuccessOrdering(AtomicOrdering Ordering) { assert(Ordering != AtomicOrdering::NotAtomic && "CmpXchg instructions can only be atomic."); @@ -547,6 +574,14 @@ ((unsigned)Ordering << 2)); } + /// Returns the ordering constraint of this cmpxchg instruction when store + /// does not occur. + AtomicOrdering getFailureOrdering() const { + return AtomicOrdering((getSubclassDataFromInstruction() >> 5) & 7); + } + + /// Sets the ordering constraint on this cmpxchg instruction when store + /// does not occur. void setFailureOrdering(AtomicOrdering Ordering) { assert(Ordering != AtomicOrdering::NotAtomic && "CmpXchg instructions can only be atomic."); @@ -554,28 +589,14 @@ ((unsigned)Ordering << 5)); } - /// Specify whether this cmpxchg is atomic and orders other operations with - /// respect to all concurrently executing threads, or only with respect to - /// signal handlers executing in the same thread. - void setSynchScope(SynchronizationScope SynchScope) { - setInstructionSubclassData((getSubclassDataFromInstruction() & ~2) | - (SynchScope << 1)); - } - - /// Returns the ordering constraint on this cmpxchg. - AtomicOrdering getSuccessOrdering() const { - return AtomicOrdering((getSubclassDataFromInstruction() >> 2) & 7); - } - - /// Returns the ordering constraint on this cmpxchg. - AtomicOrdering getFailureOrdering() const { - return AtomicOrdering((getSubclassDataFromInstruction() >> 5) & 7); + /// Returns the synchronization scope of this cmpxchg instruction. + SynchronizationScope getSynchScope() const { + return SynchScope; } - /// Returns whether this cmpxchg is atomic between threads or only within a - /// single thread. - SynchronizationScope getSynchScope() const { - return SynchronizationScope((getSubclassDataFromInstruction() & 2) >> 1); + /// Sets the synchronization scope on this cmpxchg instruction. + void setSynchScope(SynchronizationScope SynchScope) { + this->SynchScope = SynchScope; } Value *getPointerOperand() { return getOperand(0); } @@ -630,6 +651,11 @@ void setInstructionSubclassData(unsigned short D) { Instruction::setInstructionSubclassData(D); } + + /// The synchronization scope of this cmpxchg instruction. Not quite enough + /// room in SubClassData for everything, so synchronization scope gets its own + /// field. + SynchronizationScope SynchScope; }; template <> @@ -726,7 +752,12 @@ /// Transparently provide more efficient getOperand methods. DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); - /// Set the ordering constraint on this RMW. + /// Returns the ordering constraint of this RMW instruction. + AtomicOrdering getOrdering() const { + return AtomicOrdering((getSubclassDataFromInstruction() >> 2) & 7); + } + + /// Sets the ordering constraint on this RMW instruction. void setOrdering(AtomicOrdering Ordering) { assert(Ordering != AtomicOrdering::NotAtomic && "atomicrmw instructions can only be atomic."); @@ -734,25 +765,16 @@ ((unsigned)Ordering << 2)); } - /// Specify whether this RMW orders other operations with respect to all - /// concurrently executing threads, or only with respect to signal handlers - /// executing in the same thread. - void setSynchScope(SynchronizationScope SynchScope) { - setInstructionSubclassData((getSubclassDataFromInstruction() & ~2) | - (SynchScope << 1)); - } - - /// Returns the ordering constraint on this RMW. - AtomicOrdering getOrdering() const { - return AtomicOrdering((getSubclassDataFromInstruction() >> 2) & 7); - } - - /// Returns whether this RMW is atomic between threads or only within a - /// single thread. + /// Returns the synchronization scope of this RMW instruction. SynchronizationScope getSynchScope() const { - return SynchronizationScope((getSubclassDataFromInstruction() & 2) >> 1); + return SynchScope; } + /// Sets the synchronization scope on this RMW instruction. + void setSynchScope(SynchronizationScope SynchScope) { + this->SynchScope = SynchScope; + } + Value *getPointerOperand() { return getOperand(0); } const Value *getPointerOperand() const { return getOperand(0); } static unsigned getPointerOperandIndex() { return 0U; } @@ -781,6 +803,11 @@ void setInstructionSubclassData(unsigned short D) { Instruction::setInstructionSubclassData(D); } + + /// The synchronization scope of this RMW instruction. Not quite enough room + /// in SubClassData for everything, so synchronization scope gets its own + /// field. + SynchronizationScope SynchScope; }; template <> Index: lib/AsmParser/LLLexer.cpp =================================================================== --- lib/AsmParser/LLLexer.cpp +++ lib/AsmParser/LLLexer.cpp @@ -547,6 +547,7 @@ KEYWORD(acq_rel); KEYWORD(seq_cst); KEYWORD(singlethread); + KEYWORD(synchscope); KEYWORD(nnan); KEYWORD(ninf); Index: lib/AsmParser/LLParser.h =================================================================== --- lib/AsmParser/LLParser.h +++ lib/AsmParser/LLParser.h @@ -239,6 +239,7 @@ bool ParseOptionalDerefAttrBytes(lltok::Kind AttrKind, uint64_t &Bytes); bool ParseScopeAndOrdering(bool isAtomic, SynchronizationScope &Scope, AtomicOrdering &Ordering); + bool ParseScope(SynchronizationScope &Scope); bool ParseOrdering(AtomicOrdering &Ordering); bool ParseOptionalStackAlignment(unsigned &Alignment); bool ParseOptionalCommaAlign(unsigned &Alignment, bool &AteExtraComma); Index: lib/AsmParser/LLParser.cpp =================================================================== --- lib/AsmParser/LLParser.cpp +++ lib/AsmParser/LLParser.cpp @@ -1868,8 +1868,10 @@ } /// ParseScopeAndOrdering -/// if isAtomic: ::= 'singlethread'? AtomicOrdering -/// else: ::= +/// if isAtomic: +/// ::= 'singlethread' or 'synchscope' '(' uint32 ')'? AtomicOrdering +/// else +/// ::= /// /// This sets Scope and Ordering to the parsed values. bool LLParser::ParseScopeAndOrdering(bool isAtomic, SynchronizationScope &Scope, @@ -1877,11 +1879,41 @@ if (!isAtomic) return false; + return ParseScope(Scope) || ParseOrdering(Ordering); +} + +/// ParseScope +/// ::= /* empty */ +/// ::= 'singlethread' +/// ::= 'synchscope' '(' uint32 ')' +/// +/// This sets Scope to the parsed value. +bool LLParser::ParseScope(SynchronizationScope &Scope) { + if (EatIfPresent(lltok::kw_synchscope)) { + auto StartParen = Lex.getLoc(); + if (!EatIfPresent(lltok::lparen)) + return Error(StartParen, "expected '(' in synchscope"); + + unsigned ScopeU32 = 0; + auto ScopeU32At = Lex.getLoc(); + if (ParseUInt32(ScopeU32)) + return true; + if (ScopeU32 < SynchronizationScopeFirstTargetSpecific) + return Error(ScopeU32At, "invalid target specific synchronization scope"); + + auto EndParen = Lex.getLoc(); + if (!EatIfPresent(lltok::rparen)) + return Error(EndParen, "expected ')' in synchscope"); + + Scope = SynchronizationScope(ScopeU32); + return false; + } + Scope = CrossThread; if (EatIfPresent(lltok::kw_singlethread)) Scope = SingleThread; - return ParseOrdering(Ordering); + return false; } /// ParseOrdering Index: lib/AsmParser/LLToken.h =================================================================== --- lib/AsmParser/LLToken.h +++ lib/AsmParser/LLToken.h @@ -94,6 +94,8 @@ kw_acq_rel, kw_seq_cst, kw_singlethread, + kw_synchscope, + kw_nnan, kw_ninf, kw_nsz, Index: lib/Bitcode/Reader/BitcodeReader.cpp =================================================================== --- lib/Bitcode/Reader/BitcodeReader.cpp +++ lib/Bitcode/Reader/BitcodeReader.cpp @@ -860,9 +860,13 @@ } static SynchronizationScope getDecodedSynchScope(unsigned Val) { + if (Val >= bitc::SYNCHSCOPE_FIRSTTARGETSPECIFIC) + return SynchronizationScope(SynchronizationScopeFirstTargetSpecific + + (Val - bitc::SYNCHSCOPE_FIRSTTARGETSPECIFIC)); + switch (Val) { + default: llvm_unreachable("Invalid synch scope"); case bitc::SYNCHSCOPE_SINGLETHREAD: return SingleThread; - default: // Map unknown scopes to cross-thread. case bitc::SYNCHSCOPE_CROSSTHREAD: return CrossThread; } } Index: lib/Bitcode/Writer/BitcodeWriter.cpp =================================================================== --- lib/Bitcode/Writer/BitcodeWriter.cpp +++ lib/Bitcode/Writer/BitcodeWriter.cpp @@ -590,11 +590,15 @@ } static unsigned getEncodedSynchScope(SynchronizationScope SynchScope) { + if (SynchScope >= SynchronizationScopeFirstTargetSpecific) + return unsigned(bitc::SYNCHSCOPE_FIRSTTARGETSPECIFIC + + (SynchScope - SynchronizationScopeFirstTargetSpecific)); + switch (SynchScope) { + default: llvm_unreachable("Invalid synch scope"); case SingleThread: return bitc::SYNCHSCOPE_SINGLETHREAD; case CrossThread: return bitc::SYNCHSCOPE_CROSSTHREAD; } - llvm_unreachable("Invalid synch scope"); } void ModuleBitcodeWriter::writeStringRecord(unsigned Code, StringRef Str, Index: lib/CodeGen/SelectionDAG/SelectionDAG.cpp =================================================================== --- lib/CodeGen/SelectionDAG/SelectionDAG.cpp +++ lib/CodeGen/SelectionDAG/SelectionDAG.cpp @@ -6710,7 +6710,8 @@ MemSDNode::MemSDNode(unsigned Opc, unsigned Order, const DebugLoc &dl, SDVTList VTs, EVT memvt, MachineMemOperand *mmo) - : SDNode(Opc, Order, dl, VTs), MemoryVT(memvt), MMO(mmo) { + : SDNode(Opc, Order, dl, VTs), MemoryVT(memvt), MMO(mmo), + SynchScope(CrossThread) { SubclassData = encodeMemSDNodeFlags(0, ISD::UNINDEXED, MMO->isVolatile(), MMO->isNonTemporal(), MMO->isInvariant()); assert(isVolatile() == MMO->isVolatile() && "Volatile encoding error!"); Index: lib/IR/AsmWriter.cpp =================================================================== --- lib/IR/AsmWriter.cpp +++ lib/IR/AsmWriter.cpp @@ -2149,9 +2149,13 @@ if (Ordering == AtomicOrdering::NotAtomic) return; + if (SynchScope >= SynchronizationScopeFirstTargetSpecific) + Out << " synchscope(" << unsigned(SynchScope) << ')'; + switch (SynchScope) { case SingleThread: Out << " singlethread"; break; case CrossThread: break; + default: break; } Out << " " << toIRString(Ordering); @@ -2163,9 +2167,13 @@ assert(SuccessOrdering != AtomicOrdering::NotAtomic && FailureOrdering != AtomicOrdering::NotAtomic); + if (SynchScope >= SynchronizationScopeFirstTargetSpecific) + Out << " synchscope(" << unsigned(SynchScope) << ')'; + switch (SynchScope) { case SingleThread: Out << " singlethread"; break; case CrossThread: break; + default: break; } Out << " " << toIRString(SuccessOrdering); Index: lib/Target/AMDGPU/AMDGPU.h =================================================================== --- lib/Target/AMDGPU/AMDGPU.h +++ lib/Target/AMDGPU/AMDGPU.h @@ -11,6 +11,8 @@ #ifndef LLVM_LIB_TARGET_AMDGPU_AMDGPU_H #define LLVM_LIB_TARGET_AMDGPU_AMDGPU_H +#include "llvm/IR/Instructions.h" + namespace llvm { class AMDGPUTargetMachine; @@ -161,4 +163,35 @@ } // namespace AMDGPUAS +/// AMDGPU-specific synchronization scopes. +enum class AMDGPUSynchronizationScope : unsigned { + /// Synchronized with respect to the entire system, which includes all + /// work-items on all agents executing kernel dispatches for the same + /// application process, together with all agents executing the same + /// application process as the executing work-item. Only supported for the + /// global segment. + System = llvm::CrossThread, + + /// Synchronized with respect to signal handlers executing in the same + /// work-item. + SignalHandler = llvm::SingleThread, + + /// Synchronized with respect to the agent, which includes all work-items on + /// the same agent executing kernel dispatches for the same application + /// process as the executing work-item. Only supported for the global segment. + Agent = llvm::SynchronizationScopeFirstTargetSpecific, + + /// Synchronized with respect to the work-group, which includes all work-items + /// in the same work-group as the executing work-item. + WorkGroup, + + /// Synchronized with respect to the wavefront, which includes all work-items + /// in the same wavefront as the executing work-item. + Wavefront, + + /// Synchronized with respect to image fence instruction executing in the same + /// work-item. + Image +}; + #endif Index: lib/Target/SystemZ/SystemZISelLowering.cpp =================================================================== --- lib/Target/SystemZ/SystemZISelLowering.cpp +++ lib/Target/SystemZ/SystemZISelLowering.cpp @@ -3179,7 +3179,7 @@ // The only fence that needs an instruction is a sequentially-consistent // cross-thread fence. if (FenceOrdering == AtomicOrdering::SequentiallyConsistent && - FenceScope == CrossThread) { + FenceScope != SingleThread) { return SDValue(DAG.getMachineNode(SystemZ::Serialize, DL, MVT::Other, Op.getOperand(0)), 0); Index: lib/Target/X86/X86ISelLowering.cpp =================================================================== --- lib/Target/X86/X86ISelLowering.cpp +++ lib/Target/X86/X86ISelLowering.cpp @@ -21016,7 +21016,7 @@ // The only fence that needs an instruction is a sequentially-consistent // cross-thread fence. if (FenceOrdering == AtomicOrdering::SequentiallyConsistent && - FenceScope == CrossThread) { + FenceScope != SingleThread) { if (Subtarget.hasMFence()) return DAG.getNode(X86ISD::MFENCE, dl, MVT::Other, Op.getOperand(0)); Index: lib/Transforms/Instrumentation/ThreadSanitizer.cpp =================================================================== --- lib/Transforms/Instrumentation/ThreadSanitizer.cpp +++ lib/Transforms/Instrumentation/ThreadSanitizer.cpp @@ -366,9 +366,9 @@ static bool isAtomic(Instruction *I) { if (LoadInst *LI = dyn_cast(I)) - return LI->isAtomic() && LI->getSynchScope() == CrossThread; + return LI->isAtomic() && LI->getSynchScope() != SingleThread; if (StoreInst *SI = dyn_cast(I)) - return SI->isAtomic() && SI->getSynchScope() == CrossThread; + return SI->isAtomic() && SI->getSynchScope() != SingleThread; if (isa(I)) return true; if (isa(I)) Index: test/Assembler/atomic.ll =================================================================== --- test/Assembler/atomic.ll +++ test/Assembler/atomic.ll @@ -7,10 +7,14 @@ load atomic i32, i32* %x unordered, align 4 ; CHECK: load atomic volatile i32, i32* %x singlethread acquire, align 4 load atomic volatile i32, i32* %x singlethread acquire, align 4 + ; CHECK: load atomic volatile i32, i32* %x synchscope(2) acquire, align 4 + load atomic volatile i32, i32* %x synchscope(2) acquire, align 4 ; CHECK: store atomic i32 3, i32* %x release, align 4 store atomic i32 3, i32* %x release, align 4 ; CHECK: store atomic volatile i32 3, i32* %x singlethread monotonic, align 4 store atomic volatile i32 3, i32* %x singlethread monotonic, align 4 + ; CHECK: store atomic volatile i32 3, i32* %x synchscope(3) monotonic, align 4 + store atomic volatile i32 3, i32* %x synchscope(3) monotonic, align 4 ; CHECK: cmpxchg i32* %x, i32 1, i32 0 singlethread monotonic monotonic cmpxchg i32* %x, i32 1, i32 0 singlethread monotonic monotonic ; CHECK: cmpxchg volatile i32* %x, i32 0, i32 1 acq_rel acquire @@ -19,13 +23,19 @@ cmpxchg i32* %x, i32 42, i32 0 acq_rel monotonic ; CHECK: cmpxchg weak i32* %x, i32 13, i32 0 seq_cst monotonic cmpxchg weak i32* %x, i32 13, i32 0 seq_cst monotonic + ; CHECK: cmpxchg weak i32* %x, i32 13, i32 0 synchscope(4) seq_cst monotonic + cmpxchg weak i32* %x, i32 13, i32 0 synchscope(4) seq_cst monotonic ; CHECK: atomicrmw add i32* %x, i32 10 seq_cst atomicrmw add i32* %x, i32 10 seq_cst ; CHECK: atomicrmw volatile xchg i32* %x, i32 10 monotonic atomicrmw volatile xchg i32* %x, i32 10 monotonic + ; CHECK: atomicrmw volatile xchg i32* %x, i32 10 synchscope(5) monotonic + atomicrmw volatile xchg i32* %x, i32 10 synchscope(5) monotonic ; CHECK: fence singlethread release fence singlethread release ; CHECK: fence seq_cst fence seq_cst + ; CHECK: fence synchscope(6) seq_cst + fence synchscope(6) seq_cst ret void }