10b57cec5SDimitry Andric //===- StackMaps.cpp ------------------------------------------------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric 90b57cec5SDimitry Andric #include "llvm/CodeGen/StackMaps.h" 100b57cec5SDimitry Andric #include "llvm/ADT/DenseMapInfo.h" 110b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h" 120b57cec5SDimitry Andric #include "llvm/ADT/Twine.h" 130b57cec5SDimitry Andric #include "llvm/CodeGen/AsmPrinter.h" 140b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFrameInfo.h" 150b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunction.h" 160b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstr.h" 170b57cec5SDimitry Andric #include "llvm/CodeGen/MachineOperand.h" 180b57cec5SDimitry Andric #include "llvm/CodeGen/TargetOpcodes.h" 190b57cec5SDimitry Andric #include "llvm/CodeGen/TargetRegisterInfo.h" 200b57cec5SDimitry Andric #include "llvm/CodeGen/TargetSubtargetInfo.h" 210b57cec5SDimitry Andric #include "llvm/IR/DataLayout.h" 220b57cec5SDimitry Andric #include "llvm/MC/MCContext.h" 230b57cec5SDimitry Andric #include "llvm/MC/MCExpr.h" 240b57cec5SDimitry Andric #include "llvm/MC/MCObjectFileInfo.h" 250b57cec5SDimitry Andric #include "llvm/MC/MCRegisterInfo.h" 260b57cec5SDimitry Andric #include "llvm/MC/MCStreamer.h" 270b57cec5SDimitry Andric #include "llvm/Support/CommandLine.h" 280b57cec5SDimitry Andric #include "llvm/Support/Debug.h" 290b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h" 300b57cec5SDimitry Andric #include "llvm/Support/MathExtras.h" 310b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 320b57cec5SDimitry Andric #include <algorithm> 330b57cec5SDimitry Andric #include <cassert> 340b57cec5SDimitry Andric #include <cstdint> 350b57cec5SDimitry Andric #include <iterator> 360b57cec5SDimitry Andric #include <utility> 370b57cec5SDimitry Andric 380b57cec5SDimitry Andric using namespace llvm; 390b57cec5SDimitry Andric 400b57cec5SDimitry Andric #define DEBUG_TYPE "stackmaps" 410b57cec5SDimitry Andric 420b57cec5SDimitry Andric static cl::opt<int> StackMapVersion( 430b57cec5SDimitry Andric "stackmap-version", cl::init(3), cl::Hidden, 440b57cec5SDimitry Andric cl::desc("Specify the stackmap encoding version (default = 3)")); 450b57cec5SDimitry Andric 460b57cec5SDimitry Andric const char *StackMaps::WSMP = "Stack Maps: "; 470b57cec5SDimitry Andric 48e8d8bef9SDimitry Andric static uint64_t getConstMetaVal(const MachineInstr &MI, unsigned Idx) { 49e8d8bef9SDimitry Andric assert(MI.getOperand(Idx).isImm() && 50e8d8bef9SDimitry Andric MI.getOperand(Idx).getImm() == StackMaps::ConstantOp); 51e8d8bef9SDimitry Andric const auto &MO = MI.getOperand(Idx + 1); 52e8d8bef9SDimitry Andric assert(MO.isImm()); 53e8d8bef9SDimitry Andric return MO.getImm(); 54e8d8bef9SDimitry Andric } 55e8d8bef9SDimitry Andric 560b57cec5SDimitry Andric StackMapOpers::StackMapOpers(const MachineInstr *MI) 570b57cec5SDimitry Andric : MI(MI) { 580b57cec5SDimitry Andric assert(getVarIdx() <= MI->getNumOperands() && 590b57cec5SDimitry Andric "invalid stackmap definition"); 600b57cec5SDimitry Andric } 610b57cec5SDimitry Andric 620b57cec5SDimitry Andric PatchPointOpers::PatchPointOpers(const MachineInstr *MI) 630b57cec5SDimitry Andric : MI(MI), HasDef(MI->getOperand(0).isReg() && MI->getOperand(0).isDef() && 640b57cec5SDimitry Andric !MI->getOperand(0).isImplicit()) { 650b57cec5SDimitry Andric #ifndef NDEBUG 660b57cec5SDimitry Andric unsigned CheckStartIdx = 0, e = MI->getNumOperands(); 670b57cec5SDimitry Andric while (CheckStartIdx < e && MI->getOperand(CheckStartIdx).isReg() && 680b57cec5SDimitry Andric MI->getOperand(CheckStartIdx).isDef() && 690b57cec5SDimitry Andric !MI->getOperand(CheckStartIdx).isImplicit()) 700b57cec5SDimitry Andric ++CheckStartIdx; 710b57cec5SDimitry Andric 720b57cec5SDimitry Andric assert(getMetaIdx() == CheckStartIdx && 730b57cec5SDimitry Andric "Unexpected additional definition in Patchpoint intrinsic."); 740b57cec5SDimitry Andric #endif 750b57cec5SDimitry Andric } 760b57cec5SDimitry Andric 770b57cec5SDimitry Andric unsigned PatchPointOpers::getNextScratchIdx(unsigned StartIdx) const { 780b57cec5SDimitry Andric if (!StartIdx) 790b57cec5SDimitry Andric StartIdx = getVarIdx(); 800b57cec5SDimitry Andric 810b57cec5SDimitry Andric // Find the next scratch register (implicit def and early clobber) 820b57cec5SDimitry Andric unsigned ScratchIdx = StartIdx, e = MI->getNumOperands(); 830b57cec5SDimitry Andric while (ScratchIdx < e && 840b57cec5SDimitry Andric !(MI->getOperand(ScratchIdx).isReg() && 850b57cec5SDimitry Andric MI->getOperand(ScratchIdx).isDef() && 860b57cec5SDimitry Andric MI->getOperand(ScratchIdx).isImplicit() && 870b57cec5SDimitry Andric MI->getOperand(ScratchIdx).isEarlyClobber())) 880b57cec5SDimitry Andric ++ScratchIdx; 890b57cec5SDimitry Andric 900b57cec5SDimitry Andric assert(ScratchIdx != e && "No scratch register available"); 910b57cec5SDimitry Andric return ScratchIdx; 920b57cec5SDimitry Andric } 930b57cec5SDimitry Andric 94e8d8bef9SDimitry Andric unsigned StatepointOpers::getNumGcMapEntriesIdx() { 95e8d8bef9SDimitry Andric // Take index of num of allocas and skip all allocas records. 96e8d8bef9SDimitry Andric unsigned CurIdx = getNumAllocaIdx(); 97e8d8bef9SDimitry Andric unsigned NumAllocas = getConstMetaVal(*MI, CurIdx - 1); 98e8d8bef9SDimitry Andric CurIdx++; 99e8d8bef9SDimitry Andric while (NumAllocas--) 100e8d8bef9SDimitry Andric CurIdx = StackMaps::getNextMetaArgIdx(MI, CurIdx); 101e8d8bef9SDimitry Andric return CurIdx + 1; // skip <StackMaps::ConstantOp> 102e8d8bef9SDimitry Andric } 103e8d8bef9SDimitry Andric 104e8d8bef9SDimitry Andric unsigned StatepointOpers::getNumAllocaIdx() { 105e8d8bef9SDimitry Andric // Take index of num of gc ptrs and skip all gc ptr records. 106e8d8bef9SDimitry Andric unsigned CurIdx = getNumGCPtrIdx(); 107e8d8bef9SDimitry Andric unsigned NumGCPtrs = getConstMetaVal(*MI, CurIdx - 1); 108e8d8bef9SDimitry Andric CurIdx++; 109e8d8bef9SDimitry Andric while (NumGCPtrs--) 110e8d8bef9SDimitry Andric CurIdx = StackMaps::getNextMetaArgIdx(MI, CurIdx); 111e8d8bef9SDimitry Andric return CurIdx + 1; // skip <StackMaps::ConstantOp> 112e8d8bef9SDimitry Andric } 113e8d8bef9SDimitry Andric 114e8d8bef9SDimitry Andric unsigned StatepointOpers::getNumGCPtrIdx() { 115e8d8bef9SDimitry Andric // Take index of num of deopt args and skip all deopt records. 116e8d8bef9SDimitry Andric unsigned CurIdx = getNumDeoptArgsIdx(); 117e8d8bef9SDimitry Andric unsigned NumDeoptArgs = getConstMetaVal(*MI, CurIdx - 1); 118e8d8bef9SDimitry Andric CurIdx++; 119e8d8bef9SDimitry Andric while (NumDeoptArgs--) { 120e8d8bef9SDimitry Andric CurIdx = StackMaps::getNextMetaArgIdx(MI, CurIdx); 121e8d8bef9SDimitry Andric } 122e8d8bef9SDimitry Andric return CurIdx + 1; // skip <StackMaps::ConstantOp> 123e8d8bef9SDimitry Andric } 124e8d8bef9SDimitry Andric 125e8d8bef9SDimitry Andric int StatepointOpers::getFirstGCPtrIdx() { 126e8d8bef9SDimitry Andric unsigned NumGCPtrsIdx = getNumGCPtrIdx(); 127e8d8bef9SDimitry Andric unsigned NumGCPtrs = getConstMetaVal(*MI, NumGCPtrsIdx - 1); 128e8d8bef9SDimitry Andric if (NumGCPtrs == 0) 129e8d8bef9SDimitry Andric return -1; 130e8d8bef9SDimitry Andric ++NumGCPtrsIdx; // skip <num gc ptrs> 131e8d8bef9SDimitry Andric assert(NumGCPtrsIdx < MI->getNumOperands()); 132e8d8bef9SDimitry Andric return (int)NumGCPtrsIdx; 133e8d8bef9SDimitry Andric } 134e8d8bef9SDimitry Andric 135e8d8bef9SDimitry Andric unsigned StatepointOpers::getGCPointerMap( 136e8d8bef9SDimitry Andric SmallVectorImpl<std::pair<unsigned, unsigned>> &GCMap) { 137e8d8bef9SDimitry Andric unsigned CurIdx = getNumGcMapEntriesIdx(); 138e8d8bef9SDimitry Andric unsigned GCMapSize = getConstMetaVal(*MI, CurIdx - 1); 139e8d8bef9SDimitry Andric CurIdx++; 140e8d8bef9SDimitry Andric for (unsigned N = 0; N < GCMapSize; ++N) { 141e8d8bef9SDimitry Andric unsigned B = MI->getOperand(CurIdx++).getImm(); 142e8d8bef9SDimitry Andric unsigned D = MI->getOperand(CurIdx++).getImm(); 143e8d8bef9SDimitry Andric GCMap.push_back(std::make_pair(B, D)); 144e8d8bef9SDimitry Andric } 145e8d8bef9SDimitry Andric 146e8d8bef9SDimitry Andric return GCMapSize; 147e8d8bef9SDimitry Andric } 148e8d8bef9SDimitry Andric 149*bdd1243dSDimitry Andric bool StatepointOpers::isFoldableReg(Register Reg) const { 150*bdd1243dSDimitry Andric unsigned FoldableAreaStart = getVarIdx(); 151*bdd1243dSDimitry Andric for (const MachineOperand &MO : MI->uses()) { 152*bdd1243dSDimitry Andric if (MI->getOperandNo(&MO) >= FoldableAreaStart) 153*bdd1243dSDimitry Andric break; 154*bdd1243dSDimitry Andric if (MO.isReg() && MO.getReg() == Reg) 155*bdd1243dSDimitry Andric return false; 156*bdd1243dSDimitry Andric } 157*bdd1243dSDimitry Andric return true; 158*bdd1243dSDimitry Andric } 159*bdd1243dSDimitry Andric 160*bdd1243dSDimitry Andric bool StatepointOpers::isFoldableReg(const MachineInstr *MI, Register Reg) { 161*bdd1243dSDimitry Andric if (MI->getOpcode() != TargetOpcode::STATEPOINT) 162*bdd1243dSDimitry Andric return false; 163*bdd1243dSDimitry Andric return StatepointOpers(MI).isFoldableReg(Reg); 164*bdd1243dSDimitry Andric } 165*bdd1243dSDimitry Andric 1660b57cec5SDimitry Andric StackMaps::StackMaps(AsmPrinter &AP) : AP(AP) { 1670b57cec5SDimitry Andric if (StackMapVersion != 3) 1680b57cec5SDimitry Andric llvm_unreachable("Unsupported stackmap version!"); 1690b57cec5SDimitry Andric } 1700b57cec5SDimitry Andric 171e8d8bef9SDimitry Andric unsigned StackMaps::getNextMetaArgIdx(const MachineInstr *MI, unsigned CurIdx) { 172e8d8bef9SDimitry Andric assert(CurIdx < MI->getNumOperands() && "Bad meta arg index"); 173e8d8bef9SDimitry Andric const auto &MO = MI->getOperand(CurIdx); 174e8d8bef9SDimitry Andric if (MO.isImm()) { 175e8d8bef9SDimitry Andric switch (MO.getImm()) { 176e8d8bef9SDimitry Andric default: 177e8d8bef9SDimitry Andric llvm_unreachable("Unrecognized operand type."); 178e8d8bef9SDimitry Andric case StackMaps::DirectMemRefOp: 179e8d8bef9SDimitry Andric CurIdx += 2; 180e8d8bef9SDimitry Andric break; 181e8d8bef9SDimitry Andric case StackMaps::IndirectMemRefOp: 182e8d8bef9SDimitry Andric CurIdx += 3; 183e8d8bef9SDimitry Andric break; 184e8d8bef9SDimitry Andric case StackMaps::ConstantOp: 185e8d8bef9SDimitry Andric ++CurIdx; 186e8d8bef9SDimitry Andric break; 187e8d8bef9SDimitry Andric } 188e8d8bef9SDimitry Andric } 189e8d8bef9SDimitry Andric ++CurIdx; 190e8d8bef9SDimitry Andric assert(CurIdx < MI->getNumOperands() && "points past operand list"); 191e8d8bef9SDimitry Andric return CurIdx; 192e8d8bef9SDimitry Andric } 193e8d8bef9SDimitry Andric 1940b57cec5SDimitry Andric /// Go up the super-register chain until we hit a valid dwarf register number. 1950b57cec5SDimitry Andric static unsigned getDwarfRegNum(unsigned Reg, const TargetRegisterInfo *TRI) { 1960b57cec5SDimitry Andric int RegNum = TRI->getDwarfRegNum(Reg, false); 1970b57cec5SDimitry Andric for (MCSuperRegIterator SR(Reg, TRI); SR.isValid() && RegNum < 0; ++SR) 1980b57cec5SDimitry Andric RegNum = TRI->getDwarfRegNum(*SR, false); 1990b57cec5SDimitry Andric 2000b57cec5SDimitry Andric assert(RegNum >= 0 && "Invalid Dwarf register number."); 2010b57cec5SDimitry Andric return (unsigned)RegNum; 2020b57cec5SDimitry Andric } 2030b57cec5SDimitry Andric 2040b57cec5SDimitry Andric MachineInstr::const_mop_iterator 2050b57cec5SDimitry Andric StackMaps::parseOperand(MachineInstr::const_mop_iterator MOI, 2060b57cec5SDimitry Andric MachineInstr::const_mop_iterator MOE, LocationVec &Locs, 2070b57cec5SDimitry Andric LiveOutVec &LiveOuts) const { 2080b57cec5SDimitry Andric const TargetRegisterInfo *TRI = AP.MF->getSubtarget().getRegisterInfo(); 2090b57cec5SDimitry Andric if (MOI->isImm()) { 2100b57cec5SDimitry Andric switch (MOI->getImm()) { 2110b57cec5SDimitry Andric default: 2120b57cec5SDimitry Andric llvm_unreachable("Unrecognized operand type."); 2130b57cec5SDimitry Andric case StackMaps::DirectMemRefOp: { 2140b57cec5SDimitry Andric auto &DL = AP.MF->getDataLayout(); 2150b57cec5SDimitry Andric 2160b57cec5SDimitry Andric unsigned Size = DL.getPointerSizeInBits(); 2170b57cec5SDimitry Andric assert((Size % 8) == 0 && "Need pointer size in bytes."); 2180b57cec5SDimitry Andric Size /= 8; 2198bcb0991SDimitry Andric Register Reg = (++MOI)->getReg(); 2200b57cec5SDimitry Andric int64_t Imm = (++MOI)->getImm(); 2210b57cec5SDimitry Andric Locs.emplace_back(StackMaps::Location::Direct, Size, 2220b57cec5SDimitry Andric getDwarfRegNum(Reg, TRI), Imm); 2230b57cec5SDimitry Andric break; 2240b57cec5SDimitry Andric } 2250b57cec5SDimitry Andric case StackMaps::IndirectMemRefOp: { 2260b57cec5SDimitry Andric int64_t Size = (++MOI)->getImm(); 2270b57cec5SDimitry Andric assert(Size > 0 && "Need a valid size for indirect memory locations."); 2288bcb0991SDimitry Andric Register Reg = (++MOI)->getReg(); 2290b57cec5SDimitry Andric int64_t Imm = (++MOI)->getImm(); 2300b57cec5SDimitry Andric Locs.emplace_back(StackMaps::Location::Indirect, Size, 2310b57cec5SDimitry Andric getDwarfRegNum(Reg, TRI), Imm); 2320b57cec5SDimitry Andric break; 2330b57cec5SDimitry Andric } 2340b57cec5SDimitry Andric case StackMaps::ConstantOp: { 2350b57cec5SDimitry Andric ++MOI; 2360b57cec5SDimitry Andric assert(MOI->isImm() && "Expected constant operand."); 2370b57cec5SDimitry Andric int64_t Imm = MOI->getImm(); 2380b57cec5SDimitry Andric Locs.emplace_back(Location::Constant, sizeof(int64_t), 0, Imm); 2390b57cec5SDimitry Andric break; 2400b57cec5SDimitry Andric } 2410b57cec5SDimitry Andric } 2420b57cec5SDimitry Andric return ++MOI; 2430b57cec5SDimitry Andric } 2440b57cec5SDimitry Andric 2450b57cec5SDimitry Andric // The physical register number will ultimately be encoded as a DWARF regno. 2460b57cec5SDimitry Andric // The stack map also records the size of a spill slot that can hold the 2470b57cec5SDimitry Andric // register content. (The runtime can track the actual size of the data type 2480b57cec5SDimitry Andric // if it needs to.) 2490b57cec5SDimitry Andric if (MOI->isReg()) { 2500b57cec5SDimitry Andric // Skip implicit registers (this includes our scratch registers) 2510b57cec5SDimitry Andric if (MOI->isImplicit()) 2520b57cec5SDimitry Andric return ++MOI; 2530b57cec5SDimitry Andric 254e8d8bef9SDimitry Andric if (MOI->isUndef()) { 255e8d8bef9SDimitry Andric // Record `undef` register as constant. Use same value as ISel uses. 256e8d8bef9SDimitry Andric Locs.emplace_back(Location::Constant, sizeof(int64_t), 0, 0xFEFEFEFE); 257e8d8bef9SDimitry Andric return ++MOI; 258e8d8bef9SDimitry Andric } 259e8d8bef9SDimitry Andric 260*bdd1243dSDimitry Andric assert(MOI->getReg().isPhysical() && 2610b57cec5SDimitry Andric "Virtreg operands should have been rewritten before now."); 2620b57cec5SDimitry Andric const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(MOI->getReg()); 2630b57cec5SDimitry Andric assert(!MOI->getSubReg() && "Physical subreg still around."); 2640b57cec5SDimitry Andric 2650b57cec5SDimitry Andric unsigned Offset = 0; 2660b57cec5SDimitry Andric unsigned DwarfRegNum = getDwarfRegNum(MOI->getReg(), TRI); 2678bcb0991SDimitry Andric unsigned LLVMRegNum = *TRI->getLLVMRegNum(DwarfRegNum, false); 2680b57cec5SDimitry Andric unsigned SubRegIdx = TRI->getSubRegIndex(LLVMRegNum, MOI->getReg()); 2690b57cec5SDimitry Andric if (SubRegIdx) 2700b57cec5SDimitry Andric Offset = TRI->getSubRegIdxOffset(SubRegIdx); 2710b57cec5SDimitry Andric 2720b57cec5SDimitry Andric Locs.emplace_back(Location::Register, TRI->getSpillSize(*RC), 2730b57cec5SDimitry Andric DwarfRegNum, Offset); 2740b57cec5SDimitry Andric return ++MOI; 2750b57cec5SDimitry Andric } 2760b57cec5SDimitry Andric 2770b57cec5SDimitry Andric if (MOI->isRegLiveOut()) 2780b57cec5SDimitry Andric LiveOuts = parseRegisterLiveOutMask(MOI->getRegLiveOut()); 2790b57cec5SDimitry Andric 2800b57cec5SDimitry Andric return ++MOI; 2810b57cec5SDimitry Andric } 2820b57cec5SDimitry Andric 2830b57cec5SDimitry Andric void StackMaps::print(raw_ostream &OS) { 2840b57cec5SDimitry Andric const TargetRegisterInfo *TRI = 2850b57cec5SDimitry Andric AP.MF ? AP.MF->getSubtarget().getRegisterInfo() : nullptr; 2860b57cec5SDimitry Andric OS << WSMP << "callsites:\n"; 2870b57cec5SDimitry Andric for (const auto &CSI : CSInfos) { 2880b57cec5SDimitry Andric const LocationVec &CSLocs = CSI.Locations; 2890b57cec5SDimitry Andric const LiveOutVec &LiveOuts = CSI.LiveOuts; 2900b57cec5SDimitry Andric 2910b57cec5SDimitry Andric OS << WSMP << "callsite " << CSI.ID << "\n"; 2920b57cec5SDimitry Andric OS << WSMP << " has " << CSLocs.size() << " locations\n"; 2930b57cec5SDimitry Andric 2940b57cec5SDimitry Andric unsigned Idx = 0; 2950b57cec5SDimitry Andric for (const auto &Loc : CSLocs) { 2960b57cec5SDimitry Andric OS << WSMP << "\t\tLoc " << Idx << ": "; 2970b57cec5SDimitry Andric switch (Loc.Type) { 2980b57cec5SDimitry Andric case Location::Unprocessed: 2990b57cec5SDimitry Andric OS << "<Unprocessed operand>"; 3000b57cec5SDimitry Andric break; 3010b57cec5SDimitry Andric case Location::Register: 3020b57cec5SDimitry Andric OS << "Register "; 3030b57cec5SDimitry Andric if (TRI) 3040b57cec5SDimitry Andric OS << printReg(Loc.Reg, TRI); 3050b57cec5SDimitry Andric else 3060b57cec5SDimitry Andric OS << Loc.Reg; 3070b57cec5SDimitry Andric break; 3080b57cec5SDimitry Andric case Location::Direct: 3090b57cec5SDimitry Andric OS << "Direct "; 3100b57cec5SDimitry Andric if (TRI) 3110b57cec5SDimitry Andric OS << printReg(Loc.Reg, TRI); 3120b57cec5SDimitry Andric else 3130b57cec5SDimitry Andric OS << Loc.Reg; 3140b57cec5SDimitry Andric if (Loc.Offset) 3150b57cec5SDimitry Andric OS << " + " << Loc.Offset; 3160b57cec5SDimitry Andric break; 3170b57cec5SDimitry Andric case Location::Indirect: 3180b57cec5SDimitry Andric OS << "Indirect "; 3190b57cec5SDimitry Andric if (TRI) 3200b57cec5SDimitry Andric OS << printReg(Loc.Reg, TRI); 3210b57cec5SDimitry Andric else 3220b57cec5SDimitry Andric OS << Loc.Reg; 3230b57cec5SDimitry Andric OS << "+" << Loc.Offset; 3240b57cec5SDimitry Andric break; 3250b57cec5SDimitry Andric case Location::Constant: 3260b57cec5SDimitry Andric OS << "Constant " << Loc.Offset; 3270b57cec5SDimitry Andric break; 3280b57cec5SDimitry Andric case Location::ConstantIndex: 3290b57cec5SDimitry Andric OS << "Constant Index " << Loc.Offset; 3300b57cec5SDimitry Andric break; 3310b57cec5SDimitry Andric } 3320b57cec5SDimitry Andric OS << "\t[encoding: .byte " << Loc.Type << ", .byte 0" 3330b57cec5SDimitry Andric << ", .short " << Loc.Size << ", .short " << Loc.Reg << ", .short 0" 3340b57cec5SDimitry Andric << ", .int " << Loc.Offset << "]\n"; 3350b57cec5SDimitry Andric Idx++; 3360b57cec5SDimitry Andric } 3370b57cec5SDimitry Andric 3380b57cec5SDimitry Andric OS << WSMP << "\thas " << LiveOuts.size() << " live-out registers\n"; 3390b57cec5SDimitry Andric 3400b57cec5SDimitry Andric Idx = 0; 3410b57cec5SDimitry Andric for (const auto &LO : LiveOuts) { 3420b57cec5SDimitry Andric OS << WSMP << "\t\tLO " << Idx << ": "; 3430b57cec5SDimitry Andric if (TRI) 3440b57cec5SDimitry Andric OS << printReg(LO.Reg, TRI); 3450b57cec5SDimitry Andric else 3460b57cec5SDimitry Andric OS << LO.Reg; 3470b57cec5SDimitry Andric OS << "\t[encoding: .short " << LO.DwarfRegNum << ", .byte 0, .byte " 3480b57cec5SDimitry Andric << LO.Size << "]\n"; 3490b57cec5SDimitry Andric Idx++; 3500b57cec5SDimitry Andric } 3510b57cec5SDimitry Andric } 3520b57cec5SDimitry Andric } 3530b57cec5SDimitry Andric 3540b57cec5SDimitry Andric /// Create a live-out register record for the given register Reg. 3550b57cec5SDimitry Andric StackMaps::LiveOutReg 3560b57cec5SDimitry Andric StackMaps::createLiveOutReg(unsigned Reg, const TargetRegisterInfo *TRI) const { 3570b57cec5SDimitry Andric unsigned DwarfRegNum = getDwarfRegNum(Reg, TRI); 3580b57cec5SDimitry Andric unsigned Size = TRI->getSpillSize(*TRI->getMinimalPhysRegClass(Reg)); 3590b57cec5SDimitry Andric return LiveOutReg(Reg, DwarfRegNum, Size); 3600b57cec5SDimitry Andric } 3610b57cec5SDimitry Andric 3620b57cec5SDimitry Andric /// Parse the register live-out mask and return a vector of live-out registers 3630b57cec5SDimitry Andric /// that need to be recorded in the stackmap. 3640b57cec5SDimitry Andric StackMaps::LiveOutVec 3650b57cec5SDimitry Andric StackMaps::parseRegisterLiveOutMask(const uint32_t *Mask) const { 3660b57cec5SDimitry Andric assert(Mask && "No register mask specified"); 3670b57cec5SDimitry Andric const TargetRegisterInfo *TRI = AP.MF->getSubtarget().getRegisterInfo(); 3680b57cec5SDimitry Andric LiveOutVec LiveOuts; 3690b57cec5SDimitry Andric 3700b57cec5SDimitry Andric // Create a LiveOutReg for each bit that is set in the register mask. 3710b57cec5SDimitry Andric for (unsigned Reg = 0, NumRegs = TRI->getNumRegs(); Reg != NumRegs; ++Reg) 372480093f4SDimitry Andric if ((Mask[Reg / 32] >> (Reg % 32)) & 1) 3730b57cec5SDimitry Andric LiveOuts.push_back(createLiveOutReg(Reg, TRI)); 3740b57cec5SDimitry Andric 3750b57cec5SDimitry Andric // We don't need to keep track of a register if its super-register is already 3760b57cec5SDimitry Andric // in the list. Merge entries that refer to the same dwarf register and use 3770b57cec5SDimitry Andric // the maximum size that needs to be spilled. 3780b57cec5SDimitry Andric 3790b57cec5SDimitry Andric llvm::sort(LiveOuts, [](const LiveOutReg &LHS, const LiveOutReg &RHS) { 3800b57cec5SDimitry Andric // Only sort by the dwarf register number. 3810b57cec5SDimitry Andric return LHS.DwarfRegNum < RHS.DwarfRegNum; 3820b57cec5SDimitry Andric }); 3830b57cec5SDimitry Andric 3840b57cec5SDimitry Andric for (auto I = LiveOuts.begin(), E = LiveOuts.end(); I != E; ++I) { 385fcaf7f86SDimitry Andric for (auto *II = std::next(I); II != E; ++II) { 3860b57cec5SDimitry Andric if (I->DwarfRegNum != II->DwarfRegNum) { 3870b57cec5SDimitry Andric // Skip all the now invalid entries. 3880b57cec5SDimitry Andric I = --II; 3890b57cec5SDimitry Andric break; 3900b57cec5SDimitry Andric } 3910b57cec5SDimitry Andric I->Size = std::max(I->Size, II->Size); 3920b57cec5SDimitry Andric if (TRI->isSuperRegister(I->Reg, II->Reg)) 3930b57cec5SDimitry Andric I->Reg = II->Reg; 3940b57cec5SDimitry Andric II->Reg = 0; // mark for deletion. 3950b57cec5SDimitry Andric } 3960b57cec5SDimitry Andric } 3970b57cec5SDimitry Andric 398e8d8bef9SDimitry Andric llvm::erase_if(LiveOuts, [](const LiveOutReg &LO) { return LO.Reg == 0; }); 3990b57cec5SDimitry Andric 4000b57cec5SDimitry Andric return LiveOuts; 4010b57cec5SDimitry Andric } 4020b57cec5SDimitry Andric 403e8d8bef9SDimitry Andric // See statepoint MI format description in StatepointOpers' class comment 404e8d8bef9SDimitry Andric // in include/llvm/CodeGen/StackMaps.h 405e8d8bef9SDimitry Andric void StackMaps::parseStatepointOpers(const MachineInstr &MI, 406e8d8bef9SDimitry Andric MachineInstr::const_mop_iterator MOI, 407e8d8bef9SDimitry Andric MachineInstr::const_mop_iterator MOE, 408e8d8bef9SDimitry Andric LocationVec &Locations, 409e8d8bef9SDimitry Andric LiveOutVec &LiveOuts) { 410e8d8bef9SDimitry Andric LLVM_DEBUG(dbgs() << "record statepoint : " << MI << "\n"); 411e8d8bef9SDimitry Andric StatepointOpers SO(&MI); 412e8d8bef9SDimitry Andric MOI = parseOperand(MOI, MOE, Locations, LiveOuts); // CC 413e8d8bef9SDimitry Andric MOI = parseOperand(MOI, MOE, Locations, LiveOuts); // Flags 414e8d8bef9SDimitry Andric MOI = parseOperand(MOI, MOE, Locations, LiveOuts); // Num Deopts 415e8d8bef9SDimitry Andric 416e8d8bef9SDimitry Andric // Record Deopt Args. 417e8d8bef9SDimitry Andric unsigned NumDeoptArgs = Locations.back().Offset; 418e8d8bef9SDimitry Andric assert(Locations.back().Type == Location::Constant); 419e8d8bef9SDimitry Andric assert(NumDeoptArgs == SO.getNumDeoptArgs()); 420e8d8bef9SDimitry Andric 421e8d8bef9SDimitry Andric while (NumDeoptArgs--) 422e8d8bef9SDimitry Andric MOI = parseOperand(MOI, MOE, Locations, LiveOuts); 423e8d8bef9SDimitry Andric 424e8d8bef9SDimitry Andric // Record gc base/derived pairs 425e8d8bef9SDimitry Andric assert(MOI->isImm() && MOI->getImm() == StackMaps::ConstantOp); 426e8d8bef9SDimitry Andric ++MOI; 427e8d8bef9SDimitry Andric assert(MOI->isImm()); 428e8d8bef9SDimitry Andric unsigned NumGCPointers = MOI->getImm(); 429e8d8bef9SDimitry Andric ++MOI; 430e8d8bef9SDimitry Andric if (NumGCPointers) { 431e8d8bef9SDimitry Andric // Map logical index of GC ptr to MI operand index. 432e8d8bef9SDimitry Andric SmallVector<unsigned, 8> GCPtrIndices; 433e8d8bef9SDimitry Andric unsigned GCPtrIdx = (unsigned)SO.getFirstGCPtrIdx(); 434e8d8bef9SDimitry Andric assert((int)GCPtrIdx != -1); 435e8d8bef9SDimitry Andric assert(MOI - MI.operands_begin() == GCPtrIdx + 0LL); 436e8d8bef9SDimitry Andric while (NumGCPointers--) { 437e8d8bef9SDimitry Andric GCPtrIndices.push_back(GCPtrIdx); 438e8d8bef9SDimitry Andric GCPtrIdx = StackMaps::getNextMetaArgIdx(&MI, GCPtrIdx); 439e8d8bef9SDimitry Andric } 440e8d8bef9SDimitry Andric 441e8d8bef9SDimitry Andric SmallVector<std::pair<unsigned, unsigned>, 8> GCPairs; 442e8d8bef9SDimitry Andric unsigned NumGCPairs = SO.getGCPointerMap(GCPairs); 443e8d8bef9SDimitry Andric (void)NumGCPairs; 444e8d8bef9SDimitry Andric LLVM_DEBUG(dbgs() << "NumGCPairs = " << NumGCPairs << "\n"); 445e8d8bef9SDimitry Andric 446e8d8bef9SDimitry Andric auto MOB = MI.operands_begin(); 447e8d8bef9SDimitry Andric for (auto &P : GCPairs) { 448e8d8bef9SDimitry Andric assert(P.first < GCPtrIndices.size() && "base pointer index not found"); 449e8d8bef9SDimitry Andric assert(P.second < GCPtrIndices.size() && 450e8d8bef9SDimitry Andric "derived pointer index not found"); 451e8d8bef9SDimitry Andric unsigned BaseIdx = GCPtrIndices[P.first]; 452e8d8bef9SDimitry Andric unsigned DerivedIdx = GCPtrIndices[P.second]; 453e8d8bef9SDimitry Andric LLVM_DEBUG(dbgs() << "Base : " << BaseIdx << " Derived : " << DerivedIdx 454e8d8bef9SDimitry Andric << "\n"); 455e8d8bef9SDimitry Andric (void)parseOperand(MOB + BaseIdx, MOE, Locations, LiveOuts); 456e8d8bef9SDimitry Andric (void)parseOperand(MOB + DerivedIdx, MOE, Locations, LiveOuts); 457e8d8bef9SDimitry Andric } 458e8d8bef9SDimitry Andric 459e8d8bef9SDimitry Andric MOI = MOB + GCPtrIdx; 460e8d8bef9SDimitry Andric } 461e8d8bef9SDimitry Andric 462e8d8bef9SDimitry Andric // Record gc allocas 463e8d8bef9SDimitry Andric assert(MOI < MOE); 464e8d8bef9SDimitry Andric assert(MOI->isImm() && MOI->getImm() == StackMaps::ConstantOp); 465e8d8bef9SDimitry Andric ++MOI; 466e8d8bef9SDimitry Andric unsigned NumAllocas = MOI->getImm(); 467e8d8bef9SDimitry Andric ++MOI; 468e8d8bef9SDimitry Andric while (NumAllocas--) { 469e8d8bef9SDimitry Andric MOI = parseOperand(MOI, MOE, Locations, LiveOuts); 470e8d8bef9SDimitry Andric assert(MOI < MOE); 471e8d8bef9SDimitry Andric } 472e8d8bef9SDimitry Andric } 473e8d8bef9SDimitry Andric 474480093f4SDimitry Andric void StackMaps::recordStackMapOpers(const MCSymbol &MILabel, 475480093f4SDimitry Andric const MachineInstr &MI, uint64_t ID, 4760b57cec5SDimitry Andric MachineInstr::const_mop_iterator MOI, 4770b57cec5SDimitry Andric MachineInstr::const_mop_iterator MOE, 4780b57cec5SDimitry Andric bool recordResult) { 4790b57cec5SDimitry Andric MCContext &OutContext = AP.OutStreamer->getContext(); 4800b57cec5SDimitry Andric 4810b57cec5SDimitry Andric LocationVec Locations; 4820b57cec5SDimitry Andric LiveOutVec LiveOuts; 4830b57cec5SDimitry Andric 4840b57cec5SDimitry Andric if (recordResult) { 4850b57cec5SDimitry Andric assert(PatchPointOpers(&MI).hasDef() && "Stackmap has no return value."); 4860b57cec5SDimitry Andric parseOperand(MI.operands_begin(), std::next(MI.operands_begin()), Locations, 4870b57cec5SDimitry Andric LiveOuts); 4880b57cec5SDimitry Andric } 4890b57cec5SDimitry Andric 4900b57cec5SDimitry Andric // Parse operands. 491e8d8bef9SDimitry Andric if (MI.getOpcode() == TargetOpcode::STATEPOINT) 492e8d8bef9SDimitry Andric parseStatepointOpers(MI, MOI, MOE, Locations, LiveOuts); 493e8d8bef9SDimitry Andric else 494e8d8bef9SDimitry Andric while (MOI != MOE) 4950b57cec5SDimitry Andric MOI = parseOperand(MOI, MOE, Locations, LiveOuts); 4960b57cec5SDimitry Andric 4970b57cec5SDimitry Andric // Move large constants into the constant pool. 4980b57cec5SDimitry Andric for (auto &Loc : Locations) { 4990b57cec5SDimitry Andric // Constants are encoded as sign-extended integers. 5000b57cec5SDimitry Andric // -1 is directly encoded as .long 0xFFFFFFFF with no constant pool. 5010b57cec5SDimitry Andric if (Loc.Type == Location::Constant && !isInt<32>(Loc.Offset)) { 5020b57cec5SDimitry Andric Loc.Type = Location::ConstantIndex; 5030b57cec5SDimitry Andric // ConstPool is intentionally a MapVector of 'uint64_t's (as 5040b57cec5SDimitry Andric // opposed to 'int64_t's). We should never be in a situation 5050b57cec5SDimitry Andric // where we have to insert either the tombstone or the empty 5060b57cec5SDimitry Andric // keys into a map, and for a DenseMap<uint64_t, T> these are 5070b57cec5SDimitry Andric // (uint64_t)0 and (uint64_t)-1. They can be and are 5080b57cec5SDimitry Andric // represented using 32 bit integers. 5090b57cec5SDimitry Andric assert((uint64_t)Loc.Offset != DenseMapInfo<uint64_t>::getEmptyKey() && 5100b57cec5SDimitry Andric (uint64_t)Loc.Offset != 5110b57cec5SDimitry Andric DenseMapInfo<uint64_t>::getTombstoneKey() && 5120b57cec5SDimitry Andric "empty and tombstone keys should fit in 32 bits!"); 5130b57cec5SDimitry Andric auto Result = ConstPool.insert(std::make_pair(Loc.Offset, Loc.Offset)); 5140b57cec5SDimitry Andric Loc.Offset = Result.first - ConstPool.begin(); 5150b57cec5SDimitry Andric } 5160b57cec5SDimitry Andric } 5170b57cec5SDimitry Andric 5180b57cec5SDimitry Andric // Create an expression to calculate the offset of the callsite from function 5190b57cec5SDimitry Andric // entry. 5200b57cec5SDimitry Andric const MCExpr *CSOffsetExpr = MCBinaryExpr::createSub( 521480093f4SDimitry Andric MCSymbolRefExpr::create(&MILabel, OutContext), 5220b57cec5SDimitry Andric MCSymbolRefExpr::create(AP.CurrentFnSymForSize, OutContext), OutContext); 5230b57cec5SDimitry Andric 5240b57cec5SDimitry Andric CSInfos.emplace_back(CSOffsetExpr, ID, std::move(Locations), 5250b57cec5SDimitry Andric std::move(LiveOuts)); 5260b57cec5SDimitry Andric 5270b57cec5SDimitry Andric // Record the stack size of the current function and update callsite count. 5280b57cec5SDimitry Andric const MachineFrameInfo &MFI = AP.MF->getFrameInfo(); 5290b57cec5SDimitry Andric const TargetRegisterInfo *RegInfo = AP.MF->getSubtarget().getRegisterInfo(); 5300b57cec5SDimitry Andric bool HasDynamicFrameSize = 531fe6060f1SDimitry Andric MFI.hasVarSizedObjects() || RegInfo->hasStackRealignment(*(AP.MF)); 5320b57cec5SDimitry Andric uint64_t FrameSize = HasDynamicFrameSize ? UINT64_MAX : MFI.getStackSize(); 5330b57cec5SDimitry Andric 5340b57cec5SDimitry Andric auto CurrentIt = FnInfos.find(AP.CurrentFnSym); 5350b57cec5SDimitry Andric if (CurrentIt != FnInfos.end()) 5360b57cec5SDimitry Andric CurrentIt->second.RecordCount++; 5370b57cec5SDimitry Andric else 5380b57cec5SDimitry Andric FnInfos.insert(std::make_pair(AP.CurrentFnSym, FunctionInfo(FrameSize))); 5390b57cec5SDimitry Andric } 5400b57cec5SDimitry Andric 541480093f4SDimitry Andric void StackMaps::recordStackMap(const MCSymbol &L, const MachineInstr &MI) { 5420b57cec5SDimitry Andric assert(MI.getOpcode() == TargetOpcode::STACKMAP && "expected stackmap"); 5430b57cec5SDimitry Andric 5440b57cec5SDimitry Andric StackMapOpers opers(&MI); 5450b57cec5SDimitry Andric const int64_t ID = MI.getOperand(PatchPointOpers::IDPos).getImm(); 546480093f4SDimitry Andric recordStackMapOpers(L, MI, ID, std::next(MI.operands_begin(), 547480093f4SDimitry Andric opers.getVarIdx()), 5480b57cec5SDimitry Andric MI.operands_end()); 5490b57cec5SDimitry Andric } 5500b57cec5SDimitry Andric 551480093f4SDimitry Andric void StackMaps::recordPatchPoint(const MCSymbol &L, const MachineInstr &MI) { 5520b57cec5SDimitry Andric assert(MI.getOpcode() == TargetOpcode::PATCHPOINT && "expected patchpoint"); 5530b57cec5SDimitry Andric 5540b57cec5SDimitry Andric PatchPointOpers opers(&MI); 5550b57cec5SDimitry Andric const int64_t ID = opers.getID(); 5560b57cec5SDimitry Andric auto MOI = std::next(MI.operands_begin(), opers.getStackMapStartIdx()); 557480093f4SDimitry Andric recordStackMapOpers(L, MI, ID, MOI, MI.operands_end(), 5580b57cec5SDimitry Andric opers.isAnyReg() && opers.hasDef()); 5590b57cec5SDimitry Andric 5600b57cec5SDimitry Andric #ifndef NDEBUG 5610b57cec5SDimitry Andric // verify anyregcc 5620b57cec5SDimitry Andric auto &Locations = CSInfos.back().Locations; 5630b57cec5SDimitry Andric if (opers.isAnyReg()) { 5640b57cec5SDimitry Andric unsigned NArgs = opers.getNumCallArgs(); 5650b57cec5SDimitry Andric for (unsigned i = 0, e = (opers.hasDef() ? NArgs + 1 : NArgs); i != e; ++i) 5660b57cec5SDimitry Andric assert(Locations[i].Type == Location::Register && 5670b57cec5SDimitry Andric "anyreg arg must be in reg."); 5680b57cec5SDimitry Andric } 5690b57cec5SDimitry Andric #endif 5700b57cec5SDimitry Andric } 5710b57cec5SDimitry Andric 572480093f4SDimitry Andric void StackMaps::recordStatepoint(const MCSymbol &L, const MachineInstr &MI) { 5730b57cec5SDimitry Andric assert(MI.getOpcode() == TargetOpcode::STATEPOINT && "expected statepoint"); 5740b57cec5SDimitry Andric 5750b57cec5SDimitry Andric StatepointOpers opers(&MI); 5760b57cec5SDimitry Andric const unsigned StartIdx = opers.getVarIdx(); 577480093f4SDimitry Andric recordStackMapOpers(L, MI, opers.getID(), MI.operands_begin() + StartIdx, 5780b57cec5SDimitry Andric MI.operands_end(), false); 5790b57cec5SDimitry Andric } 5800b57cec5SDimitry Andric 5810b57cec5SDimitry Andric /// Emit the stackmap header. 5820b57cec5SDimitry Andric /// 5830b57cec5SDimitry Andric /// Header { 584e8d8bef9SDimitry Andric /// uint8 : Stack Map Version (currently 3) 5850b57cec5SDimitry Andric /// uint8 : Reserved (expected to be 0) 5860b57cec5SDimitry Andric /// uint16 : Reserved (expected to be 0) 5870b57cec5SDimitry Andric /// } 5880b57cec5SDimitry Andric /// uint32 : NumFunctions 5890b57cec5SDimitry Andric /// uint32 : NumConstants 5900b57cec5SDimitry Andric /// uint32 : NumRecords 5910b57cec5SDimitry Andric void StackMaps::emitStackmapHeader(MCStreamer &OS) { 5920b57cec5SDimitry Andric // Header. 5935ffd83dbSDimitry Andric OS.emitIntValue(StackMapVersion, 1); // Version. 5945ffd83dbSDimitry Andric OS.emitIntValue(0, 1); // Reserved. 5955ffd83dbSDimitry Andric OS.emitInt16(0); // Reserved. 5960b57cec5SDimitry Andric 5970b57cec5SDimitry Andric // Num functions. 5980b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << WSMP << "#functions = " << FnInfos.size() << '\n'); 5995ffd83dbSDimitry Andric OS.emitInt32(FnInfos.size()); 6000b57cec5SDimitry Andric // Num constants. 6010b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << WSMP << "#constants = " << ConstPool.size() << '\n'); 6025ffd83dbSDimitry Andric OS.emitInt32(ConstPool.size()); 6030b57cec5SDimitry Andric // Num callsites. 6040b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << WSMP << "#callsites = " << CSInfos.size() << '\n'); 6055ffd83dbSDimitry Andric OS.emitInt32(CSInfos.size()); 6060b57cec5SDimitry Andric } 6070b57cec5SDimitry Andric 6080b57cec5SDimitry Andric /// Emit the function frame record for each function. 6090b57cec5SDimitry Andric /// 6100b57cec5SDimitry Andric /// StkSizeRecord[NumFunctions] { 6110b57cec5SDimitry Andric /// uint64 : Function Address 6120b57cec5SDimitry Andric /// uint64 : Stack Size 6130b57cec5SDimitry Andric /// uint64 : Record Count 6140b57cec5SDimitry Andric /// } 6150b57cec5SDimitry Andric void StackMaps::emitFunctionFrameRecords(MCStreamer &OS) { 6160b57cec5SDimitry Andric // Function Frame records. 6170b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << WSMP << "functions:\n"); 6180b57cec5SDimitry Andric for (auto const &FR : FnInfos) { 6190b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << WSMP << "function addr: " << FR.first 6200b57cec5SDimitry Andric << " frame size: " << FR.second.StackSize 6210b57cec5SDimitry Andric << " callsite count: " << FR.second.RecordCount << '\n'); 6225ffd83dbSDimitry Andric OS.emitSymbolValue(FR.first, 8); 6235ffd83dbSDimitry Andric OS.emitIntValue(FR.second.StackSize, 8); 6245ffd83dbSDimitry Andric OS.emitIntValue(FR.second.RecordCount, 8); 6250b57cec5SDimitry Andric } 6260b57cec5SDimitry Andric } 6270b57cec5SDimitry Andric 6280b57cec5SDimitry Andric /// Emit the constant pool. 6290b57cec5SDimitry Andric /// 6300b57cec5SDimitry Andric /// int64 : Constants[NumConstants] 6310b57cec5SDimitry Andric void StackMaps::emitConstantPoolEntries(MCStreamer &OS) { 6320b57cec5SDimitry Andric // Constant pool entries. 6330b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << WSMP << "constants:\n"); 6340b57cec5SDimitry Andric for (const auto &ConstEntry : ConstPool) { 6350b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << WSMP << ConstEntry.second << '\n'); 6365ffd83dbSDimitry Andric OS.emitIntValue(ConstEntry.second, 8); 6370b57cec5SDimitry Andric } 6380b57cec5SDimitry Andric } 6390b57cec5SDimitry Andric 6400b57cec5SDimitry Andric /// Emit the callsite info for each callsite. 6410b57cec5SDimitry Andric /// 6420b57cec5SDimitry Andric /// StkMapRecord[NumRecords] { 6430b57cec5SDimitry Andric /// uint64 : PatchPoint ID 6440b57cec5SDimitry Andric /// uint32 : Instruction Offset 6450b57cec5SDimitry Andric /// uint16 : Reserved (record flags) 6460b57cec5SDimitry Andric /// uint16 : NumLocations 6470b57cec5SDimitry Andric /// Location[NumLocations] { 6480b57cec5SDimitry Andric /// uint8 : Register | Direct | Indirect | Constant | ConstantIndex 6490b57cec5SDimitry Andric /// uint8 : Size in Bytes 6500b57cec5SDimitry Andric /// uint16 : Dwarf RegNum 6510b57cec5SDimitry Andric /// int32 : Offset 6520b57cec5SDimitry Andric /// } 6530b57cec5SDimitry Andric /// uint16 : Padding 6540b57cec5SDimitry Andric /// uint16 : NumLiveOuts 6550b57cec5SDimitry Andric /// LiveOuts[NumLiveOuts] { 6560b57cec5SDimitry Andric /// uint16 : Dwarf RegNum 6570b57cec5SDimitry Andric /// uint8 : Reserved 6580b57cec5SDimitry Andric /// uint8 : Size in Bytes 6590b57cec5SDimitry Andric /// } 6600b57cec5SDimitry Andric /// uint32 : Padding (only if required to align to 8 byte) 6610b57cec5SDimitry Andric /// } 6620b57cec5SDimitry Andric /// 6630b57cec5SDimitry Andric /// Location Encoding, Type, Value: 6640b57cec5SDimitry Andric /// 0x1, Register, Reg (value in register) 6650b57cec5SDimitry Andric /// 0x2, Direct, Reg + Offset (frame index) 6660b57cec5SDimitry Andric /// 0x3, Indirect, [Reg + Offset] (spilled value) 6670b57cec5SDimitry Andric /// 0x4, Constant, Offset (small constant) 6680b57cec5SDimitry Andric /// 0x5, ConstIndex, Constants[Offset] (large constant) 6690b57cec5SDimitry Andric void StackMaps::emitCallsiteEntries(MCStreamer &OS) { 6700b57cec5SDimitry Andric LLVM_DEBUG(print(dbgs())); 6710b57cec5SDimitry Andric // Callsite entries. 6720b57cec5SDimitry Andric for (const auto &CSI : CSInfos) { 6730b57cec5SDimitry Andric const LocationVec &CSLocs = CSI.Locations; 6740b57cec5SDimitry Andric const LiveOutVec &LiveOuts = CSI.LiveOuts; 6750b57cec5SDimitry Andric 6760b57cec5SDimitry Andric // Verify stack map entry. It's better to communicate a problem to the 6770b57cec5SDimitry Andric // runtime than crash in case of in-process compilation. Currently, we do 6780b57cec5SDimitry Andric // simple overflow checks, but we may eventually communicate other 6790b57cec5SDimitry Andric // compilation errors this way. 6800b57cec5SDimitry Andric if (CSLocs.size() > UINT16_MAX || LiveOuts.size() > UINT16_MAX) { 6815ffd83dbSDimitry Andric OS.emitIntValue(UINT64_MAX, 8); // Invalid ID. 6825ffd83dbSDimitry Andric OS.emitValue(CSI.CSOffsetExpr, 4); 6835ffd83dbSDimitry Andric OS.emitInt16(0); // Reserved. 6845ffd83dbSDimitry Andric OS.emitInt16(0); // 0 locations. 6855ffd83dbSDimitry Andric OS.emitInt16(0); // padding. 6865ffd83dbSDimitry Andric OS.emitInt16(0); // 0 live-out registers. 6875ffd83dbSDimitry Andric OS.emitInt32(0); // padding. 6880b57cec5SDimitry Andric continue; 6890b57cec5SDimitry Andric } 6900b57cec5SDimitry Andric 6915ffd83dbSDimitry Andric OS.emitIntValue(CSI.ID, 8); 6925ffd83dbSDimitry Andric OS.emitValue(CSI.CSOffsetExpr, 4); 6930b57cec5SDimitry Andric 6940b57cec5SDimitry Andric // Reserved for flags. 6955ffd83dbSDimitry Andric OS.emitInt16(0); 6965ffd83dbSDimitry Andric OS.emitInt16(CSLocs.size()); 6970b57cec5SDimitry Andric 6980b57cec5SDimitry Andric for (const auto &Loc : CSLocs) { 6995ffd83dbSDimitry Andric OS.emitIntValue(Loc.Type, 1); 7005ffd83dbSDimitry Andric OS.emitIntValue(0, 1); // Reserved 7015ffd83dbSDimitry Andric OS.emitInt16(Loc.Size); 7025ffd83dbSDimitry Andric OS.emitInt16(Loc.Reg); 7035ffd83dbSDimitry Andric OS.emitInt16(0); // Reserved 7045ffd83dbSDimitry Andric OS.emitInt32(Loc.Offset); 7050b57cec5SDimitry Andric } 7060b57cec5SDimitry Andric 7070b57cec5SDimitry Andric // Emit alignment to 8 byte. 708*bdd1243dSDimitry Andric OS.emitValueToAlignment(Align(8)); 7090b57cec5SDimitry Andric 7100b57cec5SDimitry Andric // Num live-out registers and padding to align to 4 byte. 7115ffd83dbSDimitry Andric OS.emitInt16(0); 7125ffd83dbSDimitry Andric OS.emitInt16(LiveOuts.size()); 7130b57cec5SDimitry Andric 7140b57cec5SDimitry Andric for (const auto &LO : LiveOuts) { 7155ffd83dbSDimitry Andric OS.emitInt16(LO.DwarfRegNum); 7165ffd83dbSDimitry Andric OS.emitIntValue(0, 1); 7175ffd83dbSDimitry Andric OS.emitIntValue(LO.Size, 1); 7180b57cec5SDimitry Andric } 7190b57cec5SDimitry Andric // Emit alignment to 8 byte. 720*bdd1243dSDimitry Andric OS.emitValueToAlignment(Align(8)); 7210b57cec5SDimitry Andric } 7220b57cec5SDimitry Andric } 7230b57cec5SDimitry Andric 7240b57cec5SDimitry Andric /// Serialize the stackmap data. 7250b57cec5SDimitry Andric void StackMaps::serializeToStackMapSection() { 7260b57cec5SDimitry Andric (void)WSMP; 7270b57cec5SDimitry Andric // Bail out if there's no stack map data. 7280b57cec5SDimitry Andric assert((!CSInfos.empty() || ConstPool.empty()) && 7290b57cec5SDimitry Andric "Expected empty constant pool too!"); 7300b57cec5SDimitry Andric assert((!CSInfos.empty() || FnInfos.empty()) && 7310b57cec5SDimitry Andric "Expected empty function record too!"); 7320b57cec5SDimitry Andric if (CSInfos.empty()) 7330b57cec5SDimitry Andric return; 7340b57cec5SDimitry Andric 7350b57cec5SDimitry Andric MCContext &OutContext = AP.OutStreamer->getContext(); 7360b57cec5SDimitry Andric MCStreamer &OS = *AP.OutStreamer; 7370b57cec5SDimitry Andric 7380b57cec5SDimitry Andric // Create the section. 7390b57cec5SDimitry Andric MCSection *StackMapSection = 7400b57cec5SDimitry Andric OutContext.getObjectFileInfo()->getStackMapSection(); 74181ad6265SDimitry Andric OS.switchSection(StackMapSection); 7420b57cec5SDimitry Andric 7430b57cec5SDimitry Andric // Emit a dummy symbol to force section inclusion. 7445ffd83dbSDimitry Andric OS.emitLabel(OutContext.getOrCreateSymbol(Twine("__LLVM_StackMaps"))); 7450b57cec5SDimitry Andric 7460b57cec5SDimitry Andric // Serialize data. 7470b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "********** Stack Map Output **********\n"); 7480b57cec5SDimitry Andric emitStackmapHeader(OS); 7490b57cec5SDimitry Andric emitFunctionFrameRecords(OS); 7500b57cec5SDimitry Andric emitConstantPoolEntries(OS); 7510b57cec5SDimitry Andric emitCallsiteEntries(OS); 75281ad6265SDimitry Andric OS.addBlankLine(); 7530b57cec5SDimitry Andric 7540b57cec5SDimitry Andric // Clean up. 7550b57cec5SDimitry Andric CSInfos.clear(); 7560b57cec5SDimitry Andric ConstPool.clear(); 7570b57cec5SDimitry Andric } 758