LLVM: lib/Target/X86/X86DynAllocaExpander.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

31

32using namespace llvm;

33

34namespace {

35

36class X86DynAllocaExpander {

37public:

38 bool run(MachineFunction &MF);

39

40private:

41

42 enum Lowering { TouchAndSub, Sub, Probe };

43

44

45 typedef MapVector<MachineInstr*, Lowering> LoweringMap;

46

47

48 void computeLowerings(MachineFunction &MF, LoweringMap& Lowerings);

49

50

51 Lowering getLowering(int64_t CurrentOffset, int64_t AllocaAmount);

52

53

54 void lower(MachineInstr* MI, Lowering L);

55

56 MachineRegisterInfo *MRI = nullptr;

57 const X86Subtarget *STI = nullptr;

58 const TargetInstrInfo *TII = nullptr;

59 const X86RegisterInfo *TRI = nullptr;

61 unsigned SlotSize = 0;

62 int64_t StackProbeSize = 0;

63 bool NoStackArgProbe = false;

64};

65

67public:

68 X86DynAllocaExpanderLegacy() : MachineFunctionPass(ID) {}

69

70 bool runOnMachineFunction(MachineFunction &MF) override;

71

72private:

73 StringRef getPassName() const override { return "X86 DynAlloca Expander"; }

74

75public:

76 static char ID;

77};

78

79char X86DynAllocaExpanderLegacy::ID = 0;

80

81}

82

83INITIALIZE_PASS(X86DynAllocaExpanderLegacy, "x86-dyn-alloca-expander",

84 "X86 DynAlloca Expander", false, false)

85

87 return new X86DynAllocaExpanderLegacy();

88}

89

90

92 assert(MI->getOpcode() == X86::DYN_ALLOCA_32 ||

93 MI->getOpcode() == X86::DYN_ALLOCA_64);

94 assert(MI->getOperand(0).isReg());

95

96 Register AmountReg = MI->getOperand(0).getReg();

98

99 if (!Def ||

100 (Def->getOpcode() != X86::MOV32ri && Def->getOpcode() != X86::MOV64ri) ||

101 !Def->getOperand(1).isImm())

102 return -1;

103

104 return Def->getOperand(1).getImm();

105}

106

107X86DynAllocaExpander::Lowering

108X86DynAllocaExpander::getLowering(int64_t CurrentOffset,

109 int64_t AllocaAmount) {

110

111 if (AllocaAmount < 0 || AllocaAmount > StackProbeSize)

112 return Probe;

113

114

115 if (CurrentOffset + AllocaAmount <= StackProbeSize)

116 return Sub;

117

118

119 return TouchAndSub;

120}

121

123 switch (MI.getOpcode()) {

124 case X86::PUSH32r:

125 case X86::PUSH32rmm:

126 case X86::PUSH32rmr:

127 case X86::PUSH32i:

128 case X86::PUSH64r:

129 case X86::PUSH64rmm:

130 case X86::PUSH64rmr:

131 case X86::PUSH64i32:

132 case X86::POP32r:

133 case X86::POP64r:

134 return true;

135 default:

136 return false;

137 }

138}

139

140void X86DynAllocaExpander::computeLowerings(MachineFunction &MF,

141 LoweringMap &Lowerings) {

142

143

144

145

146

147 DenseMap<MachineBasicBlock *, int64_t> OutOffset;

148 for (MachineBasicBlock &MBB : MF)

149 OutOffset[&MBB] = INT32_MAX;

150

151

152

153

154

155

156 ReversePostOrderTraversal<MachineFunction*> RPO(&MF);

157

158 for (MachineBasicBlock *MBB : RPO) {

163

164 for (MachineInstr &MI : *MBB) {

165 if (MI.getOpcode() == X86::DYN_ALLOCA_32 ||

166 MI.getOpcode() == X86::DYN_ALLOCA_64) {

167

170 Lowerings[&MI] = L;

171 switch (L) {

172 case Sub:

174 break;

175 case TouchAndSub:

177 break;

178 case Probe:

180 break;

181 }

183

185 } else if (MI.getOpcode() == X86::ADJCALLSTACKUP32 ||

186 MI.getOpcode() == X86::ADJCALLSTACKUP64) {

187 Offset -= MI.getOperand(0).getImm();

188 } else if (MI.getOpcode() == X86::ADJCALLSTACKDOWN32 ||

189 MI.getOpcode() == X86::ADJCALLSTACKDOWN64) {

190 Offset += MI.getOperand(0).getImm();

191 } else if (MI.modifiesRegister(StackPtr, TRI)) {

192

194 }

195 }

196

198 }

199}

200

202 if (Is64Bit)

203 return X86::SUB64ri32;

204 return X86::SUB32ri;

205}

206

