diff --git a/llvm/include/llvm/CodeGen/MIRYamlMapping.h b/llvm/include/llvm/CodeGen/MIRYamlMapping.h index fb78a3e4c3f8..a3844723e8c2 100644 --- a/llvm/include/llvm/CodeGen/MIRYamlMapping.h +++ b/llvm/include/llvm/CodeGen/MIRYamlMapping.h @@ -396,6 +396,7 @@ struct MachineFunction { bool TracksSubRegLiveness = false; std::vector VirtualRegisters; std::vector LiveIns; + Optional> CalleeSavedRegisters; // TODO: Serialize the various register masks. // Frame information MachineFrameInfo FrameInfo; @@ -418,6 +419,7 @@ template <> struct MappingTraits { 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); diff --git a/llvm/include/llvm/CodeGen/MachineRegisterInfo.h b/llvm/include/llvm/CodeGen/MachineRegisterInfo.h index 2f823b44801d..56c85475b5d5 100644 --- a/llvm/include/llvm/CodeGen/MachineRegisterInfo.h +++ b/llvm/include/llvm/CodeGen/MachineRegisterInfo.h @@ -653,6 +653,10 @@ public: UsedPhysRegMask.setBitsNotInMask(RegMask); } + const BitVector &getUsedPhysRegsMask() const { return UsedPhysRegMask; } + + void setUsedPhysRegMask(BitVector &Mask) { UsedPhysRegMask = Mask; } + //===--------------------------------------------------------------------===// // Reserved Register Info //===--------------------------------------------------------------------===// diff --git a/llvm/lib/CodeGen/MIRParser/MIRParser.cpp b/llvm/lib/CodeGen/MIRParser/MIRParser.cpp index b5c7d2afefac..9b112e34b038 100644 --- a/llvm/lib/CodeGen/MIRParser/MIRParser.cpp +++ b/llvm/lib/CodeGen/MIRParser/MIRParser.cpp @@ -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) { diff --git a/llvm/lib/CodeGen/MIRPrinter.cpp b/llvm/lib/CodeGen/MIRPrinter.cpp index c12b2cfeaccd..8b54a981f8ed 100644 --- a/llvm/lib/CodeGen/MIRPrinter.cpp +++ b/llvm/lib/CodeGen/MIRPrinter.cpp @@ -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 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/llvm/test/CodeGen/MIR/X86/used-physical-register-info.mir b/llvm/test/CodeGen/MIR/X86/used-physical-register-info.mir new file mode 100644 index 000000000000..7858fe29841b --- /dev/null +++ b/llvm/test/CodeGen/MIR/X86/used-physical-register-info.mir @@ -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' +...