summaryrefslogtreecommitdiff
path: root/lib/CodeGen/StackMaps.cpp
diff options
context:
space:
mode:
authorAndrew Trick <atrick@apple.com>2013-12-13 18:37:03 +0000
committerAndrew Trick <atrick@apple.com>2013-12-13 18:37:03 +0000
commit539e93120cdbb66f651fc55a810416f3175adc8f (patch)
treee845453b166d6f8b462ef306f7e9b0d7cede2bbf /lib/CodeGen/StackMaps.cpp
parentedf1070ca74f7d646bce2c66db9f443d09e7d1d3 (diff)
downloadllvm-539e93120cdbb66f651fc55a810416f3175adc8f.tar.gz
llvm-539e93120cdbb66f651fc55a810416f3175adc8f.tar.bz2
llvm-539e93120cdbb66f651fc55a810416f3175adc8f.tar.xz
Liveness Analysis Pass
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@197254 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/CodeGen/StackMaps.cpp')
-rw-r--r--lib/CodeGen/StackMaps.cpp117
1 files changed, 105 insertions, 12 deletions
diff --git a/lib/CodeGen/StackMaps.cpp b/lib/CodeGen/StackMaps.cpp
index bec3021423..892e4573b0 100644
--- a/lib/CodeGen/StackMaps.cpp
+++ b/lib/CodeGen/StackMaps.cpp
@@ -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,66 @@ 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 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();
+ unsigned LLVMRegNo = MCRI.getLLVMRegNum(RegNo, false);
+ unsigned SubRegIdx = MCRI.getSubRegIndex(LLVMRegNo, Reg);
+ unsigned Offset = 0;
+ if (SubRegIdx)
+ Offset = MCRI.getSubRegIdxOffset(SubRegIdx) / 8;
+
+ return LiveOutReg(Reg, RegNo, Offset + 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;
+
+ for (unsigned Reg = 0, NumRegs = TRI->getNumRegs(); Reg != NumRegs; ++Reg)
+ if ((Mask[Reg / 32] >> Reg % 32) & 1)
+ LiveOuts.push_back(createLiveOutReg(Reg, MCRI, TRI));
+
+ std::sort(LiveOuts.begin(), LiveOuts.end());
+ for (LiveOutVec::iterator I = LiveOuts.begin(), E = LiveOuts.end();
+ I != E; ++I) {
+ if (!I->Reg)
+ continue;
+ for (LiveOutVec::iterator II = next(I); II != E; ++II) {
+ if (I->RegNo != II->RegNo)
+ break;
+ I->Size = std::max(I->Size, II->Size);
+ if (TRI->isSuperRegister(I->Reg, II->Reg))
+ I->Reg = II->Reg;
+ II->Reg = 0;
+ }
+ }
+ LiveOuts.erase(std::remove_if(LiveOuts.begin(), LiveOuts.end(),
+ LiveOutReg::isInvalid), LiveOuts.end());
+ return LiveOuts;
+}
+
void StackMaps::recordStackMapOpers(const MachineInstr &MI, uint32_t ID,
MachineInstr::const_mop_iterator MOI,
MachineInstr::const_mop_iterator MOE,
@@ -129,7 +192,8 @@ void StackMaps::recordStackMapOpers(const MachineInstr &MI, uint32_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 +202,7 @@ void StackMaps::recordStackMapOpers(const MachineInstr &MI, uint32_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 +215,9 @@ void StackMaps::recordStackMapOpers(const MachineInstr &MI, uint32_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 +225,23 @@ void StackMaps::recordStackMapOpers(const MachineInstr &MI, uint32_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();
assert((int32_t)ID == ID && "Stack maps hold 32-bit IDs");
@@ -183,7 +251,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();
@@ -222,6 +290,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:
@@ -274,6 +347,7 @@ void StackMaps::serializeToStackMapSection() {
unsigned CallsiteID = CSII->ID;
const LocationVec &CSLocs = CSII->Locations;
+ const LiveOutVec &LiveOuts = CSII->LiveOuts;
DEBUG(dbgs() << WSMP << "callsite " << CallsiteID << "\n");
@@ -281,11 +355,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) {
+ if (CSLocs.size() > UINT16_MAX || LiveOuts.size() > UINT16_MAX) {
AP.OutStreamer.EmitIntValue(UINT32_MAX, 4); // 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;
}
@@ -362,6 +437,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();