MIR Serialization: Serialize MachineFrameInfo's callee saved information.
authorAlex Lorenz <arphaman@gmail.com>
Fri, 24 Jul 2015 22:22:50 +0000 (22:22 +0000)
committerAlex Lorenz <arphaman@gmail.com>
Fri, 24 Jul 2015 22:22:50 +0000 (22:22 +0000)
This commit serializes the callee saved information from the class
'MachineFrameInfo'. This commit extends the YAML mappings for the fixed and
the ordinary stack objects and adds an optional 'callee-saved-register'
attribute. This attribute is used to serialize the callee save information.

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

include/llvm/CodeGen/MIRYamlMapping.h
lib/CodeGen/MIRParser/MIRParser.cpp
lib/CodeGen/MIRPrinter.cpp
test/CodeGen/MIR/X86/callee-saved-info.mir [new file with mode: 0644]
test/CodeGen/MIR/X86/expected-named-register-in-callee-saved-register.mir [new file with mode: 0644]

index c99dc40458d1359ba5d0a8d0ebebdcfdadd00995..138882809e2cea9710ac2369b6e3296bd132af1a 100644 (file)
@@ -159,6 +159,7 @@ struct MachineStackObject {
   int64_t Offset = 0;
   uint64_t Size = 0;
   unsigned Alignment = 0;
+  StringValue CalleeSavedRegister;
 };
 
 template <> struct ScalarEnumerationTraits<MachineStackObject::ObjectType> {
@@ -181,6 +182,8 @@ template <> struct MappingTraits<MachineStackObject> {
     if (Object.Type != MachineStackObject::VariableSized)
       YamlIO.mapRequired("size", Object.Size);
     YamlIO.mapOptional("alignment", Object.Alignment);
+    YamlIO.mapOptional("callee-saved-register", Object.CalleeSavedRegister,
+                       StringValue()); // Don't print it out when it's empty.
   }
 
   static const bool flow = true;
@@ -197,6 +200,7 @@ struct FixedMachineStackObject {
   unsigned Alignment = 0;
   bool IsImmutable = false;
   bool IsAliased = false;
+  StringValue CalleeSavedRegister;
 };
 
 template <>
@@ -221,6 +225,8 @@ template <> struct MappingTraits<FixedMachineStackObject> {
       YamlIO.mapOptional("isImmutable", Object.IsImmutable);
       YamlIO.mapOptional("isAliased", Object.IsAliased);
     }
+    YamlIO.mapOptional("callee-saved-register", Object.CalleeSavedRegister,
+                       StringValue()); // Don't print it out when it's empty.
   }
 
   static const bool flow = true;
@@ -296,7 +302,6 @@ struct MachineFrameInfo {
   bool HasCalls = false;
   // TODO: Serialize StackProtectorIdx and FunctionContextIdx
   unsigned MaxCallFrameSize = 0;
-  // TODO: Serialize callee saved info.
   // TODO: Serialize local frame objects.
   bool HasOpaqueSPAdjustment = false;
   bool HasVAStart = false;
index 67c939cc562a025ee48c7aa3193f6d0c24d2c40f..7f2267138175b06407a1c089bfccc39774cc4d65 100644 (file)
@@ -107,10 +107,15 @@ public:
                               const yaml::MachineFunction &YamlMF,
                               PerFunctionMIParsingState &PFS);
 
