10b57cec5SDimitry Andric //===-- X86WinCOFFTargetStreamer.cpp ----------------------------*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric
90b57cec5SDimitry Andric #include "X86MCTargetDesc.h"
100b57cec5SDimitry Andric #include "X86TargetStreamer.h"
110b57cec5SDimitry Andric #include "llvm/DebugInfo/CodeView/CodeView.h"
120b57cec5SDimitry Andric #include "llvm/MC/MCCodeView.h"
130b57cec5SDimitry Andric #include "llvm/MC/MCContext.h"
140b57cec5SDimitry Andric #include "llvm/MC/MCInstPrinter.h"
150b57cec5SDimitry Andric #include "llvm/MC/MCRegisterInfo.h"
160b57cec5SDimitry Andric #include "llvm/MC/MCSubtargetInfo.h"
1781ad6265SDimitry Andric #include "llvm/MC/MCSymbol.h"
180b57cec5SDimitry Andric #include "llvm/Support/FormattedStream.h"
190b57cec5SDimitry Andric
200b57cec5SDimitry Andric using namespace llvm;
210b57cec5SDimitry Andric using namespace llvm::codeview;
220b57cec5SDimitry Andric
230b57cec5SDimitry Andric namespace {
240b57cec5SDimitry Andric /// Implements Windows x86-only directives for assembly emission.
250b57cec5SDimitry Andric class X86WinCOFFAsmTargetStreamer : public X86TargetStreamer {
260b57cec5SDimitry Andric formatted_raw_ostream &OS;
270b57cec5SDimitry Andric MCInstPrinter &InstPrinter;
280b57cec5SDimitry Andric
290b57cec5SDimitry Andric public:
X86WinCOFFAsmTargetStreamer(MCStreamer & S,formatted_raw_ostream & OS,MCInstPrinter & InstPrinter)300b57cec5SDimitry Andric X86WinCOFFAsmTargetStreamer(MCStreamer &S, formatted_raw_ostream &OS,
310b57cec5SDimitry Andric MCInstPrinter &InstPrinter)
320b57cec5SDimitry Andric : X86TargetStreamer(S), OS(OS), InstPrinter(InstPrinter) {}
330b57cec5SDimitry Andric
340b57cec5SDimitry Andric bool emitFPOProc(const MCSymbol *ProcSym, unsigned ParamsSize,
350b57cec5SDimitry Andric SMLoc L) override;
360b57cec5SDimitry Andric bool emitFPOEndPrologue(SMLoc L) override;
370b57cec5SDimitry Andric bool emitFPOEndProc(SMLoc L) override;
380b57cec5SDimitry Andric bool emitFPOData(const MCSymbol *ProcSym, SMLoc L) override;
390b57cec5SDimitry Andric bool emitFPOPushReg(unsigned Reg, SMLoc L) override;
400b57cec5SDimitry Andric bool emitFPOStackAlloc(unsigned StackAlloc, SMLoc L) override;
410b57cec5SDimitry Andric bool emitFPOStackAlign(unsigned Align, SMLoc L) override;
420b57cec5SDimitry Andric bool emitFPOSetFrame(unsigned Reg, SMLoc L) override;
430b57cec5SDimitry Andric };
440b57cec5SDimitry Andric
450b57cec5SDimitry Andric /// Represents a single FPO directive.
460b57cec5SDimitry Andric struct FPOInstruction {
470b57cec5SDimitry Andric MCSymbol *Label;
480b57cec5SDimitry Andric enum Operation {
490b57cec5SDimitry Andric PushReg,
500b57cec5SDimitry Andric StackAlloc,
510b57cec5SDimitry Andric StackAlign,
520b57cec5SDimitry Andric SetFrame,
530b57cec5SDimitry Andric } Op;
540b57cec5SDimitry Andric unsigned RegOrOffset;
550b57cec5SDimitry Andric };
560b57cec5SDimitry Andric
570b57cec5SDimitry Andric struct FPOData {
580b57cec5SDimitry Andric const MCSymbol *Function = nullptr;
590b57cec5SDimitry Andric MCSymbol *Begin = nullptr;
600b57cec5SDimitry Andric MCSymbol *PrologueEnd = nullptr;
610b57cec5SDimitry Andric MCSymbol *End = nullptr;
620b57cec5SDimitry Andric unsigned ParamsSize = 0;
630b57cec5SDimitry Andric
640b57cec5SDimitry Andric SmallVector<FPOInstruction, 5> Instructions;
650b57cec5SDimitry Andric };
660b57cec5SDimitry Andric
670b57cec5SDimitry Andric /// Implements Windows x86-only directives for object emission.
680b57cec5SDimitry Andric class X86WinCOFFTargetStreamer : public X86TargetStreamer {
690b57cec5SDimitry Andric /// Map from function symbol to its FPO data.
700b57cec5SDimitry Andric DenseMap<const MCSymbol *, std::unique_ptr<FPOData>> AllFPOData;
710b57cec5SDimitry Andric
720b57cec5SDimitry Andric /// Current FPO data created by .cv_fpo_proc.
730b57cec5SDimitry Andric std::unique_ptr<FPOData> CurFPOData;
740b57cec5SDimitry Andric
haveOpenFPOData()750b57cec5SDimitry Andric bool haveOpenFPOData() { return !!CurFPOData; }
760b57cec5SDimitry Andric
770b57cec5SDimitry Andric /// Diagnoses an error at L if we are not in an FPO prologue. Return true on
780b57cec5SDimitry Andric /// error.
790b57cec5SDimitry Andric bool checkInFPOPrologue(SMLoc L);
800b57cec5SDimitry Andric
810b57cec5SDimitry Andric MCSymbol *emitFPOLabel();
820b57cec5SDimitry Andric
getContext()830b57cec5SDimitry Andric MCContext &getContext() { return getStreamer().getContext(); }
840b57cec5SDimitry Andric
850b57cec5SDimitry Andric public:
X86WinCOFFTargetStreamer(MCStreamer & S)860b57cec5SDimitry Andric X86WinCOFFTargetStreamer(MCStreamer &S) : X86TargetStreamer(S) {}
870b57cec5SDimitry Andric
880b57cec5SDimitry Andric bool emitFPOProc(const MCSymbol *ProcSym, unsigned ParamsSize,
890b57cec5SDimitry Andric SMLoc L) override;
900b57cec5SDimitry Andric bool emitFPOEndPrologue(SMLoc L) override;
910b57cec5SDimitry Andric bool emitFPOEndProc(SMLoc L) override;
920b57cec5SDimitry Andric bool emitFPOData(const MCSymbol *ProcSym, SMLoc L) override;
930b57cec5SDimitry Andric bool emitFPOPushReg(unsigned Reg, SMLoc L) override;
940b57cec5SDimitry Andric bool emitFPOStackAlloc(unsigned StackAlloc, SMLoc L) override;
950b57cec5SDimitry Andric bool emitFPOStackAlign(unsigned Align, SMLoc L) override;
960b57cec5SDimitry Andric bool emitFPOSetFrame(unsigned Reg, SMLoc L) override;
970b57cec5SDimitry Andric };
980b57cec5SDimitry Andric } // end namespace
990b57cec5SDimitry Andric
emitFPOProc(const MCSymbol * ProcSym,unsigned ParamsSize,SMLoc L)1000b57cec5SDimitry Andric bool X86WinCOFFAsmTargetStreamer::emitFPOProc(const MCSymbol *ProcSym,
1010b57cec5SDimitry Andric unsigned ParamsSize, SMLoc L) {
1020b57cec5SDimitry Andric OS << "\t.cv_fpo_proc\t";
1030b57cec5SDimitry Andric ProcSym->print(OS, getStreamer().getContext().getAsmInfo());
1040b57cec5SDimitry Andric OS << ' ' << ParamsSize << '\n';
1050b57cec5SDimitry Andric return false;
1060b57cec5SDimitry Andric }
1070b57cec5SDimitry Andric
emitFPOEndPrologue(SMLoc L)1080b57cec5SDimitry Andric bool X86WinCOFFAsmTargetStreamer::emitFPOEndPrologue(SMLoc L) {
1090b57cec5SDimitry Andric OS << "\t.cv_fpo_endprologue\n";
1100b57cec5SDimitry Andric return false;
1110b57cec5SDimitry Andric }
1120b57cec5SDimitry Andric
emitFPOEndProc(SMLoc L)1130b57cec5SDimitry Andric bool X86WinCOFFAsmTargetStreamer::emitFPOEndProc(SMLoc L) {
1140b57cec5SDimitry Andric OS << "\t.cv_fpo_endproc\n";
1150b57cec5SDimitry Andric return false;
1160b57cec5SDimitry Andric }
1170b57cec5SDimitry Andric
emitFPOData(const MCSymbol * ProcSym,SMLoc L)1180b57cec5SDimitry Andric bool X86WinCOFFAsmTargetStreamer::emitFPOData(const MCSymbol *ProcSym,
1190b57cec5SDimitry Andric SMLoc L) {
1200b57cec5SDimitry Andric OS << "\t.cv_fpo_data\t";
1210b57cec5SDimitry Andric ProcSym->print(OS, getStreamer().getContext().getAsmInfo());
1220b57cec5SDimitry Andric OS << '\n';
1230b57cec5SDimitry Andric return false;
1240b57cec5SDimitry Andric }
1250b57cec5SDimitry Andric
emitFPOPushReg(unsigned Reg,SMLoc L)1260b57cec5SDimitry Andric bool X86WinCOFFAsmTargetStreamer::emitFPOPushReg(unsigned Reg, SMLoc L) {
1270b57cec5SDimitry Andric OS << "\t.cv_fpo_pushreg\t";
1280b57cec5SDimitry Andric InstPrinter.printRegName(OS, Reg);
1290b57cec5SDimitry Andric OS << '\n';
1300b57cec5SDimitry Andric return false;
1310b57cec5SDimitry Andric }
1320b57cec5SDimitry Andric
emitFPOStackAlloc(unsigned StackAlloc,SMLoc L)1330b57cec5SDimitry Andric bool X86WinCOFFAsmTargetStreamer::emitFPOStackAlloc(unsigned StackAlloc,
1340b57cec5SDimitry Andric SMLoc L) {
1350b57cec5SDimitry Andric OS << "\t.cv_fpo_stackalloc\t" << StackAlloc << '\n';
1360b57cec5SDimitry Andric return false;
1370b57cec5SDimitry Andric }
1380b57cec5SDimitry Andric
emitFPOStackAlign(unsigned Align,SMLoc L)1390b57cec5SDimitry Andric bool X86WinCOFFAsmTargetStreamer::emitFPOStackAlign(unsigned Align, SMLoc L) {
1400b57cec5SDimitry Andric OS << "\t.cv_fpo_stackalign\t" << Align << '\n';
1410b57cec5SDimitry Andric return false;
1420b57cec5SDimitry Andric }
1430b57cec5SDimitry Andric
emitFPOSetFrame(unsigned Reg,SMLoc L)1440b57cec5SDimitry Andric bool X86WinCOFFAsmTargetStreamer::emitFPOSetFrame(unsigned Reg, SMLoc L) {
1450b57cec5SDimitry Andric OS << "\t.cv_fpo_setframe\t";
1460b57cec5SDimitry Andric InstPrinter.printRegName(OS, Reg);
1470b57cec5SDimitry Andric OS << '\n';
1480b57cec5SDimitry Andric return false;
1490b57cec5SDimitry Andric }
1500b57cec5SDimitry Andric
checkInFPOPrologue(SMLoc L)1510b57cec5SDimitry Andric bool X86WinCOFFTargetStreamer::checkInFPOPrologue(SMLoc L) {
1520b57cec5SDimitry Andric if (!haveOpenFPOData() || CurFPOData->PrologueEnd) {
1530b57cec5SDimitry Andric getContext().reportError(
1540b57cec5SDimitry Andric L,
1550b57cec5SDimitry Andric "directive must appear between .cv_fpo_proc and .cv_fpo_endprologue");
1560b57cec5SDimitry Andric return true;
1570b57cec5SDimitry Andric }
1580b57cec5SDimitry Andric return false;
1590b57cec5SDimitry Andric }
1600b57cec5SDimitry Andric
emitFPOLabel()1610b57cec5SDimitry Andric MCSymbol *X86WinCOFFTargetStreamer::emitFPOLabel() {
1620b57cec5SDimitry Andric MCSymbol *Label = getContext().createTempSymbol("cfi", true);
1635ffd83dbSDimitry Andric getStreamer().emitLabel(Label);
1640b57cec5SDimitry Andric return Label;
1650b57cec5SDimitry Andric }
1660b57cec5SDimitry Andric
emitFPOProc(const MCSymbol * ProcSym,unsigned ParamsSize,SMLoc L)1670b57cec5SDimitry Andric bool X86WinCOFFTargetStreamer::emitFPOProc(const MCSymbol *ProcSym,
1680b57cec5SDimitry Andric unsigned ParamsSize, SMLoc L) {
1690b57cec5SDimitry Andric if (haveOpenFPOData()) {
1700b57cec5SDimitry Andric getContext().reportError(
1710b57cec5SDimitry Andric L, "opening new .cv_fpo_proc before closing previous frame");
1720b57cec5SDimitry Andric return true;
1730b57cec5SDimitry Andric }
1748bcb0991SDimitry Andric CurFPOData = std::make_unique<FPOData>();
1750b57cec5SDimitry Andric CurFPOData->Function = ProcSym;
1760b57cec5SDimitry Andric CurFPOData->Begin = emitFPOLabel();
1770b57cec5SDimitry Andric CurFPOData->ParamsSize = ParamsSize;
1780b57cec5SDimitry Andric return false;
1790b57cec5SDimitry Andric }
1800b57cec5SDimitry Andric
emitFPOEndProc(SMLoc L)1810b57cec5SDimitry Andric bool X86WinCOFFTargetStreamer::emitFPOEndProc(SMLoc L) {
1820b57cec5SDimitry Andric if (!haveOpenFPOData()) {
1830b57cec5SDimitry Andric getContext().reportError(L, ".cv_fpo_endproc must appear after .cv_proc");
1840b57cec5SDimitry Andric return true;
1850b57cec5SDimitry Andric }
1860b57cec5SDimitry Andric if (!CurFPOData->PrologueEnd) {
1870b57cec5SDimitry Andric // Complain if there were prologue setup instructions but no end prologue.
1880b57cec5SDimitry Andric if (!CurFPOData->Instructions.empty()) {
1890b57cec5SDimitry Andric getContext().reportError(L, "missing .cv_fpo_endprologue");
1900b57cec5SDimitry Andric CurFPOData->Instructions.clear();
1910b57cec5SDimitry Andric }
1920b57cec5SDimitry Andric
1930b57cec5SDimitry Andric // Claim there is a zero-length prologue to make the label math work out
1940b57cec5SDimitry Andric // later.
1950b57cec5SDimitry Andric CurFPOData->PrologueEnd = CurFPOData->Begin;
1960b57cec5SDimitry Andric }
1970b57cec5SDimitry Andric
1980b57cec5SDimitry Andric CurFPOData->End = emitFPOLabel();
1990b57cec5SDimitry Andric const MCSymbol *Fn = CurFPOData->Function;
2000b57cec5SDimitry Andric AllFPOData.insert({Fn, std::move(CurFPOData)});
2010b57cec5SDimitry Andric return false;
2020b57cec5SDimitry Andric }
2030b57cec5SDimitry Andric
emitFPOSetFrame(unsigned Reg,SMLoc L)2040b57cec5SDimitry Andric bool X86WinCOFFTargetStreamer::emitFPOSetFrame(unsigned Reg, SMLoc L) {
2050b57cec5SDimitry Andric if (checkInFPOPrologue(L))
2060b57cec5SDimitry Andric return true;
2070b57cec5SDimitry Andric FPOInstruction Inst;
2080b57cec5SDimitry Andric Inst.Label = emitFPOLabel();
2090b57cec5SDimitry Andric Inst.Op = FPOInstruction::SetFrame;
2100b57cec5SDimitry Andric Inst.RegOrOffset = Reg;
2110b57cec5SDimitry Andric CurFPOData->Instructions.push_back(Inst);
2120b57cec5SDimitry Andric return false;
2130b57cec5SDimitry Andric }
2140b57cec5SDimitry Andric
emitFPOPushReg(unsigned Reg,SMLoc L)2150b57cec5SDimitry Andric bool X86WinCOFFTargetStreamer::emitFPOPushReg(unsigned Reg, SMLoc L) {
2160b57cec5SDimitry Andric if (checkInFPOPrologue(L))
2170b57cec5SDimitry Andric return true;
2180b57cec5SDimitry Andric FPOInstruction Inst;
2190b57cec5SDimitry Andric Inst.Label = emitFPOLabel();
2200b57cec5SDimitry Andric Inst.Op = FPOInstruction::PushReg;
2210b57cec5SDimitry Andric Inst.RegOrOffset = Reg;
2220b57cec5SDimitry Andric CurFPOData->Instructions.push_back(Inst);
2230b57cec5SDimitry Andric return false;
2240b57cec5SDimitry Andric }
2250b57cec5SDimitry Andric
emitFPOStackAlloc(unsigned StackAlloc,SMLoc L)2260b57cec5SDimitry Andric bool X86WinCOFFTargetStreamer::emitFPOStackAlloc(unsigned StackAlloc, SMLoc L) {
2270b57cec5SDimitry Andric if (checkInFPOPrologue(L))
2280b57cec5SDimitry Andric return true;
2290b57cec5SDimitry Andric FPOInstruction Inst;
2300b57cec5SDimitry Andric Inst.Label = emitFPOLabel();
2310b57cec5SDimitry Andric Inst.Op = FPOInstruction::StackAlloc;
2320b57cec5SDimitry Andric Inst.RegOrOffset = StackAlloc;
2330b57cec5SDimitry Andric CurFPOData->Instructions.push_back(Inst);
2340b57cec5SDimitry Andric return false;
2350b57cec5SDimitry Andric }
2360b57cec5SDimitry Andric
emitFPOStackAlign(unsigned Align,SMLoc L)2370b57cec5SDimitry Andric bool X86WinCOFFTargetStreamer::emitFPOStackAlign(unsigned Align, SMLoc L) {
2380b57cec5SDimitry Andric if (checkInFPOPrologue(L))
2390b57cec5SDimitry Andric return true;
2400eae32dcSDimitry Andric if (llvm::none_of(CurFPOData->Instructions, [](const FPOInstruction &Inst) {
2410b57cec5SDimitry Andric return Inst.Op == FPOInstruction::SetFrame;
2420b57cec5SDimitry Andric })) {
2430b57cec5SDimitry Andric getContext().reportError(
2440b57cec5SDimitry Andric L, "a frame register must be established before aligning the stack");
2450b57cec5SDimitry Andric return true;
2460b57cec5SDimitry Andric }
2470b57cec5SDimitry Andric FPOInstruction Inst;
2480b57cec5SDimitry Andric Inst.Label = emitFPOLabel();
2490b57cec5SDimitry Andric Inst.Op = FPOInstruction::StackAlign;
2500b57cec5SDimitry Andric Inst.RegOrOffset = Align;
2510b57cec5SDimitry Andric CurFPOData->Instructions.push_back(Inst);
2520b57cec5SDimitry Andric return false;
2530b57cec5SDimitry Andric }
2540b57cec5SDimitry Andric
emitFPOEndPrologue(SMLoc L)2550b57cec5SDimitry Andric bool X86WinCOFFTargetStreamer::emitFPOEndPrologue(SMLoc L) {
2560b57cec5SDimitry Andric if (checkInFPOPrologue(L))
2570b57cec5SDimitry Andric return true;
2580b57cec5SDimitry Andric CurFPOData->PrologueEnd = emitFPOLabel();
2590b57cec5SDimitry Andric return false;
2600b57cec5SDimitry Andric }
2610b57cec5SDimitry Andric
2620b57cec5SDimitry Andric namespace {
2630b57cec5SDimitry Andric struct RegSaveOffset {
RegSaveOffset__anone4092d9c0311::RegSaveOffset2640b57cec5SDimitry Andric RegSaveOffset(unsigned Reg, unsigned Offset) : Reg(Reg), Offset(Offset) {}
2650b57cec5SDimitry Andric
2660b57cec5SDimitry Andric unsigned Reg = 0;
2670b57cec5SDimitry Andric unsigned Offset = 0;
2680b57cec5SDimitry Andric };
2690b57cec5SDimitry Andric
2700b57cec5SDimitry Andric struct FPOStateMachine {
FPOStateMachine__anone4092d9c0311::FPOStateMachine2710b57cec5SDimitry Andric explicit FPOStateMachine(const FPOData *FPO) : FPO(FPO) {}
2720b57cec5SDimitry Andric
2730b57cec5SDimitry Andric const FPOData *FPO = nullptr;
2740b57cec5SDimitry Andric unsigned FrameReg = 0;
2750b57cec5SDimitry Andric unsigned FrameRegOff = 0;
2760b57cec5SDimitry Andric unsigned CurOffset = 0;
2770b57cec5SDimitry Andric unsigned LocalSize = 0;
2780b57cec5SDimitry Andric unsigned SavedRegSize = 0;
2790b57cec5SDimitry Andric unsigned StackOffsetBeforeAlign = 0;
2800b57cec5SDimitry Andric unsigned StackAlign = 0;
2810b57cec5SDimitry Andric unsigned Flags = 0; // FIXME: Set HasSEH / HasEH.
2820b57cec5SDimitry Andric
2830b57cec5SDimitry Andric SmallString<128> FrameFunc;
2840b57cec5SDimitry Andric
2850b57cec5SDimitry Andric SmallVector<RegSaveOffset, 4> RegSaveOffsets;
2860b57cec5SDimitry Andric
2870b57cec5SDimitry Andric void emitFrameDataRecord(MCStreamer &OS, MCSymbol *Label);
2880b57cec5SDimitry Andric };
2890b57cec5SDimitry Andric } // end namespace
2900b57cec5SDimitry Andric
printFPOReg(const MCRegisterInfo * MRI,unsigned LLVMReg)2910b57cec5SDimitry Andric static Printable printFPOReg(const MCRegisterInfo *MRI, unsigned LLVMReg) {
2920b57cec5SDimitry Andric return Printable([MRI, LLVMReg](raw_ostream &OS) {
2930b57cec5SDimitry Andric switch (LLVMReg) {
2940b57cec5SDimitry Andric // MSVC only seems to emit symbolic register names for EIP, EBP, and ESP,
2950b57cec5SDimitry Andric // but the format seems to support more than that, so we emit them.
2960b57cec5SDimitry Andric case X86::EAX: OS << "$eax"; break;
2970b57cec5SDimitry Andric case X86::EBX: OS << "$ebx"; break;
2980b57cec5SDimitry Andric case X86::ECX: OS << "$ecx"; break;
2990b57cec5SDimitry Andric case X86::EDX: OS << "$edx"; break;
3000b57cec5SDimitry Andric case X86::EDI: OS << "$edi"; break;
3010b57cec5SDimitry Andric case X86::ESI: OS << "$esi"; break;
3020b57cec5SDimitry Andric case X86::ESP: OS << "$esp"; break;
3030b57cec5SDimitry Andric case X86::EBP: OS << "$ebp"; break;
3040b57cec5SDimitry Andric case X86::EIP: OS << "$eip"; break;
3050b57cec5SDimitry Andric // Otherwise, get the codeview register number and print $N.
3060b57cec5SDimitry Andric default:
3070b57cec5SDimitry Andric OS << '$' << MRI->getCodeViewRegNum(LLVMReg);
3080b57cec5SDimitry Andric break;
3090b57cec5SDimitry Andric }
3100b57cec5SDimitry Andric });
3110b57cec5SDimitry Andric }
3120b57cec5SDimitry Andric
emitFrameDataRecord(MCStreamer & OS,MCSymbol * Label)3130b57cec5SDimitry Andric void FPOStateMachine::emitFrameDataRecord(MCStreamer &OS, MCSymbol *Label) {
3140b57cec5SDimitry Andric unsigned CurFlags = Flags;
3150b57cec5SDimitry Andric if (Label == FPO->Begin)
3160b57cec5SDimitry Andric CurFlags |= FrameData::IsFunctionStart;
3170b57cec5SDimitry Andric
3180b57cec5SDimitry Andric // Compute the new FrameFunc string.
3190b57cec5SDimitry Andric FrameFunc.clear();
3200b57cec5SDimitry Andric raw_svector_ostream FuncOS(FrameFunc);
3210b57cec5SDimitry Andric const MCRegisterInfo *MRI = OS.getContext().getRegisterInfo();
3220b57cec5SDimitry Andric assert((StackAlign == 0 || FrameReg != 0) &&
3230b57cec5SDimitry Andric "cannot align stack without frame reg");
3240b57cec5SDimitry Andric StringRef CFAVar = StackAlign == 0 ? "$T0" : "$T1";
3250b57cec5SDimitry Andric
3260b57cec5SDimitry Andric if (FrameReg) {
3270b57cec5SDimitry Andric // CFA is FrameReg + FrameRegOff.
3280b57cec5SDimitry Andric FuncOS << CFAVar << ' ' << printFPOReg(MRI, FrameReg) << ' ' << FrameRegOff
3290b57cec5SDimitry Andric << " + = ";
3300b57cec5SDimitry Andric
3310b57cec5SDimitry Andric // Assign $T0, the VFRAME register, the value of ESP after it is aligned.
3320b57cec5SDimitry Andric // Starting from the CFA, we subtract the size of all pushed registers, and
3330b57cec5SDimitry Andric // align the result. While we don't store any CSRs in this area, $T0 is used
3340b57cec5SDimitry Andric // by S_DEFRANGE_FRAMEPOINTER_REL records to find local variables.
3350b57cec5SDimitry Andric if (StackAlign) {
3360b57cec5SDimitry Andric FuncOS << "$T0 " << CFAVar << ' ' << StackOffsetBeforeAlign << " - "
3370b57cec5SDimitry Andric << StackAlign << " @ = ";
3380b57cec5SDimitry Andric }
3390b57cec5SDimitry Andric } else {
3400b57cec5SDimitry Andric // The address of return address is ESP + CurOffset, but we use .raSearch to
3410b57cec5SDimitry Andric // match MSVC. This seems to ask the debugger to subtract some combination
3420b57cec5SDimitry Andric // of LocalSize and SavedRegSize from ESP and grovel around in that memory
3430b57cec5SDimitry Andric // to find the address of a plausible return address.
3440b57cec5SDimitry Andric FuncOS << CFAVar << " .raSearch = ";
3450b57cec5SDimitry Andric }
3460b57cec5SDimitry Andric
3470b57cec5SDimitry Andric // Caller's $eip should be dereferenced CFA, and $esp should be CFA plus 4.
3480b57cec5SDimitry Andric FuncOS << "$eip " << CFAVar << " ^ = ";
3490b57cec5SDimitry Andric FuncOS << "$esp " << CFAVar << " 4 + = ";
3500b57cec5SDimitry Andric
3510b57cec5SDimitry Andric // Each saved register is stored at an unchanging negative CFA offset.
3520b57cec5SDimitry Andric for (RegSaveOffset RO : RegSaveOffsets)
3530b57cec5SDimitry Andric FuncOS << printFPOReg(MRI, RO.Reg) << ' ' << CFAVar << ' ' << RO.Offset
3540b57cec5SDimitry Andric << " - ^ = ";
3550b57cec5SDimitry Andric
3560b57cec5SDimitry Andric // Add it to the CV string table.
3570b57cec5SDimitry Andric CodeViewContext &CVCtx = OS.getContext().getCVContext();
3580b57cec5SDimitry Andric unsigned FrameFuncStrTabOff = CVCtx.addToStringTable(FuncOS.str()).second;
3590b57cec5SDimitry Andric
3600b57cec5SDimitry Andric // MSVC has only ever been observed to emit a MaxStackSize of zero.
3610b57cec5SDimitry Andric unsigned MaxStackSize = 0;
3620b57cec5SDimitry Andric
3630b57cec5SDimitry Andric // The FrameData record format is:
3640b57cec5SDimitry Andric // ulittle32_t RvaStart;
3650b57cec5SDimitry Andric // ulittle32_t CodeSize;
3660b57cec5SDimitry Andric // ulittle32_t LocalSize;
3670b57cec5SDimitry Andric // ulittle32_t ParamsSize;
3680b57cec5SDimitry Andric // ulittle32_t MaxStackSize;
3690b57cec5SDimitry Andric // ulittle32_t FrameFunc; // String table offset
3700b57cec5SDimitry Andric // ulittle16_t PrologSize;
3710b57cec5SDimitry Andric // ulittle16_t SavedRegsSize;
3720b57cec5SDimitry Andric // ulittle32_t Flags;
3730b57cec5SDimitry Andric
3740b57cec5SDimitry Andric OS.emitAbsoluteSymbolDiff(Label, FPO->Begin, 4); // RvaStart
3750b57cec5SDimitry Andric OS.emitAbsoluteSymbolDiff(FPO->End, Label, 4); // CodeSize
3765ffd83dbSDimitry Andric OS.emitInt32(LocalSize);
3775ffd83dbSDimitry Andric OS.emitInt32(FPO->ParamsSize);
3785ffd83dbSDimitry Andric OS.emitInt32(MaxStackSize);
3795ffd83dbSDimitry Andric OS.emitInt32(FrameFuncStrTabOff); // FrameFunc
3800b57cec5SDimitry Andric OS.emitAbsoluteSymbolDiff(FPO->PrologueEnd, Label, 2);
3815ffd83dbSDimitry Andric OS.emitInt16(SavedRegSize);
3825ffd83dbSDimitry Andric OS.emitInt32(CurFlags);
3830b57cec5SDimitry Andric }
3840b57cec5SDimitry Andric
3850b57cec5SDimitry Andric /// Compute and emit the real CodeView FrameData subsection.
emitFPOData(const MCSymbol * ProcSym,SMLoc L)3860b57cec5SDimitry Andric bool X86WinCOFFTargetStreamer::emitFPOData(const MCSymbol *ProcSym, SMLoc L) {
3870b57cec5SDimitry Andric MCStreamer &OS = getStreamer();
3880b57cec5SDimitry Andric MCContext &Ctx = OS.getContext();
3890b57cec5SDimitry Andric
3900b57cec5SDimitry Andric auto I = AllFPOData.find(ProcSym);
3910b57cec5SDimitry Andric if (I == AllFPOData.end()) {
3920b57cec5SDimitry Andric Ctx.reportError(L, Twine("no FPO data found for symbol ") +
3930b57cec5SDimitry Andric ProcSym->getName());
3940b57cec5SDimitry Andric return true;
3950b57cec5SDimitry Andric }
3960b57cec5SDimitry Andric const FPOData *FPO = I->second.get();
3970b57cec5SDimitry Andric assert(FPO->Begin && FPO->End && FPO->PrologueEnd && "missing FPO label");
3980b57cec5SDimitry Andric
3990b57cec5SDimitry Andric MCSymbol *FrameBegin = Ctx.createTempSymbol(),
4000b57cec5SDimitry Andric *FrameEnd = Ctx.createTempSymbol();
4010b57cec5SDimitry Andric
4025ffd83dbSDimitry Andric OS.emitInt32(unsigned(DebugSubsectionKind::FrameData));
4030b57cec5SDimitry Andric OS.emitAbsoluteSymbolDiff(FrameEnd, FrameBegin, 4);
4045ffd83dbSDimitry Andric OS.emitLabel(FrameBegin);
4050b57cec5SDimitry Andric
4060b57cec5SDimitry Andric // Start with the RVA of the function in question.
4075ffd83dbSDimitry Andric OS.emitValue(MCSymbolRefExpr::create(FPO->Function,
4080b57cec5SDimitry Andric MCSymbolRefExpr::VK_COFF_IMGREL32, Ctx),
4090b57cec5SDimitry Andric 4);
4100b57cec5SDimitry Andric
4110b57cec5SDimitry Andric // Emit a sequence of FrameData records.
4120b57cec5SDimitry Andric FPOStateMachine FSM(FPO);
4130b57cec5SDimitry Andric
4140b57cec5SDimitry Andric FSM.emitFrameDataRecord(OS, FPO->Begin);
4150b57cec5SDimitry Andric for (const FPOInstruction &Inst : FPO->Instructions) {
4160b57cec5SDimitry Andric switch (Inst.Op) {
4170b57cec5SDimitry Andric case FPOInstruction::PushReg:
4180b57cec5SDimitry Andric FSM.CurOffset += 4;
4190b57cec5SDimitry Andric FSM.SavedRegSize += 4;
4200b57cec5SDimitry Andric FSM.RegSaveOffsets.push_back({Inst.RegOrOffset, FSM.CurOffset});
4210b57cec5SDimitry Andric break;
4220b57cec5SDimitry Andric case FPOInstruction::SetFrame:
4230b57cec5SDimitry Andric FSM.FrameReg = Inst.RegOrOffset;
4240b57cec5SDimitry Andric FSM.FrameRegOff = FSM.CurOffset;
4250b57cec5SDimitry Andric break;
4260b57cec5SDimitry Andric case FPOInstruction::StackAlign:
4270b57cec5SDimitry Andric FSM.StackOffsetBeforeAlign = FSM.CurOffset;
4280b57cec5SDimitry Andric FSM.StackAlign = Inst.RegOrOffset;
4290b57cec5SDimitry Andric break;
4300b57cec5SDimitry Andric case FPOInstruction::StackAlloc:
4310b57cec5SDimitry Andric FSM.CurOffset += Inst.RegOrOffset;
4320b57cec5SDimitry Andric FSM.LocalSize += Inst.RegOrOffset;
4330b57cec5SDimitry Andric // No need to emit FrameData for stack allocations with a frame pointer.
4340b57cec5SDimitry Andric if (FSM.FrameReg)
4350b57cec5SDimitry Andric continue;
4360b57cec5SDimitry Andric break;
4370b57cec5SDimitry Andric }
4380b57cec5SDimitry Andric FSM.emitFrameDataRecord(OS, Inst.Label);
4390b57cec5SDimitry Andric }
4400b57cec5SDimitry Andric
441bdd1243dSDimitry Andric OS.emitValueToAlignment(Align(4), 0);
4425ffd83dbSDimitry Andric OS.emitLabel(FrameEnd);
4430b57cec5SDimitry Andric return false;
4440b57cec5SDimitry Andric }
4450b57cec5SDimitry Andric
createX86AsmTargetStreamer(MCStreamer & S,formatted_raw_ostream & OS,MCInstPrinter * InstPrinter)4460b57cec5SDimitry Andric MCTargetStreamer *llvm::createX86AsmTargetStreamer(MCStreamer &S,
4470b57cec5SDimitry Andric formatted_raw_ostream &OS,
448*0fca6ea1SDimitry Andric MCInstPrinter *InstPrinter) {
4490b57cec5SDimitry Andric // FIXME: This makes it so we textually assemble COFF directives on ELF.
4500b57cec5SDimitry Andric // That's kind of nonsensical.
4510b57cec5SDimitry Andric return new X86WinCOFFAsmTargetStreamer(S, OS, *InstPrinter);
4520b57cec5SDimitry Andric }
4530b57cec5SDimitry Andric
4540b57cec5SDimitry Andric MCTargetStreamer *
createX86ObjectTargetStreamer(MCStreamer & S,const MCSubtargetInfo & STI)4550b57cec5SDimitry Andric llvm::createX86ObjectTargetStreamer(MCStreamer &S, const MCSubtargetInfo &STI) {
4560b57cec5SDimitry Andric // No need to register a target streamer.
4570b57cec5SDimitry Andric if (!STI.getTargetTriple().isOSBinFormatCOFF())
4580b57cec5SDimitry Andric return nullptr;
4590b57cec5SDimitry Andric // Registers itself to the MCStreamer.
4600b57cec5SDimitry Andric return new X86WinCOFFTargetStreamer(S);
4610b57cec5SDimitry Andric }
462