Index: llvm/include/llvm/CodeGen/SelectionDAG.h =================================================================== --- llvm/include/llvm/CodeGen/SelectionDAG.h +++ llvm/include/llvm/CodeGen/SelectionDAG.h @@ -64,6 +64,7 @@ class DataLayout; struct fltSemantics; class FunctionLoweringInfo; +class FunctionVarLocs; class GlobalValue; struct KnownBits; class LegacyDivergenceAnalysis; @@ -218,6 +219,7 @@ const SelectionDAGTargetInfo *TSI = nullptr; const TargetLowering *TLI = nullptr; const TargetLibraryInfo *LibInfo = nullptr; + const FunctionVarLocs *FnVarLocs = nullptr; MachineFunction *MF; Pass *SDAGISelPass = nullptr; LLVMContext *Context; @@ -423,8 +425,8 @@ /// Prepare this SelectionDAG to process code in the given MachineFunction. void init(MachineFunction &NewMF, OptimizationRemarkEmitter &NewORE, Pass *PassPtr, const TargetLibraryInfo *LibraryInfo, - LegacyDivergenceAnalysis * Divergence, - ProfileSummaryInfo *PSIin, BlockFrequencyInfo *BFIin); + LegacyDivergenceAnalysis *Divergence, ProfileSummaryInfo *PSIin, + BlockFrequencyInfo *BFIin, FunctionVarLocs const *FnVarLocs); void setFunctionLoweringInfo(FunctionLoweringInfo * FuncInfo) { FLI = FuncInfo; @@ -444,6 +446,9 @@ const TargetLibraryInfo &getLibInfo() const { return *LibInfo; } const SelectionDAGTargetInfo &getSelectionDAGInfo() const { return *TSI; } const LegacyDivergenceAnalysis *getDivergenceAnalysis() const { return DA; } + /// Returns the result of the AssignmentTrackingAnalysis pass if it's + /// available, otherwise return nullptr. + const FunctionVarLocs *getFunctionVarLocs() const { return FnVarLocs; } LLVMContext *getContext() const { return Context; } OptimizationRemarkEmitter &getORE() const { return *ORE; } ProfileSummaryInfo *getPSI() const { return PSI; } Index: llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp =================================================================== --- llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp +++ llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp @@ -1207,11 +1207,11 @@ } void SelectionDAG::init(MachineFunction &NewMF, - OptimizationRemarkEmitter &NewORE, - Pass *PassPtr, const TargetLibraryInfo *LibraryInfo, - LegacyDivergenceAnalysis * Divergence, - ProfileSummaryInfo *PSIin, - BlockFrequencyInfo *BFIin) { + OptimizationRemarkEmitter &NewORE, Pass *PassPtr, + const TargetLibraryInfo *LibraryInfo, + LegacyDivergenceAnalysis *Divergence, + ProfileSummaryInfo *PSIin, BlockFrequencyInfo *BFIin, + FunctionVarLocs const *VarLocs) { MF = &NewMF; SDAGISelPass = PassPtr; ORE = &NewORE; @@ -1222,6 +1222,7 @@ DA = Divergence; PSI = PSIin; BFI = BFIin; + FnVarLocs = VarLocs; } SelectionDAG::~SelectionDAG() { Index: llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h =================================================================== --- llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h +++ llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h @@ -18,6 +18,7 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/MapVector.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/CodeGen/AssignmentTrackingAnalysis.h" #include "llvm/CodeGen/CodeGenCommonISel.h" #include "llvm/CodeGen/ISDOpcodes.h" #include "llvm/CodeGen/SelectionDAGNodes.h" @@ -103,34 +104,68 @@ /// Helper type for DanglingDebugInfoMap. class DanglingDebugInfo { - const DbgValueInst *DI = nullptr; + using DbgValTy = const DbgValueInst *; + using VarLocTy = const VarLocInfo *; + PointerUnion Info; unsigned SDNodeOrder = 0; public: DanglingDebugInfo() = default; DanglingDebugInfo(const DbgValueInst *di, DebugLoc DL, unsigned SDNO) - : DI(di), SDNodeOrder(SDNO) {} - - DILocalVariable *getVariable() const { return DI->getVariable(); } - DIExpression *getExpression() const { return DI->getExpression(); } + : Info(di), SDNodeOrder(SDNO) {} + DanglingDebugInfo(const VarLocInfo *VarLoc, DebugLoc DL, unsigned SDNO) + : Info(VarLoc), SDNodeOrder(SDNO) {} + + DILocalVariable *getVariable(const FunctionVarLocs *Locs) const { + if (Info.is()) + return Locs->getDILocalVariable(Info.get()->VariableID); + return Info.get()->getVariable(); + } + DIExpression *getExpression() const { + if (Info.is()) + return Info.get()->Expr; + return Info.get()->getExpression(); + } Value *getVariableLocationOp(unsigned Idx) const { assert(Idx == 0 && "variadic not supported yet"); - return DI->getVariableLocationOp(0); + if (Info.is()) + return Info.get()->V; + return Info.get()->getVariableLocationOp(Idx); + } + DebugLoc getdl() const { + if (Info.is()) + return Info.get()->DL; + return Info.get()->getDebugLoc(); } - DebugLoc getdl() const { return DI->getDebugLoc(); } unsigned getSDNodeOrder() const { return SDNodeOrder; } - friend raw_ostream &operator<<(raw_ostream &OS, - const DanglingDebugInfo &Info) { - OS << "DDI(var=" << *Info.getVariable() - << ", val= " << *Info.getVariableLocationOp(0) - << ", expr=" << *Info.getExpression() - << ", order=" << Info.getSDNodeOrder() << ", loc=" << Info.getdl() - << ")"; - return OS; - } + /// Helper for printing DanglingDebugInfo. This hoop-jumping is to + /// accommodate the fact that an argument is required for getVariable. + /// Call SelectionDAGBuilder::printDDI instead of using directly. + struct Print { + Print(const DanglingDebugInfo &DDI, const FunctionVarLocs *VarLocs) + : DDI(DDI), VarLocs(VarLocs) {} + const DanglingDebugInfo &DDI; + const FunctionVarLocs *VarLocs; + friend raw_ostream &operator<<(raw_ostream &OS, + const DanglingDebugInfo::Print &P) { + OS << "DDI(var=" << *P.DDI.getVariable(P.VarLocs) + << ", val= " << *P.DDI.getVariableLocationOp(0) + << ", expr=" << *P.DDI.getExpression() + << ", order=" << P.DDI.getSDNodeOrder() << ", loc=" << P.DDI.getdl() + << ")"; + return OS; + } + }; }; + /// Returns an object that defines `raw_ostream &operator<<` for printing. + /// Usage example: + //// errs() << printDDI(MyDanglingInfo) << " is dangling\n"; + DanglingDebugInfo::Print printDDI(const DanglingDebugInfo &DDI) { + return DanglingDebugInfo::Print(DDI, DAG.getFunctionVarLocs()); + } + /// Helper type for DanglingDebugInfoMap. typedef std::vector DanglingDebugInfoVector; @@ -311,6 +346,7 @@ /// Register a dbg_value which relies on a Value which we have not yet seen. void addDanglingDebugInfo(const DbgValueInst *DI, DebugLoc DL, unsigned Order); + void addDanglingDebugInfo(const VarLocInfo *VarLoc, unsigned Order); /// If we have dangling debug info that describes \p Variable, or an /// overlapping part of variable considering the \p Expr, then this method Index: llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp =================================================================== --- llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -35,6 +35,7 @@ #include "llvm/Analysis/ValueTracking.h" #include "llvm/Analysis/VectorUtils.h" #include "llvm/CodeGen/Analysis.h" +#include "llvm/CodeGen/AssignmentTrackingAnalysis.h" #include "llvm/CodeGen/FunctionLoweringInfo.h" #include "llvm/CodeGen/GCMetadata.h" #include "llvm/CodeGen/MachineBasicBlock.h" @@ -67,6 +68,7 @@ #include "llvm/IR/ConstantRange.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DataLayout.h" +#include "llvm/IR/DebugInfo.h" #include "llvm/IR/DebugInfoMetadata.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/DiagnosticInfo.h" @@ -1124,6 +1126,21 @@ HandlePHINodesInSuccessorBlocks(I.getParent()); } + // Add SDDbgValue nodes for any var locs here. Do so before updating + // SDNodeOrder, as this mapping is {Inst -> Locs BEFORE Inst}. + if (FunctionVarLocs const *FnVarLocs = DAG.getFunctionVarLocs()) { + // Add SDDbgValue nodes for any var locs here. Do so before updating + // SDNodeOrder, as this mapping is {Inst -> Locs BEFORE Inst}. + for (auto It = FnVarLocs->locs_begin(&I), End = FnVarLocs->locs_end(&I); + It != End; ++It) { + auto *Var = FnVarLocs->getDILocalVariable(It->VariableID); + dropDanglingDebugInfo(Var, It->Expr); + if (!handleDebugValue(It->V, Var, It->Expr, It->DL, SDNodeOrder, + /*IsVariadic=*/false)) + addDanglingDebugInfo(It, SDNodeOrder); + } + } + // Increase the SDNodeOrder if dealing with a non-debug instruction. if (!isa(I)) ++SDNodeOrder; @@ -1155,6 +1172,11 @@ } } +void SelectionDAGBuilder::addDanglingDebugInfo(const VarLocInfo *VarLoc, + unsigned Order) { + DanglingDebugInfoMap[VarLoc->V].emplace_back(VarLoc, VarLoc->DL, Order); +} + void SelectionDAGBuilder::addDanglingDebugInfo(const DbgValueInst *DI, DebugLoc DL, unsigned Order) { // We treat variadic dbg_values differently at this stage. @@ -1185,10 +1207,11 @@ void SelectionDAGBuilder::dropDanglingDebugInfo(const DILocalVariable *Variable, const DIExpression *Expr) { auto isMatchingDbgValue = [&](DanglingDebugInfo &DDI) { - DIVariable *DanglingVariable = DDI.getVariable(); + DIVariable *DanglingVariable = DDI.getVariable(DAG.getFunctionVarLocs()); DIExpression *DanglingExpr = DDI.getExpression(); if (DanglingVariable == Variable && Expr->fragmentsOverlap(DanglingExpr)) { - LLVM_DEBUG(dbgs() << "Dropping dangling debug info for " << DDI << "\n"); + LLVM_DEBUG(dbgs() << "Dropping dangling debug info for " << printDDI(DDI) + << "\n"); return true; } return false; @@ -1220,7 +1243,7 @@ DebugLoc dl = DDI.getdl(); unsigned ValSDNodeOrder = Val.getNode()->getIROrder(); unsigned DbgSDNodeOrder = DDI.getSDNodeOrder(); - DILocalVariable *Variable = DDI.getVariable(); + DILocalVariable *Variable = DDI.getVariable(DAG.getFunctionVarLocs()); DIExpression *Expr = DDI.getExpression(); assert(Variable->isValidLocationForIntrinsic(dl) && "Expected inlined-at fields to agree"); @@ -1233,7 +1256,8 @@ // have some test case that prove this to be correct we should avoid // calling EmitFuncArgumentDbgValue here. if (!EmitFuncArgumentDbgValue(V, Variable, Expr, dl, false, Val)) { - LLVM_DEBUG(dbgs() << "Resolve dangling debug info for " << DDI << "\n"); + LLVM_DEBUG(dbgs() << "Resolve dangling debug info for " << printDDI(DDI) + << "\n"); LLVM_DEBUG(dbgs() << " By mapping to:\n "; Val.dump()); // Increase the SDNodeOrder for the DbgValue here to make sure it is // inserted after the definition of Val when emitting the instructions @@ -1246,10 +1270,10 @@ std::max(DbgSDNodeOrder, ValSDNodeOrder)); DAG.AddDbgValue(SDV, false); } else - LLVM_DEBUG(dbgs() << "Resolved dangling debug info for " << DDI - << "in EmitFuncArgumentDbgValue\n"); + LLVM_DEBUG(dbgs() << "Resolved dangling debug info for " + << printDDI(DDI) << " in EmitFuncArgumentDbgValue\n"); } else { - LLVM_DEBUG(dbgs() << "Dropping debug info for " << DDI << "\n"); + LLVM_DEBUG(dbgs() << "Dropping debug info for " << printDDI(DDI) << "\n"); auto Undef = UndefValue::get(V->getType()); auto SDV = DAG.getConstantDbgValue(Variable, Expr, Undef, dl, DbgSDNodeOrder); @@ -1266,7 +1290,7 @@ // a DIArgList. Value *V = DDI.getVariableLocationOp(0); Value *OrigV = V; - DILocalVariable *Var = DDI.getVariable(); + DILocalVariable *Var = DDI.getVariable(DAG.getFunctionVarLocs()); DIExpression *Expr = DDI.getExpression(); DebugLoc DL = DDI.getdl(); unsigned SDOrder = DDI.getSDNodeOrder(); @@ -1321,7 +1345,8 @@ auto SDV = DAG.getConstantDbgValue(Var, Expr, Undef, DL, SDNodeOrder); DAG.AddDbgValue(SDV, false); - LLVM_DEBUG(dbgs() << "Dropping debug value info for:\n " << DDI << "\n"); + LLVM_DEBUG(dbgs() << "Dropping debug value info for:\n " << printDDI(DDI) + << "\n"); } bool SelectionDAGBuilder::handleDebugValue(ArrayRef Values, @@ -6006,6 +6031,9 @@ } case Intrinsic::dbg_addr: case Intrinsic::dbg_declare: { + // Debug intrinsics are handled seperately in assignment tracking mode. + if (getEnableAssignmentTracking()) + return; // Assume dbg.addr and dbg.declare can not currently use DIArgList, i.e. // they are non-variadic. const auto &DI = cast(I); @@ -6104,7 +6132,16 @@ DAG.AddDbgLabel(SDV); return; } + case Intrinsic::dbg_assign: { + // Debug intrinsics are handled seperately in assignment tracking mode. + assert(getEnableAssignmentTracking() && + "expected assignment tracking to be enabled"); + return; + } case Intrinsic::dbg_value: { + // Debug intrinsics are handled seperately in assignment tracking mode. + if (getEnableAssignmentTracking()) + return; const DbgValueInst &DI = cast(I); assert(DI.getVariable() && "Missing variable"); @@ -6121,7 +6158,7 @@ bool IsVariadic = DI.hasArgList(); if (!handleDebugValue(Values, Variable, Expression, DI.getDebugLoc(), SDNodeOrder, IsVariadic)) - addDanglingDebugInfo(&DI, DI.getDebugLoc(), SDNodeOrder); + addDanglingDebugInfo(&DI, dl, SDNodeOrder); return; } Index: llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp =================================================================== --- llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp +++ llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp @@ -33,6 +33,7 @@ #include "llvm/Analysis/ProfileSummaryInfo.h" #include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/Analysis/TargetTransformInfo.h" +#include "llvm/CodeGen/AssignmentTrackingAnalysis.h" #include "llvm/CodeGen/CodeGenCommonISel.h" #include "llvm/CodeGen/FastISel.h" #include "llvm/CodeGen/FunctionLoweringInfo.h" @@ -62,6 +63,7 @@ #include "llvm/IR/BasicBlock.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DataLayout.h" +#include "llvm/IR/DebugInfo.h" #include "llvm/IR/DebugInfoMetadata.h" #include "llvm/IR/DebugLoc.h" #include "llvm/IR/DiagnosticInfo.h" @@ -343,6 +345,10 @@ if (UseMBPI && OptLevel != CodeGenOpt::None) AU.addRequired(); AU.addRequired(); + if (getEnableAssignmentTracking()) { + AU.addRequired(); + AU.addPreserved(); + } if (OptLevel != CodeGenOpt::None) LazyBlockFrequencyInfoPass::getLazyBFIAnalysisUsage(AU); MachineFunctionPass::getAnalysisUsage(AU); @@ -452,12 +458,17 @@ if (PSI && PSI->hasProfileSummary() && OptLevel != CodeGenOpt::None) BFI = &getAnalysis().getBFI(); + FunctionVarLocs const *FnVarLocs = nullptr; + if (getEnableAssignmentTracking()) + FnVarLocs = getAnalysis().getResults(); + LLVM_DEBUG(dbgs() << "\n\n\n=== " << Fn.getName() << "\n"); SplitCriticalSideEffectEdges(const_cast(Fn), DT, LI); CurDAG->init(*MF, *ORE, this, LibInfo, - getAnalysisIfAvailable(), PSI, BFI); + getAnalysisIfAvailable(), PSI, BFI, + FnVarLocs); FuncInfo->set(Fn, *MF, CurDAG); SwiftError->setFunction(*MF); @@ -1323,56 +1334,75 @@ !FuncInfo.isExportedInst(I); // Exported instrs must be computed. } +static void processDbgDeclare(FunctionLoweringInfo &FuncInfo, + const Value *Address, DIExpression *Expr, + DILocalVariable *Var, DebugLoc DbgLoc) { + MachineFunction *MF = FuncInfo.MF; + const DataLayout &DL = MF->getDataLayout(); + + assert(Var && "Missing variable"); + assert(DbgLoc && "Missing location"); + + // Look through casts and constant offset GEPs. These mostly come from + // inalloca. + APInt Offset(DL.getTypeSizeInBits(Address->getType()), 0); + Address = Address->stripAndAccumulateInBoundsConstantOffsets(DL, Offset); + + // Check if the variable is a static alloca or a byval or inalloca + // argument passed in memory. If it is not, then we will ignore this + // intrinsic and handle this during isel like dbg.value. + int FI = std::numeric_limits::max(); + if (const auto *AI = dyn_cast(Address)) { + auto SI = FuncInfo.StaticAllocaMap.find(AI); + if (SI != FuncInfo.StaticAllocaMap.end()) + FI = SI->second; + } else if (const auto *Arg = dyn_cast(Address)) + FI = FuncInfo.getArgumentFrameIndex(Arg); + + if (FI == std::numeric_limits::max()) + return; + + if (Offset.getBoolValue()) + Expr = DIExpression::prepend(Expr, DIExpression::ApplyOffset, + Offset.getZExtValue()); + + LLVM_DEBUG(dbgs() << "processDbgDeclares: setVariableDbgInfo Var=" << *Var + << ", Expr=" << *Expr << ", FI=" << FI + << ", DbgLoc=" << DbgLoc << "\n"); + MF->setVariableDbgInfo(Var, Expr, FI, DbgLoc); +} + /// Collect llvm.dbg.declare information. This is done after argument lowering /// in case the declarations refer to arguments. static void processDbgDeclares(FunctionLoweringInfo &FuncInfo) { - MachineFunction *MF = FuncInfo.MF; - const DataLayout &DL = MF->getDataLayout(); for (const BasicBlock &BB : *FuncInfo.Fn) { for (const Instruction &I : BB) { - const DbgDeclareInst *DI = dyn_cast(&I); - if (!DI) - continue; - - assert(DI->getVariable() && "Missing variable"); - assert(DI->getDebugLoc() && "Missing location"); - const Value *Address = DI->getAddress(); - if (!Address) { - LLVM_DEBUG(dbgs() << "processDbgDeclares skipping " << *DI - << " (bad address)\n"); - continue; + if (const DbgDeclareInst *DI = dyn_cast(&I)) { + Value *Address = DI->getAddress(); + if (!Address) { + LLVM_DEBUG(dbgs() << "processDbgDeclares skipping " << *DI + << " (bad address)\n"); + return; + } + processDbgDeclare(FuncInfo, Address, DI->getExpression(), + DI->getVariable(), DI->getDebugLoc()); } - - // Look through casts and constant offset GEPs. These mostly come from - // inalloca. - APInt Offset(DL.getTypeSizeInBits(Address->getType()), 0); - Address = Address->stripAndAccumulateInBoundsConstantOffsets(DL, Offset); - - // Check if the variable is a static alloca or a byval or inalloca - // argument passed in memory. If it is not, then we will ignore this - // intrinsic and handle this during isel like dbg.value. - int FI = std::numeric_limits::max(); - if (const auto *AI = dyn_cast(Address)) { - auto SI = FuncInfo.StaticAllocaMap.find(AI); - if (SI != FuncInfo.StaticAllocaMap.end()) - FI = SI->second; - } else if (const auto *Arg = dyn_cast(Address)) - FI = FuncInfo.getArgumentFrameIndex(Arg); - - if (FI == std::numeric_limits::max()) - continue; - - DIExpression *Expr = DI->getExpression(); - if (Offset.getBoolValue()) - Expr = DIExpression::prepend(Expr, DIExpression::ApplyOffset, - Offset.getZExtValue()); - LLVM_DEBUG(dbgs() << "processDbgDeclares: setVariableDbgInfo FI=" << FI - << ", " << *DI << "\n"); - MF->setVariableDbgInfo(DI->getVariable(), Expr, FI, DI->getDebugLoc()); } } } +/// Collect single location variable information generated with assignment +/// tracking. This is done after argument lowering in case the declarations +/// refer to arguments. +static void processSingleLocVars(FunctionLoweringInfo &FuncInfo, + FunctionVarLocs const *FnVarLocs) { + for (auto It = FnVarLocs->single_locs_begin(), + End = FnVarLocs->single_locs_end(); + It != End; ++It) + processDbgDeclare(FuncInfo, It->V, It->Expr, + FnVarLocs->getDILocalVariable(It->VariableID), It->DL); +} + void SelectionDAGISel::SelectAllBasicBlocks(const Function &Fn) { FastISelFailed = false; // Initialize the Fast-ISel state, if needed. @@ -1433,7 +1463,13 @@ if (FastIS && Inserted) FastIS->setLastLocalValue(&*std::prev(FuncInfo->InsertPt)); - processDbgDeclares(*FuncInfo); + if (getEnableAssignmentTracking()) { + assert(CurDAG->getFunctionVarLocs() && + "expected AssignmentTrackingAnalysis pass results"); + processSingleLocVars(*FuncInfo, CurDAG->getFunctionVarLocs()); + } else { + processDbgDeclares(*FuncInfo); + } // Iterate over all basic blocks in the function. StackProtector &SP = getAnalysis();