17330f729Sjoerg //===- StackMaps.cpp ------------------------------------------------------===//
27330f729Sjoerg //
37330f729Sjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
47330f729Sjoerg // See https://llvm.org/LICENSE.txt for license information.
57330f729Sjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67330f729Sjoerg //
77330f729Sjoerg //===----------------------------------------------------------------------===//
87330f729Sjoerg
97330f729Sjoerg #include "llvm/CodeGen/StackMaps.h"
107330f729Sjoerg #include "llvm/ADT/DenseMapInfo.h"
117330f729Sjoerg #include "llvm/ADT/STLExtras.h"
127330f729Sjoerg #include "llvm/ADT/Twine.h"
137330f729Sjoerg #include "llvm/CodeGen/AsmPrinter.h"
147330f729Sjoerg #include "llvm/CodeGen/MachineFrameInfo.h"
157330f729Sjoerg #include "llvm/CodeGen/MachineFunction.h"
167330f729Sjoerg #include "llvm/CodeGen/MachineInstr.h"
177330f729Sjoerg #include "llvm/CodeGen/MachineOperand.h"
187330f729Sjoerg #include "llvm/CodeGen/TargetOpcodes.h"
197330f729Sjoerg #include "llvm/CodeGen/TargetRegisterInfo.h"
207330f729Sjoerg #include "llvm/CodeGen/TargetSubtargetInfo.h"
217330f729Sjoerg #include "llvm/IR/DataLayout.h"
227330f729Sjoerg #include "llvm/MC/MCContext.h"
237330f729Sjoerg #include "llvm/MC/MCExpr.h"
247330f729Sjoerg #include "llvm/MC/MCObjectFileInfo.h"
257330f729Sjoerg #include "llvm/MC/MCRegisterInfo.h"
267330f729Sjoerg #include "llvm/MC/MCStreamer.h"
277330f729Sjoerg #include "llvm/Support/CommandLine.h"
287330f729Sjoerg #include "llvm/Support/Debug.h"
297330f729Sjoerg #include "llvm/Support/ErrorHandling.h"
307330f729Sjoerg #include "llvm/Support/MathExtras.h"
317330f729Sjoerg #include "llvm/Support/raw_ostream.h"
327330f729Sjoerg #include <algorithm>
337330f729Sjoerg #include <cassert>
347330f729Sjoerg #include <cstdint>
357330f729Sjoerg #include <iterator>
367330f729Sjoerg #include <utility>
377330f729Sjoerg
387330f729Sjoerg using namespace llvm;
397330f729Sjoerg
407330f729Sjoerg #define DEBUG_TYPE "stackmaps"
417330f729Sjoerg
427330f729Sjoerg static cl::opt<int> StackMapVersion(
437330f729Sjoerg "stackmap-version", cl::init(3), cl::Hidden,
447330f729Sjoerg cl::desc("Specify the stackmap encoding version (default = 3)"));
457330f729Sjoerg
467330f729Sjoerg const char *StackMaps::WSMP = "Stack Maps: ";
477330f729Sjoerg
getConstMetaVal(const MachineInstr & MI,unsigned Idx)48*82d56013Sjoerg static uint64_t getConstMetaVal(const MachineInstr &MI, unsigned Idx) {
49*82d56013Sjoerg assert(MI.getOperand(Idx).isImm() &&
50*82d56013Sjoerg MI.getOperand(Idx).getImm() == StackMaps::ConstantOp);
51*82d56013Sjoerg const auto &MO = MI.getOperand(Idx + 1);
52*82d56013Sjoerg assert(MO.isImm());
53*82d56013Sjoerg return MO.getImm();
54*82d56013Sjoerg }
55*82d56013Sjoerg
StackMapOpers(const MachineInstr * MI)567330f729Sjoerg StackMapOpers::StackMapOpers(const MachineInstr *MI)
577330f729Sjoerg : MI(MI) {
587330f729Sjoerg assert(getVarIdx() <= MI->getNumOperands() &&
597330f729Sjoerg "invalid stackmap definition");
607330f729Sjoerg }
617330f729Sjoerg
PatchPointOpers(const MachineInstr * MI)627330f729Sjoerg PatchPointOpers::PatchPointOpers(const MachineInstr *MI)
637330f729Sjoerg : MI(MI), HasDef(MI->getOperand(0).isReg() && MI->getOperand(0).isDef() &&
647330f729Sjoerg !MI->getOperand(0).isImplicit()) {
657330f729Sjoerg #ifndef NDEBUG
667330f729Sjoerg unsigned CheckStartIdx = 0, e = MI->getNumOperands();
677330f729Sjoerg while (CheckStartIdx < e && MI->getOperand(CheckStartIdx).isReg() &&
687330f729Sjoerg MI->getOperand(CheckStartIdx).isDef() &&
697330f729Sjoerg !MI->getOperand(CheckStartIdx).isImplicit())
707330f729Sjoerg ++CheckStartIdx;
717330f729Sjoerg
727330f729Sjoerg assert(getMetaIdx() == CheckStartIdx &&
737330f729Sjoerg "Unexpected additional definition in Patchpoint intrinsic.");
747330f729Sjoerg #endif
757330f729Sjoerg }
767330f729Sjoerg
getNextScratchIdx(unsigned StartIdx) const777330f729Sjoerg unsigned PatchPointOpers::getNextScratchIdx(unsigned StartIdx) const {
787330f729Sjoerg if (!StartIdx)
797330f729Sjoerg StartIdx = getVarIdx();
807330f729Sjoerg
817330f729Sjoerg // Find the next scratch register (implicit def and early clobber)
827330f729Sjoerg unsigned ScratchIdx = StartIdx, e = MI->getNumOperands();
837330f729Sjoerg while (ScratchIdx < e &&
847330f729Sjoerg !(MI->getOperand(ScratchIdx).isReg() &&
857330f729Sjoerg MI->getOperand(ScratchIdx).isDef() &&
867330f729Sjoerg MI->getOperand(ScratchIdx).isImplicit() &&
877330f729Sjoerg MI->getOperand(ScratchIdx).isEarlyClobber()))
887330f729Sjoerg ++ScratchIdx;
897330f729Sjoerg
907330f729Sjoerg assert(ScratchIdx != e && "No scratch register available");
917330f729Sjoerg return ScratchIdx;
927330f729Sjoerg }
937330f729Sjoerg
getNumGcMapEntriesIdx()94*82d56013Sjoerg unsigned StatepointOpers::getNumGcMapEntriesIdx() {
95*82d56013Sjoerg // Take index of num of allocas and skip all allocas records.
96*82d56013Sjoerg unsigned CurIdx = getNumAllocaIdx();
97*82d56013Sjoerg unsigned NumAllocas = getConstMetaVal(*MI, CurIdx - 1);
98*82d56013Sjoerg CurIdx++;
99*82d56013Sjoerg while (NumAllocas--)
100*82d56013Sjoerg CurIdx = StackMaps::getNextMetaArgIdx(MI, CurIdx);
101*82d56013Sjoerg return CurIdx + 1; // skip <StackMaps::ConstantOp>
102*82d56013Sjoerg }
103*82d56013Sjoerg
getNumAllocaIdx()104*82d56013Sjoerg unsigned StatepointOpers::getNumAllocaIdx() {
105*82d56013Sjoerg // Take index of num of gc ptrs and skip all gc ptr records.
106*82d56013Sjoerg unsigned CurIdx = getNumGCPtrIdx();
107*82d56013Sjoerg unsigned NumGCPtrs = getConstMetaVal(*MI, CurIdx - 1);
108*82d56013Sjoerg CurIdx++;
109*82d56013Sjoerg while (NumGCPtrs--)
110*82d56013Sjoerg CurIdx = StackMaps::getNextMetaArgIdx(MI, CurIdx);
111*82d56013Sjoerg return CurIdx + 1; // skip <StackMaps::ConstantOp>
112*82d56013Sjoerg }
113*82d56013Sjoerg
getNumGCPtrIdx()114*82d56013Sjoerg unsigned StatepointOpers::getNumGCPtrIdx() {
115*82d56013Sjoerg // Take index of num of deopt args and skip all deopt records.
116*82d56013Sjoerg unsigned CurIdx = getNumDeoptArgsIdx();
117*82d56013Sjoerg unsigned NumDeoptArgs = getConstMetaVal(*MI, CurIdx - 1);
118*82d56013Sjoerg CurIdx++;
119*82d56013Sjoerg while (NumDeoptArgs--) {
120*82d56013Sjoerg CurIdx = StackMaps::getNextMetaArgIdx(MI, CurIdx);
121*82d56013Sjoerg }
122*82d56013Sjoerg return CurIdx + 1; // skip <StackMaps::ConstantOp>
123*82d56013Sjoerg }
124*82d56013Sjoerg
getFirstGCPtrIdx()125*82d56013Sjoerg int StatepointOpers::getFirstGCPtrIdx() {
126*82d56013Sjoerg unsigned NumGCPtrsIdx = getNumGCPtrIdx();
127*82d56013Sjoerg unsigned NumGCPtrs = getConstMetaVal(*MI, NumGCPtrsIdx - 1);
128*82d56013Sjoerg if (NumGCPtrs == 0)
129*82d56013Sjoerg return -1;
130*82d56013Sjoerg ++NumGCPtrsIdx; // skip <num gc ptrs>
131*82d56013Sjoerg assert(NumGCPtrsIdx < MI->getNumOperands());
132*82d56013Sjoerg return (int)NumGCPtrsIdx;
133*82d56013Sjoerg }
134*82d56013Sjoerg
getGCPointerMap(SmallVectorImpl<std::pair<unsigned,unsigned>> & GCMap)135*82d56013Sjoerg unsigned StatepointOpers::getGCPointerMap(
136*82d56013Sjoerg SmallVectorImpl<std::pair<unsigned, unsigned>> &GCMap) {
137*82d56013Sjoerg unsigned CurIdx = getNumGcMapEntriesIdx();
138*82d56013Sjoerg unsigned GCMapSize = getConstMetaVal(*MI, CurIdx - 1);
139*82d56013Sjoerg CurIdx++;
140*82d56013Sjoerg for (unsigned N = 0; N < GCMapSize; ++N) {
141*82d56013Sjoerg unsigned B = MI->getOperand(CurIdx++).getImm();
142*82d56013Sjoerg unsigned D = MI->getOperand(CurIdx++).getImm();
143*82d56013Sjoerg GCMap.push_back(std::make_pair(B, D));
144*82d56013Sjoerg }
145*82d56013Sjoerg
146*82d56013Sjoerg return GCMapSize;
147*82d56013Sjoerg }
148*82d56013Sjoerg
StackMaps(AsmPrinter & AP)1497330f729Sjoerg StackMaps::StackMaps(AsmPrinter &AP) : AP(AP) {
1507330f729Sjoerg if (StackMapVersion != 3)
1517330f729Sjoerg llvm_unreachable("Unsupported stackmap version!");
1527330f729Sjoerg }
1537330f729Sjoerg
getNextMetaArgIdx(const MachineInstr * MI,unsigned CurIdx)154*82d56013Sjoerg unsigned StackMaps::getNextMetaArgIdx(const MachineInstr *MI, unsigned CurIdx) {
155*82d56013Sjoerg assert(CurIdx < MI->getNumOperands() && "Bad meta arg index");
156*82d56013Sjoerg const auto &MO = MI->getOperand(CurIdx);
157*82d56013Sjoerg if (MO.isImm()) {
158*82d56013Sjoerg switch (MO.getImm()) {
159*82d56013Sjoerg default:
160*82d56013Sjoerg llvm_unreachable("Unrecognized operand type.");
161*82d56013Sjoerg case StackMaps::DirectMemRefOp:
162*82d56013Sjoerg CurIdx += 2;
163*82d56013Sjoerg break;
164*82d56013Sjoerg case StackMaps::IndirectMemRefOp:
165*82d56013Sjoerg CurIdx += 3;
166*82d56013Sjoerg break;
167*82d56013Sjoerg case StackMaps::ConstantOp:
168*82d56013Sjoerg ++CurIdx;
169*82d56013Sjoerg break;
170*82d56013Sjoerg }
171*82d56013Sjoerg }
172*82d56013Sjoerg ++CurIdx;
173*82d56013Sjoerg assert(CurIdx < MI->getNumOperands() && "points past operand list");
174*82d56013Sjoerg return CurIdx;
175*82d56013Sjoerg }
176*82d56013Sjoerg
1777330f729Sjoerg /// Go up the super-register chain until we hit a valid dwarf register number.
getDwarfRegNum(unsigned Reg,const TargetRegisterInfo * TRI)1787330f729Sjoerg static unsigned getDwarfRegNum(unsigned Reg, const TargetRegisterInfo *TRI) {
1797330f729Sjoerg int RegNum = TRI->getDwarfRegNum(Reg, false);
1807330f729Sjoerg for (MCSuperRegIterator SR(Reg, TRI); SR.isValid() && RegNum < 0; ++SR)
1817330f729Sjoerg RegNum = TRI->getDwarfRegNum(*SR, false);
1827330f729Sjoerg
1837330f729Sjoerg assert(RegNum >= 0 && "Invalid Dwarf register number.");
1847330f729Sjoerg return (unsigned)RegNum;
1857330f729Sjoerg }
1867330f729Sjoerg
1877330f729Sjoerg MachineInstr::const_mop_iterator
parseOperand(MachineInstr::const_mop_iterator MOI,MachineInstr::const_mop_iterator MOE,LocationVec & Locs,LiveOutVec & LiveOuts) const1887330f729Sjoerg StackMaps::parseOperand(MachineInstr::const_mop_iterator MOI,
1897330f729Sjoerg MachineInstr::const_mop_iterator MOE, LocationVec &Locs,
1907330f729Sjoerg LiveOutVec &LiveOuts) const {
1917330f729Sjoerg const TargetRegisterInfo *TRI = AP.MF->getSubtarget().getRegisterInfo();
1927330f729Sjoerg if (MOI->isImm()) {
1937330f729Sjoerg switch (MOI->getImm()) {
1947330f729Sjoerg default:
1957330f729Sjoerg llvm_unreachable("Unrecognized operand type.");
1967330f729Sjoerg case StackMaps::DirectMemRefOp: {
1977330f729Sjoerg auto &DL = AP.MF->getDataLayout();
1987330f729Sjoerg
1997330f729Sjoerg unsigned Size = DL.getPointerSizeInBits();
2007330f729Sjoerg assert((Size % 8) == 0 && "Need pointer size in bytes.");
2017330f729Sjoerg Size /= 8;
2027330f729Sjoerg Register Reg = (++MOI)->getReg();
2037330f729Sjoerg int64_t Imm = (++MOI)->getImm();
2047330f729Sjoerg Locs.emplace_back(StackMaps::Location::Direct, Size,
2057330f729Sjoerg getDwarfRegNum(Reg, TRI), Imm);
2067330f729Sjoerg break;
2077330f729Sjoerg }
2087330f729Sjoerg case StackMaps::IndirectMemRefOp: {
2097330f729Sjoerg int64_t Size = (++MOI)->getImm();
2107330f729Sjoerg assert(Size > 0 && "Need a valid size for indirect memory locations.");
2117330f729Sjoerg Register Reg = (++MOI)->getReg();
2127330f729Sjoerg int64_t Imm = (++MOI)->getImm();
2137330f729Sjoerg Locs.emplace_back(StackMaps::Location::Indirect, Size,
2147330f729Sjoerg getDwarfRegNum(Reg, TRI), Imm);
2157330f729Sjoerg break;
2167330f729Sjoerg }
2177330f729Sjoerg case StackMaps::ConstantOp: {
2187330f729Sjoerg ++MOI;
2197330f729Sjoerg assert(MOI->isImm() && "Expected constant operand.");
2207330f729Sjoerg int64_t Imm = MOI->getImm();
2217330f729Sjoerg Locs.emplace_back(Location::Constant, sizeof(int64_t), 0, Imm);
2227330f729Sjoerg break;
2237330f729Sjoerg }
2247330f729Sjoerg }
2257330f729Sjoerg return ++MOI;
2267330f729Sjoerg }
2277330f729Sjoerg
2287330f729Sjoerg // The physical register number will ultimately be encoded as a DWARF regno.
2297330f729Sjoerg // The stack map also records the size of a spill slot that can hold the
2307330f729Sjoerg // register content. (The runtime can track the actual size of the data type
2317330f729Sjoerg // if it needs to.)
2327330f729Sjoerg if (MOI->isReg()) {
2337330f729Sjoerg // Skip implicit registers (this includes our scratch registers)
2347330f729Sjoerg if (MOI->isImplicit())
2357330f729Sjoerg return ++MOI;
2367330f729Sjoerg
237*82d56013Sjoerg if (MOI->isUndef()) {
238*82d56013Sjoerg // Record `undef` register as constant. Use same value as ISel uses.
239*82d56013Sjoerg Locs.emplace_back(Location::Constant, sizeof(int64_t), 0, 0xFEFEFEFE);
240*82d56013Sjoerg return ++MOI;
241*82d56013Sjoerg }
242*82d56013Sjoerg
2437330f729Sjoerg assert(Register::isPhysicalRegister(MOI->getReg()) &&
2447330f729Sjoerg "Virtreg operands should have been rewritten before now.");
2457330f729Sjoerg const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(MOI->getReg());
2467330f729Sjoerg assert(!MOI->getSubReg() && "Physical subreg still around.");
2477330f729Sjoerg
2487330f729Sjoerg unsigned Offset = 0;
2497330f729Sjoerg unsigned DwarfRegNum = getDwarfRegNum(MOI->getReg(), TRI);
2507330f729Sjoerg unsigned LLVMRegNum = *TRI->getLLVMRegNum(DwarfRegNum, false);
2517330f729Sjoerg unsigned SubRegIdx = TRI->getSubRegIndex(LLVMRegNum, MOI->getReg());
2527330f729Sjoerg if (SubRegIdx)
2537330f729Sjoerg Offset = TRI->getSubRegIdxOffset(SubRegIdx);
2547330f729Sjoerg
2557330f729Sjoerg Locs.emplace_back(Location::Register, TRI->getSpillSize(*RC),
2567330f729Sjoerg DwarfRegNum, Offset);
2577330f729Sjoerg return ++MOI;
2587330f729Sjoerg }
2597330f729Sjoerg
2607330f729Sjoerg if (MOI->isRegLiveOut())
2617330f729Sjoerg LiveOuts = parseRegisterLiveOutMask(MOI->getRegLiveOut());
2627330f729Sjoerg
2637330f729Sjoerg return ++MOI;
2647330f729Sjoerg }
2657330f729Sjoerg
print(raw_ostream & OS)2667330f729Sjoerg void StackMaps::print(raw_ostream &OS) {
2677330f729Sjoerg const TargetRegisterInfo *TRI =
2687330f729Sjoerg AP.MF ? AP.MF->getSubtarget().getRegisterInfo() : nullptr;
2697330f729Sjoerg OS << WSMP << "callsites:\n";
2707330f729Sjoerg for (const auto &CSI : CSInfos) {
2717330f729Sjoerg const LocationVec &CSLocs = CSI.Locations;
2727330f729Sjoerg const LiveOutVec &LiveOuts = CSI.LiveOuts;
2737330f729Sjoerg
2747330f729Sjoerg OS << WSMP << "callsite " << CSI.ID << "\n";
2757330f729Sjoerg OS << WSMP << " has " << CSLocs.size() << " locations\n";
2767330f729Sjoerg
2777330f729Sjoerg unsigned Idx = 0;
2787330f729Sjoerg for (const auto &Loc : CSLocs) {
2797330f729Sjoerg OS << WSMP << "\t\tLoc " << Idx << ": ";
2807330f729Sjoerg switch (Loc.Type) {
2817330f729Sjoerg case Location::Unprocessed:
2827330f729Sjoerg OS << "<Unprocessed operand>";
2837330f729Sjoerg break;
2847330f729Sjoerg case Location::Register:
2857330f729Sjoerg OS << "Register ";
2867330f729Sjoerg if (TRI)
2877330f729Sjoerg OS << printReg(Loc.Reg, TRI);
2887330f729Sjoerg else
2897330f729Sjoerg OS << Loc.Reg;
2907330f729Sjoerg break;
2917330f729Sjoerg case Location::Direct:
2927330f729Sjoerg OS << "Direct ";
2937330f729Sjoerg if (TRI)
2947330f729Sjoerg OS << printReg(Loc.Reg, TRI);
2957330f729Sjoerg else
2967330f729Sjoerg OS << Loc.Reg;
2977330f729Sjoerg if (Loc.Offset)
2987330f729Sjoerg OS << " + " << Loc.Offset;
2997330f729Sjoerg break;
3007330f729Sjoerg case Location::Indirect:
3017330f729Sjoerg OS << "Indirect ";
3027330f729Sjoerg if (TRI)
3037330f729Sjoerg OS << printReg(Loc.Reg, TRI);
3047330f729Sjoerg else
3057330f729Sjoerg OS << Loc.Reg;
3067330f729Sjoerg OS << "+" << Loc.Offset;
3077330f729Sjoerg break;
3087330f729Sjoerg case Location::Constant:
3097330f729Sjoerg OS << "Constant " << Loc.Offset;
3107330f729Sjoerg break;
3117330f729Sjoerg case Location::ConstantIndex:
3127330f729Sjoerg OS << "Constant Index " << Loc.Offset;
3137330f729Sjoerg break;
3147330f729Sjoerg }
3157330f729Sjoerg OS << "\t[encoding: .byte " << Loc.Type << ", .byte 0"
3167330f729Sjoerg << ", .short " << Loc.Size << ", .short " << Loc.Reg << ", .short 0"
3177330f729Sjoerg << ", .int " << Loc.Offset << "]\n";
3187330f729Sjoerg Idx++;
3197330f729Sjoerg }
3207330f729Sjoerg
3217330f729Sjoerg OS << WSMP << "\thas " << LiveOuts.size() << " live-out registers\n";
3227330f729Sjoerg
3237330f729Sjoerg Idx = 0;
3247330f729Sjoerg for (const auto &LO : LiveOuts) {
3257330f729Sjoerg OS << WSMP << "\t\tLO " << Idx << ": ";
3267330f729Sjoerg if (TRI)
3277330f729Sjoerg OS << printReg(LO.Reg, TRI);
3287330f729Sjoerg else
3297330f729Sjoerg OS << LO.Reg;
3307330f729Sjoerg OS << "\t[encoding: .short " << LO.DwarfRegNum << ", .byte 0, .byte "
3317330f729Sjoerg << LO.Size << "]\n";
3327330f729Sjoerg Idx++;
3337330f729Sjoerg }
3347330f729Sjoerg }
3357330f729Sjoerg }
3367330f729Sjoerg
3377330f729Sjoerg /// Create a live-out register record for the given register Reg.
3387330f729Sjoerg StackMaps::LiveOutReg
createLiveOutReg(unsigned Reg,const TargetRegisterInfo * TRI) const3397330f729Sjoerg StackMaps::createLiveOutReg(unsigned Reg, const TargetRegisterInfo *TRI) const {
3407330f729Sjoerg unsigned DwarfRegNum = getDwarfRegNum(Reg, TRI);
3417330f729Sjoerg unsigned Size = TRI->getSpillSize(*TRI->getMinimalPhysRegClass(Reg));
3427330f729Sjoerg return LiveOutReg(Reg, DwarfRegNum, Size);
3437330f729Sjoerg }
3447330f729Sjoerg
3457330f729Sjoerg /// Parse the register live-out mask and return a vector of live-out registers
3467330f729Sjoerg /// that need to be recorded in the stackmap.
3477330f729Sjoerg StackMaps::LiveOutVec
parseRegisterLiveOutMask(const uint32_t * Mask) const3487330f729Sjoerg StackMaps::parseRegisterLiveOutMask(const uint32_t *Mask) const {
3497330f729Sjoerg assert(Mask && "No register mask specified");
3507330f729Sjoerg const TargetRegisterInfo *TRI = AP.MF->getSubtarget().getRegisterInfo();
3517330f729Sjoerg LiveOutVec LiveOuts;
3527330f729Sjoerg
3537330f729Sjoerg // Create a LiveOutReg for each bit that is set in the register mask.
3547330f729Sjoerg for (unsigned Reg = 0, NumRegs = TRI->getNumRegs(); Reg != NumRegs; ++Reg)
355*82d56013Sjoerg if ((Mask[Reg / 32] >> (Reg % 32)) & 1)
3567330f729Sjoerg LiveOuts.push_back(createLiveOutReg(Reg, TRI));
3577330f729Sjoerg
3587330f729Sjoerg // We don't need to keep track of a register if its super-register is already
3597330f729Sjoerg // in the list. Merge entries that refer to the same dwarf register and use
3607330f729Sjoerg // the maximum size that needs to be spilled.
3617330f729Sjoerg
3627330f729Sjoerg llvm::sort(LiveOuts, [](const LiveOutReg &LHS, const LiveOutReg &RHS) {
3637330f729Sjoerg // Only sort by the dwarf register number.
3647330f729Sjoerg return LHS.DwarfRegNum < RHS.DwarfRegNum;
3657330f729Sjoerg });
3667330f729Sjoerg
3677330f729Sjoerg for (auto I = LiveOuts.begin(), E = LiveOuts.end(); I != E; ++I) {
3687330f729Sjoerg for (auto II = std::next(I); II != E; ++II) {
3697330f729Sjoerg if (I->DwarfRegNum != II->DwarfRegNum) {
3707330f729Sjoerg // Skip all the now invalid entries.
3717330f729Sjoerg I = --II;
3727330f729Sjoerg break;
3737330f729Sjoerg }
3747330f729Sjoerg I->Size = std::max(I->Size, II->Size);
3757330f729Sjoerg if (TRI->isSuperRegister(I->Reg, II->Reg))
3767330f729Sjoerg I->Reg = II->Reg;
3777330f729Sjoerg II->Reg = 0; // mark for deletion.
3787330f729Sjoerg }
3797330f729Sjoerg }
3807330f729Sjoerg
381*82d56013Sjoerg llvm::erase_if(LiveOuts, [](const LiveOutReg &LO) { return LO.Reg == 0; });
3827330f729Sjoerg
3837330f729Sjoerg return LiveOuts;
3847330f729Sjoerg }
3857330f729Sjoerg
386*82d56013Sjoerg // See statepoint MI format description in StatepointOpers' class comment
387*82d56013Sjoerg // in include/llvm/CodeGen/StackMaps.h
parseStatepointOpers(const MachineInstr & MI,MachineInstr::const_mop_iterator MOI,MachineInstr::const_mop_iterator MOE,LocationVec & Locations,LiveOutVec & LiveOuts)388*82d56013Sjoerg void StackMaps::parseStatepointOpers(const MachineInstr &MI,
389*82d56013Sjoerg MachineInstr::const_mop_iterator MOI,
390*82d56013Sjoerg MachineInstr::const_mop_iterator MOE,
391*82d56013Sjoerg LocationVec &Locations,
392*82d56013Sjoerg LiveOutVec &LiveOuts) {
393*82d56013Sjoerg LLVM_DEBUG(dbgs() << "record statepoint : " << MI << "\n");
394*82d56013Sjoerg StatepointOpers SO(&MI);
395*82d56013Sjoerg MOI = parseOperand(MOI, MOE, Locations, LiveOuts); // CC
396*82d56013Sjoerg MOI = parseOperand(MOI, MOE, Locations, LiveOuts); // Flags
397*82d56013Sjoerg MOI = parseOperand(MOI, MOE, Locations, LiveOuts); // Num Deopts
398*82d56013Sjoerg
399*82d56013Sjoerg // Record Deopt Args.
400*82d56013Sjoerg unsigned NumDeoptArgs = Locations.back().Offset;
401*82d56013Sjoerg assert(Locations.back().Type == Location::Constant);
402*82d56013Sjoerg assert(NumDeoptArgs == SO.getNumDeoptArgs());
403*82d56013Sjoerg
404*82d56013Sjoerg while (NumDeoptArgs--)
405*82d56013Sjoerg MOI = parseOperand(MOI, MOE, Locations, LiveOuts);
406*82d56013Sjoerg
407*82d56013Sjoerg // Record gc base/derived pairs
408*82d56013Sjoerg assert(MOI->isImm() && MOI->getImm() == StackMaps::ConstantOp);
409*82d56013Sjoerg ++MOI;
410*82d56013Sjoerg assert(MOI->isImm());
411*82d56013Sjoerg unsigned NumGCPointers = MOI->getImm();
412*82d56013Sjoerg ++MOI;
413*82d56013Sjoerg if (NumGCPointers) {
414*82d56013Sjoerg // Map logical index of GC ptr to MI operand index.
415*82d56013Sjoerg SmallVector<unsigned, 8> GCPtrIndices;
416*82d56013Sjoerg unsigned GCPtrIdx = (unsigned)SO.getFirstGCPtrIdx();
417*82d56013Sjoerg assert((int)GCPtrIdx != -1);
418*82d56013Sjoerg assert(MOI - MI.operands_begin() == GCPtrIdx + 0LL);
419*82d56013Sjoerg while (NumGCPointers--) {
420*82d56013Sjoerg GCPtrIndices.push_back(GCPtrIdx);
421*82d56013Sjoerg GCPtrIdx = StackMaps::getNextMetaArgIdx(&MI, GCPtrIdx);
422*82d56013Sjoerg }
423*82d56013Sjoerg
424*82d56013Sjoerg SmallVector<std::pair<unsigned, unsigned>, 8> GCPairs;
425*82d56013Sjoerg unsigned NumGCPairs = SO.getGCPointerMap(GCPairs);
426*82d56013Sjoerg (void)NumGCPairs;
427*82d56013Sjoerg LLVM_DEBUG(dbgs() << "NumGCPairs = " << NumGCPairs << "\n");
428*82d56013Sjoerg
429*82d56013Sjoerg auto MOB = MI.operands_begin();
430*82d56013Sjoerg for (auto &P : GCPairs) {
431*82d56013Sjoerg assert(P.first < GCPtrIndices.size() && "base pointer index not found");
432*82d56013Sjoerg assert(P.second < GCPtrIndices.size() &&
433*82d56013Sjoerg "derived pointer index not found");
434*82d56013Sjoerg unsigned BaseIdx = GCPtrIndices[P.first];
435*82d56013Sjoerg unsigned DerivedIdx = GCPtrIndices[P.second];
436*82d56013Sjoerg LLVM_DEBUG(dbgs() << "Base : " << BaseIdx << " Derived : " << DerivedIdx
437*82d56013Sjoerg << "\n");
438*82d56013Sjoerg (void)parseOperand(MOB + BaseIdx, MOE, Locations, LiveOuts);
439*82d56013Sjoerg (void)parseOperand(MOB + DerivedIdx, MOE, Locations, LiveOuts);
440*82d56013Sjoerg }
441*82d56013Sjoerg
442*82d56013Sjoerg MOI = MOB + GCPtrIdx;
443*82d56013Sjoerg }
444*82d56013Sjoerg
445*82d56013Sjoerg // Record gc allocas
446*82d56013Sjoerg assert(MOI < MOE);
447*82d56013Sjoerg assert(MOI->isImm() && MOI->getImm() == StackMaps::ConstantOp);
448*82d56013Sjoerg ++MOI;
449*82d56013Sjoerg unsigned NumAllocas = MOI->getImm();
450*82d56013Sjoerg ++MOI;
451*82d56013Sjoerg while (NumAllocas--) {
452*82d56013Sjoerg MOI = parseOperand(MOI, MOE, Locations, LiveOuts);
453*82d56013Sjoerg assert(MOI < MOE);
454*82d56013Sjoerg }
455*82d56013Sjoerg }
456*82d56013Sjoerg
recordStackMapOpers(const MCSymbol & MILabel,const MachineInstr & MI,uint64_t ID,MachineInstr::const_mop_iterator MOI,MachineInstr::const_mop_iterator MOE,bool recordResult)457*82d56013Sjoerg void StackMaps::recordStackMapOpers(const MCSymbol &MILabel,
458*82d56013Sjoerg const MachineInstr &MI, uint64_t ID,
4597330f729Sjoerg MachineInstr::const_mop_iterator MOI,
4607330f729Sjoerg MachineInstr::const_mop_iterator MOE,
4617330f729Sjoerg bool recordResult) {
4627330f729Sjoerg MCContext &OutContext = AP.OutStreamer->getContext();
4637330f729Sjoerg
4647330f729Sjoerg LocationVec Locations;
4657330f729Sjoerg LiveOutVec LiveOuts;
4667330f729Sjoerg
4677330f729Sjoerg if (recordResult) {
4687330f729Sjoerg assert(PatchPointOpers(&MI).hasDef() && "Stackmap has no return value.");
4697330f729Sjoerg parseOperand(MI.operands_begin(), std::next(MI.operands_begin()), Locations,
4707330f729Sjoerg LiveOuts);
4717330f729Sjoerg }
4727330f729Sjoerg
4737330f729Sjoerg // Parse operands.
474*82d56013Sjoerg if (MI.getOpcode() == TargetOpcode::STATEPOINT)
475*82d56013Sjoerg parseStatepointOpers(MI, MOI, MOE, Locations, LiveOuts);
476*82d56013Sjoerg else
477*82d56013Sjoerg while (MOI != MOE)
4787330f729Sjoerg MOI = parseOperand(MOI, MOE, Locations, LiveOuts);
4797330f729Sjoerg
4807330f729Sjoerg // Move large constants into the constant pool.
4817330f729Sjoerg for (auto &Loc : Locations) {
4827330f729Sjoerg // Constants are encoded as sign-extended integers.
4837330f729Sjoerg // -1 is directly encoded as .long 0xFFFFFFFF with no constant pool.
4847330f729Sjoerg if (Loc.Type == Location::Constant && !isInt<32>(Loc.Offset)) {
4857330f729Sjoerg Loc.Type = Location::ConstantIndex;
4867330f729Sjoerg // ConstPool is intentionally a MapVector of 'uint64_t's (as
4877330f729Sjoerg // opposed to 'int64_t's). We should never be in a situation
4887330f729Sjoerg // where we have to insert either the tombstone or the empty
4897330f729Sjoerg // keys into a map, and for a DenseMap<uint64_t, T> these are
4907330f729Sjoerg // (uint64_t)0 and (uint64_t)-1. They can be and are
4917330f729Sjoerg // represented using 32 bit integers.
4927330f729Sjoerg assert((uint64_t)Loc.Offset != DenseMapInfo<uint64_t>::getEmptyKey() &&
4937330f729Sjoerg (uint64_t)Loc.Offset !=
4947330f729Sjoerg DenseMapInfo<uint64_t>::getTombstoneKey() &&
4957330f729Sjoerg "empty and tombstone keys should fit in 32 bits!");
4967330f729Sjoerg auto Result = ConstPool.insert(std::make_pair(Loc.Offset, Loc.Offset));
4977330f729Sjoerg Loc.Offset = Result.first - ConstPool.begin();
4987330f729Sjoerg }
4997330f729Sjoerg }
5007330f729Sjoerg
5017330f729Sjoerg // Create an expression to calculate the offset of the callsite from function
5027330f729Sjoerg // entry.
5037330f729Sjoerg const MCExpr *CSOffsetExpr = MCBinaryExpr::createSub(
504*82d56013Sjoerg MCSymbolRefExpr::create(&MILabel, OutContext),
5057330f729Sjoerg MCSymbolRefExpr::create(AP.CurrentFnSymForSize, OutContext), OutContext);
5067330f729Sjoerg
5077330f729Sjoerg CSInfos.emplace_back(CSOffsetExpr, ID, std::move(Locations),
5087330f729Sjoerg std::move(LiveOuts));
5097330f729Sjoerg
5107330f729Sjoerg // Record the stack size of the current function and update callsite count.
5117330f729Sjoerg const MachineFrameInfo &MFI = AP.MF->getFrameInfo();
5127330f729Sjoerg const TargetRegisterInfo *RegInfo = AP.MF->getSubtarget().getRegisterInfo();
5137330f729Sjoerg bool HasDynamicFrameSize =
514*82d56013Sjoerg MFI.hasVarSizedObjects() || RegInfo->hasStackRealignment(*(AP.MF));
5157330f729Sjoerg uint64_t FrameSize = HasDynamicFrameSize ? UINT64_MAX : MFI.getStackSize();
5167330f729Sjoerg
5177330f729Sjoerg auto CurrentIt = FnInfos.find(AP.CurrentFnSym);
5187330f729Sjoerg if (CurrentIt != FnInfos.end())
5197330f729Sjoerg CurrentIt->second.RecordCount++;
5207330f729Sjoerg else
5217330f729Sjoerg FnInfos.insert(std::make_pair(AP.CurrentFnSym, FunctionInfo(FrameSize)));
5227330f729Sjoerg }
5237330f729Sjoerg
recordStackMap(const MCSymbol & L,const MachineInstr & MI)524*82d56013Sjoerg void StackMaps::recordStackMap(const MCSymbol &L, const MachineInstr &MI) {
5257330f729Sjoerg assert(MI.getOpcode() == TargetOpcode::STACKMAP && "expected stackmap");
5267330f729Sjoerg
5277330f729Sjoerg StackMapOpers opers(&MI);
5287330f729Sjoerg const int64_t ID = MI.getOperand(PatchPointOpers::IDPos).getImm();
529*82d56013Sjoerg recordStackMapOpers(L, MI, ID, std::next(MI.operands_begin(),
530*82d56013Sjoerg opers.getVarIdx()),
5317330f729Sjoerg MI.operands_end());
5327330f729Sjoerg }
5337330f729Sjoerg
recordPatchPoint(const MCSymbol & L,const MachineInstr & MI)534*82d56013Sjoerg void StackMaps::recordPatchPoint(const MCSymbol &L, const MachineInstr &MI) {
5357330f729Sjoerg assert(MI.getOpcode() == TargetOpcode::PATCHPOINT && "expected patchpoint");
5367330f729Sjoerg
5377330f729Sjoerg PatchPointOpers opers(&MI);
5387330f729Sjoerg const int64_t ID = opers.getID();
5397330f729Sjoerg auto MOI = std::next(MI.operands_begin(), opers.getStackMapStartIdx());
540*82d56013Sjoerg recordStackMapOpers(L, MI, ID, MOI, MI.operands_end(),
5417330f729Sjoerg opers.isAnyReg() && opers.hasDef());
5427330f729Sjoerg
5437330f729Sjoerg #ifndef NDEBUG
5447330f729Sjoerg // verify anyregcc
5457330f729Sjoerg auto &Locations = CSInfos.back().Locations;
5467330f729Sjoerg if (opers.isAnyReg()) {
5477330f729Sjoerg unsigned NArgs = opers.getNumCallArgs();
5487330f729Sjoerg for (unsigned i = 0, e = (opers.hasDef() ? NArgs + 1 : NArgs); i != e; ++i)
5497330f729Sjoerg assert(Locations[i].Type == Location::Register &&
5507330f729Sjoerg "anyreg arg must be in reg.");
5517330f729Sjoerg }
5527330f729Sjoerg #endif
5537330f729Sjoerg }
5547330f729Sjoerg
recordStatepoint(const MCSymbol & L,const MachineInstr & MI)555*82d56013Sjoerg void StackMaps::recordStatepoint(const MCSymbol &L, const MachineInstr &MI) {
5567330f729Sjoerg assert(MI.getOpcode() == TargetOpcode::STATEPOINT && "expected statepoint");
5577330f729Sjoerg
5587330f729Sjoerg StatepointOpers opers(&MI);
5597330f729Sjoerg const unsigned StartIdx = opers.getVarIdx();
560*82d56013Sjoerg recordStackMapOpers(L, MI, opers.getID(), MI.operands_begin() + StartIdx,
5617330f729Sjoerg MI.operands_end(), false);
5627330f729Sjoerg }
5637330f729Sjoerg
5647330f729Sjoerg /// Emit the stackmap header.
5657330f729Sjoerg ///
5667330f729Sjoerg /// Header {
567*82d56013Sjoerg /// uint8 : Stack Map Version (currently 3)
5687330f729Sjoerg /// uint8 : Reserved (expected to be 0)
5697330f729Sjoerg /// uint16 : Reserved (expected to be 0)
5707330f729Sjoerg /// }
5717330f729Sjoerg /// uint32 : NumFunctions
5727330f729Sjoerg /// uint32 : NumConstants
5737330f729Sjoerg /// uint32 : NumRecords
emitStackmapHeader(MCStreamer & OS)5747330f729Sjoerg void StackMaps::emitStackmapHeader(MCStreamer &OS) {
5757330f729Sjoerg // Header.
576*82d56013Sjoerg OS.emitIntValue(StackMapVersion, 1); // Version.
577*82d56013Sjoerg OS.emitIntValue(0, 1); // Reserved.
578*82d56013Sjoerg OS.emitInt16(0); // Reserved.
5797330f729Sjoerg
5807330f729Sjoerg // Num functions.
5817330f729Sjoerg LLVM_DEBUG(dbgs() << WSMP << "#functions = " << FnInfos.size() << '\n');
582*82d56013Sjoerg OS.emitInt32(FnInfos.size());
5837330f729Sjoerg // Num constants.
5847330f729Sjoerg LLVM_DEBUG(dbgs() << WSMP << "#constants = " << ConstPool.size() << '\n');
585*82d56013Sjoerg OS.emitInt32(ConstPool.size());
5867330f729Sjoerg // Num callsites.
5877330f729Sjoerg LLVM_DEBUG(dbgs() << WSMP << "#callsites = " << CSInfos.size() << '\n');
588*82d56013Sjoerg OS.emitInt32(CSInfos.size());
5897330f729Sjoerg }
5907330f729Sjoerg
5917330f729Sjoerg /// Emit the function frame record for each function.
5927330f729Sjoerg ///
5937330f729Sjoerg /// StkSizeRecord[NumFunctions] {
5947330f729Sjoerg /// uint64 : Function Address
5957330f729Sjoerg /// uint64 : Stack Size
5967330f729Sjoerg /// uint64 : Record Count
5977330f729Sjoerg /// }
emitFunctionFrameRecords(MCStreamer & OS)5987330f729Sjoerg void StackMaps::emitFunctionFrameRecords(MCStreamer &OS) {
5997330f729Sjoerg // Function Frame records.
6007330f729Sjoerg LLVM_DEBUG(dbgs() << WSMP << "functions:\n");
6017330f729Sjoerg for (auto const &FR : FnInfos) {
6027330f729Sjoerg LLVM_DEBUG(dbgs() << WSMP << "function addr: " << FR.first
6037330f729Sjoerg << " frame size: " << FR.second.StackSize
6047330f729Sjoerg << " callsite count: " << FR.second.RecordCount << '\n');
605*82d56013Sjoerg OS.emitSymbolValue(FR.first, 8);
606*82d56013Sjoerg OS.emitIntValue(FR.second.StackSize, 8);
607*82d56013Sjoerg OS.emitIntValue(FR.second.RecordCount, 8);
6087330f729Sjoerg }
6097330f729Sjoerg }
6107330f729Sjoerg
6117330f729Sjoerg /// Emit the constant pool.
6127330f729Sjoerg ///
6137330f729Sjoerg /// int64 : Constants[NumConstants]
emitConstantPoolEntries(MCStreamer & OS)6147330f729Sjoerg void StackMaps::emitConstantPoolEntries(MCStreamer &OS) {
6157330f729Sjoerg // Constant pool entries.
6167330f729Sjoerg LLVM_DEBUG(dbgs() << WSMP << "constants:\n");
6177330f729Sjoerg for (const auto &ConstEntry : ConstPool) {
6187330f729Sjoerg LLVM_DEBUG(dbgs() << WSMP << ConstEntry.second << '\n');
619*82d56013Sjoerg OS.emitIntValue(ConstEntry.second, 8);
6207330f729Sjoerg }
6217330f729Sjoerg }
6227330f729Sjoerg
6237330f729Sjoerg /// Emit the callsite info for each callsite.
6247330f729Sjoerg ///
6257330f729Sjoerg /// StkMapRecord[NumRecords] {
6267330f729Sjoerg /// uint64 : PatchPoint ID
6277330f729Sjoerg /// uint32 : Instruction Offset
6287330f729Sjoerg /// uint16 : Reserved (record flags)
6297330f729Sjoerg /// uint16 : NumLocations
6307330f729Sjoerg /// Location[NumLocations] {
6317330f729Sjoerg /// uint8 : Register | Direct | Indirect | Constant | ConstantIndex
6327330f729Sjoerg /// uint8 : Size in Bytes
6337330f729Sjoerg /// uint16 : Dwarf RegNum
6347330f729Sjoerg /// int32 : Offset
6357330f729Sjoerg /// }
6367330f729Sjoerg /// uint16 : Padding
6377330f729Sjoerg /// uint16 : NumLiveOuts
6387330f729Sjoerg /// LiveOuts[NumLiveOuts] {
6397330f729Sjoerg /// uint16 : Dwarf RegNum
6407330f729Sjoerg /// uint8 : Reserved
6417330f729Sjoerg /// uint8 : Size in Bytes
6427330f729Sjoerg /// }
6437330f729Sjoerg /// uint32 : Padding (only if required to align to 8 byte)
6447330f729Sjoerg /// }
6457330f729Sjoerg ///
6467330f729Sjoerg /// Location Encoding, Type, Value:
6477330f729Sjoerg /// 0x1, Register, Reg (value in register)
6487330f729Sjoerg /// 0x2, Direct, Reg + Offset (frame index)
6497330f729Sjoerg /// 0x3, Indirect, [Reg + Offset] (spilled value)
6507330f729Sjoerg /// 0x4, Constant, Offset (small constant)
6517330f729Sjoerg /// 0x5, ConstIndex, Constants[Offset] (large constant)
emitCallsiteEntries(MCStreamer & OS)6527330f729Sjoerg void StackMaps::emitCallsiteEntries(MCStreamer &OS) {
6537330f729Sjoerg LLVM_DEBUG(print(dbgs()));
6547330f729Sjoerg // Callsite entries.
6557330f729Sjoerg for (const auto &CSI : CSInfos) {
6567330f729Sjoerg const LocationVec &CSLocs = CSI.Locations;
6577330f729Sjoerg const LiveOutVec &LiveOuts = CSI.LiveOuts;
6587330f729Sjoerg
6597330f729Sjoerg // Verify stack map entry. It's better to communicate a problem to the
6607330f729Sjoerg // runtime than crash in case of in-process compilation. Currently, we do
6617330f729Sjoerg // simple overflow checks, but we may eventually communicate other
6627330f729Sjoerg // compilation errors this way.
6637330f729Sjoerg if (CSLocs.size() > UINT16_MAX || LiveOuts.size() > UINT16_MAX) {
664*82d56013Sjoerg OS.emitIntValue(UINT64_MAX, 8); // Invalid ID.
665*82d56013Sjoerg OS.emitValue(CSI.CSOffsetExpr, 4);
666*82d56013Sjoerg OS.emitInt16(0); // Reserved.
667*82d56013Sjoerg OS.emitInt16(0); // 0 locations.
668*82d56013Sjoerg OS.emitInt16(0); // padding.
669*82d56013Sjoerg OS.emitInt16(0); // 0 live-out registers.
670*82d56013Sjoerg OS.emitInt32(0); // padding.
6717330f729Sjoerg continue;
6727330f729Sjoerg }
6737330f729Sjoerg
674*82d56013Sjoerg OS.emitIntValue(CSI.ID, 8);
675*82d56013Sjoerg OS.emitValue(CSI.CSOffsetExpr, 4);
6767330f729Sjoerg
6777330f729Sjoerg // Reserved for flags.
678*82d56013Sjoerg OS.emitInt16(0);
679*82d56013Sjoerg OS.emitInt16(CSLocs.size());
6807330f729Sjoerg
6817330f729Sjoerg for (const auto &Loc : CSLocs) {
682*82d56013Sjoerg OS.emitIntValue(Loc.Type, 1);
683*82d56013Sjoerg OS.emitIntValue(0, 1); // Reserved
684*82d56013Sjoerg OS.emitInt16(Loc.Size);
685*82d56013Sjoerg OS.emitInt16(Loc.Reg);
686*82d56013Sjoerg OS.emitInt16(0); // Reserved
687*82d56013Sjoerg OS.emitInt32(Loc.Offset);
6887330f729Sjoerg }
6897330f729Sjoerg
6907330f729Sjoerg // Emit alignment to 8 byte.
691*82d56013Sjoerg OS.emitValueToAlignment(8);
6927330f729Sjoerg
6937330f729Sjoerg // Num live-out registers and padding to align to 4 byte.
694*82d56013Sjoerg OS.emitInt16(0);
695*82d56013Sjoerg OS.emitInt16(LiveOuts.size());
6967330f729Sjoerg
6977330f729Sjoerg for (const auto &LO : LiveOuts) {
698*82d56013Sjoerg OS.emitInt16(LO.DwarfRegNum);
699*82d56013Sjoerg OS.emitIntValue(0, 1);
700*82d56013Sjoerg OS.emitIntValue(LO.Size, 1);
7017330f729Sjoerg }
7027330f729Sjoerg // Emit alignment to 8 byte.
703*82d56013Sjoerg OS.emitValueToAlignment(8);
7047330f729Sjoerg }
7057330f729Sjoerg }
7067330f729Sjoerg
7077330f729Sjoerg /// Serialize the stackmap data.
serializeToStackMapSection()7087330f729Sjoerg void StackMaps::serializeToStackMapSection() {
7097330f729Sjoerg (void)WSMP;
7107330f729Sjoerg // Bail out if there's no stack map data.
7117330f729Sjoerg assert((!CSInfos.empty() || ConstPool.empty()) &&
7127330f729Sjoerg "Expected empty constant pool too!");
7137330f729Sjoerg assert((!CSInfos.empty() || FnInfos.empty()) &&
7147330f729Sjoerg "Expected empty function record too!");
7157330f729Sjoerg if (CSInfos.empty())
7167330f729Sjoerg return;
7177330f729Sjoerg
7187330f729Sjoerg MCContext &OutContext = AP.OutStreamer->getContext();
7197330f729Sjoerg MCStreamer &OS = *AP.OutStreamer;
7207330f729Sjoerg
7217330f729Sjoerg // Create the section.
7227330f729Sjoerg MCSection *StackMapSection =
7237330f729Sjoerg OutContext.getObjectFileInfo()->getStackMapSection();
7247330f729Sjoerg OS.SwitchSection(StackMapSection);
7257330f729Sjoerg
7267330f729Sjoerg // Emit a dummy symbol to force section inclusion.
727*82d56013Sjoerg OS.emitLabel(OutContext.getOrCreateSymbol(Twine("__LLVM_StackMaps")));
7287330f729Sjoerg
7297330f729Sjoerg // Serialize data.
7307330f729Sjoerg LLVM_DEBUG(dbgs() << "********** Stack Map Output **********\n");
7317330f729Sjoerg emitStackmapHeader(OS);
7327330f729Sjoerg emitFunctionFrameRecords(OS);
7337330f729Sjoerg emitConstantPoolEntries(OS);
7347330f729Sjoerg emitCallsiteEntries(OS);
7357330f729Sjoerg OS.AddBlankLine();
7367330f729Sjoerg
7377330f729Sjoerg // Clean up.
7387330f729Sjoerg CSInfos.clear();
7397330f729Sjoerg ConstPool.clear();
7407330f729Sjoerg }
741