xref: /freebsd/contrib/llvm-project/llvm/lib/CodeGen/StackMaps.cpp (revision 0b57cec536236d46e3dba9bd041533462f33dbb7)
1*0b57cec5SDimitry Andric //===- StackMaps.cpp ------------------------------------------------------===//
2*0b57cec5SDimitry Andric //
3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0b57cec5SDimitry Andric //
7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
8*0b57cec5SDimitry Andric 
9*0b57cec5SDimitry Andric #include "llvm/CodeGen/StackMaps.h"
10*0b57cec5SDimitry Andric #include "llvm/ADT/DenseMapInfo.h"
11*0b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h"
12*0b57cec5SDimitry Andric #include "llvm/ADT/Twine.h"
13*0b57cec5SDimitry Andric #include "llvm/CodeGen/AsmPrinter.h"
14*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFrameInfo.h"
15*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunction.h"
16*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstr.h"
17*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineOperand.h"
18*0b57cec5SDimitry Andric #include "llvm/CodeGen/TargetOpcodes.h"
19*0b57cec5SDimitry Andric #include "llvm/CodeGen/TargetRegisterInfo.h"
20*0b57cec5SDimitry Andric #include "llvm/CodeGen/TargetSubtargetInfo.h"
21*0b57cec5SDimitry Andric #include "llvm/IR/DataLayout.h"
22*0b57cec5SDimitry Andric #include "llvm/MC/MCContext.h"
23*0b57cec5SDimitry Andric #include "llvm/MC/MCExpr.h"
24*0b57cec5SDimitry Andric #include "llvm/MC/MCObjectFileInfo.h"
25*0b57cec5SDimitry Andric #include "llvm/MC/MCRegisterInfo.h"
26*0b57cec5SDimitry Andric #include "llvm/MC/MCStreamer.h"
27*0b57cec5SDimitry Andric #include "llvm/Support/CommandLine.h"
28*0b57cec5SDimitry Andric #include "llvm/Support/Debug.h"
29*0b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h"
30*0b57cec5SDimitry Andric #include "llvm/Support/MathExtras.h"
31*0b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
32*0b57cec5SDimitry Andric #include <algorithm>
33*0b57cec5SDimitry Andric #include <cassert>
34*0b57cec5SDimitry Andric #include <cstdint>
35*0b57cec5SDimitry Andric #include <iterator>
36*0b57cec5SDimitry Andric #include <utility>
37*0b57cec5SDimitry Andric 
38*0b57cec5SDimitry Andric using namespace llvm;
39*0b57cec5SDimitry Andric 
40*0b57cec5SDimitry Andric #define DEBUG_TYPE "stackmaps"
41*0b57cec5SDimitry Andric 
42*0b57cec5SDimitry Andric static cl::opt<int> StackMapVersion(
43*0b57cec5SDimitry Andric     "stackmap-version", cl::init(3), cl::Hidden,
44*0b57cec5SDimitry Andric     cl::desc("Specify the stackmap encoding version (default = 3)"));
45*0b57cec5SDimitry Andric 
46*0b57cec5SDimitry Andric const char *StackMaps::WSMP = "Stack Maps: ";
47*0b57cec5SDimitry Andric 
48*0b57cec5SDimitry Andric StackMapOpers::StackMapOpers(const MachineInstr *MI)
49*0b57cec5SDimitry Andric   : MI(MI) {
50*0b57cec5SDimitry Andric   assert(getVarIdx() <= MI->getNumOperands() &&
51*0b57cec5SDimitry Andric          "invalid stackmap definition");
52*0b57cec5SDimitry Andric }
53*0b57cec5SDimitry Andric 
54*0b57cec5SDimitry Andric PatchPointOpers::PatchPointOpers(const MachineInstr *MI)
55*0b57cec5SDimitry Andric     : MI(MI), HasDef(MI->getOperand(0).isReg() && MI->getOperand(0).isDef() &&
56*0b57cec5SDimitry Andric                      !MI->getOperand(0).isImplicit()) {
57*0b57cec5SDimitry Andric #ifndef NDEBUG
58*0b57cec5SDimitry Andric   unsigned CheckStartIdx = 0, e = MI->getNumOperands();
59*0b57cec5SDimitry Andric   while (CheckStartIdx < e && MI->getOperand(CheckStartIdx).isReg() &&
60*0b57cec5SDimitry Andric          MI->getOperand(CheckStartIdx).isDef() &&
61*0b57cec5SDimitry Andric          !MI->getOperand(CheckStartIdx).isImplicit())
62*0b57cec5SDimitry Andric     ++CheckStartIdx;
63*0b57cec5SDimitry Andric 
64*0b57cec5SDimitry Andric   assert(getMetaIdx() == CheckStartIdx &&
65*0b57cec5SDimitry Andric          "Unexpected additional definition in Patchpoint intrinsic.");
66*0b57cec5SDimitry Andric #endif
67*0b57cec5SDimitry Andric }
68*0b57cec5SDimitry Andric 
69*0b57cec5SDimitry Andric unsigned PatchPointOpers::getNextScratchIdx(unsigned StartIdx) const {
70*0b57cec5SDimitry Andric   if (!StartIdx)
71*0b57cec5SDimitry Andric     StartIdx = getVarIdx();
72*0b57cec5SDimitry Andric 
73*0b57cec5SDimitry Andric   // Find the next scratch register (implicit def and early clobber)
74*0b57cec5SDimitry Andric   unsigned ScratchIdx = StartIdx, e = MI->getNumOperands();
75*0b57cec5SDimitry Andric   while (ScratchIdx < e &&
76*0b57cec5SDimitry Andric          !(MI->getOperand(ScratchIdx).isReg() &&
77*0b57cec5SDimitry Andric            MI->getOperand(ScratchIdx).isDef() &&
78*0b57cec5SDimitry Andric            MI->getOperand(ScratchIdx).isImplicit() &&
79*0b57cec5SDimitry Andric            MI->getOperand(ScratchIdx).isEarlyClobber()))
80*0b57cec5SDimitry Andric     ++ScratchIdx;
81*0b57cec5SDimitry Andric 
82*0b57cec5SDimitry Andric   assert(ScratchIdx != e && "No scratch register available");
83*0b57cec5SDimitry Andric   return ScratchIdx;
84*0b57cec5SDimitry Andric }
85*0b57cec5SDimitry Andric 
86*0b57cec5SDimitry Andric StackMaps::StackMaps(AsmPrinter &AP) : AP(AP) {
87*0b57cec5SDimitry Andric   if (StackMapVersion != 3)
88*0b57cec5SDimitry Andric     llvm_unreachable("Unsupported stackmap version!");
89*0b57cec5SDimitry Andric }
90*0b57cec5SDimitry Andric 
91*0b57cec5SDimitry Andric /// Go up the super-register chain until we hit a valid dwarf register number.
92*0b57cec5SDimitry Andric static unsigned getDwarfRegNum(unsigned Reg, const TargetRegisterInfo *TRI) {
93*0b57cec5SDimitry Andric   int RegNum = TRI->getDwarfRegNum(Reg, false);
94*0b57cec5SDimitry Andric   for (MCSuperRegIterator SR(Reg, TRI); SR.isValid() && RegNum < 0; ++SR)
95*0b57cec5SDimitry Andric     RegNum = TRI->getDwarfRegNum(*SR, false);
96*0b57cec5SDimitry Andric 
97*0b57cec5SDimitry Andric   assert(RegNum >= 0 && "Invalid Dwarf register number.");
98*0b57cec5SDimitry Andric   return (unsigned)RegNum;
99*0b57cec5SDimitry Andric }
100*0b57cec5SDimitry Andric 
101*0b57cec5SDimitry Andric MachineInstr::const_mop_iterator
102*0b57cec5SDimitry Andric StackMaps::parseOperand(MachineInstr::const_mop_iterator MOI,
103*0b57cec5SDimitry Andric                         MachineInstr::const_mop_iterator MOE, LocationVec &Locs,
104*0b57cec5SDimitry Andric                         LiveOutVec &LiveOuts) const {
105*0b57cec5SDimitry Andric   const TargetRegisterInfo *TRI = AP.MF->getSubtarget().getRegisterInfo();
106*0b57cec5SDimitry Andric   if (MOI->isImm()) {
107*0b57cec5SDimitry Andric     switch (MOI->getImm()) {
108*0b57cec5SDimitry Andric     default:
109*0b57cec5SDimitry Andric       llvm_unreachable("Unrecognized operand type.");
110*0b57cec5SDimitry Andric     case StackMaps::DirectMemRefOp: {
111*0b57cec5SDimitry Andric       auto &DL = AP.MF->getDataLayout();
112*0b57cec5SDimitry Andric 
113*0b57cec5SDimitry Andric       unsigned Size = DL.getPointerSizeInBits();
114*0b57cec5SDimitry Andric       assert((Size % 8) == 0 && "Need pointer size in bytes.");
115*0b57cec5SDimitry Andric       Size /= 8;
116*0b57cec5SDimitry Andric       unsigned Reg = (++MOI)->getReg();
117*0b57cec5SDimitry Andric       int64_t Imm = (++MOI)->getImm();
118*0b57cec5SDimitry Andric       Locs.emplace_back(StackMaps::Location::Direct, Size,
119*0b57cec5SDimitry Andric                         getDwarfRegNum(Reg, TRI), Imm);
120*0b57cec5SDimitry Andric       break;
121*0b57cec5SDimitry Andric     }
122*0b57cec5SDimitry Andric     case StackMaps::IndirectMemRefOp: {
123*0b57cec5SDimitry Andric       int64_t Size = (++MOI)->getImm();
124*0b57cec5SDimitry Andric       assert(Size > 0 && "Need a valid size for indirect memory locations.");
125*0b57cec5SDimitry Andric       unsigned Reg = (++MOI)->getReg();
126*0b57cec5SDimitry Andric       int64_t Imm = (++MOI)->getImm();
127*0b57cec5SDimitry Andric       Locs.emplace_back(StackMaps::Location::Indirect, Size,
128*0b57cec5SDimitry Andric                         getDwarfRegNum(Reg, TRI), Imm);
129*0b57cec5SDimitry Andric       break;
130*0b57cec5SDimitry Andric     }
131*0b57cec5SDimitry Andric     case StackMaps::ConstantOp: {
132*0b57cec5SDimitry Andric       ++MOI;
133*0b57cec5SDimitry Andric       assert(MOI->isImm() && "Expected constant operand.");
134*0b57cec5SDimitry Andric       int64_t Imm = MOI->getImm();
135*0b57cec5SDimitry Andric       Locs.emplace_back(Location::Constant, sizeof(int64_t), 0, Imm);
136*0b57cec5SDimitry Andric       break;
137*0b57cec5SDimitry Andric     }
138*0b57cec5SDimitry Andric     }
139*0b57cec5SDimitry Andric     return ++MOI;
140*0b57cec5SDimitry Andric   }
141*0b57cec5SDimitry Andric 
142*0b57cec5SDimitry Andric   // The physical register number will ultimately be encoded as a DWARF regno.
143*0b57cec5SDimitry Andric   // The stack map also records the size of a spill slot that can hold the
144*0b57cec5SDimitry Andric   // register content. (The runtime can track the actual size of the data type
145*0b57cec5SDimitry Andric   // if it needs to.)
146*0b57cec5SDimitry Andric   if (MOI->isReg()) {
147*0b57cec5SDimitry Andric     // Skip implicit registers (this includes our scratch registers)
148*0b57cec5SDimitry Andric     if (MOI->isImplicit())
149*0b57cec5SDimitry Andric       return ++MOI;
150*0b57cec5SDimitry Andric 
151*0b57cec5SDimitry Andric     assert(TargetRegisterInfo::isPhysicalRegister(MOI->getReg()) &&
152*0b57cec5SDimitry Andric            "Virtreg operands should have been rewritten before now.");
153*0b57cec5SDimitry Andric     const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(MOI->getReg());
154*0b57cec5SDimitry Andric     assert(!MOI->getSubReg() && "Physical subreg still around.");
155*0b57cec5SDimitry Andric 
156*0b57cec5SDimitry Andric     unsigned Offset = 0;
157*0b57cec5SDimitry Andric     unsigned DwarfRegNum = getDwarfRegNum(MOI->getReg(), TRI);
158*0b57cec5SDimitry Andric     unsigned LLVMRegNum = TRI->getLLVMRegNum(DwarfRegNum, false);
159*0b57cec5SDimitry Andric     unsigned SubRegIdx = TRI->getSubRegIndex(LLVMRegNum, MOI->getReg());
160*0b57cec5SDimitry Andric     if (SubRegIdx)
161*0b57cec5SDimitry Andric       Offset = TRI->getSubRegIdxOffset(SubRegIdx);
162*0b57cec5SDimitry Andric 
163*0b57cec5SDimitry Andric     Locs.emplace_back(Location::Register, TRI->getSpillSize(*RC),
164*0b57cec5SDimitry Andric                       DwarfRegNum, Offset);
165*0b57cec5SDimitry Andric     return ++MOI;
166*0b57cec5SDimitry Andric   }
167*0b57cec5SDimitry Andric 
168*0b57cec5SDimitry Andric   if (MOI->isRegLiveOut())
169*0b57cec5SDimitry Andric     LiveOuts = parseRegisterLiveOutMask(MOI->getRegLiveOut());
170*0b57cec5SDimitry Andric 
171*0b57cec5SDimitry Andric   return ++MOI;
172*0b57cec5SDimitry Andric }
173*0b57cec5SDimitry Andric 
174*0b57cec5SDimitry Andric void StackMaps::print(raw_ostream &OS) {
175*0b57cec5SDimitry Andric   const TargetRegisterInfo *TRI =
176*0b57cec5SDimitry Andric       AP.MF ? AP.MF->getSubtarget().getRegisterInfo() : nullptr;
177*0b57cec5SDimitry Andric   OS << WSMP << "callsites:\n";
178*0b57cec5SDimitry Andric   for (const auto &CSI : CSInfos) {
179*0b57cec5SDimitry Andric     const LocationVec &CSLocs = CSI.Locations;
180*0b57cec5SDimitry Andric     const LiveOutVec &LiveOuts = CSI.LiveOuts;
181*0b57cec5SDimitry Andric 
182*0b57cec5SDimitry Andric     OS << WSMP << "callsite " << CSI.ID << "\n";
183*0b57cec5SDimitry Andric     OS << WSMP << "  has " << CSLocs.size() << " locations\n";
184*0b57cec5SDimitry Andric 
185*0b57cec5SDimitry Andric     unsigned Idx = 0;
186*0b57cec5SDimitry Andric     for (const auto &Loc : CSLocs) {
187*0b57cec5SDimitry Andric       OS << WSMP << "\t\tLoc " << Idx << ": ";
188*0b57cec5SDimitry Andric       switch (Loc.Type) {
189*0b57cec5SDimitry Andric       case Location::Unprocessed:
190*0b57cec5SDimitry Andric         OS << "<Unprocessed operand>";
191*0b57cec5SDimitry Andric         break;
192*0b57cec5SDimitry Andric       case Location::Register:
193*0b57cec5SDimitry Andric         OS << "Register ";
194*0b57cec5SDimitry Andric         if (TRI)
195*0b57cec5SDimitry Andric           OS << printReg(Loc.Reg, TRI);
196*0b57cec5SDimitry Andric         else
197*0b57cec5SDimitry Andric           OS << Loc.Reg;
198*0b57cec5SDimitry Andric         break;
199*0b57cec5SDimitry Andric       case Location::Direct:
200*0b57cec5SDimitry Andric         OS << "Direct ";
201*0b57cec5SDimitry Andric         if (TRI)
202*0b57cec5SDimitry Andric           OS << printReg(Loc.Reg, TRI);
203*0b57cec5SDimitry Andric         else
204*0b57cec5SDimitry Andric           OS << Loc.Reg;
205*0b57cec5SDimitry Andric         if (Loc.Offset)
206*0b57cec5SDimitry Andric           OS << " + " << Loc.Offset;
207*0b57cec5SDimitry Andric         break;
208*0b57cec5SDimitry Andric       case Location::Indirect:
209*0b57cec5SDimitry Andric         OS << "Indirect ";
210*0b57cec5SDimitry Andric         if (TRI)
211*0b57cec5SDimitry Andric           OS << printReg(Loc.Reg, TRI);
212*0b57cec5SDimitry Andric         else
213*0b57cec5SDimitry Andric           OS << Loc.Reg;
214*0b57cec5SDimitry Andric         OS << "+" << Loc.Offset;
215*0b57cec5SDimitry Andric         break;
216*0b57cec5SDimitry Andric       case Location::Constant:
217*0b57cec5SDimitry Andric         OS << "Constant " << Loc.Offset;
218*0b57cec5SDimitry Andric         break;
219*0b57cec5SDimitry Andric       case Location::ConstantIndex:
220*0b57cec5SDimitry Andric         OS << "Constant Index " << Loc.Offset;
221*0b57cec5SDimitry Andric         break;
222*0b57cec5SDimitry Andric       }
223*0b57cec5SDimitry Andric       OS << "\t[encoding: .byte " << Loc.Type << ", .byte 0"
224*0b57cec5SDimitry Andric          << ", .short " << Loc.Size << ", .short " << Loc.Reg << ", .short 0"
225*0b57cec5SDimitry Andric          << ", .int " << Loc.Offset << "]\n";
226*0b57cec5SDimitry Andric       Idx++;
227*0b57cec5SDimitry Andric     }
228*0b57cec5SDimitry Andric 
229*0b57cec5SDimitry Andric     OS << WSMP << "\thas " << LiveOuts.size() << " live-out registers\n";
230*0b57cec5SDimitry Andric 
231*0b57cec5SDimitry Andric     Idx = 0;
232*0b57cec5SDimitry Andric     for (const auto &LO : LiveOuts) {
233*0b57cec5SDimitry Andric       OS << WSMP << "\t\tLO " << Idx << ": ";
234*0b57cec5SDimitry Andric       if (TRI)
235*0b57cec5SDimitry Andric         OS << printReg(LO.Reg, TRI);
236*0b57cec5SDimitry Andric       else
237*0b57cec5SDimitry Andric         OS << LO.Reg;
238*0b57cec5SDimitry Andric       OS << "\t[encoding: .short " << LO.DwarfRegNum << ", .byte 0, .byte "
239*0b57cec5SDimitry Andric          << LO.Size << "]\n";
240*0b57cec5SDimitry Andric       Idx++;
241*0b57cec5SDimitry Andric     }
242*0b57cec5SDimitry Andric   }
243*0b57cec5SDimitry Andric }
244*0b57cec5SDimitry Andric 
245*0b57cec5SDimitry Andric /// Create a live-out register record for the given register Reg.
246*0b57cec5SDimitry Andric StackMaps::LiveOutReg
247*0b57cec5SDimitry Andric StackMaps::createLiveOutReg(unsigned Reg, const TargetRegisterInfo *TRI) const {
248*0b57cec5SDimitry Andric   unsigned DwarfRegNum = getDwarfRegNum(Reg, TRI);
249*0b57cec5SDimitry Andric   unsigned Size = TRI->getSpillSize(*TRI->getMinimalPhysRegClass(Reg));
250*0b57cec5SDimitry Andric   return LiveOutReg(Reg, DwarfRegNum, Size);
251*0b57cec5SDimitry Andric }
252*0b57cec5SDimitry Andric 
253*0b57cec5SDimitry Andric /// Parse the register live-out mask and return a vector of live-out registers
254*0b57cec5SDimitry Andric /// that need to be recorded in the stackmap.
255*0b57cec5SDimitry Andric StackMaps::LiveOutVec
256*0b57cec5SDimitry Andric StackMaps::parseRegisterLiveOutMask(const uint32_t *Mask) const {
257*0b57cec5SDimitry Andric   assert(Mask && "No register mask specified");
258*0b57cec5SDimitry Andric   const TargetRegisterInfo *TRI = AP.MF->getSubtarget().getRegisterInfo();
259*0b57cec5SDimitry Andric   LiveOutVec LiveOuts;
260*0b57cec5SDimitry Andric 
261*0b57cec5SDimitry Andric   // Create a LiveOutReg for each bit that is set in the register mask.
262*0b57cec5SDimitry Andric   for (unsigned Reg = 0, NumRegs = TRI->getNumRegs(); Reg != NumRegs; ++Reg)
263*0b57cec5SDimitry Andric     if ((Mask[Reg / 32] >> Reg % 32) & 1)
264*0b57cec5SDimitry Andric       LiveOuts.push_back(createLiveOutReg(Reg, TRI));
265*0b57cec5SDimitry Andric 
266*0b57cec5SDimitry Andric   // We don't need to keep track of a register if its super-register is already
267*0b57cec5SDimitry Andric   // in the list. Merge entries that refer to the same dwarf register and use
268*0b57cec5SDimitry Andric   // the maximum size that needs to be spilled.
269*0b57cec5SDimitry Andric 
270*0b57cec5SDimitry Andric   llvm::sort(LiveOuts, [](const LiveOutReg &LHS, const LiveOutReg &RHS) {
271*0b57cec5SDimitry Andric     // Only sort by the dwarf register number.
272*0b57cec5SDimitry Andric     return LHS.DwarfRegNum < RHS.DwarfRegNum;
273*0b57cec5SDimitry Andric   });
274*0b57cec5SDimitry Andric 
275*0b57cec5SDimitry Andric   for (auto I = LiveOuts.begin(), E = LiveOuts.end(); I != E; ++I) {
276*0b57cec5SDimitry Andric     for (auto II = std::next(I); II != E; ++II) {
277*0b57cec5SDimitry Andric       if (I->DwarfRegNum != II->DwarfRegNum) {
278*0b57cec5SDimitry Andric         // Skip all the now invalid entries.
279*0b57cec5SDimitry Andric         I = --II;
280*0b57cec5SDimitry Andric         break;
281*0b57cec5SDimitry Andric       }
282*0b57cec5SDimitry Andric       I->Size = std::max(I->Size, II->Size);
283*0b57cec5SDimitry Andric       if (TRI->isSuperRegister(I->Reg, II->Reg))
284*0b57cec5SDimitry Andric         I->Reg = II->Reg;
285*0b57cec5SDimitry Andric       II->Reg = 0; // mark for deletion.
286*0b57cec5SDimitry Andric     }
287*0b57cec5SDimitry Andric   }
288*0b57cec5SDimitry Andric 
289*0b57cec5SDimitry Andric   LiveOuts.erase(
290*0b57cec5SDimitry Andric       llvm::remove_if(LiveOuts,
291*0b57cec5SDimitry Andric                       [](const LiveOutReg &LO) { return LO.Reg == 0; }),
292*0b57cec5SDimitry Andric       LiveOuts.end());
293*0b57cec5SDimitry Andric 
294*0b57cec5SDimitry Andric   return LiveOuts;
295*0b57cec5SDimitry Andric }
296*0b57cec5SDimitry Andric 
297*0b57cec5SDimitry Andric void StackMaps::recordStackMapOpers(const MachineInstr &MI, uint64_t ID,
298*0b57cec5SDimitry Andric                                     MachineInstr::const_mop_iterator MOI,
299*0b57cec5SDimitry Andric                                     MachineInstr::const_mop_iterator MOE,
300*0b57cec5SDimitry Andric                                     bool recordResult) {
301*0b57cec5SDimitry Andric   MCContext &OutContext = AP.OutStreamer->getContext();
302*0b57cec5SDimitry Andric   MCSymbol *MILabel = OutContext.createTempSymbol();
303*0b57cec5SDimitry Andric   AP.OutStreamer->EmitLabel(MILabel);
304*0b57cec5SDimitry Andric 
305*0b57cec5SDimitry Andric   LocationVec Locations;
306*0b57cec5SDimitry Andric   LiveOutVec LiveOuts;
307*0b57cec5SDimitry Andric 
308*0b57cec5SDimitry Andric   if (recordResult) {
309*0b57cec5SDimitry Andric     assert(PatchPointOpers(&MI).hasDef() && "Stackmap has no return value.");
310*0b57cec5SDimitry Andric     parseOperand(MI.operands_begin(), std::next(MI.operands_begin()), Locations,
311*0b57cec5SDimitry Andric                  LiveOuts);
312*0b57cec5SDimitry Andric   }
313*0b57cec5SDimitry Andric 
314*0b57cec5SDimitry Andric   // Parse operands.
315*0b57cec5SDimitry Andric   while (MOI != MOE) {
316*0b57cec5SDimitry Andric     MOI = parseOperand(MOI, MOE, Locations, LiveOuts);
317*0b57cec5SDimitry Andric   }
318*0b57cec5SDimitry Andric 
319*0b57cec5SDimitry Andric   // Move large constants into the constant pool.
320*0b57cec5SDimitry Andric   for (auto &Loc : Locations) {
321*0b57cec5SDimitry Andric     // Constants are encoded as sign-extended integers.
322*0b57cec5SDimitry Andric     // -1 is directly encoded as .long 0xFFFFFFFF with no constant pool.
323*0b57cec5SDimitry Andric     if (Loc.Type == Location::Constant && !isInt<32>(Loc.Offset)) {
324*0b57cec5SDimitry Andric       Loc.Type = Location::ConstantIndex;
325*0b57cec5SDimitry Andric       // ConstPool is intentionally a MapVector of 'uint64_t's (as
326*0b57cec5SDimitry Andric       // opposed to 'int64_t's).  We should never be in a situation
327*0b57cec5SDimitry Andric       // where we have to insert either the tombstone or the empty
328*0b57cec5SDimitry Andric       // keys into a map, and for a DenseMap<uint64_t, T> these are
329*0b57cec5SDimitry Andric       // (uint64_t)0 and (uint64_t)-1.  They can be and are
330*0b57cec5SDimitry Andric       // represented using 32 bit integers.
331*0b57cec5SDimitry Andric       assert((uint64_t)Loc.Offset != DenseMapInfo<uint64_t>::getEmptyKey() &&
332*0b57cec5SDimitry Andric              (uint64_t)Loc.Offset !=
333*0b57cec5SDimitry Andric                  DenseMapInfo<uint64_t>::getTombstoneKey() &&
334*0b57cec5SDimitry Andric              "empty and tombstone keys should fit in 32 bits!");
335*0b57cec5SDimitry Andric       auto Result = ConstPool.insert(std::make_pair(Loc.Offset, Loc.Offset));
336*0b57cec5SDimitry Andric       Loc.Offset = Result.first - ConstPool.begin();
337*0b57cec5SDimitry Andric     }
338*0b57cec5SDimitry Andric   }
339*0b57cec5SDimitry Andric 
340*0b57cec5SDimitry Andric   // Create an expression to calculate the offset of the callsite from function
341*0b57cec5SDimitry Andric   // entry.
342*0b57cec5SDimitry Andric   const MCExpr *CSOffsetExpr = MCBinaryExpr::createSub(
343*0b57cec5SDimitry Andric       MCSymbolRefExpr::create(MILabel, OutContext),
344*0b57cec5SDimitry Andric       MCSymbolRefExpr::create(AP.CurrentFnSymForSize, OutContext), OutContext);
345*0b57cec5SDimitry Andric 
346*0b57cec5SDimitry Andric   CSInfos.emplace_back(CSOffsetExpr, ID, std::move(Locations),
347*0b57cec5SDimitry Andric                        std::move(LiveOuts));
348*0b57cec5SDimitry Andric 
349*0b57cec5SDimitry Andric   // Record the stack size of the current function and update callsite count.
350*0b57cec5SDimitry Andric   const MachineFrameInfo &MFI = AP.MF->getFrameInfo();
351*0b57cec5SDimitry Andric   const TargetRegisterInfo *RegInfo = AP.MF->getSubtarget().getRegisterInfo();
352*0b57cec5SDimitry Andric   bool HasDynamicFrameSize =
353*0b57cec5SDimitry Andric       MFI.hasVarSizedObjects() || RegInfo->needsStackRealignment(*(AP.MF));
354*0b57cec5SDimitry Andric   uint64_t FrameSize = HasDynamicFrameSize ? UINT64_MAX : MFI.getStackSize();
355*0b57cec5SDimitry Andric 
356*0b57cec5SDimitry Andric   auto CurrentIt = FnInfos.find(AP.CurrentFnSym);
357*0b57cec5SDimitry Andric   if (CurrentIt != FnInfos.end())
358*0b57cec5SDimitry Andric     CurrentIt->second.RecordCount++;
359*0b57cec5SDimitry Andric   else
360*0b57cec5SDimitry Andric     FnInfos.insert(std::make_pair(AP.CurrentFnSym, FunctionInfo(FrameSize)));
361*0b57cec5SDimitry Andric }
362*0b57cec5SDimitry Andric 
363*0b57cec5SDimitry Andric void StackMaps::recordStackMap(const MachineInstr &MI) {
364*0b57cec5SDimitry Andric   assert(MI.getOpcode() == TargetOpcode::STACKMAP && "expected stackmap");
365*0b57cec5SDimitry Andric 
366*0b57cec5SDimitry Andric   StackMapOpers opers(&MI);
367*0b57cec5SDimitry Andric   const int64_t ID = MI.getOperand(PatchPointOpers::IDPos).getImm();
368*0b57cec5SDimitry Andric   recordStackMapOpers(MI, ID, std::next(MI.operands_begin(), opers.getVarIdx()),
369*0b57cec5SDimitry Andric                       MI.operands_end());
370*0b57cec5SDimitry Andric }
371*0b57cec5SDimitry Andric 
372*0b57cec5SDimitry Andric void StackMaps::recordPatchPoint(const MachineInstr &MI) {
373*0b57cec5SDimitry Andric   assert(MI.getOpcode() == TargetOpcode::PATCHPOINT && "expected patchpoint");
374*0b57cec5SDimitry Andric 
375*0b57cec5SDimitry Andric   PatchPointOpers opers(&MI);
376*0b57cec5SDimitry Andric   const int64_t ID = opers.getID();
377*0b57cec5SDimitry Andric   auto MOI = std::next(MI.operands_begin(), opers.getStackMapStartIdx());
378*0b57cec5SDimitry Andric   recordStackMapOpers(MI, ID, MOI, MI.operands_end(),
379*0b57cec5SDimitry Andric                       opers.isAnyReg() && opers.hasDef());
380*0b57cec5SDimitry Andric 
381*0b57cec5SDimitry Andric #ifndef NDEBUG
382*0b57cec5SDimitry Andric   // verify anyregcc
383*0b57cec5SDimitry Andric   auto &Locations = CSInfos.back().Locations;
384*0b57cec5SDimitry Andric   if (opers.isAnyReg()) {
385*0b57cec5SDimitry Andric     unsigned NArgs = opers.getNumCallArgs();
386*0b57cec5SDimitry Andric     for (unsigned i = 0, e = (opers.hasDef() ? NArgs + 1 : NArgs); i != e; ++i)
387*0b57cec5SDimitry Andric       assert(Locations[i].Type == Location::Register &&
388*0b57cec5SDimitry Andric              "anyreg arg must be in reg.");
389*0b57cec5SDimitry Andric   }
390*0b57cec5SDimitry Andric #endif
391*0b57cec5SDimitry Andric }
392*0b57cec5SDimitry Andric 
393*0b57cec5SDimitry Andric void StackMaps::recordStatepoint(const MachineInstr &MI) {
394*0b57cec5SDimitry Andric   assert(MI.getOpcode() == TargetOpcode::STATEPOINT && "expected statepoint");
395*0b57cec5SDimitry Andric 
396*0b57cec5SDimitry Andric   StatepointOpers opers(&MI);
397*0b57cec5SDimitry Andric   // Record all the deopt and gc operands (they're contiguous and run from the
398*0b57cec5SDimitry Andric   // initial index to the end of the operand list)
399*0b57cec5SDimitry Andric   const unsigned StartIdx = opers.getVarIdx();
400*0b57cec5SDimitry Andric   recordStackMapOpers(MI, opers.getID(), MI.operands_begin() + StartIdx,
401*0b57cec5SDimitry Andric                       MI.operands_end(), false);
402*0b57cec5SDimitry Andric }
403*0b57cec5SDimitry Andric 
404*0b57cec5SDimitry Andric /// Emit the stackmap header.
405*0b57cec5SDimitry Andric ///
406*0b57cec5SDimitry Andric /// Header {
407*0b57cec5SDimitry Andric ///   uint8  : Stack Map Version (currently 2)
408*0b57cec5SDimitry Andric ///   uint8  : Reserved (expected to be 0)
409*0b57cec5SDimitry Andric ///   uint16 : Reserved (expected to be 0)
410*0b57cec5SDimitry Andric /// }
411*0b57cec5SDimitry Andric /// uint32 : NumFunctions
412*0b57cec5SDimitry Andric /// uint32 : NumConstants
413*0b57cec5SDimitry Andric /// uint32 : NumRecords
414*0b57cec5SDimitry Andric void StackMaps::emitStackmapHeader(MCStreamer &OS) {
415*0b57cec5SDimitry Andric   // Header.
416*0b57cec5SDimitry Andric   OS.EmitIntValue(StackMapVersion, 1); // Version.
417*0b57cec5SDimitry Andric   OS.EmitIntValue(0, 1);               // Reserved.
418*0b57cec5SDimitry Andric   OS.EmitIntValue(0, 2);               // Reserved.
419*0b57cec5SDimitry Andric 
420*0b57cec5SDimitry Andric   // Num functions.
421*0b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << WSMP << "#functions = " << FnInfos.size() << '\n');
422*0b57cec5SDimitry Andric   OS.EmitIntValue(FnInfos.size(), 4);
423*0b57cec5SDimitry Andric   // Num constants.
424*0b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << WSMP << "#constants = " << ConstPool.size() << '\n');
425*0b57cec5SDimitry Andric   OS.EmitIntValue(ConstPool.size(), 4);
426*0b57cec5SDimitry Andric   // Num callsites.
427*0b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << WSMP << "#callsites = " << CSInfos.size() << '\n');
428*0b57cec5SDimitry Andric   OS.EmitIntValue(CSInfos.size(), 4);
429*0b57cec5SDimitry Andric }
430*0b57cec5SDimitry Andric 
431*0b57cec5SDimitry Andric /// Emit the function frame record for each function.
432*0b57cec5SDimitry Andric ///
433*0b57cec5SDimitry Andric /// StkSizeRecord[NumFunctions] {
434*0b57cec5SDimitry Andric ///   uint64 : Function Address
435*0b57cec5SDimitry Andric ///   uint64 : Stack Size
436*0b57cec5SDimitry Andric ///   uint64 : Record Count
437*0b57cec5SDimitry Andric /// }
438*0b57cec5SDimitry Andric void StackMaps::emitFunctionFrameRecords(MCStreamer &OS) {
439*0b57cec5SDimitry Andric   // Function Frame records.
440*0b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << WSMP << "functions:\n");
441*0b57cec5SDimitry Andric   for (auto const &FR : FnInfos) {
442*0b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << WSMP << "function addr: " << FR.first
443*0b57cec5SDimitry Andric                       << " frame size: " << FR.second.StackSize
444*0b57cec5SDimitry Andric                       << " callsite count: " << FR.second.RecordCount << '\n');
445*0b57cec5SDimitry Andric     OS.EmitSymbolValue(FR.first, 8);
446*0b57cec5SDimitry Andric     OS.EmitIntValue(FR.second.StackSize, 8);
447*0b57cec5SDimitry Andric     OS.EmitIntValue(FR.second.RecordCount, 8);
448*0b57cec5SDimitry Andric   }
449*0b57cec5SDimitry Andric }
450*0b57cec5SDimitry Andric 
451*0b57cec5SDimitry Andric /// Emit the constant pool.
452*0b57cec5SDimitry Andric ///
453*0b57cec5SDimitry Andric /// int64  : Constants[NumConstants]
454*0b57cec5SDimitry Andric void StackMaps::emitConstantPoolEntries(MCStreamer &OS) {
455*0b57cec5SDimitry Andric   // Constant pool entries.
456*0b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << WSMP << "constants:\n");
457*0b57cec5SDimitry Andric   for (const auto &ConstEntry : ConstPool) {
458*0b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << WSMP << ConstEntry.second << '\n');
459*0b57cec5SDimitry Andric     OS.EmitIntValue(ConstEntry.second, 8);
460*0b57cec5SDimitry Andric   }
461*0b57cec5SDimitry Andric }
462*0b57cec5SDimitry Andric 
463*0b57cec5SDimitry Andric /// Emit the callsite info for each callsite.
464*0b57cec5SDimitry Andric ///
465*0b57cec5SDimitry Andric /// StkMapRecord[NumRecords] {
466*0b57cec5SDimitry Andric ///   uint64 : PatchPoint ID
467*0b57cec5SDimitry Andric ///   uint32 : Instruction Offset
468*0b57cec5SDimitry Andric ///   uint16 : Reserved (record flags)
469*0b57cec5SDimitry Andric ///   uint16 : NumLocations
470*0b57cec5SDimitry Andric ///   Location[NumLocations] {
471*0b57cec5SDimitry Andric ///     uint8  : Register | Direct | Indirect | Constant | ConstantIndex
472*0b57cec5SDimitry Andric ///     uint8  : Size in Bytes
473*0b57cec5SDimitry Andric ///     uint16 : Dwarf RegNum
474*0b57cec5SDimitry Andric ///     int32  : Offset
475*0b57cec5SDimitry Andric ///   }
476*0b57cec5SDimitry Andric ///   uint16 : Padding
477*0b57cec5SDimitry Andric ///   uint16 : NumLiveOuts
478*0b57cec5SDimitry Andric ///   LiveOuts[NumLiveOuts] {
479*0b57cec5SDimitry Andric ///     uint16 : Dwarf RegNum
480*0b57cec5SDimitry Andric ///     uint8  : Reserved
481*0b57cec5SDimitry Andric ///     uint8  : Size in Bytes
482*0b57cec5SDimitry Andric ///   }
483*0b57cec5SDimitry Andric ///   uint32 : Padding (only if required to align to 8 byte)
484*0b57cec5SDimitry Andric /// }
485*0b57cec5SDimitry Andric ///
486*0b57cec5SDimitry Andric /// Location Encoding, Type, Value:
487*0b57cec5SDimitry Andric ///   0x1, Register, Reg                 (value in register)
488*0b57cec5SDimitry Andric ///   0x2, Direct, Reg + Offset          (frame index)
489*0b57cec5SDimitry Andric ///   0x3, Indirect, [Reg + Offset]      (spilled value)
490*0b57cec5SDimitry Andric ///   0x4, Constant, Offset              (small constant)
491*0b57cec5SDimitry Andric ///   0x5, ConstIndex, Constants[Offset] (large constant)
492*0b57cec5SDimitry Andric void StackMaps::emitCallsiteEntries(MCStreamer &OS) {
493*0b57cec5SDimitry Andric   LLVM_DEBUG(print(dbgs()));
494*0b57cec5SDimitry Andric   // Callsite entries.
495*0b57cec5SDimitry Andric   for (const auto &CSI : CSInfos) {
496*0b57cec5SDimitry Andric     const LocationVec &CSLocs = CSI.Locations;
497*0b57cec5SDimitry Andric     const LiveOutVec &LiveOuts = CSI.LiveOuts;
498*0b57cec5SDimitry Andric 
499*0b57cec5SDimitry Andric     // Verify stack map entry. It's better to communicate a problem to the
500*0b57cec5SDimitry Andric     // runtime than crash in case of in-process compilation. Currently, we do
501*0b57cec5SDimitry Andric     // simple overflow checks, but we may eventually communicate other
502*0b57cec5SDimitry Andric     // compilation errors this way.
503*0b57cec5SDimitry Andric     if (CSLocs.size() > UINT16_MAX || LiveOuts.size() > UINT16_MAX) {
504*0b57cec5SDimitry Andric       OS.EmitIntValue(UINT64_MAX, 8); // Invalid ID.
505*0b57cec5SDimitry Andric       OS.EmitValue(CSI.CSOffsetExpr, 4);
506*0b57cec5SDimitry Andric       OS.EmitIntValue(0, 2); // Reserved.
507*0b57cec5SDimitry Andric       OS.EmitIntValue(0, 2); // 0 locations.
508*0b57cec5SDimitry Andric       OS.EmitIntValue(0, 2); // padding.
509*0b57cec5SDimitry Andric       OS.EmitIntValue(0, 2); // 0 live-out registers.
510*0b57cec5SDimitry Andric       OS.EmitIntValue(0, 4); // padding.
511*0b57cec5SDimitry Andric       continue;
512*0b57cec5SDimitry Andric     }
513*0b57cec5SDimitry Andric 
514*0b57cec5SDimitry Andric     OS.EmitIntValue(CSI.ID, 8);
515*0b57cec5SDimitry Andric     OS.EmitValue(CSI.CSOffsetExpr, 4);
516*0b57cec5SDimitry Andric 
517*0b57cec5SDimitry Andric     // Reserved for flags.
518*0b57cec5SDimitry Andric     OS.EmitIntValue(0, 2);
519*0b57cec5SDimitry Andric     OS.EmitIntValue(CSLocs.size(), 2);
520*0b57cec5SDimitry Andric 
521*0b57cec5SDimitry Andric     for (const auto &Loc : CSLocs) {
522*0b57cec5SDimitry Andric       OS.EmitIntValue(Loc.Type, 1);
523*0b57cec5SDimitry Andric       OS.EmitIntValue(0, 1);  // Reserved
524*0b57cec5SDimitry Andric       OS.EmitIntValue(Loc.Size, 2);
525*0b57cec5SDimitry Andric       OS.EmitIntValue(Loc.Reg, 2);
526*0b57cec5SDimitry Andric       OS.EmitIntValue(0, 2);  // Reserved
527*0b57cec5SDimitry Andric       OS.EmitIntValue(Loc.Offset, 4);
528*0b57cec5SDimitry Andric     }
529*0b57cec5SDimitry Andric 
530*0b57cec5SDimitry Andric     // Emit alignment to 8 byte.
531*0b57cec5SDimitry Andric     OS.EmitValueToAlignment(8);
532*0b57cec5SDimitry Andric 
533*0b57cec5SDimitry Andric     // Num live-out registers and padding to align to 4 byte.
534*0b57cec5SDimitry Andric     OS.EmitIntValue(0, 2);
535*0b57cec5SDimitry Andric     OS.EmitIntValue(LiveOuts.size(), 2);
536*0b57cec5SDimitry Andric 
537*0b57cec5SDimitry Andric     for (const auto &LO : LiveOuts) {
538*0b57cec5SDimitry Andric       OS.EmitIntValue(LO.DwarfRegNum, 2);
539*0b57cec5SDimitry Andric       OS.EmitIntValue(0, 1);
540*0b57cec5SDimitry Andric       OS.EmitIntValue(LO.Size, 1);
541*0b57cec5SDimitry Andric     }
542*0b57cec5SDimitry Andric     // Emit alignment to 8 byte.
543*0b57cec5SDimitry Andric     OS.EmitValueToAlignment(8);
544*0b57cec5SDimitry Andric   }
545*0b57cec5SDimitry Andric }
546*0b57cec5SDimitry Andric 
547*0b57cec5SDimitry Andric /// Serialize the stackmap data.
548*0b57cec5SDimitry Andric void StackMaps::serializeToStackMapSection() {
549*0b57cec5SDimitry Andric   (void)WSMP;
550*0b57cec5SDimitry Andric   // Bail out if there's no stack map data.
551*0b57cec5SDimitry Andric   assert((!CSInfos.empty() || ConstPool.empty()) &&
552*0b57cec5SDimitry Andric          "Expected empty constant pool too!");
553*0b57cec5SDimitry Andric   assert((!CSInfos.empty() || FnInfos.empty()) &&
554*0b57cec5SDimitry Andric          "Expected empty function record too!");
555*0b57cec5SDimitry Andric   if (CSInfos.empty())
556*0b57cec5SDimitry Andric     return;
557*0b57cec5SDimitry Andric 
558*0b57cec5SDimitry Andric   MCContext &OutContext = AP.OutStreamer->getContext();
559*0b57cec5SDimitry Andric   MCStreamer &OS = *AP.OutStreamer;
560*0b57cec5SDimitry Andric 
561*0b57cec5SDimitry Andric   // Create the section.
562*0b57cec5SDimitry Andric   MCSection *StackMapSection =
563*0b57cec5SDimitry Andric       OutContext.getObjectFileInfo()->getStackMapSection();
564*0b57cec5SDimitry Andric   OS.SwitchSection(StackMapSection);
565*0b57cec5SDimitry Andric 
566*0b57cec5SDimitry Andric   // Emit a dummy symbol to force section inclusion.
567*0b57cec5SDimitry Andric   OS.EmitLabel(OutContext.getOrCreateSymbol(Twine("__LLVM_StackMaps")));
568*0b57cec5SDimitry Andric 
569*0b57cec5SDimitry Andric   // Serialize data.
570*0b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "********** Stack Map Output **********\n");
571*0b57cec5SDimitry Andric   emitStackmapHeader(OS);
572*0b57cec5SDimitry Andric   emitFunctionFrameRecords(OS);
573*0b57cec5SDimitry Andric   emitConstantPoolEntries(OS);
574*0b57cec5SDimitry Andric   emitCallsiteEntries(OS);
575*0b57cec5SDimitry Andric   OS.AddBlankLine();
576*0b57cec5SDimitry Andric 
577*0b57cec5SDimitry Andric   // Clean up.
578*0b57cec5SDimitry Andric   CSInfos.clear();
579*0b57cec5SDimitry Andric   ConstPool.clear();
580*0b57cec5SDimitry Andric }
581