[llvm] Spill/restore FP/BP around instructions in which they are clobbered (PR #81048)
Reid Kleckner via llvm-commits
llvm-commits at lists.llvm.org
Thu Aug 1 15:17:07 PDT 2024
================
@@ -4231,3 +4231,325 @@ void X86FrameLowering::restoreWinEHStackPointersInParent(
/*RestoreSP=*/IsSEH);
}
}
+
+static int computeSPAdjust4SpillFPBP(MachineFunction &MF,
+ const TargetRegisterClass *RC,
+ unsigned NumSpilledRegs) {
+ const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo();
+ unsigned AllocSize = TRI->getSpillSize(*RC) * NumSpilledRegs;
+ Align StackAlign = MF.getSubtarget().getFrameLowering()->getStackAlign();
+ unsigned AlignedSize = alignTo(AllocSize, StackAlign);
+ return AlignedSize - AllocSize;
+}
+
+void X86FrameLowering::spillFPBPUsingSP(MachineFunction &MF,
+ MachineBasicBlock::iterator BeforeMI,
+ bool SpillFP, bool SpillBP) const {
+ assert(SpillFP || SpillBP);
+
+ const TargetRegisterClass *RC;
+ unsigned NumRegs = 0;
+ MachineBasicBlock *MBB = BeforeMI->getParent();
+ DebugLoc DL = BeforeMI->getDebugLoc();
+
+ // Spill FP.
+ if (SpillFP) {
+ Register FP = TRI->getFrameRegister(MF);
+ if (STI.isTarget64BitILP32())
+ FP = Register(getX86SubSuperRegister(FP, 64));
+ RC = TRI->getMinimalPhysRegClass(FP);
+ ++NumRegs;
+
+ BuildMI(*MBB, BeforeMI, DL,
+ TII.get(getPUSHOpcode(MF.getSubtarget<X86Subtarget>())))
+ .addReg(FP);
+ }
+
+ // Spill BP.
+ if (SpillBP) {
+ Register BP = TRI->getBaseRegister();
+ if (STI.isTarget64BitILP32())
+ BP = Register(getX86SubSuperRegister(BP, 64));
+ RC = TRI->getMinimalPhysRegClass(BP);
+ ++NumRegs;
+
+ BuildMI(*MBB, BeforeMI, DL,
+ TII.get(getPUSHOpcode(MF.getSubtarget<X86Subtarget>())))
+ .addReg(BP);
+ }
+
+ // Make sure SP is aligned.
+ int SPAdjust = computeSPAdjust4SpillFPBP(MF, RC, NumRegs);
+ if (SPAdjust)
+ emitSPUpdate(*MBB, BeforeMI, DL, -SPAdjust, false);
+
+ // Emit unwinding information.
+ if (SpillFP && needsDwarfCFI(MF)) {
+ // Emit .cfi_remember_state to remember old frame.
+ unsigned CFIIndex =
+ MF.addFrameInst(MCCFIInstruction::createRememberState(nullptr));
+ BuildMI(*MBB, BeforeMI, DL, TII.get(TargetOpcode::CFI_INSTRUCTION))
+ .addCFIIndex(CFIIndex);
+
+ // Setup new CFA value with DW_CFA_def_cfa_expression:
+ // DW_OP_breg7+offset, DW_OP_deref, DW_OP_consts 16, DW_OP_plus
+ SmallString<64> CfaExpr;
+ uint8_t buffer[16];
+ int Offset = SPAdjust;
+ if (SpillBP)
+ Offset += TRI->getSpillSize(*RC);
+ // If BeforeMI is a frame setup instruction, we need to adjust the position
+ // and offset of the new cfi instruction.
+ if (TII.isFrameSetup(*BeforeMI)) {
+ Offset += alignTo(TII.getFrameSize(*BeforeMI), getStackAlign());
+ BeforeMI = std::next(BeforeMI);
+ }
+ Register StackPtr = TRI->getStackRegister();
+ if (STI.isTarget64BitILP32())
+ StackPtr = Register(getX86SubSuperRegister(StackPtr, 64));
+ unsigned DwarfStackPtr = TRI->getDwarfRegNum(StackPtr, true);
+ CfaExpr.push_back((uint8_t)(dwarf::DW_OP_breg0 + DwarfStackPtr));
+ CfaExpr.append(buffer, buffer + encodeSLEB128(Offset, buffer));
+ CfaExpr.push_back(dwarf::DW_OP_deref);
+ CfaExpr.push_back(dwarf::DW_OP_consts);
+ CfaExpr.append(buffer, buffer + encodeSLEB128(SlotSize * 2, buffer));
+ CfaExpr.push_back((uint8_t)dwarf::DW_OP_plus);
+
+ SmallString<64> DefCfaExpr;
+ DefCfaExpr.push_back(dwarf::DW_CFA_def_cfa_expression);
+ DefCfaExpr.append(buffer, buffer + encodeSLEB128(CfaExpr.size(), buffer));
+ DefCfaExpr.append(CfaExpr.str());
+ BuildCFI(*MBB, BeforeMI, DL,
+ MCCFIInstruction::createEscape(nullptr, DefCfaExpr.str()),
+ MachineInstr::FrameSetup);
+ }
+}
+
+void X86FrameLowering::restoreFPBPUsingSP(MachineFunction &MF,
+ MachineBasicBlock::iterator AfterMI,
+ bool SpillFP, bool SpillBP) const {
+ assert(SpillFP || SpillBP);
+
+ Register FP, BP;
+ const TargetRegisterClass *RC;
+ unsigned NumRegs = 0;
+ if (SpillFP) {
+ FP = TRI->getFrameRegister(MF);
+ if (STI.isTarget64BitILP32())
+ FP = Register(getX86SubSuperRegister(FP, 64));
+ RC = TRI->getMinimalPhysRegClass(FP);
----------------
rnk wrote:
This register class calculation is the same between spill and restore FPBP.
I suggest you can restructure this to have one method, `saveAndRestoreFPBPUsingSP`, which takes `BeforeMI` and `AfterMI`, calculates this shared state once, and then calls `spill/restoreFPBPUsingSP`, and maybe just pass in the `FP/BP` Register variables. They are nullable, so you can check for `isValid` before pushing or popping.
`SPAdjust` will also be the same and only needs to be calculated once.
https://github.com/llvm/llvm-project/pull/81048
More information about the llvm-commits
mailing list