mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-12-04 01:11:44 +00:00
Initial implementation of 'fence' instruction, the new C++0x-style replacement for llvm.memory.barrier.
This is just a LangRef entry and reading/writing/memory representation; optimizer+codegen support coming soon. llvm-svn: 136009
This commit is contained in:
parent
271216a67b
commit
50291d09da
@ -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>
|
||||
@ -4551,6 +4552,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>
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
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(54)
|
||||
LAST_OTHER_INST(57)
|
||||
|
||||
#undef FIRST_TERM_INST
|
||||
#undef HANDLE_TERM_INST
|
||||
|
@ -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
|
||||
//===----------------------------------------------------------------------===//
|
||||
@ -268,6 +285,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
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -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)) {
|
||||
|
@ -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); }
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
|
@ -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());
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
|
@ -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...
|
||||
|
@ -995,6 +995,26 @@ void StoreInst::setAlignment(unsigned Align) {
|
||||
assert(getAlignment() == Align && "Alignment representation error!");
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// 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());
|
||||
}
|
||||
|
@ -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()) ==
|
||||
|
Loading…
Reference in New Issue
Block a user