1
1
# Debugging the compiler
2
2
[ debugging ] : #debugging
3
3
4
- Here are a few tips to debug the compiler:
4
+ This chapter contains a few tips to debug the compiler. These tips aim to be
5
+ useful no matter what you are working on. Some of the other chapters have
6
+ advice about specific parts of the compiler (e.g. the [ Queries Debugging and
7
+ Testing
8
+ chapter] ( ./incrcomp-debugging.html ) or
9
+ the [ LLVM Debugging chapter] ( ./codegen/debugging.md ) ).
10
+
11
+ ## ` -Z ` flags
12
+
13
+ The compiler has a bunch of ` -Z ` flags. These are unstable flags that are only
14
+ enabled on nightly. Many of them are useful for debugging. To get a full listing
15
+ of ` -Z ` flags, use ` -Z help ` .
16
+
17
+ One useful flag is ` -Z verbose ` , which generally enables printing more info that
18
+ could be useful for debugging.
5
19
6
20
## Getting a backtrace
7
21
[ getting-a-backtrace ] : #getting-a-backtrace
@@ -135,6 +149,9 @@ These crates are used in compiler for logging:
135
149
* [log]
136
150
* [env-logger]: check the link to see the full ` RUST_LOG` syntax
137
151
152
+ [log]: https://docs.rs/log/0.4.6/log/index.html
153
+ [env-logger]: https://docs.rs/env_logger/0.4.3/env_logger/
154
+
138
155
The compiler has a lot of ` debug! ` calls, which print out logging information
139
156
at many points. These are very useful to at least narrow down the location of
140
157
a bug if not to find it entirely, or just to orient yourself as to why the
@@ -189,17 +206,20 @@ I also think that in some cases just setting it will not trigger a rebuild,
189
206
so if you changed it and you already have a compiler built, you might
190
207
want to call `x.py clean` to force one.
191
208
192
- ### Logging etiquette
209
+ ### Logging etiquette and conventions
193
210
194
211
Because calls to `debug!` are removed by default, in most cases, don' t worry
195
212
about adding " unnecessary" calls to ` debug! ` and leaving them in code you
196
213
commit - they won' t slow down the performance of what we ship, and if they
197
214
helped you pinning down a bug, they will probably help someone else with a
198
215
different one.
199
216
200
- However, there are still a few concerns that you might care about:
217
+ A loosely followed convention is to use `debug!("foo(...)")` at the _start_ of
218
+ a function `foo` and `debug!("foo: ...")` _within_ the function. Another
219
+ loosely followed convention is to use the `{:?}` format specifier for debug
220
+ logs.
201
221
202
- ### Expensive operations in logs
222
+ One thing to be **careful** of is **expensive** operations in logs.
203
223
204
224
If in the module `rustc::foo` you have a statement
205
225
@@ -210,9 +230,9 @@ debug!("{:?}", random_operation(tcx));
210
230
Then if someone runs a debug `rustc` with `RUST_LOG=rustc::bar`, then
211
231
`random_operation()` will run.
212
232
213
- This means that you should not put anything too expensive or likely
214
- to crash there - that would annoy anyone who wants to use logging for their own
215
- module. No-one will know it until someone tries to use logging to find *another* bug.
233
+ This means that you should not put anything too expensive or likely to crash
234
+ there - that would annoy anyone who wants to use logging for their own module.
235
+ No-one will know it until someone tries to use logging to find *another* bug.
216
236
217
237
## Formatting Graphviz output (.dot files)
218
238
[formatting-graphviz-output]: #formatting-graphviz-output
@@ -229,133 +249,13 @@ $ dot -T pdf maybe_init_suffix.dot > maybe_init_suffix.pdf
229
249
$ firefox maybe_init_suffix.pdf # Or your favorite pdf viewer
230
250
```
231
251
232
- ## Debugging LLVM
233
- [debugging-llvm]: #debugging-llvm
234
-
235
- > NOTE: If you are looking for info about code generation, please see [this
236
- > chapter][codegen] instead.
237
-
238
- [codegen]: codegen.html
239
-
240
- This section is about debugging compiler bugs in code generation (e.g. why the
241
- compiler generated some piece of code or crashed in LLVM). LLVM is a big
242
- project on its own that probably needs to have its own debugging document (not
243
- that I could find one). But here are some tips that are important in a rustc
244
- context:
245
-
246
- As a general rule, compilers generate lots of information from analyzing code.
247
- Thus, a useful first step is usually to find a minimal example. One way to do
248
- this is to
249
-
250
- 1. create a new crate that reproduces the issue (e.g. adding whatever crate is
251
- at fault as a dependency, and using it from there)
252
-
253
- 2. minimize the crate by removing external dependencies; that is, moving
254
- everything relevant to the new crate
255
-
256
- 3. further minimize the issue by making the code shorter (there are tools that
257
- help with this like `creduce`)
258
-
259
- The official compilers (including nightlies) have LLVM assertions disabled,
260
- which means that LLVM assertion failures can show up as compiler crashes (not
261
- ICEs but "real" crashes) and other sorts of weird behavior. If you are
262
- encountering these, it is a good idea to try using a compiler with LLVM
263
- assertions enabled - either an "alt" nightly or a compiler you build yourself
264
- by setting `[llvm] assertions=true` in your config.toml - and see whether
265
- anything turns up.
266
-
267
- The rustc build process builds the LLVM tools into
268
- `./build/<host-triple>/llvm/bin`. They can be called directly.
269
-
270
- The default rustc compilation pipeline has multiple codegen units, which is
271
- hard to replicate manually and means that LLVM is called multiple times in
272
- parallel. If you can get away with it (i.e. if it doesn' t make your bug
273
- disappear), passing ` -C codegen-units=1` to rustc will make debugging easier.
274
-
275
- To rustc to generate LLVM IR, you need to pass the ` --emit=llvm-ir` flag. If
276
- you are building via cargo, use the ` RUSTFLAGS` environment variable (e.g.
277
- ` RUSTFLAGS=' --emit=llvm-ir' ` ). This causes rustc to spit out LLVM IR into the
278
- target directory.
279
-
280
- ` cargo llvm-ir [options] path` spits out the LLVM IR for a particular function
281
- at ` path` . (` cargo install cargo-asm` installs ` cargo asm` and ` cargo
282
- llvm-ir` ). ` --build-type=debug` emits code for debug builds. There are also
283
- other useful options. Also, debug info in LLVM IR can clutter the output a lot:
284
- ` RUSTFLAGS=" -C debuginfo=0" ` is really useful.
285
-
286
- ` RUSTFLAGS=" -C save-temps" ` outputs LLVM bitcode (not the same as IR) at
287
- different stages during compilation, which is sometimes useful. One just needs
288
- to convert the bitcode files to ` .ll` files using ` llvm-dis` which should be in
289
- the target local compilation of rustc.
290
-
291
- If you want to play with the optimization pipeline, you can use the ` opt` tool
292
- from ` ./build/< host-triple> /llvm/bin/` with the LLVM IR emitted by rustc. Note
293
- that rustc emits different IR depending on whether ` -O` is enabled, even
294
- without LLVM' s optimizations, so if you want to play with the IR rustc emits,
295
- you should:
296
-
297
- ```bash
298
- $ rustc +local my-file.rs --emit=llvm-ir -O -C no-prepopulate-passes \
299
- -C codegen-units=1
300
- $ OPT=./build/$TRIPLE/llvm/bin/opt
301
- $ $OPT -S -O2 < my-file.ll > my
302
- ```
303
-
304
- If you just want to get the LLVM IR during the LLVM pipeline, to e.g. see which
305
- IR causes an optimization-time assertion to fail, or to see when LLVM performs
306
- a particular optimization, you can pass the rustc flag `-C
307
- llvm-args=-print-after-all`, and possibly add `-C
308
- llvm-args=' -filter-print-funcs=EXACT_FUNCTION_NAME` (e.g. ` -C
309
- llvm-args=' -filter-print-funcs=_ZN11collections3str21_$LT$impl$u20$str$GT$\
310
- 7replace17hbe10ea2e7c809b0bE' ` ).
311
-
312
- That produces a lot of output into standard error, so you' ll want to pipe that
313
- to some file. Also, if you are using neither `-filter-print-funcs` nor `-C
314
- codegen-units=1`, then, because the multiple codegen units run in parallel, the
315
- printouts will mix together and you won' t be able to read anything.
316
-
317
- If you want just the IR for a specific function (say, you want to see why it
318
- causes an assertion or doesn' t optimize correctly), you can use `llvm-extract`,
319
- e.g.
320
-
321
- ```bash
322
- $ ./build/$TRIPLE/llvm/bin/llvm-extract \
323
- -func=' _ZN11collections3str21_$LT$impl$u20$str$GT $7 replace17hbe10ea2e7c809b0bE' \
324
- -S \
325
- < unextracted.ll \
326
- > extracted.ll
327
- ```
328
-
329
- ### Filing LLVM bug reports
330
-
331
- When filing an LLVM bug report, you will probably want some sort of minimal
332
- working example that demonstrates the problem. The Godbolt compiler explorer is
333
- really helpful for this.
334
-
335
- 1. Once you have some LLVM IR for the problematic code (see above), you can
336
- create a minimal working example with Godbolt. Go to
337
- [gcc.godbolt.org](https://gcc.godbolt.org).
338
-
339
- 2. Choose `LLVM-IR` as programming language.
340
-
341
- 3. Use `llc` to compile the IR to a particular target as is:
342
- - There are some useful flags: `-mattr` enables target features, `-march=`
343
- selects the target, `-mcpu=` selects the CPU, etc.
344
- - Commands like `llc -march=help` output all architectures available, which
345
- is useful because sometimes the Rust arch names and the LLVM names do not
346
- match.
347
- - If you have compiled rustc yourself somewhere, in the target directory
348
- you have binaries for `llc`, `opt`, etc.
349
-
350
- 4. If you want to optimize the LLVM-IR, you can use `opt` to see how the LLVM
351
- optimizations transform it.
352
-
353
- 5. Once you have a godbolt link demonstrating the issue, it is pretty easy to
354
- fill in an LLVM bug.
355
-
356
- [log]: https://docs.rs/log/0.4.6/log/index.html
357
- [env-logger]: https://docs.rs/env_logger/0.4.3/env_logger/
358
-
359
252
## Narrowing (Bisecting) Regressions
360
253
361
- The [cargo-bisect-rustc](https://github.com/rust-lang-nursery/cargo-bisect-rustc) tool can be used as a quick and easy way to find exactly which PR caused a change in `rustc` behavior. It automatically downloads `rustc` PR artifacts and tests them against a project you provide until it finds the regression. You can then look at the PR to get more context on *why* it was changed. See [this tutorial](https://github.com/rust-lang-nursery/cargo-bisect-rustc/blob/master/TUTORIAL.md) on how to use it.
254
+ The
255
+ [cargo-bisect-rustc](https://github.com/rust-lang-nursery/cargo-bisect-rustc)
256
+ tool can be used as a quick and easy way to find exactly which PR caused a
257
+ change in `rustc` behavior. It automatically downloads `rustc` PR artifacts and
258
+ tests them against a project you provide until it finds the regression. You can
259
+ then look at the PR to get more context on *why* it was changed. See [this
260
+ tutorial](https://github.com/rust-lang-nursery/cargo-bisect-rustc/blob/master/TUTORIAL.md)
261
+ on how to use it.
0 commit comments