-  bool initializeFrameInfo(const Function &F, MachineFrameInfo &MFI,
+  bool initializeFrameInfo(MachineFunction &MF, MachineFrameInfo &MFI,
                            const yaml::MachineFunction &YamlMF,
-                           DenseMap<unsigned, int> &StackObjectSlots,
-                           DenseMap<unsigned, int> &FixedStackObjectSlots);
+                           PerFunctionMIParsingState &PFS);
+
+  bool parseCalleeSavedRegister(MachineFunction &MF,
+                                PerFunctionMIParsingState &PFS,
+                                std::vector<CalleeSavedInfo> &CSIInfo,
+                                const yaml::StringValue &RegisterSource,
+                                int FrameIdx);
 
   bool initializeConstantPool(MachineConstantPool &ConstantPool,
                               const yaml::MachineFunction &YamlMF,
@@ -273,8 +278,7 @@ bool MIRParserImpl::initializeMachineFunction(MachineFunction &MF) {
   PerFunctionMIParsingState PFS;
   if (initializeRegisterInfo(MF, MF.getRegInfo(), YamlMF, PFS))
     return true;
-  if (initializeFrameInfo(*MF.getFunction(), *MF.getFrameInfo(), YamlMF,
-                          PFS.StackObjectSlots, PFS.FixedStackObjectSlots))
+  if (initializeFrameInfo(MF, *MF.getFrameInfo(), YamlMF, PFS))
     return true;
   if (!YamlMF.Constants.empty()) {
     auto *ConstantPool = MF.getConstantPool();
@@ -401,11 +405,11 @@ bool MIRParserImpl::initializeRegisterInfo(MachineFunction &MF,
   return false;
 }
 
-bool MIRParserImpl::initializeFrameInfo(
-    const Function &F, MachineFrameInfo &MFI,
-    const yaml::MachineFunction &YamlMF,
-    DenseMap<unsigned, int> &StackObjectSlots,
-    DenseMap<unsigned, int> &FixedStackObjectSlots) {
+bool MIRParserImpl::initializeFrameInfo(MachineFunction &MF,
+                                        MachineFrameInfo &MFI,
+                                        const yaml::MachineFunction &YamlMF,
+                                        PerFunctionMIParsingState &PFS) {
+  const Function &F = *MF.getFunction();
   const yaml::MachineFrameInfo &YamlMFI = YamlMF.FrameInfo;
   MFI.setFrameAddressIsTaken(YamlMFI.IsFrameAddressTaken);
   MFI.setReturnAddressIsTaken(YamlMFI.IsReturnAddressTaken);
@@ -422,6 +426,7 @@ bool MIRParserImpl::initializeFrameInfo(
   MFI.setHasVAStart(YamlMFI.HasVAStart);
   MFI.setHasMustTailInVarArgFunc(YamlMFI.HasMustTailInVarArgFunc);
 
+  std::vector<CalleeSavedInfo> CSIInfo;
   // Initialize the fixed frame objects.
   for (const auto &Object : YamlMF.FixedStackObjects) {
     int ObjectIdx;
@@ -432,7 +437,10 @@ bool MIRParserImpl::initializeFrameInfo(
       ObjectIdx = MFI.CreateFixedSpillStackObject(Object.Size, Object.Offset);
     MFI.setObjectAlignment(ObjectIdx, Object.Alignment);
     // TODO: Report an error when objects are redefined.
-    FixedStackObjectSlots.insert(std::make_pair(Object.ID, ObjectIdx));
+    PFS.FixedStackObjectSlots.insert(std::make_pair(Object.ID, ObjectIdx));
+    if (parseCalleeSavedRegister(MF, PFS, CSIInfo, Object.CalleeSavedRegister,
+                                 ObjectIdx))
+      return true;
   }
 
   // Initialize the ordinary frame objects.
@@ -457,8 +465,29 @@ bool MIRParserImpl::initializeFrameInfo(
           Object.Type == yaml::MachineStackObject::SpillSlot, Alloca);
     MFI.setObjectOffset(ObjectIdx, Object.Offset);
     // TODO: Report an error when objects are redefined.
-    StackObjectSlots.insert(std::make_pair(Object.ID, ObjectIdx));
+    PFS.StackObjectSlots.insert(std::make_pair(Object.ID, ObjectIdx));
+    if (parseCalleeSavedRegister(MF, PFS, CSIInfo, Object.CalleeSavedRegister,
+                                 ObjectIdx))
+      return true;
   }
+  MFI.setCalleeSavedInfo(CSIInfo);
+  if (!CSIInfo.empty())
+    MFI.setCalleeSavedInfoValid(true);
+  return false;
+}
+
+bool MIRParserImpl::parseCalleeSavedRegister(
+    MachineFunction &MF, PerFunctionMIParsingState &PFS,
+    std::vector<CalleeSavedInfo> &CSIInfo,
+    const yaml::StringValue &RegisterSource, int FrameIdx) {
+  if (RegisterSource.Value.empty())
+    return false;
+  unsigned Reg = 0;
+  SMDiagnostic Error;
+  if (parseNamedRegisterReference(Reg, SM, MF, RegisterSource.Value, PFS,
+                                  IRSlots, Error))
+    return error(Error, RegisterSource.SourceRange);
+  CSIInfo.push_back(CalleeSavedInfo(Reg, FrameIdx));
   return false;
 }
 
index 574a0ddee1bb86f6ac750734d0231024878625b0..2287dfd4480df9d32241e8c0061be8a1e9750e5b 100644 (file)
@@ -79,7 +79,8 @@ public:
   void convert(ModuleSlotTracker &MST, yaml::MachineBasicBlock &YamlMBB,
                const MachineBasicBlock &MBB);
   void convertStackObjects(yaml::MachineFunction &MF,
-                           const MachineFrameInfo &MFI);
+                           const MachineFrameInfo &MFI,
+                           const TargetRegisterInfo *TRI);
 
 private:
   void initRegisterMaskIds(const MachineFunction &MF);
@@ -156,7 +157,8 @@ void MIRPrinter::print(const MachineFunction &MF) {
   YamlMF.HasInlineAsm = MF.hasInlineAsm();
   convert(YamlMF, MF.getRegInfo(), MF.getSubtarget().getRegisterInfo());
   convert(YamlMF.FrameInfo, *MF.getFrameInfo());
-  convertStackObjects(YamlMF, *MF.getFrameInfo());
+  convertStackObjects(YamlMF, *MF.getFrameInfo(),
+                      MF.getSubtarget().getRegisterInfo());
   if (const auto *ConstantPool = MF.getConstantPool())
     convert(YamlMF, *ConstantPool);
 
@@ -219,7 +221,8 @@ void MIRPrinter::convert(yaml::MachineFrameInfo &YamlMFI,
 }
 
 void MIRPrinter::convertStackObjects(yaml::MachineFunction &MF,
-                                     const MachineFrameInfo &MFI) {
+                                     const MachineFrameInfo &MFI,
+                                     const TargetRegisterInfo *TRI) {
   // Process fixed stack objects.
   unsigned ID = 0;
   for (int I = MFI.getObjectIndexBegin(); I < 0; ++I) {
@@ -265,6 +268,19 @@ void MIRPrinter::convertStackObjects(yaml::MachineFunction &MF,
     StackObjectOperandMapping.insert(std::make_pair(
         I, FrameIndexOperand::create(YamlObject.Name.Value, ID++)));
   }
+
+  for (const auto &CSInfo : MFI.getCalleeSavedInfo()) {
+    yaml::StringValue Reg;
+    printReg(CSInfo.getReg(), Reg, TRI);
+    auto StackObjectInfo = StackObjectOperandMapping.find(CSInfo.getFrameIdx());
+    assert(StackObjectInfo != StackObjectOperandMapping.end() &&
+           "Invalid stack object index");
+    const FrameIndexOperand &StackObject = StackObjectInfo->second;
+    if (StackObject.IsFixed)
+      MF.FixedStackObjects[StackObject.ID].CalleeSavedRegister = Reg;
+    else
+      MF.StackObjects[StackObject.ID].CalleeSavedRegister = Reg;
+  }
 }
 
 void MIRPrinter::convert(yaml::MachineFunction &MF,
diff --git a/test/CodeGen/MIR/X86/callee-saved-info.mir b/test/CodeGen/MIR/X86/callee-saved-info.mir
new file mode 100644 (file)
index 0000000..4ec5b50
--- /dev/null
@@ -0,0 +1,98 @@
+# RUN: llc -march=x86-64 -start-after prologepilog -stop-after prologepilog -o /dev/null %s | FileCheck %s
+# This test ensures that the MIR parser parses callee saved information in the
+# stack objects correctly.
+
+--- |
+
+  define i32 @compute(i32 %a) {
+  body:
+    ret i32 %a
+  }
+
+  define i32 @func(i32 %a) {
+  entry:
+    %b = alloca i32
+    store i32 %a, i32* %b
+    br label %check
+
+  check:
+    %comp = icmp sle i32 %a, 10
+    br i1 %comp, label %loop, label %exit
+
+  loop:
+    %c = load i32, i32* %b
+    %d = call i32 @compute(i32 %c)
+    %e = sub i32 %d, 1
+    store i32 %e, i32* %b
+    br label %check
+
+  exit:
+    ret i32 0
+  }
+
+...
+---
+name:            compute
+tracksRegLiveness: true
+body:
+  - id:          0
+    name:        body
+    liveins:     [ '%edi' ]
+    instructions:
+      - '%eax = COPY killed %edi'
+      - 'RETQ killed %eax'
+...
+---
+name:            func
+tracksRegLiveness: true
+frameInfo:
+  stackSize:       24
+  maxAlignment:    4
+  adjustsStack:    true
+  hasCalls:        true
+# CHECK: fixedStack:
+# CHECK-NEXT: , callee-saved-register: '%rbx' }
+fixedStack:
+  - { id: 0, type: spill-slot, offset: -16, size: 8, alignment: 16, callee-saved-register: '%rbx' }
+# CHECK: stack:
+# CHECK-NEXT: - { id: 0
+# CHECK-NEXT: , callee-saved-register: '%edi' }
+stack:
+  - { id: 0, name: b, offset: -20, size: 4, alignment: 4 }
+  - { id: 1, offset: -24, size: 4, alignment: 4, callee-saved-register: '%edi' }
+body:
+  - id:          0
+    name:        entry
+    successors:  [ '%bb.1.check' ]
+    liveins:     [ '%edi', '%rbx' ]
+    instructions:
+      - 'frame-setup PUSH64r killed %rbx, implicit-def %rsp, implicit %rsp'
+      - '%rsp = frame-setup SUB64ri8 %rsp, 16, implicit-def dead %eflags'
+      - '%ebx = COPY %edi'
+      - 'MOV32mr %rsp, 1, _, 12, _, %ebx'
+  - id:          1
+    name:        check
+    successors:  [ '%bb.2.loop', '%bb.3.exit' ]
+    liveins:     [ '%ebx' ]
+    instructions:
+      - 'CMP32ri8 %ebx, 10, implicit-def %eflags'
+      - 'JG_1 %bb.3.exit, implicit killed %eflags'
+      - 'JMP_1 %bb.2.loop'
+  - id:          2
+    name:        loop
+    successors:  [ '%bb.1.check' ]
+    liveins:     [ '%ebx' ]
+    instructions:
+      - '%edi = MOV32rm %rsp, 1, _, 12, _'
+      - 'CALL64pcrel32 @compute, csr_64, implicit %rsp, implicit %edi, implicit-def %rsp, implicit-def %eax'
+      - '%eax = DEC32r killed %eax, implicit-def dead %eflags'
+      - 'MOV32mr %rsp, 1, _, 12, _, killed %eax'
+      - 'JMP_1 %bb.1.check'
+  - id:          3
+    name:        exit
+    instructions:
+      - '%eax = MOV32r0 implicit-def dead %eflags'
+      - '%rsp = ADD64ri8 %rsp, 16, implicit-def dead %eflags'
+      - '%rbx = POP64r implicit-def %rsp, implicit %rsp'
+      - 'RETQ %eax'
+...
diff --git a/test/CodeGen/MIR/X86/expected-named-register-in-callee-saved-register.mir b/test/CodeGen/MIR/X86/expected-named-register-in-callee-saved-register.mir
new file mode 100644 (file)
index 0000000..bd9e704
--- /dev/null
@@ -0,0 +1,91 @@
+# RUN: not llc -march=x86-64 -start-after prologepilog -stop-after prologepilog -o /dev/null %s 2>&1 | FileCheck %s
+
+--- |
+
+  define i32 @compute(i32 %a) {
+  body:
+    ret i32 %a
+  }
+
+  define i32 @func(i32 %a) {
+  entry:
+    %b = alloca i32
+    store i32 %a, i32* %b
+    br label %check
+
+  check:
+    %comp = icmp sle i32 %a, 10
+    br i1 %comp, label %loop, label %exit
+
+  loop:
+    %c = load i32, i32* %b
+    %d = call i32 @compute(i32 %c)
+    %e = sub i32 %d, 1
+    store i32 %e, i32* %b
+    br label %check
+
+  exit:
+    ret i32 0
+  }
+
+...
+---
+name:            compute
+tracksRegLiveness: true
+body:
+  - id:          0
+    name:        body
+    liveins:     [ '%edi' ]
+    instructions:
+      - '%eax = COPY killed %edi'
+      - 'RETQ killed %eax'
+...
+---
+name:            func
+tracksRegLiveness: true
+frameInfo:
+  stackSize:       24
+  maxAlignment:    4
+  adjustsStack:    true
+  hasCalls:        true
+fixedStack:
+  # CHECK: [[@LINE+1]]:93: expected a named register
+  - { id: 0, type: spill-slot, offset: -16, size: 8, alignment: 16, callee-saved-register: '%0' }
+stack:
+  - { id: 0, name: b, offset: -20, size: 4, alignment: 4 }
+body:
+  - id:          0
+    name:        entry
+    successors:  [ '%bb.1.check' ]
+    liveins:     [ '%edi', '%rbx' ]
+    instructions:
+      - 'frame-setup PUSH64r killed %rbx, implicit-def %rsp, implicit %rsp'
+      - '%rsp = frame-setup SUB64ri8 %rsp, 16, implicit-def dead %eflags'
+      - '%ebx = COPY %edi'
+      - 'MOV32mr %rsp, 1, _, 12, _, %ebx'
+  - id:          1
+    name:        check
+    successors:  [ '%bb.2.loop', '%bb.3.exit' ]
+    liveins:     [ '%ebx' ]
+    instructions:
+      - 'CMP32ri8 %ebx, 10, implicit-def %eflags'
+      - 'JG_1 %bb.3.exit, implicit killed %eflags'
+      - 'JMP_1 %bb.2.loop'
+  - id:          2
+    name:        loop
+    successors:  [ '%bb.1.check' ]
+    liveins:     [ '%ebx' ]
+    instructions:
+      - '%edi = MOV32rm %rsp, 1, _, 12, _'
+      - 'CALL64pcrel32 @compute, csr_64, implicit %rsp, implicit %edi, implicit-def %rsp, implicit-def %eax'
+      - '%eax = DEC32r killed %eax, implicit-def dead %eflags'
+      - 'MOV32mr %rsp, 1, _, 12, _, killed %eax'
+      - 'JMP_1 %bb.1.check'
+  - id:          3
+    name:        exit
+    instructions:
+      - '%eax = MOV32r0 implicit-def dead %eflags'
+      - '%rsp = ADD64ri8 %rsp, 16, implicit-def dead %eflags'
+      - '%rbx = POP64r implicit-def %rsp, implicit %rsp'
+      - 'RETQ %eax'
+...