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

1

2

3

4

5

6

7

8

19

20using namespace llvm;

22

23namespace {

24

26 formatted_raw_ostream &OS;

27 MCInstPrinter &InstPrinter;

28

29public:

30 X86WinCOFFAsmTargetStreamer(MCStreamer &S, formatted_raw_ostream &OS,

31 MCInstPrinter &InstPrinter)

32 : X86TargetStreamer(S), OS(OS), InstPrinter(InstPrinter) {}

33

34 void emitCode16() override;

35 void emitCode32() override;

36 void emitCode64() override;

37

38 bool emitFPOProc(const MCSymbol *ProcSym, unsigned ParamsSize,

39 SMLoc L) override;

40 bool emitFPOEndPrologue(SMLoc L) override;

41 bool emitFPOEndProc(SMLoc L) override;

42 bool emitFPOData(const MCSymbol *ProcSym, SMLoc L) override;

43 bool emitFPOPushReg(MCRegister Reg, SMLoc L) override;

44 bool emitFPOStackAlloc(unsigned StackAlloc, SMLoc L) override;

45 bool emitFPOStackAlign(unsigned Align, SMLoc L) override;

46 bool emitFPOSetFrame(MCRegister Reg, SMLoc L) override;

47};

48

49

50struct FPOInstruction {

52 enum Operation {

53 PushReg,

54 StackAlloc,

55 StackAlign,

56 SetFrame,

57 } Op;

58

59 unsigned RegOrOffset;

60};

61

62struct FPOData {

63 const MCSymbol *Function = nullptr;

65 MCSymbol *PrologueEnd = nullptr;

67 unsigned ParamsSize = 0;

68

70};

71

72

74

75 DenseMap<const MCSymbol *, std::unique_ptr> AllFPOData;

76

77

78 std::unique_ptr CurFPOData;

79

80 bool haveOpenFPOData() { return !!CurFPOData; }

81

82

83

84 bool checkInFPOPrologue(SMLoc L);

85

87

88public:

89 X86WinCOFFTargetStreamer(MCStreamer &S) : X86TargetStreamer(S) {}

90

91 bool emitFPOProc(const MCSymbol *ProcSym, unsigned ParamsSize,

92 SMLoc L) override;

93 bool emitFPOEndPrologue(SMLoc L) override;

94 bool emitFPOEndProc(SMLoc L) override;

95 bool emitFPOData(const MCSymbol *ProcSym, SMLoc L) override;

96 bool emitFPOPushReg(MCRegister Reg, SMLoc L) override;

97 bool emitFPOStackAlloc(unsigned StackAlloc, SMLoc L) override;

98 bool emitFPOStackAlign(unsigned Align, SMLoc L) override;

99 bool emitFPOSetFrame(MCRegister Reg, SMLoc L) override;

100};

101}

102

103void X86WinCOFFAsmTargetStreamer::emitCode16() { OS << "\t.code16\n"; }

104

105void X86WinCOFFAsmTargetStreamer::emitCode32() { OS << "\t.code32\n"; }

106

107void X86WinCOFFAsmTargetStreamer::emitCode64() { OS << "\t.code64\n"; }

108

109bool X86WinCOFFAsmTargetStreamer::emitFPOProc(const MCSymbol *ProcSym,

110 unsigned ParamsSize, SMLoc L) {

111 OS << "\t.cv_fpo_proc\t";

113 OS << ' ' << ParamsSize << '\n';

114 return false;

115}

116

117bool X86WinCOFFAsmTargetStreamer::emitFPOEndPrologue(SMLoc L) {

118 OS << "\t.cv_fpo_endprologue\n";

119 return false;

120}

121

122bool X86WinCOFFAsmTargetStreamer::emitFPOEndProc(SMLoc L) {

123 OS << "\t.cv_fpo_endproc\n";

124 return false;

125}

126

127bool X86WinCOFFAsmTargetStreamer::emitFPOData(const MCSymbol *ProcSym,

128 SMLoc L) {

129 OS << "\t.cv_fpo_data\t";

130 ProcSym->print(OS, getStreamer().getContext().getAsmInfo());

131 OS << '\n';

132 return false;

133}

134

135bool X86WinCOFFAsmTargetStreamer::emitFPOPushReg(MCRegister Reg, SMLoc L) {

136 OS << "\t.cv_fpo_pushreg\t";

138 OS << '\n';

139 return false;

140}

141

