Index: llvm/trunk/lib/CodeGen/MIRParser/MILexer.h =================================================================== --- llvm/trunk/lib/CodeGen/MIRParser/MILexer.h +++ llvm/trunk/lib/CodeGen/MIRParser/MILexer.h @@ -40,6 +40,8 @@ Identifier, NamedRegister, MachineBasicBlock, + NamedGlobalValue, + GlobalValue, // Other tokens IntegerLiteral @@ -78,7 +80,8 @@ const APSInt &integerValue() const { return IntVal; } bool hasIntegerValue() const { - return Kind == IntegerLiteral || Kind == MachineBasicBlock; + return Kind == IntegerLiteral || Kind == MachineBasicBlock || + Kind == GlobalValue; } }; Index: llvm/trunk/lib/CodeGen/MIRParser/MILexer.cpp =================================================================== --- llvm/trunk/lib/CodeGen/MIRParser/MILexer.cpp +++ llvm/trunk/lib/CodeGen/MIRParser/MILexer.cpp @@ -106,6 +106,25 @@ return C; } +static Cursor lexGlobalValue(Cursor C, MIToken &Token) { + auto Range = C; + C.advance(); // Skip the '@' + // TODO: add support for quoted names. + if (!isdigit(C.peek())) { + while (isIdentifierChar(C.peek())) + C.advance(); + Token = MIToken(MIToken::NamedGlobalValue, Range.upto(C), + /*StringOffset=*/1); // Drop the '@' + return C; + } + auto NumberRange = C; + while (isdigit(C.peek())) + C.advance(); + Token = + MIToken(MIToken::GlobalValue, Range.upto(C), APSInt(NumberRange.upto(C))); + return C; +} + static Cursor lexIntegerLiteral(Cursor C, MIToken &Token) { auto Range = C; C.advance(); @@ -151,6 +170,8 @@ return lexMachineBasicBlock(C, Token, ErrorCallback).remaining(); return lexPercent(C, Token).remaining(); } + if (Char == '@') + return lexGlobalValue(C, Token).remaining(); if (isdigit(Char) || (Char == '-' && isdigit(C.peek(1)))) return lexIntegerLiteral(C, Token).remaining(); MIToken::TokenKind Kind = symbolToken(Char); Index: llvm/trunk/lib/CodeGen/MIRParser/MIParser.h =================================================================== --- llvm/trunk/lib/CodeGen/MIRParser/MIParser.h +++ llvm/trunk/lib/CodeGen/MIRParser/MIParser.h @@ -22,13 +22,14 @@ class MachineBasicBlock; class MachineInstr; class MachineFunction; +struct SlotMapping; class SMDiagnostic; class SourceMgr; MachineInstr * parseMachineInstr(SourceMgr &SM, MachineFunction &MF, StringRef Src, const DenseMap &MBBSlots, - SMDiagnostic &Error); + const SlotMapping &IRSlots, SMDiagnostic &Error); } // end namespace llvm Index: llvm/trunk/lib/CodeGen/MIRParser/MIParser.cpp =================================================================== --- llvm/trunk/lib/CodeGen/MIRParser/MIParser.cpp +++ llvm/trunk/lib/CodeGen/MIRParser/MIParser.cpp @@ -14,9 +14,11 @@ #include "MIParser.h" #include "MILexer.h" #include "llvm/ADT/StringMap.h" +#include "llvm/AsmParser/SlotMapping.h" #include "llvm/CodeGen/MachineBasicBlock.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineInstr.h" +#include "llvm/IR/Module.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/SourceMgr.h" #include "llvm/Target/TargetSubtargetInfo.h" @@ -34,6 +36,8 @@ MIToken Token; /// Maps from basic block numbers to MBBs. const DenseMap &MBBSlots; + /// Maps from indices to unnamed global values and metadata nodes. + const SlotMapping &IRSlots; /// Maps from instruction names to op codes. StringMap Names2InstrOpCodes; /// Maps from register names to registers. @@ -42,7 +46,8 @@ public: MIParser(SourceMgr &SM, MachineFunction &MF, SMDiagnostic &Error, StringRef Source, - const DenseMap &MBBSlots); + const DenseMap &MBBSlots, + const SlotMapping &IRSlots); void lex(); @@ -62,6 +67,7 @@ bool parseRegisterOperand(MachineOperand &Dest, bool IsDef = false); bool parseImmediateOperand(MachineOperand &Dest); bool parseMBBOperand(MachineOperand &Dest); + bool parseGlobalAddressOperand(MachineOperand &Dest); bool parseMachineOperand(MachineOperand &Dest); private: @@ -89,9 +95,11 @@ MIParser::MIParser(SourceMgr &SM, MachineFunction &MF, SMDiagnostic &Error, StringRef Source, - const DenseMap &MBBSlots) + const DenseMap &MBBSlots, + const SlotMapping &IRSlots) : SM(SM), MF(MF), Error(Error), Source(Source), CurrentSource(Source), - Token(MIToken::Error, StringRef()), MBBSlots(MBBSlots) {} + Token(MIToken::Error, StringRef()), MBBSlots(MBBSlots), IRSlots(IRSlots) { +} void MIParser::lex() { CurrentSource = lexMIToken( @@ -250,6 +258,36 @@ return false; } +bool MIParser::parseGlobalAddressOperand(MachineOperand &Dest) { + switch (Token.kind()) { + case MIToken::NamedGlobalValue: { + auto Name = Token.stringValue(); + const Module *M = MF.getFunction()->getParent(); + if (const auto *GV = M->getNamedValue(Name)) { + Dest = MachineOperand::CreateGA(GV, /*Offset=*/0); + break; + } + return error(Twine("use of undefined global value '@") + Name + "'"); + } + case MIToken::GlobalValue: { + unsigned GVIdx; + if (getUnsigned(GVIdx)) + return true; + if (GVIdx >= IRSlots.GlobalValues.size()) + return error(Twine("use of undefined global value '@") + Twine(GVIdx) + + "'"); + Dest = MachineOperand::CreateGA(IRSlots.GlobalValues[GVIdx], + /*Offset=*/0); + break; + } + default: + llvm_unreachable("The current token should be a global value"); + } + // TODO: Parse offset and target flags. + lex(); + return false; +} + bool MIParser::parseMachineOperand(MachineOperand &Dest) { switch (Token.kind()) { case MIToken::underscore: @@ -259,6 +297,9 @@ return parseImmediateOperand(Dest); case MIToken::MachineBasicBlock: return parseMBBOperand(Dest); + case MIToken::GlobalValue: + case MIToken::NamedGlobalValue: + return parseGlobalAddressOperand(Dest); case MIToken::Error: return true; default: @@ -314,6 +355,6 @@ MachineInstr * llvm::parseMachineInstr(SourceMgr &SM, MachineFunction &MF, StringRef Src, const DenseMap &MBBSlots, - SMDiagnostic &Error) { - return MIParser(SM, MF, Error, Src, MBBSlots).parse(); + const SlotMapping &IRSlots, SMDiagnostic &Error) { + return MIParser(SM, MF, Error, Src, MBBSlots, IRSlots).parse(); } Index: llvm/trunk/lib/CodeGen/MIRParser/MIRParser.cpp =================================================================== --- llvm/trunk/lib/CodeGen/MIRParser/MIRParser.cpp +++ llvm/trunk/lib/CodeGen/MIRParser/MIRParser.cpp @@ -19,6 +19,7 @@ #include "llvm/ADT/StringMap.h" #include "llvm/ADT/STLExtras.h" #include "llvm/AsmParser/Parser.h" +#include "llvm/AsmParser/SlotMapping.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/CodeGen/MIRYamlMapping.h" @@ -46,6 +47,7 @@ StringRef Filename; LLVMContext &Context; StringMap> Functions; + SlotMapping IRSlots; public: MIRParserImpl(std::unique_ptr Contents, StringRef Filename, @@ -157,7 +159,7 @@ dyn_cast_or_null(In.getCurrentNode())) { SMDiagnostic Error; M = parseAssembly(MemoryBufferRef(BSN->getValue(), Filename), Error, - Context); + Context, &IRSlots); if (!M) { reportDiagnostic(diagFromLLVMAssemblyDiag(Error, BSN->getSourceRange())); return M; @@ -263,7 +265,8 @@ // Parse the instructions. for (const auto &MISource : YamlMBB.Instructions) { SMDiagnostic Error; - if (auto *MI = parseMachineInstr(SM, MF, MISource.Value, MBBSlots, Error)) { + if (auto *MI = parseMachineInstr(SM, MF, MISource.Value, MBBSlots, IRSlots, + Error)) { MBB.insert(MBB.end(), MI); continue; } Index: llvm/trunk/lib/CodeGen/MIRPrinter.cpp =================================================================== --- llvm/trunk/lib/CodeGen/MIRPrinter.cpp +++ llvm/trunk/lib/CodeGen/MIRPrinter.cpp @@ -40,16 +40,18 @@ void print(const MachineFunction &MF); void convert(yaml::MachineFunction &MF, const MachineRegisterInfo &RegInfo); - void convert(yaml::MachineBasicBlock &YamlMBB, const MachineBasicBlock &MBB); + void convert(const Module &M, yaml::MachineBasicBlock &YamlMBB, + const MachineBasicBlock &MBB); }; /// This class prints out the machine instructions using the MIR serialization /// format. class MIPrinter { + const Module &M; raw_ostream &OS; public: - MIPrinter(raw_ostream &OS) : OS(OS) {} + MIPrinter(const Module &M, raw_ostream &OS) : M(M), OS(OS) {} void print(const MachineInstr &MI); void print(const MachineOperand &Op, const TargetRegisterInfo *TRI); @@ -83,6 +85,7 @@ convert(YamlMF, MF.getRegInfo()); int I = 0; + const auto &M = *MF.getFunction()->getParent(); 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 @@ -92,7 +95,7 @@ "Can't print MBBs that aren't sequentially numbered"); (void)I; yaml::MachineBasicBlock YamlMBB; - convert(YamlMBB, MBB); + convert(M, YamlMBB, MBB); YamlMF.BasicBlocks.push_back(YamlMBB); } yaml::Output Out(OS); @@ -106,7 +109,7 @@ MF.TracksSubRegLiveness = RegInfo.subRegLivenessEnabled(); } -void MIRPrinter::convert(yaml::MachineBasicBlock &YamlMBB, +void MIRPrinter::convert(const Module &M, yaml::MachineBasicBlock &YamlMBB, const MachineBasicBlock &MBB) { assert(MBB.getNumber() >= 0 && "Invalid MBB number"); YamlMBB.ID = (unsigned)MBB.getNumber(); @@ -124,7 +127,7 @@ std::string Str; for (const auto &MI : MBB) { raw_string_ostream StrOS(Str); - MIPrinter(StrOS).print(MI); + MIPrinter(M, StrOS).print(MI); YamlMBB.Instructions.push_back(StrOS.str()); Str.clear(); } @@ -191,6 +194,13 @@ OS << '.' << BB->getName(); } break; + case MachineOperand::MO_GlobalAddress: + // FIXME: Make this faster - print as operand will create a slot tracker to + // print unnamed values for the whole module every time it's called, which + // is inefficient. + Op.getGlobal()->printAsOperand(OS, /*PrintType=*/false, &M); + // TODO: Print offset and target flags. + break; default: // TODO: Print the other machine operands. llvm_unreachable("Can't print this machine operand at the moment"); Index: llvm/trunk/test/CodeGen/MIR/X86/global-value-operands.mir =================================================================== --- llvm/trunk/test/CodeGen/MIR/X86/global-value-operands.mir +++ llvm/trunk/test/CodeGen/MIR/X86/global-value-operands.mir @@ -0,0 +1,49 @@ +# RUN: llc -march=x86-64 -start-after branch-folder -stop-after branch-folder -o /dev/null %s | FileCheck %s +# This test ensures that the MIR parser parses global value operands correctly. + +--- | + + @G = external global i32 + @0 = external global i32 + + define i32 @inc() { + entry: + %a = load i32, i32* @G + %b = add i32 %a, 1 + ret i32 %b + } + + define i32 @inc2() { + entry: + %a = load i32, i32* @0 + %b = add i32 %a, 1 + ret i32 %b + } + +... +--- +# CHECK: name: inc +name: inc +body: + - id: 0 + name: entry + instructions: + # CHECK: - '%rax = MOV64rm %rip, 1, _, @G, _' + - '%rax = MOV64rm %rip, 1, _, @G, _' + - '%eax = MOV32rm %rax, 1, _, 0, _' + - '%eax = INC32r %eax' + - 'RETQ %eax' +... +--- +# CHECK: name: inc2 +name: inc2 +body: + - id: 0 + name: entry + instructions: + # CHECK: - '%rax = MOV64rm %rip, 1, _, @0, _' + - '%rax = MOV64rm %rip, 1, _, @0, _' + - '%eax = MOV32rm %rax, 1, _, 0, _' + - '%eax = INC32r %eax' + - 'RETQ %eax' +... Index: llvm/trunk/test/CodeGen/MIR/X86/undefined-global-value.mir =================================================================== --- llvm/trunk/test/CodeGen/MIR/X86/undefined-global-value.mir +++ llvm/trunk/test/CodeGen/MIR/X86/undefined-global-value.mir @@ -0,0 +1,28 @@ +# RUN: not llc -march=x86-64 -start-after branch-folder -stop-after branch-folder -o /dev/null %s 2>&1 | FileCheck %s +# This test ensures that an error is reported when an invalid global value index +# is used. + +--- | + + @0 = external global i32 + + define i32 @inc() { + entry: + %a = load i32, i32* @0 + %b = add i32 %a, 1 + ret i32 %b + } + +... +--- +name: inc +body: + - id: 0 + name: entry + instructions: + # CHECK: [[@LINE+1]]:37: use of undefined global value '@2' + - '%rax = MOV64rm %rip, 1, _, @2, _' + - '%eax = MOV32rm %rax, 1, _, 0, _' + - '%eax = INC32r %eax' + - 'RETQ %eax' +... Index: llvm/trunk/test/CodeGen/MIR/X86/undefined-named-global-value.mir =================================================================== --- llvm/trunk/test/CodeGen/MIR/X86/undefined-named-global-value.mir +++ llvm/trunk/test/CodeGen/MIR/X86/undefined-named-global-value.mir @@ -0,0 +1,28 @@ +# RUN: not llc -march=x86-64 -start-after branch-folder -stop-after branch-folder -o /dev/null %s 2>&1 | FileCheck %s +# This test ensures that an error is reported when an undefined global value is +# used. + +--- | + + @G = external global i32 + + define i32 @inc() { + entry: + %a = load i32, i32* @G + %b = add i32 %a, 1 + ret i32 %b + } + +... +--- +name: inc +body: + - id: 0 + name: entry + instructions: + # CHECK: [[@LINE+1]]:37: use of undefined global value '@GG' + - '%rax = MOV64rm %rip, 1, _, @GG, _' + - '%eax = MOV32rm %rax, 1, _, 0, _' + - '%eax = INC32r %eax' + - 'RETQ %eax' +...