Skip to content

Commit

Permalink
[Stackmaps] Refactor serialization code. No functional change intended.
Browse files Browse the repository at this point in the history
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@207804 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
ributzka committed May 1, 2014
1 parent 23fc172 commit a677552
Show file tree
Hide file tree
Showing 2 changed files with 159 additions and 125 deletions.
15 changes: 15 additions & 0 deletions include/llvm/CodeGen/StackMaps.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ namespace llvm {

class AsmPrinter;
class MCExpr;
class MCStreamer;

/// \brief MI-level patchpoint operands.
///
Expand Down Expand Up @@ -131,6 +132,8 @@ class StackMaps {
void serializeToStackMapSection();

private:
const char *WSMP = "Stack Maps: ";

typedef SmallVector<Location, 8> LocationVec;
typedef SmallVector<LiveOutReg, 8> LiveOutVec;
typedef MapVector<int64_t, int64_t> ConstantPool;
Expand Down Expand Up @@ -177,6 +180,18 @@ class StackMaps {
MachineInstr::const_mop_iterator MOI,
MachineInstr::const_mop_iterator MOE,
bool recordResult = false);

/// \brief Emit the stackmap header.
void emitStackmapHeader(MCStreamer &OS);

/// \brief Emit the function frame record for each function.
void emitFunctionFrameRecords(MCStreamer &OS);

/// \brief Emit the constant pool.
void emitConstantPoolEntries(MCStreamer &OS);

/// \brief Emit the callsite info for each stackmap/patchpoint intrinsic call.
void emitCallsiteEntries(MCStreamer &OS, const TargetRegisterInfo *TRI);
};

}
Expand Down
269 changes: 144 additions & 125 deletions lib/CodeGen/StackMaps.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,7 @@ void StackMaps::recordPatchPoint(const MachineInstr &MI) {
#endif
}

