]>
Commit | Line | Data |
---|---|---|
c295e0f8 XL |
1 | # WIP libgccjit codegen backend for rust |
2 | ||
3 | This is a GCC codegen for rustc, which means it can be loaded by the existing rustc frontend, but benefits from GCC: more architectures are supported and GCC's optimizations are used. | |
4 | ||
5 | **Despite its name, libgccjit can be used for ahead-of-time compilation, as is used here.** | |
6 | ||
7 | ## Motivation | |
8 | ||
9 | The primary goal of this project is to be able to compile Rust code on platforms unsupported by LLVM. | |
10 | A secondary goal is to check if using the gcc backend will provide any run-time speed improvement for the programs compiled using rustc. | |
11 | ||
12 | ## Building | |
13 | ||
14 | **This requires a patched libgccjit in order to work. | |
5e7ed085 | 15 | The patches in [this repository](https://github.com/antoyo/libgccjit-patches) need to be applied. |
c295e0f8 XL |
16 | (Those patches should work when applied on master, but in case it doesn't work, they are known to work when applied on 079c23cfe079f203d5df83fea8e92a60c7d7e878.) |
17 | You can also use my [fork of gcc](https://github.com/antoyo/gcc) which already includes these patches.** | |
18 | ||
19 | **Put the path to your custom build of libgccjit in the file `gcc_path`.** | |
20 | ||
21 | ```bash | |
22 | $ git clone https://github.com/rust-lang/rustc_codegen_gcc.git | |
23 | $ cd rustc_codegen_gcc | |
5e7ed085 FG |
24 | $ git clone https://github.com/llvm/llvm-project llvm --depth 1 --single-branch |
25 | $ export RUST_COMPILER_RT_ROOT="$PWD/llvm/compiler-rt" | |
c295e0f8 XL |
26 | $ ./prepare_build.sh # download and patch sysroot src |
27 | $ ./build.sh --release | |
28 | ``` | |
29 | ||
30 | To run the tests: | |
31 | ||
32 | ```bash | |
33 | $ ./prepare.sh # download and patch sysroot src and install hyperfine for benchmarking | |
34 | $ ./test.sh --release | |
35 | ``` | |
36 | ||
37 | ## Usage | |
38 | ||
39 | `$cg_gccjit_dir` is the directory you cloned this repo into in the following instructions. | |
40 | ||
41 | ### Cargo | |
42 | ||
43 | ```bash | |
44 | $ CHANNEL="release" $cg_gccjit_dir/cargo.sh run | |
45 | ``` | |
46 | ||
47 | If you compiled cg_gccjit in debug mode (aka you didn't pass `--release` to `./test.sh`) you should use `CHANNEL="debug"` instead or omit `CHANNEL="release"` completely. | |
48 | ||
49 | ### Rustc | |
50 | ||
51 | > You should prefer using the Cargo method. | |
52 | ||
53 | ```bash | |
54 | $ rustc +$(cat $cg_gccjit_dir/rust-toolchain) -Cpanic=abort -Zcodegen-backend=$cg_gccjit_dir/target/release/librustc_codegen_gcc.so --sysroot $cg_gccjit_dir/build_sysroot/sysroot my_crate.rs | |
55 | ``` | |
56 | ||
57 | ## Env vars | |
58 | ||
59 | <dl> | |
60 | <dt>CG_GCCJIT_INCR_CACHE_DISABLED</dt> | |
61 | <dd>Don't cache object files in the incremental cache. Useful during development of cg_gccjit | |
62 | to make it possible to use incremental mode for all analyses performed by rustc without caching | |
63 | object files when their content should have been changed by a change to cg_gccjit.</dd> | |
64 | <dt>CG_GCCJIT_DISPLAY_CG_TIME</dt> | |
65 | <dd>Display the time it took to perform codegen for a crate</dd> | |
66 | </dl> | |
67 | ||
68 | ## Debugging | |
69 | ||
70 | Sometimes, libgccjit will crash and output an error like this: | |
71 | ||
72 | ``` | |
73 | during RTL pass: expand | |
74 | libgccjit.so: error: in expmed_mode_index, at expmed.h:249 | |
75 | 0x7f0da2e61a35 expmed_mode_index | |
76 | ../../../gcc/gcc/expmed.h:249 | |
77 | 0x7f0da2e61aa4 expmed_op_cost_ptr | |
78 | ../../../gcc/gcc/expmed.h:271 | |
79 | 0x7f0da2e620dc sdiv_cost_ptr | |
80 | ../../../gcc/gcc/expmed.h:540 | |
81 | 0x7f0da2e62129 sdiv_cost | |
82 | ../../../gcc/gcc/expmed.h:558 | |
83 | 0x7f0da2e73c12 expand_divmod(int, tree_code, machine_mode, rtx_def*, rtx_def*, rtx_def*, int) | |
84 | ../../../gcc/gcc/expmed.c:4335 | |
85 | 0x7f0da2ea1423 expand_expr_real_2(separate_ops*, rtx_def*, machine_mode, expand_modifier) | |
86 | ../../../gcc/gcc/expr.c:9240 | |
87 | 0x7f0da2cd1a1e expand_gimple_stmt_1 | |
88 | ../../../gcc/gcc/cfgexpand.c:3796 | |
89 | 0x7f0da2cd1c30 expand_gimple_stmt | |
90 | ../../../gcc/gcc/cfgexpand.c:3857 | |
91 | 0x7f0da2cd90a9 expand_gimple_basic_block | |
92 | ../../../gcc/gcc/cfgexpand.c:5898 | |
93 | 0x7f0da2cdade8 execute | |
94 | ../../../gcc/gcc/cfgexpand.c:6582 | |
95 | ``` | |
96 | ||
97 | To see the code which causes this error, call the following function: | |
98 | ||
99 | ```c | |
100 | gcc_jit_context_dump_to_file(ctxt, "/tmp/output.c", 1 /* update_locations */) | |
101 | ``` | |
102 | ||
103 | This will create a C-like file and add the locations into the IR pointing to this C file. | |
104 | Then, rerun the program and it will output the location in the second line: | |
105 | ||
106 | ``` | |
107 | libgccjit.so: /tmp/something.c:61322:0: error: in expmed_mode_index, at expmed.h:249 | |
108 | ``` | |
109 | ||
110 | Or add a breakpoint to `add_error` in gdb and print the line number using: | |
111 | ||
112 | ``` | |
113 | p loc->m_line | |
5e7ed085 FG |
114 | p loc->m_filename->m_buffer |
115 | ``` | |
116 | ||
117 | To print a debug representation of a tree: | |
118 | ||
119 | ```c | |
120 | debug_tree(expr); | |
c295e0f8 XL |
121 | ``` |
122 | ||
a2a8927a XL |
123 | To get the `rustc` command to run in `gdb`, add the `--verbose` flag to `cargo build`. |
124 | ||
c295e0f8 XL |
125 | ### How to use a custom-build rustc |
126 | ||
127 | * Build the stage2 compiler (`rustup toolchain link debug-current build/x86_64-unknown-linux-gnu/stage2`). | |
128 | * Clean and rebuild the codegen with `debug-current` in the file `rust-toolchain`. | |
129 | ||
130 | ### How to build a cross-compiling libgccjit | |
131 | ||
132 | #### Building libgccjit | |
133 | ||
134 | * Follow these instructions: https://preshing.com/20141119/how-to-build-a-gcc-cross-compiler/ with the following changes: | |
135 | * Configure gcc with `../gcc/configure --enable-host-shared --disable-multilib --enable-languages=c,jit,c++ --disable-bootstrap --enable-checking=release --prefix=/opt/m68k-gcc/ --target=m68k-linux --without-headers`. | |
136 | * Some shells, like fish, don't define the environment variable `$MACHTYPE`. | |
137 | * Add `CFLAGS="-Wno-error=attributes -g -O2"` at the end of the configure command for building glibc (`CFLAGS="-Wno-error=attributes -Wno-error=array-parameter -Wno-error=stringop-overflow -Wno-error=array-bounds -g -O2"` for glibc 2.31, which is useful for Debian). | |
138 | ||
139 | #### Configuring rustc_codegen_gcc | |
140 | ||
141 | * Set `TARGET_TRIPLE="m68k-unknown-linux-gnu"` in config.sh. | |
142 | * Since rustc doesn't support this architecture yet, set it back to `TARGET_TRIPLE="mips-unknown-linux-gnu"` (or another target having the same attributes). Alternatively, create a [target specification file](https://book.avr-rust.com/005.1-the-target-specification-json-file.html) (note that the `arch` specified in this file must be supported by the rust compiler). | |
143 | * Set `linker='-Clinker=m68k-linux-gcc'`. | |
144 | * Set the path to the cross-compiling libgccjit in `gcc_path`. | |
145 | * Disable the 128-bit integer types if the target doesn't support them by using `let i128_type = context.new_type::<i64>();` in `context.rs` (same for u128_type). | |
5e7ed085 | 146 | * Comment the line: `context.add_command_line_option("-masm=intel");` in src/base.rs. |
c295e0f8 | 147 | * (might not be necessary) Disable the compilation of libstd.so (and possibly libcore.so?). |