Index: include/llvm/BinaryFormat/Dwarf.def =================================================================== --- include/llvm/BinaryFormat/Dwarf.def +++ include/llvm/BinaryFormat/Dwarf.def @@ -632,6 +632,9 @@ // Vendor extensions: // Extensions for GNU-style thread-local storage. HANDLE_DW_OP(0xe0, GNU_push_tls_address, 0, GNU) +// The GNU entry value extension. +// See http://www.dwarfstd.org/ShowIssue.php?issue=100909.1&type=open . +HANDLE_DW_OP(0xf3, GNU_entry_value, 0, GNU) // Extensions for Fission proposal. HANDLE_DW_OP(0xfb, GNU_addr_index, 0, GNU) HANDLE_DW_OP(0xfc, GNU_const_index, 0, GNU) Index: include/llvm/CodeGen/MachineBasicBlock.h =================================================================== --- include/llvm/CodeGen/MachineBasicBlock.h +++ include/llvm/CodeGen/MachineBasicBlock.h @@ -565,7 +565,12 @@ /// Convenience function that returns true if the block ends in a return /// instruction. bool isReturnBlock() const { - return !empty() && back().isReturn(); + if (!empty()) { + const_iterator LastMI = this->getLastNonDebugInstr(); + if((LastMI != this->end()) && (LastMI->isReturn())) + return true; + } + return false; } /// Convenience function that returns true if the bock ends in a EH scope Index: include/llvm/CodeGen/MachineInstrBuilder.h =================================================================== --- include/llvm/CodeGen/MachineInstrBuilder.h +++ include/llvm/CodeGen/MachineInstrBuilder.h @@ -459,6 +459,18 @@ /// modifying an instruction in place while iterating over a basic block. void updateDbgValueForSpill(MachineInstr &Orig, int FrameIndex); +/// Clone a DBG_CALLPARAM whose location is spilled to FrameIndex. +MachineInstr *buildDbgCallParamForSpill(MachineInstr &Orig, int FrameIndex); + +/// Clone a DBG_CALLPARAM whose location is global addres. +MachineInstr *buildDbgCallParamForGlobal(MachineInstr &Orig, + const GlobalValue *GV); + +/// Firstly check whether DBG_CALLSITEPARAM could be described with +/// DICallSiteParam metadata. If it can't be described by DICallSite metadata +/// delete it and return true. Otherwise set parameter location to 0. +bool invalidateParamLocation(MachineInstr *MI); + inline unsigned getDefRegState(bool B) { return B ? RegState::Define : 0; } Index: include/llvm/IR/DebugInfoMetadata.h =================================================================== --- include/llvm/IR/DebugInfoMetadata.h +++ include/llvm/IR/DebugInfoMetadata.h @@ -2668,19 +2668,21 @@ unsigned &AddrClass); /// Constants for DIExpression::prepend. - enum { NoDeref = false, WithDeref = true, WithStackValue = true }; + enum { NoDeref = false, WithDeref = true, WithStackValue = true, + WithEntryValue = true}; /// Prepend \p DIExpr with a deref and offset operation and optionally turn it /// into a stack value. static DIExpression *prepend(const DIExpression *Expr, bool DerefBefore, int64_t Offset = 0, bool DerefAfter = false, - bool StackValue = false); + bool StackValue = false, bool EntryValue = false); /// Prepend \p DIExpr with the given opcodes and optionally turn it into a /// stack value. static DIExpression *prependOpcodes(const DIExpression *Expr, SmallVectorImpl &Ops, - bool StackValue = false); + bool StackValue = false, + bool EntryValue = false); /// Append the opcodes \p Ops to \p DIExpr. Unlike \ref appendToStack, the /// returned expression is a stack value only if \p DIExpr is a stack value. @@ -2734,6 +2736,10 @@ return true; return fragmentCmp(Other) == 0; } + + bool isEntryValue() const { + return getNumElements() > 0 && getElement(0) == dwarf::DW_OP_GNU_entry_value; + } }; /// Global variables. Index: lib/CodeGen/CalcSpillWeights.cpp =================================================================== --- lib/CodeGen/CalcSpillWeights.cpp +++ lib/CodeGen/CalcSpillWeights.cpp @@ -206,6 +206,12 @@ I = mri.reg_instr_begin(li.reg), E = mri.reg_instr_end(); I != E; ) { MachineInstr *mi = &*(I++); + numInstr++; + + if (mi->isIdentityCopy() || mi->isImplicitDef() || mi->isDebugInstr()) + continue; + if (!visited.insert(mi).second) + continue; // For local split artifacts, we are interested only in instructions between // the expected start and end of the range. @@ -213,12 +219,6 @@ if (localSplitArtifact && ((si < *start) || (si > *end))) continue; - numInstr++; - if (mi->isIdentityCopy() || mi->isImplicitDef() || mi->isDebugInstr()) - continue; - if (!visited.insert(mi).second) - continue; - float weight = 1.0f; if (Spillable) { // Get loop info for mi. Index: lib/CodeGen/InlineSpiller.cpp =================================================================== --- lib/CodeGen/InlineSpiller.cpp +++ lib/CodeGen/InlineSpiller.cpp @@ -72,6 +72,7 @@ STATISTIC(NumFolded, "Number of folded stack accesses"); STATISTIC(NumFoldedLoads, "Number of folded loads"); STATISTIC(NumRemats, "Number of rematerialized defs for spilling"); +STATISTIC(NumDbgCallSites, "Number of dbg call sites deleted"); static cl::opt DisableHoisting("disable-spill-hoist", cl::Hidden, cl::desc("Disable inline spill hoisting")); @@ -619,6 +620,38 @@ if (MI.isDebugValue()) continue; + // If DebugCallSite parameter virtual register is present here + // that means that it should have been handled somewhere + // in register coalescing pass. For now we just set it as no-reg + // since we can't materialize it correctly here. + if (MI.isDebugCallSiteParam()) { + LLVM_DEBUG(dbgs() << "Invalidating virt reg from " << MI); + MI.getOperand(2).setReg(0U); + continue; + } + + if (MI.isDebugCallSite()) { + MachineOperand &MOCallReg = MI.getOperand(1); + if (MOCallReg.isReg() && MOCallReg.getReg() == Reg) { + // We lose a dbg info for a call site, so delete it. + ++NumDbgCallSites; + MI.eraseFromParent(); + continue; + } + + auto It = MI.getIterator(); + while (It->isBundledWithSucc()) { + It++; + MachineOperand &MO = It->getOperand(2); + if (MO.isReg() && MO.getReg() == Reg) { + LLVM_DEBUG(dbgs() << "Invalidating virt reg from " << MI); + invalidateParamLocation(&*It); + break; + } + } + continue; + } + assert(!MI.isDebugInstr() && "Did not expect to find a use in debug " "instruction that isn't a DBG_VALUE"); @@ -944,8 +977,37 @@ continue; } + if (MI->isDebugCallSite()) { + // If it ever comes to spilling of a reg that holds a call + // remove that call site. + // TODO: Try to salvage this, by making frame object for that. + MachineOperand &MOCallReg = MI->getOperand(1); + if (MOCallReg.isReg() && MOCallReg.getReg() == Reg) { + ++NumDbgCallSites; + MI->eraseFromParent(); + continue; + } + + auto It = MI->getIterator(); + SmallVector, 2> ReplaceInstrs; + while (It->isBundledWithSucc()) { + It++; + if (It->getOperand(2).isReg() && It->getOperand(2).getReg() == Reg) { + MachineInstr *SpilledCSP = buildDbgCallParamForSpill(*It, StackSlot); + ReplaceInstrs.emplace_back(&*It, SpilledCSP); + } + } + for (auto Replace : ReplaceInstrs) { + LLVM_DEBUG(dbgs() << "Modifying debug call param due to spill:\t" + << *Replace.first); + Replace.first->eraseFromBundle(); + MIBundleBuilder(MI).append(Replace.second); + } + continue; + } + assert(!MI->isDebugInstr() && "Did not expect to find a use in debug " - "instruction that isn't a DBG_VALUE"); + "instruction that isn't a DBG_VALUE"); // Ignore copies to/from snippets. We'll delete them. if (SnippetCopies.count(MI)) Index: lib/CodeGen/LexicalScopes.cpp =================================================================== --- lib/CodeGen/LexicalScopes.cpp +++ lib/CodeGen/LexicalScopes.cpp @@ -75,6 +75,12 @@ for (const auto &MInsn : MBB) { // Check if instruction has valid location information. const DILocation *MIDL = MInsn.getDebugLoc(); + + // Ignore DBG_VALUE and similar instruction that do not contribute to any + // instruction in the output. + if (MInsn.isMetaInstruction()) + continue; + if (!MIDL) { PrevMI = &MInsn; continue; @@ -86,11 +92,6 @@ continue; } - // Ignore DBG_VALUE and similar instruction that do not contribute to any - // instruction in the output. - if (MInsn.isMetaInstruction()) - continue; - if (RangeBeginMI) { // If we have already seen a beginning of an instruction range and // current instruction scope does not match scope of first instruction Index: lib/CodeGen/LiveDebugVariables.cpp =================================================================== --- lib/CodeGen/LiveDebugVariables.cpp +++ lib/CodeGen/LiveDebugVariables.cpp @@ -673,6 +673,14 @@ return true; } +static MachineInstr& getPrevNonDbgInstr(MachineBasicBlock::iterator It) { + do { + It = std::prev(It); + } while (It->isDebugCallSite() || It->isDebugCallSiteParam()); + + return *It; +} + bool LDVImpl::collectDebugValues(MachineFunction &mf) { bool Changed = false; for (MachineFunction::iterator MFI = mf.begin(), MFE = mf.end(); MFI != MFE; @@ -691,7 +699,7 @@ SlotIndex Idx = MBBI == MBB->begin() ? LIS->getMBBStartIdx(MBB) - : LIS->getInstructionIndex(*std::prev(MBBI)).getRegSlot(); + : LIS->getInstructionIndex(getPrevNonDbgInstr(MBBI)).getRegSlot(); // Handle consecutive debug instructions with the same slot index. do { // Only handle DBG_VALUE in handleDebugValue(). Skip all other Index: lib/CodeGen/LiveInterval.cpp =================================================================== --- lib/CodeGen/LiveInterval.cpp +++ lib/CodeGen/LiveInterval.cpp @@ -1310,6 +1310,11 @@ MachineInstr *MI = RI->getParent(); ++RI; const VNInfo *VNI; + + // Skip over call site debug instructions. + if (MI->isDebugCallSite() || MI->isDebugCallSiteParam()) + continue; + if (MI->isDebugValue()) { // DBG_VALUE instructions don't have slot indexes, so get the index of // the instruction before them. The value is defined there too. Index: lib/CodeGen/LiveIntervals.cpp =================================================================== --- lib/CodeGen/LiveIntervals.cpp +++ lib/CodeGen/LiveIntervals.cpp @@ -460,7 +460,7 @@ // Visit all instructions reading li->reg. unsigned Reg = li->reg; for (MachineInstr &UseMI : MRI->reg_instructions(Reg)) { - if (UseMI.isDebugValue() || !UseMI.readsVirtualRegister(Reg)) + if (UseMI.isDebugInstr() || !UseMI.readsVirtualRegister(Reg)) continue; SlotIndex Idx = getInstructionIndex(UseMI).getRegSlot(); LiveQueryResult LRQ = li->Query(Idx); Index: lib/CodeGen/MachineInstr.cpp =================================================================== --- lib/CodeGen/MachineInstr.cpp +++ lib/CodeGen/MachineInstr.cpp @@ -2195,3 +2195,43 @@ return getSpillSlotSize(Accesses, getMF()->getFrameInfo()); return None; } + +MachineInstr *llvm::buildDbgCallParamForSpill(MachineInstr &Orig, + int FrameIndex) { + auto *CSP = Orig.getDebugCallSiteParam(); + unsigned firstReg = Orig.getOperand(0).getReg(); + DebugLoc DL = Orig.getDebugLoc(); + MachineFunction *MF = Orig.getParent()->getParent(); + MachineInstr *NewInstr = + BuildMI(*MF, DL, Orig.getDesc()).addReg(firstReg, getDebugRegState(true)) + .addMetadata(CSP) + .addFrameIndex(FrameIndex) + .addImm(0); + return NewInstr; +} + +MachineInstr *llvm::buildDbgCallParamForGlobal(MachineInstr &Orig, + const GlobalValue *GV) { + auto *CSP = Orig.getDebugCallSiteParam(); + unsigned firstReg = Orig.getOperand(0).getReg(); + DebugLoc DL = Orig.getDebugLoc(); + MachineFunction *MF = Orig.getParent()->getParent(); + MachineInstr *NewInstr = + BuildMI(*MF, DL, Orig.getDesc()).addReg(firstReg, getDebugRegState(true)) + .addMetadata(CSP) + .addGlobalAddress(GV) + .addImm(0); + return NewInstr; +} + +bool llvm::invalidateParamLocation(MachineInstr *MI) { + assert(MI->isDebugCallSiteParam()); + if (!MI->getDebugCallSiteParam()->getVar() && + MI->getDebugCallSiteParam()->getExpression()->getNumElements() == 0) + { + MI->eraseFromBundle(); + return true; + } + MI->getOperand(2).setReg(0); + return false; +} Index: lib/CodeGen/MachineRegisterInfo.cpp =================================================================== --- lib/CodeGen/MachineRegisterInfo.cpp +++ lib/CodeGen/MachineRegisterInfo.cpp @@ -542,8 +542,10 @@ I != E; I = nextI) { nextI = std::next(I); // I is invalidated by the setReg MachineInstr *UseMI = &*I; - if (UseMI->isDebugValue()) + if (UseMI->isDebugValue() || UseMI->isDebugCallSite()) UseMI->getOperand(0).setReg(0U); + else if (UseMI->isDebugCallSiteParam()) + invalidateParamLocation(UseMI); } } Index: lib/CodeGen/MachineVerifier.cpp =================================================================== --- lib/CodeGen/MachineVerifier.cpp +++ lib/CodeGen/MachineVerifier.cpp @@ -840,7 +840,7 @@ if (MI->isTerminator() && !TII->isPredicated(*MI)) { if (!FirstTerminator) FirstTerminator = MI; - } else if (FirstTerminator) { + } else if (FirstTerminator && !MI->isDebugCallSite()) { report("Non-terminator instruction after the first terminator", MI); errs() << "First terminator was:\t" << *FirstTerminator; } @@ -1436,7 +1436,7 @@ const unsigned Reg = MO->getReg(); if (!Reg) return; - if (MRI->tracksLiveness() && !MI->isDebugValue()) + if (MRI->tracksLiveness() && !MI->isDebugInstr()) checkLiveness(MO, MONum); // Verify the consistency of tied operands. @@ -2621,7 +2621,7 @@ } // Make sure a basic block with return ends with zero stack adjustment. - if (!MBB->empty() && MBB->back().isReturn()) { + if (MBB->isReturnBlock()) { if (BBState.ExitIsSetup) report("A return block ends with a FrameSetup.", MBB); if (BBState.ExitValue) Index: lib/CodeGen/PostRASchedulerList.cpp =================================================================== --- lib/CodeGen/PostRASchedulerList.cpp +++ lib/CodeGen/PostRASchedulerList.cpp @@ -350,7 +350,8 @@ Scheduler.Observe(MI, CurrentCount); } I = MI; - if (MI.isBundle()) + // Check also for DBG_CALLSITE bundles. + if (MI.isBundle() || (MI.isDebugCallSite() && MI.isBundledWithSucc())) Count -= MI.getBundleSize(); } assert(Count == 0 && "Instruction count mismatch!"); Index: lib/CodeGen/PrologEpilogInserter.cpp =================================================================== --- lib/CodeGen/PrologEpilogInserter.cpp +++ lib/CodeGen/PrologEpilogInserter.cpp @@ -1080,72 +1080,89 @@ continue; } + auto handleDebugInstr = [&](MachineInstr &MI, unsigned Operand) { + assert((Operand == 0 || Operand == 2) && + "Operand must be register of dbg_value or dbg_callsiteparam"); + unsigned Reg; + int64_t Offset = TFI->getFrameIndexReference( + MF, MI.getOperand(Operand).getIndex(), Reg); + MI.getOperand(Operand).ChangeToRegister(Reg, false /*isDef*/); + MI.getOperand(Operand).setIsDebug(); + + if (Operand) + MI.getOperand(3).setImm(Offset); + else { + auto *DIExpr = DIExpression::prepend(MI.getDebugExpression(), + DIExpression::NoDeref, Offset); + MI.getOperand(3).setMetadata(DIExpr); + } + }; + MachineInstr &MI = *I; bool DoIncr = true; bool DidFinishLoop = true; - for (unsigned i = 0, e = MI.getNumOperands(); i != e; ++i) { - if (!MI.getOperand(i).isFI()) - continue; + if (MI.isDebugCallSite()) { + auto It = MI.getIterator(); + while (It->isBundledWithSucc()) { + It++; + if (It->getOperand(2).isFI()) + handleDebugInstr(*It, 2); + } + } else if (MI.isDebugValue() && MI.getOperand(0).isFI()) { // Frame indices in debug values are encoded in a target independent // way with simply the frame index and offset rather than any // target-specific addressing mode. - if (MI.isDebugValue()) { - assert(i == 0 && "Frame indices can only appear as the first " - "operand of a DBG_VALUE machine instruction"); - unsigned Reg; - int64_t Offset = - TFI->getFrameIndexReference(MF, MI.getOperand(0).getIndex(), Reg); - MI.getOperand(0).ChangeToRegister(Reg, false /*isDef*/); - MI.getOperand(0).setIsDebug(); - auto *DIExpr = DIExpression::prepend(MI.getDebugExpression(), - DIExpression::NoDeref, Offset); - MI.getOperand(3).setMetadata(DIExpr); - continue; - } - - // TODO: This code should be commoned with the code for - // PATCHPOINT. There's no good reason for the difference in - // implementation other than historical accident. The only - // remaining difference is the unconditional use of the stack - // pointer as the base register. - if (MI.getOpcode() == TargetOpcode::STATEPOINT) { - assert((!MI.isDebugValue() || i == 0) && - "Frame indicies can only appear as the first operand of a " - "DBG_VALUE machine instruction"); - unsigned Reg; - MachineOperand &Offset = MI.getOperand(i + 1); - int refOffset = TFI->getFrameIndexReferencePreferSP( - MF, MI.getOperand(i).getIndex(), Reg, /*IgnoreSPUpdates*/ false); - Offset.setImm(Offset.getImm() + refOffset + SPAdj); - MI.getOperand(i).ChangeToRegister(Reg, false /*isDef*/); - continue; - } + handleDebugInstr(MI, 0); + } else { + for (unsigned i = 0, e = MI.getNumOperands(); i != e; ++i) { + if (!MI.getOperand(i).isFI()) + continue; - // Some instructions (e.g. inline asm instructions) can have - // multiple frame indices and/or cause eliminateFrameIndex - // to insert more than one instruction. We need the register - // scavenger to go through all of these instructions so that - // it can update its register information. We keep the - // iterator at the point before insertion so that we can - // revisit them in full. - bool AtBeginning = (I == BB->begin()); - if (!AtBeginning) --I; - - // If this instruction has a FrameIndex operand, we need to - // use that target machine register info object to eliminate - // it. - TRI.eliminateFrameIndex(MI, SPAdj, i, - FrameIndexEliminationScavenging ? RS : nullptr); - - // Reset the iterator if we were at the beginning of the BB. - if (AtBeginning) { - I = BB->begin(); - DoIncr = false; + // TODO: This code should be commoned with the code for + // PATCHPOINT. There's no good reason for the difference in + // implementation other than historical accident. The only + // remaining difference is the unconditional use of the stack + // pointer as the base register. + if (MI.getOpcode() == TargetOpcode::STATEPOINT) { + assert((!MI.isDebugValue() || i == 0) && + "Frame indicies can only appear as the first operand of a " + "DBG_VALUE machine instruction"); + unsigned Reg; + MachineOperand &Offset = MI.getOperand(i + 1); + int refOffset = TFI->getFrameIndexReferencePreferSP( + MF, MI.getOperand(i).getIndex(), Reg, /*IgnoreSPUpdates*/ false); + Offset.setImm(Offset.getImm() + refOffset + SPAdj); + MI.getOperand(i).ChangeToRegister(Reg, false /*isDef*/); + continue; + } + + // Some instructions (e.g. inline asm instructions) can have + // multiple frame indices and/or cause eliminateFrameIndex + // to insert more than one instruction. We need the register + // scavenger to go through all of these instructions so that + // it can update its register information. We keep the + // iterator at the point before insertion so that we can + // revisit them in full. + bool AtBeginning = (I == BB->begin()); + if (!AtBeginning) + --I; + + // If this instruction has a FrameIndex operand, we need to + // use that target machine register info object to eliminate + // it. + TRI.eliminateFrameIndex(MI, SPAdj, i, + FrameIndexEliminationScavenging ? RS : nullptr); + + // Reset the iterator if we were at the beginning of the BB. + if (AtBeginning) { + I = BB->begin(); + DoIncr = false; + } + + DidFinishLoop = false; + break; } - - DidFinishLoop = false; - break; } // If we are looking at a call sequence, we need to keep track of Index: lib/CodeGen/RegAllocFast.cpp =================================================================== --- lib/CodeGen/RegAllocFast.cpp +++ lib/CodeGen/RegAllocFast.cpp @@ -1076,6 +1076,9 @@ dumpState() ); + if (MI.isDebugCallSite() || MI.isDebugCallSiteParam()) + continue; + // Special handling for debug values. Note that they are not allowed to // affect codegen of the other instructions in any way. if (MI.isDebugValue()) { Index: lib/CodeGen/RegisterCoalescer.cpp =================================================================== --- lib/CodeGen/RegisterCoalescer.cpp +++ lib/CodeGen/RegisterCoalescer.cpp @@ -842,7 +842,7 @@ if (UseMO.isUndef()) continue; MachineInstr *UseMI = UseMO.getParent(); - if (UseMI->isDebugValue()) { + if (UseMI->isDebugInstr()) { // FIXME These don't have an instruction index. Not clear we have enough // info to decide whether to do this replacement or not. For now do it. UseMO.setReg(NewReg); @@ -1443,19 +1443,40 @@ LLVM_DEBUG(dbgs() << "Remat: " << NewMI); ++NumReMats; - // If the virtual SrcReg is completely eliminated, update all DBG_VALUEs - // to describe DstReg instead. + CalleeSavedRegChecker CalleeSavedRegs(MF); + // If the virtual SrcReg is completely eliminated, update all dbginfo + // instructions to describe DstReg instead. if (MRI->use_nodbg_empty(SrcReg)) { for (MachineOperand &UseMO : MRI->use_operands(SrcReg)) { MachineInstr *UseMI = UseMO.getParent(); - if (UseMI->isDebugValue()) { - if (TargetRegisterInfo::isPhysicalRegister(DstReg)) - UseMO.substPhysReg(DstReg, *TRI); - else + // Sometimes global objects, like raw string of charachets, could + // be loaded into register that carries that function parameter. + // We track that global in DBG_CALLSITEPARAM. + if (UseMI->isDebugCallSiteParam() && + DefMI->getNumOperands() == 2 && + DefMI->getOperand(1).isGlobal() && + DstReg == UseMI->getOperand(0).getReg()) { + + auto RIt = UseMI->getReverseIterator(); + while(!RIt->isDebugCallSite()) RIt++; + MachineInstr *NewInstr = + buildDbgCallParamForGlobal(*UseMI, DefMI->getOperand(1).getGlobal()); + UseMI->eraseFromBundle(); + MIBundleBuilder(&*RIt).append(NewInstr); + LLVM_DEBUG(dbgs() << "\t\tupdated: " << *UseMI); + } else if (UseMI->isDebugInstr()) { + if (TargetRegisterInfo::isPhysicalRegister(DstReg)) { + if (UseMI->isDebugCallSiteParam() && + !CalleeSavedRegs.isCalleeSaved(DstReg)) + invalidateParamLocation(UseMI); + else + UseMO.substPhysReg(DstReg, *TRI); + } else UseMO.setReg(DstReg); // Move the debug value directly after the def of the rematerialized // value in DstReg. - MBB->splice(std::next(NewMI.getIterator()), UseMI->getParent(), UseMI); + if (UseMI->isDebugValue()) + MBB->splice(std::next(NewMI.getIterator()), UseMI->getParent(), UseMI); LLVM_DEBUG(dbgs() << "\t\tupdated: " << *UseMI); } } @@ -1628,7 +1649,7 @@ if (SubReg == 0 || MO.isUndef()) continue; MachineInstr &MI = *MO.getParent(); - if (MI.isDebugValue()) + if (MI.isDebugInstr()) continue; SlotIndex UseIdx = LIS->getInstructionIndex(MI).getRegSlot(true); addUndefFlag(*DstInt, UseIdx, MO, SubReg); @@ -1655,7 +1676,7 @@ // If SrcReg wasn't read, it may still be the case that DstReg is live-in // because SrcReg is a sub-register. - if (DstInt && !Reads && SubIdx && !UseMI->isDebugValue()) + if (DstInt && !Reads && SubIdx && !UseMI->isDebugInstr()) Reads = DstInt->liveAt(LIS->getInstructionIndex(*UseMI)); // Replace SrcReg with DstReg in all UseMI operands. @@ -1676,7 +1697,7 @@ LaneBitmask Mask = MRI->getMaxLaneMaskForVReg(DstInt->reg); DstInt->createSubRangeFrom(Allocator, Mask, *DstInt); } - SlotIndex MIIdx = UseMI->isDebugValue() + SlotIndex MIIdx = UseMI->isDebugInstr() ? LIS->getSlotIndexes()->getIndexBefore(*UseMI) : LIS->getInstructionIndex(*UseMI); SlotIndex UseIdx = MIIdx.getRegSlot(true); @@ -1691,7 +1712,7 @@ LLVM_DEBUG({ dbgs() << "\t\tupdated: "; - if (!UseMI->isDebugValue()) + if (!UseMI->isDebugInstr()) dbgs() << LIS->getInstructionIndex(*UseMI) << "\t"; dbgs() << *UseMI; }); Index: lib/CodeGen/ScheduleDAGInstrs.cpp =================================================================== --- lib/CodeGen/ScheduleDAGInstrs.cpp +++ lib/CodeGen/ScheduleDAGInstrs.cpp @@ -780,6 +780,9 @@ if (MI.isDebugLabel()) continue; + if (MI.isDebugCallSite() || MI.isDebugCallSiteParam()) + continue; + SUnit *SU = MISUnitMap[&MI]; assert(SU && "No SUnit mapped to this MI"); Index: lib/CodeGen/SplitKit.cpp =================================================================== --- lib/CodeGen/SplitKit.cpp +++ lib/CodeGen/SplitKit.cpp @@ -1298,6 +1298,44 @@ } } +/// For dbg call instructions we search back to the instruction that loads +/// parameter carrying register and take its slot index in order to perform +/// same subsitution that is done for that that instruction. If we do not +/// find such instruction (because it may be in other block) we set it as +/// undef reg. +static MachineInstr *getParamLoadingInstr(MachineInstr *MI) { + auto It = MI->getReverseIterator(); + unsigned Reg = MI->getOperand(0).getReg(); + auto End = It->getParent()->rend(); + It++; + while (It != End) { + if (It->isCopy()) { + if (It->getOperand(0).isReg() && It->getOperand(0).getReg() == Reg) + return &*It; + } + It++; + } + return nullptr; +} + +/// Rewrite register that holds indirect call. +static bool updateDbgCallSiteInstr(MachineInstr *MI) { + auto It = MI->getReverseIterator(); + unsigned Reg = MI->getOperand(1).getReg(); + auto End = It->getParent()->rend(); + It++; + while (It != End) { + if (It->isCopy()) { + if (It->getOperand(1).isReg() && It->getOperand(1).getReg() == Reg) { + MI->getOperand(1).setReg(It->getOperand(0).getReg()); + return true; + } + } + It++; + } + return false; +} + /// rewriteAssigned - Rewrite all uses of Edit->getReg(). void SplitEditor::rewriteAssigned(bool ExtendRanges) { struct ExtPoint { @@ -1326,7 +1364,25 @@ // operands don't really read the register, so it doesn't matter // which register we choose. When the use operand is tied to a def, we must // use the same register as the def, so just do that always. - SlotIndex Idx = LIS.getInstructionIndex(*MI); + bool isDbgCallSite = MI->isDebugCallSite() || MI->isDebugCallSiteParam(); + SlotIndex Idx; + if (MI->isDebugCallSiteParam()) { + if (MachineInstr *NonDbgInstr = getParamLoadingInstr(MI)) { + Idx = LIS.getInstructionIndex(*NonDbgInstr); + } else { + invalidateParamLocation(MI); + continue; + } + } else if (MI->isDebugCallSite()) { + if (updateDbgCallSiteInstr(MI)) + continue; + else { + MI->eraseFromParent(); + continue; + } + } else + Idx = LIS.getInstructionIndex(*MI); + if (MO.isDef() || MO.isUndef()) Idx = Idx.getRegSlot(MO.isEarlyClobber()); @@ -1338,7 +1394,7 @@ << '\t' << Idx << ':' << RegIdx << '\t' << *MI); // Extend liveness to Idx if the instruction reads reg. - if (!ExtendRanges || MO.isUndef()) + if (!ExtendRanges || MO.isUndef() || isDbgCallSite) continue; // Skip instructions that don't read Reg. Index: lib/CodeGen/StackColoring.cpp =================================================================== --- lib/CodeGen/StackColoring.cpp +++ lib/CodeGen/StackColoring.cpp @@ -960,7 +960,7 @@ // Remap all instructions to the new stack slots. for (MachineBasicBlock &BB : *MF) - for (MachineInstr &I : BB) { + for (MachineInstr &I : BB.instrs()) { // Skip lifetime markers. We'll remove them soon. if (I.getOpcode() == TargetOpcode::LIFETIME_START || I.getOpcode() == TargetOpcode::LIFETIME_END) Index: lib/CodeGen/StackSlotColoring.cpp =================================================================== --- lib/CodeGen/StackSlotColoring.cpp +++ lib/CodeGen/StackSlotColoring.cpp @@ -372,7 +372,7 @@ // Rewrite all MO_FrameIndex operands. Look for dead stores. for (MachineBasicBlock &MBB : MF) { - for (MachineInstr &MI : MBB) + for (MachineInstr &MI : MBB.instrs()) RewriteInstruction(MI, SlotMapping, MF); RemoveDeadStores(&MBB); } Index: lib/CodeGen/TailDuplicator.cpp =================================================================== --- lib/CodeGen/TailDuplicator.cpp +++ lib/CodeGen/TailDuplicator.cpp @@ -218,6 +218,9 @@ // instead of replacing the use with undef? UseMI->eraseFromParent(); continue; + } else if (UseMI->isDebugCallSiteParam()) { + UseMI->eraseFromBundle(); + continue; } if (UseMI->getParent() == DefBB && !UseMI->isPHI()) continue; Index: lib/CodeGen/VirtRegMap.cpp =================================================================== --- lib/CodeGen/VirtRegMap.cpp +++ lib/CodeGen/VirtRegMap.cpp @@ -27,6 +27,7 @@ #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/MachineInstr.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/MachineOperand.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/CodeGen/SlotIndexes.h" @@ -50,6 +51,7 @@ STATISTIC(NumSpillSlots, "Number of spill slots allocated"); STATISTIC(NumIdCopies, "Number of identity moves eliminated after rewriting"); +STATISTIC(NumCSDeleted, "Number of deleted call site parameter information"); //===----------------------------------------------------------------------===// // VirtRegMap implementation @@ -187,6 +189,7 @@ bool readsUndefSubreg(const MachineOperand &MO) const; void addLiveInsForSubRanges(const LiveInterval &LI, unsigned PhysReg) const; void handleIdentityCopy(MachineInstr &MI) const; + void handleCallSiteIdentities(MachineInstr &MI) const; void expandCopyBundle(MachineInstr &MI) const; bool subRegLiveThrough(const MachineInstr &MI, unsigned SuperPhysReg) const; @@ -491,11 +494,23 @@ return false; } +void VirtRegRewriter::handleCallSiteIdentities(MachineInstr &MI) const { + assert(MI.isDebugCallSiteParam() && "This method handles only call" && + "site params"); + + // If we have overlapping registers check whether backup location + // description based on variable and expression over variable exists. + // If not, delete this call site parameter location. + if(invalidateParamLocation(&MI)) + NumCSDeleted++; +} + void VirtRegRewriter::rewrite() { bool NoSubRegLiveness = !MRI->subRegLivenessEnabled(); SmallVector SuperDeads; SmallVector SuperDefs; SmallVector SuperKills; + CalleeSavedRegChecker CalleeSavedRegs(MF); for (MachineFunction::iterator MBBI = MF->begin(), MBBE = MF->end(); MBBI != MBBE; ++MBBI) { @@ -505,6 +520,7 @@ MachineInstr *MI = &*MII; ++MII; + bool earlyDbgCSExit = false; for (MachineInstr::mop_iterator MOI = MI->operands_begin(), MOE = MI->operands_end(); MOI != MOE; ++MOI) { MachineOperand &MO = *MOI; @@ -517,6 +533,31 @@ continue; unsigned VirtReg = MO.getReg(); unsigned PhysReg = VRM->getPhys(VirtReg); + + if (MI->isDebugCallSiteParam()) { + if (PhysReg == VirtRegMap::NO_PHYS_REG) { + // This Condition should be revisited and removed. Such + // situation should not occur. If it occurs it means that + // we have not handled virtual register or call site parameter + // properly - we didn't changed it to its new virtual/physical + // register + // location or to proper frame location. + LLVM_DEBUG(dbgs() << "Setting call parameter location as invalid " + << *MI); + if (invalidateParamLocation(MI)) + NumCSDeleted++; + earlyDbgCSExit = true; + break; + } else if (!CalleeSavedRegs.isCalleeSaved(PhysReg)) { + if (MI->getOperand(0).getReg() == PhysReg) + handleCallSiteIdentities(*MI); + else if (invalidateParamLocation(MI)) + NumCSDeleted++; + earlyDbgCSExit = true; + break; + } + } + assert(PhysReg != VirtRegMap::NO_PHYS_REG && "Instruction uses unmapped VirtReg"); assert(!MRI->isReserved(PhysReg) && "Reserved register assignment"); @@ -571,6 +612,9 @@ MO.setIsRenamable(true); } + if (earlyDbgCSExit) + continue; + // Add any missing super-register kills after rewriting the whole // instruction. while (!SuperKills.empty()) Index: lib/IR/DebugInfoMetadata.cpp =================================================================== --- lib/IR/DebugInfoMetadata.cpp +++ lib/IR/DebugInfoMetadata.cpp @@ -914,6 +914,7 @@ case dwarf::DW_OP_xderef: case dwarf::DW_OP_neg: case dwarf::DW_OP_push_object_address: + case dwarf::DW_OP_GNU_entry_value: case dwarf::DW_OP_not: case dwarf::DW_OP_dup: break; @@ -989,7 +990,7 @@ DIExpression *DIExpression::prepend(const DIExpression *Expr, bool DerefBefore, int64_t Offset, bool DerefAfter, - bool StackValue) { + bool StackValue, bool EntryValue) { SmallVector Ops; if (DerefBefore) Ops.push_back(dwarf::DW_OP_deref); @@ -998,14 +999,17 @@ if (DerefAfter) Ops.push_back(dwarf::DW_OP_deref); - return prependOpcodes(Expr, Ops, StackValue); + return prependOpcodes(Expr, Ops, StackValue, EntryValue); } DIExpression *DIExpression::prependOpcodes(const DIExpression *Expr, SmallVectorImpl &Ops, - bool StackValue) { + bool StackValue, bool EntryValue) { assert(Expr && "Can't prepend ops to this expression"); + if (EntryValue) + Ops.push_back(dwarf::DW_OP_GNU_entry_value); + // If there are no ops to prepend, do not even add the DW_OP_stack_value. if (Ops.empty()) StackValue = false; Index: lib/Target/Mips/MipsAsmPrinter.cpp =================================================================== --- lib/Target/Mips/MipsAsmPrinter.cpp +++ lib/Target/Mips/MipsAsmPrinter.cpp @@ -198,6 +198,9 @@ if (MI->isDebugLabel()) return; + if (MI->isDebugCallSite() || MI->isDebugCallSiteParam()) + return; + // If we just ended a constant pool, mark it as such. if (InConstantPool && Opc != Mips::CONSTPOOL_ENTRY) { OutStreamer->EmitDataRegion(MCDR_DataRegionEnd); Index: lib/Target/X86/X86CallFrameOptimization.cpp =================================================================== --- lib/Target/X86/X86CallFrameOptimization.cpp +++ lib/Target/X86/X86CallFrameOptimization.cpp @@ -460,7 +460,10 @@ return; Context.Call = &*I; - if ((++I)->getOpcode() != TII->getCallFrameDestroyOpcode()) + // Skip over debug instructions. Most of the times it is debug info + // for call site. + while((++I)->isDebugInstr()); + if (I->getOpcode() != TII->getCallFrameDestroyOpcode()) return; // Now, go through the vector, and see that we don't have any gaps, Index: lib/Target/X86/X86FrameLowering.cpp =================================================================== --- lib/Target/X86/X86FrameLowering.cpp +++ lib/Target/X86/X86FrameLowering.cpp @@ -1645,7 +1645,8 @@ MachineBasicBlock::iterator PI = std::prev(MBBI); unsigned Opc = PI->getOpcode(); - if (Opc != X86::DBG_VALUE && !PI->isTerminator()) { + if (Opc != X86::DBG_CALLSITE && Opc != X86::DBG_CALLSITEPARAM && + Opc != X86::DBG_VALUE && !PI->isTerminator()) { if ((Opc != X86::POP32r || !PI->getFlag(MachineInstr::FrameDestroy)) && (Opc != X86::POP64r || !PI->getFlag(MachineInstr::FrameDestroy))) break; Index: test/DebugInfo/MIR/X86/dbginfo-loading-stack-param.mir =================================================================== --- /dev/null +++ test/DebugInfo/MIR/X86/dbginfo-loading-stack-param.mir @@ -0,0 +1,189 @@ +# RUN: llc -mtriple=x86_64-linux-gnu -run-pass=greedy %s -o -| FileCheck %s +# CHECK-NOT: DBG_CALLSITEPARAM $xmm0, !15, %7 +# CHECK: DBG_CALLSITEPARAM $xmm0, !15, %stack.0 +# Frist check is for checking call dbg info virtual register spliting from +# SplitEditor::rewriteAssigned. +# Second check is for testing when virtual register is replaced with +# frame object. +# Test is produced from code: +# extern float externFunc(float); +# extern float externFunc2(float); +# +# float foo(float arg1) { +# float result = 0; +# if (arg1 > 10.1231) { +# result += externFunc(arg1); +# } +# else { +# arg1 += 10; +# result = externFunc2(arg1); +# result += externFunc(arg1); +# } +# return result; +# } + +--- | + ; ModuleID = 'dbginfo-loading-stack-param.ll' + source_filename = "dbginfo-loading-stack-param.c" + target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + target triple = "x86_64-unknown-linux-gnu" + + define float @foo(float %arg1) local_unnamed_addr !dbg !6 { + entry: + %conv = fpext float %arg1 to double, !dbg !21 + %cmp = fcmp ogt double %conv, 1.012310e+01, !dbg !21 + br i1 %cmp, label %if.then, label %if.else, !dbg !21 + + if.then: ; preds = %entry + %call = tail call float @externFunc(float %arg1), !dbg !21, !CallSite !11 + br label %if.end, !dbg !21 + + if.else: ; preds = %entry + %add2 = fadd float %arg1, 1.000000e+01, !dbg !21 + %call3 = tail call float @externFunc2(float %add2), !dbg !21, !CallSite !17 + %call4 = tail call float @externFunc(float %add2), !dbg !21, !CallSite !20 + br label %if.end + + if.end: ; preds = %if.else, %if.then + %call4.sink = phi float [ %call4, %if.else ], [ 0.000000e+00, %if.then ] + %call3.sink = phi float [ %call3, %if.else ], [ %call, %if.then ] + %add5 = fadd float %call4.sink, %call3.sink + ret float %add5, !dbg !21 + } + + declare float @externFunc(float) local_unnamed_addr + + declare float @externFunc2(float) local_unnamed_addr + + ; Function Attrs: nounwind + declare void @llvm.stackprotector(i8*, i8**) #0 + + attributes #0 = { nounwind } + + !llvm.dbg.cu = !{!0} + !llvm.module.flags = !{!3, !4} + !llvm.ident = !{!5} + + !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 4.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) + !1 = !DIFile(filename: "dbginfo-loading-stack-param.c", directory: "/") + !2 = !{} + !3 = !{i32 2, !"Dwarf Version", i32 4} + !4 = !{i32 2, !"Debug Info Version", i32 3} + !5 = !{!"clang version 4.0.0"} + !6 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 4, type: !7, isLocal: false, isDefinition: true, scopeLine: 4, flags: DIFlagPrototyped, isOptimized: true, unit: !0, retainedNodes: !10) + !7 = !DISubroutineType(types: !8) + !8 = !{!9, !9} + !9 = !DIBasicType(name: "float", size: 32, encoding: DW_ATE_float) + !10 = !{!11, !17, !20} + !11 = !DICallSite(scope: !12, file: !1, parameters: !14, line: 7, calledSubprogram: !16) + !12 = distinct !DILexicalBlock(scope: !13, file: !1, line: 6, column: 22) + !13 = distinct !DILexicalBlock(scope: !6, file: !1, line: 6, column: 6) + !14 = !{!15} + !15 = !DICallSiteParam(argno: 1, expr: !DIExpression()) + !16 = !DISubprogram(name: "externFunc", scope: !1, file: !1, line: 1, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true, retainedNodes: !2) + !17 = !DICallSite(scope: !18, file: !1, parameters: !14, line: 11, calledSubprogram: !19) + !18 = distinct !DILexicalBlock(scope: !13, file: !1, line: 9, column: 7) + !19 = !DISubprogram(name: "externFunc2", scope: !1, file: !1, line: 2, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true, retainedNodes: !2) + !20 = !DICallSite(scope: !18, file: !1, parameters: !14, line: 12, calledSubprogram: !16) + !21 = !DILocation(line: 4, column: 17, scope: !6) + +... +--- +name: foo +alignment: 4 +exposesReturnsTwice: false +legalized: false +regBankSelected: false +selected: false +tracksRegLiveness: true +registers: + - { id: 0, class: fr32 } + - { id: 1, class: fr32 } + - { id: 2, class: fr32 } + - { id: 3, class: fr32 } + - { id: 4, class: fr32 } + - { id: 5, class: fr32 } + - { id: 6, class: fr64 } + - { id: 7, class: fr32 } + - { id: 8, class: fr32 } + - { id: 9, class: fr32 } + - { id: 10, class: fr32 } + - { id: 11, class: fr32 } + - { id: 12, class: fr32 } + - { id: 13, class: fr32 } + - { id: 14, class: fr32 } +liveins: + - { reg: '$xmm0', virtual-reg: '%5' } +frameInfo: + isFrameAddressTaken: false + isReturnAddressTaken: false + hasStackMap: false + hasPatchPoint: false + stackSize: 0 + offsetAdjustment: 0 + maxAlignment: 0 + adjustsStack: false + hasCalls: true + maxCallFrameSize: 0 + hasOpaqueSPAdjustment: false + hasVAStart: false + hasMustTailInVarArgFunc: false +constants: + - id: 0 + value: 'double 1.012310e+01' + alignment: 8 + - id: 1 + value: 'float 1.000000e+01' + alignment: 4 +body: | + bb.0.entry: + successors: %bb.1.if.then(0x40000000), %bb.2.if.else(0x40000000) + liveins: $xmm0 + + %7 = COPY $xmm0 + %6 = CVTSS2SDrr %7, debug-location !21 + UCOMISDrm %6, $rip, 1, $noreg, %const.0, $noreg, implicit-def $eflags, debug-location !21 :: (load 8 from constant-pool) + JBE_1 %bb.2.if.else, implicit killed $eflags, debug-location !21 + JMP_1 %bb.1.if.then, debug-location !21 + + bb.1.if.then: + successors: %bb.3.if.end(0x80000000) + + ADJCALLSTACKDOWN64 0, 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp, debug-location !21 + $xmm0 = COPY %7, debug-location !21 + CALL64pcrel32 @externFunc, csr_64, implicit $rsp, implicit $ssp, implicit $xmm0, implicit-def $rsp, implicit-def $ssp, implicit-def $xmm0, debug-location !21 + DBG_CALLSITE 0, $noreg, !11, debug-location !21 { + DBG_CALLSITEPARAM $xmm0, !15, %7, $noreg, debug-location !21 + } + ADJCALLSTACKUP64 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp, debug-location !21 + %14 = COPY $xmm0, debug-location !21 + %13 = FsFLD0SS + JMP_1 %bb.3.if.end, debug-location !21 + + bb.2.if.else: + successors: %bb.3.if.end(0x80000000) + + %7 = ADDSSrm %7, $rip, 1, $noreg, %const.1, $noreg, debug-location !21 :: (load 4 from constant-pool) + ADJCALLSTACKDOWN64 0, 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp, debug-location !21 + $xmm0 = COPY %7, debug-location !21 + CALL64pcrel32 @externFunc2, csr_64, implicit $rsp, implicit $ssp, implicit $xmm0, implicit-def $rsp, implicit-def $ssp, implicit-def $xmm0, debug-location !21 + DBG_CALLSITE 0, $noreg, !17, debug-location !21 { + DBG_CALLSITEPARAM $xmm0, !15, %7, $noreg, debug-location !21 + } + ADJCALLSTACKUP64 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp, debug-location !21 + %14 = COPY $xmm0, debug-location !21 + ADJCALLSTACKDOWN64 0, 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp, debug-location !21 + $xmm0 = COPY %7, debug-location !21 + CALL64pcrel32 @externFunc, csr_64, implicit $rsp, implicit $ssp, implicit $xmm0, implicit-def $rsp, implicit-def $ssp, implicit-def $xmm0, debug-location !21 + DBG_CALLSITE 0, $noreg, !20, debug-location !21 { + DBG_CALLSITEPARAM $xmm0, !15, %7, $noreg, debug-location !21 + } + ADJCALLSTACKUP64 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp, debug-location !21 + %13 = COPY $xmm0, debug-location !21 + + bb.3.if.end: + %13 = ADDSSrr %13, %14 + $xmm0 = COPY %13, debug-location !21 + RET 0, $xmm0, debug-location !21 + +... Index: test/DebugInfo/MIR/X86/dbginfo-param-replace-global.mir =================================================================== --- /dev/null +++ test/DebugInfo/MIR/X86/dbginfo-param-replace-global.mir @@ -0,0 +1,88 @@ +# RUN: llc -run-pass=simple-register-coalescing %s -o -| FileCheck %s +# CHECK: DBG_CALLSITEPARAM $rdi, !16, @global, 0 +#int global = 1; +#void baa(int *); +#void foo() { +# baa(&global); +#} + +--- | + ; ModuleID = 'dbginfo-param-replace-global.ll' + source_filename = "dbginfo-param-replace-global.c" + target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + target triple = "x86_64-unknown-linux-gnu" + + @global = global i32 1, align 4, !dbg !0 + + define void @foo() local_unnamed_addr !dbg !10 { + entry: + tail call void @baa(i32* nonnull @global), !dbg !18, !CallSite !14 + ret void, !dbg !19 + } + + declare void @baa(i32*) local_unnamed_addr + + ; Function Attrs: nounwind + declare void @llvm.stackprotector(i8*, i8**) #0 + + attributes #0 = { nounwind } + + !llvm.dbg.cu = !{!2} + !llvm.module.flags = !{!7, !8} + !llvm.ident = !{!9} + + !0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) + !1 = distinct !DIGlobalVariable(name: "global", scope: !2, file: !3, line: 8, type: !6, isLocal: false, isDefinition: true) + !2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 8.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5) + !3 = !DIFile(filename: "dbginfo-param-replace-global.c", directory: "/") + !4 = !{} + !5 = !{!0} + !6 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) + !7 = !{i32 2, !"Dwarf Version", i32 4} + !8 = !{i32 2, !"Debug Info Version", i32 3} + !9 = !{!"clang version 4.0.0"} + !10 = distinct !DISubprogram(name: "foo", scope: !3, file: !3, line: 10, type: !11, isLocal: false, isDefinition: true, scopeLine: 10, isOptimized: true, unit: !2, retainedNodes: !13) + !11 = !DISubroutineType(types: !12) + !12 = !{null} + !13 = !{!14} + !14 = !DICallSite(scope: !10, file: !3, parameters: !15, line: 11, calledSubprogram: !17) + !15 = !{!16} + !16 = !DICallSiteParam(argno: 1, expr: !DIExpression()) + !17 = !DISubprogram(name: "baa", scope: !3, file: !3, line: 9, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true, retainedNodes: !4) + !18 = !DILocation(line: 11, column: 3, scope: !10) + !19 = !DILocation(line: 12, column: 1, scope: !10) + +... +--- +name: foo +alignment: 4 +exposesReturnsTwice: false +legalized: false +regBankSelected: false +selected: false +tracksRegLiveness: true +registers: + - { id: 0, class: gr64 } +frameInfo: + isFrameAddressTaken: false + isReturnAddressTaken: false + hasStackMap: false + hasPatchPoint: false + stackSize: 0 + offsetAdjustment: 0 + maxAlignment: 0 + adjustsStack: false + hasCalls: false + maxCallFrameSize: 0 + hasOpaqueSPAdjustment: false + hasVAStart: false + hasMustTailInVarArgFunc: false +body: | + bb.0.entry: + %0:gr64 = MOV32ri64 @global, debug-location !18 + $rdi = COPY %0:gr64, debug-location !18 + TCRETURNdi64 @baa, 0, csr_64, implicit $rsp, implicit killed $rdi, debug-location !18 + DBG_CALLSITE 1, $noreg, !14, debug-location !18 { + DBG_CALLSITEPARAM debug-use $rdi, !16, debug-use %0, $noreg, debug-location !18 + } +... Index: test/DebugInfo/X86/transfer-call-param-sdnode.ll =================================================================== --- /dev/null +++ test/DebugInfo/X86/transfer-call-param-sdnode.ll @@ -0,0 +1,70 @@ +; RUN: llc -stop-after="expand-isel-pseudos" %s -o -| FileCheck %s -check-prefix=DAG +; RUN: llc %s -o -| FileCheck %s +; DAG: DBG_CALLSITEPARAM $edi +; +; CHECK: movl %eax, %edi +; CHECK-NEXT: .Ltmp +; CHECK-NEXT: jmp use # TAILCALL +; CHECK-NEXT: .Ltmp +; CHECK-NEXT: #DEBUG_CALLSITE: foo: isTailCall: 1, register: %noreg0 +; CHECK-NOT: DBG_PARAM: arg1: %edi <- %eax +; void foo(int arg1) { +; int baa = arg1<<2; +; use(baa > 0 ? baa : -baa); +; } + + +; ModuleID = 'transfer-call-param-sdnode.c' +source_filename = "transfer-call-param-sdnode.c" +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +; Function Attrs: nounwind uwtable +define void @foo(i32 %arg1) local_unnamed_addr !dbg !6 { +entry: + tail call void @llvm.dbg.value(metadata i32 %arg1, i64 0, metadata !12, metadata !DIExpression()), !dbg !17 + %shl = shl i32 %arg1, 2, !dbg !18 + tail call void @llvm.dbg.value(metadata i32 %shl, i64 0, metadata !11, metadata !DIExpression()), !dbg !19 + %cmp = icmp sgt i32 %shl, 0, !dbg !20 + %sub = sub nsw i32 0, %shl, !dbg !21 + %cond = select i1 %cmp, i32 %shl, i32 %sub, !dbg !23 + tail call void @use(i32 %cond), !dbg !24, !call_site !13 + ret void, !dbg !26 +} + +declare void @use(i32) local_unnamed_addr + +; Function Attrs: nounwind readnone +declare void @llvm.dbg.value(metadata, i64, metadata, metadata) + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4} +!llvm.ident = !{!5} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 4.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) +!1 = !DIFile(filename: "transfer-call-param-sdnode.c", directory: "/") +!2 = !{} +!3 = !{i32 2, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{!"clang version 4.0.0"} +!6 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 9, type: !7, isLocal: false, isDefinition: true, scopeLine: 9, flags: DIFlagPrototyped, isOptimized: true, unit: !0, retainedNodes: !10) +!7 = !DISubroutineType(types: !8) +!8 = !{null, !9} +!9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!10 = !{!11, !12, !13} +!11 = !DILocalVariable(name: "baa", scope: !6, file: !1, line: 10, type: !9, flags: DIFlagArgumentNotModified) +!12 = !DILocalVariable(name: "arg1", arg: 1, scope: !6, file: !1, line: 9, type: !9, flags: DIFlagArgumentNotModified) +!13 = !DICallSite(scope: !6, file: !1, parameters: !14, line: 11, calledSubprogram: !16) +!14 = !{!15} +!15 = !DICallSiteParam(argno: 1, expr: !DIExpression()) +!16 = !DISubprogram(name: "use", scope: !1, file: !1, line: 8, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true, retainedNodes: !2) +!17 = !DILocation(line: 9, column: 14, scope: !6) +!18 = !DILocation(line: 10, column: 17, scope: !6) +!19 = !DILocation(line: 10, column: 7, scope: !6) +!20 = !DILocation(line: 11, column: 11, scope: !6) +!21 = !DILocation(line: 11, column: 23, scope: !22) +!22 = !DILexicalBlockFile(scope: !6, file: !1, discriminator: 2) +!23 = !DILocation(line: 11, column: 7, scope: !6) +!24 = !DILocation(line: 11, column: 3, scope: !25) +!25 = !DILexicalBlockFile(scope: !6, file: !1, discriminator: 3) +!26 = !DILocation(line: 12, column: 1, scope: !6)