142bool X86WinCOFFAsmTargetStreamer::emitFPOStackAlloc(unsigned StackAlloc,

143 SMLoc L) {

144 OS << "\t.cv_fpo_stackalloc\t" << StackAlloc << '\n';

145 return false;

146}

147

148bool X86WinCOFFAsmTargetStreamer::emitFPOStackAlign(unsigned Align, SMLoc L) {

149 OS << "\t.cv_fpo_stackalign\t" << Align << '\n';

150 return false;

151}

152

153bool X86WinCOFFAsmTargetStreamer::emitFPOSetFrame(MCRegister Reg, SMLoc L) {

154 OS << "\t.cv_fpo_setframe\t";

156 OS << '\n';

157 return false;

158}

159

160bool X86WinCOFFTargetStreamer::checkInFPOPrologue(SMLoc L) {

161 if (!haveOpenFPOData() || CurFPOData->PrologueEnd) {

163 L,

164 "directive must appear between .cv_fpo_proc and .cv_fpo_endprologue");

165 return true;

166 }

167 return false;

168}

169

170MCSymbol *X86WinCOFFTargetStreamer::emitFPOLabel() {

172 getStreamer().emitLabel(Label);

174}

175

176bool X86WinCOFFTargetStreamer::emitFPOProc(const MCSymbol *ProcSym,

177 unsigned ParamsSize, SMLoc L) {

178 if (haveOpenFPOData()) {

180 L, "opening new .cv_fpo_proc before closing previous frame");

181 return true;

182 }

183 CurFPOData = std::make_unique();

184 CurFPOData->Function = ProcSym;

185 CurFPOData->Begin = emitFPOLabel();

186 CurFPOData->ParamsSize = ParamsSize;

187 return false;

188}

189

190bool X86WinCOFFTargetStreamer::emitFPOEndProc(SMLoc L) {

191 if (!haveOpenFPOData()) {

192 getContext().reportError(L, ".cv_fpo_endproc must appear after .cv_proc");

193 return true;

194 }

195 if (!CurFPOData->PrologueEnd) {

196

197 if (!CurFPOData->Instructions.empty()) {

198 getContext().reportError(L, "missing .cv_fpo_endprologue");

199 CurFPOData->Instructions.clear();

200 }

201

202

203

204 CurFPOData->PrologueEnd = CurFPOData->Begin;

205 }

206

207 CurFPOData->End = emitFPOLabel();

208 const MCSymbol *Fn = CurFPOData->Function;

209 AllFPOData.insert({Fn, std::move(CurFPOData)});

210 return false;

211}

212

213bool X86WinCOFFTargetStreamer::emitFPOSetFrame(MCRegister Reg, SMLoc L) {

214 if (checkInFPOPrologue(L))

215 return true;

216 FPOInstruction Inst;

217 Inst.Label = emitFPOLabel();

218 Inst.Op = FPOInstruction::SetFrame;

219 Inst.RegOrOffset = Reg.id();

220 CurFPOData->Instructions.push_back(Inst);

221 return false;

222}

223

224bool X86WinCOFFTargetStreamer::emitFPOPushReg(MCRegister Reg, SMLoc L) {

225 if (checkInFPOPrologue(L))

226 return true;

227 FPOInstruction Inst;

228 Inst.Label = emitFPOLabel();

229 Inst.Op = FPOInstruction::PushReg;

230 Inst.RegOrOffset = Reg.id();

231 CurFPOData->Instructions.push_back(Inst);

232 return false;

233}

234

235bool X86WinCOFFTargetStreamer::emitFPOStackAlloc(unsigned StackAlloc, SMLoc L) {

236 if (checkInFPOPrologue(L))

237 return true;

238 FPOInstruction Inst;

239 Inst.Label = emitFPOLabel();

240 Inst.Op = FPOInstruction::StackAlloc;

241 Inst.RegOrOffset = StackAlloc;

242 CurFPOData->Instructions.push_back(Inst);

243 return false;

244}

245

246bool X86WinCOFFTargetStreamer::emitFPOStackAlign(unsigned Align, SMLoc L) {

247 if (checkInFPOPrologue(L))

248 return true;

249 if (llvm::none_of(CurFPOData->Instructions, [](const FPOInstruction &Inst) {

250 return Inst.Op == FPOInstruction::SetFrame;

251 })) {

253 L, "a frame register must be established before aligning the stack");

254 return true;

255 }

256 FPOInstruction Inst;

257 Inst.Label = emitFPOLabel();

258 Inst.Op = FPOInstruction::StackAlign;

