mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-10-19 19:12:56 +02:00
[Stackmaps] Refactor serialization code. No functional change intended.
llvm-svn: 207804
This commit is contained in:
parent
08694158e1
commit
60208fb4c5
@ -21,6 +21,7 @@ namespace llvm {
|
|||||||
|
|
||||||
class AsmPrinter;
|
class AsmPrinter;
|
||||||
class MCExpr;
|
class MCExpr;
|
||||||
|
class MCStreamer;
|
||||||
|
|
||||||
/// \brief MI-level patchpoint operands.
|
/// \brief MI-level patchpoint operands.
|
||||||
///
|
///
|
||||||
@ -131,6 +132,8 @@ public:
|
|||||||
void serializeToStackMapSection();
|
void serializeToStackMapSection();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
const char *WSMP = "Stack Maps: ";
|
||||||
|
|
||||||
typedef SmallVector<Location, 8> LocationVec;
|
typedef SmallVector<Location, 8> LocationVec;
|
||||||
typedef SmallVector<LiveOutReg, 8> LiveOutVec;
|
typedef SmallVector<LiveOutReg, 8> LiveOutVec;
|
||||||
typedef MapVector<int64_t, int64_t> ConstantPool;
|
typedef MapVector<int64_t, int64_t> ConstantPool;
|
||||||
@ -177,6 +180,18 @@ private:
|
|||||||
MachineInstr::const_mop_iterator MOI,
|
MachineInstr::const_mop_iterator MOI,
|
||||||
MachineInstr::const_mop_iterator MOE,
|
MachineInstr::const_mop_iterator MOE,
|
||||||
bool recordResult = false);
|
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);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -260,7 +260,7 @@ void StackMaps::recordPatchPoint(const MachineInstr &MI) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/// serializeToStackMapSection conceptually populates the following fields:
|
/// Emit the stackmap header.
|
||||||
///
|
///
|
||||||
/// Header {
|
/// Header {
|
||||||
/// uint8 : Stack Map Version (currently 1)
|
/// uint8 : Stack Map Version (currently 1)
|
||||||
@ -270,11 +270,54 @@ void StackMaps::recordPatchPoint(const MachineInstr &MI) {
|
|||||||
/// uint32 : NumFunctions
|
/// uint32 : NumFunctions
|
||||||
/// uint32 : NumConstants
|
/// uint32 : NumConstants
|
||||||
/// uint32 : NumRecords
|
/// 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] {
|
/// StkSizeRecord[NumFunctions] {
|
||||||
/// uint64 : Function Address
|
/// uint64 : Function Address
|
||||||
/// uint64 : Stack Size
|
/// 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]
|
/// 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] {
|
/// StkMapRecord[NumRecords] {
|
||||||
/// uint64 : PatchPoint ID
|
/// uint64 : PatchPoint ID
|
||||||
/// uint32 : Instruction Offset
|
/// uint32 : Instruction Offset
|
||||||
@ -302,95 +345,43 @@ void StackMaps::recordPatchPoint(const MachineInstr &MI) {
|
|||||||
/// 0x3, Indirect, [Reg + Offset] (spilled value)
|
/// 0x3, Indirect, [Reg + Offset] (spilled value)
|
||||||
/// 0x4, Constant, Offset (small constant)
|
/// 0x4, Constant, Offset (small constant)
|
||||||
/// 0x5, ConstIndex, Constants[Offset] (large constant)
|
/// 0x5, ConstIndex, Constants[Offset] (large constant)
|
||||||
///
|
void StackMaps::emitCallsiteEntries(MCStreamer &OS,
|
||||||
void StackMaps::serializeToStackMapSection() {
|
const TargetRegisterInfo *TRI) {
|
||||||
// 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);
|
|
||||||
|
|
||||||
// Callsite entries.
|
// Callsite entries.
|
||||||
for (CallsiteInfoList::const_iterator CSII = CSInfos.begin(),
|
DEBUG(dbgs() << WSMP << "callsites:\n");
|
||||||
CSIE = CSInfos.end(); CSII != CSIE; ++CSII) {
|
for (const auto &CSI : CSInfos) {
|
||||||
uint64_t CallsiteID = CSII->ID;
|
const LocationVec &CSLocs = CSI.Locations;
|
||||||
const LocationVec &CSLocs = CSII->Locations;
|
const LiveOutVec &LiveOuts = CSI.LiveOuts;
|
||||||
const LiveOutVec &LiveOuts = CSII->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
|
// 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
|
// runtime than crash in case of in-process compilation. Currently, we do
|
||||||
// simple overflow checks, but we may eventually communicate other
|
// simple overflow checks, but we may eventually communicate other
|
||||||
// compilation errors this way.
|
// compilation errors this way.
|
||||||
if (CSLocs.size() > UINT16_MAX || LiveOuts.size() > UINT16_MAX) {
|
if (CSLocs.size() > UINT16_MAX || LiveOuts.size() > UINT16_MAX) {
|
||||||
AP.OutStreamer.EmitIntValue(UINT64_MAX, 8); // Invalid ID.
|
OS.EmitIntValue(UINT64_MAX, 8); // Invalid ID.
|
||||||
AP.OutStreamer.EmitValue(CSII->CSOffsetExpr, 4);
|
OS.EmitValue(CSI.CSOffsetExpr, 4);
|
||||||
AP.OutStreamer.EmitIntValue(0, 2); // Reserved.
|
OS.EmitIntValue(0, 2); // Reserved.
|
||||||
AP.OutStreamer.EmitIntValue(0, 2); // 0 locations.
|
OS.EmitIntValue(0, 2); // 0 locations.
|
||||||
AP.OutStreamer.EmitIntValue(0, 2); // padding.
|
OS.EmitIntValue(0, 2); // padding.
|
||||||
AP.OutStreamer.EmitIntValue(0, 2); // 0 live-out registers.
|
OS.EmitIntValue(0, 2); // 0 live-out registers.
|
||||||
AP.OutStreamer.EmitIntValue(0, 4); // padding.
|
OS.EmitIntValue(0, 4); // padding.
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
AP.OutStreamer.EmitIntValue(CallsiteID, 8);
|
OS.EmitIntValue(CSI.ID, 8);
|
||||||
AP.OutStreamer.EmitValue(CSII->CSOffsetExpr, 4);
|
OS.EmitValue(CSI.CSOffsetExpr, 4);
|
||||||
|
|
||||||
// Reserved for flags.
|
// Reserved for flags.
|
||||||
AP.OutStreamer.EmitIntValue(0, 2);
|
OS.EmitIntValue(0, 2);
|
||||||
|
|
||||||
DEBUG(dbgs() << WSMP << " has " << CSLocs.size() << " locations\n");
|
DEBUG(dbgs() << WSMP << " has " << CSLocs.size() << " locations\n");
|
||||||
|
|
||||||
AP.OutStreamer.EmitIntValue(CSLocs.size(), 2);
|
OS.EmitIntValue(CSLocs.size(), 2);
|
||||||
|
|
||||||
unsigned operIdx = 0;
|
unsigned OperIdx = 0;
|
||||||
for (LocationVec::const_iterator LocI = CSLocs.begin(), LocE = CSLocs.end();
|
for (const auto &Loc : CSLocs) {
|
||||||
LocI != LocE; ++LocI, ++operIdx) {
|
|
||||||
const Location &Loc = *LocI;
|
|
||||||
unsigned RegNo = 0;
|
unsigned RegNo = 0;
|
||||||
int Offset = Loc.Offset;
|
int Offset = Loc.Offset;
|
||||||
if(Loc.Reg) {
|
if(Loc.Reg) {
|
||||||
@ -411,68 +402,96 @@ void StackMaps::serializeToStackMapSection() {
|
|||||||
"Missing location register");
|
"Missing location register");
|
||||||
}
|
}
|
||||||
|
|
||||||
DEBUG(
|
DEBUG(dbgs() << WSMP << " Loc " << OperIdx << ": ";
|
||||||
dbgs() << WSMP << " Loc " << operIdx << ": ";
|
switch (Loc.LocType) {
|
||||||
switch (Loc.LocType) {
|
case Location::Unprocessed:
|
||||||
case Location::Unprocessed:
|
dbgs() << "<Unprocessed operand>";
|
||||||
dbgs() << "<Unprocessed operand>";
|
break;
|
||||||
break;
|
case Location::Register:
|
||||||
case Location::Register:
|
dbgs() << "Register " << TRI->getName(Loc.Reg);
|
||||||
dbgs() << "Register " << TRI->getName(Loc.Reg);
|
break;
|
||||||
break;
|
case Location::Direct:
|
||||||
case Location::Direct:
|
dbgs() << "Direct " << TRI->getName(Loc.Reg);
|
||||||
dbgs() << "Direct " << TRI->getName(Loc.Reg);
|
if (Loc.Offset)
|
||||||
if (Loc.Offset)
|
dbgs() << " + " << Loc.Offset;
|
||||||
dbgs() << " + " << Loc.Offset;
|
break;
|
||||||
break;
|
case Location::Indirect:
|
||||||
case Location::Indirect:
|
dbgs() << "Indirect " << TRI->getName(Loc.Reg)
|
||||||
dbgs() << "Indirect " << TRI->getName(Loc.Reg)
|
<< " + " << Loc.Offset;
|
||||||
<< " + " << Loc.Offset;
|
break;
|
||||||
break;
|
case Location::Constant:
|
||||||
case Location::Constant:
|
dbgs() << "Constant " << Loc.Offset;
|
||||||
dbgs() << "Constant " << Loc.Offset;
|
break;
|
||||||
break;
|
case Location::ConstantIndex:
|
||||||
case Location::ConstantIndex:
|
dbgs() << "Constant Index " << Loc.Offset;
|
||||||
dbgs() << "Constant Index " << Loc.Offset;
|
break;
|
||||||
break;
|
}
|
||||||
}
|
dbgs() << " [encoding: .byte " << Loc.LocType
|
||||||
dbgs() << " [encoding: .byte " << Loc.LocType
|
<< ", .byte " << Loc.Size
|
||||||
<< ", .byte " << Loc.Size
|
<< ", .short " << RegNo
|
||||||
<< ", .short " << RegNo
|
<< ", .int " << Offset << "]\n";
|
||||||
<< ", .int " << Offset << "]\n";
|
);
|
||||||
);
|
|
||||||
|
|
||||||
AP.OutStreamer.EmitIntValue(Loc.LocType, 1);
|
OS.EmitIntValue(Loc.LocType, 1);
|
||||||
AP.OutStreamer.EmitIntValue(Loc.Size, 1);
|
OS.EmitIntValue(Loc.Size, 1);
|
||||||
AP.OutStreamer.EmitIntValue(RegNo, 2);
|
OS.EmitIntValue(RegNo, 2);
|
||||||
AP.OutStreamer.EmitIntValue(Offset, 4);
|
OS.EmitIntValue(Offset, 4);
|
||||||
|
OperIdx++;
|
||||||
}
|
}
|
||||||
|
|
||||||
DEBUG(dbgs() << WSMP << " has " << LiveOuts.size()
|
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.
|
// Num live-out registers and padding to align to 4 byte.
|
||||||
AP.OutStreamer.EmitIntValue(0, 2);
|
OS.EmitIntValue(0, 2);
|
||||||
AP.OutStreamer.EmitIntValue(LiveOuts.size(), 2);
|
OS.EmitIntValue(LiveOuts.size(), 2);
|
||||||
|
|
||||||
operIdx = 0;
|
OperIdx = 0;
|
||||||
for (LiveOutVec::const_iterator LI = LiveOuts.begin(), LE = LiveOuts.end();
|
for (const auto &LO : LiveOuts) {
|
||||||
LI != LE; ++LI, ++operIdx) {
|
DEBUG(dbgs() << WSMP << " LO " << OperIdx << ": "
|
||||||
DEBUG(dbgs() << WSMP << " LO " << operIdx << ": "
|
<< TRI->getName(LO.Reg)
|
||||||
<< TRI->getName(LI->Reg)
|
<< " [encoding: .short " << LO.RegNo
|
||||||
<< " [encoding: .short " << LI->RegNo
|
<< ", .byte 0, .byte " << LO.Size << "]\n");
|
||||||
<< ", .byte 0, .byte " << LI->Size << "]\n");
|
OS.EmitIntValue(LO.RegNo, 2);
|
||||||
|
OS.EmitIntValue(0, 1);
|
||||||
AP.OutStreamer.EmitIntValue(LI->RegNo, 2);
|
OS.EmitIntValue(LO.Size, 1);
|
||||||
AP.OutStreamer.EmitIntValue(0, 1);
|
|
||||||
AP.OutStreamer.EmitIntValue(LI->Size, 1);
|
|
||||||
}
|
}
|
||||||
// Emit alignment to 8 byte.
|
// Emit alignment to 8 byte.
|
||||||
AP.OutStreamer.EmitValueToAlignment(8);
|
OS.EmitValueToAlignment(8);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
AP.OutStreamer.AddBlankLine();
|
/// 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();
|
||||||
|
|
||||||
|
// 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();
|
CSInfos.clear();
|
||||||
ConstPool.clear();
|
ConstPool.clear();
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user