//
//===----------------------------------------------------------------------===//
-#define DEBUG_TYPE "stackmaps"
-
#include "llvm/CodeGen/StackMaps.h"
#include "llvm/CodeGen/AsmPrinter.h"
+#include "llvm/CodeGen/MachineFrameInfo.h"
+#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCObjectFileInfo.h"
#include "llvm/MC/MCSectionMachO.h"
#include "llvm/MC/MCStreamer.h"
-#include "llvm/Support/Debug.h"
-#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/CommandLine.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetOpcodes.h"
#include "llvm/Target/TargetRegisterInfo.h"
+#include "llvm/Target/TargetSubtargetInfo.h"
#include <iterator>
using namespace llvm;
+#define DEBUG_TYPE "stackmaps"
+
+static cl::opt<int> StackMapVersion(
+ "stackmap-version", cl::init(1),
+ cl::desc("Specify the stackmap encoding version (default = 1)"));
+
+const char *StackMaps::WSMP = "Stack Maps: ";
+
PatchPointOpers::PatchPointOpers(const MachineInstr *MI)
- : MI(MI),
- HasDef(MI->getOperand(0).isReg() && MI->getOperand(0).isDef() &&
- !MI->getOperand(0).isImplicit()),
- IsAnyReg(MI->getOperand(getMetaIdx(CCPos)).getImm() == CallingConv::AnyReg)
-{
+ : MI(MI), HasDef(MI->getOperand(0).isReg() && MI->getOperand(0).isDef() &&
+ !MI->getOperand(0).isImplicit()),
+ IsAnyReg(MI->getOperand(getMetaIdx(CCPos)).getImm() ==
+ CallingConv::AnyReg) {
#ifndef NDEBUG
unsigned CheckStartIdx = 0, e = MI->getNumOperands();
while (CheckStartIdx < e && MI->getOperand(CheckStartIdx).isReg() &&
++CheckStartIdx;
assert(getMetaIdx() == CheckStartIdx &&
- "Unexpected additonal definition in Patchpoint intrinsic.");
+ "Unexpected additional definition in Patchpoint intrinsic.");
#endif
}
return ScratchIdx;
}
+StackMaps::StackMaps(AsmPrinter &AP) : AP(AP) {
+ if (StackMapVersion != 1)
+ llvm_unreachable("Unsupported stackmap version!");
+}
+
+/// Go up the super-register chain until we hit a valid dwarf register number.
+static unsigned getDwarfRegNum(unsigned Reg, const TargetRegisterInfo *TRI) {
+ int RegNum = TRI->getDwarfRegNum(Reg, false);
+ for (MCSuperRegIterator SR(Reg, TRI); SR.isValid() && RegNum < 0; ++SR)
+ RegNum = TRI->getDwarfRegNum(*SR, false);
+
+ assert(RegNum >= 0 && "Invalid Dwarf register number.");
+ return (unsigned)RegNum;
+}
+
MachineInstr::const_mop_iterator
StackMaps::parseOperand(MachineInstr::const_mop_iterator MOI,
- MachineInstr::const_mop_iterator MOE,
- LocationVec &Locs, LiveOutVec &LiveOuts) const {
+ MachineInstr::const_mop_iterator MOE, LocationVec &Locs,
+ LiveOutVec &LiveOuts) const {
+ const TargetRegisterInfo *TRI = AP.MF->getSubtarget().getRegisterInfo();
if (MOI->isImm()) {
switch (MOI->getImm()) {
- default: llvm_unreachable("Unrecognized operand type.");
+ default:
+ llvm_unreachable("Unrecognized operand type.");
case StackMaps::DirectMemRefOp: {
- unsigned Size = AP.TM.getDataLayout()->getPointerSizeInBits();
+ auto &DL = AP.MF->getDataLayout();
+
+ unsigned Size = DL.getPointerSizeInBits();
assert((Size % 8) == 0 && "Need pointer size in bytes.");
Size /= 8;
unsigned Reg = (++MOI)->getReg();
int64_t Imm = (++MOI)->getImm();
- Locs.push_back(Location(StackMaps::Location::Direct, Size, Reg, Imm));
+ Locs.emplace_back(StackMaps::Location::Direct, Size,
+ getDwarfRegNum(Reg, TRI), Imm);
break;
}
case StackMaps::IndirectMemRefOp: {
assert(Size > 0 && "Need a valid size for indirect memory locations.");
unsigned Reg = (++MOI)->getReg();
int64_t Imm = (++MOI)->getImm();
- Locs.push_back(Location(StackMaps::Location::Indirect, Size, Reg, Imm));
+ Locs.emplace_back(StackMaps::Location::Indirect, Size,
+ getDwarfRegNum(Reg, TRI), Imm);
break;
}
case StackMaps::ConstantOp: {
++MOI;
assert(MOI->isImm() && "Expected constant operand.");
int64_t Imm = MOI->getImm();
- Locs.push_back(Location(Location::Constant, sizeof(int64_t), 0, Imm));
+ Locs.emplace_back(Location::Constant, sizeof(int64_t), 0, Imm);
break;
}
}
assert(TargetRegisterInfo::isPhysicalRegister(MOI->getReg()) &&
"Virtreg operands should have been rewritten before now.");
- const TargetRegisterClass *RC =
- AP.TM.getRegisterInfo()->getMinimalPhysRegClass(MOI->getReg());
+ const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(MOI->getReg());
assert(!MOI->getSubReg() && "Physical subreg still around.");
- Locs.push_back(
- Location(Location::Register, RC->getSize(), MOI->getReg(), 0));
+
+ unsigned Offset = 0;
+ unsigned DwarfRegNum = getDwarfRegNum(MOI->getReg(), TRI);
+ unsigned LLVMRegNum = TRI->getLLVMRegNum(DwarfRegNum, false);
+ unsigned SubRegIdx = TRI->getSubRegIndex(LLVMRegNum, MOI->getReg());
+ if (SubRegIdx)
+ Offset = TRI->getSubRegIdxOffset(SubRegIdx);
+
+ Locs.emplace_back(Location::Register, RC->getSize(), DwarfRegNum, Offset);
return ++MOI;
}
return ++MOI;
}
-/// Go up the super-register chain until we hit a valid dwarf register number.
-static unsigned short getDwarfRegNum(unsigned Reg, const MCRegisterInfo &MCRI,
- const TargetRegisterInfo *TRI) {
- int RegNo = MCRI.getDwarfRegNum(Reg, false);
- for (MCSuperRegIterator SR(Reg, TRI);
- SR.isValid() && RegNo < 0; ++SR)
- RegNo = TRI->getDwarfRegNum(*SR, false);
-
- assert(RegNo >= 0 && "Invalid Dwarf register number.");
- return (unsigned short) RegNo;
+void StackMaps::print(raw_ostream &OS) {
+ const TargetRegisterInfo *TRI =
+ AP.MF ? AP.MF->getSubtarget().getRegisterInfo() : nullptr;
+ OS << WSMP << "callsites:\n";
+ for (const auto &CSI : CSInfos) {
+ const LocationVec &CSLocs = CSI.Locations;
+ const LiveOutVec &LiveOuts = CSI.LiveOuts;
+
+ OS << WSMP << "callsite " << CSI.ID << "\n";
+ OS << WSMP << " has " << CSLocs.size() << " locations\n";
+
+ unsigned Idx = 0;
+ for (const auto &Loc : CSLocs) {
+ OS << WSMP << "\t\tLoc " << Idx << ": ";
+ switch (Loc.Type) {
+ case Location::Unprocessed:
+ OS << "<Unprocessed operand>";
+ break;
+ case Location::Register:
+ OS << "Register ";
+ if (TRI)
+ OS << TRI->getName(Loc.Reg);
+ else
+ OS << Loc.Reg;
+ break;
+ case Location::Direct:
+ OS << "Direct ";
+ if (TRI)
+ OS << TRI->getName(Loc.Reg);
+ else
+ OS << Loc.Reg;
+ if (Loc.Offset)
+ OS << " + " << Loc.Offset;
+ break;
+ case Location::Indirect:
+ OS << "Indirect ";
+ if (TRI)
+ OS << TRI->getName(Loc.Reg);
+ else
+ OS << Loc.Reg;
+ OS << "+" << Loc.Offset;
+ break;
+ case Location::Constant:
+ OS << "Constant " << Loc.Offset;
+ break;
+ case Location::ConstantIndex:
+ OS << "Constant Index " << Loc.Offset;
+ break;
+ }
+ OS << "\t[encoding: .byte " << Loc.Type << ", .byte " << Loc.Size
+ << ", .short " << Loc.Reg << ", .int " << Loc.Offset << "]\n";
+ Idx++;
+ }
+
+ OS << WSMP << "\thas " << LiveOuts.size() << " live-out registers\n";
+
+ Idx = 0;
+ for (const auto &LO : LiveOuts) {
+ OS << WSMP << "\t\tLO " << Idx << ": ";
+ if (TRI)
+ OS << TRI->getName(LO.Reg);
+ else
+ OS << LO.Reg;
+ OS << "\t[encoding: .short " << LO.DwarfRegNum << ", .byte 0, .byte "
+ << LO.Size << "]\n";
+ Idx++;
+ }
+ }
}
/// Create a live-out register record for the given register Reg.
StackMaps::LiveOutReg
-StackMaps::createLiveOutReg(unsigned Reg, const MCRegisterInfo &MCRI,
- const TargetRegisterInfo *TRI) const {
- unsigned RegNo = getDwarfRegNum(Reg, MCRI, TRI);
+StackMaps::createLiveOutReg(unsigned Reg, const TargetRegisterInfo *TRI) const {
+ unsigned DwarfRegNum = getDwarfRegNum(Reg, TRI);
unsigned Size = TRI->getMinimalPhysRegClass(Reg)->getSize();
- return LiveOutReg(Reg, RegNo, Size);
+ return LiveOutReg(Reg, DwarfRegNum, Size);
}
/// Parse the register live-out mask and return a vector of live-out registers
StackMaps::LiveOutVec
StackMaps::parseRegisterLiveOutMask(const uint32_t *Mask) const {
assert(Mask && "No register mask specified");
- const TargetRegisterInfo *TRI = AP.TM.getRegisterInfo();
- MCContext &OutContext = AP.OutStreamer.getContext();
- const MCRegisterInfo &MCRI = *OutContext.getRegisterInfo();
+ const TargetRegisterInfo *TRI = AP.MF->getSubtarget().getRegisterInfo();
LiveOutVec LiveOuts;
// Create a LiveOutReg for each bit that is set in the register mask.
for (unsigned Reg = 0, NumRegs = TRI->getNumRegs(); Reg != NumRegs; ++Reg)
if ((Mask[Reg / 32] >> Reg % 32) & 1)
- LiveOuts.push_back(createLiveOutReg(Reg, MCRI, TRI));
+ LiveOuts.push_back(createLiveOutReg(Reg, TRI));
// We don't need to keep track of a register if its super-register is already
// in the list. Merge entries that refer to the same dwarf register and use
// the maximum size that needs to be spilled.
- std::sort(LiveOuts.begin(), LiveOuts.end());
- for (LiveOutVec::iterator I = LiveOuts.begin(), E = LiveOuts.end();
- I != E; ++I) {
- for (LiveOutVec::iterator II = next(I); II != E; ++II) {
- if (I->RegNo != II->RegNo) {
+
+ std::sort(LiveOuts.begin(), LiveOuts.end(),
+ [](const LiveOutReg &LHS, const LiveOutReg &RHS) {
+ // Only sort by the dwarf register number.
+ return LHS.DwarfRegNum < RHS.DwarfRegNum;
+ });
+
+ for (auto I = LiveOuts.begin(), E = LiveOuts.end(); I != E; ++I) {
+ for (auto II = std::next(I); II != E; ++II) {
+ if (I->DwarfRegNum != II->DwarfRegNum) {
// Skip all the now invalid entries.
I = --II;
break;
I->Size = std::max(I->Size, II->Size);
if (TRI->isSuperRegister(I->Reg, II->Reg))
I->Reg = II->Reg;
- II->MarkInvalid();
+ II->Reg = 0; // mark for deletion.
}
}
- LiveOuts.erase(std::remove_if(LiveOuts.begin(), LiveOuts.end(),
- LiveOutReg::IsInvalid), LiveOuts.end());
+
+ LiveOuts.erase(
+ std::remove_if(LiveOuts.begin(), LiveOuts.end(),
+ [](const LiveOutReg &LO) { return LO.Reg == 0; }),
+ LiveOuts.end());
+
return LiveOuts;
}
MachineInstr::const_mop_iterator MOE,
bool recordResult) {
- MCContext &OutContext = AP.OutStreamer.getContext();
- MCSymbol *MILabel = OutContext.CreateTempSymbol();
- AP.OutStreamer.EmitLabel(MILabel);
+ MCContext &OutContext = AP.OutStreamer->getContext();
+ MCSymbol *MILabel = OutContext.createTempSymbol();
+ AP.OutStreamer->EmitLabel(MILabel);
LocationVec Locations;
LiveOutVec LiveOuts;
if (recordResult) {
assert(PatchPointOpers(&MI).hasDef() && "Stackmap has no return value.");
- parseOperand(MI.operands_begin(), llvm::next(MI.operands_begin()),
- Locations, LiveOuts);
+ parseOperand(MI.operands_begin(), std::next(MI.operands_begin()), Locations,
+ LiveOuts);
}
// Parse operands.
}
// Move large constants into the constant pool.
- for (LocationVec::iterator I = Locations.begin(), E = Locations.end();
- I != E; ++I) {
+ for (auto &Loc : Locations) {
// Constants are encoded as sign-extended integers.
// -1 is directly encoded as .long 0xFFFFFFFF with no constant pool.
- if (I->LocType == Location::Constant &&
- ((I->Offset + (int64_t(1)<<31)) >> 32) != 0) {
- I->LocType = Location::ConstantIndex;
- I->Offset = ConstPool.getConstantIndex(I->Offset);
+ if (Loc.Type == Location::Constant && !isInt<32>(Loc.Offset)) {
+ Loc.Type = Location::ConstantIndex;
+ // ConstPool is intentionally a MapVector of 'uint64_t's (as
+ // opposed to 'int64_t's). We should never be in a situation
+ // where we have to insert either the tombstone or the empty
+ // keys into a map, and for a DenseMap<uint64_t, T> these are
+ // (uint64_t)0 and (uint64_t)-1. They can be and are
+ // represented using 32 bit integers.
+ assert((uint64_t)Loc.Offset != DenseMapInfo<uint64_t>::getEmptyKey() &&
+ (uint64_t)Loc.Offset !=
+ DenseMapInfo<uint64_t>::getTombstoneKey() &&
+ "empty and tombstone keys should fit in 32 bits!");
+ auto Result = ConstPool.insert(std::make_pair(Loc.Offset, Loc.Offset));
+ Loc.Offset = Result.first - ConstPool.begin();
}
}
- const MCExpr *CSOffsetExpr = MCBinaryExpr::CreateSub(
- MCSymbolRefExpr::Create(MILabel, OutContext),
- MCSymbolRefExpr::Create(AP.CurrentFnSym, OutContext),
- OutContext);
-
- CSInfos.push_back(CallsiteInfo(CSOffsetExpr, ID, Locations, LiveOuts));
+ // Create an expression to calculate the offset of the callsite from function
+ // entry.
+ const MCExpr *CSOffsetExpr = MCBinaryExpr::createSub(
+ MCSymbolRefExpr::create(MILabel, OutContext),
+ MCSymbolRefExpr::create(AP.CurrentFnSymForSize, OutContext), OutContext);
+
+ CSInfos.emplace_back(CSOffsetExpr, ID, std::move(Locations),
+ std::move(LiveOuts));
+
+ // Record the stack size of the current function.
+ const MachineFrameInfo *MFI = AP.MF->getFrameInfo();
+ const TargetRegisterInfo *RegInfo = AP.MF->getSubtarget().getRegisterInfo();
+ bool HasDynamicFrameSize =
+ MFI->hasVarSizedObjects() || RegInfo->needsStackRealignment(*(AP.MF));
+ FnStackSize[AP.CurrentFnSym] =
+ HasDynamicFrameSize ? UINT64_MAX : MFI->getStackSize();
}
void StackMaps::recordStackMap(const MachineInstr &MI) {
assert(MI.getOpcode() == TargetOpcode::STACKMAP && "expected stackmap");
int64_t ID = MI.getOperand(0).getImm();
- recordStackMapOpers(MI, ID, llvm::next(MI.operands_begin(), 2),
+ recordStackMapOpers(MI, ID, std::next(MI.operands_begin(), 2),
MI.operands_end());
}
PatchPointOpers opers(&MI);
int64_t ID = opers.getMetaOper(PatchPointOpers::IDPos).getImm();
- MachineInstr::const_mop_iterator MOI =
- llvm::next(MI.operands_begin(), opers.getStackMapStartIdx());
+ auto MOI = std::next(MI.operands_begin(), opers.getStackMapStartIdx());
recordStackMapOpers(MI, ID, MOI, MI.operands_end(),
opers.isAnyReg() && opers.hasDef());
#ifndef NDEBUG
// verify anyregcc
- LocationVec &Locations = CSInfos.back().Locations;
+ auto &Locations = CSInfos.back().Locations;
if (opers.isAnyReg()) {
unsigned NArgs = opers.getMetaOper(PatchPointOpers::NArgPos).getImm();
- for (unsigned i = 0, e = (opers.hasDef() ? NArgs+1 : NArgs); i != e; ++i)
- assert(Locations[i].LocType == Location::Register &&
+ for (unsigned i = 0, e = (opers.hasDef() ? NArgs + 1 : NArgs); i != e; ++i)
+ assert(Locations[i].Type == Location::Register &&
"anyreg arg must be in reg.");
}
#endif
}
+void StackMaps::recordStatepoint(const MachineInstr &MI) {
+ assert(MI.getOpcode() == TargetOpcode::STATEPOINT && "expected statepoint");
+
+ StatepointOpers opers(&MI);
+ // Record all the deopt and gc operands (they're contiguous and run from the
+ // initial index to the end of the operand list)
+ const unsigned StartIdx = opers.getVarIdx();
+ recordStackMapOpers(MI, opers.getID(), MI.operands_begin() + StartIdx,
+ MI.operands_end(), false);
+}
-/// serializeToStackMapSection conceptually populates the following fields:
+/// Emit the stackmap header.
///
-/// uint32 : Reserved (header)
+/// Header {
+/// uint8 : Stack Map Version (currently 1)
+/// uint8 : Reserved (expected to be 0)
+/// uint16 : Reserved (expected to be 0)
+/// }
+/// uint32 : NumFunctions
/// uint32 : NumConstants
-/// int64 : Constants[NumConstants]
/// uint32 : NumRecords
+void StackMaps::emitStackmapHeader(MCStreamer &OS) {
+ // Header.
+ OS.EmitIntValue(StackMapVersion, 1); // Version.
+ OS.EmitIntValue(0, 1); // Reserved.
+ OS.EmitIntValue(0, 2); // Reserved.
+
+ // Num functions.
+ DEBUG(dbgs() << WSMP << "#functions = " << FnStackSize.size() << '\n');
+ OS.EmitIntValue(FnStackSize.size(), 4);
+ // Num constants.
+ DEBUG(dbgs() << WSMP << "#constants = " << ConstPool.size() << '\n');
+ OS.EmitIntValue(ConstPool.size(), 4);
+ // Num callsites.
+ DEBUG(dbgs() << WSMP << "#callsites = " << CSInfos.size() << '\n');
+ OS.EmitIntValue(CSInfos.size(), 4);
+}
+
+/// Emit the function frame record for each function.
+///
+/// StkSizeRecord[NumFunctions] {
+/// uint64 : Function Address
+/// uint64 : Stack Size
+/// }
+void StackMaps::emitFunctionFrameRecords(MCStreamer &OS) {
+ // Function Frame records.
+ DEBUG(dbgs() << WSMP << "functions:\n");
+ for (auto const &FR : FnStackSize) {
+ DEBUG(dbgs() << WSMP << "function addr: " << FR.first
+ << " frame size: " << FR.second);
+ OS.EmitSymbolValue(FR.first, 8);
+ OS.EmitIntValue(FR.second, 8);
+ }
+}
+
+/// Emit the constant pool.
+///
+/// int64 : Constants[NumConstants]
+void StackMaps::emitConstantPoolEntries(MCStreamer &OS) {
+ // Constant pool entries.
+ DEBUG(dbgs() << WSMP << "constants:\n");
+ for (const auto &ConstEntry : ConstPool) {
+ DEBUG(dbgs() << WSMP << ConstEntry.second << '\n');
+ OS.EmitIntValue(ConstEntry.second, 8);
+ }
+}
+
+/// Emit the callsite info for each callsite.
+///
/// StkMapRecord[NumRecords] {
/// uint64 : PatchPoint ID
/// uint32 : Instruction Offset
/// uint16 : Dwarf RegNum
/// int32 : Offset
/// }
+/// uint16 : Padding
/// uint16 : NumLiveOuts
-/// LiveOuts[NumLiveOuts]
+/// LiveOuts[NumLiveOuts] {
/// uint16 : Dwarf RegNum
/// uint8 : Reserved
/// uint8 : Size in Bytes
+/// }
+/// uint32 : Padding (only if required to align to 8 byte)
/// }
///
/// Location Encoding, Type, Value:
/// 0x3, Indirect, [Reg + Offset] (spilled value)
/// 0x4, Constant, Offset (small constant)
/// 0x5, ConstIndex, Constants[Offset] (large constant)
-///
-void StackMaps::serializeToStackMapSection() {
- // Bail out if there's no stack map data.
- if (CSInfos.empty())
- return;
-
- MCContext &OutContext = AP.OutStreamer.getContext();
- const TargetRegisterInfo *TRI = AP.TM.getRegisterInfo();
-
- // Create the section.
- const MCSection *StackMapSection =
- OutContext.getObjectFileInfo()->getStackMapSection();
- AP.OutStreamer.SwitchSection(StackMapSection);
-
- // Emit a dummy symbol to force section inclusion.
- AP.OutStreamer.EmitLabel(
- OutContext.GetOrCreateSymbol(Twine("__LLVM_StackMaps")));
-
- // Serialize data.
- const char *WSMP = "Stack Maps: ";
- (void)WSMP;
- const MCRegisterInfo &MCRI = *OutContext.getRegisterInfo();
-
- DEBUG(dbgs() << "********** Stack Map Output **********\n");
-
- // Header.
- AP.OutStreamer.EmitIntValue(0, 4);
-
- // Num constants.
- AP.OutStreamer.EmitIntValue(ConstPool.getNumConstants(), 4);
-
- // Constant pool entries.
- for (unsigned i = 0; i < ConstPool.getNumConstants(); ++i)
- AP.OutStreamer.EmitIntValue(ConstPool.getConstant(i), 8);
-
- DEBUG(dbgs() << WSMP << "#callsites = " << CSInfos.size() << "\n");
- AP.OutStreamer.EmitIntValue(CSInfos.size(), 4);
-
- for (CallsiteInfoList::const_iterator CSII = CSInfos.begin(),
- CSIE = CSInfos.end();
- CSII != CSIE; ++CSII) {
-
- uint64_t CallsiteID = CSII->ID;
- const LocationVec &CSLocs = CSII->Locations;
- const LiveOutVec &LiveOuts = CSII->LiveOuts;
-
- DEBUG(dbgs() << WSMP << "callsite " << CallsiteID << "\n");
+void StackMaps::emitCallsiteEntries(MCStreamer &OS) {
+ DEBUG(print(dbgs()));
+ // Callsite entries.
+ for (const auto &CSI : CSInfos) {
+ const LocationVec &CSLocs = CSI.Locations;
+ const LiveOutVec &LiveOuts = CSI.LiveOuts;
// Verify stack map entry. It's better to communicate a problem to the
// runtime than crash in case of in-process compilation. Currently, we do
// simple overflow checks, but we may eventually communicate other
// compilation errors this way.
if (CSLocs.size() > UINT16_MAX || LiveOuts.size() > UINT16_MAX) {
- AP.OutStreamer.EmitIntValue(UINT64_MAX, 8); // Invalid ID.
- AP.OutStreamer.EmitValue(CSII->CSOffsetExpr, 4);
- AP.OutStreamer.EmitIntValue(0, 2); // Reserved.
- AP.OutStreamer.EmitIntValue(0, 2); // 0 locations.
- AP.OutStreamer.EmitIntValue(0, 2); // 0 live-out registers.
+ OS.EmitIntValue(UINT64_MAX, 8); // Invalid ID.
+ OS.EmitValue(CSI.CSOffsetExpr, 4);
+ OS.EmitIntValue(0, 2); // Reserved.
+ OS.EmitIntValue(0, 2); // 0 locations.
+ OS.EmitIntValue(0, 2); // padding.
+ OS.EmitIntValue(0, 2); // 0 live-out registers.
+ OS.EmitIntValue(0, 4); // padding.
continue;
}
- AP.OutStreamer.EmitIntValue(CallsiteID, 8);
- AP.OutStreamer.EmitValue(CSII->CSOffsetExpr, 4);
+ OS.EmitIntValue(CSI.ID, 8);
+ OS.EmitValue(CSI.CSOffsetExpr, 4);
// Reserved for flags.
- AP.OutStreamer.EmitIntValue(0, 2);
-
- DEBUG(dbgs() << WSMP << " has " << CSLocs.size() << " locations\n");
-
- AP.OutStreamer.EmitIntValue(CSLocs.size(), 2);
-
- unsigned operIdx = 0;
- for (LocationVec::const_iterator LocI = CSLocs.begin(), LocE = CSLocs.end();
- LocI != LocE; ++LocI, ++operIdx) {
- const Location &Loc = *LocI;
- unsigned RegNo = 0;
- int Offset = Loc.Offset;
- if(Loc.Reg) {
- RegNo = MCRI.getDwarfRegNum(Loc.Reg, false);
- for (MCSuperRegIterator SR(Loc.Reg, TRI);
- SR.isValid() && (int)RegNo < 0; ++SR) {
- RegNo = TRI->getDwarfRegNum(*SR, false);
- }
- // If this is a register location, put the subregister byte offset in
- // the location offset.
- if (Loc.LocType == Location::Register) {
- assert(!Loc.Offset && "Register location should have zero offset");
- unsigned LLVMRegNo = MCRI.getLLVMRegNum(RegNo, false);
- unsigned SubRegIdx = MCRI.getSubRegIndex(LLVMRegNo, Loc.Reg);
- if (SubRegIdx)
- Offset = MCRI.getSubRegIdxOffset(SubRegIdx);
- }
- }
- else {
- assert(Loc.LocType != Location::Register &&
- "Missing location register");
- }
+ OS.EmitIntValue(0, 2);
+ OS.EmitIntValue(CSLocs.size(), 2);
+
+ for (const auto &Loc : CSLocs) {
+ OS.EmitIntValue(Loc.Type, 1);
+ OS.EmitIntValue(Loc.Size, 1);
+ OS.EmitIntValue(Loc.Reg, 2);
+ OS.EmitIntValue(Loc.Offset, 4);
+ }
- DEBUG(
- dbgs() << WSMP << " Loc " << operIdx << ": ";
- switch (Loc.LocType) {
- case Location::Unprocessed:
- dbgs() << "<Unprocessed operand>";
- break;
- case Location::Register:
- dbgs() << "Register " << MCRI.getName(Loc.Reg);
- break;
- case Location::Direct:
- dbgs() << "Direct " << MCRI.getName(Loc.Reg);
- if (Loc.Offset)
- dbgs() << " + " << Loc.Offset;
- break;
- case Location::Indirect:
- dbgs() << "Indirect " << MCRI.getName(Loc.Reg)
- << " + " << Loc.Offset;
- break;
- case Location::Constant:
- dbgs() << "Constant " << Loc.Offset;
- break;
- case Location::ConstantIndex:
- dbgs() << "Constant Index " << Loc.Offset;
- break;
- }
- dbgs() << " [encoding: .byte " << Loc.LocType
- << ", .byte " << Loc.Size
- << ", .short " << RegNo
- << ", .int " << Offset << "]\n";
- );
-
- AP.OutStreamer.EmitIntValue(Loc.LocType, 1);
- AP.OutStreamer.EmitIntValue(Loc.Size, 1);
- AP.OutStreamer.EmitIntValue(RegNo, 2);
- AP.OutStreamer.EmitIntValue(Offset, 4);
+ // Num live-out registers and padding to align to 4 byte.
+ OS.EmitIntValue(0, 2);
+ OS.EmitIntValue(LiveOuts.size(), 2);
+
+ for (const auto &LO : LiveOuts) {
+ OS.EmitIntValue(LO.DwarfRegNum, 2);
+ OS.EmitIntValue(0, 1);
+ OS.EmitIntValue(LO.Size, 1);
}
+ // Emit alignment to 8 byte.
+ OS.EmitValueToAlignment(8);
+ }
+}
- DEBUG(dbgs() << WSMP << " has " << LiveOuts.size()
- << " live-out registers\n");
+/// Serialize the stackmap data.
+void StackMaps::serializeToStackMapSection() {
+ (void)WSMP;
+ // Bail out if there's no stack map data.
+ assert((!CSInfos.empty() || (CSInfos.empty() && ConstPool.empty())) &&
+ "Expected empty constant pool too!");
+ assert((!CSInfos.empty() || (CSInfos.empty() && FnStackSize.empty())) &&
+ "Expected empty function record too!");
+ if (CSInfos.empty())
+ return;
- AP.OutStreamer.EmitIntValue(LiveOuts.size(), 2);
+ MCContext &OutContext = AP.OutStreamer->getContext();
+ MCStreamer &OS = *AP.OutStreamer;
- operIdx = 0;
- for (LiveOutVec::const_iterator LI = LiveOuts.begin(), LE = LiveOuts.end();
- LI != LE; ++LI, ++operIdx) {
- DEBUG(dbgs() << WSMP << " LO " << operIdx << ": "
- << MCRI.getName(LI->Reg)
- << " [encoding: .short " << LI->RegNo
- << ", .byte 0, .byte " << LI->Size << "]\n");
+ // Create the section.
+ MCSection *StackMapSection =
+ OutContext.getObjectFileInfo()->getStackMapSection();
+ OS.SwitchSection(StackMapSection);
- AP.OutStreamer.EmitIntValue(LI->RegNo, 2);
- AP.OutStreamer.EmitIntValue(0, 1);
- AP.OutStreamer.EmitIntValue(LI->Size, 1);
- }
- }
+ // Emit a dummy symbol to force section inclusion.
+ OS.EmitLabel(OutContext.getOrCreateSymbol(Twine("__LLVM_StackMaps")));
- AP.OutStreamer.AddBlankLine();
+ // Serialize data.
+ DEBUG(dbgs() << "********** Stack Map Output **********\n");
+ emitStackmapHeader(OS);
+ emitFunctionFrameRecords(OS);
+ emitConstantPoolEntries(OS);
+ emitCallsiteEntries(OS);
+ OS.AddBlankLine();
+ // Clean up.
CSInfos.clear();
+ ConstPool.clear();
}