Skip to content

Commit f0f8e9b

Browse files
Merge pull request #73398 from Snowy1803/6.0-lost-vars-stats-onone
[6.0] Lost variables statistics + Fix -Onone
2 parents 1233992 + af71a36 commit f0f8e9b

11 files changed

+245
-50
lines changed

docs/DebuggingTheCompiler.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,7 @@ If one builds swift using ninja and wants to dump the SIL of the
260260
stdlib using some of the SIL dumping options from the previous
261261
section, one can use the following one-liner:
262262

263-
ninja -t commands | grep swiftc | grep Swift.o | grep " -c "
263+
ninja -t commands | grep swiftc | grep 'Swift\.o'
264264

265265
This should give one a single command line that one can use for
266266
Swift.o, perfect for applying the previous sections options to.
@@ -302,6 +302,13 @@ with the proper attributes to ensure they'll be available in the debugger. In
302302
particular, if you see `SWIFT_DEBUG_DUMP` in a class declaration, that class
303303
has a `dump()` method you can call.
304304

305+
### Pass statistics
306+
307+
There are options to output a lot of different statistics, including about
308+
SIL passes. More information is available in
309+
[Compiler Performance](CompilerPerformance.md) for the unified statistics, and
310+
[Optimizer Counter Analysis](OptimizerCountersAnalysis.md) for pass counters.
311+
305312
## Debugging and Profiling on SIL level
306313

307314
### SIL source level profiling

docs/HowToUpdateDebugInfo.md

Lines changed: 39 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@ merge drop and copy locations, since all the same considerations apply. Helpers
1616
like `SILBuilderWithScope` make it easy to copy source locations when expanding
1717
SIL instructions.
1818

19+
> [!Warning]
20+
> Don't use `SILBuilderWithScope` when replacing a single instruction of type
21+
> `AllocStackInst` or `DebugValueInst`. These meta instructions are skipped,
22+
> so the wrong scope will be inferred.
23+
1924
## Variables
2025