259 Inst.RegOrOffset = Align;

260 CurFPOData->Instructions.push_back(Inst);

261 return false;

262}

263

264bool X86WinCOFFTargetStreamer::emitFPOEndPrologue(SMLoc L) {

265 if (checkInFPOPrologue(L))

266 return true;

267 CurFPOData->PrologueEnd = emitFPOLabel();

268 return false;

269}

270

271namespace {

272struct RegSaveOffset {

274

275 unsigned Reg = 0;

277};

278

279struct FPOStateMachine {

280 explicit FPOStateMachine(const FPOData *FPO) : FPO(FPO) {}

281

282 const FPOData *FPO = nullptr;

283 unsigned FrameReg = 0;

284 unsigned FrameRegOff = 0;

285 unsigned CurOffset = 0;

286 unsigned LocalSize = 0;

287 unsigned SavedRegSize = 0;

288 unsigned StackOffsetBeforeAlign = 0;

289 unsigned StackAlign = 0;

290 unsigned Flags = 0;

291

292 SmallString<128> FrameFunc;

293

295

296 void emitFrameDataRecord(MCStreamer &OS, MCSymbol *Label);

297};

298}

299

302 switch (LLVMReg) {

303

304

305 case X86::EAX: OS << "$eax"; break;

306 case X86::EBX: OS << "$ebx"; break;

307 case X86::ECX: OS << "$ecx"; break;

308 case X86::EDX: OS << "$edx"; break;

309 case X86::EDI: OS << "$edi"; break;

310 case X86::ESI: OS << "$esi"; break;

311 case X86::ESP: OS << "$esp"; break;

312 case X86::EBP: OS << "$ebp"; break;

313 case X86::EIP: OS << "$eip"; break;

314

315 default:

316 OS << '$' << MRI->getCodeViewRegNum(LLVMReg);

317 break;

318 }

319 });

320}

321

322void FPOStateMachine::emitFrameDataRecord(MCStreamer &OS, MCSymbol *Label) {

323 unsigned CurFlags = Flags;

324 if (Label == FPO->Begin)

326

327

328 FrameFunc.clear();

329 raw_svector_ostream FuncOS(FrameFunc);

331 assert((StackAlign == 0 || FrameReg != 0) &&

332 "cannot align stack without frame reg");

333 StringRef CFAVar = StackAlign == 0 ? "$T0" : "$T1";

334

335 if (FrameReg) {

336

337 FuncOS << CFAVar << ' ' << printFPOReg(MRI, FrameReg) << ' ' << FrameRegOff

338 << " + = ";

339

340

341

342

343

344 if (StackAlign) {

345 FuncOS << "$T0 " << CFAVar << ' ' << StackOffsetBeforeAlign << " - "

346 << StackAlign << " @ = ";

347 }

348 } else {

349

350

351

352

353 FuncOS << CFAVar << " .raSearch = ";

354 }

355

356

357 FuncOS << "$eip " << CFAVar << " ^ = ";

358 FuncOS << "$esp " << CFAVar << " 4 + = ";

359

360

361 for (RegSaveOffset RO : RegSaveOffsets)

362 FuncOS << printFPOReg(MRI, RO.Reg) << ' ' << CFAVar << ' ' << RO.Offset

363 << " - ^ = ";

364

365

367 unsigned FrameFuncStrTabOff = CVCtx.addToStringTable(FuncOS.str()).second;

368

369

370 unsigned MaxStackSize = 0;

371

372

373

374

375

376

377

378

379

380

381

382

388 OS.emitInt32(FrameFuncStrTabOff);

392}

393

394

