Mercurial > hg > Members > tobaru > cbc > CbC_llvm
diff lib/Target/X86/X86WinAllocaExpander.cpp @ 120:1172e4bd9c6f
update 4.0.0
author | mir3636 |
---|---|
date | Fri, 25 Nov 2016 19:14:25 +0900 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/Target/X86/X86WinAllocaExpander.cpp Fri Nov 25 19:14:25 2016 +0900 @@ -0,0 +1,295 @@ +//===----- X86WinAllocaExpander.cpp - Expand WinAlloca pseudo instruction -===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines a pass that expands WinAlloca pseudo-instructions. +// +// It performs a conservative analysis to determine whether each allocation +// falls within a region of the stack that is safe to use, or whether stack +// probes must be emitted. +// +//===----------------------------------------------------------------------===// + +#include "X86.h" +#include "X86InstrBuilder.h" +#include "X86InstrInfo.h" +#include "X86MachineFunctionInfo.h" +#include "X86Subtarget.h" +#include "llvm/ADT/PostOrderIterator.h" +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/Passes.h" +#include "llvm/IR/Function.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Target/TargetInstrInfo.h" + +using namespace llvm; + +namespace { + +class X86WinAllocaExpander : public MachineFunctionPass { +public: + X86WinAllocaExpander() : MachineFunctionPass(ID) {} + + bool runOnMachineFunction(MachineFunction &MF) override; + +private: + /// Strategies for lowering a WinAlloca. + enum Lowering { TouchAndSub, Sub, Probe }; + + /// Deterministic-order map from WinAlloca instruction to desired lowering. + typedef MapVector<MachineInstr*, Lowering> LoweringMap; + + /// Compute which lowering to use for each WinAlloca instruction. + void computeLowerings(MachineFunction &MF, LoweringMap& Lowerings); + + /// Get the appropriate lowering based on current offset and amount. + Lowering getLowering(int64_t CurrentOffset, int64_t AllocaAmount); + + /// Lower a WinAlloca instruction. + void lower(MachineInstr* MI, Lowering L); + + MachineRegisterInfo *MRI; + const X86Subtarget *STI; + const TargetInstrInfo *TII; + const X86RegisterInfo *TRI; + unsigned StackPtr; + unsigned SlotSize; + int64_t StackProbeSize; + + StringRef getPassName() const override { return "X86 WinAlloca Expander"; } + static char ID; +}; + +char X86WinAllocaExpander::ID = 0; + +} // end anonymous namespace + +FunctionPass *llvm::createX86WinAllocaExpander() { + return new X86WinAllocaExpander(); +} + +/// Return the allocation amount for a WinAlloca instruction, or -1 if unknown. +static int64_t getWinAllocaAmount(MachineInstr *MI, MachineRegisterInfo *MRI) { + assert(MI->getOpcode() == X86::WIN_ALLOCA_32 || + MI->getOpcode() == X86::WIN_ALLOCA_64); + assert(MI->getOperand(0).isReg()); + + unsigned AmountReg = MI->getOperand(0).getReg(); + MachineInstr *Def = MRI->getUniqueVRegDef(AmountReg); + + // Look through copies. + while (Def && Def->isCopy() && Def->getOperand(1).isReg()) + Def = MRI->getUniqueVRegDef(Def->getOperand(1).getReg()); + + if (!Def || + (Def->getOpcode() != X86::MOV32ri && Def->getOpcode() != X86::MOV64ri) || + !Def->getOperand(1).isImm()) + return -1; + + return Def->getOperand(1).getImm(); +} + +X86WinAllocaExpander::Lowering +X86WinAllocaExpander::getLowering(int64_t CurrentOffset, + int64_t AllocaAmount) { + // For a non-constant amount or a large amount, we have to probe. + if (AllocaAmount < 0 || AllocaAmount > StackProbeSize) + return Probe; + + // If it fits within the safe region of the stack, just subtract. + if (CurrentOffset + AllocaAmount <= StackProbeSize) + return Sub; + + // Otherwise, touch the current tip of the stack, then subtract. + return TouchAndSub; +} + +static bool isPushPop(const MachineInstr &MI) { + switch (MI.getOpcode()) { + case X86::PUSH32i8: + case X86::PUSH32r: + case X86::PUSH32rmm: + case X86::PUSH32rmr: + case X86::PUSHi32: + case X86::PUSH64i8: + case X86::PUSH64r: + case X86::PUSH64rmm: + case X86::PUSH64rmr: + case X86::PUSH64i32: + case X86::POP32r: + case X86::POP64r: + return true; + default: + return false; + } +} + +void X86WinAllocaExpander::computeLowerings(MachineFunction &MF, + LoweringMap &Lowerings) { + // Do a one-pass reverse post-order walk of the CFG to conservatively estimate + // the offset between the stack pointer and the lowest touched part of the + // stack, and use that to decide how to lower each WinAlloca instruction. + + // Initialize OutOffset[B], the stack offset at exit from B, to something big. + DenseMap<MachineBasicBlock *, int64_t> OutOffset; + for (MachineBasicBlock &MBB : MF) + OutOffset[&MBB] = INT32_MAX; + + // Note: we don't know the offset at the start of the entry block since the + // prologue hasn't been inserted yet, and how much that will adjust the stack + // pointer depends on register spills, which have not been computed yet. + + // Compute the reverse post-order. + ReversePostOrderTraversal<MachineFunction*> RPO(&MF); + + for (MachineBasicBlock *MBB : RPO) { + int64_t Offset = -1; + for (MachineBasicBlock *Pred : MBB->predecessors()) + Offset = std::max(Offset, OutOffset[Pred]); + if (Offset == -1) Offset = INT32_MAX; + + for (MachineInstr &MI : *MBB) { + if (MI.getOpcode() == X86::WIN_ALLOCA_32 || + MI.getOpcode() == X86::WIN_ALLOCA_64) { + // A WinAlloca moves StackPtr, and potentially touches it. + int64_t Amount = getWinAllocaAmount(&MI, MRI); + Lowering L = getLowering(Offset, Amount); + Lowerings[&MI] = L; + switch (L) { + case Sub: + Offset += Amount; + break; + case TouchAndSub: + Offset = Amount; + break; + case Probe: + Offset = 0; + break; + } + } else if (MI.isCall() || isPushPop(MI)) { + // Calls, pushes and pops touch the tip of the stack. + Offset = 0; + } else if (MI.getOpcode() == X86::ADJCALLSTACKUP32 || + MI.getOpcode() == X86::ADJCALLSTACKUP64) { + Offset -= MI.getOperand(0).getImm(); + } else if (MI.getOpcode() == X86::ADJCALLSTACKDOWN32 || + MI.getOpcode() == X86::ADJCALLSTACKDOWN64) { + Offset += MI.getOperand(0).getImm(); + } else if (MI.modifiesRegister(StackPtr, TRI)) { + // Any other modification of SP means we've lost track of it. + Offset = INT32_MAX; + } + } + + OutOffset[MBB] = Offset; + } +} + +static unsigned getSubOpcode(bool Is64Bit, int64_t Amount) { + if (Is64Bit) + return isInt<8>(Amount) ? X86::SUB64ri8 : X86::SUB64ri32; + return isInt<8>(Amount) ? X86::SUB32ri8 : X86::SUB32ri; +} + +void X86WinAllocaExpander::lower(MachineInstr* MI, Lowering L) { + DebugLoc DL = MI->getDebugLoc(); + MachineBasicBlock *MBB = MI->getParent(); + MachineBasicBlock::iterator I = *MI; + + int64_t Amount = getWinAllocaAmount(MI, MRI); + if (Amount == 0) { + MI->eraseFromParent(); + return; + } + + bool Is64Bit = STI->is64Bit(); + assert(SlotSize == 4 || SlotSize == 8); + unsigned RegA = (SlotSize == 8) ? X86::RAX : X86::EAX; + + switch (L) { + case TouchAndSub: + assert(Amount >= SlotSize); + + // Use a push to touch the top of the stack. + BuildMI(*MBB, I, DL, TII->get(Is64Bit ? X86::PUSH64r : X86::PUSH32r)) + .addReg(RegA, RegState::Undef); + Amount -= SlotSize; + if (!Amount) + break; + + // Fall through to make any remaining adjustment. + LLVM_FALLTHROUGH; + case Sub: + assert(Amount > 0); + if (Amount == SlotSize) { + // Use push to save size. + BuildMI(*MBB, I, DL, TII->get(Is64Bit ? X86::PUSH64r : X86::PUSH32r)) + .addReg(RegA, RegState::Undef); + } else { + // Sub. + BuildMI(*MBB, I, DL, TII->get(getSubOpcode(Is64Bit, Amount)), StackPtr) + .addReg(StackPtr) + .addImm(Amount); + } + break; + case Probe: + // The probe lowering expects the amount in RAX/EAX. + BuildMI(*MBB, MI, DL, TII->get(TargetOpcode::COPY), RegA) + .addReg(MI->getOperand(0).getReg()); + + // Do the probe. + STI->getFrameLowering()->emitStackProbe(*MBB->getParent(), *MBB, MI, DL, + /*InPrologue=*/false); + break; + } + + unsigned AmountReg = MI->getOperand(0).getReg(); + MI->eraseFromParent(); + + // Delete the definition of AmountReg, possibly walking a chain of copies. + for (;;) { + if (!MRI->use_empty(AmountReg)) + break; + MachineInstr *AmountDef = MRI->getUniqueVRegDef(AmountReg); + if (!AmountDef) + break; + if (AmountDef->isCopy() && AmountDef->getOperand(1).isReg()) + AmountReg = AmountDef->getOperand(1).isReg(); + AmountDef->eraseFromParent(); + break; + } +} + +bool X86WinAllocaExpander::runOnMachineFunction(MachineFunction &MF) { + if (!MF.getInfo<X86MachineFunctionInfo>()->hasWinAlloca()) + return false; + + MRI = &MF.getRegInfo(); + STI = &MF.getSubtarget<X86Subtarget>(); + TII = STI->getInstrInfo(); + TRI = STI->getRegisterInfo(); + StackPtr = TRI->getStackRegister(); + SlotSize = TRI->getSlotSize(); + + StackProbeSize = 4096; + if (MF.getFunction()->hasFnAttribute("stack-probe-size")) { + MF.getFunction() + ->getFnAttribute("stack-probe-size") + .getValueAsString() + .getAsInteger(0, StackProbeSize); + } + + LoweringMap Lowerings; + computeLowerings(MF, Lowerings); + for (auto &P : Lowerings) + lower(P.first, P.second); + + return true; +}