40#define DEBUG_TYPE "stackmaps"
44 cl::desc(
"Specify the stackmap encoding version (default = 3)"));
46const char *StackMaps::WSMP =
"Stack Maps: ";
50 MI.getOperand(
Idx).getImm() == StackMaps::ConstantOp);
51 const auto &MO =
MI.getOperand(
Idx + 1);
59 "invalid stackmap definition");
63 :
MI(
MI), HasDef(
MI->getOperand(0).
isReg() &&
MI->getOperand(0).isDef() &&
64 !
MI->getOperand(0).isImplicit()) {
66 unsigned CheckStartIdx = 0, e =
MI->getNumOperands();
67 while (CheckStartIdx < e && MI->getOperand(CheckStartIdx).
isReg() &&
68 MI->getOperand(CheckStartIdx).isDef() &&
69 !
MI->getOperand(CheckStartIdx).isImplicit())
72 assert(getMetaIdx() == CheckStartIdx &&
73 "Unexpected additional definition in Patchpoint intrinsic.");
83 while (ScratchIdx < e &&
90 assert(ScratchIdx != e &&
"No scratch register available");
119 while (NumDeoptArgs--) {
131 assert(NumGCPtrsIdx < MI->getNumOperands());
132 return (
int)NumGCPtrsIdx;
140 for (
unsigned N = 0;
N < GCMapSize; ++
N) {
143 GCMap.push_back(std::make_pair(
B,
D));
150 unsigned FoldableAreaStart =
getVarIdx();
152 if (MO.getOperandNo() >= FoldableAreaStart)
154 if (MO.isReg() && MO.getReg() == Reg)
161 if (
MI->getOpcode() != TargetOpcode::STATEPOINT)
172 assert(CurIdx < MI->getNumOperands() &&
"Bad meta arg index");
173 const auto &MO =
MI->getOperand(CurIdx);
175 switch (MO.getImm()) {
178 case StackMaps::DirectMemRefOp:
181 case StackMaps::IndirectMemRefOp:
184 case StackMaps::ConstantOp:
190 assert(CurIdx < MI->getNumOperands() &&
"points past operand list");
198 RegNum =
TRI->getDwarfRegNum(SR,
false);
203 assert(RegNum >= 0 &&
"Invalid Dwarf register number.");
204 return (
unsigned)RegNum;
210 LiveOutVec &LiveOuts)
const {
216 case StackMaps::DirectMemRefOp: {
219 unsigned Size =
DL.getPointerSizeInBits();
220 assert((
Size % 8) == 0 &&
"Need pointer size in bytes.");
223 int64_t
Imm = (++MOI)->getImm();
228 case StackMaps::IndirectMemRefOp: {
229 int64_t
Size = (++MOI)->getImm();
230 assert(
Size > 0 &&
"Need a valid size for indirect memory locations.");
232 int64_t
Imm = (++MOI)->getImm();
237 case StackMaps::ConstantOp: {
239 assert(MOI->
isImm() &&
"Expected constant operand.");
264 "Virtreg operands should have been rewritten before now.");
270 unsigned LLVMRegNum = *
TRI->getLLVMRegNum(DwarfRegNum,
false);
271 unsigned SubRegIdx =
TRI->getSubRegIndex(LLVMRegNum, MOI->
getReg());
273 Offset =
TRI->getSubRegIdxOffset(SubRegIdx);
289 OS << WSMP <<
"callsites:\n";
290 for (
const auto &CSI : CSInfos) {
294 OS << WSMP <<
"callsite " << CSI.ID <<
"\n";
295 OS << WSMP <<
" has " << CSLocs.size() <<
" locations\n";
298 for (
const auto &Loc : CSLocs) {
299 OS << WSMP <<
"\t\tLoc " <<
Idx <<
": ";
302 OS <<
"<Unprocessed operand>";
318 OS <<
" + " << Loc.Offset;
326 OS <<
"+" << Loc.Offset;
329 OS <<
"Constant " << Loc.Offset;
332 OS <<
"Constant Index " << Loc.Offset;
335 OS <<
"\t[encoding: .byte " << Loc.Type <<
", .byte 0"
336 <<
", .short " << Loc.Size <<
", .short " << Loc.Reg <<
", .short 0"
337 <<
", .int " << Loc.Offset <<
"]\n";
341 OS << WSMP <<
"\thas " << LiveOuts.size() <<
" live-out registers\n";
344 for (
const auto &LO : LiveOuts) {
345 OS << WSMP <<
"\t\tLO " <<
Idx <<
": ";
350 OS <<
"\t[encoding: .short " <<
LO.DwarfRegNum <<
", .byte 0, .byte "
361 unsigned Size =
TRI->getSpillSize(*
TRI->getMinimalPhysRegClass(Reg));
362 return LiveOutReg(Reg, DwarfRegNum,
Size);
368StackMaps::parseRegisterLiveOutMask(
const uint32_t *Mask)
const {
369 assert(Mask &&
"No register mask specified");
374 for (
unsigned Reg = 0, NumRegs =
TRI->getNumRegs(); Reg != NumRegs; ++Reg)
375 if ((Mask[Reg / 32] >> (Reg % 32)) & 1)
382 llvm::sort(LiveOuts, [](
const LiveOutReg &LHS,
const LiveOutReg &RHS) {
384 return LHS.DwarfRegNum <
RHS.DwarfRegNum;
387 for (
auto I = LiveOuts.begin(),
E = LiveOuts.end();
I !=
E; ++
I) {
388 for (
auto *II = std::next(
I); II !=
E; ++II) {
389 if (
I->DwarfRegNum != II->DwarfRegNum) {
394 I->Size = std::max(
I->Size, II->Size);
395 if (
I->Reg &&
TRI->isSuperRegister(
I->Reg, II->Reg))
411 LocationVec &Locations,
412 LiveOutVec &LiveOuts) {
415 MOI = parseOperand(MOI, MOE, Locations, LiveOuts);
416 MOI = parseOperand(MOI, MOE, Locations, LiveOuts);
417 MOI = parseOperand(MOI, MOE, Locations, LiveOuts);
420 unsigned NumDeoptArgs =
Locations.back().Offset;
422 assert(NumDeoptArgs == SO.getNumDeoptArgs());
424 while (NumDeoptArgs--)
425 MOI = parseOperand(MOI, MOE, Locations, LiveOuts);
431 unsigned NumGCPointers = MOI->
getImm();
436 unsigned GCPtrIdx = (
unsigned)SO.getFirstGCPtrIdx();
437 assert((
int)GCPtrIdx != -1);
438 assert(MOI -
MI.operands_begin() == GCPtrIdx + 0LL);
439 while (NumGCPointers--) {
445 unsigned NumGCPairs = SO.getGCPointerMap(GCPairs);
449 auto MOB =
MI.operands_begin();
450 for (
auto &
P : GCPairs) {
451 assert(
P.first < GCPtrIndices.
size() &&
"base pointer index not found");
453 "derived pointer index not found");
454 unsigned BaseIdx = GCPtrIndices[
P.first];
455 unsigned DerivedIdx = GCPtrIndices[
P.second];
456 LLVM_DEBUG(
dbgs() <<
"Base : " << BaseIdx <<
" Derived : " << DerivedIdx
458 (void)parseOperand(MOB + BaseIdx, MOE, Locations, LiveOuts);
459 (void)parseOperand(MOB + DerivedIdx, MOE, Locations, LiveOuts);
462 MOI = MOB + GCPtrIdx;
469 unsigned NumAllocas = MOI->
getImm();
471 while (NumAllocas--) {
472 MOI = parseOperand(MOI, MOE, Locations, LiveOuts);
477void StackMaps::recordStackMapOpers(
const MCSymbol &MILabel,
489 parseOperand(
MI.operands_begin(), std::next(
MI.operands_begin()), Locations,
494 if (
MI.getOpcode() == TargetOpcode::STATEPOINT)
495 parseStatepointOpers(
MI, MOI, MOE, Locations, LiveOuts);
498 MOI = parseOperand(MOI, MOE, Locations, LiveOuts);
501 for (
auto &Loc : Locations) {
515 "empty and tombstone keys should fit in 32 bits!");
516 auto Result = ConstPool.
insert(std::make_pair(Loc.Offset, Loc.Offset));
527 CSInfos.emplace_back(CSOffsetExpr,
ID, std::move(Locations),
528 std::move(LiveOuts));
533 bool HasDynamicFrameSize =
538 if (CurrentIt != FnInfos.
end())
539 CurrentIt->second.RecordCount++;
545 assert(
MI.getOpcode() == TargetOpcode::STACKMAP &&
"expected stackmap");
549 recordStackMapOpers(L,
MI,
ID, std::next(
MI.operands_begin(),
555 assert(
MI.getOpcode() == TargetOpcode::PATCHPOINT &&
"expected patchpoint");
558 const int64_t
ID = opers.
getID();
560 recordStackMapOpers(L,
MI,
ID, MOI,
MI.operands_end(),
565 auto &Locations = CSInfos.back().Locations;
568 for (
unsigned i = 0, e = (opers.
hasDef() ? NArgs + 1 : NArgs); i != e; ++i)
570 "anyreg arg must be in reg.");
576 assert(
MI.getOpcode() == TargetOpcode::STATEPOINT &&
"expected statepoint");
579 const unsigned StartIdx = opers.
getVarIdx();
580 recordStackMapOpers(L,
MI, opers.
getID(),
MI.operands_begin() + StartIdx,
581 MI.operands_end(),
false);
597 OS.emitIntValue(0, 1);
602 OS.emitInt32(FnInfos.
size());
605 OS.emitInt32(ConstPool.
size());
607 LLVM_DEBUG(
dbgs() << WSMP <<
"#callsites = " << CSInfos.size() <<
'\n');
608 OS.emitInt32(CSInfos.size());
618void StackMaps::emitFunctionFrameRecords(
MCStreamer &
OS) {
621 for (
auto const &FR : FnInfos) {
623 <<
" frame size: " << FR.second.StackSize
624 <<
" callsite count: " << FR.second.RecordCount <<
'\n');
625 OS.emitSymbolValue(FR.first, 8);
626 OS.emitIntValue(FR.second.StackSize, 8);
627 OS.emitIntValue(FR.second.RecordCount, 8);
634void StackMaps::emitConstantPoolEntries(
MCStreamer &
OS) {
637 for (
const auto &ConstEntry : ConstPool) {
639 OS.emitIntValue(ConstEntry.second, 8);
675 for (
const auto &CSI : CSInfos) {
683 if (CSLocs.size() > UINT16_MAX || LiveOuts.size() > UINT16_MAX) {
685 OS.emitValue(CSI.CSOffsetExpr, 4);
694 OS.emitIntValue(CSI.ID, 8);
695 OS.emitValue(CSI.CSOffsetExpr, 4);
699 OS.emitInt16(CSLocs.size());
701 for (
const auto &Loc : CSLocs) {
702 OS.emitIntValue(Loc.Type, 1);
703 OS.emitIntValue(0, 1);
704 OS.emitInt16(Loc.Size);
705 OS.emitInt16(Loc.Reg);
707 OS.emitInt32(Loc.Offset);
711 OS.emitValueToAlignment(
Align(8));
715 OS.emitInt16(LiveOuts.size());
717 for (
const auto &LO : LiveOuts) {
718 OS.emitInt16(
LO.DwarfRegNum);
719 OS.emitIntValue(0, 1);
720 OS.emitIntValue(
LO.Size, 1);
723 OS.emitValueToAlignment(
Align(8));
731 assert((!CSInfos.empty() || ConstPool.empty()) &&
732 "Expected empty constant pool too!");
733 assert((!CSInfos.empty() || FnInfos.empty()) &&
734 "Expected empty function record too!");
744 OS.switchSection(StackMapSection);
751 emitStackmapHeader(
OS);
752 emitFunctionFrameRecords(
OS);
753 emitConstantPoolEntries(
OS);
754 emitCallsiteEntries(
OS);
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static GCRegistry::Add< StatepointGC > D("statepoint-example", "an example strategy for statepoint")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
Returns the sub type a function will return at a given Idx Should correspond to the result type of an ExtractValue instruction executed with just that one unsigned Idx
This file defines DenseMapInfo traits for DenseMap.
unsigned const TargetRegisterInfo * TRI
static unsigned getReg(const MCDisassembler *D, unsigned RC, unsigned RegNo)
static bool isReg(const MCInst &MI, unsigned OpNo)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
static uint64_t getConstMetaVal(const MachineInstr &MI, unsigned Idx)
static unsigned getDwarfRegNum(unsigned Reg, const TargetRegisterInfo *TRI)
Go up the super-register chain until we hit a valid dwarf register number.
static cl::opt< int > StackMapVersion("stackmap-version", cl::init(3), cl::Hidden, cl::desc("Specify the stackmap encoding version (default = 3)"))
This class is intended to be used as a driving class for all asm writers.
MachineFunction * MF
The current machine function.
MCSymbol * CurrentFnSym
The symbol for the current function.
std::unique_ptr< MCStreamer > OutStreamer
This is the MCStreamer object for the file we are generating.
MCSymbol * CurrentFnSymForSize
The symbol used to represent the start of the current function for the purpose of calculating its siz...
static const MCBinaryExpr * createSub(const MCExpr *LHS, const MCExpr *RHS, MCContext &Ctx)
Context object for machine code objects.
const MCObjectFileInfo * getObjectFileInfo() const
MCSymbol * getOrCreateSymbol(const Twine &Name)
Lookup the symbol inside with the specified Name.
Base class for the full range of assembler expressions which are needed for parsing.
MCSection * getStackMapSection() const
Instances of this class represent a uniqued identifier for a section in the current translation unit.
Streaming machine code generation interface.
static const MCSymbolRefExpr * create(const MCSymbol *Symbol, MCContext &Ctx)
MCSymbol - Instances of this class represent a symbol name in the MC file, and MCSymbols are created ...
The MachineFrameInfo class represents an abstract stack frame until prolog/epilog code is inserted.
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.
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
MachineFrameInfo & getFrameInfo()
getFrameInfo - Return the frame info object for the current function.
const DataLayout & getDataLayout() const
Return the DataLayout attached to the Module associated to this MF.
Representation of each machine instruction.
iterator_range< mop_iterator > uses()
Returns a range that includes all operands that are register uses.
unsigned getNumOperands() const
Retuns the total number of operands.
const MachineOperand & getOperand(unsigned i) const
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.
bool isEarlyClobber() const
Register getReg() const
getReg - Returns the register number.
iterator find(const KeyT &Key)
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
MI-level patchpoint operands.
uint32_t getNumCallArgs() const
Return the number of call arguments.
PatchPointOpers(const MachineInstr *MI)
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.
StackMapOpers(const MachineInstr *MI)
unsigned getVarIdx() const
Get the operand index of the variable list of non-argument operands.
static unsigned getNextMetaArgIdx(const MachineInstr *MI, unsigned CurIdx)
Get index of next meta operand.
StackMaps(AsmPrinter &AP)
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
void recordStatepoint(const MCSymbol &L, const MachineInstr &MI)
Generate a stackmap record for a statepoint instruction.
void recordPatchPoint(const MCSymbol &L, const MachineInstr &MI)
Generate a stackmap record for a patchpoint instruction.
void recordStackMap(const MCSymbol &L, const MachineInstr &MI)
Generate a stackmap record for a stackmap instruction.
MI-level Statepoint operands.
unsigned getGCPointerMap(SmallVectorImpl< std::pair< unsigned, unsigned > > &GCMap)
Get vector of base/derived pairs from statepoint.
unsigned getNumAllocaIdx()
Get index of number of gc allocas.
unsigned getNumGcMapEntriesIdx()
Get index of number of gc map entries.
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.
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,...
unsigned getNumGCPtrIdx()
Get index of number of GC pointers.
TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...
virtual const TargetRegisterInfo * getRegisterInfo() const
getRegisterInfo - If register information is available, return it.
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.
Reg
All possible values of the reg field in the ModR/M byte.
initializer< Ty > init(const Ty &Val)
This is an optimization pass for GlobalISel generic memory operations.
void sort(IteratorTy Start, IteratorTy End)
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
void erase_if(Container &C, UnaryPredicate P)
Provide a container algorithm similar to C++ Library Fundamentals v2's erase_if which is equivalent t...
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.
This struct is a compact representation of a valid (non-zero power of two) alignment.
An information struct used to provide DenseMap with the various necessary components for a given valu...