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 149bdd1243dSDimitry Andric bool StatepointOpers::isFoldableReg(Register Reg) const { 150bdd1243dSDimitry Andric unsigned FoldableAreaStart = getVarIdx(); 151bdd1243dSDimitry Andric for (const MachineOperand &MO : MI->uses()) { 15206c3fb27SDimitry Andric if (MO.getOperandNo() >= FoldableAreaStart) 153bdd1243dSDimitry Andric break; 154bdd1243dSDimitry Andric if (MO.isReg() && MO.getReg() == Reg) 155bdd1243dSDimitry Andric return false; 156bdd1243dSDimitry Andric } 157bdd1243dSDimitry Andric return true; 158bdd1243dSDimitry Andric } 159bdd1243dSDimitry Andric 160bdd1243dSDimitry Andric bool StatepointOpers::isFoldableReg(const MachineInstr *MI, Register Reg) { 161bdd1243dSDimitry Andric if (MI->getOpcode() != TargetOpcode::STATEPOINT) 162bdd1243dSDimitry Andric return false; 163bdd1243dSDimitry Andric return StatepointOpers(MI).isFoldableReg(Reg); 164bdd1243dSDimitry Andric } 165bdd1243dSDimitry 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) { 19606c3fb27SDimitry Andric int RegNum; 19706c3fb27SDimitry Andric for (MCPhysReg SR : TRI->superregs_inclusive(Reg)) { 19806c3fb27SDimitry Andric RegNum = TRI->getDwarfRegNum(SR, false); 19906c3fb27SDimitry Andric if (RegNum >= 0) 20006c3fb27SDimitry Andric break; 20106c3fb27SDimitry Andric } 2020b57cec5SDimitry Andric 203*7a6dacacSDimitry Andric assert(RegNum >= 0 && isUInt<16>(RegNum) && "Invalid Dwarf register number."); 2040b57cec5SDimitry Andric return (unsigned)RegNum; 2050b57cec5SDimitry Andric } 2060b57cec5SDimitry Andric 2070b57cec5SDimitry Andric MachineInstr::const_mop_iterator 2080b57cec5SDimitry Andric StackMaps::parseOperand(MachineInstr::const_mop_iterator MOI, 2090b57cec5SDimitry Andric MachineInstr::const_mop_iterator MOE, LocationVec &Locs, 210*7a6dacacSDimitry Andric LiveOutVec &LiveOuts) { 2110b57cec5SDimitry Andric const TargetRegisterInfo *TRI = AP.MF->getSubtarget().getRegisterInfo(); 2120b57cec5SDimitry Andric if (MOI->isImm()) { 2130b57cec5SDimitry Andric switch (MOI->getImm()) { 2140b57cec5SDimitry Andric default: 2150b57cec5SDimitry Andric llvm_unreachable("Unrecognized operand type."); 2160b57cec5SDimitry Andric case StackMaps::DirectMemRefOp: { 2170b57cec5SDimitry Andric auto &DL = AP.MF->getDataLayout(); 2180b57cec5SDimitry Andric 2190b57cec5SDimitry Andric unsigned Size = DL.getPointerSizeInBits(); 2200b57cec5SDimitry Andric assert((Size % 8) == 0 && "Need pointer size in bytes."); 2210b57cec5SDimitry Andric Size /= 8; 2228bcb0991SDimitry Andric Register Reg = (++MOI)->getReg(); 2230b57cec5SDimitry Andric int64_t Imm = (++MOI)->getImm(); 2240b57cec5SDimitry Andric Locs.emplace_back(StackMaps::Location::Direct, Size, 2250b57cec5SDimitry Andric getDwarfRegNum(Reg, TRI), Imm); 2260b57cec5SDimitry Andric break; 2270b57cec5SDimitry Andric } 2280b57cec5SDimitry Andric case StackMaps::IndirectMemRefOp: { 2290b57cec5SDimitry Andric int64_t Size = (++MOI)->getImm(); 2300b57cec5SDimitry Andric assert(Size > 0 && "Need a valid size for indirect memory locations."); 2318bcb0991SDimitry Andric Register Reg = (++MOI)->getReg(); 2320b57cec5SDimitry Andric int64_t Imm = (++MOI)->getImm(); 2330b57cec5SDimitry Andric Locs.emplace_back(StackMaps::Location::Indirect, Size, 2340b57cec5SDimitry Andric getDwarfRegNum(Reg, TRI), Imm); 2350b57cec5SDimitry Andric break; 2360b57cec5SDimitry Andric } 2370b57cec5SDimitry Andric case StackMaps::ConstantOp: { 2380b57cec5SDimitry Andric ++MOI; 2390b57cec5SDimitry Andric assert(MOI->isImm() && "Expected constant operand."); 2400b57cec5SDimitry Andric int64_t Imm = MOI->getImm(); 241*7a6dacacSDimitry Andric if (isInt<32>(Imm)) { 2420b57cec5SDimitry Andric Locs.emplace_back(Location::Constant, sizeof(int64_t), 0, Imm); 243*7a6dacacSDimitry Andric } else { 244*7a6dacacSDimitry Andric // ConstPool is intentionally a MapVector of 'uint64_t's (as 245*7a6dacacSDimitry Andric // opposed to 'int64_t's). We should never be in a situation 246*7a6dacacSDimitry Andric // where we have to insert either the tombstone or the empty 247*7a6dacacSDimitry Andric // keys into a map, and for a DenseMap<uint64_t, T> these are 248*7a6dacacSDimitry Andric // (uint64_t)0 and (uint64_t)-1. They can be and are 249*7a6dacacSDimitry Andric // represented using 32 bit integers. 250*7a6dacacSDimitry Andric assert((uint64_t)Imm != DenseMapInfo<uint64_t>::getEmptyKey() && 251*7a6dacacSDimitry Andric (uint64_t)Imm != DenseMapInfo<uint64_t>::getTombstoneKey() && 252*7a6dacacSDimitry Andric "empty and tombstone keys should fit in 32 bits!"); 253*7a6dacacSDimitry Andric auto Result = ConstPool.insert(std::make_pair(Imm, Imm)); 254*7a6dacacSDimitry Andric Locs.emplace_back(Location::ConstantIndex, sizeof(int64_t), 0, 255*7a6dacacSDimitry Andric Result.first - ConstPool.begin()); 256*7a6dacacSDimitry Andric } 2570b57cec5SDimitry Andric break; 2580b57cec5SDimitry Andric } 2590b57cec5SDimitry Andric } 2600b57cec5SDimitry Andric return ++MOI; 2610b57cec5SDimitry Andric } 2620b57cec5SDimitry Andric 2630b57cec5SDimitry Andric // The physical register number will ultimately be encoded as a DWARF regno. 2640b57cec5SDimitry Andric // The stack map also records the size of a spill slot that can hold the 2650b57cec5SDimitry Andric // register content. (The runtime can track the actual size of the data type 2660b57cec5SDimitry Andric // if it needs to.) 2670b57cec5SDimitry Andric if (MOI->isReg()) { 2680b57cec5SDimitry Andric // Skip implicit registers (this includes our scratch registers) 2690b57cec5SDimitry Andric if (MOI->isImplicit()) 2700b57cec5SDimitry Andric return ++MOI; 2710b57cec5SDimitry Andric 272e8d8bef9SDimitry Andric if (MOI->isUndef()) { 273e8d8bef9SDimitry Andric // Record `undef` register as constant. Use same value as ISel uses. 274e8d8bef9SDimitry Andric Locs.emplace_back(Location::Constant, sizeof(int64_t), 0, 0xFEFEFEFE); 275e8d8bef9SDimitry Andric return ++MOI; 276e8d8bef9SDimitry Andric } 277e8d8bef9SDimitry Andric 278bdd1243dSDimitry Andric assert(MOI->getReg().isPhysical() && 2790b57cec5SDimitry Andric "Virtreg operands should have been rewritten before now."); 2800b57cec5SDimitry Andric const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(MOI->getReg()); 2810b57cec5SDimitry Andric assert(!MOI->getSubReg() && "Physical subreg still around."); 2820b57cec5SDimitry Andric 2830b57cec5SDimitry Andric unsigned Offset = 0; 2840b57cec5SDimitry Andric unsigned DwarfRegNum = getDwarfRegNum(MOI->getReg(), TRI); 2858bcb0991SDimitry Andric unsigned LLVMRegNum = *TRI->getLLVMRegNum(DwarfRegNum, false); 2860b57cec5SDimitry Andric unsigned SubRegIdx = TRI->getSubRegIndex(LLVMRegNum, MOI->getReg()); 2870b57cec5SDimitry Andric if (SubRegIdx) 2880b57cec5SDimitry Andric Offset = TRI->getSubRegIdxOffset(SubRegIdx); 2890b57cec5SDimitry Andric 2900b57cec5SDimitry Andric Locs.emplace_back(Location::Register, TRI->getSpillSize(*RC), 2910b57cec5SDimitry Andric DwarfRegNum, Offset); 2920b57cec5SDimitry Andric return ++MOI; 2930b57cec5SDimitry Andric } 2940b57cec5SDimitry Andric 2950b57cec5SDimitry Andric if (MOI->isRegLiveOut()) 2960b57cec5SDimitry Andric LiveOuts = parseRegisterLiveOutMask(MOI->getRegLiveOut()); 2970b57cec5SDimitry Andric 2980b57cec5SDimitry Andric return ++MOI; 2990b57cec5SDimitry Andric } 3000b57cec5SDimitry Andric 3010b57cec5SDimitry Andric void StackMaps::print(raw_ostream &OS) { 3020b57cec5SDimitry Andric const TargetRegisterInfo *TRI = 3030b57cec5SDimitry Andric AP.MF ? AP.MF->getSubtarget().getRegisterInfo() : nullptr; 3040b57cec5SDimitry Andric OS << WSMP << "callsites:\n"; 3050b57cec5SDimitry Andric for (const auto &CSI : CSInfos) { 3060b57cec5SDimitry Andric const LocationVec &CSLocs = CSI.Locations; 3070b57cec5SDimitry Andric const LiveOutVec &LiveOuts = CSI.LiveOuts; 3080b57cec5SDimitry Andric 3090b57cec5SDimitry Andric OS << WSMP << "callsite " << CSI.ID << "\n"; 3100b57cec5SDimitry Andric OS << WSMP << " has " << CSLocs.size() << " locations\n"; 3110b57cec5SDimitry Andric 3120b57cec5SDimitry Andric unsigned Idx = 0; 3130b57cec5SDimitry Andric for (const auto &Loc : CSLocs) { 3140b57cec5SDimitry Andric OS << WSMP << "\t\tLoc " << Idx << ": "; 3150b57cec5SDimitry Andric switch (Loc.Type) { 3160b57cec5SDimitry Andric case Location::Unprocessed: 3170b57cec5SDimitry Andric OS << "<Unprocessed operand>"; 3180b57cec5SDimitry Andric break; 3190b57cec5SDimitry Andric case Location::Register: 3200b57cec5SDimitry Andric OS << "Register "; 3210b57cec5SDimitry Andric if (TRI) 3220b57cec5SDimitry Andric OS << printReg(Loc.Reg, TRI); 3230b57cec5SDimitry Andric else 3240b57cec5SDimitry Andric OS << Loc.Reg; 3250b57cec5SDimitry Andric break; 3260b57cec5SDimitry Andric case Location::Direct: 3270b57cec5SDimitry Andric OS << "Direct "; 3280b57cec5SDimitry Andric if (TRI) 3290b57cec5SDimitry Andric OS << printReg(Loc.Reg, TRI); 3300b57cec5SDimitry Andric else 3310b57cec5SDimitry Andric OS << Loc.Reg; 3320b57cec5SDimitry Andric if (Loc.Offset) 3330b57cec5SDimitry Andric OS << " + " << Loc.Offset; 3340b57cec5SDimitry Andric break; 3350b57cec5SDimitry Andric case Location::Indirect: 3360b57cec5SDimitry Andric OS << "Indirect "; 3370b57cec5SDimitry Andric if (TRI) 3380b57cec5SDimitry Andric OS << printReg(Loc.Reg, TRI); 3390b57cec5SDimitry Andric else 3400b57cec5SDimitry Andric OS << Loc.Reg; 3410b57cec5SDimitry Andric OS << "+" << Loc.Offset; 3420b57cec5SDimitry Andric break; 3430b57cec5SDimitry Andric case Location::Constant: 3440b57cec5SDimitry Andric OS << "Constant " << Loc.Offset; 3450b57cec5SDimitry Andric break; 3460b57cec5SDimitry Andric case Location::ConstantIndex: 3470b57cec5SDimitry Andric OS << "Constant Index " << Loc.Offset; 3480b57cec5SDimitry Andric break; 3490b57cec5SDimitry Andric } 3500b57cec5SDimitry Andric OS << "\t[encoding: .byte " << Loc.Type << ", .byte 0" 3510b57cec5SDimitry Andric << ", .short " << Loc.Size << ", .short " << Loc.Reg << ", .short 0" 3520b57cec5SDimitry Andric << ", .int " << Loc.Offset << "]\n"; 3530b57cec5SDimitry Andric Idx++; 3540b57cec5SDimitry Andric } 3550b57cec5SDimitry Andric 3560b57cec5SDimitry Andric OS << WSMP << "\thas " << LiveOuts.size() << " live-out registers\n"; 3570b57cec5SDimitry Andric 3580b57cec5SDimitry Andric Idx = 0; 3590b57cec5SDimitry Andric for (const auto &LO : LiveOuts) { 3600b57cec5SDimitry Andric OS << WSMP << "\t\tLO " << Idx << ": "; 3610b57cec5SDimitry Andric if (TRI) 3620b57cec5SDimitry Andric OS << printReg(LO.Reg, TRI); 3630b57cec5SDimitry Andric else 3640b57cec5SDimitry Andric OS << LO.Reg; 3650b57cec5SDimitry Andric OS << "\t[encoding: .short " << LO.DwarfRegNum << ", .byte 0, .byte " 3660b57cec5SDimitry Andric << LO.Size << "]\n"; 3670b57cec5SDimitry Andric Idx++; 3680b57cec5SDimitry Andric } 3690b57cec5SDimitry Andric } 3700b57cec5SDimitry Andric } 3710b57cec5SDimitry Andric 3720b57cec5SDimitry Andric /// Create a live-out register record for the given register Reg. 3730b57cec5SDimitry Andric StackMaps::LiveOutReg 3740b57cec5SDimitry Andric StackMaps::createLiveOutReg(unsigned Reg, const TargetRegisterInfo *TRI) const { 3750b57cec5SDimitry Andric unsigned DwarfRegNum = getDwarfRegNum(Reg, TRI); 3760b57cec5SDimitry Andric unsigned Size = TRI->getSpillSize(*TRI->getMinimalPhysRegClass(Reg)); 3770b57cec5SDimitry Andric return LiveOutReg(Reg, DwarfRegNum, Size); 3780b57cec5SDimitry Andric } 3790b57cec5SDimitry Andric 3800b57cec5SDimitry Andric /// Parse the register live-out mask and return a vector of live-out registers 3810b57cec5SDimitry Andric /// that need to be recorded in the stackmap. 3820b57cec5SDimitry Andric StackMaps::LiveOutVec 3830b57cec5SDimitry Andric StackMaps::parseRegisterLiveOutMask(const uint32_t *Mask) const { 3840b57cec5SDimitry Andric assert(Mask && "No register mask specified"); 3850b57cec5SDimitry Andric const TargetRegisterInfo *TRI = AP.MF->getSubtarget().getRegisterInfo(); 3860b57cec5SDimitry Andric LiveOutVec LiveOuts; 3870b57cec5SDimitry Andric 3880b57cec5SDimitry Andric // Create a LiveOutReg for each bit that is set in the register mask. 3890b57cec5SDimitry Andric for (unsigned Reg = 0, NumRegs = TRI->getNumRegs(); Reg != NumRegs; ++Reg) 390480093f4SDimitry Andric if ((Mask[Reg / 32] >> (Reg % 32)) & 1) 3910b57cec5SDimitry Andric LiveOuts.push_back(createLiveOutReg(Reg, TRI)); 3920b57cec5SDimitry Andric 3930b57cec5SDimitry Andric // We don't need to keep track of a register if its super-register is already 3940b57cec5SDimitry Andric // in the list. Merge entries that refer to the same dwarf register and use 3950b57cec5SDimitry Andric // the maximum size that needs to be spilled. 3960b57cec5SDimitry Andric 3970b57cec5SDimitry Andric llvm::sort(LiveOuts, [](const LiveOutReg &LHS, const LiveOutReg &RHS) { 3980b57cec5SDimitry Andric // Only sort by the dwarf register number. 3990b57cec5SDimitry Andric return LHS.DwarfRegNum < RHS.DwarfRegNum; 4000b57cec5SDimitry Andric }); 4010b57cec5SDimitry Andric 4020b57cec5SDimitry Andric for (auto I = LiveOuts.begin(), E = LiveOuts.end(); I != E; ++I) { 403fcaf7f86SDimitry Andric for (auto *II = std::next(I); II != E; ++II) { 4040b57cec5SDimitry Andric if (I->DwarfRegNum != II->DwarfRegNum) { 4050b57cec5SDimitry Andric // Skip all the now invalid entries. 4060b57cec5SDimitry Andric I = --II; 4070b57cec5SDimitry Andric break; 4080b57cec5SDimitry Andric } 4090b57cec5SDimitry Andric I->Size = std::max(I->Size, II->Size); 41006c3fb27SDimitry Andric if (I->Reg && TRI->isSuperRegister(I->Reg, II->Reg)) 4110b57cec5SDimitry Andric I->Reg = II->Reg; 4120b57cec5SDimitry Andric II->Reg = 0; // mark for deletion. 4130b57cec5SDimitry Andric } 4140b57cec5SDimitry Andric } 4150b57cec5SDimitry Andric 416e8d8bef9SDimitry Andric llvm::erase_if(LiveOuts, [](const LiveOutReg &LO) { return LO.Reg == 0; }); 4170b57cec5SDimitry Andric 4180b57cec5SDimitry Andric return LiveOuts; 4190b57cec5SDimitry Andric } 4200b57cec5SDimitry Andric 421e8d8bef9SDimitry Andric // See statepoint MI format description in StatepointOpers' class comment 422e8d8bef9SDimitry Andric // in include/llvm/CodeGen/StackMaps.h 423e8d8bef9SDimitry Andric void StackMaps::parseStatepointOpers(const MachineInstr &MI, 424e8d8bef9SDimitry Andric MachineInstr::const_mop_iterator MOI, 425e8d8bef9SDimitry Andric MachineInstr::const_mop_iterator MOE, 426e8d8bef9SDimitry Andric LocationVec &Locations, 427e8d8bef9SDimitry Andric LiveOutVec &LiveOuts) { 428e8d8bef9SDimitry Andric LLVM_DEBUG(dbgs() << "record statepoint : " << MI << "\n"); 429e8d8bef9SDimitry Andric StatepointOpers SO(&MI); 430e8d8bef9SDimitry Andric MOI = parseOperand(MOI, MOE, Locations, LiveOuts); // CC 431e8d8bef9SDimitry Andric MOI = parseOperand(MOI, MOE, Locations, LiveOuts); // Flags 432e8d8bef9SDimitry Andric MOI = parseOperand(MOI, MOE, Locations, LiveOuts); // Num Deopts 433e8d8bef9SDimitry Andric 434e8d8bef9SDimitry Andric // Record Deopt Args. 435e8d8bef9SDimitry Andric unsigned NumDeoptArgs = Locations.back().Offset; 436e8d8bef9SDimitry Andric assert(Locations.back().Type == Location::Constant); 437e8d8bef9SDimitry Andric assert(NumDeoptArgs == SO.getNumDeoptArgs()); 438e8d8bef9SDimitry Andric 439e8d8bef9SDimitry Andric while (NumDeoptArgs--) 440e8d8bef9SDimitry Andric MOI = parseOperand(MOI, MOE, Locations, LiveOuts); 441e8d8bef9SDimitry Andric 442e8d8bef9SDimitry Andric // Record gc base/derived pairs 443e8d8bef9SDimitry Andric assert(MOI->isImm() && MOI->getImm() == StackMaps::ConstantOp); 444e8d8bef9SDimitry Andric ++MOI; 445e8d8bef9SDimitry Andric assert(MOI->isImm()); 446e8d8bef9SDimitry Andric unsigned NumGCPointers = MOI->getImm(); 447e8d8bef9SDimitry Andric ++MOI; 448e8d8bef9SDimitry Andric if (NumGCPointers) { 449e8d8bef9SDimitry Andric // Map logical index of GC ptr to MI operand index. 450e8d8bef9SDimitry Andric SmallVector<unsigned, 8> GCPtrIndices; 451e8d8bef9SDimitry Andric unsigned GCPtrIdx = (unsigned)SO.getFirstGCPtrIdx(); 452e8d8bef9SDimitry Andric assert((int)GCPtrIdx != -1); 453e8d8bef9SDimitry Andric assert(MOI - MI.operands_begin() == GCPtrIdx + 0LL); 454e8d8bef9SDimitry Andric while (NumGCPointers--) { 455e8d8bef9SDimitry Andric GCPtrIndices.push_back(GCPtrIdx); 456e8d8bef9SDimitry Andric GCPtrIdx = StackMaps::getNextMetaArgIdx(&MI, GCPtrIdx); 457e8d8bef9SDimitry Andric } 458e8d8bef9SDimitry Andric 459e8d8bef9SDimitry Andric SmallVector<std::pair<unsigned, unsigned>, 8> GCPairs; 460e8d8bef9SDimitry Andric unsigned NumGCPairs = SO.getGCPointerMap(GCPairs); 461e8d8bef9SDimitry Andric (void)NumGCPairs; 462e8d8bef9SDimitry Andric LLVM_DEBUG(dbgs() << "NumGCPairs = " << NumGCPairs << "\n"); 463e8d8bef9SDimitry Andric 464e8d8bef9SDimitry Andric auto MOB = MI.operands_begin(); 465e8d8bef9SDimitry Andric for (auto &P : GCPairs) { 466e8d8bef9SDimitry Andric assert(P.first < GCPtrIndices.size() && "base pointer index not found"); 467e8d8bef9SDimitry Andric assert(P.second < GCPtrIndices.size() && 468e8d8bef9SDimitry Andric "derived pointer index not found"); 469e8d8bef9SDimitry Andric unsigned BaseIdx = GCPtrIndices[P.first]; 470e8d8bef9SDimitry Andric unsigned DerivedIdx = GCPtrIndices[P.second]; 471e8d8bef9SDimitry Andric LLVM_DEBUG(dbgs() << "Base : " << BaseIdx << " Derived : " << DerivedIdx 472e8d8bef9SDimitry Andric << "\n"); 473e8d8bef9SDimitry Andric (void)parseOperand(MOB + BaseIdx, MOE, Locations, LiveOuts); 474e8d8bef9SDimitry Andric (void)parseOperand(MOB + DerivedIdx, MOE, Locations, LiveOuts); 475e8d8bef9SDimitry Andric } 476e8d8bef9SDimitry Andric 477e8d8bef9SDimitry Andric MOI = MOB + GCPtrIdx; 478e8d8bef9SDimitry Andric } 479e8d8bef9SDimitry Andric 480e8d8bef9SDimitry Andric // Record gc allocas 481e8d8bef9SDimitry Andric assert(MOI < MOE); 482e8d8bef9SDimitry Andric assert(MOI->isImm() && MOI->getImm() == StackMaps::ConstantOp); 483e8d8bef9SDimitry Andric ++MOI; 484e8d8bef9SDimitry Andric unsigned NumAllocas = MOI->getImm(); 485e8d8bef9SDimitry Andric ++MOI; 486e8d8bef9SDimitry Andric while (NumAllocas--) { 487e8d8bef9SDimitry Andric MOI = parseOperand(MOI, MOE, Locations, LiveOuts); 488e8d8bef9SDimitry Andric assert(MOI < MOE); 489e8d8bef9SDimitry Andric } 490e8d8bef9SDimitry Andric } 491e8d8bef9SDimitry Andric 492480093f4SDimitry Andric void StackMaps::recordStackMapOpers(const MCSymbol &MILabel, 493480093f4SDimitry Andric const MachineInstr &MI, uint64_t ID, 4940b57cec5SDimitry Andric MachineInstr::const_mop_iterator MOI, 4950b57cec5SDimitry Andric MachineInstr::const_mop_iterator MOE, 4960b57cec5SDimitry Andric bool recordResult) { 4970b57cec5SDimitry Andric MCContext &OutContext = AP.OutStreamer->getContext(); 4980b57cec5SDimitry Andric 4990b57cec5SDimitry Andric LocationVec Locations; 5000b57cec5SDimitry Andric LiveOutVec LiveOuts; 5010b57cec5SDimitry Andric 5020b57cec5SDimitry Andric if (recordResult) { 5030b57cec5SDimitry Andric assert(PatchPointOpers(&MI).hasDef() && "Stackmap has no return value."); 5040b57cec5SDimitry Andric parseOperand(MI.operands_begin(), std::next(MI.operands_begin()), Locations, 5050b57cec5SDimitry Andric LiveOuts); 5060b57cec5SDimitry Andric } 5070b57cec5SDimitry Andric 5080b57cec5SDimitry Andric // Parse operands. 509e8d8bef9SDimitry Andric if (MI.getOpcode() == TargetOpcode::STATEPOINT) 510e8d8bef9SDimitry Andric parseStatepointOpers(MI, MOI, MOE, Locations, LiveOuts); 511e8d8bef9SDimitry Andric else 512e8d8bef9SDimitry Andric while (MOI != MOE) 5130b57cec5SDimitry Andric MOI = parseOperand(MOI, MOE, Locations, LiveOuts); 5140b57cec5SDimitry Andric 5150b57cec5SDimitry Andric // Create an expression to calculate the offset of the callsite from function 5160b57cec5SDimitry Andric // entry. 5170b57cec5SDimitry Andric const MCExpr *CSOffsetExpr = MCBinaryExpr::createSub( 518480093f4SDimitry Andric MCSymbolRefExpr::create(&MILabel, OutContext), 5190b57cec5SDimitry Andric MCSymbolRefExpr::create(AP.CurrentFnSymForSize, OutContext), OutContext); 5200b57cec5SDimitry Andric 5210b57cec5SDimitry Andric CSInfos.emplace_back(CSOffsetExpr, ID, std::move(Locations), 5220b57cec5SDimitry Andric std::move(LiveOuts)); 5230b57cec5SDimitry Andric 5240b57cec5SDimitry Andric // Record the stack size of the current function and update callsite count. 5250b57cec5SDimitry Andric const MachineFrameInfo &MFI = AP.MF->getFrameInfo(); 5260b57cec5SDimitry Andric const TargetRegisterInfo *RegInfo = AP.MF->getSubtarget().getRegisterInfo(); 5270b57cec5SDimitry Andric bool HasDynamicFrameSize = 528fe6060f1SDimitry Andric MFI.hasVarSizedObjects() || RegInfo->hasStackRealignment(*(AP.MF)); 5290b57cec5SDimitry Andric uint64_t FrameSize = HasDynamicFrameSize ? UINT64_MAX : MFI.getStackSize(); 5300b57cec5SDimitry Andric 5310b57cec5SDimitry Andric auto CurrentIt = FnInfos.find(AP.CurrentFnSym); 5320b57cec5SDimitry Andric if (CurrentIt != FnInfos.end()) 5330b57cec5SDimitry Andric CurrentIt->second.RecordCount++; 5340b57cec5SDimitry Andric else 5350b57cec5SDimitry Andric FnInfos.insert(std::make_pair(AP.CurrentFnSym, FunctionInfo(FrameSize))); 5360b57cec5SDimitry Andric } 5370b57cec5SDimitry Andric 538480093f4SDimitry Andric void StackMaps::recordStackMap(const MCSymbol &L, const MachineInstr &MI) { 5390b57cec5SDimitry Andric assert(MI.getOpcode() == TargetOpcode::STACKMAP && "expected stackmap"); 5400b57cec5SDimitry Andric 5410b57cec5SDimitry Andric StackMapOpers opers(&MI); 5420b57cec5SDimitry Andric const int64_t ID = MI.getOperand(PatchPointOpers::IDPos).getImm(); 543480093f4SDimitry Andric recordStackMapOpers(L, MI, ID, std::next(MI.operands_begin(), 544480093f4SDimitry Andric opers.getVarIdx()), 5450b57cec5SDimitry Andric MI.operands_end()); 5460b57cec5SDimitry Andric } 5470b57cec5SDimitry Andric 548480093f4SDimitry Andric void StackMaps::recordPatchPoint(const MCSymbol &L, const MachineInstr &MI) { 5490b57cec5SDimitry Andric assert(MI.getOpcode() == TargetOpcode::PATCHPOINT && "expected patchpoint"); 5500b57cec5SDimitry Andric 5510b57cec5SDimitry Andric PatchPointOpers opers(&MI); 5520b57cec5SDimitry Andric const int64_t ID = opers.getID(); 5530b57cec5SDimitry Andric auto MOI = std::next(MI.operands_begin(), opers.getStackMapStartIdx()); 554480093f4SDimitry Andric recordStackMapOpers(L, MI, ID, MOI, MI.operands_end(), 5550b57cec5SDimitry Andric opers.isAnyReg() && opers.hasDef()); 5560b57cec5SDimitry Andric 5570b57cec5SDimitry Andric #ifndef NDEBUG 5580b57cec5SDimitry Andric // verify anyregcc 5590b57cec5SDimitry Andric auto &Locations = CSInfos.back().Locations; 5600b57cec5SDimitry Andric if (opers.isAnyReg()) { 5610b57cec5SDimitry Andric unsigned NArgs = opers.getNumCallArgs(); 5620b57cec5SDimitry Andric for (unsigned i = 0, e = (opers.hasDef() ? NArgs + 1 : NArgs); i != e; ++i) 5630b57cec5SDimitry Andric assert(Locations[i].Type == Location::Register && 5640b57cec5SDimitry Andric "anyreg arg must be in reg."); 5650b57cec5SDimitry Andric } 5660b57cec5SDimitry Andric #endif 5670b57cec5SDimitry Andric } 5680b57cec5SDimitry Andric 569480093f4SDimitry Andric void StackMaps::recordStatepoint(const MCSymbol &L, const MachineInstr &MI) { 5700b57cec5SDimitry Andric assert(MI.getOpcode() == TargetOpcode::STATEPOINT && "expected statepoint"); 5710b57cec5SDimitry Andric 5720b57cec5SDimitry Andric StatepointOpers opers(&MI); 5730b57cec5SDimitry Andric const unsigned StartIdx = opers.getVarIdx(); 574480093f4SDimitry Andric recordStackMapOpers(L, MI, opers.getID(), MI.operands_begin() + StartIdx, 5750b57cec5SDimitry Andric MI.operands_end(), false); 5760b57cec5SDimitry Andric } 5770b57cec5SDimitry Andric 5780b57cec5SDimitry Andric /// Emit the stackmap header. 5790b57cec5SDimitry Andric /// 5800b57cec5SDimitry Andric /// Header { 581e8d8bef9SDimitry Andric /// uint8 : Stack Map Version (currently 3) 5820b57cec5SDimitry Andric /// uint8 : Reserved (expected to be 0) 5830b57cec5SDimitry Andric /// uint16 : Reserved (expected to be 0) 5840b57cec5SDimitry Andric /// } 5850b57cec5SDimitry Andric /// uint32 : NumFunctions 5860b57cec5SDimitry Andric /// uint32 : NumConstants 5870b57cec5SDimitry Andric /// uint32 : NumRecords 5880b57cec5SDimitry Andric void StackMaps::emitStackmapHeader(MCStreamer &OS) { 5890b57cec5SDimitry Andric // Header. 5905ffd83dbSDimitry Andric OS.emitIntValue(StackMapVersion, 1); // Version. 5915ffd83dbSDimitry Andric OS.emitIntValue(0, 1); // Reserved. 5925ffd83dbSDimitry Andric OS.emitInt16(0); // Reserved. 5930b57cec5SDimitry Andric 5940b57cec5SDimitry Andric // Num functions. 5950b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << WSMP << "#functions = " << FnInfos.size() << '\n'); 5965ffd83dbSDimitry Andric OS.emitInt32(FnInfos.size()); 5970b57cec5SDimitry Andric // Num constants. 5980b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << WSMP << "#constants = " << ConstPool.size() << '\n'); 5995ffd83dbSDimitry Andric OS.emitInt32(ConstPool.size()); 6000b57cec5SDimitry Andric // Num callsites. 6010b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << WSMP << "#callsites = " << CSInfos.size() << '\n'); 6025ffd83dbSDimitry Andric OS.emitInt32(CSInfos.size()); 6030b57cec5SDimitry Andric } 6040b57cec5SDimitry Andric 6050b57cec5SDimitry Andric /// Emit the function frame record for each function. 6060b57cec5SDimitry Andric /// 6070b57cec5SDimitry Andric /// StkSizeRecord[NumFunctions] { 6080b57cec5SDimitry Andric /// uint64 : Function Address 6090b57cec5SDimitry Andric /// uint64 : Stack Size 6100b57cec5SDimitry Andric /// uint64 : Record Count 6110b57cec5SDimitry Andric /// } 6120b57cec5SDimitry Andric void StackMaps::emitFunctionFrameRecords(MCStreamer &OS) { 6130b57cec5SDimitry Andric // Function Frame records. 6140b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << WSMP << "functions:\n"); 6150b57cec5SDimitry Andric for (auto const &FR : FnInfos) { 6160b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << WSMP << "function addr: " << FR.first 6170b57cec5SDimitry Andric << " frame size: " << FR.second.StackSize 6180b57cec5SDimitry Andric << " callsite count: " << FR.second.RecordCount << '\n'); 6195ffd83dbSDimitry Andric OS.emitSymbolValue(FR.first, 8); 6205ffd83dbSDimitry Andric OS.emitIntValue(FR.second.StackSize, 8); 6215ffd83dbSDimitry Andric OS.emitIntValue(FR.second.RecordCount, 8); 6220b57cec5SDimitry Andric } 6230b57cec5SDimitry Andric } 6240b57cec5SDimitry Andric 6250b57cec5SDimitry Andric /// Emit the constant pool. 6260b57cec5SDimitry Andric /// 6270b57cec5SDimitry Andric /// int64 : Constants[NumConstants] 6280b57cec5SDimitry Andric void StackMaps::emitConstantPoolEntries(MCStreamer &OS) { 6290b57cec5SDimitry Andric // Constant pool entries. 6300b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << WSMP << "constants:\n"); 6310b57cec5SDimitry Andric for (const auto &ConstEntry : ConstPool) { 6320b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << WSMP << ConstEntry.second << '\n'); 6335ffd83dbSDimitry Andric OS.emitIntValue(ConstEntry.second, 8); 6340b57cec5SDimitry Andric } 6350b57cec5SDimitry Andric } 6360b57cec5SDimitry Andric 6370b57cec5SDimitry Andric /// Emit the callsite info for each callsite. 6380b57cec5SDimitry Andric /// 6390b57cec5SDimitry Andric /// StkMapRecord[NumRecords] { 6400b57cec5SDimitry Andric /// uint64 : PatchPoint ID 6410b57cec5SDimitry Andric /// uint32 : Instruction Offset 6420b57cec5SDimitry Andric /// uint16 : Reserved (record flags) 6430b57cec5SDimitry Andric /// uint16 : NumLocations 6440b57cec5SDimitry Andric /// Location[NumLocations] { 6450b57cec5SDimitry Andric /// uint8 : Register | Direct | Indirect | Constant | ConstantIndex 6460b57cec5SDimitry Andric /// uint8 : Size in Bytes 6470b57cec5SDimitry Andric /// uint16 : Dwarf RegNum 6480b57cec5SDimitry Andric /// int32 : Offset 6490b57cec5SDimitry Andric /// } 6500b57cec5SDimitry Andric /// uint16 : Padding 6510b57cec5SDimitry Andric /// uint16 : NumLiveOuts 6520b57cec5SDimitry Andric /// LiveOuts[NumLiveOuts] { 6530b57cec5SDimitry Andric /// uint16 : Dwarf RegNum 6540b57cec5SDimitry Andric /// uint8 : Reserved 6550b57cec5SDimitry Andric /// uint8 : Size in Bytes 6560b57cec5SDimitry Andric /// } 6570b57cec5SDimitry Andric /// uint32 : Padding (only if required to align to 8 byte) 6580b57cec5SDimitry Andric /// } 6590b57cec5SDimitry Andric /// 6600b57cec5SDimitry Andric /// Location Encoding, Type, Value: 6610b57cec5SDimitry Andric /// 0x1, Register, Reg (value in register) 6620b57cec5SDimitry Andric /// 0x2, Direct, Reg + Offset (frame index) 6630b57cec5SDimitry Andric /// 0x3, Indirect, [Reg + Offset] (spilled value) 6640b57cec5SDimitry Andric /// 0x4, Constant, Offset (small constant) 6650b57cec5SDimitry Andric /// 0x5, ConstIndex, Constants[Offset] (large constant) 6660b57cec5SDimitry Andric void StackMaps::emitCallsiteEntries(MCStreamer &OS) { 6670b57cec5SDimitry Andric LLVM_DEBUG(print(dbgs())); 6680b57cec5SDimitry Andric // Callsite entries. 6690b57cec5SDimitry Andric for (const auto &CSI : CSInfos) { 6700b57cec5SDimitry Andric const LocationVec &CSLocs = CSI.Locations; 6710b57cec5SDimitry Andric const LiveOutVec &LiveOuts = CSI.LiveOuts; 6720b57cec5SDimitry Andric 6730b57cec5SDimitry Andric // Verify stack map entry. It's better to communicate a problem to the 6740b57cec5SDimitry Andric // runtime than crash in case of in-process compilation. Currently, we do 6750b57cec5SDimitry Andric // simple overflow checks, but we may eventually communicate other 6760b57cec5SDimitry Andric // compilation errors this way. 6770b57cec5SDimitry Andric if (CSLocs.size() > UINT16_MAX || LiveOuts.size() > UINT16_MAX) { 6785ffd83dbSDimitry Andric OS.emitIntValue(UINT64_MAX, 8); // Invalid ID. 6795ffd83dbSDimitry Andric OS.emitValue(CSI.CSOffsetExpr, 4); 6805ffd83dbSDimitry Andric OS.emitInt16(0); // Reserved. 6815ffd83dbSDimitry Andric OS.emitInt16(0); // 0 locations. 6825ffd83dbSDimitry Andric OS.emitInt16(0); // padding. 6835ffd83dbSDimitry Andric OS.emitInt16(0); // 0 live-out registers. 6845ffd83dbSDimitry Andric OS.emitInt32(0); // padding. 6850b57cec5SDimitry Andric continue; 6860b57cec5SDimitry Andric } 6870b57cec5SDimitry Andric 6885ffd83dbSDimitry Andric OS.emitIntValue(CSI.ID, 8); 6895ffd83dbSDimitry Andric OS.emitValue(CSI.CSOffsetExpr, 4); 6900b57cec5SDimitry Andric 6910b57cec5SDimitry Andric // Reserved for flags. 6925ffd83dbSDimitry Andric OS.emitInt16(0); 6935ffd83dbSDimitry Andric OS.emitInt16(CSLocs.size()); 6940b57cec5SDimitry Andric 6950b57cec5SDimitry Andric for (const auto &Loc : CSLocs) { 6965ffd83dbSDimitry Andric OS.emitIntValue(Loc.Type, 1); 6975ffd83dbSDimitry Andric OS.emitIntValue(0, 1); // Reserved 6985ffd83dbSDimitry Andric OS.emitInt16(Loc.Size); 6995ffd83dbSDimitry Andric OS.emitInt16(Loc.Reg); 7005ffd83dbSDimitry Andric OS.emitInt16(0); // Reserved 7015ffd83dbSDimitry Andric OS.emitInt32(Loc.Offset); 7020b57cec5SDimitry Andric } 7030b57cec5SDimitry Andric 7040b57cec5SDimitry Andric // Emit alignment to 8 byte. 705bdd1243dSDimitry Andric OS.emitValueToAlignment(Align(8)); 7060b57cec5SDimitry Andric 7070b57cec5SDimitry Andric // Num live-out registers and padding to align to 4 byte. 7085ffd83dbSDimitry Andric OS.emitInt16(0); 7095ffd83dbSDimitry Andric OS.emitInt16(LiveOuts.size()); 7100b57cec5SDimitry Andric 7110b57cec5SDimitry Andric for (const auto &LO : LiveOuts) { 7125ffd83dbSDimitry Andric OS.emitInt16(LO.DwarfRegNum); 7135ffd83dbSDimitry Andric OS.emitIntValue(0, 1); 7145ffd83dbSDimitry Andric OS.emitIntValue(LO.Size, 1); 7150b57cec5SDimitry Andric } 7160b57cec5SDimitry Andric // Emit alignment to 8 byte. 717bdd1243dSDimitry Andric OS.emitValueToAlignment(Align(8)); 7180b57cec5SDimitry Andric } 7190b57cec5SDimitry Andric } 7200b57cec5SDimitry Andric 7210b57cec5SDimitry Andric /// Serialize the stackmap data. 7220b57cec5SDimitry Andric void StackMaps::serializeToStackMapSection() { 7230b57cec5SDimitry Andric (void)WSMP; 7240b57cec5SDimitry Andric // Bail out if there's no stack map data. 7250b57cec5SDimitry Andric assert((!CSInfos.empty() || ConstPool.empty()) && 7260b57cec5SDimitry Andric "Expected empty constant pool too!"); 7270b57cec5SDimitry Andric assert((!CSInfos.empty() || FnInfos.empty()) && 7280b57cec5SDimitry Andric "Expected empty function record too!"); 7290b57cec5SDimitry Andric if (CSInfos.empty()) 7300b57cec5SDimitry Andric return; 7310b57cec5SDimitry Andric 7320b57cec5SDimitry Andric MCContext &OutContext = AP.OutStreamer->getContext(); 7330b57cec5SDimitry Andric MCStreamer &OS = *AP.OutStreamer; 7340b57cec5SDimitry Andric 7350b57cec5SDimitry Andric // Create the section. 7360b57cec5SDimitry Andric MCSection *StackMapSection = 7370b57cec5SDimitry Andric OutContext.getObjectFileInfo()->getStackMapSection(); 73881ad6265SDimitry Andric OS.switchSection(StackMapSection); 7390b57cec5SDimitry Andric 7400b57cec5SDimitry Andric // Emit a dummy symbol to force section inclusion. 7415ffd83dbSDimitry Andric OS.emitLabel(OutContext.getOrCreateSymbol(Twine("__LLVM_StackMaps"))); 7420b57cec5SDimitry Andric 7430b57cec5SDimitry Andric // Serialize data. 7440b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "********** Stack Map Output **********\n"); 7450b57cec5SDimitry Andric emitStackmapHeader(OS); 7460b57cec5SDimitry Andric emitFunctionFrameRecords(OS); 7470b57cec5SDimitry Andric emitConstantPoolEntries(OS); 7480b57cec5SDimitry Andric emitCallsiteEntries(OS); 74981ad6265SDimitry Andric OS.addBlankLine(); 7500b57cec5SDimitry Andric 7510b57cec5SDimitry Andric // Clean up. 7520b57cec5SDimitry Andric CSInfos.clear(); 7530b57cec5SDimitry Andric ConstPool.clear(); 7540b57cec5SDimitry Andric } 755