diff --git a/llvm/include/llvm/Analysis/ScalarEvolution.h b/llvm/include/llvm/Analysis/ScalarEvolution.h --- a/llvm/include/llvm/Analysis/ScalarEvolution.h +++ b/llvm/include/llvm/Analysis/ScalarEvolution.h @@ -1769,7 +1769,9 @@ /// frugal here since we just bail out of actually constructing and /// canonicalizing an expression in the cases where the result isn't going /// to be a constant. +public: Optional computeConstantDifference(const SCEV *LHS, const SCEV *RHS); +private: /// Drop memoized information computed for S. void forgetMemoizedResults(const SCEV *S); diff --git a/llvm/lib/Transforms/Scalar/LoopStrengthReduce.cpp b/llvm/lib/Transforms/Scalar/LoopStrengthReduce.cpp --- a/llvm/lib/Transforms/Scalar/LoopStrengthReduce.cpp +++ b/llvm/lib/Transforms/Scalar/LoopStrengthReduce.cpp @@ -59,6 +59,7 @@ #include "llvm/ADT/Hashing.h" #include "llvm/ADT/PointerIntPair.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SetOperations.h" #include "llvm/ADT/SetVector.h" #include "llvm/ADT/SmallBitVector.h" #include "llvm/ADT/SmallPtrSet.h" @@ -81,6 +82,7 @@ #include "llvm/IR/BasicBlock.h" #include "llvm/IR/Constant.h" #include "llvm/IR/Constants.h" +#include "llvm/IR/DebugInfoMetadata.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/Dominators.h" #include "llvm/IR/GlobalValue.h" @@ -5801,6 +5803,44 @@ AU.addPreserved(); } +bool collectCyclicDead(Value *V, PHINode *PHI, + DenseSet &MaybeDead) { + Instruction *I = dyn_cast(V); + if (!I) + return false; + // 1. Make sure that I has no side effects and that all succs of I are + // either MaybeDead or debug-uses. + if (I->mayWriteToMemory()) + return false; + + for (auto UseOfI_ : I->users()) { + auto UseOfI = dyn_cast(UseOfI_); + if (MaybeDead.count(UseOfI)) + continue; + if (isa(UseOfI)) + continue; + // I has a live non-debug use. + return false; + } + + // 2. If we found PHI (and it has no live uses) we are done. Also don't go + // past different phi-node. + if (isa(I)) + return (I == PHI); + + // 3. Add I to MaybeDead. + MaybeDead.insert(I); + + // 4. Foreach pred of MI call recursively. + bool ReachedPhi = false; + for (auto &OpOfI : I->operands()) { + if (isa(OpOfI)) { + ReachedPhi |= collectCyclicDead(OpOfI, PHI, MaybeDead); + } + } + return ReachedPhi; +} + static bool ReduceLoopStrength(Loop *L, IVUsers &IU, ScalarEvolution &SE, DominatorTree &DT, LoopInfo &LI, const TargetTransformInfo &TTI, @@ -5812,10 +5852,65 @@ if (MSSA) MSSAU = std::make_unique(MSSA); + DenseSet OldPHIs, NewPHIs; + for (PHINode &PN : L->getHeader()->phis()) + OldPHIs.insert(&PN); + // Run the main LSR transformation. Changed |= LSRInstance(L, IU, SE, DT, LI, TTI, AC, TLI, MSSAU.get()).getChanged(); + // Perform extra SCEV based debug info salvaging. + // This algorithm operates in three steps: + // 1. Find which new 'lsr' PHI-nodes were introduced as a result of calling + // LSRInstance above. + // 2. Find which llvm.dbg.value instructions need to be updated. This means + // we need to find out which instructions are now dead and record their + // llvm.dbg.value uses if any. + // 3. For each such llvm.dbg.value compute the SCEV of its variable reference + // and compare it to the SCEV of any of the new PHI-nodes and if they match + // do a replace. Matching with a constant offset is also allowed in which + // case we compensate for the offset in the DIExpression. + + for (PHINode &PN : L->getHeader()->phis()) + NewPHIs.insert(&PN); + + NewPHIs = set_difference(NewPHIs, OldPHIs); + + SmallVector DbgValuesToUpdate; + for (PHINode &PN : L->getHeader()->phis()) { + DenseSet MaybeDead; + MaybeDead.insert(&PN); + if (collectCyclicDead(PN.getIncomingValueForBlock(L->getHeader()), &PN, + MaybeDead)) { + for (auto D : MaybeDead) + findDbgValues(DbgValuesToUpdate, D); + } + } + + dbgs() << "The following llvm.dbg.value needs to be updated:\n"; + for (auto D : DbgValuesToUpdate) { + auto DUS = SE.getSCEV(D->getVariableLocation()); + dbgs() << " " << *DUS << " :" << *D << "\n"; + for (auto NPN : NewPHIs) { + auto NPNS = SE.getSCEV(NPN); + dbgs() << " " << *NPNS << " :" << *NPN << "\n"; + Optional Offset = SE.computeConstantDifference(DUS, NPNS); + if (Offset) { + dbgs() << " Match with offset " << Offset << "\n"; + D->setOperand(0, MetadataAsValue::get(NPN->getContext(), + ValueAsMetadata::get(NPN))); + if (Offset.getValue().getSExtValue()) { + SmallVector Ops; + DIExpression::appendOffset(Ops, Offset.getValue().getSExtValue()); + auto DIExpr = + DIExpression::prependOpcodes(D->getExpression(), Ops, true); + D->setOperand(2, MetadataAsValue::get(NPN->getContext(), DIExpr)); + } + } + } + } + // Remove any extra phis created by processing inner loops. Changed |= DeleteDeadPHIs(L->getHeader(), &TLI, MSSAU.get()); if (EnablePhiElim && L->isLoopSimplifyForm()) {