diff --git a/include/llvm/CodeGen/MIRYamlMapping.h b/include/llvm/CodeGen/MIRYamlMapping.h index e14a1fd6327..903ba2880ec 100644 --- a/include/llvm/CodeGen/MIRYamlMapping.h +++ b/include/llvm/CodeGen/MIRYamlMapping.h @@ -135,6 +135,7 @@ template <> struct MappingTraits { struct MachineBasicBlock { unsigned ID; StringValue Name; + StringValue IRBlock; unsigned Alignment = 0; bool IsLandingPad = false; bool AddressTaken = false; @@ -149,6 +150,8 @@ template <> struct MappingTraits { YamlIO.mapRequired("id", MBB.ID); YamlIO.mapOptional("name", MBB.Name, StringValue()); // Don't print out an empty name. + YamlIO.mapOptional("ir-block", MBB.IRBlock, + StringValue()); // Don't print out an empty BB reference. YamlIO.mapOptional("alignment", MBB.Alignment); YamlIO.mapOptional("isLandingPad", MBB.IsLandingPad); YamlIO.mapOptional("addressTaken", MBB.AddressTaken); diff --git a/lib/CodeGen/MIRParser/MILexer.cpp b/lib/CodeGen/MIRParser/MILexer.cpp index 2f038ff5684..d730dce6c75 100644 --- a/lib/CodeGen/MIRParser/MILexer.cpp +++ b/lib/CodeGen/MIRParser/MILexer.cpp @@ -219,6 +219,10 @@ static Cursor maybeLexConstantPoolItem(Cursor C, MIToken &Token) { return maybeLexIndex(C, Token, "%const.", MIToken::ConstantPoolItem); } +static Cursor maybeLexIRBlock(Cursor C, MIToken &Token) { + return maybeLexIndex(C, Token, "%ir-block.", MIToken::IRBlock); +} + static Cursor lexVirtualRegister(Cursor C, MIToken &Token) { auto Range = C; C.advance(); // Skip '%' @@ -351,6 +355,8 @@ StringRef llvm::lexMIToken( return R.remaining(); if (Cursor R = maybeLexConstantPoolItem(C, Token)) return R.remaining(); + if (Cursor R = maybeLexIRBlock(C, Token)) + return R.remaining(); if (Cursor R = maybeLexRegister(C, Token)) return R.remaining(); if (Cursor R = maybeLexGlobalValue(C, Token, ErrorCallback)) diff --git a/lib/CodeGen/MIRParser/MILexer.h b/lib/CodeGen/MIRParser/MILexer.h index b84fb743599..06fa1f256dd 100644 --- a/lib/CodeGen/MIRParser/MILexer.h +++ b/lib/CodeGen/MIRParser/MILexer.h @@ -66,7 +66,8 @@ struct MIToken { IntegerLiteral, VirtualRegister, ConstantPoolItem, - JumpTableIndex + JumpTableIndex, + IRBlock, }; private: @@ -132,7 +133,8 @@ public: return Kind == IntegerLiteral || Kind == MachineBasicBlock || Kind == StackObject || Kind == FixedStackObject || Kind == GlobalValue || Kind == VirtualRegister || - Kind == ConstantPoolItem || Kind == JumpTableIndex; + Kind == ConstantPoolItem || Kind == JumpTableIndex || + Kind == IRBlock; } }; diff --git a/lib/CodeGen/MIRParser/MIParser.cpp b/lib/CodeGen/MIRParser/MIParser.cpp index c46adf5c719..1bdaedb5d3a 100644 --- a/lib/CodeGen/MIRParser/MIParser.cpp +++ b/lib/CodeGen/MIRParser/MIParser.cpp @@ -23,6 +23,7 @@ #include "llvm/CodeGen/MachineModuleInfo.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/Module.h" +#include "llvm/IR/ModuleSlotTracker.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/SourceMgr.h" #include "llvm/Target/TargetSubtargetInfo.h" @@ -77,6 +78,8 @@ class MIParser { StringMap Names2RegMasks; /// Maps from subregister names to subregister indices. StringMap Names2SubRegIndices; + /// Maps from slot numbers to function's unnamed basic blocks. + DenseMap Slots2BasicBlocks; public: MIParser(SourceMgr &SM, MachineFunction &MF, SMDiagnostic &Error, @@ -99,6 +102,7 @@ public: bool parseStandaloneMBB(MachineBasicBlock *&MBB); bool parseStandaloneNamedRegister(unsigned &Reg); bool parseStandaloneVirtualRegister(unsigned &Reg); + bool parseStandaloneIRBlockReference(const BasicBlock *&BB); bool parseRegister(unsigned &Reg); bool parseRegisterFlag(unsigned &Flags); @@ -160,6 +164,10 @@ private: /// /// Return 0 if the name isn't a subregister index class. unsigned getSubRegIndex(StringRef Name); + + void initSlots2BasicBlocks(); + + const BasicBlock *getIRBlock(unsigned Slot); }; } // end anonymous namespace @@ -302,6 +310,23 @@ bool MIParser::parseStandaloneVirtualRegister(unsigned &Reg) { return false; } +bool MIParser::parseStandaloneIRBlockReference(const BasicBlock *&BB) { + lex(); + if (Token.isNot(MIToken::IRBlock)) + return error("expected an IR block reference"); + unsigned SlotNumber = 0; + if (getUnsigned(SlotNumber)) + return true; + BB = getIRBlock(SlotNumber); + if (!BB) + return error(Twine("use of undefined IR block '%ir-block.") + + Twine(SlotNumber) + "'"); + lex(); + if (Token.isNot(MIToken::Eof)) + return error("expected end of string after the IR block reference"); + return false; +} + static const char *printImplicitRegisterFlag(const MachineOperand &MO) { assert(MO.isImplicit()); return MO.isDef() ? "implicit-def" : "implicit"; @@ -842,6 +867,30 @@ unsigned MIParser::getSubRegIndex(StringRef Name) { return SubRegInfo->getValue(); } +void MIParser::initSlots2BasicBlocks() { + if (!Slots2BasicBlocks.empty()) + return; + const auto &F = *MF.getFunction(); + ModuleSlotTracker MST(F.getParent()); + MST.incorporateFunction(F); + for (auto &BB : F) { + if (BB.hasName()) + continue; + int Slot = MST.getLocalSlot(&BB); + if (Slot == -1) + continue; + Slots2BasicBlocks.insert(std::make_pair(unsigned(Slot), &BB)); + } +} + +const BasicBlock *MIParser::getIRBlock(unsigned Slot) { + initSlots2BasicBlocks(); + auto BlockInfo = Slots2BasicBlocks.find(Slot); + if (BlockInfo == Slots2BasicBlocks.end()) + return nullptr; + return BlockInfo->second; +} + bool llvm::parseMachineInstr(MachineInstr *&MI, SourceMgr &SM, MachineFunction &MF, StringRef Src, const PerFunctionMIParsingState &PFS, @@ -873,3 +922,12 @@ bool llvm::parseVirtualRegisterReference(unsigned &Reg, SourceMgr &SM, return MIParser(SM, MF, Error, Src, PFS, IRSlots) .parseStandaloneVirtualRegister(Reg); } + +bool llvm::parseIRBlockReference(const BasicBlock *&BB, SourceMgr &SM, + MachineFunction &MF, StringRef Src, + const PerFunctionMIParsingState &PFS, + const SlotMapping &IRSlots, + SMDiagnostic &Error) { + return MIParser(SM, MF, Error, Src, PFS, IRSlots) + .parseStandaloneIRBlockReference(BB); +} diff --git a/lib/CodeGen/MIRParser/MIParser.h b/lib/CodeGen/MIRParser/MIParser.h index 49530f1a36e..92698f6e6d1 100644 --- a/lib/CodeGen/MIRParser/MIParser.h +++ b/lib/CodeGen/MIRParser/MIParser.h @@ -19,6 +19,7 @@ namespace llvm { +class BasicBlock; class MachineBasicBlock; class MachineInstr; class MachineFunction; @@ -56,6 +57,11 @@ bool parseVirtualRegisterReference(unsigned &Reg, SourceMgr &SM, const SlotMapping &IRSlots, SMDiagnostic &Error); +bool parseIRBlockReference(const BasicBlock *&BB, SourceMgr &SM, + MachineFunction &MF, StringRef Src, + const PerFunctionMIParsingState &PFS, + const SlotMapping &IRSlots, SMDiagnostic &Error); + } // end namespace llvm #endif diff --git a/lib/CodeGen/MIRParser/MIRParser.cpp b/lib/CodeGen/MIRParser/MIRParser.cpp index 45b401917a3..f733d633357 100644 --- a/lib/CodeGen/MIRParser/MIRParser.cpp +++ b/lib/CodeGen/MIRParser/MIRParser.cpp @@ -292,6 +292,7 @@ bool MIRParserImpl::initializeMachineFunction(MachineFunction &MF) { for (const auto &YamlMBB : YamlMF.BasicBlocks) { const BasicBlock *BB = nullptr; const yaml::StringValue &Name = YamlMBB.Name; + const yaml::StringValue &IRBlock = YamlMBB.IRBlock; if (!Name.Value.empty()) { BB = dyn_cast_or_null( F.getValueSymbolTable().lookup(Name.Value)); @@ -301,6 +302,12 @@ bool MIRParserImpl::initializeMachineFunction(MachineFunction &MF) { "' is not defined in the function '" + MF.getName() + "'"); } + if (!IRBlock.Value.empty()) { + // TODO: Report an error when both name and ir block are specified. + SMDiagnostic Error; + if (parseIRBlockReference(BB, SM, MF, IRBlock.Value, PFS, IRSlots, Error)) + return error(Error, IRBlock.SourceRange); + } auto *MBB = MF.CreateMachineBasicBlock(BB); MF.insert(MF.end(), MBB); bool WasInserted = diff --git a/lib/CodeGen/MIRPrinter.cpp b/lib/CodeGen/MIRPrinter.cpp index 3db6368b94d..cb20df8eab6 100644 --- a/lib/CodeGen/MIRPrinter.cpp +++ b/lib/CodeGen/MIRPrinter.cpp @@ -163,6 +163,7 @@ void MIRPrinter::print(const MachineFunction &MF) { convert(YamlMF, *ConstantPool); ModuleSlotTracker MST(MF.getFunction()->getParent()); + MST.incorporateFunction(*MF.getFunction()); if (const auto *JumpTableInfo = MF.getJumpTableInfo()) convert(MST, YamlMF.JumpTableInfo, *JumpTableInfo); int I = 0; @@ -336,11 +337,17 @@ void MIRPrinter::convert(ModuleSlotTracker &MST, const MachineBasicBlock &MBB) { assert(MBB.getNumber() >= 0 && "Invalid MBB number"); YamlMBB.ID = (unsigned)MBB.getNumber(); - // TODO: Serialize unnamed BB references. - if (const auto *BB = MBB.getBasicBlock()) - YamlMBB.Name.Value = BB->hasName() ? BB->getName() : ""; - else - YamlMBB.Name.Value = ""; + if (const auto *BB = MBB.getBasicBlock()) { + if (BB->hasName()) { + YamlMBB.Name.Value = BB->getName(); + } else { + int Slot = MST.getLocalSlot(BB); + if (Slot == -1) + YamlMBB.IRBlock.Value = ""; + else + YamlMBB.IRBlock.Value = (Twine("%ir-block.") + Twine(Slot)).str(); + } + } YamlMBB.Alignment = MBB.getAlignment(); YamlMBB.AddressTaken = MBB.hasAddressTaken(); YamlMBB.IsLandingPad = MBB.isLandingPad(); diff --git a/test/CodeGen/MIR/machine-basic-block-expected-ir-block.mir b/test/CodeGen/MIR/machine-basic-block-expected-ir-block.mir new file mode 100644 index 00000000000..2f3d40af792 --- /dev/null +++ b/test/CodeGen/MIR/machine-basic-block-expected-ir-block.mir @@ -0,0 +1,16 @@ +# RUN: not llc -start-after branch-folder -stop-after branch-folder -o /dev/null %s 2>&1 | FileCheck %s + +--- | + + define i32 @foo() { + ret i32 0 + } + +... +--- +name: foo +body: + - id: 0 +# CHECK: [[@LINE+1]]:19: expected an IR block reference + ir-block: '0' +... diff --git a/test/CodeGen/MIR/machine-basic-block-ir-block-reference.mir b/test/CodeGen/MIR/machine-basic-block-ir-block-reference.mir new file mode 100644 index 00000000000..ccbab534388 --- /dev/null +++ b/test/CodeGen/MIR/machine-basic-block-ir-block-reference.mir @@ -0,0 +1,19 @@ +# RUN: llc -start-after branch-folder -stop-after branch-folder -o /dev/null %s | FileCheck %s +# This test ensures that the MIR parser preserves unnamed LLVM IR block +# references. + +--- | + + define i32 @foo() { + ret i32 0 + } + +... +--- +name: foo +body: +# CHECK: id: 0 +# CHECK: ir-block: '%ir-block.0' + - id: 0 + ir-block: '%ir-block.0' +... diff --git a/test/CodeGen/MIR/machine-basic-block-undefined-ir-block.mir b/test/CodeGen/MIR/machine-basic-block-undefined-ir-block.mir new file mode 100644 index 00000000000..76d561e61fa --- /dev/null +++ b/test/CodeGen/MIR/machine-basic-block-undefined-ir-block.mir @@ -0,0 +1,16 @@ +# RUN: not llc -start-after branch-folder -stop-after branch-folder -o /dev/null %s 2>&1 | FileCheck %s + +--- | + + define i32 @foo() { + ret i32 0 + } + +... +--- +name: foo +body: + - id: 0 +# CHECK: [[@LINE+1]]:19: use of undefined IR block '%ir-block.10' + ir-block: '%ir-block.10' +...