/// serializeToStackMapSection conceptually populates the following fields:
/// Emit the stackmap header.
///
/// Header {
/// uint8 : Stack Map Version (currently 1)
Expand All @@ -270,11 +270,54 @@ void StackMaps::recordPatchPoint(const MachineInstr &MI) {
/// uint32 : NumFunctions
/// uint32 : NumConstants
/// uint32 : NumRecords
void StackMaps::emitStackmapHeader(MCStreamer &OS) {
// Header.
OS.EmitIntValue(1, 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 (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
Expand Down Expand Up @@ -302,95 +345,43 @@ void StackMaps::recordPatchPoint(const MachineInstr &MI) {
/// 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;

DEBUG(dbgs() << "********** Stack Map Output **********\n");

// Header.
AP.OutStreamer.EmitIntValue(1, 1); // Version.
AP.OutStreamer.EmitIntValue(0, 1); // Reserved.
AP.OutStreamer.EmitIntValue(0, 2); // Reserved.

// Num functions.
DEBUG(dbgs() << WSMP << "#functions = " << FnStackSize.size() << '\n');
AP.OutStreamer.EmitIntValue(FnStackSize.size(), 4);
// Num constants.
DEBUG(dbgs() << WSMP << "#constants = " << ConstPool.size()
<< '\n');
AP.OutStreamer.EmitIntValue(ConstPool.size(), 4);
// Num callsites.
DEBUG(dbgs() << WSMP << "#callsites = " << CSInfos.size() << '\n');
AP.OutStreamer.EmitIntValue(CSInfos.size(), 4);

// Function stack size entries.
for (FnStackSizeMap::iterator I = FnStackSize.begin(), E = FnStackSize.end();
I != E; ++I) {
AP.OutStreamer.EmitSymbolValue(I->first, 8);
AP.OutStreamer.EmitIntValue(I->second, 8);
}

// Constant pool entries.
for (auto Constant : ConstPool)
AP.OutStreamer.EmitIntValue(Constant.second, 8);

void StackMaps::emitCallsiteEntries(MCStreamer &OS,
const TargetRegisterInfo *TRI) {
// Callsite entries.
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 << "callsites:\n");
for (const auto &CSI : CSInfos) {
const LocationVec &CSLocs = CSI.Locations;
const LiveOutVec &LiveOuts = CSI.LiveOuts;

DEBUG(dbgs() << WSMP << "callsite " << CallsiteID << "\n");
DEBUG(dbgs() << WSMP << "callsite " << CSI.ID << "\n");

// 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); // padding.
AP.OutStreamer.EmitIntValue(0, 2); // 0 live-out registers.
AP.OutStreamer.EmitIntValue(0, 4); // padding.
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);
OS.EmitIntValue(0, 2);

DEBUG(dbgs() << WSMP << " has " << CSLocs.size() << " locations\n");

AP.OutStreamer.EmitIntValue(CSLocs.size(), 2);
OS.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 OperIdx = 0;
for (const auto &Loc : CSLocs) {
unsigned RegNo = 0;
int Offset = Loc.Offset;
if(Loc.Reg) {
Expand All @@ -411,68 +402,96 @@ void StackMaps::serializeToStackMapSection() {
"Missing location register");
}

DEBUG(
dbgs() << WSMP << " Loc " << operIdx << ": ";
switch (Loc.LocType) {
case Location::Unprocessed:
dbgs() << "<Unprocessed operand>";
break;
case Location::Register:
dbgs() << "Register " << TRI->getName(Loc.Reg);
break;
case Location::Direct:
dbgs() << "Direct " << TRI->getName(Loc.Reg);
if (Loc.Offset)
dbgs() << " + " << Loc.Offset;
break;
case Location::Indirect:
dbgs() << "Indirect " << TRI->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);
DEBUG(dbgs() << WSMP << " Loc " << OperIdx << ": ";
switch (Loc.LocType) {
case Location::Unprocessed:
dbgs() << "<Unprocessed operand>";
break;
case Location::Register:
dbgs() << "Register " << TRI->getName(Loc.Reg);
break;
case Location::Direct:
dbgs() << "Direct " << TRI->getName(Loc.Reg);
if (Loc.Offset)
dbgs() << " + " << Loc.Offset;
break;
case Location::Indirect:
dbgs() << "Indirect " << TRI->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";
);

OS.EmitIntValue(Loc.LocType, 1);
OS.EmitIntValue(Loc.Size, 1);
OS.EmitIntValue(RegNo, 2);
OS.EmitIntValue(Offset, 4);
OperIdx++;
}

DEBUG(dbgs() << WSMP << " has " << LiveOuts.size()
<< " live-out registers\n");
<< " live-out registers\n");

// Num live-out registers and padding to align to 4 byte.
AP.OutStreamer.EmitIntValue(0, 2);
AP.OutStreamer.EmitIntValue(LiveOuts.size(), 2);

operIdx = 0;
for (LiveOutVec::const_iterator LI = LiveOuts.begin(), LE = LiveOuts.end();
LI != LE; ++LI, ++operIdx) {
DEBUG(dbgs() << WSMP << " LO " << operIdx << ": "
<< TRI->getName(LI->Reg)
<< " [encoding: .short " << LI->RegNo
<< ", .byte 0, .byte " << LI->Size << "]\n");

AP.OutStreamer.EmitIntValue(LI->RegNo, 2);
AP.OutStreamer.EmitIntValue(0, 1);
AP.OutStreamer.EmitIntValue(LI->Size, 1);
OS.EmitIntValue(0, 2);
OS.EmitIntValue(LiveOuts.size(), 2);

OperIdx = 0;
for (const auto &LO : LiveOuts) {
DEBUG(dbgs() << WSMP << " LO " << OperIdx << ": "
<< TRI->getName(LO.Reg)
<< " [encoding: .short " << LO.RegNo
<< ", .byte 0, .byte " << LO.Size << "]\n");
OS.EmitIntValue(LO.RegNo, 2);
OS.EmitIntValue(0, 1);
OS.EmitIntValue(LO.Size, 1);
}
// Emit alignment to 8 byte.
AP.OutStreamer.EmitValueToAlignment(8);
OS.EmitValueToAlignment(8);
}
}

/// Serialize the stackmap data.
void StackMaps::serializeToStackMapSection() {
// 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;

MCContext &OutContext = AP.OutStreamer.getContext();
MCStreamer &OS = AP.OutStreamer;
const TargetRegisterInfo *TRI = AP.TM.getRegisterInfo();

AP.OutStreamer.AddBlankLine();
// Create the section.
const MCSection *StackMapSection =
OutContext.getObjectFileInfo()->getStackMapSection();
OS.SwitchSection(StackMapSection);

// Emit a dummy symbol to force section inclusion.
OS.EmitLabel(OutContext.GetOrCreateSymbol(Twine("__LLVM_StackMaps")));

// Serialize data.
DEBUG(dbgs() << "********** Stack Map Output **********\n");
emitStackmapHeader(OS);
emitFunctionFrameRecords(OS);
emitConstantPoolEntries(OS);
emitCallsiteEntries(OS, TRI);
OS.AddBlankLine();

// Clean up.
CSInfos.clear();
ConstPool.clear();
}

0 comments on commit a677552

Please sign in to comment.