From 539e93120cdbb66f651fc55a810416f3175adc8f Mon Sep 17 00:00:00 2001 From: Andrew Trick Date: Fri, 13 Dec 2013 18:37:03 +0000 Subject: Liveness Analysis Pass git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@197254 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/StackMaps.cpp | 117 +++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 105 insertions(+), 12 deletions(-) (limited to 'lib/CodeGen/StackMaps.cpp') 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::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 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(); -- cgit v1.2.3