diff options
-rw-r--r-- | docs/LangRef.html | 58 | ||||
-rw-r--r-- | include/llvm/Bitcode/LLVMBitCodes.h | 20 | ||||
-rw-r--r-- | include/llvm/Instruction.def | 63 | ||||
-rw-r--r-- | include/llvm/Instructions.h | 93 | ||||
-rw-r--r-- | include/llvm/Support/IRBuilder.h | 4 | ||||
-rw-r--r-- | include/llvm/Support/InstVisitor.h | 1 | ||||
-rw-r--r-- | lib/AsmParser/LLLexer.cpp | 10 | ||||
-rw-r--r-- | lib/AsmParser/LLParser.cpp | 44 | ||||
-rw-r--r-- | lib/AsmParser/LLParser.h | 4 | ||||
-rw-r--r-- | lib/AsmParser/LLToken.h | 5 | ||||
-rw-r--r-- | lib/Bitcode/Reader/BitcodeReader.cpp | 33 | ||||
-rw-r--r-- | lib/Bitcode/Writer/BitcodeWriter.cpp | 26 | ||||
-rw-r--r-- | lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp | 4 | ||||
-rw-r--r-- | lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h | 1 | ||||
-rw-r--r-- | lib/VMCore/AsmWriter.cpp | 25 | ||||
-rw-r--r-- | lib/VMCore/Instruction.cpp | 1 | ||||
-rw-r--r-- | lib/VMCore/Instructions.cpp | 24 | ||||
-rw-r--r-- | lib/VMCore/Verifier.cpp | 10 |
18 files changed, 393 insertions, 33 deletions
diff --git a/docs/LangRef.html b/docs/LangRef.html index ec75150..ad74b1c 100644 --- a/docs/LangRef.html +++ b/docs/LangRef.html @@ -170,6 +170,7 @@ <li><a href="#i_alloca">'<tt>alloca</tt>' Instruction</a></li> <li><a href="#i_load">'<tt>load</tt>' Instruction</a></li> <li><a href="#i_store">'<tt>store</tt>' Instruction</a></li> + <li><a href="#i_fence">'<tt>fence</tt>' Instruction</a></li> <li><a href="#i_getelementptr">'<tt>getelementptr</tt>' Instruction</a></li> </ol> </li> @@ -4552,6 +4553,63 @@ that the invoke/unwind semantics are likely to change in future versions.</p> </div> <!-- _______________________________________________________________________ --> +<div class="doc_subsubsection"> <a name="i_fence">'<tt>fence</tt>' +Instruction</a> </div> + +<div class="doc_text"> + +<h5>Syntax:</h5> +<pre> + fence [singlethread] <ordering> <i>; yields {void}</i> +</pre> + +<h5>Overview:</h5> +<p>The '<tt>fence</tt>' instruction is used to introduce happens-before edges +between operations.</p> + +<h5>Arguments:</h5> <p>'<code>fence</code>' instructions take an <a +href="#ordering">ordering</a> argument which defines what +<i>synchronizes-with</i> edges they add. They can only be given +<code>acquire</code>, <code>release</code>, <code>acq_rel</code>, and +<code>seq_cst</code> orderings.</p> + +<h5>Semantics:</h5> +<p>A fence <var>A</var> which has (at least) <code>release</code> ordering +semantics <i>synchronizes with</i> a fence <var>B</var> with (at least) +<code>acquire</code> ordering semantics if and only if there exist atomic +operations <var>X</var> and <var>Y</var>, both operating on some atomic object +<var>M</var>, such that <var>A</var> is sequenced before <var>X</var>, +<var>X</var> modifies <var>M</var> (either directly or through some side effect +of a sequence headed by <var>X</var>), <var>Y</var> is sequenced before +<var>B</var>, and <var>Y</var> observes <var>M</var>. This provides a +<i>happens-before</i> dependency between <var>A</var> and <var>B</var>. Rather +than an explicit <code>fence</code>, one (but not both) of the atomic operations +<var>X</var> or <var>Y</var> might provide a <code>release</code> or +<code>acquire</code> (resp.) ordering constraint and still +<i>synchronize-with</i> the explicit <code>fence</code> and establish the +<i>happens-before</i> edge.</p> + +<p>A <code>fence</code> which has <code>seq_cst</code> ordering, in addition to +having both <code>acquire</code> and <code>release</code> semantics specified +above, participates in the global program order of other <code>seq_cst</code> +operations and/or fences.</p> + +<p>The optional "<a href="#singlethread"><code>singlethread</code></a>" argument +specifies that the fence only synchronizes with other fences in the same +thread. (This is useful for interacting with signal handlers.)</p> + +<p>FIXME: This instruction is a work in progress; until it is finished, use + llvm.memory.barrier. + +<h5>Example:</h5> +<pre> + fence acquire <i>; yields {void}</i> + fence singlethread seq_cst <i>; yields {void}</i> +</pre> + +</div> + +<!-- _______________________________________________________________________ --> <h4> <a name="i_getelementptr">'<tt>getelementptr</tt>' Instruction</a> </h4> diff --git a/include/llvm/Bitcode/LLVMBitCodes.h b/include/llvm/Bitcode/LLVMBitCodes.h index df68bd5..503a867 100644 --- a/include/llvm/Bitcode/LLVMBitCodes.h +++ b/include/llvm/Bitcode/LLVMBitCodes.h @@ -218,6 +218,23 @@ namespace bitc { PEO_EXACT = 0 }; + /// Encoded AtomicOrdering values. + enum AtomicOrderingCodes { + ORDERING_NOTATOMIC = 0, + ORDERING_UNORDERED = 1, + ORDERING_MONOTONIC = 2, + ORDERING_ACQUIRE = 3, + ORDERING_RELEASE = 4, + ORDERING_ACQREL = 5, + ORDERING_SEQCST = 6 + }; + + /// Encoded SynchronizationScope values. + enum AtomicSynchScopeCodes { + SYNCHSCOPE_SINGLETHREAD = 0, + SYNCHSCOPE_CROSSTHREAD = 1 + }; + // The function body block (FUNCTION_BLOCK_ID) describes function bodies. It // can contain a constant block (CONSTANTS_BLOCK_ID). enum FunctionCodes { @@ -266,7 +283,8 @@ namespace bitc { FUNC_CODE_INST_CALL = 34, // CALL: [attr, fnty, fnid, args...] - FUNC_CODE_DEBUG_LOC = 35 // DEBUG_LOC: [Line,Col,ScopeVal, IAVal] + FUNC_CODE_DEBUG_LOC = 35, // DEBUG_LOC: [Line,Col,ScopeVal, IAVal] + FUNC_CODE_INST_FENCE = 36 // FENCE: [ordering, synchscope] }; } // End bitc namespace } // End llvm namespace diff --git a/include/llvm/Instruction.def b/include/llvm/Instruction.def index 205f303..e418165 100644 --- a/include/llvm/Instruction.def +++ b/include/llvm/Instruction.def @@ -133,43 +133,44 @@ HANDLE_MEMORY_INST(26, Alloca, AllocaInst) // Stack management HANDLE_MEMORY_INST(27, Load , LoadInst ) // Memory manipulation instrs HANDLE_MEMORY_INST(28, Store , StoreInst ) HANDLE_MEMORY_INST(29, GetElementPtr, GetElementPtrInst) - LAST_MEMORY_INST(29) +HANDLE_MEMORY_INST(30, Fence , FenceInst ) + LAST_MEMORY_INST(32) // Cast operators ... // NOTE: The order matters here because CastInst::isEliminableCastPair // NOTE: (see Instructions.cpp) encodes a table based on this ordering. - FIRST_CAST_INST(30) -HANDLE_CAST_INST(30, Trunc , TruncInst ) // Truncate integers -HANDLE_CAST_INST(31, ZExt , ZExtInst ) // Zero extend integers -HANDLE_CAST_INST(32, SExt , SExtInst ) // Sign extend integers -HANDLE_CAST_INST(33, FPToUI , FPToUIInst ) // floating point -> UInt -HANDLE_CAST_INST(34, FPToSI , FPToSIInst ) // floating point -> SInt -HANDLE_CAST_INST(35, UIToFP , UIToFPInst ) // UInt -> floating point -HANDLE_CAST_INST(36, SIToFP , SIToFPInst ) // SInt -> floating point -HANDLE_CAST_INST(37, FPTrunc , FPTruncInst ) // Truncate floating point -HANDLE_CAST_INST(38, FPExt , FPExtInst ) // Extend floating point -HANDLE_CAST_INST(39, PtrToInt, PtrToIntInst) // Pointer -> Integer -HANDLE_CAST_INST(40, IntToPtr, IntToPtrInst) // Integer -> Pointer -HANDLE_CAST_INST(41, BitCast , BitCastInst ) // Type cast - LAST_CAST_INST(41) + FIRST_CAST_INST(33) +HANDLE_CAST_INST(33, Trunc , TruncInst ) // Truncate integers +HANDLE_CAST_INST(34, ZExt , ZExtInst ) // Zero extend integers +HANDLE_CAST_INST(35, SExt , SExtInst ) // Sign extend integers +HANDLE_CAST_INST(36, FPToUI , FPToUIInst ) // floating point -> UInt +HANDLE_CAST_INST(37, FPToSI , FPToSIInst ) // floating point -> SInt +HANDLE_CAST_INST(38, UIToFP , UIToFPInst ) // UInt -> floating point +HANDLE_CAST_INST(39, SIToFP , SIToFPInst ) // SInt -> floating point +HANDLE_CAST_INST(40, FPTrunc , FPTruncInst ) // Truncate floating point +HANDLE_CAST_INST(41, FPExt , FPExtInst ) // Extend floating point +HANDLE_CAST_INST(42, PtrToInt, PtrToIntInst) // Pointer -> Integer +HANDLE_CAST_INST(43, IntToPtr, IntToPtrInst) // Integer -> Pointer +HANDLE_CAST_INST(44, BitCast , BitCastInst ) // Type cast + LAST_CAST_INST(44) // Other operators... - FIRST_OTHER_INST(42) -HANDLE_OTHER_INST(42, ICmp , ICmpInst ) // Integer comparison instruction -HANDLE_OTHER_INST(43, FCmp , FCmpInst ) // Floating point comparison instr. -HANDLE_OTHER_INST(44, PHI , PHINode ) // PHI node instruction -HANDLE_OTHER_INST(45, Call , CallInst ) // Call a function -HANDLE_OTHER_INST(46, Select , SelectInst ) // select instruction -HANDLE_OTHER_INST(47, UserOp1, Instruction) // May be used internally in a pass -HANDLE_OTHER_INST(48, UserOp2, Instruction) // Internal to passes only -HANDLE_OTHER_INST(49, VAArg , VAArgInst ) // vaarg instruction -HANDLE_OTHER_INST(50, ExtractElement, ExtractElementInst)// extract from vector -HANDLE_OTHER_INST(51, InsertElement, InsertElementInst) // insert into vector -HANDLE_OTHER_INST(52, ShuffleVector, ShuffleVectorInst) // shuffle two vectors. -HANDLE_OTHER_INST(53, ExtractValue, ExtractValueInst)// extract from aggregate -HANDLE_OTHER_INST(54, InsertValue, InsertValueInst) // insert into aggregate - - LAST_OTHER_INST(54) + FIRST_OTHER_INST(45) +HANDLE_OTHER_INST(45, ICmp , ICmpInst ) // Integer comparison instruction +HANDLE_OTHER_INST(46, FCmp , FCmpInst ) // Floating point comparison instr. +HANDLE_OTHER_INST(47, PHI , PHINode ) // PHI node instruction +HANDLE_OTHER_INST(48, Call , CallInst ) // Call a function +HANDLE_OTHER_INST(49, Select , SelectInst ) // select instruction +HANDLE_OTHER_INST(50, UserOp1, Instruction) // May be used internally in a pass +HANDLE_OTHER_INST(51, UserOp2, Instruction) // Internal to passes only +HANDLE_OTHER_INST(52, VAArg , VAArgInst ) // vaarg instruction +HANDLE_OTHER_INST(53, ExtractElement, ExtractElementInst)// extract from vector +HANDLE_OTHER_INST(54, InsertElement, InsertElementInst) // insert into vector +HANDLE_OTHER_INST(55, ShuffleVector, ShuffleVectorInst) // shuffle two vectors. +HANDLE_OTHER_INST(56, ExtractValue, ExtractValueInst)// extract from aggregate +HANDLE_OTHER_INST(57, InsertValue, InsertValueInst) // insert into aggregate + + LAST_OTHER_INST(57) #undef FIRST_TERM_INST #undef HANDLE_TERM_INST diff --git a/include/llvm/Instructions.h b/include/llvm/Instructions.h index 72d60a3..89eb901 100644 --- a/include/llvm/Instructions.h +++ b/include/llvm/Instructions.h @@ -22,6 +22,7 @@ #include "llvm/CallingConv.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/Support/ErrorHandling.h" #include <iterator> namespace llvm { @@ -31,6 +32,22 @@ class ConstantRange; class APInt; class LLVMContext; +enum AtomicOrdering { + NotAtomic = 0, + Unordered = 1, + Monotonic = 2, + // Consume = 3, // Not specified yet. + Acquire = 4, + Release = 5, + AcquireRelease = 6, + SequentiallyConsistent = 7 +}; + +enum SynchronizationScope { + SingleThread = 0, + CrossThread = 1 +}; + //===----------------------------------------------------------------------===// // AllocaInst Class //===----------------------------------------------------------------------===// @@ -269,6 +286,82 @@ struct OperandTraits<StoreInst> : public FixedNumOperandTraits<StoreInst, 2> { DEFINE_TRANSPARENT_OPERAND_ACCESSORS(StoreInst, Value) //===----------------------------------------------------------------------===// +// FenceInst Class +//===----------------------------------------------------------------------===// + +/// FenceInst - an instruction for ordering other memory operations +/// +class FenceInst : public Instruction { + void *operator new(size_t, unsigned); // DO NOT IMPLEMENT + void Init(AtomicOrdering Ordering, SynchronizationScope SynchScope); +protected: + virtual FenceInst *clone_impl() const; +public: + // allocate space for exactly zero operands + void *operator new(size_t s) { + return User::operator new(s, 0); + } + + // Ordering may only be Acquire, Release, AcquireRelease, or + // SequentiallyConsistent. + FenceInst(LLVMContext &C, AtomicOrdering Ordering, + SynchronizationScope SynchScope = CrossThread, + Instruction *InsertBefore = 0); + FenceInst(LLVMContext &C, AtomicOrdering Ordering, + SynchronizationScope SynchScope, + BasicBlock *InsertAtEnd); + + /// Returns the ordering effect of this fence. + AtomicOrdering getOrdering() const { + return AtomicOrdering(getSubclassDataFromInstruction() >> 1); + } + + /// Set the ordering constraint on this fence. May only be Acquire, Release, + /// AcquireRelease, or SequentiallyConsistent. + void setOrdering(AtomicOrdering Ordering) { + switch (Ordering) { + case Acquire: + case Release: + case AcquireRelease: + case SequentiallyConsistent: + setInstructionSubclassData((getSubclassDataFromInstruction() & 1) | + (Ordering << 1)); + return; + default: + llvm_unreachable("FenceInst ordering must be Acquire, Release," + " AcquireRelease, or SequentiallyConsistent"); + } + } + + SynchronizationScope getSynchScope() const { + return SynchronizationScope(getSubclassDataFromInstruction() & 1); + } + + /// 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); + } + + // Methods for support type inquiry through isa, cast, and dyn_cast: + static inline bool classof(const FenceInst *) { return true; } + static inline bool classof(const Instruction *I) { + return I->getOpcode() == Instruction::Fence; + } + static inline bool classof(const Value *V) { + return isa<Instruction>(V) && classof(cast<Instruction>(V)); + } +private: + // Shadow Instruction::setInstructionSubclassData with a private forwarding + // method so that subclasses cannot accidentally use it. + void setInstructionSubclassData(unsigned short D) { + Instruction::setInstructionSubclassData(D); + } +}; + +//===----------------------------------------------------------------------===// // GetElementPtrInst Class //===----------------------------------------------------------------------===// diff --git a/include/llvm/Support/IRBuilder.h b/include/llvm/Support/IRBuilder.h index caabbb9..0a2800e 100644 --- a/include/llvm/Support/IRBuilder.h +++ b/include/llvm/Support/IRBuilder.h @@ -762,6 +762,10 @@ public: StoreInst *CreateStore(Value *Val, Value *Ptr, bool isVolatile = false) { return Insert(new StoreInst(Val, Ptr, isVolatile)); } + FenceInst *CreateFence(AtomicOrdering Ordering, + SynchronizationScope SynchScope = CrossThread) { + return Insert(new FenceInst(Context, Ordering, SynchScope)); + } Value *CreateGEP(Value *Ptr, ArrayRef<Value *> IdxList, const Twine &Name = "") { if (Constant *PC = dyn_cast<Constant>(Ptr)) { diff --git a/include/llvm/Support/InstVisitor.h b/include/llvm/Support/InstVisitor.h index b2e5d58..83b26f5 100644 --- a/include/llvm/Support/InstVisitor.h +++ b/include/llvm/Support/InstVisitor.h @@ -169,6 +169,7 @@ public: RetTy visitAllocaInst(AllocaInst &I) { DELEGATE(Instruction); } RetTy visitLoadInst(LoadInst &I) { DELEGATE(Instruction); } RetTy visitStoreInst(StoreInst &I) { DELEGATE(Instruction); } + RetTy visitFenceInst(FenceInst &I) { DELEGATE(Instruction); } RetTy visitGetElementPtrInst(GetElementPtrInst &I){ DELEGATE(Instruction); } RetTy visitPHINode(PHINode &I) { DELEGATE(Instruction); } RetTy visitTruncInst(TruncInst &I) { DELEGATE(CastInst); } diff --git a/lib/AsmParser/LLLexer.cpp b/lib/AsmParser/LLLexer.cpp index 29eb944..cdee98b 100644 --- a/lib/AsmParser/LLLexer.cpp +++ b/lib/AsmParser/LLLexer.cpp @@ -506,6 +506,15 @@ lltok::Kind LLLexer::LexIdentifier() { KEYWORD(deplibs); KEYWORD(datalayout); KEYWORD(volatile); + KEYWORD(atomic); + KEYWORD(unordered); + KEYWORD(monotonic); + KEYWORD(acquire); + KEYWORD(release); + KEYWORD(acq_rel); + KEYWORD(seq_cst); + KEYWORD(singlethread); + KEYWORD(nuw); KEYWORD(nsw); KEYWORD(exact); @@ -630,6 +639,7 @@ lltok::Kind LLLexer::LexIdentifier() { INSTKEYWORD(alloca, Alloca); INSTKEYWORD(load, Load); INSTKEYWORD(store, Store); + INSTKEYWORD(fence, Fence); INSTKEYWORD(getelementptr, GetElementPtr); INSTKEYWORD(extractelement, ExtractElement); diff --git a/lib/AsmParser/LLParser.cpp b/lib/AsmParser/LLParser.cpp index 7164ae1..76771c2 100644 --- a/lib/AsmParser/LLParser.cpp +++ b/lib/AsmParser/LLParser.cpp @@ -1145,6 +1145,32 @@ bool LLParser::ParseOptionalCommaAlign(unsigned &Alignment, return false; } +/// ParseScopeAndOrdering +/// if isAtomic: ::= 'singlethread'? AtomicOrdering +/// else: ::= +/// +/// This sets Scope and Ordering to the parsed values. +bool LLParser::ParseScopeAndOrdering(bool isAtomic, SynchronizationScope &Scope, + AtomicOrdering &Ordering) { + if (!isAtomic) + return false; + + Scope = CrossThread; + if (EatIfPresent(lltok::kw_singlethread)) + Scope = SingleThread; + switch (Lex.getKind()) { + default: return TokError("Expected ordering on atomic instruction"); + case lltok::kw_unordered: Ordering = Unordered; break; + case lltok::kw_monotonic: Ordering = Monotonic; break; + case lltok::kw_acquire: Ordering = Acquire; break; + case lltok::kw_release: Ordering = Release; break; + case lltok::kw_acq_rel: Ordering = AcquireRelease; break; + case lltok::kw_seq_cst: Ordering = SequentiallyConsistent; break; + } + Lex.Lex(); + return false; +} + /// ParseOptionalStackAlignment /// ::= /* empty */ /// ::= 'alignstack' '(' 4 ')' @@ -2924,6 +2950,7 @@ int LLParser::ParseInstruction(Instruction *&Inst, BasicBlock *BB, case lltok::kw_alloca: return ParseAlloc(Inst, PFS); case lltok::kw_load: return ParseLoad(Inst, PFS, false); case lltok::kw_store: return ParseStore(Inst, PFS, false); + case lltok::kw_fence: return ParseFence(Inst, PFS); case lltok::kw_volatile: if (EatIfPresent(lltok::kw_load)) return ParseLoad(Inst, PFS, true); @@ -3633,6 +3660,23 @@ int LLParser::ParseStore(Instruction *&Inst, PerFunctionState &PFS, return AteExtraComma ? InstExtraComma : InstNormal; } +/// ParseFence +/// ::= 'fence' 'singlethread'? AtomicOrdering +int LLParser::ParseFence(Instruction *&Inst, PerFunctionState &PFS) { + AtomicOrdering Ordering = NotAtomic; + SynchronizationScope Scope = CrossThread; + if (ParseScopeAndOrdering(true /*Always atomic*/, Scope, Ordering)) + return true; + + if (Ordering == Unordered) + return TokError("fence cannot be unordered"); + if (Ordering == Monotonic) + return TokError("fence cannot be monotonic"); + + Inst = new FenceInst(Context, Ordering, Scope); + return InstNormal; +} + /// ParseGetElementPtr /// ::= 'getelementptr' 'inbounds'? TypeAndValue (',' TypeAndValue)* int LLParser::ParseGetElementPtr(Instruction *&Inst, PerFunctionState &PFS) { diff --git a/lib/AsmParser/LLParser.h b/lib/AsmParser/LLParser.h index 41e42ca..1eaf325 100644 --- a/lib/AsmParser/LLParser.h +++ b/lib/AsmParser/LLParser.h @@ -15,6 +15,7 @@ #define LLVM_ASMPARSER_LLPARSER_H #include "LLLexer.h" +#include "llvm/Instructions.h" #include "llvm/Module.h" #include "llvm/Type.h" #include "llvm/ADT/DenseMap.h" @@ -178,6 +179,8 @@ namespace llvm { bool ParseOptionalVisibility(unsigned &Visibility); bool ParseOptionalCallingConv(CallingConv::ID &CC); bool ParseOptionalAlignment(unsigned &Alignment); + bool ParseScopeAndOrdering(bool isAtomic, SynchronizationScope &Scope, + AtomicOrdering &Ordering); bool ParseOptionalStackAlignment(unsigned &Alignment); bool ParseOptionalCommaAlign(unsigned &Alignment, bool &AteExtraComma); bool ParseIndexList(SmallVectorImpl<unsigned> &Indices,bool &AteExtraComma); @@ -360,6 +363,7 @@ namespace llvm { int ParseAlloc(Instruction *&I, PerFunctionState &PFS); int ParseLoad(Instruction *&I, PerFunctionState &PFS, bool isVolatile); int ParseStore(Instruction *&I, PerFunctionState &PFS, bool isVolatile); + int ParseFence(Instruction *&I, PerFunctionState &PFS); int ParseGetElementPtr(Instruction *&I, PerFunctionState &PFS); int ParseExtractValue(Instruction *&I, PerFunctionState &PFS); int ParseInsertValue(Instruction *&I, PerFunctionState &PFS); diff --git a/lib/AsmParser/LLToken.h b/lib/AsmParser/LLToken.h index a5f89fc..bf41c68 100644 --- a/lib/AsmParser/LLToken.h +++ b/lib/AsmParser/LLToken.h @@ -53,6 +53,9 @@ namespace lltok { kw_deplibs, kw_datalayout, kw_volatile, + kw_atomic, + kw_unordered, kw_monotonic, kw_acquire, kw_release, kw_acq_rel, kw_seq_cst, + kw_singlethread, kw_nuw, kw_nsw, kw_exact, @@ -121,7 +124,7 @@ namespace lltok { kw_ret, kw_br, kw_switch, kw_indirectbr, kw_invoke, kw_unwind, kw_unreachable, - kw_alloca, kw_load, kw_store, kw_getelementptr, + kw_alloca, kw_load, kw_store, kw_fence, kw_getelementptr, kw_extractelement, kw_insertelement, kw_shufflevector, kw_extractvalue, kw_insertvalue, kw_blockaddress, diff --git a/lib/Bitcode/Reader/BitcodeReader.cpp b/lib/Bitcode/Reader/BitcodeReader.cpp index 914c6c1..2029f43 100644 --- a/lib/Bitcode/Reader/BitcodeReader.cpp +++ b/lib/Bitcode/Reader/BitcodeReader.cpp @@ -131,6 +131,27 @@ static int GetDecodedBinaryOpcode(unsigned Val, Type *Ty) { } } +static AtomicOrdering GetDecodedOrdering(unsigned Val) { + switch (Val) { + case bitc::ORDERING_NOTATOMIC: return NotAtomic; + case bitc::ORDERING_UNORDERED: return Unordered; + case bitc::ORDERING_MONOTONIC: return Monotonic; + case bitc::ORDERING_ACQUIRE: return Acquire; + case bitc::ORDERING_RELEASE: return Release; + case bitc::ORDERING_ACQREL: return AcquireRelease; + default: // Map unknown orderings to sequentially-consistent. + case bitc::ORDERING_SEQCST: return SequentiallyConsistent; + } +} + +static SynchronizationScope GetDecodedSynchScope(unsigned Val) { + switch (Val) { + case bitc::SYNCHSCOPE_SINGLETHREAD: return SingleThread; + default: // Map unknown scopes to cross-thread. + case bitc::SYNCHSCOPE_CROSSTHREAD: return CrossThread; + } +} + namespace llvm { namespace { /// @brief A class for maintaining the slot number definition @@ -2534,6 +2555,18 @@ bool BitcodeReader::ParseFunctionBody(Function *F) { InstructionList.push_back(I); break; } + case bitc::FUNC_CODE_INST_FENCE: { // FENCE:[ordering, synchscope] + if (2 != Record.size()) + return Error("Invalid FENCE record"); + AtomicOrdering Ordering = GetDecodedOrdering(Record[0]); + if (Ordering == NotAtomic || Ordering == Unordered || + Ordering == Monotonic) + return Error("Invalid FENCE record"); + SynchronizationScope SynchScope = GetDecodedSynchScope(Record[1]); + I = new FenceInst(Context, Ordering, SynchScope); + InstructionList.push_back(I); + break; + } case bitc::FUNC_CODE_INST_CALL: { // CALL: [paramattrs, cc, fnty, fnid, arg0, arg1...] if (Record.size() < 3) diff --git a/lib/Bitcode/Writer/BitcodeWriter.cpp b/lib/Bitcode/Writer/BitcodeWriter.cpp index 4dfa0ba..9df3c17 100644 --- a/lib/Bitcode/Writer/BitcodeWriter.cpp +++ b/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -101,6 +101,27 @@ static unsigned GetEncodedBinaryOpcode(unsigned Opcode) { } } +static unsigned GetEncodedOrdering(AtomicOrdering Ordering) { + switch (Ordering) { + default: llvm_unreachable("Unknown atomic ordering"); + case NotAtomic: return bitc::ORDERING_NOTATOMIC; + case Unordered: return bitc::ORDERING_UNORDERED; + case Monotonic: return bitc::ORDERING_MONOTONIC; + case Acquire: return bitc::ORDERING_ACQUIRE; + case Release: return bitc::ORDERING_RELEASE; + case AcquireRelease: return bitc::ORDERING_ACQREL; + case SequentiallyConsistent: return bitc::ORDERING_SEQCST; + } +} + +static unsigned GetEncodedSynchScope(SynchronizationScope SynchScope) { + switch (SynchScope) { + default: llvm_unreachable("Unknown synchronization scope"); + case SingleThread: return bitc::SYNCHSCOPE_SINGLETHREAD; + case CrossThread: return bitc::SYNCHSCOPE_CROSSTHREAD; + } +} + static void WriteStringRecord(unsigned Code, StringRef Str, unsigned AbbrevToUse, BitstreamWriter &Stream) { SmallVector<unsigned, 64> Vals; @@ -1147,6 +1168,11 @@ static void WriteInstruction(const Instruction &I, unsigned InstID, Vals.push_back(Log2_32(cast<StoreInst>(I).getAlignment())+1); Vals.push_back(cast<StoreInst>(I).isVolatile()); break; + case Instruction::Fence: + Code = bitc::FUNC_CODE_INST_FENCE; + Vals.push_back(GetEncodedOrdering(cast<FenceInst>(I).getOrdering())); + Vals.push_back(GetEncodedSynchScope(cast<FenceInst>(I).getSynchScope())); + break; case Instruction::Call: { const CallInst &CI = cast<CallInst>(I); PointerType *PTy = cast<PointerType>(CI.getCalledValue()->getType()); diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp index ba18465..649a38a 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ b/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -3211,6 +3211,10 @@ void SelectionDAGBuilder::visitStore(const StoreInst &I) { DAG.setRoot(StoreNode); } +void SelectionDAGBuilder::visitFence(const FenceInst &I) { + llvm_unreachable("Not implemented yet"); +} + /// visitTargetIntrinsic - Lower a call of a target intrinsic to an INTRINSIC /// node. void SelectionDAGBuilder::visitTargetIntrinsic(const CallInst &I, diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h b/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h index a0884eb..d5d106b 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h +++ b/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h @@ -504,6 +504,7 @@ private: void visitAlloca(const AllocaInst &I); void visitLoad(const LoadInst &I); void visitStore(const StoreInst &I); + void visitFence(const FenceInst &I); void visitPHI(const PHINode &I); void visitCall(const CallInst &I); bool visitMemCmpCall(const CallInst &I); diff --git a/lib/VMCore/AsmWriter.cpp b/lib/VMCore/AsmWriter.cpp index 1ce0447..1f8e891 100644 --- a/lib/VMCore/AsmWriter.cpp +++ b/lib/VMCore/AsmWriter.cpp @@ -1098,6 +1098,7 @@ public: void writeOperand(const Value *Op, bool PrintType); void writeParamOperand(const Value *Operand, Attributes Attrs); + void writeAtomic(AtomicOrdering Ordering, SynchronizationScope SynchScope); void writeAllMDNodes(); @@ -1128,6 +1129,28 @@ void AssemblyWriter::writeOperand(const Value *Operand, bool PrintType) { WriteAsOperandInternal(Out, Operand, &TypePrinter, &Machine, TheModule); } +void AssemblyWriter::writeAtomic(AtomicOrdering Ordering, + SynchronizationScope SynchScope) { + if (Ordering == NotAtomic) + return; + + switch (SynchScope) { + default: Out << " <bad scope " << int(SynchScope) << ">"; break; + case SingleThread: Out << " singlethread"; break; + case CrossThread: break; + } + + switch (Ordering) { + default: Out << " <bad ordering " << int(Ordering) << ">"; break; + case Unordered: Out << " unordered"; break; + case Monotonic: Out << " monotonic"; break; + case Acquire: Out << " acquire"; break; + case Release: Out << " release"; break; + case AcquireRelease: Out << " acq_rel"; break; + case SequentiallyConsistent: Out << " seq_cst"; break; + } +} + void AssemblyWriter::writeParamOperand(const Value *Operand, Attributes Attrs) { if (Operand == 0) { @@ -1883,6 +1906,8 @@ void AssemblyWriter::printInstruction(const Instruction &I) { Out << ", align " << cast<LoadInst>(I).getAlignment(); } else if (isa<StoreInst>(I) && cast<StoreInst>(I).getAlignment()) { Out << ", align " << cast<StoreInst>(I).getAlignment(); + } else if (const FenceInst *FI = dyn_cast<FenceInst>(&I)) { + writeAtomic(FI->getOrdering(), FI->getSynchScope()); } // Print Metadata info. diff --git a/lib/VMCore/Instruction.cpp b/lib/VMCore/Instruction.cpp index 4627e71..4597b57 100644 --- a/lib/VMCore/Instruction.cpp +++ b/lib/VMCore/Instruction.cpp @@ -127,6 +127,7 @@ const char *Instruction::getOpcodeName(unsigned OpCode) { case Alloca: return "alloca"; case Load: return "load"; case Store: return "store"; + case Fence: return "fence"; case GetElementPtr: return "getelementptr"; // Convert instructions... diff --git a/lib/VMCore/Instructions.cpp b/lib/VMCore/Instructions.cpp index 6d27689..ba4dae5 100644 --- a/lib/VMCore/Instructions.cpp +++ b/lib/VMCore/Instructions.cpp @@ -996,6 +996,26 @@ void StoreInst::setAlignment(unsigned Align) { } //===----------------------------------------------------------------------===// +// FenceInst Implementation +//===----------------------------------------------------------------------===// + +FenceInst::FenceInst(LLVMContext &C, AtomicOrdering Ordering, + SynchronizationScope SynchScope, + Instruction *InsertBefore) + : Instruction(Type::getVoidTy(C), Fence, 0, 0, InsertBefore) { + setOrdering(Ordering); + setSynchScope(SynchScope); +} + +FenceInst::FenceInst(LLVMContext &C, AtomicOrdering Ordering, + SynchronizationScope SynchScope, + BasicBlock *InsertAtEnd) + : Instruction(Type::getVoidTy(C), Fence, 0, 0, InsertAtEnd) { + setOrdering(Ordering); + setSynchScope(SynchScope); +} + +//===----------------------------------------------------------------------===// // GetElementPtrInst Implementation //===----------------------------------------------------------------------===// @@ -3018,6 +3038,10 @@ StoreInst *StoreInst::clone_impl() const { isVolatile(), getAlignment()); } +FenceInst *FenceInst::clone_impl() const { + return new FenceInst(getContext(), getOrdering(), getSynchScope()); +} + TruncInst *TruncInst::clone_impl() const { return new TruncInst(getOperand(0), getType()); } diff --git a/lib/VMCore/Verifier.cpp b/lib/VMCore/Verifier.cpp index c6b14c0..2b2b815 100644 --- a/lib/VMCore/Verifier.cpp +++ b/lib/VMCore/Verifier.cpp @@ -278,6 +278,7 @@ namespace { void visitUserOp1(Instruction &I); void visitUserOp2(Instruction &I) { visitUserOp1(I); } void visitIntrinsicFunctionCall(Intrinsic::ID ID, CallInst &CI); + void visitFenceInst(FenceInst &FI); void visitAllocaInst(AllocaInst &AI); void visitExtractValueInst(ExtractValueInst &EVI); void visitInsertValueInst(InsertValueInst &IVI); @@ -1315,6 +1316,15 @@ void Verifier::visitAllocaInst(AllocaInst &AI) { visitInstruction(AI); } +void Verifier::visitFenceInst(FenceInst &FI) { + const AtomicOrdering Ordering = FI.getOrdering(); + Assert1(Ordering == Acquire || Ordering == Release || + Ordering == AcquireRelease || Ordering == SequentiallyConsistent, + "fence instructions may only have " + " acquire, release, acq_rel, or seq_cst ordering.", &FI); + visitInstruction(FI); +} + void Verifier::visitExtractValueInst(ExtractValueInst &EVI) { Assert1(ExtractValueInst::getIndexedType(EVI.getAggregateOperand()->getType(), EVI.getIndices()) == |