MIR Serialization: Serialize UsedPhysRegMask from the machine register info.
authorAlex Lorenz <arphaman@gmail.com>
Tue, 11 Aug 2015 00:32:49 +0000 (00:32 +0000)
committerAlex Lorenz <arphaman@gmail.com>
Tue, 11 Aug 2015 00:32:49 +0000 (00:32 +0000)
This commit serializes the UsedPhysRegMask register mask from the machine
register information class. The mask is serialized as an inverted
'calleeSavedRegisters' mask to keep the output minimal.

This commit also allows the MIR parser to infer this mask from the register
mask operands if the machine function doesn't specify it.

Reviewers: Duncan P. N. Exon Smith

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

include/llvm/CodeGen/MIRYamlMapping.h
include/llvm/CodeGen/MachineRegisterInfo.h
lib/CodeGen/MIRParser/MIRParser.cpp
lib/CodeGen/MIRPrinter.cpp
test/CodeGen/MIR/X86/used-physical-register-info.mir [new file with mode: 0644]

index fb78a3e4c3f8ef2473aa5d7ee4d58502d874759e..a3844723e8c21520d29fb2c6e3a793836d506b13 100644 (file)
@@ -396,6 +396,7 @@ struct MachineFunction {
   bool TracksSubRegLiveness = false;
   std::vector<VirtualRegisterDefinition> VirtualRegisters;
   std::vector<MachineFunctionLiveIn> LiveIns;
+  Optional<std::vector<FlowStringValue>> CalleeSavedRegisters;
   // TODO: Serialize the various register masks.
   // Frame information
   MachineFrameInfo FrameInfo;
@@ -418,6 +419,7 @@ template <> struct MappingTraits<MachineFunction> {
     YamlIO.mapOptional("tracksSubRegLiveness", MF.TracksSubRegLiveness);
     YamlIO.mapOptional("registers", MF.VirtualRegisters);
     YamlIO.mapOptional("liveins", MF.LiveIns);
+    YamlIO.mapOptional("calleeSavedRegisters", MF.CalleeSavedRegisters);
     YamlIO.mapOptional("frameInfo", MF.FrameInfo);
     YamlIO.mapOptional("fixedStack", MF.FixedStackObjects);
     YamlIO.mapOptional("stack", MF.StackObjects);
index 2f823b44801de1eba51ef3525e8374b0b06f3b66..56c85475b5d56f6c0260c53db5d2367f162dba6e 100644 (file)
@@ -653,6 +653,10 @@ public:
     UsedPhysRegMask.setBitsNotInMask(RegMask);
   }
 
+  const BitVector &getUsedPhysRegsMask() const { return UsedPhysRegMask; }
+
+  void setUsedPhysRegMask(BitVector &Mask) { UsedPhysRegMask = Mask; }
+
   //===--------------------------------------------------------------------===//
   // Reserved Register Info
   //===--------------------------------------------------------------------===//
index b5c7d2afefac9142c1e43d288736f95672493f7e..9b112e34b0380d5b2d09082f3474f0ef2ea6d874 100644 (file)
@@ -107,6 +107,9 @@ public:
                               const yaml::MachineFunction &YamlMF,
                               PerFunctionMIParsingState &PFS);
 
+  void inferRegisterInfo(MachineFunction &MF,
+                         const yaml::MachineFunction &YamlMF);
+
   bool initializeFrameInfo(MachineFunction &MF,
                            const yaml::MachineFunction &YamlMF,
                            PerFunctionMIParsingState &PFS);
@@ -339,6 +342,7 @@ bool MIRParserImpl::initializeMachineFunction(MachineFunction &MF) {
                                     PFS))
       return true;
   }
+  inferRegisterInfo(MF, YamlMF);
   // FIXME: This is a temporary workaround until the reserved registers can be
   // serialized.
   MF.getRegInfo().freezeReservedRegs(MF);
