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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

25

26using namespace llvm;

27

28#define DEBUG_TYPE "x86-wineh-unwindv2"

29

31 "Number of functions that meet Unwind v2 criteria");

33 "Number of functions that fail Unwind v2 criteria");

34

36 "x86-wineh-unwindv2-max-unwind-codes", cl::Hidden,

37 cl::desc("Maximum number of unwind codes permitted in each unwind info."),

39

42 cl::desc("Overwrites the Unwind v2 mode for testing purposes."));

43

44namespace {

45

47public:

48 static char ID;

49

52 }

53

54 StringRef getPassName() const override { return "WinEH Unwind V2"; }

55

56 bool runOnMachineFunction(MachineFunction &MF) override;

57

58private:

59

60 static bool rejectCurrentFunctionInternalError(const MachineFunction &MF,

62 StringRef Reason);

63};

64

65enum class FunctionState {

66 InProlog,

67 HasProlog,

68 InEpilog,

69 FinishedEpilog,

70};

71

72}

73

74char X86WinEHUnwindV2::ID = 0;

75

77 "Analyze and emit instructions for Win64 Unwind v2", false,

78 false)

79

81 return new X86WinEHUnwindV2();

82}

83

86 if (MI.getDebugLoc())

87 return MI.getDebugLoc();

88

90}

91

