diff options
Diffstat (limited to 'llvm/lib/Target/X86/X86FrameLowering.cpp')
| -rw-r--r-- | llvm/lib/Target/X86/X86FrameLowering.cpp | 320 |
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); + } + } +} |