@@ -443,9 +447,37 @@ bool MIRParserImpl::initializeRegisterInfo(MachineFunction &MF,
     }
     RegInfo.addLiveIn(Reg, VReg);
   }
+
+  // Parse the callee saved register mask.
+  BitVector CalleeSavedRegisterMask(RegInfo.getUsedPhysRegsMask().size());
+  if (!YamlMF.CalleeSavedRegisters)
+    return false;
+  for (const auto &RegSource : YamlMF.CalleeSavedRegisters.getValue()) {
+    unsigned Reg = 0;
+    if (parseNamedRegisterReference(Reg, SM, MF, RegSource.Value, PFS, IRSlots,
+                                    Error))
+      return error(Error, RegSource.SourceRange);
+    CalleeSavedRegisterMask[Reg] = true;
+  }
+  RegInfo.setUsedPhysRegMask(CalleeSavedRegisterMask.flip());
   return false;
 }
 
+void MIRParserImpl::inferRegisterInfo(MachineFunction &MF,
+                                      const yaml::MachineFunction &YamlMF) {
+  if (YamlMF.CalleeSavedRegisters)
+    return;
+  for (const MachineBasicBlock &MBB : MF) {
+    for (const MachineInstr &MI : MBB) {
+      for (const MachineOperand &MO : MI.operands()) {
+        if (!MO.isRegMask())
+          continue;
+        MF.getRegInfo().addPhysRegsUsedFromRegMask(MO.getRegMask());
+      }
+    }
+  }
+}
+
 bool MIRParserImpl::initializeFrameInfo(MachineFunction &MF,
                                         const yaml::MachineFunction &YamlMF,
                                         PerFunctionMIParsingState &PFS) {
index c12b2cfeaccdf788b35daf456ee8a6418858d051..8b54a981f8ed0660aded82eada74c58599142d77 100644 (file)
@@ -218,6 +218,20 @@ void MIRPrinter::convert(yaml::MachineFunction &MF,
       printReg(I->second, LiveIn.VirtualRegister, TRI);
     MF.LiveIns.push_back(LiveIn);
   }
+  // The used physical register mask is printed as an inverted callee saved
+  // register mask.
+  const BitVector &UsedPhysRegMask = RegInfo.getUsedPhysRegsMask();
+  if (UsedPhysRegMask.none())
+    return;
+  std::vector<yaml::FlowStringValue> CalleeSavedRegisters;
+  for (unsigned I = 0, E = UsedPhysRegMask.size(); I != E; ++I) {
+    if (!UsedPhysRegMask[I]) {
+      yaml::FlowStringValue Reg;
+      printReg(I, Reg, TRI);
+      CalleeSavedRegisters.push_back(Reg);
+    }
+  }
+  MF.CalleeSavedRegisters = CalleeSavedRegisters;
 }
 
 void MIRPrinter::convert(ModuleSlotTracker &MST,
diff --git a/test/CodeGen/MIR/X86/used-physical-register-info.mir b/test/CodeGen/MIR/X86/used-physical-register-info.mir
new file mode 100644 (file)
index 0000000..7858fe2
--- /dev/null
@@ -0,0 +1,113 @@
+# 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 callee saved register mask
+# correctly and that the MIR parser can infer it as well.
+
+--- |
+
+  define i32 @compute(i32 %a) #0 {
+  body:
+    %c = mul i32 %a, 11
+    ret i32 %c
+  }
+
+  define i32 @foo(i32 %a) #0 {
+  entry:
+    %b = call i32 @compute(i32 %a)
+    ret i32 %b
+  }
+
+  define i32 @bar(i32 %a) #0 {
+  entry:
+    %b = call i32 @compute(i32 %a)
+    ret i32 %b
+  }
+
+  define i32 @empty(i32 %a) #0 {
+  entry:
+    %b = call i32 @compute(i32 %a)
+    ret i32 %b
+  }
+
+  attributes #0 = { "no-frame-pointer-elim"="false" }
+
+...
+---
+# CHECK: name: compute
+# CHECK: liveins:
+# CHECK-NEXT: - { reg: '%edi' }
+# CHECK-NEXT: frameInfo:
+name:            compute
+liveins:
+  - { reg: '%edi' }
+frameInfo:
+  stackSize:     8
+body:
+  - id:          0
+    name:        body
+    liveins:     [ '%edi' ]
+    instructions:
+      - '%eax = IMUL32rri8 %edi, 11, implicit-def %eflags'
+      - 'RETQ %eax'
+...
+---
+name:            foo
+liveins:
+  - { reg: '%edi' }
+# CHECK: name: foo
+# CHECK: calleeSavedRegisters: [ '%bh', '%bl', '%bp', '%bpl', '%bx', '%ebp', '%ebx',
+# CHECK-NEXT:                    '%rbp', '%rbx', '%r12', '%r13', '%r14', '%r15',
+# CHECK-NEXT:                    '%r12b', '%r13b', '%r14b', '%r15b', '%r12d', '%r13d',
+# CHECK-NEXT:                    '%r14d', '%r15d', '%r12w', '%r13w', '%r14w', '%r15w' ]
+calleeSavedRegisters: [ '%bh', '%bl', '%bp', '%bpl', '%bx', '%ebp', '%ebx',
+                        '%rbp', '%rbx', '%r12', '%r13', '%r14', '%r15',
+                        '%r12b', '%r13b', '%r14b', '%r15b', '%r12d', '%r13d',
+                        '%r14d', '%r15d', '%r12w', '%r13w', '%r14w', '%r15w' ]
+body:
+  - id:          0
+    name:        entry
+    liveins:     [ '%edi' ]
+    instructions:
+      - 'PUSH64r %rax, implicit-def %rsp, implicit %rsp'
+      - 'CALL64pcrel32 @compute, csr_64, implicit %rsp, implicit %edi, implicit-def %rsp, implicit-def %eax'
+      - '%rdx = POP64r implicit-def %rsp, implicit %rsp'
+      - 'RETQ %eax'
+...
+---
+name:            bar
+liveins:
+  - { reg: '%edi' }
+# Verify that the callee saved register can be inferred from register mask
+# machine operands:
+# CHECK: name: bar
+# CHECK: calleeSavedRegisters: [ '%bh', '%bl', '%bp', '%bpl', '%bx', '%ebp', '%ebx',
+# CHECK-NEXT:                    '%rbp', '%rbx', '%r12', '%r13', '%r14', '%r15',
+# CHECK-NEXT:                    '%r12b', '%r13b', '%r14b', '%r15b', '%r12d', '%r13d',
+# CHECK-NEXT:                    '%r14d', '%r15d', '%r12w', '%r13w', '%r14w', '%r15w' ]
+body:
+  - id:          0
+    name:        entry
+    liveins:     [ '%edi' ]
+    instructions:
+      - 'PUSH64r %rax, implicit-def %rsp, implicit %rsp'
+      - 'CALL64pcrel32 @compute, csr_64, implicit %rsp, implicit %edi, implicit-def %rsp, implicit-def %eax'
+      - '%rdx = POP64r implicit-def %rsp, implicit %rsp'
+      - 'RETQ %eax'
+...
+---
+name:            empty
+liveins:
+  - { reg: '%edi' }
+# Verify that the callee saved register can be empty.
+# CHECK: name: empty
+# CHECK: calleeSavedRegisters: [ ]
+calleeSavedRegisters: [ ]
+body:
+  - id:          0
+    name:        entry
+    liveins:     [ '%edi' ]
+    instructions:
+      - 'PUSH64r %rax, implicit-def %rsp, implicit %rsp'
+      - 'CALL64pcrel32 @compute, csr_64, implicit %rsp, implicit %edi, implicit-def %rsp, implicit-def %eax'
+      - '%rdx = POP64r implicit-def %rsp, implicit %rsp'
+      - 'RETQ %eax'
+...