207void X86DynAllocaExpander::lower(MachineInstr *MI, Lowering L) {

209 MachineBasicBlock *MBB = MI->getParent();

211

213 if (Amount == 0) {

214 MI->eraseFromParent();

215 return;

216 }

217

218

219

220 bool Is64Bit = STI->is64Bit();

221 bool Is64BitAlloca = MI->getOpcode() == X86::DYN_ALLOCA_64;

222 assert(SlotSize == 4 || SlotSize == 8);

223

224 std::optionalMachineFunction::DebugInstrOperandPair InstrNum;

225 if (unsigned Num = MI->peekDebugInstrNum()) {

226

227 InstrNum = {Num, 2};

228 }

229

230 switch (L) {

231 case TouchAndSub: {

232 assert(Amount >= SlotSize);

233

234

235 unsigned RegA = Is64Bit ? X86::RAX : X86::EAX;

236 BuildMI(*MBB, I, DL, TII->get(Is64Bit ? X86::PUSH64r : X86::PUSH32r))

238 Amount -= SlotSize;

239 if (!Amount)

240 break;

241

242

243 [[fallthrough]];

244 }

245 case Sub:

247 if (Amount == SlotSize) {

248

249 unsigned RegA = Is64Bit ? X86::RAX : X86::EAX;

250 BuildMI(*MBB, I, DL, TII->get(Is64Bit ? X86::PUSH64r : X86::PUSH32r))

252 } else {

253

257 }

258 break;

259 case Probe:

260 if (!NoStackArgProbe) {

261

262 unsigned RegA = Is64BitAlloca ? X86::RAX : X86::EAX;

264 .addReg(MI->getOperand(0).getReg());

265

266

268 false, InstrNum);

269 } else {

270

272 TII->get(Is64BitAlloca ? X86::SUB64rr : X86::SUB32rr), StackPtr)

274 .addReg(MI->getOperand(0).getReg());

275 }

276 break;

277 }

278

279 Register AmountReg = MI->getOperand(0).getReg();

280 MI->eraseFromParent();

281

282

283 if (MRI->use_empty(AmountReg))

284 if (MachineInstr *AmountDef = MRI->getUniqueVRegDef(AmountReg))

285 AmountDef->eraseFromParent();

286}

287

288bool X86DynAllocaExpander::run(MachineFunction &MF) {

289 if (!MF.getInfo()->hasDynAlloca())

290 return false;

291

296 StackPtr = TRI->getStackRegister();

297 SlotSize = TRI->getSlotSize();

300 if (NoStackArgProbe)

302

303 LoweringMap Lowerings;

304 computeLowerings(MF, Lowerings);

305 for (auto &P : Lowerings)

306 lower(P.first, P.second);

307

308 return true;

309}

310

311bool X86DynAllocaExpanderLegacy::runOnMachineFunction(MachineFunction &MF) {

312 return X86DynAllocaExpander().run(MF);

313}

314

315PreservedAnalyses

318 bool Changed = X86DynAllocaExpander().run(MF);

321

324 return PA;

325}

unsigned const MachineRegisterInfo * MRI

assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")

MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL

const HexagonInstrInfo * TII

Register const TargetRegisterInfo * TRI

This file implements a map that provides insertion order iteration.

Promote Memory to Register

#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)

This file builds on the ADT/GraphTraits.h file to build a generic graph post order iterator.

pre isel intrinsic Pre ISel Intrinsic Lowering

static bool isPushPop(const MachineInstr &MI)

Definition X86DynAllocaExpander.cpp:122

static int64_t getDynAllocaAmount(MachineInstr *MI, MachineRegisterInfo *MRI)

Return the allocation amount for a DynAlloca instruction, or -1 if unknown.

Definition X86DynAllocaExpander.cpp:91

static unsigned getSubOpcode(bool Is64Bit)

Definition X86DynAllocaExpander.cpp:201

Represents analyses that only rely on functions' control flow.

FunctionPass class - This class is used to implement most global optimizations.

bool hasFnAttribute(Attribute::AttrKind Kind) const

Return true if the function has the attribute.

const MachineFunction * getParent() const

Return the MachineFunction containing this basic block.

iterator_range< pred_iterator > predecessors()

MachineInstrBundleIterator< MachineInstr > iterator

MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...

const TargetSubtargetInfo & getSubtarget() const

getSubtarget - Return the subtarget for which this machine code is being compiled.

MachineRegisterInfo & getRegInfo()

getRegInfo - Return information about the registers currently in use.

Function & getFunction()

Return the LLVM function that this machine code represents.

Ty * getInfo()

getInfo - Keep track of various per-function pieces of information for backends that would like to do...

const MachineInstrBuilder & addImm(int64_t Val) const

Add a new immediate operand.

const MachineInstrBuilder & addReg(Register RegNo, unsigned flags=0, unsigned SubReg=0) const

Add a new virtual register operand.

Representation of each machine instruction.

MachineRegisterInfo - Keep track of information for virtual and physical registers,...

A set of analyses that are preserved following a run of a transformation pass.

static PreservedAnalyses none()

Convenience factory function for the empty preserved set.

static PreservedAnalyses all()

Construct a special preserved set that preserves all passes.

PreservedAnalyses & preserveSet()

Mark an analysis set as preserved.

Wrapper class representing virtual and physical registers.

PreservedAnalyses run(MachineFunction &MF, MachineFunctionAnalysisManager &MFAM)

Definition X86DynAllocaExpander.cpp:316

void emitStackProbe(MachineFunction &MF, MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, const DebugLoc &DL, bool InProlog, std::optional< MachineFunction::DebugInstrOperandPair > InstrNum=std::nullopt) const

Emit target stack probe code.

const X86TargetLowering * getTargetLowering() const override

const X86InstrInfo * getInstrInfo() const override

const X86RegisterInfo * getRegisterInfo() const override

const X86FrameLowering * getFrameLowering() const override

unsigned getStackProbeSize(const MachineFunction &MF) const

Pass manager infrastructure for declaring and invalidating analyses.

@ Undef

Value of the register doesn't matter.

PointerTypeMap run(const Module &M)

Compute the PointerTypeMap for the module M.

This is an optimization pass for GlobalISel generic memory operations.

MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)

Builder interface. Specify how to create the initial instruction itself.

FunctionPass * createX86DynAllocaExpanderLegacyPass()

AnalysisManager< MachineFunction > MachineFunctionAnalysisManager

@ Sub

Subtraction of integers.