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