39#define DEBUG_TYPE "stackmaps"
43 cl::desc(
"Specify the stackmap encoding version (default = 3)"));
45const char *StackMaps::WSMP =
"Stack Maps: ";
49 MI.getOperand(Idx).getImm() == StackMaps::ConstantOp);
50 const auto &MO =
MI.getOperand(Idx + 1);
58 "invalid stackmap definition");
62 : MI(MI), HasDef(MI->getOperand(0).
isReg() && MI->getOperand(0).isDef() &&
63 !MI->getOperand(0).isImplicit()) {
65 unsigned CheckStartIdx = 0, e = MI->getNumOperands();
66 while (CheckStartIdx < e && MI->getOperand(CheckStartIdx).
isReg() &&
67 MI->getOperand(CheckStartIdx).isDef() &&
68 !MI->getOperand(CheckStartIdx).isImplicit())
71 assert(getMetaIdx() == CheckStartIdx &&
72 "Unexpected additional definition in Patchpoint intrinsic.");
81 unsigned ScratchIdx = StartIdx, e = MI->getNumOperands();
82 while (ScratchIdx < e &&
83 !(MI->getOperand(ScratchIdx).isReg() &&
84 MI->getOperand(ScratchIdx).isDef() &&
85 MI->getOperand(ScratchIdx).isImplicit() &&
86 MI->getOperand(ScratchIdx).isEarlyClobber()))
89 assert(ScratchIdx != e &&
"No scratch register available");
118 while (NumDeoptArgs--) {
130 assert(NumGCPtrsIdx < MI->getNumOperands());
131 return (
int)NumGCPtrsIdx;
139 for (
unsigned N = 0;
N < GCMapSize; ++
N) {
140 unsigned B = MI->getOperand(CurIdx++).getImm();
141 unsigned D = MI->getOperand(CurIdx++).getImm();
142 GCMap.push_back(std::make_pair(
B,
D));
149 unsigned FoldableAreaStart =
getVarIdx();
151 if (MO.getOperandNo() >= FoldableAreaStart)
153 if (MO.isReg() && MO.getReg() == Reg)
160 if (MI->getOpcode() != TargetOpcode::STATEPOINT)
171 assert(CurIdx < MI->getNumOperands() &&
"Bad meta arg index");
172 const auto &MO =
MI->getOperand(CurIdx);
174 switch (MO.getImm()) {
177 case StackMaps::DirectMemRefOp:
180 case StackMaps::IndirectMemRefOp:
183 case StackMaps::ConstantOp:
189 assert(CurIdx < MI->getNumOperands() &&
"points past operand list");
197 RegNum =
TRI->getDwarfRegNum(SR,
false);
202 assert(RegNum >= 0 &&
isUInt<16>(RegNum) &&
"Invalid Dwarf register number.");
203 return (
unsigned)RegNum;
209 LiveOutVec &LiveOuts) {
210 const TargetRegisterInfo *
TRI = AP.MF->getSubtarget().getRegisterInfo();
215 case StackMaps::DirectMemRefOp: {
216 auto &
DL = AP.MF->getDataLayout();
218 unsigned Size =
DL.getPointerSizeInBits();
219 assert((
Size % 8) == 0 &&
"Need pointer size in bytes.");
227 case StackMaps::IndirectMemRefOp: {
229 assert(
Size > 0 &&
"Need a valid size for indirect memory locations.");
236 case StackMaps::ConstantOp: {
238 assert(MOI->
isImm() &&
"Expected constant operand.");
248 assert((uint64_t)Imm != DenseMapInfo<uint64_t>::getEmptyKey() &&
249 "empty key should fit in 32 bits!");
250 auto Result = ConstPool.insert(std::make_pair(Imm, Imm));
252 Result.first - ConstPool.begin());
270 "Virtreg operands should have been rewritten before now.");
271 const TargetRegisterClass *RC =
TRI->getMinimalPhysRegClass(MOI->
getReg());
276 MCRegister LLVMRegNum = *
TRI->getLLVMRegNum(DwarfRegNum,
false);
277 unsigned SubRegIdx =
TRI->getSubRegIndex(LLVMRegNum, MOI->
getReg());
279 Offset =
TRI->getSubRegIdxOffset(SubRegIdx);
293 const TargetRegisterInfo *
TRI =
294 AP.MF ? AP.MF->getSubtarget().getRegisterInfo() :
nullptr;
295 OS << WSMP <<
"callsites:\n";
296 for (
const auto &CSI : CSInfos) {
300 OS << WSMP <<
"callsite " << CSI.ID <<
"\n";
301 OS << WSMP <<
" has " << CSLocs.size() <<
" locations\n";
304 for (
const auto &Loc : CSLocs) {
305 OS << WSMP <<
"\t\tLoc " << Idx <<
": ";
308 OS <<
"<Unprocessed operand>";
324 OS <<
" + " << Loc.Offset;
332 OS <<
"+" << Loc.Offset;
335 OS <<
"Constant " << Loc.Offset;
338 OS <<
"Constant Index " << Loc.Offset;
341 OS <<
"\t[encoding: .byte " << Loc.Type <<
", .byte 0"
342 <<
", .short " << Loc.Size <<
", .short " << Loc.Reg <<
", .short 0"
343 <<
", .int " << Loc.Offset <<
"]\n";
347 OS << WSMP <<
"\thas " << LiveOuts.size() <<
" live-out registers\n";
350 for (
const auto &LO : LiveOuts) {
351 OS << WSMP <<
"\t\tLO " << Idx <<
": ";
356 OS <<
"\t[encoding: .short " <<
LO.DwarfRegNum <<
", .byte 0, .byte "
367 unsigned Size =
TRI->getSpillSize(*
TRI->getMinimalPhysRegClass(
Reg));
374StackMaps::parseRegisterLiveOutMask(
const uint32_t *Mask)
const {
375 assert(Mask &&
"No register mask specified");
376 const TargetRegisterInfo *
TRI = AP.MF->getSubtarget().getRegisterInfo();
380 for (
unsigned Reg = 0, NumRegs =
TRI->getNumRegs();
Reg != NumRegs; ++
Reg)
381 if ((Mask[
Reg / 32] >> (
Reg % 32)) & 1)
382 LiveOuts.push_back(createLiveOutReg(
Reg,
TRI));
390 return LHS.DwarfRegNum <
RHS.DwarfRegNum;
393 for (
auto I = LiveOuts.begin(),
E = LiveOuts.end();
I !=
E; ++
I) {
394 for (
auto *
II = std::next(
I);
II !=
E; ++
II) {
395 if (
I->DwarfRegNum !=
II->DwarfRegNum) {
400 I->Size = std::max(
I->Size,
II->Size);
401 if (
I->Reg &&
TRI->isSuperRegister(
I->Reg,
II->Reg))
417 LocationVec &Locations,
418 LiveOutVec &LiveOuts) {
420 StatepointOpers SO(&
MI);
421 MOI = parseOperand(MOI, MOE, Locations, LiveOuts);
422 MOI = parseOperand(MOI, MOE, Locations, LiveOuts);
423 MOI = parseOperand(MOI, MOE, Locations, LiveOuts);
426 unsigned NumDeoptArgs =
Locations.back().Offset;
428 assert(NumDeoptArgs == SO.getNumDeoptArgs());
430 while (NumDeoptArgs--)
431 MOI = parseOperand(MOI, MOE, Locations, LiveOuts);
437 unsigned NumGCPointers = MOI->
getImm();
441 SmallVector<unsigned, 8> GCPtrIndices;
442 unsigned GCPtrIdx = (unsigned)SO.getFirstGCPtrIdx();
443 assert((
int)GCPtrIdx != -1);
444 assert(MOI -
MI.operands_begin() == GCPtrIdx + 0LL);
445 while (NumGCPointers--) {
451 unsigned NumGCPairs = SO.getGCPointerMap(GCPairs);
455 auto MOB =
MI.operands_begin();
456 for (
auto &
P : GCPairs) {
457 assert(
P.first < GCPtrIndices.
size() &&
"base pointer index not found");
459 "derived pointer index not found");
460 unsigned BaseIdx = GCPtrIndices[
P.first];
461 unsigned DerivedIdx = GCPtrIndices[
P.second];
462 LLVM_DEBUG(
dbgs() <<
"Base : " << BaseIdx <<
" Derived : " << DerivedIdx
464 (void)parseOperand(MOB + BaseIdx, MOE, Locations, LiveOuts);
465 (void)parseOperand(MOB + DerivedIdx, MOE, Locations, LiveOuts);
468 MOI = MOB + GCPtrIdx;
475 unsigned NumAllocas = MOI->
getImm();
477 while (NumAllocas--) {
478 MOI = parseOperand(MOI, MOE, Locations, LiveOuts);
483void StackMaps::recordStackMapOpers(
const MCSymbol &MILabel,
488 MCContext &OutContext = AP.OutStreamer->getContext();
494 assert(PatchPointOpers(&
MI).hasDef() &&
"Stackmap has no return value.");
495 parseOperand(
MI.operands_begin(), std::next(
MI.operands_begin()), Locations,
500 if (
MI.getOpcode() == TargetOpcode::STATEPOINT)
501 parseStatepointOpers(
MI, MOI, MOE, Locations, LiveOuts);
504 MOI = parseOperand(MOI, MOE, Locations, LiveOuts);
512 CSInfos.emplace_back(CSOffsetExpr,
ID, std::move(Locations),
513 std::move(LiveOuts));
516 const MachineFrameInfo &MFI = AP.MF->getFrameInfo();
517 const TargetRegisterInfo *RegInfo = AP.MF->getSubtarget().getRegisterInfo();
518 bool HasDynamicFrameSize =
522 auto [CurrentIt,
Inserted] = FnInfos.try_emplace(AP.CurrentFnSym, FrameSize);
524 CurrentIt->second.RecordCount++;
528 assert(
MI.getOpcode() == TargetOpcode::STACKMAP &&
"expected stackmap");
532 recordStackMapOpers(L,
MI,
ID, std::next(
MI.operands_begin(),
538 assert(
MI.getOpcode() == TargetOpcode::PATCHPOINT &&
"expected patchpoint");
541 const int64_t
ID = opers.
getID();
543 recordStackMapOpers(L,
MI,
ID, MOI,
MI.operands_end(),
548 auto &Locations = CSInfos.back().Locations;
551 for (
unsigned i = 0, e = (opers.
hasDef() ? NArgs + 1 : NArgs); i != e; ++i)
553 "anyreg arg must be in reg.");
559 assert(
MI.getOpcode() == TargetOpcode::STATEPOINT &&
"expected statepoint");
562 const unsigned StartIdx = opers.
getVarIdx();
563 recordStackMapOpers(L,
MI, opers.
getID(),
MI.operands_begin() + StartIdx,
564 MI.operands_end(),
false);
577void StackMaps::emitStackmapHeader(
MCStreamer &OS) {
590 LLVM_DEBUG(
dbgs() << WSMP <<
"#callsites = " << CSInfos.size() <<
'\n');
601void StackMaps::emitFunctionFrameRecords(
MCStreamer &OS) {
604 for (
auto const &FR : FnInfos) {
606 <<
" frame size: " << FR.second.StackSize
607 <<
" callsite count: " << FR.second.RecordCount <<
'\n');
617void StackMaps::emitConstantPoolEntries(
MCStreamer &OS) {
620 for (
const auto &ConstEntry : ConstPool) {
655void StackMaps::emitCallsiteEntries(
MCStreamer &OS) {
658 for (
const auto &CSI : CSInfos) {
666 if (CSLocs.size() > UINT16_MAX || LiveOuts.size() > UINT16_MAX) {
684 for (
const auto &Loc : CSLocs) {
700 for (
const auto &LO : LiveOuts) {
714 assert((!CSInfos.empty() || ConstPool.empty()) &&
715 "Expected empty constant pool too!");
716 assert((!CSInfos.empty() || FnInfos.empty()) &&
717 "Expected empty function record too!");
721 MCContext &OutContext = AP.OutStreamer->getContext();
734 emitStackmapHeader(OS);
735 emitFunctionFrameRecords(OS);
736 emitConstantPoolEntries(OS);
737 emitCallsiteEntries(OS);
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static GCRegistry::Add< StatepointGC > D("statepoint-example", "an example strategy for statepoint")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
This file defines DenseMapInfo traits for DenseMap.
Register const TargetRegisterInfo * TRI
Promote Memory to Register
static MCRegister getReg(const MCDisassembler *D, unsigned RC, unsigned RegNo)
static bool isReg(const MCInst &MI, unsigned OpNo)
uint64_t IntrinsicInst * II
static uint64_t getConstMetaVal(const MachineInstr &MI, unsigned Idx)
static cl::opt< int > StackMapVersion("stackmap-version", cl::init(3), cl::Hidden, cl::desc("Specify the stackmap encoding version (default = 3)"))
static unsigned getDwarfRegNum(MCRegister Reg, const TargetRegisterInfo *TRI)
Go up the super-register chain until we hit a valid dwarf register number.
This class is intended to be used as a driving class for all asm writers.
static const MCBinaryExpr * createSub(const MCExpr *LHS, const MCExpr *RHS, MCContext &Ctx)
Context object for machine code objects.
const MCObjectFileInfo * getObjectFileInfo() const
LLVM_ABI MCSymbol * getOrCreateSymbol(const Twine &Name)
Lookup the symbol inside with the specified Name.
MCSection * getStackMapSection() const
Wrapper class representing physical registers. Should be passed by value.
Instances of this class represent a uniqued identifier for a section in the current translation unit.
Streaming machine code generation interface.
virtual void addBlankLine()
Emit a blank line to a .s file to pretty it up.
void emitValue(const MCExpr *Value, unsigned Size, SMLoc Loc=SMLoc())
void emitSymbolValue(const MCSymbol *Sym, unsigned Size, bool IsSectionRelative=false)
Special case of EmitValue that avoids the client having to pass in a MCExpr for MCSymbols.
virtual void emitLabel(MCSymbol *Symbol, SMLoc Loc=SMLoc())
Emit a label for Symbol into the current section.
virtual void emitValueToAlignment(Align Alignment, int64_t Fill=0, uint8_t FillLen=1, unsigned MaxBytesToEmit=0)
Emit some number of copies of Value until the byte alignment ByteAlignment is reached.
virtual void emitIntValue(uint64_t Value, unsigned Size)
Special case of EmitValue that avoids the client having to pass in a MCExpr for constant integers.
void emitInt16(uint64_t Value)
virtual void switchSection(MCSection *Section, uint32_t Subsec=0)
Set the current section where code is being emitted to Section.
void emitInt32(uint64_t Value)
static const MCSymbolRefExpr * create(const MCSymbol *Symbol, MCContext &Ctx, SMLoc Loc=SMLoc())
MCSymbol - Instances of this class represent a symbol name in the MC file, and MCSymbols are created ...
bool hasVarSizedObjects() const
This method may be called any time after instruction selection is complete to determine if the stack ...
uint64_t getStackSize() const
Return the number of bytes that must be allocated to hold all of the fixed size frame objects.
Representation of each machine instruction.
const MachineOperand * const_mop_iterator
MachineOperand class - Representation of each machine instruction operand.
unsigned getSubReg() const
const uint32_t * getRegLiveOut() const
getRegLiveOut - Returns a bit mask of live-out registers.
bool isReg() const
isReg - Tests if this is a MO_Register operand.
bool isImm() const
isImm - Tests if this is a MO_Immediate operand.
bool isRegLiveOut() const
isRegLiveOut - Tests if this is a MO_RegisterLiveOut operand.
Register getReg() const
getReg - Returns the register number.
MI-level patchpoint operands.
uint32_t getNumCallArgs() const
Return the number of call arguments.
LLVM_ABI PatchPointOpers(const MachineInstr *MI)
LLVM_ABI unsigned getNextScratchIdx(unsigned StartIdx=0) const
Get the next scratch register operand index.
uint64_t getID() const
Return the ID for the given patchpoint.
unsigned getStackMapStartIdx() const
Get the index at which stack map locations will be recorded.
unsigned getVarIdx() const
Get the operand index of the variable list of non-argument operands.
Wrapper class representing virtual and physical registers.
constexpr bool isPhysical() const
Return true if the specified register number is in the physical register namespace.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void push_back(const T &Elt)
MI-level stackmap operands.
LLVM_ABI StackMapOpers(const MachineInstr *MI)
unsigned getVarIdx() const
Get the operand index of the variable list of non-argument operands.
static LLVM_ABI unsigned getNextMetaArgIdx(const MachineInstr *MI, unsigned CurIdx)
Get index of next meta operand.
LLVM_ABI StackMaps(AsmPrinter &AP)
LLVM_ABI void serializeToStackMapSection()
If there is any stack map data, create a stack map section and serialize the map info into it.
SmallVector< LiveOutReg, 8 > LiveOutVec
SmallVector< Location, 8 > LocationVec
LLVM_ABI void recordStatepoint(const MCSymbol &L, const MachineInstr &MI)
Generate a stackmap record for a statepoint instruction.
LLVM_ABI void recordPatchPoint(const MCSymbol &L, const MachineInstr &MI)
Generate a stackmap record for a patchpoint instruction.
LLVM_ABI void recordStackMap(const MCSymbol &L, const MachineInstr &MI)
Generate a stackmap record for a stackmap instruction.
MI-level Statepoint operands.
StatepointOpers(const MachineInstr *MI)
LLVM_ABI unsigned getGCPointerMap(SmallVectorImpl< std::pair< unsigned, unsigned > > &GCMap)
Get vector of base/derived pairs from statepoint.
LLVM_ABI unsigned getNumAllocaIdx()
Get index of number of gc allocas.
LLVM_ABI unsigned getNumGcMapEntriesIdx()
Get index of number of gc map entries.
LLVM_ABI int getFirstGCPtrIdx()
Get index of first GC pointer operand of -1 if there are none.
unsigned getNumDeoptArgsIdx() const
Get index of Number Deopt Arguments operand.
uint64_t getID() const
Return the ID for the given statepoint.
LLVM_ABI bool isFoldableReg(Register Reg) const
Return true if Reg is used only in operands which can be folded to stack usage.
unsigned getVarIdx() const
Get starting index of non call related arguments (calling convention, statepoint flags,...
LLVM_ABI unsigned getNumGCPtrIdx()
Get index of number of GC pointers.
TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...
bool hasStackRealignment(const MachineFunction &MF) const
True if stack realignment is required and still possible.
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
The instances of the Type class are immutable: once they are created, they are never changed.
This class implements an extremely fast bulk output stream that can only output to a stream.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
constexpr char Align[]
Key for Kernel::Arg::Metadata::mAlign.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
initializer< Ty > init(const Ty &Val)
This is an optimization pass for GlobalISel generic memory operations.
constexpr bool isInt(int64_t x)
Checks if an integer fits into the given bit width.
MachineInstr * getImm(const MachineOperand &MO, const MachineRegisterInfo *MRI)
void sort(IteratorTy Start, IteratorTy End)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
constexpr bool isUInt(uint64_t x)
Checks if an unsigned integer fits into the given bit width.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
uint16_t MCPhysReg
An unsigned integer type large enough to represent all physical registers, but not necessarily virtua...
void erase_if(Container &C, UnaryPredicate P)
Provide a container algorithm similar to C++ Library Fundamentals v2's erase_if which is equivalent t...
LLVM_ABI Printable printReg(Register Reg, const TargetRegisterInfo *TRI=nullptr, unsigned SubIdx=0, const MachineRegisterInfo *MRI=nullptr)
Prints virtual and physical registers with or without a TRI instance.