6868#include " llvm/Support/CommandLine.h"
6969#include " llvm/Support/FileSystem.h"
7070#include " llvm/Support/Process.h"
71- #include " swift/SIL/SILValue.h"
71+ #include " swift/Basic/SourceManager.h"
72+ #include " swift/SIL/DebugUtils.h"
7273#include " swift/SIL/SILVisitor.h"
7374#include " swift/SILOptimizer/Analysis/Analysis.h"
7475#include " swift/SILOptimizer/PassManager/PassManager.h"
@@ -186,6 +187,11 @@ llvm::cl::opt<bool> SILStatsFunctions(
186187 " sil-stats-functions" , llvm::cl::init(false ),
187188 llvm::cl::desc(" Enable computation of statistics for SIL functions" ));
188189
190+ // / Dump statistics about lost debug variables.
191+ llvm::cl::opt<bool > SILStatsLostVariables (
192+ " sil-stats-lost-variables" , llvm::cl::init(false ),
193+ llvm::cl::desc(" Dump lost debug variables stats" ));
194+
189195// / The name of the output file for optimizer counters.
190196llvm::cl::opt<std::string> SILStatsOutputFile (
191197 " sil-stats-output-file" , llvm::cl::init(" " ),
@@ -272,16 +278,28 @@ struct FunctionStat {
272278 // / Instruction counts per SILInstruction kind.
273279 InstructionCounts InstCounts;
274280
281+ using VarID = std::tuple<const SILDebugScope *, llvm::StringRef,
282+ unsigned , unsigned >;
283+ llvm::StringSet<> VarNames;
284+ llvm::DenseSet<FunctionStat::VarID> DebugVariables;
285+
275286 FunctionStat (SILFunction *F);
276287 FunctionStat () {}
277288
289+ // The DebugVariables set contains pointers to VarNames. Disallow copy.
290+ FunctionStat (const FunctionStat &) = delete ;
291+ FunctionStat (FunctionStat &&) = default ;
292+ FunctionStat &operator =(const FunctionStat &) = delete ;
293+ FunctionStat &operator =(FunctionStat &&) = default ;
294+
278295 void print (llvm::raw_ostream &stream) const {
279296 stream << " FunctionStat("
280297 << " blocks = " << BlockCount << " , Inst = " << InstCount << " )\n " ;
281298 }
282299
283300 bool operator ==(const FunctionStat &rhs) const {
284- return BlockCount == rhs.BlockCount && InstCount == rhs.InstCount ;
301+ return BlockCount == rhs.BlockCount && InstCount == rhs.InstCount
302+ && DebugVariables == rhs.DebugVariables ;
285303 }
286304
287305 bool operator !=(const FunctionStat &rhs) const { return !(*this == rhs); }
@@ -360,14 +378,20 @@ struct ModuleStat {
360378 bool operator !=(const ModuleStat &rhs) const { return !(*this == rhs); }
361379};
362380
363- // A helper type to collect the stats about the number of instructions and basic
364- // blocks .
381+ // / A helper type to collect the stats about a function ( instructions, blocks,
382+ // / debug variables) .
365383struct InstCountVisitor : SILInstructionVisitor<InstCountVisitor> {
366384 int BlockCount = 0 ;
367385 int InstCount = 0 ;
368386 InstructionCounts &InstCounts;
369387
370- InstCountVisitor (InstructionCounts &InstCounts) : InstCounts(InstCounts) {}
388+ llvm::StringSet<> &VarNames;
389+ llvm::DenseSet<FunctionStat::VarID> &DebugVariables;
390+
391+ InstCountVisitor (InstructionCounts &InstCounts,
392+ llvm::StringSet<> &VarNames,
393+ llvm::DenseSet<FunctionStat::VarID> &DebugVariables)
394+ : InstCounts(InstCounts), VarNames(VarNames), DebugVariables(DebugVariables) {}
371395
372396 int getBlockCount () const {
373397 return BlockCount;
@@ -385,6 +409,29 @@ struct InstCountVisitor : SILInstructionVisitor<InstCountVisitor> {
385409 void visit (SILInstruction *I) {
386410 ++InstCount;
387411 ++InstCounts[I->getKind ()];
412+
413+ if (!SILStatsLostVariables)
414+ return ;
415+ // Check the debug variable.
416+ DebugVarCarryingInst inst (I);
417+ if (!inst)
418+ return ;
419+ std::optional<SILDebugVariable> varInfo = inst.getVarInfo ();
420+ if (!varInfo)
421+ return ;
422+
423+ llvm::StringRef UniqueName = VarNames.insert (varInfo->Name ).first ->getKey ();
424+ if (!varInfo->Loc )
425+ varInfo->Loc = inst->getLoc ();
426+ unsigned line = 0 , col = 0 ;
427+ if (varInfo->Loc && varInfo->Loc ->getSourceLoc ().isValid ()) {
428+ std::tie (line, col) = inst->getModule ().getSourceManager ()
429+ .getPresumedLineAndColumnForLoc (varInfo->Loc ->getSourceLoc (), 0 );
430+ }
431+ FunctionStat::VarID key (
432+ varInfo->Scope ? varInfo->Scope : inst->getDebugScope (),
433+ UniqueName, line, col);
434+ DebugVariables.insert (key);
388435 }
389436};
390437
@@ -549,7 +596,7 @@ class NewLineInserter {
549596std::unique_ptr<llvm::raw_ostream, void (*)(llvm::raw_ostream *)>
550597 stats_output_stream = {nullptr , nullptr };
551598
552- // / Return the output streamm to be used for logging the collected statistics.
599+ // / Return the output stream to be used for logging the collected statistics.
553600llvm::raw_ostream &stats_os () {
554601 // Initialize the stream if it is not initialized yet.
555602 if (!stats_output_stream) {
@@ -664,6 +711,18 @@ bool isFirstTimeData(int Old, int New) {
664711 return Old == 0 && New != Old;
665712}
666713
714+ int computeLostVariables (llvm::DenseSet<FunctionStat::VarID> &Old,
715+ llvm::DenseSet<FunctionStat::VarID> &New) {
716+ unsigned count = 0 ;
717+ for (auto &var : Old) {
718+ if (New.contains (var))
719+ continue ;
720+ // llvm::dbgs() << "Lost variable: " << std::get<1>(var) << "\n";
721+ count++;
722+ }
723+ return count;
724+ }
725+
667726// / Dump statistics for a SILFunction. It is only used if a user asked to
668727// / produce detailed stats about transformations of SILFunctions. This
669728// / information is dumped unconditionally, for each transformation that changed
@@ -710,7 +769,7 @@ void processFuncStatsChanges(SILFunction *F, FunctionStat &OldStat,
710769 TransformationContext &Ctx) {
711770 processFuncStatHistory (F, NewStat, Ctx);
712771
713- if (!SILStatsFunctions && !SILStatsDumpAll)
772+ if (!SILStatsFunctions && !SILStatsLostVariables && ! SILStatsDumpAll)
714773 return ;
715774
716775 if (OldStat == NewStat)
@@ -724,6 +783,8 @@ void processFuncStatsChanges(SILFunction *F, FunctionStat &OldStat,
724783 // Compute deltas.
725784 double DeltaBlockCount = computeDelta (OldStat.BlockCount , NewStat.BlockCount );
726785 double DeltaInstCount = computeDelta (OldStat.InstCount , NewStat.InstCount );
786+ int LostVariables = computeLostVariables (OldStat.DebugVariables ,
787+ NewStat.DebugVariables );
727788
728789 NewLineInserter nl;
729790
@@ -744,6 +805,11 @@ void processFuncStatsChanges(SILFunction *F, FunctionStat &OldStat,
744805 printCounterChange (" function" , " inst" , DeltaInstCount, OldStat.InstCount ,
745806 NewStat.InstCount , Ctx, F->getName ());
746807 }
808+
809+ if ((SILStatsDumpAll || SILStatsLostVariables) && LostVariables) {
810+ stats_os () << nl.get ();
811+ printCounterValue (" function" , " lostvars" , LostVariables, F->getName (), Ctx);
812+ }
747813}
748814
749815// / Process SILModule's statistics changes.
@@ -867,10 +933,10 @@ void OptimizerStatsAnalysis::updateModuleStats(TransformationContext &Ctx) {
867933 auto &FuncStat = getFunctionStat (&F);
868934 FunctionStat NewFuncStat (&F);
869935 processFuncStatHistory (&F, NewFuncStat, Ctx);
870- // Update function stats.
871- FuncStat = NewFuncStat;
872936 // Update module stats.
873937 NewModStat.addFunctionStat (NewFuncStat);
938+ // Update function stats.
939+ FuncStat = std::move (NewFuncStat);
874940 }
875941 } else {
876942 // Go only over functions that were changed since the last computation.
@@ -893,20 +959,20 @@ void OptimizerStatsAnalysis::updateModuleStats(TransformationContext &Ctx) {
893959 auto *F = InvalidatedFuncs.back ();
894960 InvalidatedFuncs.pop_back ();
895961 auto &FuncStat = getFunctionStat (F);
896- auto OldFuncStat = FuncStat;
962+ auto & OldFuncStat = FuncStat;
897963 FunctionStat NewFuncStat (F);
898964 processFuncStatsChanges (F, OldFuncStat, NewFuncStat, Ctx);
899965 NewModStat.subFunctionStat (OldFuncStat);
900966 NewModStat.addFunctionStat (NewFuncStat);
901- FuncStat = NewFuncStat;
967+ FuncStat = std::move ( NewFuncStat) ;
902968 }
903969
904970 // Process deleted functions.
905971 while (!DeletedFuncs.empty ()) {
906972 auto *F = DeletedFuncs.back ();
907973 DeletedFuncs.pop_back ();
908974 auto &FuncStat = getFunctionStat (F);
909- auto OldFuncStat = FuncStat;
975+ auto & OldFuncStat = FuncStat;
910976 FunctionStat NewFuncStat;
911977 processFuncStatsChanges (F, OldFuncStat, NewFuncStat, Ctx);
912978 NewModStat.subFunctionStat (OldFuncStat);
@@ -922,7 +988,7 @@ void OptimizerStatsAnalysis::updateModuleStats(TransformationContext &Ctx) {
922988 FunctionStat NewFuncStat (F);
923989 processFuncStatsChanges (F, OldFuncStat, NewFuncStat, Ctx);
924990 NewModStat.addFunctionStat (NewFuncStat);
925- FuncStat = NewFuncStat;
991+ FuncStat = std::move ( NewFuncStat) ;
926992 }
927993 }
928994
@@ -939,7 +1005,7 @@ void OptimizerStatsAnalysis::updateModuleStats(TransformationContext &Ctx) {
9391005}
9401006
9411007FunctionStat::FunctionStat (SILFunction *F) {
942- InstCountVisitor V (InstCounts);
1008+ InstCountVisitor V (InstCounts, VarNames, DebugVariables );
9431009 V.visitSILFunction (F);
9441010 BlockCount = V.getBlockCount ();
9451011 InstCount = V.getInstCount ();
@@ -957,7 +1023,8 @@ void swift::updateSILModuleStatsAfterTransform(SILModule &M,
9571023 SILTransform *Transform,
9581024 SILPassManager &PM,
9591025 int PassNumber, int Duration) {
960- if (!SILStatsModules && !SILStatsFunctions && !SILStatsDumpAll)
1026+ if (!SILStatsModules && !SILStatsFunctions && !SILStatsLostVariables
1027+ && !SILStatsDumpAll)
9611028 return ;
9621029 TransformationContext Ctx (M, PM, Transform, PassNumber, Duration);
9631030 OptimizerStatsAnalysis *Stats = PM.getAnalysis <OptimizerStatsAnalysis>();
0 commit comments