Index: include/llvm/CodeGen/MIRYamlMapping.h =================================================================== --- include/llvm/CodeGen/MIRYamlMapping.h +++ include/llvm/CodeGen/MIRYamlMapping.h @@ -64,6 +64,7 @@ namespace yaml { struct MachineBasicBlock { + unsigned Number; std::string Name; unsigned Alignment = 0; bool IsLandingPad = false; @@ -75,6 +76,7 @@ template <> struct MappingTraits { static void mapping(IO &YamlIO, MachineBasicBlock &MBB) { + YamlIO.mapRequired("number", MBB.Number); YamlIO.mapOptional("name", MBB.Name, std::string()); // Don't print out an empty name. YamlIO.mapOptional("alignment", MBB.Alignment); Index: lib/CodeGen/MIRParser/MILexer.h =================================================================== --- lib/CodeGen/MIRParser/MILexer.h +++ lib/CodeGen/MIRParser/MILexer.h @@ -39,6 +39,7 @@ // Identifier tokens Identifier, NamedRegister, + MachineBasicBlock, // Other tokens IntegerLiteral @@ -46,14 +47,17 @@ private: TokenKind Kind; + unsigned StringOffset; StringRef Range; APSInt IntVal; public: - MIToken(TokenKind Kind, StringRef Range) : Kind(Kind), Range(Range) {} + MIToken(TokenKind Kind, StringRef Range, unsigned StringOffset = 0) + : Kind(Kind), StringOffset(StringOffset), Range(Range) {} - MIToken(TokenKind Kind, StringRef Range, const APSInt &IntVal) - : Kind(Kind), Range(Range), IntVal(IntVal) {} + MIToken(TokenKind Kind, StringRef Range, const APSInt &IntVal, + unsigned StringOffset = 0) + : Kind(Kind), StringOffset(StringOffset), Range(Range), IntVal(IntVal) {} TokenKind kind() const { return Kind; } @@ -69,9 +73,13 @@ StringRef::iterator location() const { return Range.begin(); } - StringRef stringValue() const { return Range; } + StringRef stringValue() const { return Range.drop_front(StringOffset); } const APSInt &integerValue() const { return IntVal; } + + bool hasIntegerValue() const { + return Kind == IntegerLiteral || Kind == MachineBasicBlock; + } }; /// Consume a single machine instruction token in the given source and return Index: lib/CodeGen/MIRParser/MILexer.cpp =================================================================== --- lib/CodeGen/MIRParser/MILexer.cpp +++ lib/CodeGen/MIRParser/MILexer.cpp @@ -35,7 +35,7 @@ char peek(unsigned I = 0) const { return End - Ptr <= I ? 0 : Ptr[I]; } - void advance() { ++Ptr; } + void advance(unsigned I = 1) { Ptr += I; } StringRef remaining() const { return StringRef(Ptr, End - Ptr); } @@ -70,12 +70,39 @@ return C; } +static Cursor lexMachineBasicBlock( + Cursor C, MIToken &Token, + function_ref ErrorCallback) { + auto Range = C; + C.advance(4); // Skip '%bb.' + if (!isdigit(C.peek())) { + Token = MIToken(MIToken::Error, C.remaining()); + ErrorCallback(C.location(), "expected a number after '%bb.'"); + return C; + } + auto NumberRange = C; + while (isdigit(C.peek())) + C.advance(); + StringRef Number = NumberRange.upto(C); + unsigned StringOffset = 4 + Number.size(); // Drop '%bb.' + if (C.peek() == '.') { + C.advance(); // Skip '.' + ++StringOffset; + while (isIdentifierChar(C.peek())) + C.advance(); + } + Token = MIToken(MIToken::MachineBasicBlock, Range.upto(C), APSInt(Number), + StringOffset); + return C; +} + static Cursor lexPercent(Cursor C, MIToken &Token) { auto Range = C; C.advance(); // Skip '%' while (isIdentifierChar(C.peek())) C.advance(); - Token = MIToken(MIToken::NamedRegister, Range.upto(C)); + Token = MIToken(MIToken::NamedRegister, Range.upto(C), + /*StringOffset=*/1); // Drop the '%' return C; } @@ -119,8 +146,11 @@ auto Char = C.peek(); if (isalpha(Char) || Char == '_') return lexIdentifier(C, Token).remaining(); - if (Char == '%') + if (Char == '%') { + if (C.remaining().startswith("%bb.")) + return lexMachineBasicBlock(C, Token, ErrorCallback).remaining(); return lexPercent(C, Token).remaining(); + } if (isdigit(Char) || (Char == '-' && isdigit(C.peek(1)))) return lexIntegerLiteral(C, Token).remaining(); MIToken::TokenKind Kind = symbolToken(Char); Index: lib/CodeGen/MIRParser/MIParser.h =================================================================== --- lib/CodeGen/MIRParser/MIParser.h +++ lib/CodeGen/MIRParser/MIParser.h @@ -14,17 +14,21 @@ #ifndef LLVM_LIB_CODEGEN_MIRPARSER_MIPARSER_H #define LLVM_LIB_CODEGEN_MIRPARSER_MIPARSER_H +#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/StringRef.h" namespace llvm { +class MachineBasicBlock; class MachineInstr; class MachineFunction; class SMDiagnostic; class SourceMgr; -MachineInstr *parseMachineInstr(SourceMgr &SM, MachineFunction &MF, - StringRef Src, SMDiagnostic &Error); +MachineInstr * +parseMachineInstr(SourceMgr &SM, MachineFunction &MF, StringRef Src, + const DenseMap &MBBMapping, + SMDiagnostic &Error); } // end namespace llvm Index: lib/CodeGen/MIRParser/MIParser.cpp =================================================================== --- lib/CodeGen/MIRParser/MIParser.cpp +++ lib/CodeGen/MIRParser/MIParser.cpp @@ -32,6 +32,8 @@ SMDiagnostic &Error; StringRef Source, CurrentSource; MIToken Token; + /// Maps from basic block numbers to MBBs. + const DenseMap &MBBMapping; /// Maps from instruction names to op codes. StringMap Names2InstrOpCodes; /// Maps from register names to registers. @@ -39,7 +41,8 @@ public: MIParser(SourceMgr &SM, MachineFunction &MF, SMDiagnostic &Error, - StringRef Source); + StringRef Source, + const DenseMap &MBBMapping); void lex(); @@ -58,9 +61,15 @@ bool parseRegister(unsigned &Reg); bool parseRegisterOperand(MachineOperand &Dest, bool IsDef = false); bool parseImmediateOperand(MachineOperand &Dest); + bool parseMBBOperand(MachineOperand &Dest); bool parseMachineOperand(MachineOperand &Dest); private: + /// Convert the integer literal in the current token into an unsigned integer. + /// + /// Return true if an error occurred. + bool getUnsigned(unsigned &Result); + void initNames2InstrOpCodes(); /// Try to convert an instruction name to an opcode. Return true if the @@ -79,9 +88,10 @@ } // end anonymous namespace MIParser::MIParser(SourceMgr &SM, MachineFunction &MF, SMDiagnostic &Error, - StringRef Source) + StringRef Source, + const DenseMap &MBBMapping) : SM(SM), MF(MF), Error(Error), Source(Source), CurrentSource(Source), - Token(MIToken::Error, StringRef()) {} + Token(MIToken::Error, StringRef()), MBBMapping(MBBMapping) {} void MIParser::lex() { CurrentSource = lexMIToken( @@ -178,7 +188,7 @@ Reg = 0; break; case MIToken::NamedRegister: { - StringRef Name = Token.stringValue().drop_front(1); // Drop the '%' + StringRef Name = Token.stringValue(); if (getRegisterByName(Name, Reg)) return error(Twine("unknown register name '") + Name + "'"); break; @@ -212,6 +222,34 @@ return false; } +bool MIParser::getUnsigned(unsigned &Result) { + assert(Token.hasIntegerValue() && "Expected a token with an integer value"); + const uint64_t Limit = uint64_t(std::numeric_limits::max()) + 1; + uint64_t Val64 = Token.integerValue().getLimitedValue(Limit); + if (Val64 == Limit) + return error("expected 32-bit integer (too large)"); + Result = Val64; + return false; +} + +bool MIParser::parseMBBOperand(MachineOperand &Dest) { + assert(Token.is(MIToken::MachineBasicBlock)); + unsigned Number; + if (getUnsigned(Number)) + return true; + auto MBBInfo = MBBMapping.find(Number); + if (MBBInfo == MBBMapping.end()) + return error(Twine("use of undefined machine basic block #") + + Twine(Number)); + MachineBasicBlock *MBB = MBBInfo->second; + if (!Token.stringValue().empty() && Token.stringValue() != MBB->getName()) + return error(Twine("the name of machine basic block #") + Twine(Number) + + " isn't '" + Token.stringValue() + "'"); + Dest = MachineOperand::CreateMBB(MBB); + lex(); + return false; +} + bool MIParser::parseMachineOperand(MachineOperand &Dest) { switch (Token.kind()) { case MIToken::underscore: @@ -219,6 +257,8 @@ return parseRegisterOperand(Dest); case MIToken::IntegerLiteral: return parseImmediateOperand(Dest); + case MIToken::MachineBasicBlock: + return parseMBBOperand(Dest); case MIToken::Error: return true; default: @@ -271,7 +311,9 @@ return false; } -MachineInstr *llvm::parseMachineInstr(SourceMgr &SM, MachineFunction &MF, - StringRef Src, SMDiagnostic &Error) { - return MIParser(SM, MF, Error, Src).parse(); +MachineInstr *llvm::parseMachineInstr( + SourceMgr &SM, MachineFunction &MF, StringRef Src, + const DenseMap &MBBMapping, + SMDiagnostic &Error) { + return MIParser(SM, MF, Error, Src, MBBMapping).parse(); } Index: lib/CodeGen/MIRParser/MIRParser.cpp =================================================================== --- lib/CodeGen/MIRParser/MIRParser.cpp +++ lib/CodeGen/MIRParser/MIRParser.cpp @@ -14,6 +14,7 @@ #include "llvm/CodeGen/MIRParser/MIRParser.h" #include "MIParser.h" +#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/STLExtras.h" @@ -80,8 +81,10 @@ /// Initialize the machine basic block using it's YAML representation. /// /// Return true if an error occurred. - bool initializeMachineBasicBlock(MachineFunction &MF, MachineBasicBlock &MBB, - const yaml::MachineBasicBlock &YamlMBB); + bool initializeMachineBasicBlock( + MachineFunction &MF, MachineBasicBlock &MBB, + const yaml::MachineBasicBlock &YamlMBB, + const DenseMap &MBBMapping); private: /// Return a MIR diagnostic converted from an MI string diagnostic. @@ -213,6 +216,7 @@ MF.setExposesReturnsTwice(YamlMF.ExposesReturnsTwice); MF.setHasInlineAsm(YamlMF.HasInlineAsm); const auto &F = *MF.getFunction(); + DenseMap MBBMapping; for (const auto &YamlMBB : YamlMF.BasicBlocks) { const BasicBlock *BB = nullptr; if (!YamlMBB.Name.empty()) { @@ -224,7 +228,19 @@ } auto *MBB = MF.CreateMachineBasicBlock(BB); MF.insert(MF.end(), MBB); - if (initializeMachineBasicBlock(MF, *MBB, YamlMBB)) + bool WasInserted = + MBBMapping.insert(std::make_pair(YamlMBB.Number, MBB)).second; + if (!WasInserted) + return error(Twine("redefinition of machine basic block with number ") + + Twine(YamlMBB.Number)); + } + + // Initialize the machine basic blocks after creating them all so that the + // machine instructions parser can resolve the MBB references. + unsigned I = 0; + for (const auto &YamlMBB : YamlMF.BasicBlocks) { + if (initializeMachineBasicBlock(MF, *MF.getBlockNumbered(I++), YamlMBB, + MBBMapping)) return true; } return false; @@ -232,7 +248,8 @@ bool MIRParserImpl::initializeMachineBasicBlock( MachineFunction &MF, MachineBasicBlock &MBB, - const yaml::MachineBasicBlock &YamlMBB) { + const yaml::MachineBasicBlock &YamlMBB, + const DenseMap &MBBMapping) { MBB.setAlignment(YamlMBB.Alignment); if (YamlMBB.AddressTaken) MBB.setHasAddressTaken(); @@ -240,7 +257,8 @@ // Parse the instructions. for (const auto &MISource : YamlMBB.Instructions) { SMDiagnostic Error; - if (auto *MI = parseMachineInstr(SM, MF, MISource.Value, Error)) { + if (auto *MI = + parseMachineInstr(SM, MF, MISource.Value, MBBMapping, Error)) { MBB.insert(MBB.end(), MI); continue; } Index: lib/CodeGen/MIRPrinter.cpp =================================================================== --- lib/CodeGen/MIRPrinter.cpp +++ lib/CodeGen/MIRPrinter.cpp @@ -78,7 +78,15 @@ YamlMF.Alignment = MF.getAlignment(); YamlMF.ExposesReturnsTwice = MF.exposesReturnsTwice(); YamlMF.HasInlineAsm = MF.hasInlineAsm(); + + int I = 0; for (const auto &MBB : MF) { + // TODO: Allow printing of non sequentially numbered MBBs. + // This is currently needed as the basic block references get their index + // from MBB.getNumber(), thus it should be sequential so that the parser can + // map back to the correct MBBs when parsing the output. + assert(MBB.getNumber() == I++ && + "Can't print MBBs that aren't sequentially numbered"); yaml::MachineBasicBlock YamlMBB; convert(YamlMBB, MBB); YamlMF.BasicBlocks.push_back(YamlMBB); @@ -89,6 +97,8 @@ void MIRPrinter::convert(yaml::MachineBasicBlock &YamlMBB, const MachineBasicBlock &MBB) { + assert(MBB.getNumber() >= 0 && "Invalid MBB number"); + YamlMBB.Number = (unsigned)MBB.getNumber(); // TODO: Serialize unnamed BB references. if (const auto *BB = MBB.getBasicBlock()) YamlMBB.Name = BB->hasName() ? BB->getName() : ""; @@ -163,6 +173,13 @@ case MachineOperand::MO_Immediate: OS << Op.getImm(); break; + case MachineOperand::MO_MachineBasicBlock: + OS << "%bb." << Op.getMBB()->getNumber(); + if (const auto *BB = Op.getMBB()->getBasicBlock()) { + if (BB->hasName()) + OS << '.' << BB->getName(); + } + break; default: // TODO: Print the other machine operands. llvm_unreachable("Can't print this machine operand at the moment"); Index: test/CodeGen/MIR/X86/expected-machine-operand.mir =================================================================== --- test/CodeGen/MIR/X86/expected-machine-operand.mir +++ test/CodeGen/MIR/X86/expected-machine-operand.mir @@ -11,7 +11,8 @@ --- name: foo body: - - name: entry + - number: 0 + name: entry instructions: # CHECK: [[@LINE+1]]:24: expected a machine operand - '%eax = XOR32rr =' Index: test/CodeGen/MIR/X86/expected-number-after-bb.mir =================================================================== --- /dev/null +++ test/CodeGen/MIR/X86/expected-number-after-bb.mir @@ -0,0 +1,37 @@ +# RUN: not llc -march=x86-64 -start-after branch-folder -stop-after branch-folder -o /dev/null %s 2>&1 | FileCheck %s + +--- | + + define i32 @foo(i32* %p) { + entry: + %a = load i32, i32* %p + %b = icmp sle i32 %a, 10 + br i1 %b, label %yes, label %nah + + yes: + ret i32 0 + + nah: + ret i32 %a + } + +... +--- +name: foo +body: + - number: 0 + name: entry + instructions: + - '%eax = MOV32rm %rdi, 1, _, 0, _' + - 'CMP32ri8 %eax, 10' + # CHECK: [[@LINE+1]]:18: expected a number after '%bb.' + - 'JG_1 %bb.nah' + - number: 1 + name: yes + instructions: + - '%eax = MOV32r0' + - number: 2 + name: nah + instructions: + - 'RETQ %eax' +... Index: test/CodeGen/MIR/X86/immediate-operands.mir =================================================================== --- test/CodeGen/MIR/X86/immediate-operands.mir +++ test/CodeGen/MIR/X86/immediate-operands.mir @@ -18,7 +18,8 @@ # CHECK: name: foo name: foo body: - - name: entry + - number: 0 + name: entry instructions: # CHECK: - '%eax = MOV32ri 42' # CHECK-NEXT: - 'RETQ %eax' @@ -29,7 +30,8 @@ # CHECK: name: bar name: bar body: - - name: entry + - number: 0 + name: entry instructions: # CHECK: - '%eax = MOV32ri -11' # CHECK-NEXT: - 'RETQ %eax' Index: test/CodeGen/MIR/X86/large-index-number-error.mir =================================================================== --- /dev/null +++ test/CodeGen/MIR/X86/large-index-number-error.mir @@ -0,0 +1,35 @@ +# RUN: not llc -march=x86-64 -start-after branch-folder -stop-after branch-folder -o /dev/null %s 2>&1 | FileCheck %s + +--- | + + define i32 @foo(i32* %p) { + entry: + %a = load i32, i32* %p + %b = icmp sle i32 %a, 10 + br i1 %b, label %0, label %1 + + ;