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;
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);
const yaml::MachineFunction &YamlMF,
PerFunctionMIParsingState &PFS);
+ void inferRegisterInfo(MachineFunction &MF,
+ const yaml::MachineFunction &YamlMF);
+
bool initializeFrameInfo(MachineFunction &MF,
const yaml::MachineFunction &YamlMF,
PerFunctionMIParsingState &PFS);
PFS))
return true;
}
+ inferRegisterInfo(MF, YamlMF);
// FIXME: This is a temporary workaround until the reserved registers can be
// serialized.
MF.getRegInfo().freezeReservedRegs(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) {
--- /dev/null
+# 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'
+...