diff --git a/include/llvm/Bitcode/LLVMBitCodes.h b/include/llvm/Bitcode/LLVMBitCodes.h index 2f967d6c9ad..dccd8e035d7 100644 --- a/include/llvm/Bitcode/LLVMBitCodes.h +++ b/include/llvm/Bitcode/LLVMBitCodes.h @@ -34,7 +34,8 @@ namespace bitc { FUNCTION_BLOCK_ID, TYPE_SYMTAB_BLOCK_ID, VALUE_SYMTAB_BLOCK_ID, - METADATA_BLOCK_ID + METADATA_BLOCK_ID, + METADATA_ATTACHMENT_ID }; @@ -111,7 +112,9 @@ namespace bitc { METADATA_STRING = 1, // MDSTRING: [values] METADATA_NODE = 2, // MDNODE: [n x (type num, value num)] METADATA_NAME = 3, // STRING: [values] - METADATA_NAMED_NODE = 4 // NAMEDMDNODE: [n x mdnodes] + METADATA_NAMED_NODE = 4, // NAMEDMDNODE: [n x mdnodes] + METADATA_KIND = 5, // [n x [id, name]] + METADATA_ATTACHMENT = 6 // [m x [value, [n x [id, mdnode]]] }; // The constants block (CONSTANTS_BLOCK_ID) describes emission for each // constant and maintains an implicit current type value. diff --git a/include/llvm/Metadata.h b/include/llvm/Metadata.h index a2394beb400..21f907a371c 100644 --- a/include/llvm/Metadata.h +++ b/include/llvm/Metadata.h @@ -311,13 +311,14 @@ public: /// MDKindID - This id identifies metadata kind the metadata store. Valid /// ID values are 1 or higher. This ID is set by RegisterMDKind. typedef unsigned MDKindID; + class Metadata { public: typedef std::pair MDPairTy; typedef SmallVector MDMapTy; - -private: typedef DenseMap MDStoreTy; + friend class BitcodeReader; +private: /// MetadataStore - Collection of metadata used in this context. MDStoreTy MetadataStore; @@ -344,6 +345,10 @@ public: /// setMD - Attach the metadata of given kind with an Instruction. void setMD(MDKindID Kind, MDNode *Node, Instruction *Inst); + /// getHandlerNames - Get handler names. This is used by bitcode + /// writer. + const StringMap *getHandlerNames(); + /// ValueIsDeleted - This handler is used to update metadata store /// when a value is deleted. void ValueIsDeleted(Value *V) {} diff --git a/lib/Bitcode/Reader/BitcodeReader.cpp b/lib/Bitcode/Reader/BitcodeReader.cpp index b217c188868..70d2fc5907e 100644 --- a/lib/Bitcode/Reader/BitcodeReader.cpp +++ b/lib/Bitcode/Reader/BitcodeReader.cpp @@ -830,6 +830,22 @@ bool BitcodeReader::ParseMetadata() { MDValueList.AssignValue(V, NextValueNo++); break; } + case bitc::METADATA_KIND: { + unsigned RecordLength = Record.size(); + if (Record.empty() || RecordLength < 2) + return Error("Invalid METADATA_KIND record"); + SmallString<8> Name; + Name.resize(RecordLength-1); + MDKindID Kind = Record[0]; + for (unsigned i = 1; i != RecordLength; ++i) + Name[i-1] = Record[i]; + Metadata &TheMetadata = Context.getMetadata(); + assert(TheMetadata.MDHandlerNames.find(Name.str()) + == TheMetadata.MDHandlerNames.end() && + "Already registered MDKind!"); + TheMetadata.MDHandlerNames[Name.str()] = Kind; + break; + } } } } @@ -1535,6 +1551,45 @@ bool BitcodeReader::ParseBitcode() { return false; } +/// ParseMetadataAttachment - Parse metadata attachments. +bool BitcodeReader::ParseMetadataAttachment() { + if (Stream.EnterSubBlock(bitc::METADATA_ATTACHMENT_ID)) + return Error("Malformed block record"); + + Metadata &TheMetadata = Context.getMetadata(); + SmallVector Record; + while(1) { + unsigned Code = Stream.ReadCode(); + if (Code == bitc::END_BLOCK) { + if (Stream.ReadBlockEnd()) + return Error("Error at end of PARAMATTR block"); + break; + } + if (Code == bitc::DEFINE_ABBREV) { + Stream.ReadAbbrevRecord(); + continue; + } + // Read a metadata attachment record. + Record.clear(); + switch (Stream.ReadRecord(Code, Record)) { + default: // Default behavior: ignore. + break; + case bitc::METADATA_ATTACHMENT: { + unsigned RecordLength = Record.size(); + if (Record.empty() || (RecordLength - 1) % 2 == 1) + return Error ("Invalid METADATA_ATTACHMENT reader!"); + Instruction *Inst = InstructionList[Record[0]]; + for (unsigned i = 1; i != RecordLength; i = i+2) { + MDKindID Kind = Record[i]; + Value *Node = MDValueList.getValueFwdRef(Record[i+1]); + TheMetadata.setMD(Kind, cast(Node), Inst); + } + break; + } + } + } + return false; +} /// ParseFunctionBody - Lazily parse the specified function body block. bool BitcodeReader::ParseFunctionBody(Function *F) { @@ -1574,6 +1629,9 @@ bool BitcodeReader::ParseFunctionBody(Function *F) { case bitc::VALUE_SYMTAB_BLOCK_ID: if (ParseValueSymbolTable()) return true; break; + case bitc::METADATA_ATTACHMENT_ID: + if (ParseMetadataAttachment()) return true; + break; } continue; } @@ -1611,6 +1669,7 @@ bool BitcodeReader::ParseFunctionBody(Function *F) { int Opc = GetDecodedBinaryOpcode(Record[OpNum++], LHS->getType()); if (Opc == -1) return Error("Invalid BINOP record"); I = BinaryOperator::Create((Instruction::BinaryOps)Opc, LHS, RHS); + InstructionList.push_back(I); if (OpNum < Record.size()) { if (Opc == Instruction::Add || Opc == Instruction::Sub || @@ -1638,6 +1697,7 @@ bool BitcodeReader::ParseFunctionBody(Function *F) { if (Opc == -1 || ResTy == 0) return Error("Invalid CAST record"); I = CastInst::Create((Instruction::CastOps)Opc, Op, ResTy); + InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_INBOUNDS_GEP: @@ -1656,6 +1716,7 @@ bool BitcodeReader::ParseFunctionBody(Function *F) { } I = GetElementPtrInst::Create(BasePtr, GEPIdx.begin(), GEPIdx.end()); + InstructionList.push_back(I); if (BitCode == bitc::FUNC_CODE_INST_INBOUNDS_GEP) cast(I)->setIsInBounds(true); break; @@ -1679,6 +1740,7 @@ bool BitcodeReader::ParseFunctionBody(Function *F) { I = ExtractValueInst::Create(Agg, EXTRACTVALIdx.begin(), EXTRACTVALIdx.end()); + InstructionList.push_back(I); break; } @@ -1703,6 +1765,7 @@ bool BitcodeReader::ParseFunctionBody(Function *F) { I = InsertValueInst::Create(Agg, Val, INSERTVALIdx.begin(), INSERTVALIdx.end()); + InstructionList.push_back(I); break; } @@ -1717,6 +1780,7 @@ bool BitcodeReader::ParseFunctionBody(Function *F) { return Error("Invalid SELECT record"); I = SelectInst::Create(Cond, TrueVal, FalseVal); + InstructionList.push_back(I); break; } @@ -1743,6 +1807,7 @@ bool BitcodeReader::ParseFunctionBody(Function *F) { } I = SelectInst::Create(Cond, TrueVal, FalseVal); + InstructionList.push_back(I); break; } @@ -1753,6 +1818,7 @@ bool BitcodeReader::ParseFunctionBody(Function *F) { getValue(Record, OpNum, Type::getInt32Ty(Context), Idx)) return Error("Invalid EXTRACTELT record"); I = ExtractElementInst::Create(Vec, Idx); + InstructionList.push_back(I); break; } @@ -1765,6 +1831,7 @@ bool BitcodeReader::ParseFunctionBody(Function *F) { getValue(Record, OpNum, Type::getInt32Ty(Context), Idx)) return Error("Invalid INSERTELT record"); I = InsertElementInst::Create(Vec, Elt, Idx); + InstructionList.push_back(I); break; } @@ -1778,6 +1845,7 @@ bool BitcodeReader::ParseFunctionBody(Function *F) { if (getValueTypePair(Record, OpNum, NextValueNo, Mask)) return Error("Invalid SHUFFLEVEC record"); I = new ShuffleVectorInst(Vec1, Vec2, Mask); + InstructionList.push_back(I); break; } @@ -1799,6 +1867,7 @@ bool BitcodeReader::ParseFunctionBody(Function *F) { I = new FCmpInst((FCmpInst::Predicate)Record[OpNum], LHS, RHS); else I = new ICmpInst((ICmpInst::Predicate)Record[OpNum], LHS, RHS); + InstructionList.push_back(I); break; } @@ -1810,6 +1879,7 @@ bool BitcodeReader::ParseFunctionBody(Function *F) { getValueTypePair(Record, OpNum, NextValueNo, Op); unsigned Index = Record[1]; I = ExtractValueInst::Create(Op, Index); + InstructionList.push_back(I); break; } @@ -1818,6 +1888,7 @@ bool BitcodeReader::ParseFunctionBody(Function *F) { unsigned Size = Record.size(); if (Size == 0) { I = ReturnInst::Create(Context); + InstructionList.push_back(I); break; } @@ -1837,15 +1908,18 @@ bool BitcodeReader::ParseFunctionBody(Function *F) { Value *RV = UndefValue::get(ReturnType); for (unsigned i = 0, e = Vs.size(); i != e; ++i) { I = InsertValueInst::Create(RV, Vs[i], i, "mrv"); + InstructionList.push_back(I); CurBB->getInstList().push_back(I); ValueList.AssignValue(I, NextValueNo++); RV = I; } I = ReturnInst::Create(Context, RV); + InstructionList.push_back(I); break; } I = ReturnInst::Create(Context, Vs[0]); + InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_BR: { // BR: [bb#, bb#, opval] or [bb#] @@ -1855,14 +1929,17 @@ bool BitcodeReader::ParseFunctionBody(Function *F) { if (TrueDest == 0) return Error("Invalid BR record"); - if (Record.size() == 1) + if (Record.size() == 1) { I = BranchInst::Create(TrueDest); + InstructionList.push_back(I); + } else { BasicBlock *FalseDest = getBasicBlock(Record[1]); Value *Cond = getFnValueByID(Record[2], Type::getInt1Ty(Context)); if (FalseDest == 0 || Cond == 0) return Error("Invalid BR record"); I = BranchInst::Create(TrueDest, FalseDest, Cond); + InstructionList.push_back(I); } break; } @@ -1876,6 +1953,7 @@ bool BitcodeReader::ParseFunctionBody(Function *F) { return Error("Invalid SWITCH record"); unsigned NumCases = (Record.size()-3)/2; SwitchInst *SI = SwitchInst::Create(Cond, Default, NumCases); + InstructionList.push_back(SI); for (unsigned i = 0, e = NumCases; i != e; ++i) { ConstantInt *CaseVal = dyn_cast_or_null(getFnValueByID(Record[3+i*2], OpTy)); @@ -1933,6 +2011,7 @@ bool BitcodeReader::ParseFunctionBody(Function *F) { I = InvokeInst::Create(Callee, NormalBB, UnwindBB, Ops.begin(), Ops.end()); + InstructionList.push_back(I); cast(I)->setCallingConv( static_cast(CCInfo)); cast(I)->setAttributes(PAL); @@ -1940,9 +2019,11 @@ bool BitcodeReader::ParseFunctionBody(Function *F) { } case bitc::FUNC_CODE_INST_UNWIND: // UNWIND I = new UnwindInst(Context); + InstructionList.push_back(I); break; case bitc::FUNC_CODE_INST_UNREACHABLE: // UNREACHABLE I = new UnreachableInst(Context); + InstructionList.push_back(I); break; case bitc::FUNC_CODE_INST_PHI: { // PHI: [ty, val0,bb0, ...] if (Record.size() < 1 || ((Record.size()-1)&1)) @@ -1951,6 +2032,7 @@ bool BitcodeReader::ParseFunctionBody(Function *F) { if (!Ty) return Error("Invalid PHI record"); PHINode *PN = PHINode::Create(Ty); + InstructionList.push_back(PN); PN->reserveOperandSpace((Record.size()-1)/2); for (unsigned i = 0, e = Record.size()-1; i != e; i += 2) { @@ -1972,6 +2054,7 @@ bool BitcodeReader::ParseFunctionBody(Function *F) { unsigned Align = Record[2]; if (!Ty || !Size) return Error("Invalid MALLOC record"); I = new MallocInst(Ty->getElementType(), Size, (1 << Align) >> 1); + InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_FREE: { // FREE: [op, opty] @@ -1981,6 +2064,7 @@ bool BitcodeReader::ParseFunctionBody(Function *F) { OpNum != Record.size()) return Error("Invalid FREE record"); I = new FreeInst(Op); + InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_ALLOCA: { // ALLOCA: [instty, op, align] @@ -1992,6 +2076,7 @@ bool BitcodeReader::ParseFunctionBody(Function *F) { unsigned Align = Record[2]; if (!Ty || !Size) return Error("Invalid ALLOCA record"); I = new AllocaInst(Ty->getElementType(), Size, (1 << Align) >> 1); + InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_LOAD: { // LOAD: [opty, op, align, vol] @@ -2002,6 +2087,7 @@ bool BitcodeReader::ParseFunctionBody(Function *F) { return Error("Invalid LOAD record"); I = new LoadInst(Op, "", Record[OpNum+1], (1 << Record[OpNum]) >> 1); + InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_STORE2: { // STORE2:[ptrty, ptr, val, align, vol] @@ -2014,6 +2100,7 @@ bool BitcodeReader::ParseFunctionBody(Function *F) { return Error("Invalid STORE record"); I = new StoreInst(Val, Ptr, Record[OpNum+1], (1 << Record[OpNum]) >> 1); + InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_STORE: { // STORE:[val, valty, ptr, align, vol] @@ -2027,6 +2114,7 @@ bool BitcodeReader::ParseFunctionBody(Function *F) { return Error("Invalid STORE record"); I = new StoreInst(Val, Ptr, Record[OpNum+1], (1 << Record[OpNum]) >> 1); + InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_CALL: { @@ -2072,6 +2160,7 @@ bool BitcodeReader::ParseFunctionBody(Function *F) { } I = CallInst::Create(Callee, Args.begin(), Args.end()); + InstructionList.push_back(I); cast(I)->setCallingConv( static_cast(CCInfo>>1)); cast(I)->setTailCall(CCInfo & 1); @@ -2087,6 +2176,7 @@ bool BitcodeReader::ParseFunctionBody(Function *F) { if (!OpTy || !Op || !ResTy) return Error("Invalid VAARG record"); I = new VAArgInst(Op, ResTy); + InstructionList.push_back(I); break; } } diff --git a/lib/Bitcode/Reader/BitcodeReader.h b/lib/Bitcode/Reader/BitcodeReader.h index a7853abbc98..eefc7bdc28a 100644 --- a/lib/Bitcode/Reader/BitcodeReader.h +++ b/lib/Bitcode/Reader/BitcodeReader.h @@ -132,6 +132,8 @@ class BitcodeReader : public ModuleProvider { std::vector TypeList; BitcodeReaderValueList ValueList; BitcodeReaderMDValueList MDValueList; + SmallVector InstructionList; + std::vector > GlobalInits; std::vector > AliasInits; @@ -250,6 +252,7 @@ private: bool ParseFunctionBody(Function *F); bool ResolveGlobalAndAliasInits(); bool ParseMetadata(); + bool ParseMetadataAttachment(); }; } // End llvm namespace diff --git a/lib/Bitcode/Writer/BitcodeWriter.cpp b/lib/Bitcode/Writer/BitcodeWriter.cpp index 9cb57585762..3d89f3d0f00 100644 --- a/lib/Bitcode/Writer/BitcodeWriter.cpp +++ b/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -551,7 +551,74 @@ static void WriteModuleMetadata(const ValueEnumerator &VE, } if (StartedMetadataBlock) - Stream.ExitBlock(); + Stream.ExitBlock(); +} + +static void WriteMetadataAttachment(const Function &F, + const ValueEnumerator &VE, + BitstreamWriter &Stream) { + bool StartedMetadataBlock = false; + SmallVector Record; + + // Write metadata attachments + // METADATA_ATTACHMENT - [m x [value, [n x [id, mdnode]]] + Metadata &TheMetadata = F.getContext().getMetadata(); + for (Function::const_iterator BB = F.begin(), E = F.end(); BB != E; ++BB) + for (BasicBlock::const_iterator I = BB->begin(), E = BB->end(); + I != E; ++I) { + const Metadata::MDMapTy *P = TheMetadata.getMDs(I); + if (!P) continue; + bool RecordedInstruction = false; + for (Metadata::MDMapTy::const_iterator PI = P->begin(), PE = P->end(); + PI != PE; ++PI) { + if (MDNode *ND = dyn_cast_or_null(PI->second)) { + if (RecordedInstruction == false) { + Record.push_back(VE.getInstructionID(I)); + RecordedInstruction = true; + } + Record.push_back(PI->first); + Record.push_back(VE.getValueID(ND)); + } + } + if (!StartedMetadataBlock) { + Stream.EnterSubblock(bitc::METADATA_ATTACHMENT_ID, 3); + StartedMetadataBlock = true; + } + Stream.EmitRecord(bitc::METADATA_ATTACHMENT, Record, 0); + Record.clear(); + } + + if (StartedMetadataBlock) + Stream.ExitBlock(); +} + +static void WriteModuleMetadataStore(const Module *M, + const ValueEnumerator &VE, + BitstreamWriter &Stream) { + + bool StartedMetadataBlock = false; + SmallVector Record; + + // Write metadata kinds + // METADATA_KIND - [n x [id, name]] + Metadata &TheMetadata = M->getContext().getMetadata(); + const StringMap *Kinds = TheMetadata.getHandlerNames(); + for (StringMap::const_iterator + I = Kinds->begin(), E = Kinds->end(); I != E; ++I) { + Record.push_back(I->second); + StringRef KName = I->first(); + for (unsigned i = 0, e = KName.size(); i != e; ++i) + Record.push_back(KName[i]); + if (!StartedMetadataBlock) { + Stream.EnterSubblock(bitc::METADATA_BLOCK_ID, 3); + StartedMetadataBlock = true; + } + Stream.EmitRecord(bitc::METADATA_KIND, Record, 0); + Record.clear(); + } + + if (StartedMetadataBlock) + Stream.ExitBlock(); } static void WriteConstants(unsigned FirstVal, unsigned LastVal, @@ -833,6 +900,7 @@ static void WriteInstruction(const Instruction &I, unsigned InstID, SmallVector &Vals) { unsigned Code = 0; unsigned AbbrevToUse = 0; + VE.setInstructionID(&I); switch (I.getOpcode()) { default: if (Instruction::isCast(I.getOpcode())) { @@ -1146,7 +1214,8 @@ static void WriteFunction(const Function &F, ValueEnumerator &VE, // Emit names for all the instructions etc. WriteValueSymbolTable(F.getValueSymbolTable(), VE, Stream); - + + WriteMetadataAttachment(F, VE, Stream); VE.purgeFunction(); Stream.ExitBlock(); } @@ -1390,6 +1459,9 @@ static void WriteModule(const Module *M, BitstreamWriter &Stream) { for (Module::const_iterator I = M->begin(), E = M->end(); I != E; ++I) if (!I->isDeclaration()) WriteFunction(*I, VE, Stream); + + // Emit metadata. + WriteModuleMetadataStore(M, VE, Stream); // Emit the type symbol table information. WriteTypeSymbolTable(M->getTypeSymbolTable(), VE, Stream); diff --git a/lib/Bitcode/Writer/ValueEnumerator.cpp b/lib/Bitcode/Writer/ValueEnumerator.cpp index 783022cac29..f4682a2f637 100644 --- a/lib/Bitcode/Writer/ValueEnumerator.cpp +++ b/lib/Bitcode/Writer/ValueEnumerator.cpp @@ -40,6 +40,8 @@ static bool CompareByFrequency(const std::pairglobal_begin(), E = M->global_end(); I != E; ++I) @@ -83,7 +85,8 @@ ValueEnumerator::ValueEnumerator(const Module *M) { for (Function::const_arg_iterator I = F->arg_begin(), E = F->arg_end(); I != E; ++I) EnumerateType(I->getType()); - + + Metadata &TheMetadata = F->getContext().getMetadata(); for (Function::const_iterator BB = F->begin(), E = F->end(); BB != E; ++BB) for (BasicBlock::const_iterator I = BB->begin(), E = BB->end(); I!=E;++I){ for (User::const_op_iterator OI = I->op_begin(), E = I->op_end(); @@ -94,6 +97,14 @@ ValueEnumerator::ValueEnumerator(const Module *M) { EnumerateAttributes(CI->getAttributes()); else if (const InvokeInst *II = dyn_cast(I)) EnumerateAttributes(II->getAttributes()); + + // Enumerate metadata attached with this instruction. + const Metadata::MDMapTy *MDs = TheMetadata.getMDs(I); + if (MDs) + for (Metadata::MDMapTy::const_iterator MI = MDs->begin(), + ME = MDs->end(); MI != ME; ++MI) + if (MDNode *MDN = dyn_cast_or_null(MI->second)) + EnumerateMetadata(MDN); } } @@ -114,6 +125,16 @@ ValueEnumerator::ValueEnumerator(const Module *M) { TypeMap[Types[i].first] = i+1; } +unsigned ValueEnumerator::getInstructionID(const Instruction *Inst) const { + InstructionMapType::const_iterator I = InstructionMap.find(Inst); + assert (I != InstructionMap.end() && "Instruction is not mapped!"); + return I->second; +} + +void ValueEnumerator::setInstructionID(const Instruction *I) { + InstructionMap[I] = InstructionCount++; +} + unsigned ValueEnumerator::getValueID(const Value *V) const { if (isa(V)) { ValueMapType::const_iterator I = MDValueMap.find(V); diff --git a/lib/Bitcode/Writer/ValueEnumerator.h b/lib/Bitcode/Writer/ValueEnumerator.h index b5106f0809f..da63dde2a27 100644 --- a/lib/Bitcode/Writer/ValueEnumerator.h +++ b/lib/Bitcode/Writer/ValueEnumerator.h @@ -22,6 +22,7 @@ namespace llvm { class Type; class Value; +class Instruction; class BasicBlock; class Function; class Module; @@ -47,11 +48,15 @@ private: ValueList Values; ValueList MDValues; ValueMapType MDValueMap; - + typedef DenseMap AttributeMapType; AttributeMapType AttributeMap; std::vector Attributes; + typedef DenseMap InstructionMapType; + InstructionMapType InstructionMap; + unsigned InstructionCount; + /// BasicBlocks - This contains all the basic blocks for the currently /// incorporated function. Their reverse mapping is stored in ValueMap. std::vector BasicBlocks; @@ -74,7 +79,10 @@ public: assert(I != TypeMap.end() && "Type not in ValueEnumerator!"); return I->second-1; } - + + unsigned getInstructionID(const Instruction *I) const; + void setInstructionID(const Instruction *I); + unsigned getAttributeID(const AttrListPtr &PAL) const { if (PAL.isEmpty()) return 0; // Null maps to zero. AttributeMapType::const_iterator I = AttributeMap.find(PAL.getRawPointer()); diff --git a/lib/VMCore/Metadata.cpp b/lib/VMCore/Metadata.cpp index 2c80a60a8cf..8ae584e9207 100644 --- a/lib/VMCore/Metadata.cpp +++ b/lib/VMCore/Metadata.cpp @@ -317,6 +317,12 @@ const Metadata::MDMapTy *Metadata::getMDs(const Instruction *Inst) { return &(I->second); } +/// getHandlerNames - Get handler names. This is used by bitcode +/// writer. +const StringMap *Metadata::getHandlerNames() { + return &MDHandlerNames; +} + /// ValueIsDeleted - This handler is used to update metadata store /// when a value is deleted. void Metadata::ValueIsDeleted(const Instruction *Inst) { diff --git a/test/Feature/md_on_instruction2.ll b/test/Feature/md_on_instruction2.ll new file mode 100644 index 00000000000..f5bd513e4c6 --- /dev/null +++ b/test/Feature/md_on_instruction2.ll @@ -0,0 +1,22 @@ +; RUN: llvm-as < %s | llvm-dis | grep " dbg " | count 4 +define i32 @foo() nounwind ssp { +entry: + %retval = alloca i32 ; [#uses=2] + call void @llvm.dbg.func.start(metadata !0) + store i32 42, i32* %retval, dbg !3 + br label %0, dbg !3 + +;