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()))
GlobalValue,
// Other tokens
- IntegerLiteral
+ IntegerLiteral,
+ VirtualRegister
};
private:
bool isError() const { return Kind == Error; }
bool isRegister() const {
- return Kind == NamedRegister || Kind == underscore;
+ return Kind == NamedRegister || Kind == underscore ||
+ Kind == VirtualRegister;
}
bool isRegisterFlag() const {
bool hasIntegerValue() const {
return Kind == IntegerLiteral || Kind == MachineBasicBlock ||
- Kind == GlobalValue;
+ Kind == GlobalValue || Kind == VirtualRegister;
}
};
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");
case MIToken::kw_undef:
case MIToken::underscore:
case MIToken::NamedRegister:
+ case MIToken::VirtualRegister:
return parseRegisterOperand(Dest);
case MIToken::IntegerLiteral:
return parseImmediateOperand(Dest);
struct PerFunctionMIParsingState {
DenseMap<unsigned, MachineBasicBlock *> MBBSlots;
+ DenseMap<unsigned, unsigned> VirtualRegisterSlots;
};
bool parseMachineInstr(MachineInstr *&MI, SourceMgr &SM, MachineFunction &MF,
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<unsigned, unsigned> &VirtualRegisterSlots);
bool initializeFrameInfo(MachineFrameInfo &MFI,
const yaml::MachineFunction &YamlMF);
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;
bool MIRParserImpl::initializeRegisterInfo(
const MachineFunction &MF, MachineRegisterInfo &RegInfo,
- const yaml::MachineFunction &YamlMF) {
+ const yaml::MachineFunction &YamlMF,
+ DenseMap<unsigned, unsigned> &VirtualRegisterSlots) {
assert(RegInfo.isSSA());
if (!YamlMF.IsSSA)
RegInfo.leaveSSA();
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;
}
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
--- /dev/null
+# 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'
+...
+
# 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.
--- |
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
- { 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'
...
-