xref: /src/contrib/llvm-project/llvm/lib/CodeGen/StackMaps.cpp (revision 7a6dacaca14b62ca4b74406814becb87a3fefac0) !
171d5a254SDimitry Andric //===- StackMaps.cpp ------------------------------------------------------===//
2f8af5cf6SDimitry Andric //
3e6d15924SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e6d15924SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5e6d15924SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6f8af5cf6SDimitry Andric //
7f8af5cf6SDimitry Andric //===----------------------------------------------------------------------===//
8f8af5cf6SDimitry Andric 
97ab83427SDimitry Andric #include "llvm/CodeGen/StackMaps.h"
1071d5a254SDimitry Andric #include "llvm/ADT/DenseMapInfo.h"
1171d5a254SDimitry Andric #include "llvm/ADT/STLExtras.h"
1271d5a254SDimitry Andric #include "llvm/ADT/Twine.h"
13f8af5cf6SDimitry Andric #include "llvm/CodeGen/AsmPrinter.h"
145ca98fd9SDimitry Andric #include "llvm/CodeGen/MachineFrameInfo.h"
155ca98fd9SDimitry Andric #include "llvm/CodeGen/MachineFunction.h"
16f8af5cf6SDimitry Andric #include "llvm/CodeGen/MachineInstr.h"
1771d5a254SDimitry Andric #include "llvm/CodeGen/MachineOperand.h"
18044eb2f6SDimitry Andric #include "llvm/CodeGen/TargetOpcodes.h"
19044eb2f6SDimitry Andric #include "llvm/CodeGen/TargetRegisterInfo.h"
20044eb2f6SDimitry Andric #include "llvm/CodeGen/TargetSubtargetInfo.h"
215ca98fd9SDimitry Andric #include "llvm/IR/DataLayout.h"
22f8af5cf6SDimitry Andric #include "llvm/MC/MCContext.h"
23f8af5cf6SDimitry Andric #include "llvm/MC/MCExpr.h"
24f8af5cf6SDimitry Andric #include "llvm/MC/MCObjectFileInfo.h"
2571d5a254SDimitry Andric #include "llvm/MC/MCRegisterInfo.h"
26f8af5cf6SDimitry Andric #include "llvm/MC/MCStreamer.h"
275ca98fd9SDimitry Andric #include "llvm/Support/CommandLine.h"
2871d5a254SDimitry Andric #include "llvm/Support/Debug.h"
2971d5a254SDimitry Andric #include "llvm/Support/ErrorHandling.h"
3071d5a254SDimitry Andric #include "llvm/Support/MathExtras.h"
3171d5a254SDimitry Andric #include "llvm/Support/raw_ostream.h"
3271d5a254SDimitry Andric #include <algorithm>
3371d5a254SDimitry Andric #include <cassert>
3471d5a254SDimitry Andric #include <cstdint>
35f8af5cf6SDimitry Andric #include <iterator>
3671d5a254SDimitry Andric #include <utility>
37f8af5cf6SDimitry Andric 
38f8af5cf6SDimitry Andric using namespace llvm;
39f8af5cf6SDimitry Andric 
405ca98fd9SDimitry Andric #define DEBUG_TYPE "stackmaps"
415ca98fd9SDimitry Andric 
42ee8648bdSDimitry Andric static cl::opt<int> StackMapVersion(
43044eb2f6SDimitry Andric     "stackmap-version", cl::init(3), cl::Hidden,
44a303c417SDimitry Andric     cl::desc("Specify the stackmap encoding version (default = 3)"));
455ca98fd9SDimitry Andric 
465ca98fd9SDimitry Andric const char *StackMaps::WSMP = "Stack Maps: ";
475ca98fd9SDimitry Andric 
getConstMetaVal(const MachineInstr & MI,unsigned Idx)48b60736ecSDimitry Andric static uint64_t getConstMetaVal(const MachineInstr &MI, unsigned Idx) {
49b60736ecSDimitry Andric   assert(MI.getOperand(Idx).isImm() &&
50b60736ecSDimitry Andric          MI.getOperand(Idx).getImm() == StackMaps::ConstantOp);
51b60736ecSDimitry Andric   const auto &MO = MI.getOperand(Idx + 1);
52b60736ecSDimitry Andric   assert(MO.isImm());
53b60736ecSDimitry Andric   return MO.getImm();
54b60736ecSDimitry Andric }
55b60736ecSDimitry Andric 
StackMapOpers(const MachineInstr * MI)56b915e9e0SDimitry Andric StackMapOpers::StackMapOpers(const MachineInstr *MI)
57b915e9e0SDimitry Andric   : MI(MI) {
58b915e9e0SDimitry Andric   assert(getVarIdx() <= MI->getNumOperands() &&
59b915e9e0SDimitry Andric          "invalid stackmap definition");
60b915e9e0SDimitry Andric }
61b915e9e0SDimitry Andric 
PatchPointOpers(const MachineInstr * MI)625ca98fd9SDimitry Andric PatchPointOpers::PatchPointOpers(const MachineInstr *MI)
63ee8648bdSDimitry Andric     : MI(MI), HasDef(MI->getOperand(0).isReg() && MI->getOperand(0).isDef() &&
64b915e9e0SDimitry Andric                      !MI->getOperand(0).isImplicit()) {
655ca98fd9SDimitry Andric #ifndef NDEBUG
66f8af5cf6SDimitry Andric   unsigned CheckStartIdx = 0, e = MI->getNumOperands();
67f8af5cf6SDimitry Andric   while (CheckStartIdx < e && MI->getOperand(CheckStartIdx).isReg() &&
68f8af5cf6SDimitry Andric          MI->getOperand(CheckStartIdx).isDef() &&
69f8af5cf6SDimitry Andric          !MI->getOperand(CheckStartIdx).isImplicit())
70f8af5cf6SDimitry Andric     ++CheckStartIdx;
71f8af5cf6SDimitry Andric 
72f8af5cf6SDimitry Andric   assert(getMetaIdx() == CheckStartIdx &&
735ca98fd9SDimitry Andric          "Unexpected additional definition in Patchpoint intrinsic.");
74f8af5cf6SDimitry Andric #endif
75f8af5cf6SDimitry Andric }
76f8af5cf6SDimitry Andric 
getNextScratchIdx(unsigned StartIdx) const77f8af5cf6SDimitry Andric unsigned PatchPointOpers::getNextScratchIdx(unsigned StartIdx) const {
78f8af5cf6SDimitry Andric   if (!StartIdx)
79f8af5cf6SDimitry Andric     StartIdx = getVarIdx();
80f8af5cf6SDimitry Andric 
81f8af5cf6SDimitry Andric   // Find the next scratch register (implicit def and early clobber)
82f8af5cf6SDimitry Andric   unsigned ScratchIdx = StartIdx, e = MI->getNumOperands();
83f8af5cf6SDimitry Andric   while (ScratchIdx < e &&
84f8af5cf6SDimitry Andric          !(MI->getOperand(ScratchIdx).isReg() &&
85f8af5cf6SDimitry Andric            MI->getOperand(ScratchIdx).isDef() &&
86f8af5cf6SDimitry Andric            MI->getOperand(ScratchIdx).isImplicit() &&
87f8af5cf6SDimitry Andric            MI->getOperand(ScratchIdx).isEarlyClobber()))
88f8af5cf6SDimitry Andric     ++ScratchIdx;
89f8af5cf6SDimitry Andric 
90f8af5cf6SDimitry Andric   assert(ScratchIdx != e && "No scratch register available");
91f8af5cf6SDimitry Andric   return ScratchIdx;
92f8af5cf6SDimitry Andric }
93f8af5cf6SDimitry Andric 
getNumGcMapEntriesIdx()94b60736ecSDimitry Andric unsigned StatepointOpers::getNumGcMapEntriesIdx() {
95b60736ecSDimitry Andric   // Take index of num of allocas and skip all allocas records.
96b60736ecSDimitry Andric   unsigned CurIdx = getNumAllocaIdx();
97b60736ecSDimitry Andric   unsigned NumAllocas = getConstMetaVal(*MI, CurIdx - 1);
98b60736ecSDimitry Andric   CurIdx++;
99b60736ecSDimitry Andric   while (NumAllocas--)
100b60736ecSDimitry Andric     CurIdx = StackMaps::getNextMetaArgIdx(MI, CurIdx);
101b60736ecSDimitry Andric   return CurIdx + 1; // skip <StackMaps::ConstantOp>
102b60736ecSDimitry Andric }
103b60736ecSDimitry Andric 
getNumAllocaIdx()104b60736ecSDimitry Andric unsigned StatepointOpers::getNumAllocaIdx() {
105b60736ecSDimitry Andric   // Take index of num of gc ptrs and skip all gc ptr records.
106b60736ecSDimitry Andric   unsigned CurIdx = getNumGCPtrIdx();
107b60736ecSDimitry Andric   unsigned NumGCPtrs = getConstMetaVal(*MI, CurIdx - 1);
108b60736ecSDimitry Andric   CurIdx++;
109b60736ecSDimitry Andric   while (NumGCPtrs--)
110b60736ecSDimitry Andric     CurIdx = StackMaps::getNextMetaArgIdx(MI, CurIdx);
111b60736ecSDimitry Andric   return CurIdx + 1; // skip <StackMaps::ConstantOp>
112b60736ecSDimitry Andric }
113b60736ecSDimitry Andric 
getNumGCPtrIdx()114b60736ecSDimitry Andric unsigned StatepointOpers::getNumGCPtrIdx() {
115b60736ecSDimitry Andric   // Take index of num of deopt args and skip all deopt records.
116b60736ecSDimitry Andric   unsigned CurIdx = getNumDeoptArgsIdx();
117b60736ecSDimitry Andric   unsigned NumDeoptArgs = getConstMetaVal(*MI, CurIdx - 1);
118b60736ecSDimitry Andric   CurIdx++;
119b60736ecSDimitry Andric   while (NumDeoptArgs--) {
120b60736ecSDimitry Andric     CurIdx = StackMaps::getNextMetaArgIdx(MI, CurIdx);
121b60736ecSDimitry Andric   }
122b60736ecSDimitry Andric   return CurIdx + 1; // skip <StackMaps::ConstantOp>
123b60736ecSDimitry Andric }
124b60736ecSDimitry Andric 
getFirstGCPtrIdx()125b60736ecSDimitry Andric int StatepointOpers::getFirstGCPtrIdx() {
126b60736ecSDimitry Andric   unsigned NumGCPtrsIdx = getNumGCPtrIdx();
127b60736ecSDimitry Andric   unsigned NumGCPtrs = getConstMetaVal(*MI, NumGCPtrsIdx - 1);
128b60736ecSDimitry Andric   if (NumGCPtrs == 0)
129b60736ecSDimitry Andric     return -1;
130b60736ecSDimitry Andric   ++NumGCPtrsIdx; // skip <num gc ptrs>
131b60736ecSDimitry Andric   assert(NumGCPtrsIdx < MI->getNumOperands());
132b60736ecSDimitry Andric   return (int)NumGCPtrsIdx;
133b60736ecSDimitry Andric }
134b60736ecSDimitry Andric 
getGCPointerMap(SmallVectorImpl<std::pair<unsigned,unsigned>> & GCMap)135b60736ecSDimitry Andric unsigned StatepointOpers::getGCPointerMap(
136b60736ecSDimitry Andric     SmallVectorImpl<std::pair<unsigned, unsigned>> &GCMap) {
137b60736ecSDimitry Andric   unsigned CurIdx = getNumGcMapEntriesIdx();
138b60736ecSDimitry Andric   unsigned GCMapSize = getConstMetaVal(*MI, CurIdx - 1);
139b60736ecSDimitry Andric   CurIdx++;
140b60736ecSDimitry Andric   for (unsigned N = 0; N < GCMapSize; ++N) {
141b60736ecSDimitry Andric     unsigned B = MI->getOperand(CurIdx++).getImm();
142b60736ecSDimitry Andric     unsigned D = MI->getOperand(CurIdx++).getImm();
143b60736ecSDimitry Andric     GCMap.push_back(std::make_pair(B, D));
144b60736ecSDimitry Andric   }
145b60736ecSDimitry Andric 
146b60736ecSDimitry Andric   return GCMapSize;
147b60736ecSDimitry Andric }
148b60736ecSDimitry Andric 
isFoldableReg(Register Reg) const149e3b55780SDimitry Andric bool StatepointOpers::isFoldableReg(Register Reg) const {
150e3b55780SDimitry Andric   unsigned FoldableAreaStart = getVarIdx();
151e3b55780SDimitry Andric   for (const MachineOperand &MO : MI->uses()) {
1527fa27ce4SDimitry Andric     if (MO.getOperandNo() >= FoldableAreaStart)
153e3b55780SDimitry Andric       break;
154e3b55780SDimitry Andric     if (MO.isReg() && MO.getReg() == Reg)
155e3b55780SDimitry Andric       return false;
156e3b55780SDimitry Andric   }
157e3b55780SDimitry Andric   return true;
158e3b55780SDimitry Andric }
159e3b55780SDimitry Andric 
isFoldableReg(const MachineInstr * MI,Register Reg)160e3b55780SDimitry Andric bool StatepointOpers::isFoldableReg(const MachineInstr *MI, Register Reg) {
161e3b55780SDimitry Andric   if (MI->getOpcode() != TargetOpcode::STATEPOINT)
162e3b55780SDimitry Andric     return false;
163e3b55780SDimitry Andric   return StatepointOpers(MI).isFoldableReg(Reg);
164e3b55780SDimitry Andric }
165e3b55780SDimitry Andric 
StackMaps(AsmPrinter & AP)1665ca98fd9SDimitry Andric StackMaps::StackMaps(AsmPrinter &AP) : AP(AP) {
167a303c417SDimitry Andric   if (StackMapVersion != 3)
1685ca98fd9SDimitry Andric     llvm_unreachable("Unsupported stackmap version!");
1695ca98fd9SDimitry Andric }
1705ca98fd9SDimitry Andric 
getNextMetaArgIdx(const MachineInstr * MI,unsigned CurIdx)171b60736ecSDimitry Andric unsigned StackMaps::getNextMetaArgIdx(const MachineInstr *MI, unsigned CurIdx) {
172b60736ecSDimitry Andric   assert(CurIdx < MI->getNumOperands() && "Bad meta arg index");
173b60736ecSDimitry Andric   const auto &MO = MI->getOperand(CurIdx);
174b60736ecSDimitry Andric   if (MO.isImm()) {
175b60736ecSDimitry Andric     switch (MO.getImm()) {
176b60736ecSDimitry Andric     default:
177b60736ecSDimitry Andric       llvm_unreachable("Unrecognized operand type.");
178b60736ecSDimitry Andric     case StackMaps::DirectMemRefOp:
179b60736ecSDimitry Andric       CurIdx += 2;
180b60736ecSDimitry Andric       break;
181b60736ecSDimitry Andric     case StackMaps::IndirectMemRefOp:
182b60736ecSDimitry Andric       CurIdx += 3;
183b60736ecSDimitry Andric       break;
184b60736ecSDimitry Andric     case StackMaps::ConstantOp:
185b60736ecSDimitry Andric       ++CurIdx;
186b60736ecSDimitry Andric       break;
187b60736ecSDimitry Andric     }
188b60736ecSDimitry Andric   }
189b60736ecSDimitry Andric   ++CurIdx;
190b60736ecSDimitry Andric   assert(CurIdx < MI->getNumOperands() && "points past operand list");
191b60736ecSDimitry Andric   return CurIdx;
192b60736ecSDimitry Andric }
193b60736ecSDimitry Andric 
1945a5ac124SDimitry Andric /// Go up the super-register chain until we hit a valid dwarf register number.
getDwarfRegNum(unsigned Reg,const TargetRegisterInfo * TRI)1955a5ac124SDimitry Andric static unsigned getDwarfRegNum(unsigned Reg, const TargetRegisterInfo *TRI) {
1967fa27ce4SDimitry Andric   int RegNum;
1977fa27ce4SDimitry Andric   for (MCPhysReg SR : TRI->superregs_inclusive(Reg)) {
1987fa27ce4SDimitry Andric     RegNum = TRI->getDwarfRegNum(SR, false);
1997fa27ce4SDimitry Andric     if (RegNum >= 0)
2007fa27ce4SDimitry Andric       break;
2017fa27ce4SDimitry Andric   }
2025a5ac124SDimitry Andric 
2034df029ccSDimitry Andric   assert(RegNum >= 0 && isUInt<16>(RegNum) && "Invalid Dwarf register number.");
204ee8648bdSDimitry Andric   return (unsigned)RegNum;
2055a5ac124SDimitry Andric }
2065a5ac124SDimitry Andric 
2075ca98fd9SDimitry Andric MachineInstr::const_mop_iterator
parseOperand(MachineInstr::const_mop_iterator MOI,MachineInstr::const_mop_iterator MOE,LocationVec & Locs,LiveOutVec & LiveOuts)2085ca98fd9SDimitry Andric StackMaps::parseOperand(MachineInstr::const_mop_iterator MOI,
209ee8648bdSDimitry Andric                         MachineInstr::const_mop_iterator MOE, LocationVec &Locs,
2104df029ccSDimitry Andric                         LiveOutVec &LiveOuts) {
2115a5ac124SDimitry Andric   const TargetRegisterInfo *TRI = AP.MF->getSubtarget().getRegisterInfo();
2125ca98fd9SDimitry Andric   if (MOI->isImm()) {
2135ca98fd9SDimitry Andric     switch (MOI->getImm()) {
214ee8648bdSDimitry Andric     default:
215ee8648bdSDimitry Andric       llvm_unreachable("Unrecognized operand type.");
2165ca98fd9SDimitry Andric     case StackMaps::DirectMemRefOp: {
217dd58ef01SDimitry Andric       auto &DL = AP.MF->getDataLayout();
218dd58ef01SDimitry Andric 
219dd58ef01SDimitry Andric       unsigned Size = DL.getPointerSizeInBits();
2205ca98fd9SDimitry Andric       assert((Size % 8) == 0 && "Need pointer size in bytes.");
2215ca98fd9SDimitry Andric       Size /= 8;
2221d5ae102SDimitry Andric       Register Reg = (++MOI)->getReg();
2235ca98fd9SDimitry Andric       int64_t Imm = (++MOI)->getImm();
224ee8648bdSDimitry Andric       Locs.emplace_back(StackMaps::Location::Direct, Size,
225ee8648bdSDimitry Andric                         getDwarfRegNum(Reg, TRI), Imm);
2265ca98fd9SDimitry Andric       break;
2275ca98fd9SDimitry Andric     }
2285ca98fd9SDimitry Andric     case StackMaps::IndirectMemRefOp: {
2295ca98fd9SDimitry Andric       int64_t Size = (++MOI)->getImm();
2305ca98fd9SDimitry Andric       assert(Size > 0 && "Need a valid size for indirect memory locations.");
2311d5ae102SDimitry Andric       Register Reg = (++MOI)->getReg();
2325ca98fd9SDimitry Andric       int64_t Imm = (++MOI)->getImm();
233ee8648bdSDimitry Andric       Locs.emplace_back(StackMaps::Location::Indirect, Size,
234ee8648bdSDimitry Andric                         getDwarfRegNum(Reg, TRI), Imm);
2355ca98fd9SDimitry Andric       break;
2365ca98fd9SDimitry Andric     }
2375ca98fd9SDimitry Andric     case StackMaps::ConstantOp: {
2385ca98fd9SDimitry Andric       ++MOI;
2395ca98fd9SDimitry Andric       assert(MOI->isImm() && "Expected constant operand.");
2405ca98fd9SDimitry Andric       int64_t Imm = MOI->getImm();
2414df029ccSDimitry Andric       if (isInt<32>(Imm)) {
242ee8648bdSDimitry Andric         Locs.emplace_back(Location::Constant, sizeof(int64_t), 0, Imm);
2434df029ccSDimitry Andric       } else {
2444df029ccSDimitry Andric         // ConstPool is intentionally a MapVector of 'uint64_t's (as
2454df029ccSDimitry Andric         // opposed to 'int64_t's).  We should never be in a situation
2464df029ccSDimitry Andric         // where we have to insert either the tombstone or the empty
2474df029ccSDimitry Andric         // keys into a map, and for a DenseMap<uint64_t, T> these are
2484df029ccSDimitry Andric         // (uint64_t)0 and (uint64_t)-1.  They can be and are
2494df029ccSDimitry Andric         // represented using 32 bit integers.
2504df029ccSDimitry Andric         assert((uint64_t)Imm != DenseMapInfo<uint64_t>::getEmptyKey() &&
2514df029ccSDimitry Andric                (uint64_t)Imm != DenseMapInfo<uint64_t>::getTombstoneKey() &&
2524df029ccSDimitry Andric                "empty and tombstone keys should fit in 32 bits!");
2534df029ccSDimitry Andric         auto Result = ConstPool.insert(std::make_pair(Imm, Imm));
2544df029ccSDimitry Andric         Locs.emplace_back(Location::ConstantIndex, sizeof(int64_t), 0,
2554df029ccSDimitry Andric                           Result.first - ConstPool.begin());
2564df029ccSDimitry Andric       }
2575ca98fd9SDimitry Andric       break;
2585ca98fd9SDimitry Andric     }
2595ca98fd9SDimitry Andric     }
2605ca98fd9SDimitry Andric     return ++MOI;
2615ca98fd9SDimitry Andric   }
2625ca98fd9SDimitry Andric 
2635ca98fd9SDimitry Andric   // The physical register number will ultimately be encoded as a DWARF regno.
2645ca98fd9SDimitry Andric   // The stack map also records the size of a spill slot that can hold the
2655ca98fd9SDimitry Andric   // register content. (The runtime can track the actual size of the data type
2665ca98fd9SDimitry Andric   // if it needs to.)
2675ca98fd9SDimitry Andric   if (MOI->isReg()) {
2685ca98fd9SDimitry Andric     // Skip implicit registers (this includes our scratch registers)
2695ca98fd9SDimitry Andric     if (MOI->isImplicit())
2705ca98fd9SDimitry Andric       return ++MOI;
2715ca98fd9SDimitry Andric 
272b60736ecSDimitry Andric     if (MOI->isUndef()) {
273b60736ecSDimitry Andric       // Record `undef` register as constant. Use same value as ISel uses.
274b60736ecSDimitry Andric       Locs.emplace_back(Location::Constant, sizeof(int64_t), 0, 0xFEFEFEFE);
275b60736ecSDimitry Andric       return ++MOI;
276b60736ecSDimitry Andric     }
277b60736ecSDimitry Andric 
278e3b55780SDimitry Andric     assert(MOI->getReg().isPhysical() &&
2795ca98fd9SDimitry Andric            "Virtreg operands should have been rewritten before now.");
2805a5ac124SDimitry Andric     const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(MOI->getReg());
2815ca98fd9SDimitry Andric     assert(!MOI->getSubReg() && "Physical subreg still around.");
2825a5ac124SDimitry Andric 
2835a5ac124SDimitry Andric     unsigned Offset = 0;
284ee8648bdSDimitry Andric     unsigned DwarfRegNum = getDwarfRegNum(MOI->getReg(), TRI);
2851d5ae102SDimitry Andric     unsigned LLVMRegNum = *TRI->getLLVMRegNum(DwarfRegNum, false);
286ee8648bdSDimitry Andric     unsigned SubRegIdx = TRI->getSubRegIndex(LLVMRegNum, MOI->getReg());
2875a5ac124SDimitry Andric     if (SubRegIdx)
2885a5ac124SDimitry Andric       Offset = TRI->getSubRegIdxOffset(SubRegIdx);
2895a5ac124SDimitry Andric 
29012f3ca4cSDimitry Andric     Locs.emplace_back(Location::Register, TRI->getSpillSize(*RC),
29112f3ca4cSDimitry Andric                       DwarfRegNum, Offset);
2925ca98fd9SDimitry Andric     return ++MOI;
2935ca98fd9SDimitry Andric   }
2945ca98fd9SDimitry Andric 
2955ca98fd9SDimitry Andric   if (MOI->isRegLiveOut())
2965ca98fd9SDimitry Andric     LiveOuts = parseRegisterLiveOutMask(MOI->getRegLiveOut());
2975ca98fd9SDimitry Andric 
2985ca98fd9SDimitry Andric   return ++MOI;
2995ca98fd9SDimitry Andric }
3005ca98fd9SDimitry Andric 
print(raw_ostream & OS)3015a5ac124SDimitry Andric void StackMaps::print(raw_ostream &OS) {
3025a5ac124SDimitry Andric   const TargetRegisterInfo *TRI =
3035a5ac124SDimitry Andric       AP.MF ? AP.MF->getSubtarget().getRegisterInfo() : nullptr;
3045a5ac124SDimitry Andric   OS << WSMP << "callsites:\n";
3055a5ac124SDimitry Andric   for (const auto &CSI : CSInfos) {
3065a5ac124SDimitry Andric     const LocationVec &CSLocs = CSI.Locations;
3075a5ac124SDimitry Andric     const LiveOutVec &LiveOuts = CSI.LiveOuts;
3085ca98fd9SDimitry Andric 
3095a5ac124SDimitry Andric     OS << WSMP << "callsite " << CSI.ID << "\n";
3105a5ac124SDimitry Andric     OS << WSMP << "  has " << CSLocs.size() << " locations\n";
3115a5ac124SDimitry Andric 
312ee8648bdSDimitry Andric     unsigned Idx = 0;
3135a5ac124SDimitry Andric     for (const auto &Loc : CSLocs) {
314ee8648bdSDimitry Andric       OS << WSMP << "\t\tLoc " << Idx << ": ";
315ee8648bdSDimitry Andric       switch (Loc.Type) {
3165a5ac124SDimitry Andric       case Location::Unprocessed:
3175a5ac124SDimitry Andric         OS << "<Unprocessed operand>";
3185a5ac124SDimitry Andric         break;
3195a5ac124SDimitry Andric       case Location::Register:
3205a5ac124SDimitry Andric         OS << "Register ";
3215a5ac124SDimitry Andric         if (TRI)
322044eb2f6SDimitry Andric           OS << printReg(Loc.Reg, TRI);
3235a5ac124SDimitry Andric         else
3245a5ac124SDimitry Andric           OS << Loc.Reg;
3255a5ac124SDimitry Andric         break;
3265a5ac124SDimitry Andric       case Location::Direct:
3275a5ac124SDimitry Andric         OS << "Direct ";
3285a5ac124SDimitry Andric         if (TRI)
329044eb2f6SDimitry Andric           OS << printReg(Loc.Reg, TRI);
3305a5ac124SDimitry Andric         else
3315a5ac124SDimitry Andric           OS << Loc.Reg;
3325a5ac124SDimitry Andric         if (Loc.Offset)
3335a5ac124SDimitry Andric           OS << " + " << Loc.Offset;
3345a5ac124SDimitry Andric         break;
3355a5ac124SDimitry Andric       case Location::Indirect:
3365a5ac124SDimitry Andric         OS << "Indirect ";
3375a5ac124SDimitry Andric         if (TRI)
338044eb2f6SDimitry Andric           OS << printReg(Loc.Reg, TRI);
3395a5ac124SDimitry Andric         else
3405a5ac124SDimitry Andric           OS << Loc.Reg;
3415a5ac124SDimitry Andric         OS << "+" << Loc.Offset;
3425a5ac124SDimitry Andric         break;
3435a5ac124SDimitry Andric       case Location::Constant:
3445a5ac124SDimitry Andric         OS << "Constant " << Loc.Offset;
3455a5ac124SDimitry Andric         break;
3465a5ac124SDimitry Andric       case Location::ConstantIndex:
3475a5ac124SDimitry Andric         OS << "Constant Index " << Loc.Offset;
3485a5ac124SDimitry Andric         break;
3495a5ac124SDimitry Andric       }
350a303c417SDimitry Andric       OS << "\t[encoding: .byte " << Loc.Type << ", .byte 0"
351a303c417SDimitry Andric          << ", .short " << Loc.Size << ", .short " << Loc.Reg << ", .short 0"
352a303c417SDimitry Andric          << ", .int " << Loc.Offset << "]\n";
353ee8648bdSDimitry Andric       Idx++;
3545a5ac124SDimitry Andric     }
3555a5ac124SDimitry Andric 
356ee8648bdSDimitry Andric     OS << WSMP << "\thas " << LiveOuts.size() << " live-out registers\n";
3575a5ac124SDimitry Andric 
358ee8648bdSDimitry Andric     Idx = 0;
3595a5ac124SDimitry Andric     for (const auto &LO : LiveOuts) {
360ee8648bdSDimitry Andric       OS << WSMP << "\t\tLO " << Idx << ": ";
3615a5ac124SDimitry Andric       if (TRI)
362044eb2f6SDimitry Andric         OS << printReg(LO.Reg, TRI);
3635a5ac124SDimitry Andric       else
3645a5ac124SDimitry Andric         OS << LO.Reg;
365ee8648bdSDimitry Andric       OS << "\t[encoding: .short " << LO.DwarfRegNum << ", .byte 0, .byte "
3665a5ac124SDimitry Andric          << LO.Size << "]\n";
367ee8648bdSDimitry Andric       Idx++;
3685a5ac124SDimitry Andric     }
3695a5ac124SDimitry Andric   }
3705ca98fd9SDimitry Andric }
3715ca98fd9SDimitry Andric 
3725ca98fd9SDimitry Andric /// Create a live-out register record for the given register Reg.
3735ca98fd9SDimitry Andric StackMaps::LiveOutReg
createLiveOutReg(unsigned Reg,const TargetRegisterInfo * TRI) const3745ca98fd9SDimitry Andric StackMaps::createLiveOutReg(unsigned Reg, const TargetRegisterInfo *TRI) const {
375ee8648bdSDimitry Andric   unsigned DwarfRegNum = getDwarfRegNum(Reg, TRI);
37612f3ca4cSDimitry Andric   unsigned Size = TRI->getSpillSize(*TRI->getMinimalPhysRegClass(Reg));
377ee8648bdSDimitry Andric   return LiveOutReg(Reg, DwarfRegNum, Size);
3785ca98fd9SDimitry Andric }
3795ca98fd9SDimitry Andric 
3805ca98fd9SDimitry Andric /// Parse the register live-out mask and return a vector of live-out registers
3815ca98fd9SDimitry Andric /// that need to be recorded in the stackmap.
3825ca98fd9SDimitry Andric StackMaps::LiveOutVec
parseRegisterLiveOutMask(const uint32_t * Mask) const3835ca98fd9SDimitry Andric StackMaps::parseRegisterLiveOutMask(const uint32_t *Mask) const {
3845ca98fd9SDimitry Andric   assert(Mask && "No register mask specified");
3855a5ac124SDimitry Andric   const TargetRegisterInfo *TRI = AP.MF->getSubtarget().getRegisterInfo();
3865ca98fd9SDimitry Andric   LiveOutVec LiveOuts;
3875ca98fd9SDimitry Andric 
3885ca98fd9SDimitry Andric   // Create a LiveOutReg for each bit that is set in the register mask.
3895ca98fd9SDimitry Andric   for (unsigned Reg = 0, NumRegs = TRI->getNumRegs(); Reg != NumRegs; ++Reg)
390706b4fc4SDimitry Andric     if ((Mask[Reg / 32] >> (Reg % 32)) & 1)
3915ca98fd9SDimitry Andric       LiveOuts.push_back(createLiveOutReg(Reg, TRI));
3925ca98fd9SDimitry Andric 
3935ca98fd9SDimitry Andric   // We don't need to keep track of a register if its super-register is already
3945ca98fd9SDimitry Andric   // in the list. Merge entries that refer to the same dwarf register and use
3955ca98fd9SDimitry Andric   // the maximum size that needs to be spilled.
396ee8648bdSDimitry Andric 
397d8e91e46SDimitry Andric   llvm::sort(LiveOuts, [](const LiveOutReg &LHS, const LiveOutReg &RHS) {
398ee8648bdSDimitry Andric     // Only sort by the dwarf register number.
399ee8648bdSDimitry Andric     return LHS.DwarfRegNum < RHS.DwarfRegNum;
400ee8648bdSDimitry Andric   });
401ee8648bdSDimitry Andric 
402ee8648bdSDimitry Andric   for (auto I = LiveOuts.begin(), E = LiveOuts.end(); I != E; ++I) {
4034b4fe385SDimitry Andric     for (auto *II = std::next(I); II != E; ++II) {
404ee8648bdSDimitry Andric       if (I->DwarfRegNum != II->DwarfRegNum) {
4055ca98fd9SDimitry Andric         // Skip all the now invalid entries.
4065ca98fd9SDimitry Andric         I = --II;
4075ca98fd9SDimitry Andric         break;
4085ca98fd9SDimitry Andric       }
4095ca98fd9SDimitry Andric       I->Size = std::max(I->Size, II->Size);
4107fa27ce4SDimitry Andric       if (I->Reg && TRI->isSuperRegister(I->Reg, II->Reg))
4115ca98fd9SDimitry Andric         I->Reg = II->Reg;
412ee8648bdSDimitry Andric       II->Reg = 0; // mark for deletion.
4135ca98fd9SDimitry Andric     }
4145ca98fd9SDimitry Andric   }
415ee8648bdSDimitry Andric 
416b60736ecSDimitry Andric   llvm::erase_if(LiveOuts, [](const LiveOutReg &LO) { return LO.Reg == 0; });
417ee8648bdSDimitry Andric 
4185ca98fd9SDimitry Andric   return LiveOuts;
4195ca98fd9SDimitry Andric }
4205ca98fd9SDimitry Andric 
421b60736ecSDimitry Andric // See statepoint MI format description in StatepointOpers' class comment
422b60736ecSDimitry Andric // in include/llvm/CodeGen/StackMaps.h
parseStatepointOpers(const MachineInstr & MI,MachineInstr::const_mop_iterator MOI,MachineInstr::const_mop_iterator MOE,LocationVec & Locations,LiveOutVec & LiveOuts)423b60736ecSDimitry Andric void StackMaps::parseStatepointOpers(const MachineInstr &MI,
424b60736ecSDimitry Andric                                      MachineInstr::const_mop_iterator MOI,
425b60736ecSDimitry Andric                                      MachineInstr::const_mop_iterator MOE,
426b60736ecSDimitry Andric                                      LocationVec &Locations,
427b60736ecSDimitry Andric                                      LiveOutVec &LiveOuts) {
428b60736ecSDimitry Andric   LLVM_DEBUG(dbgs() << "record statepoint : " << MI << "\n");
429b60736ecSDimitry Andric   StatepointOpers SO(&MI);
430b60736ecSDimitry Andric   MOI = parseOperand(MOI, MOE, Locations, LiveOuts); // CC
431b60736ecSDimitry Andric   MOI = parseOperand(MOI, MOE, Locations, LiveOuts); // Flags
432b60736ecSDimitry Andric   MOI = parseOperand(MOI, MOE, Locations, LiveOuts); // Num Deopts
433b60736ecSDimitry Andric 
434b60736ecSDimitry Andric   // Record Deopt Args.
435b60736ecSDimitry Andric   unsigned NumDeoptArgs = Locations.back().Offset;
436b60736ecSDimitry Andric   assert(Locations.back().Type == Location::Constant);
437b60736ecSDimitry Andric   assert(NumDeoptArgs == SO.getNumDeoptArgs());
438b60736ecSDimitry Andric 
439b60736ecSDimitry Andric   while (NumDeoptArgs--)
440b60736ecSDimitry Andric     MOI = parseOperand(MOI, MOE, Locations, LiveOuts);
441b60736ecSDimitry Andric 
442b60736ecSDimitry Andric   // Record gc base/derived pairs
443b60736ecSDimitry Andric   assert(MOI->isImm() && MOI->getImm() == StackMaps::ConstantOp);
444b60736ecSDimitry Andric   ++MOI;
445b60736ecSDimitry Andric   assert(MOI->isImm());
446b60736ecSDimitry Andric   unsigned NumGCPointers = MOI->getImm();
447b60736ecSDimitry Andric   ++MOI;
448b60736ecSDimitry Andric   if (NumGCPointers) {
449b60736ecSDimitry Andric     // Map logical index of GC ptr to MI operand index.
450b60736ecSDimitry Andric     SmallVector<unsigned, 8> GCPtrIndices;
451b60736ecSDimitry Andric     unsigned GCPtrIdx = (unsigned)SO.getFirstGCPtrIdx();
452b60736ecSDimitry Andric     assert((int)GCPtrIdx != -1);
453b60736ecSDimitry Andric     assert(MOI - MI.operands_begin() == GCPtrIdx + 0LL);
454b60736ecSDimitry Andric     while (NumGCPointers--) {
455b60736ecSDimitry Andric       GCPtrIndices.push_back(GCPtrIdx);
456b60736ecSDimitry Andric       GCPtrIdx = StackMaps::getNextMetaArgIdx(&MI, GCPtrIdx);
457b60736ecSDimitry Andric     }
458b60736ecSDimitry Andric 
459b60736ecSDimitry Andric     SmallVector<std::pair<unsigned, unsigned>, 8> GCPairs;
460b60736ecSDimitry Andric     unsigned NumGCPairs = SO.getGCPointerMap(GCPairs);
461b60736ecSDimitry Andric     (void)NumGCPairs;
462b60736ecSDimitry Andric     LLVM_DEBUG(dbgs() << "NumGCPairs = " << NumGCPairs << "\n");
463b60736ecSDimitry Andric 
464b60736ecSDimitry Andric     auto MOB = MI.operands_begin();
465b60736ecSDimitry Andric     for (auto &P : GCPairs) {
466b60736ecSDimitry Andric       assert(P.first < GCPtrIndices.size() && "base pointer index not found");
467b60736ecSDimitry Andric       assert(P.second < GCPtrIndices.size() &&
468b60736ecSDimitry Andric              "derived pointer index not found");
469b60736ecSDimitry Andric       unsigned BaseIdx = GCPtrIndices[P.first];
470b60736ecSDimitry Andric       unsigned DerivedIdx = GCPtrIndices[P.second];
471b60736ecSDimitry Andric       LLVM_DEBUG(dbgs() << "Base : " << BaseIdx << " Derived : " << DerivedIdx
472b60736ecSDimitry Andric                         << "\n");
473b60736ecSDimitry Andric       (void)parseOperand(MOB + BaseIdx, MOE, Locations, LiveOuts);
474b60736ecSDimitry Andric       (void)parseOperand(MOB + DerivedIdx, MOE, Locations, LiveOuts);
475b60736ecSDimitry Andric     }
476b60736ecSDimitry Andric 
477b60736ecSDimitry Andric     MOI = MOB + GCPtrIdx;
478b60736ecSDimitry Andric   }
479b60736ecSDimitry Andric 
480b60736ecSDimitry Andric   // Record gc allocas
481b60736ecSDimitry Andric   assert(MOI < MOE);
482b60736ecSDimitry Andric   assert(MOI->isImm() && MOI->getImm() == StackMaps::ConstantOp);
483b60736ecSDimitry Andric   ++MOI;
484b60736ecSDimitry Andric   unsigned NumAllocas = MOI->getImm();
485b60736ecSDimitry Andric   ++MOI;
486b60736ecSDimitry Andric   while (NumAllocas--) {
487b60736ecSDimitry Andric     MOI = parseOperand(MOI, MOE, Locations, LiveOuts);
488b60736ecSDimitry Andric     assert(MOI < MOE);
489b60736ecSDimitry Andric   }
490b60736ecSDimitry Andric }
491b60736ecSDimitry Andric 
recordStackMapOpers(const MCSymbol & MILabel,const MachineInstr & MI,uint64_t ID,MachineInstr::const_mop_iterator MOI,MachineInstr::const_mop_iterator MOE,bool recordResult)492706b4fc4SDimitry Andric void StackMaps::recordStackMapOpers(const MCSymbol &MILabel,
493706b4fc4SDimitry Andric                                     const MachineInstr &MI, uint64_t ID,
494f8af5cf6SDimitry Andric                                     MachineInstr::const_mop_iterator MOI,
495f8af5cf6SDimitry Andric                                     MachineInstr::const_mop_iterator MOE,
496f8af5cf6SDimitry Andric                                     bool recordResult) {
4975a5ac124SDimitry Andric   MCContext &OutContext = AP.OutStreamer->getContext();
498f8af5cf6SDimitry Andric 
4995ca98fd9SDimitry Andric   LocationVec Locations;
5005ca98fd9SDimitry Andric   LiveOutVec LiveOuts;
501f8af5cf6SDimitry Andric 
502f8af5cf6SDimitry Andric   if (recordResult) {
5035ca98fd9SDimitry Andric     assert(PatchPointOpers(&MI).hasDef() && "Stackmap has no return value.");
504ee8648bdSDimitry Andric     parseOperand(MI.operands_begin(), std::next(MI.operands_begin()), Locations,
505ee8648bdSDimitry Andric                  LiveOuts);
506f8af5cf6SDimitry Andric   }
507f8af5cf6SDimitry Andric 
5085ca98fd9SDimitry Andric   // Parse operands.
509b60736ecSDimitry Andric   if (MI.getOpcode() == TargetOpcode::STATEPOINT)
510b60736ecSDimitry Andric     parseStatepointOpers(MI, MOI, MOE, Locations, LiveOuts);
511b60736ecSDimitry Andric   else
512b60736ecSDimitry Andric     while (MOI != MOE)
5135ca98fd9SDimitry Andric       MOI = parseOperand(MOI, MOE, Locations, LiveOuts);
514f8af5cf6SDimitry Andric 
5155ca98fd9SDimitry Andric   // Create an expression to calculate the offset of the callsite from function
5165ca98fd9SDimitry Andric   // entry.
51785d8b2bbSDimitry Andric   const MCExpr *CSOffsetExpr = MCBinaryExpr::createSub(
518706b4fc4SDimitry Andric       MCSymbolRefExpr::create(&MILabel, OutContext),
519ee8648bdSDimitry Andric       MCSymbolRefExpr::create(AP.CurrentFnSymForSize, OutContext), OutContext);
520f8af5cf6SDimitry Andric 
52167c32a98SDimitry Andric   CSInfos.emplace_back(CSOffsetExpr, ID, std::move(Locations),
52267c32a98SDimitry Andric                        std::move(LiveOuts));
523f8af5cf6SDimitry Andric 
524b915e9e0SDimitry Andric   // Record the stack size of the current function and update callsite count.
525b915e9e0SDimitry Andric   const MachineFrameInfo &MFI = AP.MF->getFrameInfo();
52667c32a98SDimitry Andric   const TargetRegisterInfo *RegInfo = AP.MF->getSubtarget().getRegisterInfo();
527ee8648bdSDimitry Andric   bool HasDynamicFrameSize =
528344a3780SDimitry Andric       MFI.hasVarSizedObjects() || RegInfo->hasStackRealignment(*(AP.MF));
529b915e9e0SDimitry Andric   uint64_t FrameSize = HasDynamicFrameSize ? UINT64_MAX : MFI.getStackSize();
530b915e9e0SDimitry Andric 
531b915e9e0SDimitry Andric   auto CurrentIt = FnInfos.find(AP.CurrentFnSym);
532b915e9e0SDimitry Andric   if (CurrentIt != FnInfos.end())
533b915e9e0SDimitry Andric     CurrentIt->second.RecordCount++;
534b915e9e0SDimitry Andric   else
535b915e9e0SDimitry Andric     FnInfos.insert(std::make_pair(AP.CurrentFnSym, FunctionInfo(FrameSize)));
536f8af5cf6SDimitry Andric }
537f8af5cf6SDimitry Andric 
recordStackMap(const MCSymbol & L,const MachineInstr & MI)538706b4fc4SDimitry Andric void StackMaps::recordStackMap(const MCSymbol &L, const MachineInstr &MI) {
5395ca98fd9SDimitry Andric   assert(MI.getOpcode() == TargetOpcode::STACKMAP && "expected stackmap");
540f8af5cf6SDimitry Andric 
541b915e9e0SDimitry Andric   StackMapOpers opers(&MI);
542b915e9e0SDimitry Andric   const int64_t ID = MI.getOperand(PatchPointOpers::IDPos).getImm();
543706b4fc4SDimitry Andric   recordStackMapOpers(L, MI, ID, std::next(MI.operands_begin(),
544706b4fc4SDimitry Andric                                            opers.getVarIdx()),
5455ca98fd9SDimitry Andric                       MI.operands_end());
546f8af5cf6SDimitry Andric }
547f8af5cf6SDimitry Andric 
recordPatchPoint(const MCSymbol & L,const MachineInstr & MI)548706b4fc4SDimitry Andric void StackMaps::recordPatchPoint(const MCSymbol &L, const MachineInstr &MI) {
5495ca98fd9SDimitry Andric   assert(MI.getOpcode() == TargetOpcode::PATCHPOINT && "expected patchpoint");
550f8af5cf6SDimitry Andric 
551f8af5cf6SDimitry Andric   PatchPointOpers opers(&MI);
552b915e9e0SDimitry Andric   const int64_t ID = opers.getID();
553ee8648bdSDimitry Andric   auto MOI = std::next(MI.operands_begin(), opers.getStackMapStartIdx());
554706b4fc4SDimitry Andric   recordStackMapOpers(L, MI, ID, MOI, MI.operands_end(),
555f8af5cf6SDimitry Andric                       opers.isAnyReg() && opers.hasDef());
556f8af5cf6SDimitry Andric 
557f8af5cf6SDimitry Andric #ifndef NDEBUG
558f8af5cf6SDimitry Andric   // verify anyregcc
559ee8648bdSDimitry Andric   auto &Locations = CSInfos.back().Locations;
560f8af5cf6SDimitry Andric   if (opers.isAnyReg()) {
561b915e9e0SDimitry Andric     unsigned NArgs = opers.getNumCallArgs();
562f8af5cf6SDimitry Andric     for (unsigned i = 0, e = (opers.hasDef() ? NArgs + 1 : NArgs); i != e; ++i)
563ee8648bdSDimitry Andric       assert(Locations[i].Type == Location::Register &&
564f8af5cf6SDimitry Andric              "anyreg arg must be in reg.");
565f8af5cf6SDimitry Andric   }
566f8af5cf6SDimitry Andric #endif
567f8af5cf6SDimitry Andric }
56871d5a254SDimitry Andric 
recordStatepoint(const MCSymbol & L,const MachineInstr & MI)569706b4fc4SDimitry Andric void StackMaps::recordStatepoint(const MCSymbol &L, const MachineInstr &MI) {
570ee8648bdSDimitry Andric   assert(MI.getOpcode() == TargetOpcode::STATEPOINT && "expected statepoint");
57167c32a98SDimitry Andric 
57267c32a98SDimitry Andric   StatepointOpers opers(&MI);
57367c32a98SDimitry Andric   const unsigned StartIdx = opers.getVarIdx();
574706b4fc4SDimitry Andric   recordStackMapOpers(L, MI, opers.getID(), MI.operands_begin() + StartIdx,
5755a5ac124SDimitry Andric                       MI.operands_end(), false);
57667c32a98SDimitry Andric }
577f8af5cf6SDimitry Andric 
5785ca98fd9SDimitry Andric /// Emit the stackmap header.
579f8af5cf6SDimitry Andric ///
5805ca98fd9SDimitry Andric /// Header {
581b60736ecSDimitry Andric ///   uint8  : Stack Map Version (currently 3)
5825ca98fd9SDimitry Andric ///   uint8  : Reserved (expected to be 0)
5835ca98fd9SDimitry Andric ///   uint16 : Reserved (expected to be 0)
5845ca98fd9SDimitry Andric /// }
5855ca98fd9SDimitry Andric /// uint32 : NumFunctions
586f8af5cf6SDimitry Andric /// uint32 : NumConstants
587f8af5cf6SDimitry Andric /// uint32 : NumRecords
emitStackmapHeader(MCStreamer & OS)5885ca98fd9SDimitry Andric void StackMaps::emitStackmapHeader(MCStreamer &OS) {
5895ca98fd9SDimitry Andric   // Header.
590cfca06d7SDimitry Andric   OS.emitIntValue(StackMapVersion, 1); // Version.
591cfca06d7SDimitry Andric   OS.emitIntValue(0, 1);               // Reserved.
592cfca06d7SDimitry Andric   OS.emitInt16(0);                     // Reserved.
5935ca98fd9SDimitry Andric 
5945ca98fd9SDimitry Andric   // Num functions.
595eb11fae6SDimitry Andric   LLVM_DEBUG(dbgs() << WSMP << "#functions = " << FnInfos.size() << '\n');
596cfca06d7SDimitry Andric   OS.emitInt32(FnInfos.size());
5975ca98fd9SDimitry Andric   // Num constants.
598eb11fae6SDimitry Andric   LLVM_DEBUG(dbgs() << WSMP << "#constants = " << ConstPool.size() << '\n');
599cfca06d7SDimitry Andric   OS.emitInt32(ConstPool.size());
6005ca98fd9SDimitry Andric   // Num callsites.
601eb11fae6SDimitry Andric   LLVM_DEBUG(dbgs() << WSMP << "#callsites = " << CSInfos.size() << '\n');
602cfca06d7SDimitry Andric   OS.emitInt32(CSInfos.size());
6035ca98fd9SDimitry Andric }
6045ca98fd9SDimitry Andric 
6055ca98fd9SDimitry Andric /// Emit the function frame record for each function.
6065ca98fd9SDimitry Andric ///
6075ca98fd9SDimitry Andric /// StkSizeRecord[NumFunctions] {
6085ca98fd9SDimitry Andric ///   uint64 : Function Address
6095ca98fd9SDimitry Andric ///   uint64 : Stack Size
610b915e9e0SDimitry Andric ///   uint64 : Record Count
6115ca98fd9SDimitry Andric /// }
emitFunctionFrameRecords(MCStreamer & OS)6125ca98fd9SDimitry Andric void StackMaps::emitFunctionFrameRecords(MCStreamer &OS) {
6135ca98fd9SDimitry Andric   // Function Frame records.
614eb11fae6SDimitry Andric   LLVM_DEBUG(dbgs() << WSMP << "functions:\n");
615b915e9e0SDimitry Andric   for (auto const &FR : FnInfos) {
616eb11fae6SDimitry Andric     LLVM_DEBUG(dbgs() << WSMP << "function addr: " << FR.first
617b915e9e0SDimitry Andric                       << " frame size: " << FR.second.StackSize
618b915e9e0SDimitry Andric                       << " callsite count: " << FR.second.RecordCount << '\n');
619cfca06d7SDimitry Andric     OS.emitSymbolValue(FR.first, 8);
620cfca06d7SDimitry Andric     OS.emitIntValue(FR.second.StackSize, 8);
621cfca06d7SDimitry Andric     OS.emitIntValue(FR.second.RecordCount, 8);
6225ca98fd9SDimitry Andric   }
6235ca98fd9SDimitry Andric }
6245ca98fd9SDimitry Andric 
6255ca98fd9SDimitry Andric /// Emit the constant pool.
6265ca98fd9SDimitry Andric ///
6275ca98fd9SDimitry Andric /// int64  : Constants[NumConstants]
emitConstantPoolEntries(MCStreamer & OS)6285ca98fd9SDimitry Andric void StackMaps::emitConstantPoolEntries(MCStreamer &OS) {
6295ca98fd9SDimitry Andric   // Constant pool entries.
630eb11fae6SDimitry Andric   LLVM_DEBUG(dbgs() << WSMP << "constants:\n");
631ee8648bdSDimitry Andric   for (const auto &ConstEntry : ConstPool) {
632eb11fae6SDimitry Andric     LLVM_DEBUG(dbgs() << WSMP << ConstEntry.second << '\n');
633cfca06d7SDimitry Andric     OS.emitIntValue(ConstEntry.second, 8);
6345ca98fd9SDimitry Andric   }
6355ca98fd9SDimitry Andric }
6365ca98fd9SDimitry Andric 
6375ca98fd9SDimitry Andric /// Emit the callsite info for each callsite.
6385ca98fd9SDimitry Andric ///
639f8af5cf6SDimitry Andric /// StkMapRecord[NumRecords] {
6405ca98fd9SDimitry Andric ///   uint64 : PatchPoint ID
641f8af5cf6SDimitry Andric ///   uint32 : Instruction Offset
642f8af5cf6SDimitry Andric ///   uint16 : Reserved (record flags)
643f8af5cf6SDimitry Andric ///   uint16 : NumLocations
644f8af5cf6SDimitry Andric ///   Location[NumLocations] {
645f8af5cf6SDimitry Andric ///     uint8  : Register | Direct | Indirect | Constant | ConstantIndex
646f8af5cf6SDimitry Andric ///     uint8  : Size in Bytes
647f8af5cf6SDimitry Andric ///     uint16 : Dwarf RegNum
648f8af5cf6SDimitry Andric ///     int32  : Offset
649f8af5cf6SDimitry Andric ///   }
6505ca98fd9SDimitry Andric ///   uint16 : Padding
6515ca98fd9SDimitry Andric ///   uint16 : NumLiveOuts
6525ca98fd9SDimitry Andric ///   LiveOuts[NumLiveOuts] {
6535ca98fd9SDimitry Andric ///     uint16 : Dwarf RegNum
6545ca98fd9SDimitry Andric ///     uint8  : Reserved
6555ca98fd9SDimitry Andric ///     uint8  : Size in Bytes
6565ca98fd9SDimitry Andric ///   }
6575ca98fd9SDimitry Andric ///   uint32 : Padding (only if required to align to 8 byte)
658f8af5cf6SDimitry Andric /// }
659f8af5cf6SDimitry Andric ///
660f8af5cf6SDimitry Andric /// Location Encoding, Type, Value:
661f8af5cf6SDimitry Andric ///   0x1, Register, Reg                 (value in register)
662f8af5cf6SDimitry Andric ///   0x2, Direct, Reg + Offset          (frame index)
663f8af5cf6SDimitry Andric ///   0x3, Indirect, [Reg + Offset]      (spilled value)
664f8af5cf6SDimitry Andric ///   0x4, Constant, Offset              (small constant)
665f8af5cf6SDimitry Andric ///   0x5, ConstIndex, Constants[Offset] (large constant)
emitCallsiteEntries(MCStreamer & OS)6665a5ac124SDimitry Andric void StackMaps::emitCallsiteEntries(MCStreamer &OS) {
667eb11fae6SDimitry Andric   LLVM_DEBUG(print(dbgs()));
6685ca98fd9SDimitry Andric   // Callsite entries.
6695ca98fd9SDimitry Andric   for (const auto &CSI : CSInfos) {
6705ca98fd9SDimitry Andric     const LocationVec &CSLocs = CSI.Locations;
6715ca98fd9SDimitry Andric     const LiveOutVec &LiveOuts = CSI.LiveOuts;
672f8af5cf6SDimitry Andric 
673f8af5cf6SDimitry Andric     // Verify stack map entry. It's better to communicate a problem to the
674f8af5cf6SDimitry Andric     // runtime than crash in case of in-process compilation. Currently, we do
675f8af5cf6SDimitry Andric     // simple overflow checks, but we may eventually communicate other
676f8af5cf6SDimitry Andric     // compilation errors this way.
6775ca98fd9SDimitry Andric     if (CSLocs.size() > UINT16_MAX || LiveOuts.size() > UINT16_MAX) {
678cfca06d7SDimitry Andric       OS.emitIntValue(UINT64_MAX, 8); // Invalid ID.
679cfca06d7SDimitry Andric       OS.emitValue(CSI.CSOffsetExpr, 4);
680cfca06d7SDimitry Andric       OS.emitInt16(0); // Reserved.
681cfca06d7SDimitry Andric       OS.emitInt16(0); // 0 locations.
682cfca06d7SDimitry Andric       OS.emitInt16(0); // padding.
683cfca06d7SDimitry Andric       OS.emitInt16(0); // 0 live-out registers.
684cfca06d7SDimitry Andric       OS.emitInt32(0); // padding.
685f8af5cf6SDimitry Andric       continue;
686f8af5cf6SDimitry Andric     }
687f8af5cf6SDimitry Andric 
688cfca06d7SDimitry Andric     OS.emitIntValue(CSI.ID, 8);
689cfca06d7SDimitry Andric     OS.emitValue(CSI.CSOffsetExpr, 4);
690f8af5cf6SDimitry Andric 
691f8af5cf6SDimitry Andric     // Reserved for flags.
692cfca06d7SDimitry Andric     OS.emitInt16(0);
693cfca06d7SDimitry Andric     OS.emitInt16(CSLocs.size());
694f8af5cf6SDimitry Andric 
6955ca98fd9SDimitry Andric     for (const auto &Loc : CSLocs) {
696cfca06d7SDimitry Andric       OS.emitIntValue(Loc.Type, 1);
697cfca06d7SDimitry Andric       OS.emitIntValue(0, 1);  // Reserved
698cfca06d7SDimitry Andric       OS.emitInt16(Loc.Size);
699cfca06d7SDimitry Andric       OS.emitInt16(Loc.Reg);
700cfca06d7SDimitry Andric       OS.emitInt16(0); // Reserved
701cfca06d7SDimitry Andric       OS.emitInt32(Loc.Offset);
702f8af5cf6SDimitry Andric     }
7035ca98fd9SDimitry Andric 
704a303c417SDimitry Andric     // Emit alignment to 8 byte.
705e3b55780SDimitry Andric     OS.emitValueToAlignment(Align(8));
706a303c417SDimitry Andric 
7075ca98fd9SDimitry Andric     // Num live-out registers and padding to align to 4 byte.
708cfca06d7SDimitry Andric     OS.emitInt16(0);
709cfca06d7SDimitry Andric     OS.emitInt16(LiveOuts.size());
7105ca98fd9SDimitry Andric 
7115ca98fd9SDimitry Andric     for (const auto &LO : LiveOuts) {
712cfca06d7SDimitry Andric       OS.emitInt16(LO.DwarfRegNum);
713cfca06d7SDimitry Andric       OS.emitIntValue(0, 1);
714cfca06d7SDimitry Andric       OS.emitIntValue(LO.Size, 1);
715f8af5cf6SDimitry Andric     }
7165ca98fd9SDimitry Andric     // Emit alignment to 8 byte.
717e3b55780SDimitry Andric     OS.emitValueToAlignment(Align(8));
718f8af5cf6SDimitry Andric   }
719f8af5cf6SDimitry Andric }
720f8af5cf6SDimitry Andric 
7215ca98fd9SDimitry Andric /// Serialize the stackmap data.
serializeToStackMapSection()7225ca98fd9SDimitry Andric void StackMaps::serializeToStackMapSection() {
7235ca98fd9SDimitry Andric   (void)WSMP;
7245ca98fd9SDimitry Andric   // Bail out if there's no stack map data.
72501095a5dSDimitry Andric   assert((!CSInfos.empty() || ConstPool.empty()) &&
7265ca98fd9SDimitry Andric          "Expected empty constant pool too!");
727b915e9e0SDimitry Andric   assert((!CSInfos.empty() || FnInfos.empty()) &&
7285ca98fd9SDimitry Andric          "Expected empty function record too!");
7295ca98fd9SDimitry Andric   if (CSInfos.empty())
7305ca98fd9SDimitry Andric     return;
731f8af5cf6SDimitry Andric 
7325a5ac124SDimitry Andric   MCContext &OutContext = AP.OutStreamer->getContext();
7335a5ac124SDimitry Andric   MCStreamer &OS = *AP.OutStreamer;
7345ca98fd9SDimitry Andric 
7355ca98fd9SDimitry Andric   // Create the section.
7365a5ac124SDimitry Andric   MCSection *StackMapSection =
7375ca98fd9SDimitry Andric       OutContext.getObjectFileInfo()->getStackMapSection();
738145449b1SDimitry Andric   OS.switchSection(StackMapSection);
7395ca98fd9SDimitry Andric 
7405ca98fd9SDimitry Andric   // Emit a dummy symbol to force section inclusion.
741cfca06d7SDimitry Andric   OS.emitLabel(OutContext.getOrCreateSymbol(Twine("__LLVM_StackMaps")));
7425ca98fd9SDimitry Andric 
7435ca98fd9SDimitry Andric   // Serialize data.
744eb11fae6SDimitry Andric   LLVM_DEBUG(dbgs() << "********** Stack Map Output **********\n");
7455ca98fd9SDimitry Andric   emitStackmapHeader(OS);
7465ca98fd9SDimitry Andric   emitFunctionFrameRecords(OS);
7475ca98fd9SDimitry Andric   emitConstantPoolEntries(OS);
7485a5ac124SDimitry Andric   emitCallsiteEntries(OS);
749145449b1SDimitry Andric   OS.addBlankLine();
7505ca98fd9SDimitry Andric 
7515ca98fd9SDimitry Andric   // Clean up.
752f8af5cf6SDimitry Andric   CSInfos.clear();
7535ca98fd9SDimitry Andric   ConstPool.clear();
754f8af5cf6SDimitry Andric }
755