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 1490b57cec5SDimitry Andric StackMaps::StackMaps(AsmPrinter &AP) : AP(AP) { 1500b57cec5SDimitry Andric if (StackMapVersion != 3) 1510b57cec5SDimitry Andric llvm_unreachable("Unsupported stackmap version!"); 1520b57cec5SDimitry Andric } 1530b57cec5SDimitry Andric 154e8d8bef9SDimitry Andric unsigned StackMaps::getNextMetaArgIdx(const MachineInstr *MI, unsigned CurIdx) { 155e8d8bef9SDimitry Andric assert(CurIdx < MI->getNumOperands() && "Bad meta arg index"); 156e8d8bef9SDimitry Andric const auto &MO = MI->getOperand(CurIdx); 157e8d8bef9SDimitry Andric if (MO.isImm()) { 158e8d8bef9SDimitry Andric switch (MO.getImm()) { 159e8d8bef9SDimitry Andric default: 160e8d8bef9SDimitry Andric llvm_unreachable("Unrecognized operand type."); 161e8d8bef9SDimitry Andric case StackMaps::DirectMemRefOp: 162e8d8bef9SDimitry Andric CurIdx += 2; 163e8d8bef9SDimitry Andric break; 164e8d8bef9SDimitry Andric case StackMaps::IndirectMemRefOp: 165e8d8bef9SDimitry Andric CurIdx += 3; 166e8d8bef9SDimitry Andric break; 167e8d8bef9SDimitry Andric case StackMaps::ConstantOp: 168e8d8bef9SDimitry Andric ++CurIdx; 169e8d8bef9SDimitry Andric break; 170e8d8bef9SDimitry Andric } 171e8d8bef9SDimitry Andric } 172e8d8bef9SDimitry Andric ++CurIdx; 173e8d8bef9SDimitry Andric assert(CurIdx < MI->getNumOperands() && "points past operand list"); 174e8d8bef9SDimitry Andric return CurIdx; 175e8d8bef9SDimitry Andric } 176e8d8bef9SDimitry Andric 1770b57cec5SDimitry Andric /// Go up the super-register chain until we hit a valid dwarf register number. 1780b57cec5SDimitry Andric static unsigned getDwarfRegNum(unsigned Reg, const TargetRegisterInfo *TRI) { 1790b57cec5SDimitry Andric int RegNum = TRI->getDwarfRegNum(Reg, false); 1800b57cec5SDimitry Andric for (MCSuperRegIterator SR(Reg, TRI); SR.isValid() && RegNum < 0; ++SR) 1810b57cec5SDimitry Andric RegNum = TRI->getDwarfRegNum(*SR, false); 1820b57cec5SDimitry Andric 1830b57cec5SDimitry Andric assert(RegNum >= 0 && "Invalid Dwarf register number."); 1840b57cec5SDimitry Andric return (unsigned)RegNum; 1850b57cec5SDimitry Andric } 1860b57cec5SDimitry Andric 1870b57cec5SDimitry Andric MachineInstr::const_mop_iterator 1880b57cec5SDimitry Andric StackMaps::parseOperand(MachineInstr::const_mop_iterator MOI, 1890b57cec5SDimitry Andric MachineInstr::const_mop_iterator MOE, LocationVec &Locs, 1900b57cec5SDimitry Andric LiveOutVec &LiveOuts) const { 1910b57cec5SDimitry Andric const TargetRegisterInfo *TRI = AP.MF->getSubtarget().getRegisterInfo(); 1920b57cec5SDimitry Andric if (MOI->isImm()) { 1930b57cec5SDimitry Andric switch (MOI->getImm()) { 1940b57cec5SDimitry Andric default: 1950b57cec5SDimitry Andric llvm_unreachable("Unrecognized operand type."); 1960b57cec5SDimitry Andric case StackMaps::DirectMemRefOp: { 1970b57cec5SDimitry Andric auto &DL = AP.MF->getDataLayout(); 1980b57cec5SDimitry Andric 1990b57cec5SDimitry Andric unsigned Size = DL.getPointerSizeInBits(); 2000b57cec5SDimitry Andric assert((Size % 8) == 0 && "Need pointer size in bytes."); 2010b57cec5SDimitry Andric Size /= 8; 2028bcb0991SDimitry Andric Register Reg = (++MOI)->getReg(); 2030b57cec5SDimitry Andric int64_t Imm = (++MOI)->getImm(); 2040b57cec5SDimitry Andric Locs.emplace_back(StackMaps::Location::Direct, Size, 2050b57cec5SDimitry Andric getDwarfRegNum(Reg, TRI), Imm); 2060b57cec5SDimitry Andric break; 2070b57cec5SDimitry Andric } 2080b57cec5SDimitry Andric case StackMaps::IndirectMemRefOp: { 2090b57cec5SDimitry Andric int64_t Size = (++MOI)->getImm(); 2100b57cec5SDimitry Andric assert(Size > 0 && "Need a valid size for indirect memory locations."); 2118bcb0991SDimitry Andric Register Reg = (++MOI)->getReg(); 2120b57cec5SDimitry Andric int64_t Imm = (++MOI)->getImm(); 2130b57cec5SDimitry Andric Locs.emplace_back(StackMaps::Location::Indirect, Size, 2140b57cec5SDimitry Andric getDwarfRegNum(Reg, TRI), Imm); 2150b57cec5SDimitry Andric break; 2160b57cec5SDimitry Andric } 2170b57cec5SDimitry Andric case StackMaps::ConstantOp: { 2180b57cec5SDimitry Andric ++MOI; 2190b57cec5SDimitry Andric assert(MOI->isImm() && "Expected constant operand."); 2200b57cec5SDimitry Andric int64_t Imm = MOI->getImm(); 2210b57cec5SDimitry Andric Locs.emplace_back(Location::Constant, sizeof(int64_t), 0, Imm); 2220b57cec5SDimitry Andric break; 2230b57cec5SDimitry Andric } 2240b57cec5SDimitry Andric } 2250b57cec5SDimitry Andric return ++MOI; 2260b57cec5SDimitry Andric } 2270b57cec5SDimitry Andric 2280b57cec5SDimitry Andric // The physical register number will ultimately be encoded as a DWARF regno. 2290b57cec5SDimitry Andric // The stack map also records the size of a spill slot that can hold the 2300b57cec5SDimitry Andric // register content. (The runtime can track the actual size of the data type 2310b57cec5SDimitry Andric // if it needs to.) 2320b57cec5SDimitry Andric if (MOI->isReg()) { 2330b57cec5SDimitry Andric // Skip implicit registers (this includes our scratch registers) 2340b57cec5SDimitry Andric if (MOI->isImplicit()) 2350b57cec5SDimitry Andric return ++MOI; 2360b57cec5SDimitry Andric 237e8d8bef9SDimitry Andric if (MOI->isUndef()) { 238e8d8bef9SDimitry Andric // Record `undef` register as constant. Use same value as ISel uses. 239e8d8bef9SDimitry Andric Locs.emplace_back(Location::Constant, sizeof(int64_t), 0, 0xFEFEFEFE); 240e8d8bef9SDimitry Andric return ++MOI; 241e8d8bef9SDimitry Andric } 242e8d8bef9SDimitry Andric 2438bcb0991SDimitry Andric assert(Register::isPhysicalRegister(MOI->getReg()) && 2440b57cec5SDimitry Andric "Virtreg operands should have been rewritten before now."); 2450b57cec5SDimitry Andric const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(MOI->getReg()); 2460b57cec5SDimitry Andric assert(!MOI->getSubReg() && "Physical subreg still around."); 2470b57cec5SDimitry Andric 2480b57cec5SDimitry Andric unsigned Offset = 0; 2490b57cec5SDimitry Andric unsigned DwarfRegNum = getDwarfRegNum(MOI->getReg(), TRI); 2508bcb0991SDimitry Andric unsigned LLVMRegNum = *TRI->getLLVMRegNum(DwarfRegNum, false); 2510b57cec5SDimitry Andric unsigned SubRegIdx = TRI->getSubRegIndex(LLVMRegNum, MOI->getReg()); 2520b57cec5SDimitry Andric if (SubRegIdx) 2530b57cec5SDimitry Andric Offset = TRI->getSubRegIdxOffset(SubRegIdx); 2540b57cec5SDimitry Andric 2550b57cec5SDimitry Andric Locs.emplace_back(Location::Register, TRI->getSpillSize(*RC), 2560b57cec5SDimitry Andric DwarfRegNum, Offset); 2570b57cec5SDimitry Andric return ++MOI; 2580b57cec5SDimitry Andric } 2590b57cec5SDimitry Andric 2600b57cec5SDimitry Andric if (MOI->isRegLiveOut()) 2610b57cec5SDimitry Andric LiveOuts = parseRegisterLiveOutMask(MOI->getRegLiveOut()); 2620b57cec5SDimitry Andric 2630b57cec5SDimitry Andric return ++MOI; 2640b57cec5SDimitry Andric } 2650b57cec5SDimitry Andric 2660b57cec5SDimitry Andric void StackMaps::print(raw_ostream &OS) { 2670b57cec5SDimitry Andric const TargetRegisterInfo *TRI = 2680b57cec5SDimitry Andric AP.MF ? AP.MF->getSubtarget().getRegisterInfo() : nullptr; 2690b57cec5SDimitry Andric OS << WSMP << "callsites:\n"; 2700b57cec5SDimitry Andric for (const auto &CSI : CSInfos) { 2710b57cec5SDimitry Andric const LocationVec &CSLocs = CSI.Locations; 2720b57cec5SDimitry Andric const LiveOutVec &LiveOuts = CSI.LiveOuts; 2730b57cec5SDimitry Andric 2740b57cec5SDimitry Andric OS << WSMP << "callsite " << CSI.ID << "\n"; 2750b57cec5SDimitry Andric OS << WSMP << " has " << CSLocs.size() << " locations\n"; 2760b57cec5SDimitry Andric 2770b57cec5SDimitry Andric unsigned Idx = 0; 2780b57cec5SDimitry Andric for (const auto &Loc : CSLocs) { 2790b57cec5SDimitry Andric OS << WSMP << "\t\tLoc " << Idx << ": "; 2800b57cec5SDimitry Andric switch (Loc.Type) { 2810b57cec5SDimitry Andric case Location::Unprocessed: 2820b57cec5SDimitry Andric OS << "<Unprocessed operand>"; 2830b57cec5SDimitry Andric break; 2840b57cec5SDimitry Andric case Location::Register: 2850b57cec5SDimitry Andric OS << "Register "; 2860b57cec5SDimitry Andric if (TRI) 2870b57cec5SDimitry Andric OS << printReg(Loc.Reg, TRI); 2880b57cec5SDimitry Andric else 2890b57cec5SDimitry Andric OS << Loc.Reg; 2900b57cec5SDimitry Andric break; 2910b57cec5SDimitry Andric case Location::Direct: 2920b57cec5SDimitry Andric OS << "Direct "; 2930b57cec5SDimitry Andric if (TRI) 2940b57cec5SDimitry Andric OS << printReg(Loc.Reg, TRI); 2950b57cec5SDimitry Andric else 2960b57cec5SDimitry Andric OS << Loc.Reg; 2970b57cec5SDimitry Andric if (Loc.Offset) 2980b57cec5SDimitry Andric OS << " + " << Loc.Offset; 2990b57cec5SDimitry Andric break; 3000b57cec5SDimitry Andric case Location::Indirect: 3010b57cec5SDimitry Andric OS << "Indirect "; 3020b57cec5SDimitry Andric if (TRI) 3030b57cec5SDimitry Andric OS << printReg(Loc.Reg, TRI); 3040b57cec5SDimitry Andric else 3050b57cec5SDimitry Andric OS << Loc.Reg; 3060b57cec5SDimitry Andric OS << "+" << Loc.Offset; 3070b57cec5SDimitry Andric break; 3080b57cec5SDimitry Andric case Location::Constant: 3090b57cec5SDimitry Andric OS << "Constant " << Loc.Offset; 3100b57cec5SDimitry Andric break; 3110b57cec5SDimitry Andric case Location::ConstantIndex: 3120b57cec5SDimitry Andric OS << "Constant Index " << Loc.Offset; 3130b57cec5SDimitry Andric break; 3140b57cec5SDimitry Andric } 3150b57cec5SDimitry Andric OS << "\t[encoding: .byte " << Loc.Type << ", .byte 0" 3160b57cec5SDimitry Andric << ", .short " << Loc.Size << ", .short " << Loc.Reg << ", .short 0" 3170b57cec5SDimitry Andric << ", .int " << Loc.Offset << "]\n"; 3180b57cec5SDimitry Andric Idx++; 3190b57cec5SDimitry Andric } 3200b57cec5SDimitry Andric 3210b57cec5SDimitry Andric OS << WSMP << "\thas " << LiveOuts.size() << " live-out registers\n"; 3220b57cec5SDimitry Andric 3230b57cec5SDimitry Andric Idx = 0; 3240b57cec5SDimitry Andric for (const auto &LO : LiveOuts) { 3250b57cec5SDimitry Andric OS << WSMP << "\t\tLO " << Idx << ": "; 3260b57cec5SDimitry Andric if (TRI) 3270b57cec5SDimitry Andric OS << printReg(LO.Reg, TRI); 3280b57cec5SDimitry Andric else 3290b57cec5SDimitry Andric OS << LO.Reg; 3300b57cec5SDimitry Andric OS << "\t[encoding: .short " << LO.DwarfRegNum << ", .byte 0, .byte " 3310b57cec5SDimitry Andric << LO.Size << "]\n"; 3320b57cec5SDimitry Andric Idx++; 3330b57cec5SDimitry Andric } 3340b57cec5SDimitry Andric } 3350b57cec5SDimitry Andric } 3360b57cec5SDimitry Andric 3370b57cec5SDimitry Andric /// Create a live-out register record for the given register Reg. 3380b57cec5SDimitry Andric StackMaps::LiveOutReg 3390b57cec5SDimitry Andric StackMaps::createLiveOutReg(unsigned Reg, const TargetRegisterInfo *TRI) const { 3400b57cec5SDimitry Andric unsigned DwarfRegNum = getDwarfRegNum(Reg, TRI); 3410b57cec5SDimitry Andric unsigned Size = TRI->getSpillSize(*TRI->getMinimalPhysRegClass(Reg)); 3420b57cec5SDimitry Andric return LiveOutReg(Reg, DwarfRegNum, Size); 3430b57cec5SDimitry Andric } 3440b57cec5SDimitry Andric 3450b57cec5SDimitry Andric /// Parse the register live-out mask and return a vector of live-out registers 3460b57cec5SDimitry Andric /// that need to be recorded in the stackmap. 3470b57cec5SDimitry Andric StackMaps::LiveOutVec 3480b57cec5SDimitry Andric StackMaps::parseRegisterLiveOutMask(const uint32_t *Mask) const { 3490b57cec5SDimitry Andric assert(Mask && "No register mask specified"); 3500b57cec5SDimitry Andric const TargetRegisterInfo *TRI = AP.MF->getSubtarget().getRegisterInfo(); 3510b57cec5SDimitry Andric LiveOutVec LiveOuts; 3520b57cec5SDimitry Andric 3530b57cec5SDimitry Andric // Create a LiveOutReg for each bit that is set in the register mask. 3540b57cec5SDimitry Andric for (unsigned Reg = 0, NumRegs = TRI->getNumRegs(); Reg != NumRegs; ++Reg) 355480093f4SDimitry Andric if ((Mask[Reg / 32] >> (Reg % 32)) & 1) 3560b57cec5SDimitry Andric LiveOuts.push_back(createLiveOutReg(Reg, TRI)); 3570b57cec5SDimitry Andric 3580b57cec5SDimitry Andric // We don't need to keep track of a register if its super-register is already 3590b57cec5SDimitry Andric // in the list. Merge entries that refer to the same dwarf register and use 3600b57cec5SDimitry Andric // the maximum size that needs to be spilled. 3610b57cec5SDimitry Andric 3620b57cec5SDimitry Andric llvm::sort(LiveOuts, [](const LiveOutReg &LHS, const LiveOutReg &RHS) { 3630b57cec5SDimitry Andric // Only sort by the dwarf register number. 3640b57cec5SDimitry Andric return LHS.DwarfRegNum < RHS.DwarfRegNum; 3650b57cec5SDimitry Andric }); 3660b57cec5SDimitry Andric 3670b57cec5SDimitry Andric for (auto I = LiveOuts.begin(), E = LiveOuts.end(); I != E; ++I) { 3680b57cec5SDimitry Andric for (auto II = std::next(I); II != E; ++II) { 3690b57cec5SDimitry Andric if (I->DwarfRegNum != II->DwarfRegNum) { 3700b57cec5SDimitry Andric // Skip all the now invalid entries. 3710b57cec5SDimitry Andric I = --II; 3720b57cec5SDimitry Andric break; 3730b57cec5SDimitry Andric } 3740b57cec5SDimitry Andric I->Size = std::max(I->Size, II->Size); 3750b57cec5SDimitry Andric if (TRI->isSuperRegister(I->Reg, II->Reg)) 3760b57cec5SDimitry Andric I->Reg = II->Reg; 3770b57cec5SDimitry Andric II->Reg = 0; // mark for deletion. 3780b57cec5SDimitry Andric } 3790b57cec5SDimitry Andric } 3800b57cec5SDimitry Andric 381e8d8bef9SDimitry Andric llvm::erase_if(LiveOuts, [](const LiveOutReg &LO) { return LO.Reg == 0; }); 3820b57cec5SDimitry Andric 3830b57cec5SDimitry Andric return LiveOuts; 3840b57cec5SDimitry Andric } 3850b57cec5SDimitry Andric 386e8d8bef9SDimitry Andric // See statepoint MI format description in StatepointOpers' class comment 387e8d8bef9SDimitry Andric // in include/llvm/CodeGen/StackMaps.h 388e8d8bef9SDimitry Andric void StackMaps::parseStatepointOpers(const MachineInstr &MI, 389e8d8bef9SDimitry Andric MachineInstr::const_mop_iterator MOI, 390e8d8bef9SDimitry Andric MachineInstr::const_mop_iterator MOE, 391e8d8bef9SDimitry Andric LocationVec &Locations, 392e8d8bef9SDimitry Andric LiveOutVec &LiveOuts) { 393e8d8bef9SDimitry Andric LLVM_DEBUG(dbgs() << "record statepoint : " << MI << "\n"); 394e8d8bef9SDimitry Andric StatepointOpers SO(&MI); 395e8d8bef9SDimitry Andric MOI = parseOperand(MOI, MOE, Locations, LiveOuts); // CC 396e8d8bef9SDimitry Andric MOI = parseOperand(MOI, MOE, Locations, LiveOuts); // Flags 397e8d8bef9SDimitry Andric MOI = parseOperand(MOI, MOE, Locations, LiveOuts); // Num Deopts 398e8d8bef9SDimitry Andric 399e8d8bef9SDimitry Andric // Record Deopt Args. 400e8d8bef9SDimitry Andric unsigned NumDeoptArgs = Locations.back().Offset; 401e8d8bef9SDimitry Andric assert(Locations.back().Type == Location::Constant); 402e8d8bef9SDimitry Andric assert(NumDeoptArgs == SO.getNumDeoptArgs()); 403e8d8bef9SDimitry Andric 404e8d8bef9SDimitry Andric while (NumDeoptArgs--) 405e8d8bef9SDimitry Andric MOI = parseOperand(MOI, MOE, Locations, LiveOuts); 406e8d8bef9SDimitry Andric 407e8d8bef9SDimitry Andric // Record gc base/derived pairs 408e8d8bef9SDimitry Andric assert(MOI->isImm() && MOI->getImm() == StackMaps::ConstantOp); 409e8d8bef9SDimitry Andric ++MOI; 410e8d8bef9SDimitry Andric assert(MOI->isImm()); 411e8d8bef9SDimitry Andric unsigned NumGCPointers = MOI->getImm(); 412e8d8bef9SDimitry Andric ++MOI; 413e8d8bef9SDimitry Andric if (NumGCPointers) { 414e8d8bef9SDimitry Andric // Map logical index of GC ptr to MI operand index. 415e8d8bef9SDimitry Andric SmallVector<unsigned, 8> GCPtrIndices; 416e8d8bef9SDimitry Andric unsigned GCPtrIdx = (unsigned)SO.getFirstGCPtrIdx(); 417e8d8bef9SDimitry Andric assert((int)GCPtrIdx != -1); 418e8d8bef9SDimitry Andric assert(MOI - MI.operands_begin() == GCPtrIdx + 0LL); 419e8d8bef9SDimitry Andric while (NumGCPointers--) { 420e8d8bef9SDimitry Andric GCPtrIndices.push_back(GCPtrIdx); 421e8d8bef9SDimitry Andric GCPtrIdx = StackMaps::getNextMetaArgIdx(&MI, GCPtrIdx); 422e8d8bef9SDimitry Andric } 423e8d8bef9SDimitry Andric 424e8d8bef9SDimitry Andric SmallVector<std::pair<unsigned, unsigned>, 8> GCPairs; 425e8d8bef9SDimitry Andric unsigned NumGCPairs = SO.getGCPointerMap(GCPairs); 426e8d8bef9SDimitry Andric (void)NumGCPairs; 427e8d8bef9SDimitry Andric LLVM_DEBUG(dbgs() << "NumGCPairs = " << NumGCPairs << "\n"); 428e8d8bef9SDimitry Andric 429e8d8bef9SDimitry Andric auto MOB = MI.operands_begin(); 430e8d8bef9SDimitry Andric for (auto &P : GCPairs) { 431e8d8bef9SDimitry Andric assert(P.first < GCPtrIndices.size() && "base pointer index not found"); 432e8d8bef9SDimitry Andric assert(P.second < GCPtrIndices.size() && 433e8d8bef9SDimitry Andric "derived pointer index not found"); 434e8d8bef9SDimitry Andric unsigned BaseIdx = GCPtrIndices[P.first]; 435e8d8bef9SDimitry Andric unsigned DerivedIdx = GCPtrIndices[P.second]; 436e8d8bef9SDimitry Andric LLVM_DEBUG(dbgs() << "Base : " << BaseIdx << " Derived : " << DerivedIdx 437e8d8bef9SDimitry Andric << "\n"); 438e8d8bef9SDimitry Andric (void)parseOperand(MOB + BaseIdx, MOE, Locations, LiveOuts); 439e8d8bef9SDimitry Andric (void)parseOperand(MOB + DerivedIdx, MOE, Locations, LiveOuts); 440e8d8bef9SDimitry Andric } 441e8d8bef9SDimitry Andric 442e8d8bef9SDimitry Andric MOI = MOB + GCPtrIdx; 443e8d8bef9SDimitry Andric } 444e8d8bef9SDimitry Andric 445e8d8bef9SDimitry Andric // Record gc allocas 446e8d8bef9SDimitry Andric assert(MOI < MOE); 447e8d8bef9SDimitry Andric assert(MOI->isImm() && MOI->getImm() == StackMaps::ConstantOp); 448e8d8bef9SDimitry Andric ++MOI; 449e8d8bef9SDimitry Andric unsigned NumAllocas = MOI->getImm(); 450e8d8bef9SDimitry Andric ++MOI; 451e8d8bef9SDimitry Andric while (NumAllocas--) { 452e8d8bef9SDimitry Andric MOI = parseOperand(MOI, MOE, Locations, LiveOuts); 453e8d8bef9SDimitry Andric assert(MOI < MOE); 454e8d8bef9SDimitry Andric } 455e8d8bef9SDimitry Andric } 456e8d8bef9SDimitry Andric 457480093f4SDimitry Andric void StackMaps::recordStackMapOpers(const MCSymbol &MILabel, 458480093f4SDimitry Andric const MachineInstr &MI, uint64_t ID, 4590b57cec5SDimitry Andric MachineInstr::const_mop_iterator MOI, 4600b57cec5SDimitry Andric MachineInstr::const_mop_iterator MOE, 4610b57cec5SDimitry Andric bool recordResult) { 4620b57cec5SDimitry Andric MCContext &OutContext = AP.OutStreamer->getContext(); 4630b57cec5SDimitry Andric 4640b57cec5SDimitry Andric LocationVec Locations; 4650b57cec5SDimitry Andric LiveOutVec LiveOuts; 4660b57cec5SDimitry Andric 4670b57cec5SDimitry Andric if (recordResult) { 4680b57cec5SDimitry Andric assert(PatchPointOpers(&MI).hasDef() && "Stackmap has no return value."); 4690b57cec5SDimitry Andric parseOperand(MI.operands_begin(), std::next(MI.operands_begin()), Locations, 4700b57cec5SDimitry Andric LiveOuts); 4710b57cec5SDimitry Andric } 4720b57cec5SDimitry Andric 4730b57cec5SDimitry Andric // Parse operands. 474e8d8bef9SDimitry Andric if (MI.getOpcode() == TargetOpcode::STATEPOINT) 475e8d8bef9SDimitry Andric parseStatepointOpers(MI, MOI, MOE, Locations, LiveOuts); 476e8d8bef9SDimitry Andric else 477e8d8bef9SDimitry Andric while (MOI != MOE) 4780b57cec5SDimitry Andric MOI = parseOperand(MOI, MOE, Locations, LiveOuts); 4790b57cec5SDimitry Andric 4800b57cec5SDimitry Andric // Move large constants into the constant pool. 4810b57cec5SDimitry Andric for (auto &Loc : Locations) { 4820b57cec5SDimitry Andric // Constants are encoded as sign-extended integers. 4830b57cec5SDimitry Andric // -1 is directly encoded as .long 0xFFFFFFFF with no constant pool. 4840b57cec5SDimitry Andric if (Loc.Type == Location::Constant && !isInt<32>(Loc.Offset)) { 4850b57cec5SDimitry Andric Loc.Type = Location::ConstantIndex; 4860b57cec5SDimitry Andric // ConstPool is intentionally a MapVector of 'uint64_t's (as 4870b57cec5SDimitry Andric // opposed to 'int64_t's). We should never be in a situation 4880b57cec5SDimitry Andric // where we have to insert either the tombstone or the empty 4890b57cec5SDimitry Andric // keys into a map, and for a DenseMap<uint64_t, T> these are 4900b57cec5SDimitry Andric // (uint64_t)0 and (uint64_t)-1. They can be and are 4910b57cec5SDimitry Andric // represented using 32 bit integers. 4920b57cec5SDimitry Andric assert((uint64_t)Loc.Offset != DenseMapInfo<uint64_t>::getEmptyKey() && 4930b57cec5SDimitry Andric (uint64_t)Loc.Offset != 4940b57cec5SDimitry Andric DenseMapInfo<uint64_t>::getTombstoneKey() && 4950b57cec5SDimitry Andric "empty and tombstone keys should fit in 32 bits!"); 4960b57cec5SDimitry Andric auto Result = ConstPool.insert(std::make_pair(Loc.Offset, Loc.Offset)); 4970b57cec5SDimitry Andric Loc.Offset = Result.first - ConstPool.begin(); 4980b57cec5SDimitry Andric } 4990b57cec5SDimitry Andric } 5000b57cec5SDimitry Andric 5010b57cec5SDimitry Andric // Create an expression to calculate the offset of the callsite from function 5020b57cec5SDimitry Andric // entry. 5030b57cec5SDimitry Andric const MCExpr *CSOffsetExpr = MCBinaryExpr::createSub( 504480093f4SDimitry Andric MCSymbolRefExpr::create(&MILabel, OutContext), 5050b57cec5SDimitry Andric MCSymbolRefExpr::create(AP.CurrentFnSymForSize, OutContext), OutContext); 5060b57cec5SDimitry Andric 5070b57cec5SDimitry Andric CSInfos.emplace_back(CSOffsetExpr, ID, std::move(Locations), 5080b57cec5SDimitry Andric std::move(LiveOuts)); 5090b57cec5SDimitry Andric 5100b57cec5SDimitry Andric // Record the stack size of the current function and update callsite count. 5110b57cec5SDimitry Andric const MachineFrameInfo &MFI = AP.MF->getFrameInfo(); 5120b57cec5SDimitry Andric const TargetRegisterInfo *RegInfo = AP.MF->getSubtarget().getRegisterInfo(); 5130b57cec5SDimitry Andric bool HasDynamicFrameSize = 514fe6060f1SDimitry Andric MFI.hasVarSizedObjects() || RegInfo->hasStackRealignment(*(AP.MF)); 5150b57cec5SDimitry Andric uint64_t FrameSize = HasDynamicFrameSize ? UINT64_MAX : MFI.getStackSize(); 5160b57cec5SDimitry Andric 5170b57cec5SDimitry Andric auto CurrentIt = FnInfos.find(AP.CurrentFnSym); 5180b57cec5SDimitry Andric if (CurrentIt != FnInfos.end()) 5190b57cec5SDimitry Andric CurrentIt->second.RecordCount++; 5200b57cec5SDimitry Andric else 5210b57cec5SDimitry Andric FnInfos.insert(std::make_pair(AP.CurrentFnSym, FunctionInfo(FrameSize))); 5220b57cec5SDimitry Andric } 5230b57cec5SDimitry Andric 524480093f4SDimitry Andric void StackMaps::recordStackMap(const MCSymbol &L, const MachineInstr &MI) { 5250b57cec5SDimitry Andric assert(MI.getOpcode() == TargetOpcode::STACKMAP && "expected stackmap"); 5260b57cec5SDimitry Andric 5270b57cec5SDimitry Andric StackMapOpers opers(&MI); 5280b57cec5SDimitry Andric const int64_t ID = MI.getOperand(PatchPointOpers::IDPos).getImm(); 529480093f4SDimitry Andric recordStackMapOpers(L, MI, ID, std::next(MI.operands_begin(), 530480093f4SDimitry Andric opers.getVarIdx()), 5310b57cec5SDimitry Andric MI.operands_end()); 5320b57cec5SDimitry Andric } 5330b57cec5SDimitry Andric 534480093f4SDimitry Andric void StackMaps::recordPatchPoint(const MCSymbol &L, const MachineInstr &MI) { 5350b57cec5SDimitry Andric assert(MI.getOpcode() == TargetOpcode::PATCHPOINT && "expected patchpoint"); 5360b57cec5SDimitry Andric 5370b57cec5SDimitry Andric PatchPointOpers opers(&MI); 5380b57cec5SDimitry Andric const int64_t ID = opers.getID(); 5390b57cec5SDimitry Andric auto MOI = std::next(MI.operands_begin(), opers.getStackMapStartIdx()); 540480093f4SDimitry Andric recordStackMapOpers(L, MI, ID, MOI, MI.operands_end(), 5410b57cec5SDimitry Andric opers.isAnyReg() && opers.hasDef()); 5420b57cec5SDimitry Andric 5430b57cec5SDimitry Andric #ifndef NDEBUG 5440b57cec5SDimitry Andric // verify anyregcc 5450b57cec5SDimitry Andric auto &Locations = CSInfos.back().Locations; 5460b57cec5SDimitry Andric if (opers.isAnyReg()) { 5470b57cec5SDimitry Andric unsigned NArgs = opers.getNumCallArgs(); 5480b57cec5SDimitry Andric for (unsigned i = 0, e = (opers.hasDef() ? NArgs + 1 : NArgs); i != e; ++i) 5490b57cec5SDimitry Andric assert(Locations[i].Type == Location::Register && 5500b57cec5SDimitry Andric "anyreg arg must be in reg."); 5510b57cec5SDimitry Andric } 5520b57cec5SDimitry Andric #endif 5530b57cec5SDimitry Andric } 5540b57cec5SDimitry Andric 555480093f4SDimitry Andric void StackMaps::recordStatepoint(const MCSymbol &L, const MachineInstr &MI) { 5560b57cec5SDimitry Andric assert(MI.getOpcode() == TargetOpcode::STATEPOINT && "expected statepoint"); 5570b57cec5SDimitry Andric 5580b57cec5SDimitry Andric StatepointOpers opers(&MI); 5590b57cec5SDimitry Andric const unsigned StartIdx = opers.getVarIdx(); 560480093f4SDimitry Andric recordStackMapOpers(L, MI, opers.getID(), MI.operands_begin() + StartIdx, 5610b57cec5SDimitry Andric MI.operands_end(), false); 5620b57cec5SDimitry Andric } 5630b57cec5SDimitry Andric 5640b57cec5SDimitry Andric /// Emit the stackmap header. 5650b57cec5SDimitry Andric /// 5660b57cec5SDimitry Andric /// Header { 567e8d8bef9SDimitry Andric /// uint8 : Stack Map Version (currently 3) 5680b57cec5SDimitry Andric /// uint8 : Reserved (expected to be 0) 5690b57cec5SDimitry Andric /// uint16 : Reserved (expected to be 0) 5700b57cec5SDimitry Andric /// } 5710b57cec5SDimitry Andric /// uint32 : NumFunctions 5720b57cec5SDimitry Andric /// uint32 : NumConstants 5730b57cec5SDimitry Andric /// uint32 : NumRecords 5740b57cec5SDimitry Andric void StackMaps::emitStackmapHeader(MCStreamer &OS) { 5750b57cec5SDimitry Andric // Header. 5765ffd83dbSDimitry Andric OS.emitIntValue(StackMapVersion, 1); // Version. 5775ffd83dbSDimitry Andric OS.emitIntValue(0, 1); // Reserved. 5785ffd83dbSDimitry Andric OS.emitInt16(0); // Reserved. 5790b57cec5SDimitry Andric 5800b57cec5SDimitry Andric // Num functions. 5810b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << WSMP << "#functions = " << FnInfos.size() << '\n'); 5825ffd83dbSDimitry Andric OS.emitInt32(FnInfos.size()); 5830b57cec5SDimitry Andric // Num constants. 5840b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << WSMP << "#constants = " << ConstPool.size() << '\n'); 5855ffd83dbSDimitry Andric OS.emitInt32(ConstPool.size()); 5860b57cec5SDimitry Andric // Num callsites. 5870b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << WSMP << "#callsites = " << CSInfos.size() << '\n'); 5885ffd83dbSDimitry Andric OS.emitInt32(CSInfos.size()); 5890b57cec5SDimitry Andric } 5900b57cec5SDimitry Andric 5910b57cec5SDimitry Andric /// Emit the function frame record for each function. 5920b57cec5SDimitry Andric /// 5930b57cec5SDimitry Andric /// StkSizeRecord[NumFunctions] { 5940b57cec5SDimitry Andric /// uint64 : Function Address 5950b57cec5SDimitry Andric /// uint64 : Stack Size 5960b57cec5SDimitry Andric /// uint64 : Record Count 5970b57cec5SDimitry Andric /// } 5980b57cec5SDimitry Andric void StackMaps::emitFunctionFrameRecords(MCStreamer &OS) { 5990b57cec5SDimitry Andric // Function Frame records. 6000b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << WSMP << "functions:\n"); 6010b57cec5SDimitry Andric for (auto const &FR : FnInfos) { 6020b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << WSMP << "function addr: " << FR.first 6030b57cec5SDimitry Andric << " frame size: " << FR.second.StackSize 6040b57cec5SDimitry Andric << " callsite count: " << FR.second.RecordCount << '\n'); 6055ffd83dbSDimitry Andric OS.emitSymbolValue(FR.first, 8); 6065ffd83dbSDimitry Andric OS.emitIntValue(FR.second.StackSize, 8); 6075ffd83dbSDimitry Andric OS.emitIntValue(FR.second.RecordCount, 8); 6080b57cec5SDimitry Andric } 6090b57cec5SDimitry Andric } 6100b57cec5SDimitry Andric 6110b57cec5SDimitry Andric /// Emit the constant pool. 6120b57cec5SDimitry Andric /// 6130b57cec5SDimitry Andric /// int64 : Constants[NumConstants] 6140b57cec5SDimitry Andric void StackMaps::emitConstantPoolEntries(MCStreamer &OS) { 6150b57cec5SDimitry Andric // Constant pool entries. 6160b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << WSMP << "constants:\n"); 6170b57cec5SDimitry Andric for (const auto &ConstEntry : ConstPool) { 6180b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << WSMP << ConstEntry.second << '\n'); 6195ffd83dbSDimitry Andric OS.emitIntValue(ConstEntry.second, 8); 6200b57cec5SDimitry Andric } 6210b57cec5SDimitry Andric } 6220b57cec5SDimitry Andric 6230b57cec5SDimitry Andric /// Emit the callsite info for each callsite. 6240b57cec5SDimitry Andric /// 6250b57cec5SDimitry Andric /// StkMapRecord[NumRecords] { 6260b57cec5SDimitry Andric /// uint64 : PatchPoint ID 6270b57cec5SDimitry Andric /// uint32 : Instruction Offset 6280b57cec5SDimitry Andric /// uint16 : Reserved (record flags) 6290b57cec5SDimitry Andric /// uint16 : NumLocations 6300b57cec5SDimitry Andric /// Location[NumLocations] { 6310b57cec5SDimitry Andric /// uint8 : Register | Direct | Indirect | Constant | ConstantIndex 6320b57cec5SDimitry Andric /// uint8 : Size in Bytes 6330b57cec5SDimitry Andric /// uint16 : Dwarf RegNum 6340b57cec5SDimitry Andric /// int32 : Offset 6350b57cec5SDimitry Andric /// } 6360b57cec5SDimitry Andric /// uint16 : Padding 6370b57cec5SDimitry Andric /// uint16 : NumLiveOuts 6380b57cec5SDimitry Andric /// LiveOuts[NumLiveOuts] { 6390b57cec5SDimitry Andric /// uint16 : Dwarf RegNum 6400b57cec5SDimitry Andric /// uint8 : Reserved 6410b57cec5SDimitry Andric /// uint8 : Size in Bytes 6420b57cec5SDimitry Andric /// } 6430b57cec5SDimitry Andric /// uint32 : Padding (only if required to align to 8 byte) 6440b57cec5SDimitry Andric /// } 6450b57cec5SDimitry Andric /// 6460b57cec5SDimitry Andric /// Location Encoding, Type, Value: 6470b57cec5SDimitry Andric /// 0x1, Register, Reg (value in register) 6480b57cec5SDimitry Andric /// 0x2, Direct, Reg + Offset (frame index) 6490b57cec5SDimitry Andric /// 0x3, Indirect, [Reg + Offset] (spilled value) 6500b57cec5SDimitry Andric /// 0x4, Constant, Offset (small constant) 6510b57cec5SDimitry Andric /// 0x5, ConstIndex, Constants[Offset] (large constant) 6520b57cec5SDimitry Andric void StackMaps::emitCallsiteEntries(MCStreamer &OS) { 6530b57cec5SDimitry Andric LLVM_DEBUG(print(dbgs())); 6540b57cec5SDimitry Andric // Callsite entries. 6550b57cec5SDimitry Andric for (const auto &CSI : CSInfos) { 6560b57cec5SDimitry Andric const LocationVec &CSLocs = CSI.Locations; 6570b57cec5SDimitry Andric const LiveOutVec &LiveOuts = CSI.LiveOuts; 6580b57cec5SDimitry Andric 6590b57cec5SDimitry Andric // Verify stack map entry. It's better to communicate a problem to the 6600b57cec5SDimitry Andric // runtime than crash in case of in-process compilation. Currently, we do 6610b57cec5SDimitry Andric // simple overflow checks, but we may eventually communicate other 6620b57cec5SDimitry Andric // compilation errors this way. 6630b57cec5SDimitry Andric if (CSLocs.size() > UINT16_MAX || LiveOuts.size() > UINT16_MAX) { 6645ffd83dbSDimitry Andric OS.emitIntValue(UINT64_MAX, 8); // Invalid ID. 6655ffd83dbSDimitry Andric OS.emitValue(CSI.CSOffsetExpr, 4); 6665ffd83dbSDimitry Andric OS.emitInt16(0); // Reserved. 6675ffd83dbSDimitry Andric OS.emitInt16(0); // 0 locations. 6685ffd83dbSDimitry Andric OS.emitInt16(0); // padding. 6695ffd83dbSDimitry Andric OS.emitInt16(0); // 0 live-out registers. 6705ffd83dbSDimitry Andric OS.emitInt32(0); // padding. 6710b57cec5SDimitry Andric continue; 6720b57cec5SDimitry Andric } 6730b57cec5SDimitry Andric 6745ffd83dbSDimitry Andric OS.emitIntValue(CSI.ID, 8); 6755ffd83dbSDimitry Andric OS.emitValue(CSI.CSOffsetExpr, 4); 6760b57cec5SDimitry Andric 6770b57cec5SDimitry Andric // Reserved for flags. 6785ffd83dbSDimitry Andric OS.emitInt16(0); 6795ffd83dbSDimitry Andric OS.emitInt16(CSLocs.size()); 6800b57cec5SDimitry Andric 6810b57cec5SDimitry Andric for (const auto &Loc : CSLocs) { 6825ffd83dbSDimitry Andric OS.emitIntValue(Loc.Type, 1); 6835ffd83dbSDimitry Andric OS.emitIntValue(0, 1); // Reserved 6845ffd83dbSDimitry Andric OS.emitInt16(Loc.Size); 6855ffd83dbSDimitry Andric OS.emitInt16(Loc.Reg); 6865ffd83dbSDimitry Andric OS.emitInt16(0); // Reserved 6875ffd83dbSDimitry Andric OS.emitInt32(Loc.Offset); 6880b57cec5SDimitry Andric } 6890b57cec5SDimitry Andric 6900b57cec5SDimitry Andric // Emit alignment to 8 byte. 6915ffd83dbSDimitry Andric OS.emitValueToAlignment(8); 6920b57cec5SDimitry Andric 6930b57cec5SDimitry Andric // Num live-out registers and padding to align to 4 byte. 6945ffd83dbSDimitry Andric OS.emitInt16(0); 6955ffd83dbSDimitry Andric OS.emitInt16(LiveOuts.size()); 6960b57cec5SDimitry Andric 6970b57cec5SDimitry Andric for (const auto &LO : LiveOuts) { 6985ffd83dbSDimitry Andric OS.emitInt16(LO.DwarfRegNum); 6995ffd83dbSDimitry Andric OS.emitIntValue(0, 1); 7005ffd83dbSDimitry Andric OS.emitIntValue(LO.Size, 1); 7010b57cec5SDimitry Andric } 7020b57cec5SDimitry Andric // Emit alignment to 8 byte. 7035ffd83dbSDimitry Andric OS.emitValueToAlignment(8); 7040b57cec5SDimitry Andric } 7050b57cec5SDimitry Andric } 7060b57cec5SDimitry Andric 7070b57cec5SDimitry Andric /// Serialize the stackmap data. 7080b57cec5SDimitry Andric void StackMaps::serializeToStackMapSection() { 7090b57cec5SDimitry Andric (void)WSMP; 7100b57cec5SDimitry Andric // Bail out if there's no stack map data. 7110b57cec5SDimitry Andric assert((!CSInfos.empty() || ConstPool.empty()) && 7120b57cec5SDimitry Andric "Expected empty constant pool too!"); 7130b57cec5SDimitry Andric assert((!CSInfos.empty() || FnInfos.empty()) && 7140b57cec5SDimitry Andric "Expected empty function record too!"); 7150b57cec5SDimitry Andric if (CSInfos.empty()) 7160b57cec5SDimitry Andric return; 7170b57cec5SDimitry Andric 7180b57cec5SDimitry Andric MCContext &OutContext = AP.OutStreamer->getContext(); 7190b57cec5SDimitry Andric MCStreamer &OS = *AP.OutStreamer; 7200b57cec5SDimitry Andric 7210b57cec5SDimitry Andric // Create the section. 7220b57cec5SDimitry Andric MCSection *StackMapSection = 7230b57cec5SDimitry Andric OutContext.getObjectFileInfo()->getStackMapSection(); 724*81ad6265SDimitry Andric OS.switchSection(StackMapSection); 7250b57cec5SDimitry Andric 7260b57cec5SDimitry Andric // Emit a dummy symbol to force section inclusion. 7275ffd83dbSDimitry Andric OS.emitLabel(OutContext.getOrCreateSymbol(Twine("__LLVM_StackMaps"))); 7280b57cec5SDimitry Andric 7290b57cec5SDimitry Andric // Serialize data. 7300b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "********** Stack Map Output **********\n"); 7310b57cec5SDimitry Andric emitStackmapHeader(OS); 7320b57cec5SDimitry Andric emitFunctionFrameRecords(OS); 7330b57cec5SDimitry Andric emitConstantPoolEntries(OS); 7340b57cec5SDimitry Andric emitCallsiteEntries(OS); 735*81ad6265SDimitry Andric OS.addBlankLine(); 7360b57cec5SDimitry Andric 7370b57cec5SDimitry Andric // Clean up. 7380b57cec5SDimitry Andric CSInfos.clear(); 7390b57cec5SDimitry Andric ConstPool.clear(); 7400b57cec5SDimitry Andric } 741