Index: llvm/trunk/lib/CodeGen/MIRParser/MILexer.h =================================================================== --- llvm/trunk/lib/CodeGen/MIRParser/MILexer.h +++ llvm/trunk/lib/CodeGen/MIRParser/MILexer.h @@ -34,6 +34,7 @@ // Tokens with no info. comma, equal, + underscore, // Identifier tokens Identifier, @@ -58,7 +59,9 @@ bool isError() const { return Kind == Error; } - bool isRegister() const { return Kind == NamedRegister; } + bool isRegister() const { + return Kind == NamedRegister || Kind == underscore; + } bool is(TokenKind K) const { return Kind == K; } Index: llvm/trunk/lib/CodeGen/MIRParser/MILexer.cpp =================================================================== --- llvm/trunk/lib/CodeGen/MIRParser/MILexer.cpp +++ llvm/trunk/lib/CodeGen/MIRParser/MILexer.cpp @@ -64,7 +64,9 @@ auto Range = C; while (isIdentifierChar(C.peek())) C.advance(); - Token = MIToken(MIToken::Identifier, Range.upto(C)); + auto Identifier = Range.upto(C); + Token = MIToken(Identifier == "_" ? MIToken::underscore : MIToken::Identifier, + Identifier); return C; } Index: llvm/trunk/lib/CodeGen/MIRParser/MIParser.cpp =================================================================== --- llvm/trunk/lib/CodeGen/MIRParser/MIParser.cpp +++ llvm/trunk/lib/CodeGen/MIRParser/MIParser.cpp @@ -174,6 +174,9 @@ bool MIParser::parseRegister(unsigned &Reg) { switch (Token.kind()) { + case MIToken::underscore: + Reg = 0; + break; case MIToken::NamedRegister: { StringRef Name = Token.stringValue().drop_front(1); // Drop the '%' if (getRegisterByName(Name, Reg)) @@ -211,6 +214,7 @@ bool MIParser::parseMachineOperand(MachineOperand &Dest) { switch (Token.kind()) { + case MIToken::underscore: case MIToken::NamedRegister: return parseRegisterOperand(Dest); case MIToken::IntegerLiteral: @@ -245,6 +249,8 @@ void MIParser::initNames2Regs() { if (!Names2Regs.empty()) return; + // The '%noreg' register is the register 0. + Names2Regs.insert(std::make_pair("noreg", 0)); const auto *TRI = MF.getSubtarget().getRegisterInfo(); assert(TRI && "Expected target register info"); for (unsigned I = 0, E = TRI->getNumRegs(); I < E; ++I) { Index: llvm/trunk/lib/CodeGen/MIRPrinter.cpp =================================================================== --- llvm/trunk/lib/CodeGen/MIRPrinter.cpp +++ llvm/trunk/lib/CodeGen/MIRPrinter.cpp @@ -144,9 +144,10 @@ static void printReg(unsigned Reg, raw_ostream &OS, const TargetRegisterInfo *TRI) { // TODO: Print Stack Slots. - // TODO: Print no register. // TODO: Print virtual registers. - if (Reg < TRI->getNumRegs()) + if (!Reg) + OS << '_'; + else if (Reg < TRI->getNumRegs()) OS << '%' << StringRef(TRI->getName(Reg)).lower(); else llvm_unreachable("Can't print this kind of register yet"); Index: llvm/trunk/test/CodeGen/MIR/X86/null-register-operands.mir =================================================================== --- llvm/trunk/test/CodeGen/MIR/X86/null-register-operands.mir +++ llvm/trunk/test/CodeGen/MIR/X86/null-register-operands.mir @@ -0,0 +1,23 @@ +# 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 null register operands correctly. + +--- | + + define i32 @deref(i32* %p) { + entry: + %a = load i32, i32* %p + ret i32 %a + } + +... +--- +# CHECK: name: deref +name: deref +body: + - name: entry + instructions: + # CHECK: - '%eax = MOV32rm %rdi, 1, _, 0, _' + # CHECK-NEXT: - 'RETQ %eax' + - '%eax = MOV32rm %rdi, 1, _, 0, %noreg' + - 'RETQ %eax' +...