@@ -771,6 +771,17 @@ class DeadObjectElimination : public SILFunctionTransform {
771
771
DominanceInfo *domInfo = nullptr ;
772
772
773
773
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);
774
785
775
786
bool processAllocRef (AllocRefInstBase *ARI);
776
787
bool processAllocStack (AllocStackInst *ASI);
@@ -833,6 +844,52 @@ DeadObjectElimination::removeInstructions(ArrayRef<SILInstruction*> toRemove) {
833
844
}
834
845
}
835
846
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
+
836
893
bool DeadObjectElimination::processAllocRef (AllocRefInstBase *ARI) {
837
894
// Ok, we have an alloc_ref. Check the cache to see if we have already
838
895
// computed the destructor behavior for its SILType.
@@ -957,6 +1014,8 @@ bool DeadObjectElimination::processAllocStack(AllocStackInst *ASI) {
957
1014
}
958
1015
}
959
1016
1017
+ for (auto *I : UsersToRemove)
1018
+ salvageDebugInfo (I);
960
1019
// Remove the AllocRef and all of its users.
961
1020
removeInstructions (
962
1021
ArrayRef<SILInstruction*>(UsersToRemove.begin (), UsersToRemove.end ()));
0 commit comments