//===---- X86ArgumentStackSlotRebase.cpp - rebase argument stack slot -----===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This pass replace the frame register with a GPR virtual register and set // the stack offset for each instruction which reference argument from stack. // //===----------------------------------------------------------------------===// #include "X86.h" #include "X86InstrBuilder.h" #include "X86MachineFunctionInfo.h" #include "X86RegisterInfo.h" #include "X86Subtarget.h" #include "llvm/CodeGen/MachineBasicBlock.h" #include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/MachineInstr.h" #include "llvm/CodeGen/MachineOperand.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/CodeGen/TargetOpcodes.h" #include "llvm/CodeGen/TargetRegisterInfo.h" #include "llvm/CodeGen/TargetSubtargetInfo.h" #include "llvm/IR/Attributes.h" #include "llvm/IR/Function.h" #include "llvm/InitializePasses.h" #include "llvm/Pass.h" using namespace llvm; #define DEBUG_TYPE "x86argumentstackrebase" namespace { class X86ArgumentStackSlotPass : public MachineFunctionPass { public: static char ID; // Pass identification, replacement for typeid explicit X86ArgumentStackSlotPass() : MachineFunctionPass(ID) { initializeX86ArgumentStackSlotPassPass(*PassRegistry::getPassRegistry()); } bool runOnMachineFunction(MachineFunction &MF) override; void getAnalysisUsage(AnalysisUsage &AU) const override { AU.setPreservesCFG(); MachineFunctionPass::getAnalysisUsage(AU); } }; } // end anonymous namespace char X86ArgumentStackSlotPass::ID = 0; INITIALIZE_PASS(X86ArgumentStackSlotPass, DEBUG_TYPE, "Argument Stack Rebase", false, false) FunctionPass *llvm::createX86ArgumentStackSlotPass() { return new X86ArgumentStackSlotPass(); } static Register getArgBaseReg(MachineFunction &MF) { MachineRegisterInfo &MRI = MF.getRegInfo(); const X86Subtarget &STI = MF.getSubtarget(); const Function &F = MF.getFunction(); CallingConv::ID CC = F.getCallingConv(); Register NoReg; const TargetRegisterClass *RC = nullptr; switch (CC) { // We need a virtual register in case there is inline assembly // clobber argument base register. case CallingConv::C: RC = STI.is64Bit() ? &X86::GR64_ArgRefRegClass : &X86::GR32_ArgRefRegClass; break; case CallingConv::X86_RegCall: // FIXME: For regcall there is no scratch register on 32-bit target. // We may use a callee saved register as argument base register and // save it before being changed as base pointer. We need DW_CFA to // indicate where the callee saved register is saved, so that it can // be correctly unwind. // push ebx // mov ebx, esp // and esp, -128 // ... // pop ebx // ret RC = STI.is64Bit() ? &X86::GR64_ArgRefRegClass : nullptr; break; // TODO: Refine register class for each calling convention. default: break; } if (RC) return MRI.createVirtualRegister(RC); else return NoReg; } bool X86ArgumentStackSlotPass::runOnMachineFunction(MachineFunction &MF) { const Function &F = MF.getFunction(); MachineFrameInfo &MFI = MF.getFrameInfo(); const X86Subtarget &STI = MF.getSubtarget(); const X86RegisterInfo *TRI = STI.getRegisterInfo(); const X86InstrInfo *TII = STI.getInstrInfo(); X86MachineFunctionInfo *X86FI = MF.getInfo(); bool Changed = false; if (F.hasFnAttribute(Attribute::Naked)) return false; // Only support Linux and ELF. if (!STI.isTargetLinux() && !STI.isTargetELF()) return false; if (!TRI->hasBasePointer(MF)) return false; // Don't support X32 if (STI.isTarget64BitILP32()) return false; Register BasePtr = TRI->getBaseRegister(); auto IsBaseRegisterClobbered = [&]() { for (MachineBasicBlock &MBB : MF) { for (MachineInstr &MI : MBB) { if (!MI.isInlineAsm()) continue; for (MachineOperand &MO : MI.operands()) { if (!MO.isReg()) continue; Register Reg = MO.getReg(); if (!Register::isPhysicalRegister(Reg)) continue; if (TRI->isSuperOrSubRegisterEq(BasePtr, Reg)) return true; } } } return false; }; if (!IsBaseRegisterClobbered()) return false; Register ArgBaseReg = getArgBaseReg(MF); if (!ArgBaseReg.isValid()) return false; // leal 4(%esp), %reg MachineBasicBlock &MBB = MF.front(); MachineBasicBlock::iterator MBBI = MBB.begin(); DebugLoc DL; // Emit instruction to copy get stack pointer to a virtual register // and save the instruction to x86 machine functon info. We can get // physical register of ArgBaseReg after register allocation. The // stack slot is used to save/restore argument base pointer. We can // get the index from the instruction. unsigned SlotSize = TRI->getSlotSize(); int FI = MFI.CreateSpillStackObject(SlotSize, Align(SlotSize)); // Use pseudo LEA to prevent the instruction from being eliminated. // TODO: if it is duplicated we can expand it to lea. MachineInstr *LEA = BuildMI(MBB, MBBI, DL, TII->get(STI.is64Bit() ? X86::PLEA64r : X86::PLEA32r), ArgBaseReg) .addFrameIndex(FI) .addImm(1) .addUse(X86::NoRegister) .addImm(SlotSize) .addUse(X86::NoRegister) .setMIFlag(MachineInstr::FrameSetup); X86FI->setStackPtrSaveMI(LEA); for (MachineBasicBlock &MBB : MF) { for (MachineInstr &MI : MBB) { int I = 0; for (MachineOperand &MO : MI.operands()) { if (MO.isFI()) { int Idx = MO.getIndex(); if (!MFI.isFixedObjectIndex(Idx)) continue; int64_t Offset = MFI.getObjectOffset(Idx); if (Offset < 0) continue; // TODO replace register for debug instruction if (MI.isDebugInstr()) continue; // Replace frame register with argument base pointer and its offset. TRI->eliminateFrameIndex(MI.getIterator(), I, ArgBaseReg, Offset); Changed = true; } ++I; } } } return Changed; }