summaryrefslogtreecommitdiff
path: root/llvm/lib/Target/X86/X86FrameLowering.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/Target/X86/X86FrameLowering.cpp')
-rw-r--r--llvm/lib/Target/X86/X86FrameLowering.cpp320
1 files changed, 320 insertions, 0 deletions
diff --git a/llvm/lib/Target/X86/X86FrameLowering.cpp b/llvm/lib/Target/X86/X86FrameLowering.cpp
index bdc9a0d29670..77dac1197f85 100644
--- a/llvm/lib/Target/X86/X86FrameLowering.cpp
+++ b/llvm/lib/Target/X86/X86FrameLowering.cpp
@@ -4227,3 +4227,323 @@ void X86FrameLowering::restoreWinEHStackPointersInParent(
/*RestoreSP=*/IsSEH);
}
}
+
+// Compute the alignment gap between current SP after spilling FP/BP and the
+// next properly aligned stack offset.
+static int computeFPBPAlignmentGap(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,
+ Register FP, Register BP,
+ int SPAdjust) const {
+ assert(FP.isValid() || BP.isValid());
+
+ MachineBasicBlock *MBB = BeforeMI->getParent();
+ DebugLoc DL = BeforeMI->getDebugLoc();
+
+ // Spill FP.
+ if (FP.isValid()) {
+ BuildMI(*MBB, BeforeMI, DL,
+ TII.get(getPUSHOpcode(MF.getSubtarget<X86Subtarget>())))
+ .addReg(FP);
+ }
+
+ // Spill BP.
+ if (BP.isValid()) {
+ BuildMI(*MBB, BeforeMI, DL,
+ TII.get(getPUSHOpcode(MF.getSubtarget<X86Subtarget>())))
+ .addReg(BP);
+ }
+
+ // Make sure SP is aligned.
+ if (SPAdjust)
+ emitSPUpdate(*MBB, BeforeMI, DL, -SPAdjust, false);
+
+ // Emit unwinding information.
+ if (FP.isValid() && 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 (BP.isValid())
+ Offset += TRI->getSpillSize(*TRI->getMinimalPhysRegClass(BP));
+ // 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,
+ Register FP, Register BP,
+ int SPAdjust) const {
+ assert(FP.isValid() || BP.isValid());
+
+ // Adjust SP so it points to spilled FP or BP.
+ MachineBasicBlock *MBB = AfterMI->getParent();
+ MachineBasicBlock::iterator Pos = std::next(AfterMI);
+ DebugLoc DL = AfterMI->getDebugLoc();
+ if (SPAdjust)
+ emitSPUpdate(*MBB, Pos, DL, SPAdjust, false);
+
+ // Restore BP.
+ if (BP.isValid()) {
+ BuildMI(*MBB, Pos, DL,
+ TII.get(getPOPOpcode(MF.getSubtarget<X86Subtarget>())), BP);
+ }
+
+ // Restore FP.
+ if (FP.isValid()) {
+ BuildMI(*MBB, Pos, DL,
+ TII.get(getPOPOpcode(MF.getSubtarget<X86Subtarget>())), FP);
+
+ // Emit unwinding information.
+ if (needsDwarfCFI(MF)) {
+ // Restore original frame with .cfi_restore_state.
+ unsigned CFIIndex =
+ MF.addFrameInst(MCCFIInstruction::createRestoreState(nullptr));
+ BuildMI(*MBB, Pos, DL, TII.get(TargetOpcode::CFI_INSTRUCTION))
+ .addCFIIndex(CFIIndex);
+ }
+ }
+}
+
+void X86FrameLowering::saveAndRestoreFPBPUsingSP(
+ MachineFunction &MF, MachineBasicBlock::iterator BeforeMI,
+ 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);
+ ++NumRegs;
+ }
+ if (SpillBP) {
+ BP = TRI->getBaseRegister();
+ if (STI.isTarget64BitILP32())
+ BP = Register(getX86SubSuperRegister(BP, 64));
+ RC = TRI->getMinimalPhysRegClass(BP);
+ ++NumRegs;
+ }
+ int SPAdjust = computeFPBPAlignmentGap(MF, RC, NumRegs);
+
+ spillFPBPUsingSP(MF, BeforeMI, FP, BP, SPAdjust);
+ restoreFPBPUsingSP(MF, AfterMI, FP, BP, SPAdjust);
+}
+
+bool X86FrameLowering::skipSpillFPBP(
+ MachineFunction &MF, MachineBasicBlock::reverse_iterator &MI) const {
+ if (MI->getOpcode() == X86::LCMPXCHG16B_SAVE_RBX) {
+ // The pseudo instruction LCMPXCHG16B_SAVE_RBX is generated in the form
+ // SaveRbx = COPY RBX
+ // SaveRbx = LCMPXCHG16B_SAVE_RBX ..., SaveRbx, implicit-def rbx
+ // And later LCMPXCHG16B_SAVE_RBX is expanded to restore RBX from SaveRbx.
+ // We should skip this instruction sequence.
+ int FI;
+ unsigned Reg;
+ while (!(MI->getOpcode() == TargetOpcode::COPY &&
+ MI->getOperand(1).getReg() == X86::RBX) &&
+ !((Reg = TII.isStoreToStackSlot(*MI, FI)) && Reg == X86::RBX))
+ ++MI;
+ return true;
+ }
+ return false;
+}
+
+static bool isFPBPAccess(const MachineInstr &MI, Register FP, Register BP,
+ const TargetRegisterInfo *TRI, bool &AccessFP,
+ bool &AccessBP) {
+ AccessFP = AccessBP = false;
+ if (FP) {
+ if (MI.findRegisterUseOperandIdx(FP, TRI, false) != -1 ||
+ MI.findRegisterDefOperandIdx(FP, TRI, false, true) != -1)
+ AccessFP = true;
+ }
+ if (BP) {
+ if (MI.findRegisterUseOperandIdx(BP, TRI, false) != -1 ||
+ MI.findRegisterDefOperandIdx(BP, TRI, false, true) != -1)
+ AccessBP = true;
+ }
+ return AccessFP || AccessBP;
+}
+
+// Invoke instruction has been lowered to normal function call. We try to figure
+// out if MI comes from Invoke.
+// Do we have any better method?
+static bool isInvoke(const MachineInstr &MI, bool InsideEHLabels) {
+ if (!MI.isCall())
+ return false;
+ if (InsideEHLabels)
+ return true;
+
+ const MachineBasicBlock *MBB = MI.getParent();
+ if (!MBB->hasEHPadSuccessor())
+ return false;
+
+ // Check if there is another call instruction from MI to the end of MBB.
+ MachineBasicBlock::const_iterator MBBI = MI, ME = MBB->end();
+ for (++MBBI; MBBI != ME; ++MBBI)
+ if (MBBI->isCall())
+ return false;
+ return true;
+}
+
+/// If a function uses base pointer and the base pointer is clobbered by inline
+/// asm, RA doesn't detect this case, and after the inline asm, the base pointer
+/// contains garbage value.
+/// For example if a 32b x86 function uses base pointer esi, and esi is
+/// clobbered by following inline asm
+/// asm("rep movsb" : "+D"(ptr), "+S"(x), "+c"(c)::"memory");
+/// We need to save esi before the asm and restore it after the asm.
+///
+/// The problem can also occur to frame pointer if there is a function call, and
+/// the callee uses a different calling convention and clobbers the fp.
+///
+/// Because normal frame objects (spill slots) are accessed through fp/bp
+/// register, so we can't spill fp/bp to normal spill slots.
+///
+/// FIXME: There are 2 possible enhancements:
+/// 1. In many cases there are different physical registers not clobbered by
+/// inline asm, we can use one of them as base pointer. Or use a virtual
+/// register as base pointer and let RA allocate a physical register to it.
+/// 2. If there is no other instructions access stack with fp/bp from the
+/// inline asm to the epilog, and no cfi requirement for a correct fp, we can
+/// skip the save and restore operations.
+void X86FrameLowering::spillFPBP(MachineFunction &MF) const {
+ Register FP, BP;
+ const TargetFrameLowering &TFI = *MF.getSubtarget().getFrameLowering();
+ if (TFI.hasFP(MF))
+ FP = TRI->getFrameRegister(MF);
+ if (TRI->hasBasePointer(MF))
+ BP = TRI->getBaseRegister();
+ if (!FP && !BP)
+ return;
+
+ for (MachineBasicBlock &MBB : MF) {
+ bool InsideEHLabels = false;
+ auto MI = MBB.rbegin(), ME = MBB.rend();
+ auto TermMI = MBB.getFirstTerminator();
+ if (TermMI != MBB.begin())
+ MI = *(std::prev(TermMI));
+
+ while (MI != ME) {
+ // Skip frame setup/destroy instructions.
+ // Skip Invoke (call inside try block) instructions.
+ // Skip instructions handled by target.
+ if (MI->getFlag(MachineInstr::MIFlag::FrameSetup) ||
+ MI->getFlag(MachineInstr::MIFlag::FrameDestroy) ||
+ isInvoke(*MI, InsideEHLabels) || skipSpillFPBP(MF, MI)) {
+ ++MI;
+ continue;
+ }
+
+ if (MI->getOpcode() == TargetOpcode::EH_LABEL) {
+ InsideEHLabels = !InsideEHLabels;
+ ++MI;
+ continue;
+ }
+
+ bool AccessFP, AccessBP;
+ // Check if fp or bp is used in MI.
+ if (!isFPBPAccess(*MI, FP, BP, TRI, AccessFP, AccessBP)) {
+ ++MI;
+ continue;
+ }
+
+ // Look for the range [DefMI, KillMI] in which fp or bp is defined and
+ // used.
+ bool FPLive = false, BPLive = false;
+ bool SpillFP = false, SpillBP = false;
+ auto DefMI = MI, KillMI = MI;
+ do {
+ SpillFP |= AccessFP;
+ SpillBP |= AccessBP;
+
+ // Maintain FPLive and BPLive.
+ if (FPLive && MI->findRegisterDefOperandIdx(FP, TRI, false, true) != -1)
+ FPLive = false;
+ if (FP && MI->findRegisterUseOperandIdx(FP, TRI, false) != -1)
+ FPLive = true;
+ if (BPLive && MI->findRegisterDefOperandIdx(BP, TRI, false, true) != -1)
+ BPLive = false;
+ if (BP && MI->findRegisterUseOperandIdx(BP, TRI, false) != -1)
+ BPLive = true;
+
+ DefMI = MI++;
+ } while ((MI != ME) &&
+ (FPLive || BPLive ||
+ isFPBPAccess(*MI, FP, BP, TRI, AccessFP, AccessBP)));
+
+ // Don't need to save/restore if FP is accessed through llvm.frameaddress.
+ if (FPLive && !SpillBP)
+ continue;
+
+ // If the bp is clobbered by a call, we should save and restore outside of
+ // the frame setup instructions.
+ if (KillMI->isCall() && DefMI != ME) {
+ const TargetInstrInfo &TII = *MF.getSubtarget().getInstrInfo();
+ auto FrameSetup = std::next(DefMI);
+ // Look for frame setup instruction toward the start of the BB.
+ // If we reach another call instruction, it means no frame setup
+ // instruction for the current call instruction.
+ while (FrameSetup != ME && !TII.isFrameSetup(*FrameSetup) &&
+ !FrameSetup->isCall())
+ ++FrameSetup;
+ // If a frame setup instruction is found, we need to find out the
+ // corresponding frame destroy instruction.
+ if (FrameSetup != ME && TII.isFrameSetup(*FrameSetup)) {
+ while (!TII.isFrameInstr(*KillMI))
+ --KillMI;
+ DefMI = FrameSetup;
+ MI = DefMI;
+ ++MI;
+ }
+ }
+
+ // Call target function to spill and restore FP and BP registers.
+ saveAndRestoreFPBPUsingSP(MF, &(*DefMI), &(*KillMI), SpillFP, SpillBP);
+ }
+ }
+}