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:
Eli Friedman 2011-07-25 23:16:38 +00:00
parent 271216a67b
commit 50291d09da
18 changed files with 392 additions and 32 deletions

View File

@ -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] &lt;ordering&gt; <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>

View File

@ -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

View File

@ -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

View File

@ -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
//===----------------------------------------------------------------------===//

View File

@ -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)) {

View File

@ -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); }

View File

@ -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);

View File

@ -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) {

View File

@ -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);

View File

@ -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,

View File

@ -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)

View File

@ -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());

View File

@ -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,

View File

@ -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);

View File

@ -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.

View File

@ -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...

View File

@ -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());
}

View File

@ -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()) ==