2126
Each `debug_value` (and variable-carrying instruction) defines an update point
@@ -254,12 +259,37 @@ debug_value %1 : $Int, var, name "pair", type $Pair, expr op_fragment:#Pair.a //
254259
```
255260

256261
## Rules of thumb
257-
- Optimization passes may never drop a variable entirely. If a variable is
258-
entirely optimized away, an `undef` debug value should still be kept.
259-
- A `debug_value` must always describe a correct value for that source variable
260-
at that source location. If a value is only correct on some paths through that
261-
instruction, it must be replaced with `undef`. Debug info never speculates.
262-
- When a SIL instruction is deleted, call salvageDebugInfo(). It will try to
263-
capture the effect of the deleted instruction in a debug expression, so the
264-
location can be preserved. You can also use an `InstructionDeleter` which will
265-
automatically call `salvageDebugInfo`.
262+
263+
### Correctness
264+
A `debug_value` must always describe a correct value for that source variable
265+
at that source location. If a value is only correct on some paths through that
266+
instruction, it must be replaced with `undef`. Debug info never speculates.
267+
268+
### Don't drop debug info
269+
270+
Optimization passes may never drop a variable entirely. If a variable is
271+
entirely optimized away, an `undef` debug value should still be kept. The only
272+
exception is when the variable is in an unreachable function or scope, where it
273+
can be removed with the rest of the instructions.
274+
275+
### Instruction Deletion
276+
277+
When a SIL instruction is deleted, call `salvageDebugInfo`. It will try to
278+
capture the effect of the deleted instruction in a debug expression, so the
279+
location can be preserved.
280+
281+
Alternatively, you can use an `InstructionDeleter`, which will automatically
282+
call `salvageDebugInfo`.
283+
284+
If the debug info cannot be salvaged by `salvageDebugInfo`, and the pass has a
285+
special knowledge of the value, the pass can directly replace the debug value
286+
with the known value.
287+
288+
If an instruction is being replaced by another, use `replaceAllUsesWith`. It
289+
will also update debug values to use the new instruction.
290+
291+
> [!Tip]
292+
> To detect when a pass drops a variable, you can use the
293+
> `-Xllvm -sil-stats-lost-variables` to print when a variable is lost by a pass.
294+
> More information about this option is available in
295+
> [Optimizer Counter Analysis](OptimizerCountersAnalysis.md)

docs/OptimizerCountersAnalysis.md

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,8 @@ The following statistics can be recorded:
5454

5555
* For SILFunctions: the number of SIL basic blocks for each SILFunction, the
5656
number of SIL instructions, the number of SILInstructions of a specific
57-
kind (e.g. a number of alloc_ref instructions)
57+
kind (e.g. a number of alloc_ref instructions), the number of debug
58+
variables
5859

5960
* For SILModules: the number of SIL basic blocks in the SILModule, the number
6061
of SIL instructions, the number of SILFunctions, the number of
@@ -118,6 +119,16 @@ e.g. `-Xllvm -sil-stats-only-instructions=alloc_ref,alloc_stack`. If you need to
118119
collect stats about all kinds of SIL instructions, you can use this syntax:
119120
`-Xllvm -sil-stats-only-instructions=all`.
120121

122+
### Debug variable level counters
123+
A different type of counter is the lost debug variables counter. It is enabled
124+
by using the `-Xllvm -sil-stats-lost-variables` command-line option. It only
125+
tracks statistics about lost variables in SILFunctions. It is not enabled by
126+
any other command-line option, but can be combined with the others. It is not
127+
compatible with thresholds, it always counts lost variables. Note that it does
128+
not track the number of debug variables: it counts the number of debug variables
129+
that were present, but aren't anymore. If a variable changes location or scope,
130+
which is not allowed, it will be counted as lost.
131+
121132
## Configuring which counters changes should be recorded
122133

123134
The user has a possibility to configure a number of thresholds, which control
@@ -181,9 +192,9 @@ And for counter stats it looks like this:
181192
* `function_history` corresponds to the verbose mode of function
182193
counters collection, when changes to the SILFunction counters are logged
183194
unconditionally, without any on-line filtering.
184-
* `CounterName` is typically one of `block`, `inst`, `function`, `memory`,
185-
or `inst_instruction_name` if you collect counters for specific kinds of SIL
186-
instructions.
195+
* `CounterName` is typically one of `block`, `inst`, `function`, `memory`,
196+
`lostvars`, or `inst_instruction_name` if you collect counters for specific
197+
kinds of SIL instructions.
187198
* `Symbol` is e.g. the name of a function
188199
* `StageName` is the name of the current optimizer pipeline stage
189200
* `TransformName` is the name of the current optimizer transformation/pass
@@ -192,6 +203,14 @@ And for counter stats it looks like this:
192203
want to reproduce the result later using
193204
`-Xllvm -sil-opt-pass-count -Xllvm TransformPassNumber`
194205

206+
## Extract Lost Variables per Pass
207+
208+
For lost variables, there is a script to output a CSV with only the amount of
209+
lost variables per pass. You can then easily open the resulting CSV in Numbers
210+
to make graphs.
211+
212+
`utils/process-stats-lost-variables csv_file_with_counters > csv_aggregate`
213+
195214
## Storing the produced statistics into a database
196215

197216
To store the set of produced counters into a database, you can use the
@@ -345,4 +364,3 @@ from Counters C where C.counter = 'inst' and C.kind = 'module'
345364
group by Stage
346365
order by sum(C.Delta);
347366
```
348-

