Go to the documentation of this file.
40 #define DEBUG_TYPE "stackmaps"
44 cl::desc(
"Specify the stackmap encoding version (default = 3)"));
46 const 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();
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");
200 assert(RegNum >= 0 &&
"Invalid Dwarf register number.");
201 return (
unsigned)RegNum;
207 LiveOutVec &LiveOuts)
const {
213 case StackMaps::DirectMemRefOp: {
216 unsigned Size =
DL.getPointerSizeInBits();
217 assert((Size % 8) == 0 &&
"Need pointer size in bytes.");
220 int64_t
Imm = (++MOI)->getImm();
225 case StackMaps::IndirectMemRefOp: {
226 int64_t
Size = (++MOI)->getImm();
227 assert(Size > 0 &&
"Need a valid size for indirect memory locations.");
229 int64_t
Imm = (++MOI)->getImm();
234 case StackMaps::ConstantOp: {
236 assert(MOI->
isImm() &&
"Expected constant operand.");
261 "Virtreg operands should have been rewritten before now.");
286 OS << WSMP <<
"callsites:\n";
287 for (
const auto &CSI : CSInfos) {
291 OS << WSMP <<
"callsite " << CSI.ID <<
"\n";
292 OS << WSMP <<
" has " << CSLocs.size() <<
" locations\n";
295 for (
const auto &Loc : CSLocs) {
296 OS << WSMP <<
"\t\tLoc " << Idx <<
": ";
299 OS <<
"<Unprocessed operand>";
315 OS <<
" + " << Loc.Offset;
323 OS <<
"+" << Loc.Offset;
326 OS <<
"Constant " << Loc.Offset;
329 OS <<
"Constant Index " << Loc.Offset;
332 OS <<
"\t[encoding: .byte " << Loc.Type <<
", .byte 0"
333 <<
", .short " << Loc.Size <<
", .short " << Loc.Reg <<
", .short 0"
334 <<
", .int " << Loc.Offset <<
"]\n";
338 OS << WSMP <<
"\thas " << LiveOuts.size() <<
" live-out registers\n";
341 for (
const auto &
LO : LiveOuts) {
342 OS << WSMP <<
"\t\tLO " << Idx <<
": ";
347 OS <<
"\t[encoding: .short " <<
LO.DwarfRegNum <<
", .byte 0, .byte "
359 return LiveOutReg(
Reg, DwarfRegNum, Size);
365 StackMaps::parseRegisterLiveOutMask(
const uint32_t *
Mask)
const {
373 LiveOuts.push_back(createLiveOutReg(
Reg,
TRI));
381 return LHS.DwarfRegNum <
RHS.DwarfRegNum;
384 for (
auto I = LiveOuts.begin(),
E = LiveOuts.end();
I !=
E; ++
I) {
385 for (
auto *II = std::next(
I); II !=
E; ++II) {
386 if (
I->DwarfRegNum != II->DwarfRegNum) {
408 LocationVec &Locations,
409 LiveOutVec &LiveOuts) {
412 MOI = parseOperand(MOI, MOE, Locations, LiveOuts);
413 MOI = parseOperand(MOI, MOE, Locations, LiveOuts);
414 MOI = parseOperand(MOI, MOE, Locations, LiveOuts);
417 unsigned NumDeoptArgs =
Locations.back().Offset;
419 assert(NumDeoptArgs == SO.getNumDeoptArgs());
421 while (NumDeoptArgs--)
422 MOI = parseOperand(MOI, MOE, Locations, LiveOuts);
428 unsigned NumGCPointers = MOI->
getImm();
433 unsigned GCPtrIdx = (unsigned)SO.getFirstGCPtrIdx();
434 assert((
int)GCPtrIdx != -1);
435 assert(MOI -
MI.operands_begin() == GCPtrIdx + 0LL);
436 while (NumGCPointers--) {
437 GCPtrIndices.push_back(GCPtrIdx);
442 unsigned NumGCPairs = SO.getGCPointerMap(GCPairs);
446 auto MOB =
MI.operands_begin();
447 for (
auto &
P : GCPairs) {
448 assert(
P.first < GCPtrIndices.size() &&
"base pointer index not found");
449 assert(
P.second < GCPtrIndices.size() &&
450 "derived pointer index not found");
451 unsigned BaseIdx = GCPtrIndices[
P.first];
452 unsigned DerivedIdx = GCPtrIndices[
P.second];
453 LLVM_DEBUG(
dbgs() <<
"Base : " << BaseIdx <<
" Derived : " << DerivedIdx
455 (void)parseOperand(MOB + BaseIdx, MOE, Locations, LiveOuts);
456 (void)parseOperand(MOB + DerivedIdx, MOE, Locations, LiveOuts);
459 MOI = MOB + GCPtrIdx;
466 unsigned NumAllocas = MOI->
getImm();
468 while (NumAllocas--) {
469 MOI = parseOperand(MOI, MOE, Locations, LiveOuts);
474 void StackMaps::recordStackMapOpers(
const MCSymbol &MILabel,
486 parseOperand(
MI.operands_begin(), std::next(
MI.operands_begin()), Locations,
491 if (
MI.getOpcode() == TargetOpcode::STATEPOINT)
492 parseStatepointOpers(
MI, MOI, MOE, Locations, LiveOuts);
495 MOI = parseOperand(MOI, MOE, Locations, LiveOuts);
498 for (
auto &Loc : Locations) {
512 "empty and tombstone keys should fit in 32 bits!");
513 auto Result = ConstPool.
insert(std::make_pair(Loc.Offset, Loc.Offset));
524 CSInfos.emplace_back(CSOffsetExpr,
ID,
std::move(Locations),
530 bool HasDynamicFrameSize =
535 if (CurrentIt != FnInfos.
end())
536 CurrentIt->second.RecordCount++;
546 recordStackMapOpers(L,
MI,
ID, std::next(
MI.operands_begin(),
555 const int64_t
ID = opers.
getID();
557 recordStackMapOpers(L,
MI,
ID, MOI,
MI.operands_end(),
562 auto &Locations = CSInfos.back().Locations;
565 for (
unsigned i = 0,
e = (opers.
hasDef() ? NArgs + 1 : NArgs);
i !=
e; ++
i)
567 "anyreg arg must be in reg.");
573 assert(
MI.getOpcode() == TargetOpcode::STATEPOINT &&
"expected statepoint");
576 const unsigned StartIdx = opers.
getVarIdx();
577 recordStackMapOpers(L,
MI, opers.
getID(),
MI.operands_begin() + StartIdx,
578 MI.operands_end(),
false);
591 void StackMaps::emitStackmapHeader(
MCStreamer &OS) {
604 LLVM_DEBUG(
dbgs() << WSMP <<
"#callsites = " << CSInfos.size() <<
'\n');
615 void StackMaps::emitFunctionFrameRecords(
MCStreamer &OS) {
618 for (
auto const &FR : FnInfos) {
620 <<
" frame size: " << FR.second.StackSize
621 <<
" callsite count: " << FR.second.RecordCount <<
'\n');
631 void StackMaps::emitConstantPoolEntries(
MCStreamer &OS) {
634 for (
const auto &ConstEntry : ConstPool) {
669 void StackMaps::emitCallsiteEntries(
MCStreamer &OS) {
672 for (
const auto &CSI : CSInfos) {
680 if (CSLocs.size() > UINT16_MAX || LiveOuts.size() > UINT16_MAX) {
698 for (
const auto &Loc : CSLocs) {
714 for (
const auto &
LO : LiveOuts) {
728 assert((!CSInfos.empty() || ConstPool.empty()) &&
729 "Expected empty constant pool too!");
730 assert((!CSInfos.empty() || FnInfos.empty()) &&
731 "Expected empty function record too!");
748 emitStackmapHeader(OS);
749 emitFunctionFrameRecords(OS);
750 emitConstantPoolEntries(OS);
751 emitCallsiteEntries(OS);
bool hasVarSizedObjects() const
This method may be called any time after instruction selection is complete to determine if the stack ...
const MCObjectFileInfo * getObjectFileInfo() const
uint32_t getNumCallArgs() const
Return the number of call arguments.
iterator_range< mop_iterator > uses()
Returns a range that includes all operands that are register uses.
unsigned getOperandNo(const_mop_iterator I) const
Returns the number of the operand iterator I points to.
This is an optimization pass for GlobalISel generic memory operations.
MI-level stackmap operands.
static cl::opt< int > StackMapVersion("stackmap-version", cl::init(3), cl::Hidden, cl::desc("Specify the stackmap encoding version (default = 3)"))
MCSymbol - Instances of this class represent a symbol name in the MC file, and MCSymbols are created ...
void recordStatepoint(const MCSymbol &L, const MachineInstr &MI)
Generate a stackmap record for a statepoint instruction.
MCSymbol * CurrentFnSymForSize
The symbol used to represent the start of the current function for the purpose of calculating its siz...
Context object for machine code objects.
This currently compiles esp xmm0 movsd esp eax eax esp ret We should use not the dag combiner This is because dagcombine2 needs to be able to see through the X86ISD::Wrapper which DAGCombine can t really do The code for turning x load into a single vector load is target independent and should be moved to the dag combiner The code for turning x load into a vector load can only handle a direct load from a global or a direct load from the stack It should be generalized to handle any load from P
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
int getDwarfRegNum(MCRegister RegNum, bool isEH) const
Map a target register to an equivalent dwarf register number.
unsigned getNumRegs() const
Return the number of registers this target has (useful for sizing arrays holding per register informa...
Reg
All possible values of the reg field in the ModR/M byte.
void erase_if(Container &C, UnaryPredicate P)
Provide a container algorithm similar to C++ Library Fundamentals v2's erase_if which is equivalent t...
virtual const TargetRegisterInfo * getRegisterInfo() const
getRegisterInfo - If register information is available, return it.
void emitValue(const MCExpr *Value, unsigned Size, SMLoc Loc=SMLoc())
StatepointOpers(const MachineInstr *MI)
static unsigned getDwarfRegNum(unsigned Reg, const TargetRegisterInfo *TRI)
Go up the super-register chain until we hit a valid dwarf register number.
TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...
The instances of the Type class are immutable: once they are created, they are never changed.
unsigned getNumGcMapEntriesIdx()
Get index of number of gc map entries.
void emitInt32(uint64_t Value)
Expected< ExpressionValue > max(const ExpressionValue &Lhs, const ExpressionValue &Rhs)
MI-level patchpoint operands.
unsigned const TargetRegisterInfo * TRI
uint64_t getID() const
Return the ID for the given patchpoint.
void recordStackMap(const MCSymbol &L, const MachineInstr &MI)
Generate a stackmap record for a stackmap instruction.
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
constexpr std::underlying_type_t< E > Mask()
Get a bitmask with 1s in all places up to the high-order bit of E's largest value.
bool isPhysical() const
Return true if the specified register number is in the physical register namespace.
Streaming machine code generation interface.
unsigned getNumDeoptArgsIdx() const
Get index of Number Deopt Arguments operand.
An information struct used to provide DenseMap with the various necessary components for a given valu...
MCSymbol * getOrCreateSymbol(const Twine &Name)
Lookup the symbol inside with the specified Name.
static unsigned getReg(const MCDisassembler *D, unsigned RC, unsigned RegNo)
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
std::unique_ptr< MCStreamer > OutStreamer
This is the MCStreamer object for the file we are generating.
const MachineOperand & getOperand(unsigned i) const
unsigned getGCPointerMap(SmallVectorImpl< std::pair< unsigned, unsigned >> &GCMap)
Get vector of base/derived pairs from statepoint.
virtual void emitLabel(MCSymbol *Symbol, SMLoc Loc=SMLoc())
Emit a label for Symbol into the current section.
virtual void switchSection(MCSection *Section, const MCExpr *Subsection=nullptr)
Set the current section where code is being emitted to Section.
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.
MCSection * getStackMapSection() const
unsigned getSubRegIndex(MCRegister RegNo, MCRegister SubRegNo) const
For a given register pair, return the sub-register index if the second register is a sub-register of ...
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
MachineOperand class - Representation of each machine instruction operand.
unsigned getVarIdx() const
Get starting index of non call related arguments (calling convention, statepoint flags,...
MCSymbol * CurrentFnSym
The symbol for the current function.
StackMaps(AsmPrinter &AP)
PatchPointOpers(const MachineInstr *MI)
This class implements an extremely fast bulk output stream that can only output to a stream.
uint64_t getStackSize() const
Return the number of bytes that must be allocated to hold all of the fixed size frame objects.
virtual void addBlankLine()
Emit a blank line to a .s file to pretty it up.
bool isRegLiveOut() const
isRegLiveOut - Tests if this is a MO_RegisterLiveOut operand.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
void sort(IteratorTy Start, IteratorTy End)
unsigned getNextScratchIdx(unsigned StartIdx=0) const
Get the next scratch register operand index.
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
void emitInt16(uint64_t Value)
unsigned getSpillSize(const TargetRegisterClass &RC) const
Return the size in bytes of the stack slot allocated to hold a spilled copy of a register from class ...
unsigned getNumAllocaIdx()
Get index of number of gc allocas.
unsigned getVarIdx() const
Get the operand index of the variable list of non-argument operands.
unsigned getVarIdx() const
Get the operand index of the variable list of non-argument operands.
iterator find(const KeyT &Key)
bool isReg() const
isReg - Tests if this is a MO_Register operand.
Representation of each machine instruction.
static GCRegistry::Add< StatepointGC > D("statepoint-example", "an example strategy for statepoint")
void serializeToStackMapSection()
If there is any stack map data, create a stack map section and serialize the map info into it.
compiles ldr LCPI1_0 ldr ldr mov lsr tst moveq r1 ldr LCPI1_1 and r0 bx lr It would be better to do something like to fold the shift into the conditional move
initializer< Ty > init(const Ty &Val)
SmallVector< LiveOutReg, 8 > LiveOutVec
std::optional< unsigned > getLLVMRegNum(unsigned RegNum, bool isEH) const
Map a dwarf register back to a target register.
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
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.
MachineFrameInfo & getFrameInfo()
getFrameInfo - Return the frame info object for the current function.
bool isEarlyClobber() const
static const MCBinaryExpr * createSub(const MCExpr *LHS, const MCExpr *RHS, MCContext &Ctx)
MachineFunction * MF
The current machine function.
MCSuperRegIterator enumerates all super-registers of Reg.
Register getReg() const
getReg - Returns the register number.
static unsigned getNextMetaArgIdx(const MachineInstr *MI, unsigned CurIdx)
Get index of next meta operand.
unsigned getStackMapStartIdx() const
Get the index at which stack map locations will be recorded.
static bool isReg(const MCInst &MI, unsigned OpNo)
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
Instances of this class represent a uniqued identifier for a section in the current translation unit.
virtual void emitValueToAlignment(Align Alignment, int64_t Value=0, unsigned ValueSize=1, unsigned MaxBytesToEmit=0)
Emit some number of copies of Value until the byte alignment ByteAlignment is reached.
StackMapOpers(const MachineInstr *MI)
Wrapper class representing virtual and physical registers.
unsigned getSubReg() const
int getFirstGCPtrIdx()
Get index of first GC pointer operand of -1 if there are none.
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
MI-level Statepoint operands.
bool isFoldableReg(Register Reg) const
Return true if Reg is used only in operands which can be folded to stack usage.
void recordPatchPoint(const MCSymbol &L, const MachineInstr &MI)
Generate a stackmap record for a patchpoint instruction.
This class is intended to be used as a driving class for all asm writers.
static const MCSymbolRefExpr * create(const MCSymbol *Symbol, MCContext &Ctx)
bool isImm() const
isImm - Tests if this is a MO_Immediate operand.
bool hasStackRealignment(const MachineFunction &MF) const
True if stack realignment is required and still possible.
bool isSuperRegister(MCRegister RegA, MCRegister RegB) const
Returns true if RegB is a super-register of RegA.
static uint64_t getConstMetaVal(const MachineInstr &MI, unsigned Idx)
The MachineFrameInfo class represents an abstract stack frame until prolog/epilog code is inserted.
bool isValid() const
isValid - returns true if this iterator is not yet at the end.
unsigned getNumOperands() const
Retuns the total number of operands.
const DataLayout & getDataLayout() const
Return the DataLayout attached to the Module associated to this MF.
const uint32_t * getRegLiveOut() const
getRegLiveOut - Returns a bit mask of live-out registers.
unsigned getSubRegIdxOffset(unsigned Idx) const
Get the offset of the bit range covered by a sub-register index.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
uint64_t getID() const
Return the ID for the given statepoint.
SmallVector< Location, 8 > LocationVec
const TargetRegisterClass * getMinimalPhysRegClass(MCRegister Reg, MVT VT=MVT::Other) const
Returns the Register Class of a physical register of the given type, picking the most sub register cl...
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.
Base class for the full range of assembler expressions which are needed for parsing.
unsigned getNumGCPtrIdx()
Get index of number of GC pointers.