92bool X86WinEHUnwindV2::runOnMachineFunction(MachineFunction &MF) {

97

98 if (Mode == WinX64EHUnwindV2Mode::Disabled)

99 return false;

100

101

102

103 FunctionState State = FunctionState::InProlog;

104

105

107 bool HasStackAlloc = false;

108 bool HasSetFrame = false;

109 unsigned ApproximatePrologCodeCount = 0;

110

111

113

114 for (MachineBasicBlock &MBB : MF) {

115

116

117 unsigned PoppedRegCount = 0;

118 bool HasStackDealloc = false;

119 MachineInstr *UnwindV2StartLocation = nullptr;

120

121 for (MachineInstr &MI : MBB) {

122 switch (MI.getOpcode()) {

123

124

125

126 case X86::SEH_PushReg:

127 if (State != FunctionState::InProlog)

129 ApproximatePrologCodeCount++;

130 PushedRegs.push_back(MI.getOperand(0).getImm());

131 break;

132

133 case X86::SEH_StackAlloc:

134 if (State != FunctionState::InProlog)

136

137 ApproximatePrologCodeCount += 3;

138 HasStackAlloc = true;

139 break;

140

141 case X86::SEH_SetFrame:

142 if (State != FunctionState::InProlog)

144 ApproximatePrologCodeCount++;

145 HasSetFrame = true;

146 break;

147

148 case X86::SEH_SaveReg:

149 case X86::SEH_SaveXMM:

150 if (State != FunctionState::InProlog)

151 llvm_unreachable("SEH_SaveXMM or SEH_SaveReg outside of prolog");

152

153 ApproximatePrologCodeCount += 3;

154 break;

155

156 case X86::SEH_PushFrame:

157 if (State != FunctionState::InProlog)

159 ApproximatePrologCodeCount++;

160 break;

161

162 case X86::SEH_EndPrologue:

163 if (State != FunctionState::InProlog)

165 State = FunctionState::HasProlog;

166 break;

167

168

169

170

171 case X86::SEH_BeginEpilogue:

172 if (State != FunctionState::HasProlog)

173 llvm_unreachable("SEH_BeginEpilogue in prolog or another epilog");

174 State = FunctionState::InEpilog;

175 break;

176

177 case X86::SEH_EndEpilogue:

178 if (State != FunctionState::InEpilog)

180 if (HasStackAlloc != HasStackDealloc)

181 return rejectCurrentFunctionInternalError(

183 "The prolog made a stack allocation, "

184 "but the epilog did not deallocate it");

185 if (PoppedRegCount != PushedRegs.size())

186 return rejectCurrentFunctionInternalError(

188 "The prolog pushed more registers than "

189 "the epilog popped");

190

191

192

193 if (!UnwindV2StartLocation)

194 UnwindV2StartLocation = &MI;

195 UnwindV2StartLocations.push_back(UnwindV2StartLocation);

196 State = FunctionState::FinishedEpilog;

197 break;

198

199 case X86::MOV64rr:

200 if (State == FunctionState::InEpilog) {

201

202

203 if (!HasSetFrame)

204 return rejectCurrentFunctionInternalError(

206 "The epilog is setting frame back, but prolog did not set it");

207 if (PoppedRegCount > 0)

208 return rejectCurrentFunctionInternalError(

210 "The epilog is setting the frame back after popping "

211 "registers");

212 if (HasStackDealloc)

213 return rejectCurrentFunctionInternalError(

215 "Cannot set the frame back after the stack "

216 "allocation has been deallocated");

217 } else if (State == FunctionState::FinishedEpilog)

218 return rejectCurrentFunctionInternalError(

219 MF, Mode, "Unexpected mov instruction after the epilog");

220 break;

221

222 case X86::LEA64r:

223 case X86::ADD64ri32:

224 if (State == FunctionState::InEpilog) {

225

226

227 if (!HasStackAlloc)

228 return rejectCurrentFunctionInternalError(

230 "The epilog is deallocating a stack "

231 "allocation, but the prolog did "

232 "not allocate one");

233 if (PoppedRegCount > 0)

234 return rejectCurrentFunctionInternalError(

236 "The epilog is deallocating a stack allocation after popping "

237 "registers");

238

239 HasStackDealloc = true;

240 } else if (State == FunctionState::FinishedEpilog)

241 return rejectCurrentFunctionInternalError(

242 MF, Mode, "Unexpected lea or add instruction after the epilog");

243 break;

244

245 case X86::POP64r:

246 if (State == FunctionState::InEpilog) {

248 if (HasStackAlloc && (PoppedRegCount == 0) &&

250

251

252 HasStackDealloc = true;

253 } else {

254

255

256 PoppedRegCount++;

257 if (HasStackAlloc != HasStackDealloc)

258 return rejectCurrentFunctionInternalError(

260 "Cannot pop registers before the stack "

261 "allocation has been deallocated");

262 if (PoppedRegCount > PushedRegs.size())

263 return rejectCurrentFunctionInternalError(

265 "The epilog is popping more registers than the prolog "

266 "pushed");

267 if (PushedRegs[PushedRegs.size() - PoppedRegCount] != Reg.id())

268 return rejectCurrentFunctionInternalError(

270 "The epilog is popping a registers in "

271 "a different order than the "

272 "prolog pushed them");

273

274

275

276

277

278 if (!UnwindV2StartLocation) {

279 assert(PoppedRegCount == 1);

280 UnwindV2StartLocation = &MI;

281 }

282 }

283 } else if (State == FunctionState::FinishedEpilog)

284

285 return rejectCurrentFunctionInternalError(

286 MF, Mode, "Registers are being popped after the epilog");

287 break;

288

289 default:

290 if (MI.isTerminator()) {

291 if (State == FunctionState::FinishedEpilog)

292

293

294 State = FunctionState::HasProlog;

295 else if (State == FunctionState::InEpilog)

297 } else if (MI.isDebugOrPseudoInstr()) {

298 if ((State == FunctionState::FinishedEpilog) ||

299 (State == FunctionState::InEpilog))

300

301 return rejectCurrentFunctionInternalError(

302 MF, Mode, "Unexpected instruction in or after the epilog");

303 }

304 }

305 }

306 }

307

308 if (UnwindV2StartLocations.empty())

309 return false;

310

311 MachineBasicBlock &FirstMBB = MF.front();

312

313

314

315 if (ApproximatePrologCodeCount + UnwindV2StartLocations.size() + 1 >

317 if (Mode == WinX64EHUnwindV2Mode::Required)

318 MF.getFunction().getContext().diagnose(DiagnosticInfoGenericWithLoc(

319 "Windows x64 Unwind v2 is required, but the function '" +

320 MF.getName() +

321 "' has too many unwind codes. Try splitting the function or "

322 "reducing the number of places where it exits early with a tail "

323 "call.",

325

326 FailsUnwindV2Criteria++;

327 return false;

328 }

329

330 MeetsUnwindV2Criteria++;

331

332

333 const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo();

334 for (MachineInstr *MI : UnwindV2StartLocations) {

336 TII->get(X86::SEH_UnwindV2Start));

337 }

338

340 TII->get(X86::SEH_UnwindVersion))

342

343 return true;

344}

