diff options
author | Sanjoy Das <sanjoy@playingwithpointers.com> | 2015-09-24 23:34:52 +0000 |
---|---|---|
committer | Sanjoy Das <sanjoy@playingwithpointers.com> | 2015-09-24 23:34:52 +0000 |
commit | b513a9fa4f1b68d10f658848e5bff39dab4bb8bd (patch) | |
tree | 3433cf0682329f82b9839ceeff71586505b63ab8 /llvm/lib | |
parent | f021808d606eb35434fe54ae3ad2e1992af527b3 (diff) | |
download | bcm5719-llvm-b513a9fa4f1b68d10f658848e5bff39dab4bb8bd.tar.gz bcm5719-llvm-b513a9fa4f1b68d10f658848e5bff39dab4bb8bd.zip |
[Bitcode][Asm] Teach LLVM to read and write operand bundles.
Summary:
This also adds the first set of tests for operand bundles.
The optimizer has not been audited to ensure that it does the right
thing with operand bundles.
Depends on D12456.
Reviewers: reames, chandlerc, majnemer, dexonsmith, kmod, JosephTremoulet, rnk, bogner
Subscribers: maksfb, llvm-commits
Differential Revision: http://reviews.llvm.org/D12457
llvm-svn: 248551
Diffstat (limited to 'llvm/lib')
-rw-r--r-- | llvm/lib/AsmParser/LLParser.cpp | 75 | ||||
-rw-r--r-- | llvm/lib/AsmParser/LLParser.h | 4 | ||||
-rw-r--r-- | llvm/lib/Bitcode/Reader/BitcodeReader.cpp | 82 | ||||
-rw-r--r-- | llvm/lib/Bitcode/Writer/BitcodeWriter.cpp | 55 | ||||
-rw-r--r-- | llvm/lib/IR/AsmWriter.cpp | 43 |
5 files changed, 247 insertions, 12 deletions
diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp index f7c24191746..b99d8579ce3 100644 --- a/llvm/lib/AsmParser/LLParser.cpp +++ b/llvm/lib/AsmParser/LLParser.cpp @@ -1942,7 +1942,61 @@ bool LLParser::ParseParameterList(SmallVectorImpl<ParamInfo> &ArgList, return false; } +/// ParseOptionalOperandBundles +/// ::= /*empty*/ +/// ::= '[' OperandBundle [, OperandBundle ]* ']' +/// +/// OperandBundle +/// ::= bundle-tag '(' ')' +/// ::= bundle-tag '(' Type Value [, Type Value ]* ')' +/// +/// bundle-tag ::= String Constant +bool LLParser::ParseOptionalOperandBundles( + SmallVectorImpl<OperandBundleDef> &BundleList, PerFunctionState &PFS) { + LocTy BeginLoc = Lex.getLoc(); + if (!EatIfPresent(lltok::lsquare)) + return false; + + while (Lex.getKind() != lltok::rsquare) { + // If this isn't the first operand bundle, we need a comma. + if (!BundleList.empty() && + ParseToken(lltok::comma, "expected ',' in input list")) + return true; + + std::string Tag; + if (ParseStringConstant(Tag)) + return true; + + BundleList.emplace_back(); + auto &OBI = BundleList.back(); + OBI.Tag = std::move(Tag); + + if (ParseToken(lltok::lparen, "expected '(' in operand bundle")) + return true; + + while (Lex.getKind() != lltok::rparen) { + // If this isn't the first input, we need a comma. + if (!OBI.Inputs.empty() && + ParseToken(lltok::comma, "expected ',' in input list")) + return true; + + Type *Ty = nullptr; + Value *Input = nullptr; + if (ParseType(Ty) || ParseValue(Ty, Input, PFS)) + return true; + OBI.Inputs.push_back(Input); + } + + Lex.Lex(); // Lex the ')'. + } + + if (BundleList.empty()) + return Error(BeginLoc, "operand bundle set must not be empty"); + + Lex.Lex(); // Lex the ']'. + return false; +} /// ParseArgumentList - Parse the argument list for a function type or function /// prototype. @@ -4991,15 +5045,15 @@ bool LLParser::ParseInvoke(Instruction *&Inst, PerFunctionState &PFS) { LocTy RetTypeLoc; ValID CalleeID; SmallVector<ParamInfo, 16> ArgList; + SmallVector<OperandBundleDef, 2> BundleList; BasicBlock *NormalBB, *UnwindBB; - if (ParseOptionalCallingConv(CC) || - ParseOptionalReturnAttrs(RetAttrs) || + if (ParseOptionalCallingConv(CC) || ParseOptionalReturnAttrs(RetAttrs) || ParseType(RetType, RetTypeLoc, true /*void allowed*/) || - ParseValID(CalleeID) || - ParseParameterList(ArgList, PFS) || + ParseValID(CalleeID) || ParseParameterList(ArgList, PFS) || ParseFnAttributeValuePairs(FnAttrs, FwdRefAttrGrps, false, NoBuiltinLoc) || + ParseOptionalOperandBundles(BundleList, PFS) || ParseToken(lltok::kw_to, "expected 'to' in invoke") || ParseTypeAndBasicBlock(NormalBB, PFS) || ParseToken(lltok::kw_unwind, "expected 'unwind' in invoke") || @@ -5075,7 +5129,8 @@ bool LLParser::ParseInvoke(Instruction *&Inst, PerFunctionState &PFS) { // Finish off the Attribute and check them AttributeSet PAL = AttributeSet::get(Context, Attrs); - InvokeInst *II = InvokeInst::Create(Ty, Callee, NormalBB, UnwindBB, Args); + InvokeInst *II = + InvokeInst::Create(Ty, Callee, NormalBB, UnwindBB, Args, BundleList); II->setCallingConv(CC); II->setAttributes(PAL); ForwardRefAttrGroups[II] = FwdRefAttrGrps; @@ -5589,18 +5644,18 @@ bool LLParser::ParseCall(Instruction *&Inst, PerFunctionState &PFS, LocTy RetTypeLoc; ValID CalleeID; SmallVector<ParamInfo, 16> ArgList; + SmallVector<OperandBundleDef, 2> BundleList; LocTy CallLoc = Lex.getLoc(); if ((TCK != CallInst::TCK_None && ParseToken(lltok::kw_call, "expected 'tail call'")) || - ParseOptionalCallingConv(CC) || - ParseOptionalReturnAttrs(RetAttrs) || + ParseOptionalCallingConv(CC) || ParseOptionalReturnAttrs(RetAttrs) || ParseType(RetType, RetTypeLoc, true /*void allowed*/) || ParseValID(CalleeID) || ParseParameterList(ArgList, PFS, TCK == CallInst::TCK_MustTail, PFS.getFunction().isVarArg()) || - ParseFnAttributeValuePairs(FnAttrs, FwdRefAttrGrps, false, - BuiltinLoc)) + ParseFnAttributeValuePairs(FnAttrs, FwdRefAttrGrps, false, BuiltinLoc) || + ParseOptionalOperandBundles(BundleList, PFS)) return true; // If RetType is a non-function pointer type, then this is the short syntax @@ -5672,7 +5727,7 @@ bool LLParser::ParseCall(Instruction *&Inst, PerFunctionState &PFS, // Finish off the Attribute and check them AttributeSet PAL = AttributeSet::get(Context, Attrs); - CallInst *CI = CallInst::Create(Ty, Callee, Args); + CallInst *CI = CallInst::Create(Ty, Callee, Args, BundleList); CI->setTailCallKind(TCK); CI->setCallingConv(CC); CI->setAttributes(PAL); diff --git a/llvm/lib/AsmParser/LLParser.h b/llvm/lib/AsmParser/LLParser.h index 51ba7dec919..24ff8e75023 100644 --- a/llvm/lib/AsmParser/LLParser.h +++ b/llvm/lib/AsmParser/LLParser.h @@ -406,6 +406,10 @@ namespace llvm { bool IsMustTailCall = false, bool InVarArgsFunc = false); + bool + ParseOptionalOperandBundles(SmallVectorImpl<OperandBundleDef> &BundleList, + PerFunctionState &PFS); + bool ParseExceptionArgs(SmallVectorImpl<Value *> &Args, PerFunctionState &PFS); diff --git a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp index f38f26cd636..165ab6e20c5 100644 --- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp +++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp @@ -226,6 +226,8 @@ class BitcodeReader : public GVMaterializer { bool StripDebugInfo = false; + std::vector<std::string> BundleTags; + public: std::error_code error(BitcodeError E, const Twine &Message); std::error_code error(BitcodeError E); @@ -370,6 +372,7 @@ private: std::error_code parseAttributeGroupBlock(); std::error_code parseTypeTable(); std::error_code parseTypeTableBody(); + std::error_code parseOperandBundleTags(); ErrorOr<Value *> recordValue(SmallVectorImpl<uint64_t> &Record, unsigned NameIndex, Triple &TT); @@ -1586,6 +1589,42 @@ std::error_code BitcodeReader::parseTypeTableBody() { } } +std::error_code BitcodeReader::parseOperandBundleTags() { + if (Stream.EnterSubBlock(bitc::OPERAND_BUNDLE_TAGS_BLOCK_ID)) + return error("Invalid record"); + + if (!BundleTags.empty()) + return error("Invalid multiple blocks"); + + SmallVector<uint64_t, 64> Record; + + while (1) { + BitstreamEntry Entry = Stream.advanceSkippingSubblocks(); + + switch (Entry.Kind) { + case BitstreamEntry::SubBlock: // Handled for us already. + case BitstreamEntry::Error: + return error("Malformed block"); + case BitstreamEntry::EndBlock: + return std::error_code(); + case BitstreamEntry::Record: + // The interesting case. + break; + } + + // Tags are implicitly mapped to integers by their order. + + if (Stream.readRecord(Entry.ID, Record) != bitc::OPERAND_BUNDLE_TAG) + return error("Invalid record"); + + // OPERAND_BUNDLE_TAG: [strchr x N] + BundleTags.emplace_back(); + if (convertToString(Record, 0, BundleTags.back())) + return error("Invalid record"); + Record.clear(); + } +} + /// Associate a value with its name from the given index in the provided record. ErrorOr<Value *> BitcodeReader::recordValue(SmallVectorImpl<uint64_t> &Record, unsigned NameIndex, Triple &TT) { @@ -3019,6 +3058,10 @@ std::error_code BitcodeReader::parseModule(bool Resume, if (std::error_code EC = parseUseLists()) return EC; break; + case bitc::OPERAND_BUNDLE_TAGS_BLOCK_ID: + if (std::error_code EC = parseOperandBundleTags()) + return EC; + break; } continue; @@ -3556,6 +3599,8 @@ std::error_code BitcodeReader::parseFunctionBody(Function *F) { return nullptr; }; + std::vector<OperandBundleDef> OperandBundles; + // Read all the records. SmallVector<uint64_t, 64> Record; while (1) { @@ -4325,7 +4370,8 @@ std::error_code BitcodeReader::parseFunctionBody(Function *F) { } } - I = InvokeInst::Create(Callee, NormalBB, UnwindBB, Ops); + I = InvokeInst::Create(Callee, NormalBB, UnwindBB, Ops, OperandBundles); + OperandBundles.clear(); InstructionList.push_back(I); cast<InvokeInst>(I) ->setCallingConv(static_cast<CallingConv::ID>(~(1U << 13) & CCInfo)); @@ -4708,7 +4754,8 @@ std::error_code BitcodeReader::parseFunctionBody(Function *F) { } } - I = CallInst::Create(FTy, Callee, Args); + I = CallInst::Create(FTy, Callee, Args, OperandBundles); + OperandBundles.clear(); InstructionList.push_back(I); cast<CallInst>(I)->setCallingConv( static_cast<CallingConv::ID>((~(1U << 14) & CCInfo) >> 1)); @@ -4733,6 +4780,30 @@ std::error_code BitcodeReader::parseFunctionBody(Function *F) { InstructionList.push_back(I); break; } + + case bitc::FUNC_CODE_OPERAND_BUNDLE: { + // A call or an invoke can be optionally prefixed with some variable + // number of operand bundle blocks. These blocks are read into + // OperandBundles and consumed at the next call or invoke instruction. + + if (Record.size() < 1 || Record[0] >= BundleTags.size()) + return error("Invalid record"); + + OperandBundles.emplace_back(); + OperandBundles.back().Tag = BundleTags[Record[0]]; + + std::vector<Value *> &Inputs = OperandBundles.back().Inputs; + + unsigned OpNum = 1; + while (OpNum != Record.size()) { + Value *Op; + if (getValueTypePair(Record, OpNum, NextValueNo, Op)) + return error("Invalid record"); + Inputs.push_back(Op); + } + + continue; + } } // Add instruction to end of current BB. If there is no current BB, reject @@ -4741,6 +4812,10 @@ std::error_code BitcodeReader::parseFunctionBody(Function *F) { delete I; return error("Invalid instruction with no BB"); } + if (!OperandBundles.empty()) { + delete I; + return error("Operand bundles found with no consumer"); + } CurBB->getInstList().push_back(I); // If this was a terminator instruction, move to the next block. @@ -4757,6 +4832,9 @@ std::error_code BitcodeReader::parseFunctionBody(Function *F) { OutOfRecordLoop: + if (!OperandBundles.empty()) + return error("Operand bundles found with no consumer"); + // Check the function list for unresolved values. if (Argument *A = dyn_cast<Argument>(ValueList.back())) { if (!A->getParent()) { diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp index 3ab738a2c02..f6455728975 100644 --- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp +++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -16,11 +16,13 @@ #include "llvm/ADT/Triple.h" #include "llvm/Bitcode/BitstreamWriter.h" #include "llvm/Bitcode/LLVMBitCodes.h" +#include "llvm/IR/CallSite.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DebugInfoMetadata.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/InlineAsm.h" #include "llvm/IR/Instructions.h" +#include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" #include "llvm/IR/Operator.h" #include "llvm/IR/UseListOrder.h" @@ -1392,6 +1394,33 @@ static void WriteModuleMetadataStore(const Module *M, BitstreamWriter &Stream) { Stream.ExitBlock(); } +static void WriteOperandBundleTags(const Module *M, BitstreamWriter &Stream) { + // Write metadata kinds + // + // OPERAND_BUNDLE_TAGS_BLOCK_ID : N x OPERAND_BUNDLE_TAG + // + // OPERAND_BUNDLE_TAG - [strchr x N] + + SmallVector<StringRef, 8> Tags; + M->getOperandBundleTags(Tags); + + if (Tags.empty()) + return; + + Stream.EnterSubblock(bitc::OPERAND_BUNDLE_TAGS_BLOCK_ID, 3); + + SmallVector<uint64_t, 64> Record; + + for (auto Tag : Tags) { + Record.append(Tag.begin(), Tag.end()); + + Stream.EmitRecord(bitc::OPERAND_BUNDLE_TAG, Record, 0); + Record.clear(); + } + + Stream.ExitBlock(); +} + static void emitSignedInt64(SmallVectorImpl<uint64_t> &Vals, uint64_t V) { if ((int64_t)V >= 0) Vals.push_back(V << 1); @@ -1700,6 +1729,23 @@ static bool PushValueAndType(const Value *V, unsigned InstID, return false; } +static void WriteOperandBundles(BitstreamWriter &Stream, ImmutableCallSite CS, + unsigned InstID, ValueEnumerator &VE) { + SmallVector<unsigned, 64> Record; + LLVMContext &C = CS.getInstruction()->getContext(); + + for (unsigned i = 0, e = CS.getNumOperandBundles(); i != e; ++i) { + const auto &Bundle = CS.getOperandBundle(i); + Record.push_back(C.getOperandBundleTagID(Bundle.Tag)); + + for (auto &Input : Bundle.Inputs) + PushValueAndType(Input, InstID, Record, VE); + + Stream.EmitRecord(bitc::FUNC_CODE_OPERAND_BUNDLE, Record); + Record.clear(); + } +} + /// pushValue - Like PushValueAndType, but where the type of the value is /// omitted (perhaps it was already encoded in an earlier operand). static void pushValue(const Value *V, unsigned InstID, @@ -1862,6 +1908,10 @@ static void WriteInstruction(const Instruction &I, unsigned InstID, const InvokeInst *II = cast<InvokeInst>(&I); const Value *Callee = II->getCalledValue(); FunctionType *FTy = II->getFunctionType(); + + if (II->hasOperandBundles()) + WriteOperandBundles(Stream, II, InstID, VE); + Code = bitc::FUNC_CODE_INST_INVOKE; Vals.push_back(VE.getAttributeID(II->getAttributes())); @@ -2071,6 +2121,9 @@ static void WriteInstruction(const Instruction &I, unsigned InstID, const CallInst &CI = cast<CallInst>(I); FunctionType *FTy = CI.getFunctionType(); + if (CI.hasOperandBundles()) + WriteOperandBundles(Stream, &CI, InstID, VE); + Code = bitc::FUNC_CODE_INST_CALL; Vals.push_back(VE.getAttributeID(CI.getAttributes())); @@ -2591,6 +2644,8 @@ static void WriteModule(const Module *M, BitstreamWriter &Stream, if (VE.shouldPreserveUseListOrder()) WriteUseListBlock(nullptr, VE, Stream); + WriteOperandBundleTags(M, Stream); + // Emit function bodies. DenseMap<const Function *, uint64_t> FunctionIndex; for (Module::const_iterator F = M->begin(), E = M->end(); F != E; ++F) diff --git a/llvm/lib/IR/AsmWriter.cpp b/llvm/lib/IR/AsmWriter.cpp index 3aeabf8bf17..3387657129c 100644 --- a/llvm/lib/IR/AsmWriter.cpp +++ b/llvm/lib/IR/AsmWriter.cpp @@ -2022,6 +2022,7 @@ public: void writeOperand(const Value *Op, bool PrintType); void writeParamOperand(const Value *Operand, AttributeSet Attrs,unsigned Idx); + void writeOperandBundles(ImmutableCallSite CS); void writeAtomic(AtomicOrdering Ordering, SynchronizationScope SynchScope); void writeAtomicCmpXchg(AtomicOrdering SuccessOrdering, AtomicOrdering FailureOrdering, @@ -2157,6 +2158,43 @@ void AssemblyWriter::writeParamOperand(const Value *Operand, WriteAsOperandInternal(Out, Operand, &TypePrinter, &Machine, TheModule); } +void AssemblyWriter::writeOperandBundles(ImmutableCallSite CS) { + if (!CS.hasOperandBundles()) + return; + + Out << " [ "; + + bool FirstBundle = true; + for (unsigned i = 0, e = CS.getNumOperandBundles(); i != e; ++i) { + OperandBundleUse BU = CS.getOperandBundle(i); + + if (!FirstBundle) + Out << ", "; + FirstBundle = false; + + Out << '"'; + PrintEscapedString(BU.Tag, Out); + Out << '"'; + + Out << '('; + + bool FirstInput = true; + for (const auto &Input : BU.Inputs) { + if (!FirstInput) + Out << ", "; + FirstInput = false; + + TypePrinter.print(Input->getType(), Out); + Out << " "; + WriteAsOperandInternal(Out, Input, &TypePrinter, &Machine, TheModule); + } + + Out << ')'; + } + + Out << " ]"; +} + void AssemblyWriter::printModule(const Module *M) { Machine.initialize(); @@ -2944,6 +2982,9 @@ void AssemblyWriter::printInstruction(const Instruction &I) { Out << ')'; if (PAL.hasAttributes(AttributeSet::FunctionIndex)) Out << " #" << Machine.getAttributeGroupSlot(PAL.getFnAttributes()); + + writeOperandBundles(CI); + } else if (const InvokeInst *II = dyn_cast<InvokeInst>(&I)) { Operand = II->getCalledValue(); FunctionType *FTy = cast<FunctionType>(II->getFunctionType()); @@ -2978,6 +3019,8 @@ void AssemblyWriter::printInstruction(const Instruction &I) { if (PAL.hasAttributes(AttributeSet::FunctionIndex)) Out << " #" << Machine.getAttributeGroupSlot(PAL.getFnAttributes()); + writeOperandBundles(II); + Out << "\n to "; writeOperand(II->getNormalDest(), true); Out << " unwind "; |