]> git.proxmox.com Git - rustc.git/blob - src/doc/rustc-dev-guide/src/backend/debugging.md
New upstream version 1.52.0~beta.3+dfsg1
[rustc.git] / src / doc / rustc-dev-guide / src / backend / debugging.md
1 ## Debugging LLVM
2
3 > NOTE: If you are looking for info about code generation, please see [this
4 > chapter][codegen] instead.
5
6 [codegen]: ./codegen.md
7
8 This section is about debugging compiler bugs in code generation (e.g. why the
9 compiler generated some piece of code or crashed in LLVM). LLVM is a big
10 project on its own that probably needs to have its own debugging document (not
11 that I could find one). But here are some tips that are important in a rustc
12 context:
13
14 As a general rule, compilers generate lots of information from analyzing code.
15 Thus, a useful first step is usually to find a minimal example. One way to do
16 this is to
17
18 1. create a new crate that reproduces the issue (e.g. adding whatever crate is
19 at fault as a dependency, and using it from there)
20
21 2. minimize the crate by removing external dependencies; that is, moving
22 everything relevant to the new crate
23
24 3. further minimize the issue by making the code shorter (there are tools that
25 help with this like `creduce`)
26
27 The official compilers (including nightlies) have LLVM assertions disabled,
28 which means that LLVM assertion failures can show up as compiler crashes (not
29 ICEs but "real" crashes) and other sorts of weird behavior. If you are
30 encountering these, it is a good idea to try using a compiler with LLVM
31 assertions enabled - either an "alt" nightly or a compiler you build yourself
32 by setting `[llvm] assertions=true` in your config.toml - and see whether
33 anything turns up.
34
35 The rustc build process builds the LLVM tools into
36 `./build/<host-triple>/llvm/bin`. They can be called directly.
37
38 The default rustc compilation pipeline has multiple codegen units, which is
39 hard to replicate manually and means that LLVM is called multiple times in
40 parallel. If you can get away with it (i.e. if it doesn't make your bug
41 disappear), passing `-C codegen-units=1` to rustc will make debugging easier.
42
43 For rustc to generate LLVM IR, you need to pass the `--emit=llvm-ir` flag. If
44 you are building via cargo, use the `RUSTFLAGS` environment variable (e.g.
45 `RUSTFLAGS='--emit=llvm-ir'`). This causes rustc to spit out LLVM IR into the
46 target directory.
47
48 `cargo llvm-ir [options] path` spits out the LLVM IR for a particular function
49 at `path`. (`cargo install cargo-asm` installs `cargo asm` and `cargo
50 llvm-ir`). `--build-type=debug` emits code for debug builds. There are also
51 other useful options. Also, debug info in LLVM IR can clutter the output a lot:
52 `RUSTFLAGS="-C debuginfo=0"` is really useful.
53
54 `RUSTFLAGS="-C save-temps"` outputs LLVM bitcode (not the same as IR) at
55 different stages during compilation, which is sometimes useful. One just needs
56 to convert the bitcode files to `.ll` files using `llvm-dis` which should be in
57 the target local compilation of rustc.
58
59 If you want to play with the optimization pipeline, you can use the `opt` tool
60 from `./build/<host-triple>/llvm/bin/` with the LLVM IR emitted by rustc. Note
61 that rustc emits different IR depending on whether `-O` is enabled, even
62 without LLVM's optimizations, so if you want to play with the IR rustc emits,
63 you should:
64
65 ```bash
66 $ rustc +local my-file.rs --emit=llvm-ir -O -C no-prepopulate-passes \
67 -C codegen-units=1
68 $ OPT=./build/$TRIPLE/llvm/bin/opt
69 $ $OPT -S -O2 < my-file.ll > my
70 ```
71
72 If you just want to get the LLVM IR during the LLVM pipeline, to e.g. see which
73 IR causes an optimization-time assertion to fail, or to see when LLVM performs
74 a particular optimization, you can pass the rustc flag `-C
75 llvm-args=-print-after-all`, and possibly add `-C
76 llvm-args='-filter-print-funcs=EXACT_FUNCTION_NAME` (e.g. `-C
77 llvm-args='-filter-print-funcs=_ZN11collections3str21_$LT$impl$u20$str$GT$\
78 7replace17hbe10ea2e7c809b0bE'`).
79
80 That produces a lot of output into standard error, so you'll want to pipe that
81 to some file. Also, if you are using neither `-filter-print-funcs` nor `-C
82 codegen-units=1`, then, because the multiple codegen units run in parallel, the
83 printouts will mix together and you won't be able to read anything.
84
85 If you want just the IR for a specific function (say, you want to see why it
86 causes an assertion or doesn't optimize correctly), you can use `llvm-extract`,
87 e.g.
88
89 ```bash
90 $ ./build/$TRIPLE/llvm/bin/llvm-extract \
91 -func='_ZN11collections3str21_$LT$impl$u20$str$GT$7replace17hbe10ea2e7c809b0bE' \
92 -S \
93 < unextracted.ll \
94 > extracted.ll
95 ```
96
97 ### Getting help and asking questions
98
99 If you have some questions, head over to the [rust-lang Zulip] and
100 specifically the `#t-compiler/wg-llvm` stream.
101
102 [rust-lang Zulip]: https://rust-lang.zulipchat.com/
103
104 ### Compiler options to know and love
105
106 The `-C help` and `-Z help` compiler switches will list out a variety
107 of interesting options you may find useful. Here are a few of the most
108 common that pertain to LLVM development (some of them are employed in the
109 tutorial above):
110
111 - The `--emit llvm-ir` option emits a `<filename>.ll` file with LLVM IR in textual format
112 - The `--emit llvm-bc` option emits in bytecode format (`<filename>.bc`)
113 - Passing `-C llvm-args=<foo>` allows passing pretty much all the
114 options that tools like llc and opt would accept;
115 e.g. `-C llvm-args=-print-before-all` to print IR before every LLVM
116 pass.
117 - The `-C no-prepopulate-passes` will avoid pre-populate the LLVM pass
118 manager with a list of passes. This will allow you to view the LLVM
119 IR that rustc generates, not the LLVM IR after optimizations.
120 - The `-C passes=val` option allows you to supply a space separated list of extra LLVM passes to run
121 - The `-C save-temps` option saves all temporary output files during compilation
122 - The `-Z print-llvm-passes` option will print out LLVM optimization passes being run
123 - The `-Z time-llvm-passes` option measures the time of each LLVM pass
124 - The `-Z verify-llvm-ir` option will verify the LLVM IR for correctness
125 - The `-Z no-parallel-llvm` will disable parallel compilation of distinct compilation units
126 - The `-Z llvm-time-trace` option will output a Chrome profiler compatible JSON file
127 which contains details and timings for LLVM passes.
128
129 ### Filing LLVM bug reports
130
131 When filing an LLVM bug report, you will probably want some sort of minimal
132 working example that demonstrates the problem. The Godbolt compiler explorer is
133 really helpful for this.
134
135 1. Once you have some LLVM IR for the problematic code (see above), you can
136 create a minimal working example with Godbolt. Go to
137 [gcc.godbolt.org](https://gcc.godbolt.org).
138
139 2. Choose `LLVM-IR` as programming language.
140
141 3. Use `llc` to compile the IR to a particular target as is:
142 - There are some useful flags: `-mattr` enables target features, `-march=`
143 selects the target, `-mcpu=` selects the CPU, etc.
144 - Commands like `llc -march=help` output all architectures available, which
145 is useful because sometimes the Rust arch names and the LLVM names do not
146 match.
147 - If you have compiled rustc yourself somewhere, in the target directory
148 you have binaries for `llc`, `opt`, etc.
149
150 4. If you want to optimize the LLVM-IR, you can use `opt` to see how the LLVM
151 optimizations transform it.
152
153 5. Once you have a godbolt link demonstrating the issue, it is pretty easy to
154 fill in an LLVM bug. Just visit [bugs.llvm.org](https://bugs.llvm.org/).
155
156 ### Porting bug fixes from LLVM
157
158 Once you've identified the bug as an LLVM bug, you will sometimes
159 find that it has already been reported and fixed in LLVM, but we haven't
160 gotten the fix yet (or perhaps you are familiar enough with LLVM to fix it yourself).
161
162 In that case, we can sometimes opt to port the fix for the bug
163 directly to our own LLVM fork, so that rustc can use it more easily.
164 Our fork of LLVM is maintained in [rust-lang/llvm-project]. Once
165 you've landed the fix there, you'll also need to land a PR modifying
166 our submodule commits -- ask around on Zulip for help.
167
168 [rust-lang/llvm-project]: https://github.com/rust-lang/llvm-project/