|
@@ -68,10 +68,10 @@ unsigned PatchPointOpers::getNextScratchIdx(unsigned StartIdx) const {
|
|
|
|
|
|
std::pair<StackMaps::Location, MachineInstr::const_mop_iterator>
|
|
|
StackMaps::parseOperand(MachineInstr::const_mop_iterator MOI,
|
|
|
- MachineInstr::const_mop_iterator MOE) {
|
|
|
+ MachineInstr::const_mop_iterator MOE) const {
|
|
|
const MachineOperand &MOP = *MOI;
|
|
|
- assert(!MOP.isRegMask() && (!MOP.isReg() || !MOP.isImplicit()) &&
|
|
|
- "Register mask and implicit operands should not be processed.");
|
|
|
+ assert((!MOP.isReg() || !MOP.isImplicit()) &&
|
|
|
+ "Implicit operands should not be processed.");
|
|
|
|
|
|
if (MOP.isImm()) {
|
|
|
// Verify anyregcc
|
|
@@ -106,6 +106,9 @@ StackMaps::parseOperand(MachineInstr::const_mop_iterator MOI,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ if (MOP.isRegMask() || MOP.isRegLiveOut())
|
|
|
+ return std::make_pair(Location(), ++MOI);
|
|
|
+
|
|
|
// Otherwise this is a reg operand. The physical register number will
|
|
|
// ultimately be encoded as a DWARF regno. The stack map also records the size
|
|
|
// of a spill slot that can hold the register content. (The runtime can
|
|
@@ -120,6 +123,65 @@ StackMaps::parseOperand(MachineInstr::const_mop_iterator MOI,
|
|
|
Location(Location::Register, RC->getSize(), MOP.getReg(), 0), ++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;
|
|
|
+}
|
|
|
+
|
|
|
+/// 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);
|
|
|
+ unsigned Size = TRI->getMinimalPhysRegClass(Reg)->getSize();
|
|
|
+ return LiveOutReg(Reg, RegNo, Size);
|
|
|
+}
|
|
|
+
|
|
|
+/// Parse the register live-out mask and return a vector of live-out registers
|
|
|
+/// that need to be recorded in the stackmap.
|
|
|
+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();
|
|
|
+ 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));
|
|
|
+
|
|
|
+ // 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) {
|
|
|
+ // 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();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ LiveOuts.erase(std::remove_if(LiveOuts.begin(), LiveOuts.end(),
|
|
|
+ LiveOutReg::IsInvalid), LiveOuts.end());
|
|
|
+ return LiveOuts;
|
|
|
+}
|
|
|
+
|
|
|
void StackMaps::recordStackMapOpers(const MachineInstr &MI, uint64_t ID,
|
|
|
MachineInstr::const_mop_iterator MOI,
|
|
|
MachineInstr::const_mop_iterator MOE,
|
|
@@ -129,7 +191,8 @@ void StackMaps::recordStackMapOpers(const MachineInstr &MI, uint64_t ID,
|
|
|
MCSymbol *MILabel = OutContext.CreateTempSymbol();
|
|
|
AP.OutStreamer.EmitLabel(MILabel);
|
|
|
|
|
|
- LocationVec CallsiteLocs;
|
|
|
+ LocationVec Locations;
|
|
|
+ LiveOutVec LiveOuts;
|
|
|
|
|
|
if (recordResult) {
|
|
|
std::pair<Location, MachineInstr::const_mop_iterator> ParseResult =
|
|
@@ -138,7 +201,7 @@ void StackMaps::recordStackMapOpers(const MachineInstr &MI, uint64_t ID,
|
|
|
Location &Loc = ParseResult.first;
|
|
|
assert(Loc.LocType == Location::Register &&
|
|
|
"Stackmap return location must be a register.");
|
|
|
- CallsiteLocs.push_back(Loc);
|
|
|
+ Locations.push_back(Loc);
|
|
|
}
|
|
|
|
|
|
while (MOI != MOE) {
|
|
@@ -151,7 +214,9 @@ void StackMaps::recordStackMapOpers(const MachineInstr &MI, uint64_t ID,
|
|
|
Loc.Offset = ConstPool.getConstantIndex(Loc.Offset);
|
|
|
}
|
|
|
|
|
|
- CallsiteLocs.push_back(Loc);
|
|
|
+ // Skip the register mask and register live-out mask
|
|
|
+ if (Loc.LocType != Location::Unprocessed)
|
|
|
+ Locations.push_back(Loc);
|
|
|
}
|
|
|
|
|
|
const MCExpr *CSOffsetExpr = MCBinaryExpr::CreateSub(
|
|
@@ -159,21 +224,23 @@ void StackMaps::recordStackMapOpers(const MachineInstr &MI, uint64_t ID,
|
|
|
MCSymbolRefExpr::Create(AP.CurrentFnSym, OutContext),
|
|
|
OutContext);
|
|
|
|
|
|
- CSInfos.push_back(CallsiteInfo(CSOffsetExpr, ID, CallsiteLocs));
|
|
|
+ if (MOI->isRegLiveOut())
|
|
|
+ LiveOuts = parseRegisterLiveOutMask(MOI->getRegLiveOut());
|
|
|
+
|
|
|
+ CSInfos.push_back(CallsiteInfo(CSOffsetExpr, ID, Locations, LiveOuts));
|
|
|
}
|
|
|
|
|
|
static MachineInstr::const_mop_iterator
|
|
|
getStackMapEndMOP(MachineInstr::const_mop_iterator MOI,
|
|
|
MachineInstr::const_mop_iterator MOE) {
|
|
|
for (; MOI != MOE; ++MOI)
|
|
|
- if (MOI->isRegMask() || (MOI->isReg() && MOI->isImplicit()))
|
|
|
+ if (MOI->isRegLiveOut() || (MOI->isReg() && MOI->isImplicit()))
|
|
|
break;
|
|
|
-
|
|
|
return MOI;
|
|
|
}
|
|
|
|
|
|
void StackMaps::recordStackMap(const MachineInstr &MI) {
|
|
|
- assert(MI.getOpcode() == TargetOpcode::STACKMAP && "exected stackmap");
|
|
|
+ assert(MI.getOpcode() == TargetOpcode::STACKMAP && "expected stackmap");
|
|
|
|
|
|
int64_t ID = MI.getOperand(0).getImm();
|
|
|
recordStackMapOpers(MI, ID, llvm::next(MI.operands_begin(), 2),
|
|
@@ -182,7 +249,7 @@ void StackMaps::recordStackMap(const MachineInstr &MI) {
|
|
|
}
|
|
|
|
|
|
void StackMaps::recordPatchPoint(const MachineInstr &MI) {
|
|
|
- assert(MI.getOpcode() == TargetOpcode::PATCHPOINT && "exected stackmap");
|
|
|
+ assert(MI.getOpcode() == TargetOpcode::PATCHPOINT && "expected patchpoint");
|
|
|
|
|
|
PatchPointOpers opers(&MI);
|
|
|
int64_t ID = opers.getMetaOper(PatchPointOpers::IDPos).getImm();
|
|
@@ -221,6 +288,11 @@ void StackMaps::recordPatchPoint(const MachineInstr &MI) {
|
|
|
/// uint16 : Dwarf RegNum
|
|
|
/// int32 : Offset
|
|
|
/// }
|
|
|
+/// uint16 : NumLiveOuts
|
|
|
+/// LiveOuts[NumLiveOuts]
|
|
|
+/// uint16 : Dwarf RegNum
|
|
|
+/// uint8 : Reserved
|
|
|
+/// uint8 : Size in Bytes
|
|
|
/// }
|
|
|
///
|
|
|
/// Location Encoding, Type, Value:
|
|
@@ -273,6 +345,7 @@ void StackMaps::serializeToStackMapSection() {
|
|
|
|
|
|
uint64_t CallsiteID = CSII->ID;
|
|
|
const LocationVec &CSLocs = CSII->Locations;
|
|
|
+ const LiveOutVec &LiveOuts = CSII->LiveOuts;
|
|
|
|
|
|
DEBUG(dbgs() << WSMP << "callsite " << CallsiteID << "\n");
|
|
|
|
|
@@ -280,11 +353,12 @@ void StackMaps::serializeToStackMapSection() {
|
|
|
// 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) {
|
|
|
- AP.OutStreamer.EmitIntValue(UINT32_MAX, 8); // Invalid ID.
|
|
|
+ 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.
|
|
|
continue;
|
|
|
}
|
|
|
|
|
@@ -361,6 +435,24 @@ void StackMaps::serializeToStackMapSection() {
|
|
|
AP.OutStreamer.EmitIntValue(RegNo, 2);
|
|
|
AP.OutStreamer.EmitIntValue(Offset, 4);
|
|
|
}
|
|
|
+
|
|
|
+ DEBUG(dbgs() << WSMP << " has " << LiveOuts.size()
|
|
|
+ << " live-out registers\n");
|
|
|
+
|
|
|
+ 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 << ": "
|
|
|
+ << MCRI.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);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
AP.OutStreamer.AddBlankLine();
|