Index: llvm/trunk/lib/CodeGen/MIRParser/MILexer.h =================================================================== --- llvm/trunk/lib/CodeGen/MIRParser/MILexer.h +++ llvm/trunk/lib/CodeGen/MIRParser/MILexer.h @@ -51,7 +51,8 @@ GlobalValue, // Other tokens - IntegerLiteral + IntegerLiteral, + VirtualRegister }; private: @@ -73,7 +74,8 @@ bool isError() const { return Kind == Error; } bool isRegister() const { - return Kind == NamedRegister || Kind == underscore; + return Kind == NamedRegister || Kind == underscore || + Kind == VirtualRegister; } bool isRegisterFlag() const { @@ -93,7 +95,7 @@ bool hasIntegerValue() const { return Kind == IntegerLiteral || Kind == MachineBasicBlock || - Kind == GlobalValue; + Kind == GlobalValue || Kind == VirtualRegister; } }; Index: llvm/trunk/lib/CodeGen/MIRParser/MILexer.cpp =================================================================== --- llvm/trunk/lib/CodeGen/MIRParser/MILexer.cpp +++ llvm/trunk/lib/CodeGen/MIRParser/MILexer.cpp @@ -115,9 +115,22 @@ return C; } +static Cursor lexVirtualRegister(Cursor C, MIToken &Token) { + auto Range = C; + C.advance(); // Skip '%' + auto NumberRange = C; + while (isdigit(C.peek())) + C.advance(); + Token = MIToken(MIToken::VirtualRegister, Range.upto(C), + APSInt(NumberRange.upto(C))); + return C; +} + static Cursor maybeLexRegister(Cursor C, MIToken &Token) { if (C.peek() != '%') return None; + if (isdigit(C.peek(1))) + return lexVirtualRegister(C, Token); auto Range = C; C.advance(); // Skip '%' while (isIdentifierChar(C.peek())) Index: llvm/trunk/lib/CodeGen/MIRParser/MIParser.h =================================================================== --- llvm/trunk/lib/CodeGen/MIRParser/MIParser.h +++ llvm/trunk/lib/CodeGen/MIRParser/MIParser.h @@ -28,6 +28,7 @@ struct PerFunctionMIParsingState { DenseMap MBBSlots; + DenseMap VirtualRegisterSlots; }; bool parseMachineInstr(MachineInstr *&MI, SourceMgr &SM, MachineFunction &MF, Index: llvm/trunk/lib/CodeGen/MIRParser/MIParser.cpp =================================================================== --- llvm/trunk/lib/CodeGen/MIRParser/MIParser.cpp +++ llvm/trunk/lib/CodeGen/MIRParser/MIParser.cpp @@ -288,6 +288,17 @@ return error(Twine("unknown register name '") + Name + "'"); break; } + case MIToken::VirtualRegister: { + unsigned ID; + if (getUnsigned(ID)) + return true; + const auto RegInfo = PFS.VirtualRegisterSlots.find(ID); + if (RegInfo == PFS.VirtualRegisterSlots.end()) + return error(Twine("use of undefined virtual register '%") + Twine(ID) + + "'"); + Reg = RegInfo->second; + break; + } // TODO: Parse other register kinds. default: llvm_unreachable("The current token should be a register"); @@ -425,6 +436,7 @@ case MIToken::kw_undef: case MIToken::underscore: case MIToken::NamedRegister: + case MIToken::VirtualRegister: return parseRegisterOperand(Dest); case MIToken::IntegerLiteral: return parseImmediateOperand(Dest); Index: llvm/trunk/lib/CodeGen/MIRParser/MIRParser.cpp =================================================================== --- llvm/trunk/lib/CodeGen/MIRParser/MIRParser.cpp +++ llvm/trunk/lib/CodeGen/MIRParser/MIRParser.cpp @@ -102,9 +102,11 @@ const yaml::MachineBasicBlock &YamlMBB, const PerFunctionMIParsingState &PFS); - bool initializeRegisterInfo(const MachineFunction &MF, - MachineRegisterInfo &RegInfo, - const yaml::MachineFunction &YamlMF); + bool + initializeRegisterInfo(const MachineFunction &MF, + MachineRegisterInfo &RegInfo, + const yaml::MachineFunction &YamlMF, + DenseMap &VirtualRegisterSlots); bool initializeFrameInfo(MachineFrameInfo &MFI, const yaml::MachineFunction &YamlMF); @@ -258,12 +260,13 @@ MF.setAlignment(YamlMF.Alignment); MF.setExposesReturnsTwice(YamlMF.ExposesReturnsTwice); MF.setHasInlineAsm(YamlMF.HasInlineAsm); - if (initializeRegisterInfo(MF, MF.getRegInfo(), YamlMF)) + PerFunctionMIParsingState PFS; + if (initializeRegisterInfo(MF, MF.getRegInfo(), YamlMF, + PFS.VirtualRegisterSlots)) return true; if (initializeFrameInfo(*MF.getFrameInfo(), YamlMF)) return true; - PerFunctionMIParsingState PFS; const auto &F = *MF.getFunction(); for (const auto &YamlMBB : YamlMF.BasicBlocks) { const BasicBlock *BB = nullptr; @@ -330,7 +333,8 @@ bool MIRParserImpl::initializeRegisterInfo( const MachineFunction &MF, MachineRegisterInfo &RegInfo, - const yaml::MachineFunction &YamlMF) { + const yaml::MachineFunction &YamlMF, + DenseMap &VirtualRegisterSlots) { assert(RegInfo.isSSA()); if (!YamlMF.IsSSA) RegInfo.leaveSSA(); @@ -346,9 +350,10 @@ return error(VReg.Class.SourceRange.Start, Twine("use of undefined register class '") + VReg.Class.Value + "'"); - // TODO: create the mapping from IDs to registers so that the virtual - // register references can be parsed correctly. - RegInfo.createVirtualRegister(RC); + unsigned Reg = RegInfo.createVirtualRegister(RC); + // TODO: Report an error when the same virtual register with the same ID is + // redefined. + VirtualRegisterSlots.insert(std::make_pair(VReg.ID, Reg)); } return false; } Index: llvm/trunk/lib/CodeGen/MIRPrinter.cpp =================================================================== --- llvm/trunk/lib/CodeGen/MIRPrinter.cpp +++ llvm/trunk/lib/CodeGen/MIRPrinter.cpp @@ -250,9 +250,10 @@ static void printReg(unsigned Reg, raw_ostream &OS, const TargetRegisterInfo *TRI) { // TODO: Print Stack Slots. - // TODO: Print virtual registers. if (!Reg) OS << '_'; + else if (TargetRegisterInfo::isVirtualRegister(Reg)) + OS << '%' << TargetRegisterInfo::virtReg2Index(Reg); else if (Reg < TRI->getNumRegs()) OS << '%' << StringRef(TRI->getName(Reg)).lower(); else Index: llvm/trunk/test/CodeGen/MIR/X86/undefined-virtual-register.mir =================================================================== --- llvm/trunk/test/CodeGen/MIR/X86/undefined-virtual-register.mir +++ llvm/trunk/test/CodeGen/MIR/X86/undefined-virtual-register.mir @@ -0,0 +1,28 @@ +# RUN: not llc -march=x86-64 -start-after machine-sink -stop-after machine-sink -o /dev/null %s 2>&1 | FileCheck %s +# This test ensures that the MIR parser reports an error when parsing a +# reference to an undefined virtual register. + +--- | + + define i32 @test(i32 %a) { + entry: + ret i32 %a + } + +... +--- +name: test +isSSA: true +tracksRegLiveness: true +registers: + - { id: 0, class: gr32 } +body: + - id: 0 + name: entry + instructions: + - '%0 = COPY %edi' + # CHECK: [[@LINE+1]]:22: use of undefined virtual register '%10' + - '%eax = COPY %10' + - 'RETQ %eax' +... + Index: llvm/trunk/test/CodeGen/MIR/X86/virtual-registers.mir =================================================================== --- llvm/trunk/test/CodeGen/MIR/X86/virtual-registers.mir +++ llvm/trunk/test/CodeGen/MIR/X86/virtual-registers.mir @@ -1,6 +1,6 @@ # RUN: llc -march=x86-64 -start-after machine-sink -stop-after machine-sink -o /dev/null %s | FileCheck %s -# This test ensures that the MIR parser parses virtual register definitions -# correctly. +# This test ensures that the MIR parser parses virtual register definitions and +# references correctly. --- | @@ -16,6 +16,18 @@ ret i32 %a } + define i32 @foo(i32 %a) { + entry: + %0 = icmp sle i32 %a, 10 + br i1 %0, label %less, label %exit + + less: + ret i32 0 + + exit: + ret i32 %a + } + ... --- name: bar @@ -30,6 +42,64 @@ - { id: 1, class: gr32 } - { id: 2, class: gr32 } body: - - id: 0 + - id: 0 + name: entry + # CHECK: %0 = COPY %edi + # CHECK-NEXT: %1 = SUB32ri8 %0, 10 + instructions: + - '%0 = COPY %edi' + - '%1 = SUB32ri8 %0, 10, implicit-def %eflags' + - 'JG_1 %bb.2.exit, implicit %eflags' + - 'JMP_1 %bb.1.less' + - id: 1 + name: less + # CHECK: %2 = MOV32r0 + # CHECK-NEXT: %eax = COPY %2 + instructions: + - '%2 = MOV32r0 implicit-def %eflags' + - '%eax = COPY %2' + - 'RETQ %eax' + - id: 2 + name: exit + instructions: + - '%eax = COPY %0' + - 'RETQ %eax' +... +--- +name: foo +isSSA: true +tracksRegLiveness: true +# CHECK: name: foo +# CHECK: registers: +# CHECK-NEXT: - { id: 0, class: gr32 } +# CHECK-NEXT: - { id: 1, class: gr32 } +# CHECK-NEXT: - { id: 2, class: gr32 } +registers: + - { id: 2, class: gr32 } + - { id: 0, class: gr32 } + - { id: 10, class: gr32 } +body: + - id: 0 + name: entry + # CHECK: %0 = COPY %edi + # CHECK-NEXT: %1 = SUB32ri8 %0, 10 + instructions: + - '%2 = COPY %edi' + - '%0 = SUB32ri8 %2, 10, implicit-def %eflags' + - 'JG_1 %bb.2.exit, implicit %eflags' + - 'JMP_1 %bb.1.less' + - id: 1 + name: less + # CHECK: %2 = MOV32r0 + # CHECK-NEXT: %eax = COPY %2 + instructions: + - '%10 = MOV32r0 implicit-def %eflags' + - '%eax = COPY %10' + - 'RETQ %eax' + - id: 2 + name: exit + # CHECK: %eax = COPY %0 + instructions: + - '%eax = COPY %2' + - 'RETQ %eax' ... -