MIR Serialization: Serialize the virtual register operands.
authorAlex Lorenz <arphaman@gmail.com>
Fri, 10 Jul 2015 22:51:20 +0000 (22:51 +0000)
committerAlex Lorenz <arphaman@gmail.com>
Fri, 10 Jul 2015 22:51:20 +0000 (22:51 +0000)
Reviewers: Duncan P. N. Exon Smith

Differential Revision: http://reviews.llvm.org/D11005

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@241959 91177308-0d34-0410-b5e6-96231b3b80d8

lib/CodeGen/MIRParser/MILexer.cpp
lib/CodeGen/MIRParser/MILexer.h
lib/CodeGen/MIRParser/MIParser.cpp
lib/CodeGen/MIRParser/MIParser.h
lib/CodeGen/MIRParser/MIRParser.cpp
lib/CodeGen/MIRPrinter.cpp
test/CodeGen/MIR/X86/undefined-virtual-register.mir [new file with mode: 0644]
test/CodeGen/MIR/X86/virtual-registers.mir

index 4baa3859461f78af7c0819a5c228c7ecea577f7a..1ba5725d1f85f36844bae86c307e328c1fc33882 100644 (file)
@@ -115,9 +115,22 @@ static Cursor maybeLexMachineBasicBlock(
   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 ef471d250c269c949727e374d688572b3b1ac323..187747c6dd316b46fad43a09aed756c979cc8cc4 100644 (file)
@@ -51,7 +51,8 @@ struct MIToken {
     GlobalValue,
 
     // Other tokens
-    IntegerLiteral
+    IntegerLiteral,
+    VirtualRegister
   };
 
 private:
@@ -73,7 +74,8 @@ public:
   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 @@ public:
 
   bool hasIntegerValue() const {
     return Kind == IntegerLiteral || Kind == MachineBasicBlock ||
-           Kind == GlobalValue;
+           Kind == GlobalValue || Kind == VirtualRegister;
   }
 };
 
index 7fd794bd2119392c180e6d1427c24b0a15252da8..5a88a8d21a596827551e6e2ba6e8fa064cb21a86 100644 (file)
@@ -288,6 +288,17 @@ bool MIParser::parseRegister(unsigned &Reg) {
       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 @@ bool MIParser::parseMachineOperand(MachineOperand &Dest) {
   case MIToken::kw_undef:
   case MIToken::underscore:
   case MIToken::NamedRegister:
+  case MIToken::VirtualRegister:
     return parseRegisterOperand(Dest);
   case MIToken::IntegerLiteral:
     return parseImmediateOperand(Dest);
index e4c38004272cb7b0da3800e30321698083382301..8a911b32a764eac0f24630b4025d10b17b8a996c 100644 (file)
@@ -28,6 +28,7 @@ class SourceMgr;
 
 struct PerFunctionMIParsingState {
   DenseMap<unsigned, MachineBasicBlock *> MBBSlots;
+  DenseMap<unsigned, unsigned> VirtualRegisterSlots;
 };
 
 bool parseMachineInstr(MachineInstr *&MI, SourceMgr &SM, MachineFunction &MF,
index 0f7673eea070b6c16a8f9fa49729f242a8813e0f..612084c0b8d0701423e65ada03000dfe46663c81 100644 (file)
@@ -102,9 +102,11 @@ public:
                                    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);
@@ -258,12 +260,13 @@ bool MIRParserImpl::initializeMachineFunction(MachineFunction &MF) {
     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::initializeMachineBasicBlock(
 
 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();
@@ -346,9 +350,10 @@ bool MIRParserImpl::initializeRegisterInfo(
       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 8e97ce4dbf108c7c4549265f651b48cb1906798e..2ae3c4491a62b4fcdb73f23344a8bc61e9d983a3 100644 (file)
@@ -250,9 +250,10 @@ void MIPrinter::print(const MachineInstr &MI) {
 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
diff --git a/test/CodeGen/MIR/X86/undefined-virtual-register.mir b/test/CodeGen/MIR/X86/undefined-virtual-register.mir
new file mode 100644 (file)
index 0000000..12370c8
--- /dev/null
@@ -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 154c71335bb03b0443822e1b74b693668172578b..c6d76e6a18c5841429e897791504a4b54ecb3959 100644 (file)
@@ -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.
 
 --- |
 
     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 @@ registers:
   - { 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'
 ...
-