@@ -771,6 +771,17 @@ class DeadObjectElimination : public SILFunctionTransform {
771771 DominanceInfo *domInfo = nullptr ;
772772
773773 void removeInstructions (ArrayRef<SILInstruction*> toRemove);
774+
775+ // / Try to salvage the debug info for a dead instruction removed by
776+ // / DeadObjectElimination.
777+ // /
778+ // / Dead stores will be replaced by a debug value for the object variable,
779+ // / using a fragment expression. By walking from the store to the allocation,
780+ // / we can know which member of the object is being assigned, and create
781+ // / fragments for each member. Other instructions are not salvaged.
782+ // / Currently only supports dead stack-allocated objects.
783+ void salvageDebugInfo (SILInstruction *toBeRemoved);
784+ std::optional<SILDebugVariable> buildDIExpression (SILInstruction *current);
774785
775786 bool processAllocRef (AllocRefInstBase *ARI);
776787 bool processAllocStack (AllocStackInst *ASI);
@@ -833,6 +844,52 @@ DeadObjectElimination::removeInstructions(ArrayRef<SILInstruction*> toRemove) {
833844 }
834845}
835846
847+ void DeadObjectElimination::salvageDebugInfo (SILInstruction *toBeRemoved) {
848+ auto *SI = dyn_cast<StoreInst>(toBeRemoved);
849+ if (!SI)
850+ return ;
851+
852+ auto *parent = SI->getDest ()->getDefiningInstruction ();
853+ auto varInfo = buildDIExpression (parent);
854+ if (!varInfo)
855+ return ;
856+
857+ SILBuilderWithScope Builder (SI);
858+ Builder.createDebugValue (SI->getLoc (), SI->getSrc (), *varInfo);
859+ }
860+
861+ std::optional<SILDebugVariable>
862+ DeadObjectElimination::buildDIExpression (SILInstruction *current) {
863+ if (!current)
864+ return {};
865+ if (auto dvci = dyn_cast<AllocStackInst>(current)) {
866+ auto var = dvci->getVarInfo ();
867+ if (!var)
868+ return {};
869+ var->Type = dvci->getType ();
870+ return var;
871+ }
872+ if (auto *tupleAddr = dyn_cast<TupleElementAddrInst>(current)) {
873+ auto *definer = tupleAddr->getOperand ().getDefiningInstruction ();
874+ auto path = buildDIExpression (definer);
875+ if (!path)
876+ return {};
877+ path->DIExpr .append (SILDebugInfoExpression::createTupleFragment (
878+ tupleAddr->getTupleType (), tupleAddr->getFieldIndex ()));
879+ return path;
880+ }
881+ if (auto *structAddr = dyn_cast<StructElementAddrInst>(current)) {
882+ auto *definer = structAddr->getOperand ().getDefiningInstruction ();
883+ auto path = buildDIExpression (definer);
884+ if (!path)
885+ return {};
886+ path->DIExpr .append (SILDebugInfoExpression::createFragment (
887+ structAddr->getField ()));
888+ return path;
889+ }
890+ return {};
891+ }
892+
836893bool DeadObjectElimination::processAllocRef (AllocRefInstBase *ARI) {
837894 // Ok, we have an alloc_ref. Check the cache to see if we have already
838895 // computed the destructor behavior for its SILType.
@@ -957,6 +1014,8 @@ bool DeadObjectElimination::processAllocStack(AllocStackInst *ASI) {
9571014 }
9581015 }
9591016
1017+ for (auto *I : UsersToRemove)
1018+ salvageDebugInfo (I);
9601019 // Remove the AllocRef and all of its users.
9611020 removeInstructions (
9621021 ArrayRef<SILInstruction*>(UsersToRemove.begin (), UsersToRemove.end ()));
0 commit comments