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 480b57cec5SDimitry Andric StackMapOpers::StackMapOpers(const MachineInstr *MI) 490b57cec5SDimitry Andric : MI(MI) { 500b57cec5SDimitry Andric assert(getVarIdx() <= MI->getNumOperands() && 510b57cec5SDimitry Andric "invalid stackmap definition"); 520b57cec5SDimitry Andric } 530b57cec5SDimitry Andric 540b57cec5SDimitry Andric PatchPointOpers::PatchPointOpers(const MachineInstr *MI) 550b57cec5SDimitry Andric : MI(MI), HasDef(MI->getOperand(0).isReg() && MI->getOperand(0).isDef() && 560b57cec5SDimitry Andric !MI->getOperand(0).isImplicit()) { 570b57cec5SDimitry Andric #ifndef NDEBUG 580b57cec5SDimitry Andric unsigned CheckStartIdx = 0, e = MI->getNumOperands(); 590b57cec5SDimitry Andric while (CheckStartIdx < e && MI->getOperand(CheckStartIdx).isReg() && 600b57cec5SDimitry Andric MI->getOperand(CheckStartIdx).isDef() && 610b57cec5SDimitry Andric !MI->getOperand(CheckStartIdx).isImplicit()) 620b57cec5SDimitry Andric ++CheckStartIdx; 630b57cec5SDimitry Andric 640b57cec5SDimitry Andric assert(getMetaIdx() == CheckStartIdx && 650b57cec5SDimitry Andric "Unexpected additional definition in Patchpoint intrinsic."); 660b57cec5SDimitry Andric #endif 670b57cec5SDimitry Andric } 680b57cec5SDimitry Andric 690b57cec5SDimitry Andric unsigned PatchPointOpers::getNextScratchIdx(unsigned StartIdx) const { 700b57cec5SDimitry Andric if (!StartIdx) 710b57cec5SDimitry Andric StartIdx = getVarIdx(); 720b57cec5SDimitry Andric 730b57cec5SDimitry Andric // Find the next scratch register (implicit def and early clobber) 740b57cec5SDimitry Andric unsigned ScratchIdx = StartIdx, e = MI->getNumOperands(); 750b57cec5SDimitry Andric while (ScratchIdx < e && 760b57cec5SDimitry Andric !(MI->getOperand(ScratchIdx).isReg() && 770b57cec5SDimitry Andric MI->getOperand(ScratchIdx).isDef() && 780b57cec5SDimitry Andric MI->getOperand(ScratchIdx).isImplicit() && 790b57cec5SDimitry Andric MI->getOperand(ScratchIdx).isEarlyClobber())) 800b57cec5SDimitry Andric ++ScratchIdx; 810b57cec5SDimitry Andric 820b57cec5SDimitry Andric assert(ScratchIdx != e && "No scratch register available"); 830b57cec5SDimitry Andric return ScratchIdx; 840b57cec5SDimitry Andric } 850b57cec5SDimitry Andric 860b57cec5SDimitry Andric StackMaps::StackMaps(AsmPrinter &AP) : AP(AP) { 870b57cec5SDimitry Andric if (StackMapVersion != 3) 880b57cec5SDimitry Andric llvm_unreachable("Unsupported stackmap version!"); 890b57cec5SDimitry Andric } 900b57cec5SDimitry Andric 910b57cec5SDimitry Andric /// Go up the super-register chain until we hit a valid dwarf register number. 920b57cec5SDimitry Andric static unsigned getDwarfRegNum(unsigned Reg, const TargetRegisterInfo *TRI) { 930b57cec5SDimitry Andric int RegNum = TRI->getDwarfRegNum(Reg, false); 940b57cec5SDimitry Andric for (MCSuperRegIterator SR(Reg, TRI); SR.isValid() && RegNum < 0; ++SR) 950b57cec5SDimitry Andric RegNum = TRI->getDwarfRegNum(*SR, false); 960b57cec5SDimitry Andric 970b57cec5SDimitry Andric assert(RegNum >= 0 && "Invalid Dwarf register number."); 980b57cec5SDimitry Andric return (unsigned)RegNum; 990b57cec5SDimitry Andric } 1000b57cec5SDimitry Andric 1010b57cec5SDimitry Andric MachineInstr::const_mop_iterator 1020b57cec5SDimitry Andric StackMaps::parseOperand(MachineInstr::const_mop_iterator MOI, 1030b57cec5SDimitry Andric MachineInstr::const_mop_iterator MOE, LocationVec &Locs, 1040b57cec5SDimitry Andric LiveOutVec &LiveOuts) const { 1050b57cec5SDimitry Andric const TargetRegisterInfo *TRI = AP.MF->getSubtarget().getRegisterInfo(); 1060b57cec5SDimitry Andric if (MOI->isImm()) { 1070b57cec5SDimitry Andric switch (MOI->getImm()) { 1080b57cec5SDimitry Andric default: 1090b57cec5SDimitry Andric llvm_unreachable("Unrecognized operand type."); 1100b57cec5SDimitry Andric case StackMaps::DirectMemRefOp: { 1110b57cec5SDimitry Andric auto &DL = AP.MF->getDataLayout(); 1120b57cec5SDimitry Andric 1130b57cec5SDimitry Andric unsigned Size = DL.getPointerSizeInBits(); 1140b57cec5SDimitry Andric assert((Size % 8) == 0 && "Need pointer size in bytes."); 1150b57cec5SDimitry Andric Size /= 8; 1168bcb0991SDimitry Andric Register Reg = (++MOI)->getReg(); 1170b57cec5SDimitry Andric int64_t Imm = (++MOI)->getImm(); 1180b57cec5SDimitry Andric Locs.emplace_back(StackMaps::Location::Direct, Size, 1190b57cec5SDimitry Andric getDwarfRegNum(Reg, TRI), Imm); 1200b57cec5SDimitry Andric break; 1210b57cec5SDimitry Andric } 1220b57cec5SDimitry Andric case StackMaps::IndirectMemRefOp: { 1230b57cec5SDimitry Andric int64_t Size = (++MOI)->getImm(); 1240b57cec5SDimitry Andric assert(Size > 0 && "Need a valid size for indirect memory locations."); 1258bcb0991SDimitry Andric Register Reg = (++MOI)->getReg(); 1260b57cec5SDimitry Andric int64_t Imm = (++MOI)->getImm(); 1270b57cec5SDimitry Andric Locs.emplace_back(StackMaps::Location::Indirect, Size, 1280b57cec5SDimitry Andric getDwarfRegNum(Reg, TRI), Imm); 1290b57cec5SDimitry Andric break; 1300b57cec5SDimitry Andric } 1310b57cec5SDimitry Andric case StackMaps::ConstantOp: { 1320b57cec5SDimitry Andric ++MOI; 1330b57cec5SDimitry Andric assert(MOI->isImm() && "Expected constant operand."); 1340b57cec5SDimitry Andric int64_t Imm = MOI->getImm(); 1350b57cec5SDimitry Andric Locs.emplace_back(Location::Constant, sizeof(int64_t), 0, Imm); 1360b57cec5SDimitry Andric break; 1370b57cec5SDimitry Andric } 1380b57cec5SDimitry Andric } 1390b57cec5SDimitry Andric return ++MOI; 1400b57cec5SDimitry Andric } 1410b57cec5SDimitry Andric 1420b57cec5SDimitry Andric // The physical register number will ultimately be encoded as a DWARF regno. 1430b57cec5SDimitry Andric // The stack map also records the size of a spill slot that can hold the 1440b57cec5SDimitry Andric // register content. (The runtime can track the actual size of the data type 1450b57cec5SDimitry Andric // if it needs to.) 1460b57cec5SDimitry Andric if (MOI->isReg()) { 1470b57cec5SDimitry Andric // Skip implicit registers (this includes our scratch registers) 1480b57cec5SDimitry Andric if (MOI->isImplicit()) 1490b57cec5SDimitry Andric return ++MOI; 1500b57cec5SDimitry Andric 1518bcb0991SDimitry Andric assert(Register::isPhysicalRegister(MOI->getReg()) && 1520b57cec5SDimitry Andric "Virtreg operands should have been rewritten before now."); 1530b57cec5SDimitry Andric const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(MOI->getReg()); 1540b57cec5SDimitry Andric assert(!MOI->getSubReg() && "Physical subreg still around."); 1550b57cec5SDimitry Andric 1560b57cec5SDimitry Andric unsigned Offset = 0; 1570b57cec5SDimitry Andric unsigned DwarfRegNum = getDwarfRegNum(MOI->getReg(), TRI); 1588bcb0991SDimitry Andric unsigned LLVMRegNum = *TRI->getLLVMRegNum(DwarfRegNum, false); 1590b57cec5SDimitry Andric unsigned SubRegIdx = TRI->getSubRegIndex(LLVMRegNum, MOI->getReg()); 1600b57cec5SDimitry Andric if (SubRegIdx) 1610b57cec5SDimitry Andric Offset = TRI->getSubRegIdxOffset(SubRegIdx); 1620b57cec5SDimitry Andric 1630b57cec5SDimitry Andric Locs.emplace_back(Location::Register, TRI->getSpillSize(*RC), 1640b57cec5SDimitry Andric DwarfRegNum, Offset); 1650b57cec5SDimitry Andric return ++MOI; 1660b57cec5SDimitry Andric } 1670b57cec5SDimitry Andric 1680b57cec5SDimitry Andric if (MOI->isRegLiveOut()) 1690b57cec5SDimitry Andric LiveOuts = parseRegisterLiveOutMask(MOI->getRegLiveOut()); 1700b57cec5SDimitry Andric 1710b57cec5SDimitry Andric return ++MOI; 1720b57cec5SDimitry Andric } 1730b57cec5SDimitry Andric 1740b57cec5SDimitry Andric void StackMaps::print(raw_ostream &OS) { 1750b57cec5SDimitry Andric const TargetRegisterInfo *TRI = 1760b57cec5SDimitry Andric AP.MF ? AP.MF->getSubtarget().getRegisterInfo() : nullptr; 1770b57cec5SDimitry Andric OS << WSMP << "callsites:\n"; 1780b57cec5SDimitry Andric for (const auto &CSI : CSInfos) { 1790b57cec5SDimitry Andric const LocationVec &CSLocs = CSI.Locations; 1800b57cec5SDimitry Andric const LiveOutVec &LiveOuts = CSI.LiveOuts; 1810b57cec5SDimitry Andric 1820b57cec5SDimitry Andric OS << WSMP << "callsite " << CSI.ID << "\n"; 1830b57cec5SDimitry Andric OS << WSMP << " has " << CSLocs.size() << " locations\n"; 1840b57cec5SDimitry Andric 1850b57cec5SDimitry Andric unsigned Idx = 0; 1860b57cec5SDimitry Andric for (const auto &Loc : CSLocs) { 1870b57cec5SDimitry Andric OS << WSMP << "\t\tLoc " << Idx << ": "; 1880b57cec5SDimitry Andric switch (Loc.Type) { 1890b57cec5SDimitry Andric case Location::Unprocessed: 1900b57cec5SDimitry Andric OS << "<Unprocessed operand>"; 1910b57cec5SDimitry Andric break; 1920b57cec5SDimitry Andric case Location::Register: 1930b57cec5SDimitry Andric OS << "Register "; 1940b57cec5SDimitry Andric if (TRI) 1950b57cec5SDimitry Andric OS << printReg(Loc.Reg, TRI); 1960b57cec5SDimitry Andric else 1970b57cec5SDimitry Andric OS << Loc.Reg; 1980b57cec5SDimitry Andric break; 1990b57cec5SDimitry Andric case Location::Direct: 2000b57cec5SDimitry Andric OS << "Direct "; 2010b57cec5SDimitry Andric if (TRI) 2020b57cec5SDimitry Andric OS << printReg(Loc.Reg, TRI); 2030b57cec5SDimitry Andric else 2040b57cec5SDimitry Andric OS << Loc.Reg; 2050b57cec5SDimitry Andric if (Loc.Offset) 2060b57cec5SDimitry Andric OS << " + " << Loc.Offset; 2070b57cec5SDimitry Andric break; 2080b57cec5SDimitry Andric case Location::Indirect: 2090b57cec5SDimitry Andric OS << "Indirect "; 2100b57cec5SDimitry Andric if (TRI) 2110b57cec5SDimitry Andric OS << printReg(Loc.Reg, TRI); 2120b57cec5SDimitry Andric else 2130b57cec5SDimitry Andric OS << Loc.Reg; 2140b57cec5SDimitry Andric OS << "+" << Loc.Offset; 2150b57cec5SDimitry Andric break; 2160b57cec5SDimitry Andric case Location::Constant: 2170b57cec5SDimitry Andric OS << "Constant " << Loc.Offset; 2180b57cec5SDimitry Andric break; 2190b57cec5SDimitry Andric case Location::ConstantIndex: 2200b57cec5SDimitry Andric OS << "Constant Index " << Loc.Offset; 2210b57cec5SDimitry Andric break; 2220b57cec5SDimitry Andric } 2230b57cec5SDimitry Andric OS << "\t[encoding: .byte " << Loc.Type << ", .byte 0" 2240b57cec5SDimitry Andric << ", .short " << Loc.Size << ", .short " << Loc.Reg << ", .short 0" 2250b57cec5SDimitry Andric << ", .int " << Loc.Offset << "]\n"; 2260b57cec5SDimitry Andric Idx++; 2270b57cec5SDimitry Andric } 2280b57cec5SDimitry Andric 2290b57cec5SDimitry Andric OS << WSMP << "\thas " << LiveOuts.size() << " live-out registers\n"; 2300b57cec5SDimitry Andric 2310b57cec5SDimitry Andric Idx = 0; 2320b57cec5SDimitry Andric for (const auto &LO : LiveOuts) { 2330b57cec5SDimitry Andric OS << WSMP << "\t\tLO " << Idx << ": "; 2340b57cec5SDimitry Andric if (TRI) 2350b57cec5SDimitry Andric OS << printReg(LO.Reg, TRI); 2360b57cec5SDimitry Andric else 2370b57cec5SDimitry Andric OS << LO.Reg; 2380b57cec5SDimitry Andric OS << "\t[encoding: .short " << LO.DwarfRegNum << ", .byte 0, .byte " 2390b57cec5SDimitry Andric << LO.Size << "]\n"; 2400b57cec5SDimitry Andric Idx++; 2410b57cec5SDimitry Andric } 2420b57cec5SDimitry Andric } 2430b57cec5SDimitry Andric } 2440b57cec5SDimitry Andric 2450b57cec5SDimitry Andric /// Create a live-out register record for the given register Reg. 2460b57cec5SDimitry Andric StackMaps::LiveOutReg 2470b57cec5SDimitry Andric StackMaps::createLiveOutReg(unsigned Reg, const TargetRegisterInfo *TRI) const { 2480b57cec5SDimitry Andric unsigned DwarfRegNum = getDwarfRegNum(Reg, TRI); 2490b57cec5SDimitry Andric unsigned Size = TRI->getSpillSize(*TRI->getMinimalPhysRegClass(Reg)); 2500b57cec5SDimitry Andric return LiveOutReg(Reg, DwarfRegNum, Size); 2510b57cec5SDimitry Andric } 2520b57cec5SDimitry Andric 2530b57cec5SDimitry Andric /// Parse the register live-out mask and return a vector of live-out registers 2540b57cec5SDimitry Andric /// that need to be recorded in the stackmap. 2550b57cec5SDimitry Andric StackMaps::LiveOutVec 2560b57cec5SDimitry Andric StackMaps::parseRegisterLiveOutMask(const uint32_t *Mask) const { 2570b57cec5SDimitry Andric assert(Mask && "No register mask specified"); 2580b57cec5SDimitry Andric const TargetRegisterInfo *TRI = AP.MF->getSubtarget().getRegisterInfo(); 2590b57cec5SDimitry Andric LiveOutVec LiveOuts; 2600b57cec5SDimitry Andric 2610b57cec5SDimitry Andric // Create a LiveOutReg for each bit that is set in the register mask. 2620b57cec5SDimitry Andric for (unsigned Reg = 0, NumRegs = TRI->getNumRegs(); Reg != NumRegs; ++Reg) 263*480093f4SDimitry Andric if ((Mask[Reg / 32] >> (Reg % 32)) & 1) 2640b57cec5SDimitry Andric LiveOuts.push_back(createLiveOutReg(Reg, TRI)); 2650b57cec5SDimitry Andric 2660b57cec5SDimitry Andric // We don't need to keep track of a register if its super-register is already 2670b57cec5SDimitry Andric // in the list. Merge entries that refer to the same dwarf register and use 2680b57cec5SDimitry Andric // the maximum size that needs to be spilled. 2690b57cec5SDimitry Andric 2700b57cec5SDimitry Andric llvm::sort(LiveOuts, [](const LiveOutReg &LHS, const LiveOutReg &RHS) { 2710b57cec5SDimitry Andric // Only sort by the dwarf register number. 2720b57cec5SDimitry Andric return LHS.DwarfRegNum < RHS.DwarfRegNum; 2730b57cec5SDimitry Andric }); 2740b57cec5SDimitry Andric 2750b57cec5SDimitry Andric for (auto I = LiveOuts.begin(), E = LiveOuts.end(); I != E; ++I) { 2760b57cec5SDimitry Andric for (auto II = std::next(I); II != E; ++II) { 2770b57cec5SDimitry Andric if (I->DwarfRegNum != II->DwarfRegNum) { 2780b57cec5SDimitry Andric // Skip all the now invalid entries. 2790b57cec5SDimitry Andric I = --II; 2800b57cec5SDimitry Andric break; 2810b57cec5SDimitry Andric } 2820b57cec5SDimitry Andric I->Size = std::max(I->Size, II->Size); 2830b57cec5SDimitry Andric if (TRI->isSuperRegister(I->Reg, II->Reg)) 2840b57cec5SDimitry Andric I->Reg = II->Reg; 2850b57cec5SDimitry Andric II->Reg = 0; // mark for deletion. 2860b57cec5SDimitry Andric } 2870b57cec5SDimitry Andric } 2880b57cec5SDimitry Andric 2890b57cec5SDimitry Andric LiveOuts.erase( 2900b57cec5SDimitry Andric llvm::remove_if(LiveOuts, 2910b57cec5SDimitry Andric [](const LiveOutReg &LO) { return LO.Reg == 0; }), 2920b57cec5SDimitry Andric LiveOuts.end()); 2930b57cec5SDimitry Andric 2940b57cec5SDimitry Andric return LiveOuts; 2950b57cec5SDimitry Andric } 2960b57cec5SDimitry Andric 297*480093f4SDimitry Andric void StackMaps::recordStackMapOpers(const MCSymbol &MILabel, 298*480093f4SDimitry Andric const MachineInstr &MI, uint64_t ID, 2990b57cec5SDimitry Andric MachineInstr::const_mop_iterator MOI, 3000b57cec5SDimitry Andric MachineInstr::const_mop_iterator MOE, 3010b57cec5SDimitry Andric bool recordResult) { 3020b57cec5SDimitry Andric MCContext &OutContext = AP.OutStreamer->getContext(); 3030b57cec5SDimitry Andric 3040b57cec5SDimitry Andric LocationVec Locations; 3050b57cec5SDimitry Andric LiveOutVec LiveOuts; 3060b57cec5SDimitry Andric 3070b57cec5SDimitry Andric if (recordResult) { 3080b57cec5SDimitry Andric assert(PatchPointOpers(&MI).hasDef() && "Stackmap has no return value."); 3090b57cec5SDimitry Andric parseOperand(MI.operands_begin(), std::next(MI.operands_begin()), Locations, 3100b57cec5SDimitry Andric LiveOuts); 3110b57cec5SDimitry Andric } 3120b57cec5SDimitry Andric 3130b57cec5SDimitry Andric // Parse operands. 3140b57cec5SDimitry Andric while (MOI != MOE) { 3150b57cec5SDimitry Andric MOI = parseOperand(MOI, MOE, Locations, LiveOuts); 3160b57cec5SDimitry Andric } 3170b57cec5SDimitry Andric 3180b57cec5SDimitry Andric // Move large constants into the constant pool. 3190b57cec5SDimitry Andric for (auto &Loc : Locations) { 3200b57cec5SDimitry Andric // Constants are encoded as sign-extended integers. 3210b57cec5SDimitry Andric // -1 is directly encoded as .long 0xFFFFFFFF with no constant pool. 3220b57cec5SDimitry Andric if (Loc.Type == Location::Constant && !isInt<32>(Loc.Offset)) { 3230b57cec5SDimitry Andric Loc.Type = Location::ConstantIndex; 3240b57cec5SDimitry Andric // ConstPool is intentionally a MapVector of 'uint64_t's (as 3250b57cec5SDimitry Andric // opposed to 'int64_t's). We should never be in a situation 3260b57cec5SDimitry Andric // where we have to insert either the tombstone or the empty 3270b57cec5SDimitry Andric // keys into a map, and for a DenseMap<uint64_t, T> these are 3280b57cec5SDimitry Andric // (uint64_t)0 and (uint64_t)-1. They can be and are 3290b57cec5SDimitry Andric // represented using 32 bit integers. 3300b57cec5SDimitry Andric assert((uint64_t)Loc.Offset != DenseMapInfo<uint64_t>::getEmptyKey() && 3310b57cec5SDimitry Andric (uint64_t)Loc.Offset != 3320b57cec5SDimitry Andric DenseMapInfo<uint64_t>::getTombstoneKey() && 3330b57cec5SDimitry Andric "empty and tombstone keys should fit in 32 bits!"); 3340b57cec5SDimitry Andric auto Result = ConstPool.insert(std::make_pair(Loc.Offset, Loc.Offset)); 3350b57cec5SDimitry Andric Loc.Offset = Result.first - ConstPool.begin(); 3360b57cec5SDimitry Andric } 3370b57cec5SDimitry Andric } 3380b57cec5SDimitry Andric 3390b57cec5SDimitry Andric // Create an expression to calculate the offset of the callsite from function 3400b57cec5SDimitry Andric // entry. 3410b57cec5SDimitry Andric const MCExpr *CSOffsetExpr = MCBinaryExpr::createSub( 342*480093f4SDimitry Andric MCSymbolRefExpr::create(&MILabel, OutContext), 3430b57cec5SDimitry Andric MCSymbolRefExpr::create(AP.CurrentFnSymForSize, OutContext), OutContext); 3440b57cec5SDimitry Andric 3450b57cec5SDimitry Andric CSInfos.emplace_back(CSOffsetExpr, ID, std::move(Locations), 3460b57cec5SDimitry Andric std::move(LiveOuts)); 3470b57cec5SDimitry Andric 3480b57cec5SDimitry Andric // Record the stack size of the current function and update callsite count. 3490b57cec5SDimitry Andric const MachineFrameInfo &MFI = AP.MF->getFrameInfo(); 3500b57cec5SDimitry Andric const TargetRegisterInfo *RegInfo = AP.MF->getSubtarget().getRegisterInfo(); 3510b57cec5SDimitry Andric bool HasDynamicFrameSize = 3520b57cec5SDimitry Andric MFI.hasVarSizedObjects() || RegInfo->needsStackRealignment(*(AP.MF)); 3530b57cec5SDimitry Andric uint64_t FrameSize = HasDynamicFrameSize ? UINT64_MAX : MFI.getStackSize(); 3540b57cec5SDimitry Andric 3550b57cec5SDimitry Andric auto CurrentIt = FnInfos.find(AP.CurrentFnSym); 3560b57cec5SDimitry Andric if (CurrentIt != FnInfos.end()) 3570b57cec5SDimitry Andric CurrentIt->second.RecordCount++; 3580b57cec5SDimitry Andric else 3590b57cec5SDimitry Andric FnInfos.insert(std::make_pair(AP.CurrentFnSym, FunctionInfo(FrameSize))); 3600b57cec5SDimitry Andric } 3610b57cec5SDimitry Andric 362*480093f4SDimitry Andric void StackMaps::recordStackMap(const MCSymbol &L, const MachineInstr &MI) { 3630b57cec5SDimitry Andric assert(MI.getOpcode() == TargetOpcode::STACKMAP && "expected stackmap"); 3640b57cec5SDimitry Andric 3650b57cec5SDimitry Andric StackMapOpers opers(&MI); 3660b57cec5SDimitry Andric const int64_t ID = MI.getOperand(PatchPointOpers::IDPos).getImm(); 367*480093f4SDimitry Andric recordStackMapOpers(L, MI, ID, std::next(MI.operands_begin(), 368*480093f4SDimitry Andric opers.getVarIdx()), 3690b57cec5SDimitry Andric MI.operands_end()); 3700b57cec5SDimitry Andric } 3710b57cec5SDimitry Andric 372*480093f4SDimitry Andric void StackMaps::recordPatchPoint(const MCSymbol &L, const MachineInstr &MI) { 3730b57cec5SDimitry Andric assert(MI.getOpcode() == TargetOpcode::PATCHPOINT && "expected patchpoint"); 3740b57cec5SDimitry Andric 3750b57cec5SDimitry Andric PatchPointOpers opers(&MI); 3760b57cec5SDimitry Andric const int64_t ID = opers.getID(); 3770b57cec5SDimitry Andric auto MOI = std::next(MI.operands_begin(), opers.getStackMapStartIdx()); 378*480093f4SDimitry Andric recordStackMapOpers(L, MI, ID, MOI, MI.operands_end(), 3790b57cec5SDimitry Andric opers.isAnyReg() && opers.hasDef()); 3800b57cec5SDimitry Andric 3810b57cec5SDimitry Andric #ifndef NDEBUG 3820b57cec5SDimitry Andric // verify anyregcc 3830b57cec5SDimitry Andric auto &Locations = CSInfos.back().Locations; 3840b57cec5SDimitry Andric if (opers.isAnyReg()) { 3850b57cec5SDimitry Andric unsigned NArgs = opers.getNumCallArgs(); 3860b57cec5SDimitry Andric for (unsigned i = 0, e = (opers.hasDef() ? NArgs + 1 : NArgs); i != e; ++i) 3870b57cec5SDimitry Andric assert(Locations[i].Type == Location::Register && 3880b57cec5SDimitry Andric "anyreg arg must be in reg."); 3890b57cec5SDimitry Andric } 3900b57cec5SDimitry Andric #endif 3910b57cec5SDimitry Andric } 3920b57cec5SDimitry Andric 393*480093f4SDimitry Andric void StackMaps::recordStatepoint(const MCSymbol &L, const MachineInstr &MI) { 3940b57cec5SDimitry Andric assert(MI.getOpcode() == TargetOpcode::STATEPOINT && "expected statepoint"); 3950b57cec5SDimitry Andric 3960b57cec5SDimitry Andric StatepointOpers opers(&MI); 3970b57cec5SDimitry Andric // Record all the deopt and gc operands (they're contiguous and run from the 3980b57cec5SDimitry Andric // initial index to the end of the operand list) 3990b57cec5SDimitry Andric const unsigned StartIdx = opers.getVarIdx(); 400*480093f4SDimitry Andric recordStackMapOpers(L, MI, opers.getID(), MI.operands_begin() + StartIdx, 4010b57cec5SDimitry Andric MI.operands_end(), false); 4020b57cec5SDimitry Andric } 4030b57cec5SDimitry Andric 4040b57cec5SDimitry Andric /// Emit the stackmap header. 4050b57cec5SDimitry Andric /// 4060b57cec5SDimitry Andric /// Header { 4070b57cec5SDimitry Andric /// uint8 : Stack Map Version (currently 2) 4080b57cec5SDimitry Andric /// uint8 : Reserved (expected to be 0) 4090b57cec5SDimitry Andric /// uint16 : Reserved (expected to be 0) 4100b57cec5SDimitry Andric /// } 4110b57cec5SDimitry Andric /// uint32 : NumFunctions 4120b57cec5SDimitry Andric /// uint32 : NumConstants 4130b57cec5SDimitry Andric /// uint32 : NumRecords 4140b57cec5SDimitry Andric void StackMaps::emitStackmapHeader(MCStreamer &OS) { 4150b57cec5SDimitry Andric // Header. 4160b57cec5SDimitry Andric OS.EmitIntValue(StackMapVersion, 1); // Version. 4170b57cec5SDimitry Andric OS.EmitIntValue(0, 1); // Reserved. 4180b57cec5SDimitry Andric OS.EmitIntValue(0, 2); // Reserved. 4190b57cec5SDimitry Andric 4200b57cec5SDimitry Andric // Num functions. 4210b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << WSMP << "#functions = " << FnInfos.size() << '\n'); 4220b57cec5SDimitry Andric OS.EmitIntValue(FnInfos.size(), 4); 4230b57cec5SDimitry Andric // Num constants. 4240b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << WSMP << "#constants = " << ConstPool.size() << '\n'); 4250b57cec5SDimitry Andric OS.EmitIntValue(ConstPool.size(), 4); 4260b57cec5SDimitry Andric // Num callsites. 4270b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << WSMP << "#callsites = " << CSInfos.size() << '\n'); 4280b57cec5SDimitry Andric OS.EmitIntValue(CSInfos.size(), 4); 4290b57cec5SDimitry Andric } 4300b57cec5SDimitry Andric 4310b57cec5SDimitry Andric /// Emit the function frame record for each function. 4320b57cec5SDimitry Andric /// 4330b57cec5SDimitry Andric /// StkSizeRecord[NumFunctions] { 4340b57cec5SDimitry Andric /// uint64 : Function Address 4350b57cec5SDimitry Andric /// uint64 : Stack Size 4360b57cec5SDimitry Andric /// uint64 : Record Count 4370b57cec5SDimitry Andric /// } 4380b57cec5SDimitry Andric void StackMaps::emitFunctionFrameRecords(MCStreamer &OS) { 4390b57cec5SDimitry Andric // Function Frame records. 4400b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << WSMP << "functions:\n"); 4410b57cec5SDimitry Andric for (auto const &FR : FnInfos) { 4420b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << WSMP << "function addr: " << FR.first 4430b57cec5SDimitry Andric << " frame size: " << FR.second.StackSize 4440b57cec5SDimitry Andric << " callsite count: " << FR.second.RecordCount << '\n'); 4450b57cec5SDimitry Andric OS.EmitSymbolValue(FR.first, 8); 4460b57cec5SDimitry Andric OS.EmitIntValue(FR.second.StackSize, 8); 4470b57cec5SDimitry Andric OS.EmitIntValue(FR.second.RecordCount, 8); 4480b57cec5SDimitry Andric } 4490b57cec5SDimitry Andric } 4500b57cec5SDimitry Andric 4510b57cec5SDimitry Andric /// Emit the constant pool. 4520b57cec5SDimitry Andric /// 4530b57cec5SDimitry Andric /// int64 : Constants[NumConstants] 4540b57cec5SDimitry Andric void StackMaps::emitConstantPoolEntries(MCStreamer &OS) { 4550b57cec5SDimitry Andric // Constant pool entries. 4560b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << WSMP << "constants:\n"); 4570b57cec5SDimitry Andric for (const auto &ConstEntry : ConstPool) { 4580b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << WSMP << ConstEntry.second << '\n'); 4590b57cec5SDimitry Andric OS.EmitIntValue(ConstEntry.second, 8); 4600b57cec5SDimitry Andric } 4610b57cec5SDimitry Andric } 4620b57cec5SDimitry Andric 4630b57cec5SDimitry Andric /// Emit the callsite info for each callsite. 4640b57cec5SDimitry Andric /// 4650b57cec5SDimitry Andric /// StkMapRecord[NumRecords] { 4660b57cec5SDimitry Andric /// uint64 : PatchPoint ID 4670b57cec5SDimitry Andric /// uint32 : Instruction Offset 4680b57cec5SDimitry Andric /// uint16 : Reserved (record flags) 4690b57cec5SDimitry Andric /// uint16 : NumLocations 4700b57cec5SDimitry Andric /// Location[NumLocations] { 4710b57cec5SDimitry Andric /// uint8 : Register | Direct | Indirect | Constant | ConstantIndex 4720b57cec5SDimitry Andric /// uint8 : Size in Bytes 4730b57cec5SDimitry Andric /// uint16 : Dwarf RegNum 4740b57cec5SDimitry Andric /// int32 : Offset 4750b57cec5SDimitry Andric /// } 4760b57cec5SDimitry Andric /// uint16 : Padding 4770b57cec5SDimitry Andric /// uint16 : NumLiveOuts 4780b57cec5SDimitry Andric /// LiveOuts[NumLiveOuts] { 4790b57cec5SDimitry Andric /// uint16 : Dwarf RegNum 4800b57cec5SDimitry Andric /// uint8 : Reserved 4810b57cec5SDimitry Andric /// uint8 : Size in Bytes 4820b57cec5SDimitry Andric /// } 4830b57cec5SDimitry Andric /// uint32 : Padding (only if required to align to 8 byte) 4840b57cec5SDimitry Andric /// } 4850b57cec5SDimitry Andric /// 4860b57cec5SDimitry Andric /// Location Encoding, Type, Value: 4870b57cec5SDimitry Andric /// 0x1, Register, Reg (value in register) 4880b57cec5SDimitry Andric /// 0x2, Direct, Reg + Offset (frame index) 4890b57cec5SDimitry Andric /// 0x3, Indirect, [Reg + Offset] (spilled value) 4900b57cec5SDimitry Andric /// 0x4, Constant, Offset (small constant) 4910b57cec5SDimitry Andric /// 0x5, ConstIndex, Constants[Offset] (large constant) 4920b57cec5SDimitry Andric void StackMaps::emitCallsiteEntries(MCStreamer &OS) { 4930b57cec5SDimitry Andric LLVM_DEBUG(print(dbgs())); 4940b57cec5SDimitry Andric // Callsite entries. 4950b57cec5SDimitry Andric for (const auto &CSI : CSInfos) { 4960b57cec5SDimitry Andric const LocationVec &CSLocs = CSI.Locations; 4970b57cec5SDimitry Andric const LiveOutVec &LiveOuts = CSI.LiveOuts; 4980b57cec5SDimitry Andric 4990b57cec5SDimitry Andric // Verify stack map entry. It's better to communicate a problem to the 5000b57cec5SDimitry Andric // runtime than crash in case of in-process compilation. Currently, we do 5010b57cec5SDimitry Andric // simple overflow checks, but we may eventually communicate other 5020b57cec5SDimitry Andric // compilation errors this way. 5030b57cec5SDimitry Andric if (CSLocs.size() > UINT16_MAX || LiveOuts.size() > UINT16_MAX) { 5040b57cec5SDimitry Andric OS.EmitIntValue(UINT64_MAX, 8); // Invalid ID. 5050b57cec5SDimitry Andric OS.EmitValue(CSI.CSOffsetExpr, 4); 5060b57cec5SDimitry Andric OS.EmitIntValue(0, 2); // Reserved. 5070b57cec5SDimitry Andric OS.EmitIntValue(0, 2); // 0 locations. 5080b57cec5SDimitry Andric OS.EmitIntValue(0, 2); // padding. 5090b57cec5SDimitry Andric OS.EmitIntValue(0, 2); // 0 live-out registers. 5100b57cec5SDimitry Andric OS.EmitIntValue(0, 4); // padding. 5110b57cec5SDimitry Andric continue; 5120b57cec5SDimitry Andric } 5130b57cec5SDimitry Andric 5140b57cec5SDimitry Andric OS.EmitIntValue(CSI.ID, 8); 5150b57cec5SDimitry Andric OS.EmitValue(CSI.CSOffsetExpr, 4); 5160b57cec5SDimitry Andric 5170b57cec5SDimitry Andric // Reserved for flags. 5180b57cec5SDimitry Andric OS.EmitIntValue(0, 2); 5190b57cec5SDimitry Andric OS.EmitIntValue(CSLocs.size(), 2); 5200b57cec5SDimitry Andric 5210b57cec5SDimitry Andric for (const auto &Loc : CSLocs) { 5220b57cec5SDimitry Andric OS.EmitIntValue(Loc.Type, 1); 5230b57cec5SDimitry Andric OS.EmitIntValue(0, 1); // Reserved 5240b57cec5SDimitry Andric OS.EmitIntValue(Loc.Size, 2); 5250b57cec5SDimitry Andric OS.EmitIntValue(Loc.Reg, 2); 5260b57cec5SDimitry Andric OS.EmitIntValue(0, 2); // Reserved 5270b57cec5SDimitry Andric OS.EmitIntValue(Loc.Offset, 4); 5280b57cec5SDimitry Andric } 5290b57cec5SDimitry Andric 5300b57cec5SDimitry Andric // Emit alignment to 8 byte. 5310b57cec5SDimitry Andric OS.EmitValueToAlignment(8); 5320b57cec5SDimitry Andric 5330b57cec5SDimitry Andric // Num live-out registers and padding to align to 4 byte. 5340b57cec5SDimitry Andric OS.EmitIntValue(0, 2); 5350b57cec5SDimitry Andric OS.EmitIntValue(LiveOuts.size(), 2); 5360b57cec5SDimitry Andric 5370b57cec5SDimitry Andric for (const auto &LO : LiveOuts) { 5380b57cec5SDimitry Andric OS.EmitIntValue(LO.DwarfRegNum, 2); 5390b57cec5SDimitry Andric OS.EmitIntValue(0, 1); 5400b57cec5SDimitry Andric OS.EmitIntValue(LO.Size, 1); 5410b57cec5SDimitry Andric } 5420b57cec5SDimitry Andric // Emit alignment to 8 byte. 5430b57cec5SDimitry Andric OS.EmitValueToAlignment(8); 5440b57cec5SDimitry Andric } 5450b57cec5SDimitry Andric } 5460b57cec5SDimitry Andric 5470b57cec5SDimitry Andric /// Serialize the stackmap data. 5480b57cec5SDimitry Andric void StackMaps::serializeToStackMapSection() { 5490b57cec5SDimitry Andric (void)WSMP; 5500b57cec5SDimitry Andric // Bail out if there's no stack map data. 5510b57cec5SDimitry Andric assert((!CSInfos.empty() || ConstPool.empty()) && 5520b57cec5SDimitry Andric "Expected empty constant pool too!"); 5530b57cec5SDimitry Andric assert((!CSInfos.empty() || FnInfos.empty()) && 5540b57cec5SDimitry Andric "Expected empty function record too!"); 5550b57cec5SDimitry Andric if (CSInfos.empty()) 5560b57cec5SDimitry Andric return; 5570b57cec5SDimitry Andric 5580b57cec5SDimitry Andric MCContext &OutContext = AP.OutStreamer->getContext(); 5590b57cec5SDimitry Andric MCStreamer &OS = *AP.OutStreamer; 5600b57cec5SDimitry Andric 5610b57cec5SDimitry Andric // Create the section. 5620b57cec5SDimitry Andric MCSection *StackMapSection = 5630b57cec5SDimitry Andric OutContext.getObjectFileInfo()->getStackMapSection(); 5640b57cec5SDimitry Andric OS.SwitchSection(StackMapSection); 5650b57cec5SDimitry Andric 5660b57cec5SDimitry Andric // Emit a dummy symbol to force section inclusion. 5670b57cec5SDimitry Andric OS.EmitLabel(OutContext.getOrCreateSymbol(Twine("__LLVM_StackMaps"))); 5680b57cec5SDimitry Andric 5690b57cec5SDimitry Andric // Serialize data. 5700b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "********** Stack Map Output **********\n"); 5710b57cec5SDimitry Andric emitStackmapHeader(OS); 5720b57cec5SDimitry Andric emitFunctionFrameRecords(OS); 5730b57cec5SDimitry Andric emitConstantPoolEntries(OS); 5740b57cec5SDimitry Andric emitCallsiteEntries(OS); 5750b57cec5SDimitry Andric OS.AddBlankLine(); 5760b57cec5SDimitry Andric 5770b57cec5SDimitry Andric // Clean up. 5780b57cec5SDimitry Andric CSInfos.clear(); 5790b57cec5SDimitry Andric ConstPool.clear(); 5800b57cec5SDimitry Andric } 581