345

346bool X86WinEHUnwindV2::rejectCurrentFunctionInternalError(

348 if (Mode == WinX64EHUnwindV2Mode::Required)

350 "generated incompatible code in function '" +

351 MF.getName() + "': " + Reason);

352

353 FailsUnwindV2Criteria++;

354 return false;

355}

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

const TargetInstrInfo & TII

Module.h This file contains the declarations for the Module class.

Promote Memory to Register

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

static cl::opt< RegAllocEvictionAdvisorAnalysisLegacy::AdvisorMode > Mode("regalloc-enable-advisor", cl::Hidden, cl::init(RegAllocEvictionAdvisorAnalysisLegacy::AdvisorMode::Default), cl::desc("Enable regalloc advisor mode"), cl::values(clEnumValN(RegAllocEvictionAdvisorAnalysisLegacy::AdvisorMode::Default, "default", "Default"), clEnumValN(RegAllocEvictionAdvisorAnalysisLegacy::AdvisorMode::Release, "release", "precompiled"), clEnumValN(RegAllocEvictionAdvisorAnalysisLegacy::AdvisorMode::Development, "development", "for training")))

This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...

#define STATISTIC(VARNAME, DESC)

DebugLoc findDebugLoc(const MachineBasicBlock &MBB)

Definition X86WinEHUnwindV2.cpp:84

static cl::opt< unsigned > ForceMode("x86-wineh-unwindv2-force-mode", cl::Hidden, cl::desc("Overwrites the Unwind v2 mode for testing purposes."))

static cl::opt< unsigned > MaximumUnwindCodes("x86-wineh-unwindv2-max-unwind-codes", cl::Hidden, cl::desc("Maximum number of unwind codes permitted in each unwind info."), cl::init(UINT8_MAX))

static DebugLoc getUnknown()

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

Module * getParent()

Get the module that this global value is contained inside of...

const MCInstrDesc & get(unsigned Opcode) const

Return the machine instruction descriptor that corresponds to the specified instruction opcode.

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

StringRef getName() const

getName - Return the name of the corresponding LLVM function.

Function & getFunction()

Return the LLVM function that this machine code represents.

const MachineInstrBuilder & addImm(int64_t Val) const

Add a new immediate operand.

Representation of each machine instruction.

WinX64EHUnwindV2Mode getWinX64EHUnwindV2Mode() const

Get how unwind v2 (epilog) information should be generated for x64 Windows.

static LLVM_ABI PassRegistry * getPassRegistry()

getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...

constexpr unsigned id() const

void push_back(const T &Elt)

#define llvm_unreachable(msg)

Marks that the current location is not supposed to be reachable.

unsigned ID

LLVM IR allows to use arbitrary numbers as calling convention identifiers.

initializer< Ty > init(const Ty &Val)

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.

LLVM_ABI void reportFatalInternalError(Error Err)

Report a fatal error that indicates a bug in LLVM.

void initializeX86WinEHUnwindV2Pass(PassRegistry &)

class LLVM_GSL_OWNER SmallVector

Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...

FunctionPass * createX86WinEHUnwindV2Pass()

// Analyzes and emits pseudos to support Win x64 Unwind V2.

bool is_contained(R &&Range, const E &Element)

Returns true if Element is found in Range.