lib/IRGen/AllocStackHoisting.cpp

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -157,9 +157,8 @@ void moveAllocStackToBeginningOfBlock(
157157
// of the debug_value to the original position.
158158
if (haveMovedElt) {
159159
if (auto varInfo = AS->getVarInfo()) {
160-
SILBuilderWithScope Builder(AS);
161160
// SILBuilderWithScope skips over meta instructions when picking a scope.
162-
Builder.setCurrentDebugScope(AS->getDebugScope());
161+
SILBuilder Builder(AS, AS->getDebugScope());
163162
auto *DVI = Builder.createDebugValue(AS->getLoc(), AS, *varInfo);
164163
DVI->setUsesMoveableValueDebugInfo();
165164
DebugValueToBreakBlocksAt.push_back(DVI);
@@ -198,14 +197,14 @@ void Partition::assignStackLocation(
198197
if (AssignedLoc == AllocStack) continue;
199198
eraseDeallocStacks(AllocStack);
200199
AllocStack->replaceAllUsesWith(AssignedLoc);
201-
if (hasAtLeastOneMovedElt) {
202-
if (auto VarInfo = AllocStack->getVarInfo()) {
203-
SILBuilderWithScope Builder(AllocStack);
204-
auto *DVI = Builder.createDebugValue(AllocStack->getLoc(), AssignedLoc,
205-
*VarInfo);
200+
if (auto VarInfo = AllocStack->getVarInfo()) {
201+
SILBuilder Builder(AllocStack, AllocStack->getDebugScope());
202+
auto *DVI = Builder.createDebugValueAddr(AllocStack->getLoc(),
203+
AssignedLoc, *VarInfo);
204+
if (hasAtLeastOneMovedElt) {
206205
DVI->setUsesMoveableValueDebugInfo();
207-
DebugValueToBreakBlocksAt.push_back(DVI);
208206
}
207+
DebugValueToBreakBlocksAt.push_back(DVI);
209208
}
210209
AllocStack->eraseFromParent();
211210
}

lib/IRGen/LoadableByAddress.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include "swift/SILOptimizer/Analysis/DeadEndBlocksAnalysis.h"
3434
#include "swift/SILOptimizer/PassManager/Transforms.h"
3535
#include "swift/SILOptimizer/Utils/BasicBlockOptUtils.h"
36+
#include "swift/SILOptimizer/Utils/DebugOptUtils.h"
3637
#include "swift/SILOptimizer/Utils/InstOptUtils.h"
3738
#include "swift/SILOptimizer/Utils/StackNesting.h"
3839
#include "llvm/ADT/MapVector.h"
@@ -1777,7 +1778,7 @@ static void rewriteUsesOfSscalar(StructLoweringState &pass,
17771778
createOutlinedCopyCall(copyBuilder, address, dest, pass);
17781779
storeUser->eraseFromParent();
17791780
} else if (auto *dbgInst = dyn_cast<DebugValueInst>(user)) {
1780-
SILBuilderWithScope dbgBuilder(dbgInst);
1781+
SILBuilder dbgBuilder(dbgInst, dbgInst->getDebugScope());
17811782
// Rewrite the debug_value to point to the variable in the alloca.
17821783
dbgBuilder.createDebugValueAddr(dbgInst->getLoc(), address,
17831784
*dbgInst->getVarInfo());
@@ -2150,9 +2151,8 @@ static void rewriteFunction(StructLoweringState &pass,
21502151
} else {
21512152
assert(currOperand->getType().isAddress() &&
21522153
"Expected an address type");
2153-
SILBuilderWithScope debugBuilder(instr);
21542154
// SILBuilderWithScope skips over metainstructions.
2155-
debugBuilder.setCurrentDebugScope(instr->getDebugScope());
2155+
SILBuilder debugBuilder(instr, instr->getDebugScope());
21562156
debugBuilder.createDebugValueAddr(instr->getLoc(), currOperand,
21572157
*instr->getVarInfo());
21582158
instr->getParent()->erase(instr);
@@ -3637,6 +3637,7 @@ class AssignAddressToDef : SILInstructionVisitor<AssignAddressToDef> {
36373637

36383638
builder.createCopyAddr(load->getLoc(), load->getOperand(), addr, IsTake,
36393639
IsInitialization);
3640+
swift::salvageLoadDebugInfo(load);
36403641
assignment.markForDeletion(load);
36413642
}
36423643

lib/SIL/IR/SILInstruction.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1475,9 +1475,8 @@ bool SILInstruction::mayTrap() const {
14751475
}
14761476

14771477
bool SILInstruction::isMetaInstruction() const {
1478-
// Every instruction that implements getVarInfo() should be in this list.
1478+
// Every instruction that doesn't generate code should be in this list.
14791479
switch (getKind()) {
1480-
case SILInstructionKind::AllocBoxInst:
14811480
case SILInstructionKind::AllocStackInst:
14821481
case SILInstructionKind::DebugValueInst:
14831482
return true;

0 commit comments

Comments
 (0)