File: X86ArgumentStackSlotRebase.cpp

package info (click to toggle)
llvm-toolchain-17 1%3A17.0.6-22
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 1,799,624 kB
  • sloc: cpp: 6,428,607; ansic: 1,383,196; asm: 793,408; python: 223,504; objc: 75,364; f90: 60,502; lisp: 33,869; pascal: 15,282; sh: 9,684; perl: 7,453; ml: 4,937; awk: 3,523; makefile: 2,889; javascript: 2,149; xml: 888; fortran: 619; cs: 573
file content (198 lines) | stat: -rw-r--r-- 6,561 bytes parent folder | download | duplicates (6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
//===---- 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<X86Subtarget>();
  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<X86Subtarget>();
  const X86RegisterInfo *TRI = STI.getRegisterInfo();
  const X86InstrInfo *TII = STI.getInstrInfo();
  X86MachineFunctionInfo *X86FI = MF.getInfo<X86MachineFunctionInfo>();
  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;
}