Index: lib/CodeGen/MIRParser/MILexer.h =================================================================== --- lib/CodeGen/MIRParser/MILexer.h +++ lib/CodeGen/MIRParser/MILexer.h @@ -36,6 +36,10 @@ equal, underscore, + // Keywords + kw_implicit, + kw_implicit_define, + // Identifier tokens Identifier, NamedRegister, @@ -69,6 +73,10 @@ return Kind == NamedRegister || Kind == underscore; } + bool isRegisterFlag() const { + return Kind == kw_implicit || Kind == kw_implicit_define; + } + bool is(TokenKind K) const { return Kind == K; } bool isNot(TokenKind K) const { return Kind != K; } Index: lib/CodeGen/MIRParser/MILexer.cpp =================================================================== --- lib/CodeGen/MIRParser/MILexer.cpp +++ lib/CodeGen/MIRParser/MILexer.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "MILexer.h" +#include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Twine.h" #include @@ -60,13 +61,20 @@ return isalpha(C) || isdigit(C) || C == '_' || C == '-' || C == '.'; } +static MIToken::TokenKind getIdentifierKind(StringRef Identifier) { + return StringSwitch(Identifier) + .Case("_", MIToken::underscore) + .Case("implicit", MIToken::kw_implicit) + .Case("implicit-def", MIToken::kw_implicit_define) + .Default(MIToken::Identifier); +} + static Cursor lexIdentifier(Cursor C, MIToken &Token) { auto Range = C; while (isIdentifierChar(C.peek())) C.advance(); auto Identifier = Range.upto(C); - Token = MIToken(Identifier == "_" ? MIToken::underscore : MIToken::Identifier, - Identifier); + Token = MIToken(getIdentifierKind(Identifier), Identifier); return C; } Index: lib/CodeGen/MIRParser/MIParser.cpp =================================================================== --- lib/CodeGen/MIRParser/MIParser.cpp +++ lib/CodeGen/MIRParser/MIParser.cpp @@ -18,6 +18,7 @@ #include "llvm/CodeGen/MachineBasicBlock.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineInstr.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/IR/Module.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/SourceMgr.h" @@ -66,6 +67,7 @@ MachineInstr *parse(); bool parseRegister(unsigned &Reg); + bool parseRegisterFlag(unsigned &Flags); bool parseRegisterOperand(MachineOperand &Dest, bool IsDef = false); bool parseImmediateOperand(MachineOperand &Dest); bool parseMBBOperand(MachineOperand &Dest); @@ -136,7 +138,7 @@ // TODO: Allow parsing of multiple operands before '=' MachineOperand MO = MachineOperand::CreateImm(0); SmallVector Operands; - if (Token.isRegister()) { + if (Token.isRegister() || Token.isRegisterFlag()) { if (parseRegisterOperand(MO, /*IsDef=*/true)) return nullptr; Operands.push_back(MO); @@ -169,21 +171,8 @@ const auto &MCID = MF.getSubtarget().getInstrInfo()->get(OpCode); - // Verify machine operands. - if (!MCID.isVariadic()) { - for (size_t I = 0, E = Operands.size(); I < E; ++I) { - if (I < MCID.getNumOperands()) - continue; - // Mark this register as implicit to prevent an assertion when it's added - // to an instruction. This is a temporary workaround until the implicit - // register flag can be parsed. - if (Operands[I].isReg()) - Operands[I].setImplicit(); - } - } - - // TODO: Determine the implicit behaviour when implicit register flags are - // parsed. + // TODO: Check for extraneous machine operands. + // TODO: Check that this instruction has the implicit register operands. auto *MI = MF.CreateMachineInstr(MCID, DebugLoc(), /*NoImplicit=*/true); for (const auto &Operand : Operands) MI->addOperand(MF, Operand); @@ -218,14 +207,38 @@ return false; } +bool MIParser::parseRegisterFlag(unsigned &Flags) { + switch (Token.kind()) { + case MIToken::kw_implicit: + Flags |= RegState::Implicit; + break; + case MIToken::kw_implicit_define: + Flags |= RegState::ImplicitDefine; + break; + // TODO: report an error when we specify the same flag more than once. + // TODO: parse the other register flags. + default: + llvm_unreachable("The current token should be a register flag"); + } + lex(); + return false; +} + bool MIParser::parseRegisterOperand(MachineOperand &Dest, bool IsDef) { unsigned Reg; - // TODO: Parse register flags. + unsigned Flags = IsDef ? RegState::Define : 0; + while (Token.isRegisterFlag()) { + if (parseRegisterFlag(Flags)) + return true; + } + if (!Token.isRegister()) + return error("expected a register after register flags"); if (parseRegister(Reg)) return true; lex(); // TODO: Parse subregister. - Dest = MachineOperand::CreateReg(Reg, IsDef); + Dest = MachineOperand::CreateReg(Reg, Flags & RegState::Define, + Flags & RegState::Implicit); return false; } @@ -300,6 +313,8 @@ bool MIParser::parseMachineOperand(MachineOperand &Dest) { switch (Token.kind()) { + case MIToken::kw_implicit: + case MIToken::kw_implicit_define: case MIToken::underscore: case MIToken::NamedRegister: return parseRegisterOperand(Dest); Index: lib/CodeGen/MIRPrinter.cpp =================================================================== --- lib/CodeGen/MIRPrinter.cpp +++ lib/CodeGen/MIRPrinter.cpp @@ -196,7 +196,9 @@ void MIPrinter::print(const MachineOperand &Op, const TargetRegisterInfo *TRI) { switch (Op.getType()) { case MachineOperand::MO_Register: - // TODO: Print register flags. + // TODO: Print the other register flags. + if (Op.isImplicit()) + OS << (Op.isDef() ? "implicit-def " : "implicit "); printReg(Op.getReg(), OS, TRI); // TODO: Print sub register. break; Index: test/CodeGen/MIR/X86/expected-register-after-flags.mir =================================================================== --- /dev/null +++ test/CodeGen/MIR/X86/expected-register-after-flags.mir @@ -0,0 +1,22 @@ +# 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 a register operand doesn't +# follow register flags. + +--- | + + define i32 @foo() { + entry: + ret i32 0 + } + +... +--- +name: foo +body: + - id: 0 + name: entry + instructions: + # CHECK: [[@LINE+1]]:37: expected a register after register flags + - '%eax = MOV32r0 implicit-def 2' + - 'RETQ %eax' +... Index: test/CodeGen/MIR/X86/implicit-register-flag.mir =================================================================== --- /dev/null +++ test/CodeGen/MIR/X86/implicit-register-flag.mir @@ -0,0 +1,41 @@ +# 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 the 'implicit' and 'implicit-def' +# register flags correctly. + +--- | + + 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: foo +body: + - id: 0 + name: entry + instructions: + # CHECK: - 'CMP32ri8 %edi, 10, implicit-def %eflags' + # CHECK-NEXT: - 'JG_1 %bb.2.exit, implicit %eflags' + - 'CMP32ri8 %edi, 10, implicit-def %eflags' + - 'JG_1 %bb.2.exit, implicit %eflags' + - id: 1 + name: less + instructions: + # CHECK: - '%eax = MOV32r0 implicit-def %eflags' + - '%eax = MOV32r0 implicit-def %eflags' + - 'RETQ %eax' + - id: 2 + name: exit + instructions: + - '%eax = COPY %edi' + - 'RETQ %eax' +... Index: test/CodeGen/MIR/X86/register-mask-operands.mir =================================================================== --- test/CodeGen/MIR/X86/register-mask-operands.mir +++ test/CodeGen/MIR/X86/register-mask-operands.mir @@ -35,9 +35,9 @@ name: entry instructions: # CHECK: - 'PUSH64r %rax - # CHECK-NEXT: - 'CALL64pcrel32 @compute, csr_64, %rsp, %edi, %rsp, %eax' + # CHECK-NEXT: - 'CALL64pcrel32 @compute, csr_64, implicit %rsp, implicit %edi, implicit-def %rsp, implicit-def %eax' - 'PUSH64r %rax' - - 'CALL64pcrel32 @compute, csr_64, %rsp, %edi, %rsp, %eax' + - 'CALL64pcrel32 @compute, csr_64, implicit %rsp, implicit %edi, implicit-def %rsp, implicit-def %eax' - '%rdx = POP64r' - 'RETQ %eax' ...