395bool X86WinCOFFTargetStreamer::emitFPOData(const MCSymbol *ProcSym, SMLoc L) {

396 MCStreamer &OS = getStreamer();

398

399 auto I = AllFPOData.find(ProcSym);

400 if (I == AllFPOData.end()) {

401 Ctx.reportError(L, Twine("no FPO data found for symbol ") +

403 return true;

404 }

405 const FPOData *FPO = I->second.get();

406 assert(FPO->Begin && FPO->End && FPO->PrologueEnd && "missing FPO label");

407

410

411 OS.emitInt32(unsigned(DebugSubsectionKind::FrameData));

414

415

418 4);

419

420

421 FPOStateMachine FSM(FPO);

422

423 FSM.emitFrameDataRecord(OS, FPO->Begin);

424 for (const FPOInstruction &Inst : FPO->Instructions) {

425 switch (Inst.Op) {

426 case FPOInstruction::PushReg:

427 FSM.CurOffset += 4;

428 FSM.SavedRegSize += 4;

429 FSM.RegSaveOffsets.push_back({Inst.RegOrOffset, FSM.CurOffset});

430 break;

431 case FPOInstruction::SetFrame:

432 FSM.FrameReg = Inst.RegOrOffset;

433 FSM.FrameRegOff = FSM.CurOffset;

434 break;

435 case FPOInstruction::StackAlign:

436 FSM.StackOffsetBeforeAlign = FSM.CurOffset;

437 FSM.StackAlign = Inst.RegOrOffset;

438 break;

439 case FPOInstruction::StackAlloc:

440 FSM.CurOffset += Inst.RegOrOffset;

441 FSM.LocalSize += Inst.RegOrOffset;

442

443 if (FSM.FrameReg)

444 continue;

445 break;

446 }

447 FSM.emitFrameDataRecord(OS, Inst.Label);

448 }

449

452 return false;

453}

454

458

459

460 return new X86WinCOFFAsmTargetStreamer(S, OS, *InstPrinter);

461}

462

465

468

469 return new X86WinCOFFTargetStreamer(S);

470}

unsigned const MachineRegisterInfo * MRI

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

static Printable printFPOReg(const MCRegisterInfo *MRI, unsigned LLVMReg)

Definition X86WinCOFFTargetStreamer.cpp:300

std::pair< StringRef, unsigned > addToStringTable(StringRef S)

Add something to the string table.

LLVM_ABI MCSymbol * createTempSymbol()

Create a temporary symbol with a unique name.

LLVM_ABI CodeViewContext & getCVContext()

const MCRegisterInfo * getRegisterInfo() const

LLVM_ABI void reportError(SMLoc L, const Twine &Msg)

This is an instance of a target assembly language printer that converts an MCInst to valid target ass...

virtual void printRegName(raw_ostream &OS, MCRegister Reg)

Print the assembler register name.

MCRegisterInfo base class - We assume that the target defines a static array of MCRegisterDesc object...

Streaming machine code generation interface.

MCContext & getContext() const

void emitValue(const MCExpr *Value, unsigned Size, SMLoc Loc=SMLoc())

virtual void emitAbsoluteSymbolDiff(const MCSymbol *Hi, const MCSymbol *Lo, unsigned Size)

Emit the absolute difference between two symbols.

virtual void emitLabel(MCSymbol *Symbol, SMLoc Loc=SMLoc())

Emit a label for Symbol into the current section.

virtual void emitValueToAlignment(Align Alignment, int64_t Fill=0, uint8_t FillLen=1, unsigned MaxBytesToEmit=0)

Emit some number of copies of Value until the byte alignment ByteAlignment is reached.

void emitInt16(uint64_t Value)

void emitInt32(uint64_t Value)

Generic base class for all target subtargets.

const Triple & getTargetTriple() const

static const MCSymbolRefExpr * create(const MCSymbol *Symbol, MCContext &Ctx, SMLoc Loc=SMLoc())

LLVM_ABI void print(raw_ostream &OS, const MCAsmInfo *MAI) const

print - Print the value to the stream OS.

StringRef getName() const

getName - Get the symbol name.

Target specific streamer interface.

Simple wrapper around std::function<void(raw_ostream&)>.

constexpr unsigned id() const

bool isOSBinFormatCOFF() const

Tests whether the OS uses the COFF binary format.

X86 target streamer implementing x86-only assembly directives.

formatted_raw_ostream - A raw_ostream that wraps another one and keeps track of line and column posit...

This class implements an extremely fast bulk output stream that can only output to a stream.

constexpr char Align[]

Key for Kernel::Arg::Metadata::mAlign.

Context & getContext() const

This is an optimization pass for GlobalISel generic memory operations.

MCTargetStreamer * createX86ObjectTargetStreamer(MCStreamer &S, const MCSubtargetInfo &STI)

Implements X86-only directives for object files.

Definition X86WinCOFFTargetStreamer.cpp:464

MCTargetStreamer * createX86AsmTargetStreamer(MCStreamer &S, formatted_raw_ostream &OS, MCInstPrinter *InstPrinter)

Implements X86-only directives for assembly emission.

Definition X86WinCOFFTargetStreamer.cpp:455

bool none_of(R &&Range, UnaryPredicate P)

Provide wrappers to std::none_of which take ranges instead of having to pass begin/end explicitly.

class LLVM_GSL_OWNER SmallVector

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