mirror of
https://github.com/Noratrieb/website.git
synced 2026-01-14 08:55:01 +01:00
644 lines
19 KiB
HTML
644 lines
19 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="utf-8" />
|
|
<meta
|
|
name="viewport"
|
|
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"
|
|
/>
|
|
|
|
<title>how rust compiles</title>
|
|
|
|
<link rel="stylesheet" href="../dist/reset.css" />
|
|
<link rel="stylesheet" href="../dist/reveal.css" />
|
|
<link rel="stylesheet" href="../dist/theme/black.css" />
|
|
|
|
<!-- Theme used for syntax highlighted code -->
|
|
<link rel="stylesheet" href="../plugin/highlight/monokai.css" />
|
|
<style>
|
|
* {
|
|
--r-heading-text-transform: initial;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="reveal">
|
|
<div class="slides">
|
|
<section>
|
|
<h2>how Rust compiles</h2>
|
|
<h4>i promise it's actually doing something useful while you wait</h4>
|
|
</section>
|
|
<section style="height: 100%">
|
|
<div style="display: flex; align-items: flex-start; height: 100%">
|
|
<details>
|
|
<summary>the rust compilation model has surprising effects</summary>
|
|
<iframe
|
|
height="600"
|
|
width="800"
|
|
src="https://play.integer32.com/?version=stable&mode=debug&edition=2024&gist=7ac62650fd0b942ae5952b0027e0c1ce"
|
|
referrerpolicy="no-referrer"
|
|
></iframe>
|
|
</details>
|
|
</div>
|
|
</section>
|
|
<section>
|
|
<h2>introduction to me</h2>
|
|
<div style="display: flex">
|
|
<div>
|
|
<div>Noratrieb (she/her)</div>
|
|
contributing to the compiler since 2021
|
|
<br />
|
|
</div>
|
|
<div>
|
|
<img src="me.png" height="300" />
|
|
</div>
|
|
</div>
|
|
</section>
|
|
<section>
|
|
<h2>behind cargo build</h2>
|
|
<p>cargo vs rustc</p>
|
|
<div style="display: grid; grid-template-columns: 2fr 1fr 2fr">
|
|
<pre><code data-trim>
|
|
$ cargo build -v
|
|
</code></pre>
|
|
<div style="display: flex; align-items: center">cargo</div>
|
|
<div style="display: flex; flex-direction: column; align-items: flex-start">
|
|
<div>rustc (clap)</div>
|
|
<div>rustc (tokio)</div>
|
|
<div>rustc (tracing)</div>
|
|
<div>rustc (yourcrate)</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
<section>
|
|
<h2>what does rustc like, do?</h2>
|
|
<h4>a quick overview of the compilation phases</h4>
|
|
</section>
|
|
<section>
|
|
<h2>it all starts at the source</h2>
|
|
<pre><code data-trim>
|
|
#[no_mangle]
|
|
pub fn add(a: u8, b: u8) -> u8 {
|
|
a.wrapping_add(b)
|
|
}
|
|
</code></pre>
|
|
</section>
|
|
<section>
|
|
<h2>the frontend and the backend</h2>
|
|
<div class="mermaid">
|
|
<pre>
|
|
%%{init: {'theme': 'dark', 'themeVariables': { 'darkMode': true, 'fontSize': '25px' }}}%%
|
|
flowchart LR
|
|
subgraph compiler
|
|
frontend --> backend
|
|
end
|
|
source --> frontend
|
|
backend --> binary
|
|
</pre>
|
|
</div>
|
|
</section>
|
|
<section>
|
|
<h2>lex, parse, resolve, typecheck, all these fancy things</h2>
|
|
<div class="mermaid">
|
|
<pre>
|
|
%%{init: {'theme': 'dark', 'themeVariables': { 'darkMode': true, 'fontSize': '25px' }}}%%
|
|
flowchart TB
|
|
function --> return
|
|
function --> params
|
|
params --> a_def[a]
|
|
params --> b_def[b]
|
|
function --> body
|
|
body --> cl["method call"]
|
|
cl --> a_use[a]
|
|
cl --> wrapping_add
|
|
cl --> b_use[b]
|
|
</pre>
|
|
</div>
|
|
</section>
|
|
<section>
|
|
<h2>so you want to compile a crate</h2>
|
|
<p>MIR</p>
|
|
<img src="add-runtime-mir.svg" />
|
|
</section>
|
|
<section data-markdown>
|
|
<textarea data-template>
|
|
## so you want to compile a crate
|
|
LLVM IR
|
|
|
|
```
|
|
; meow::add
|
|
define noundef i8 @add(i8 noundef %a, i8 noundef %b) unnamed_addr #0 {
|
|
start:
|
|
%_0 = add i8 %b, %a
|
|
ret i8 %_0
|
|
}
|
|
```
|
|
</textarea>
|
|
</section>
|
|
<section data-markdown>
|
|
<textarea data-template>
|
|
## so you want to compile a crate
|
|
Assembly
|
|
|
|
```
|
|
<add>:
|
|
lea (%rsi,%rdi,1),%eax
|
|
ret
|
|
```
|
|
</textarea>
|
|
</section>
|
|
<section data-markdown>
|
|
<textarea data-template>
|
|
## but compiling a ton of crates can't be that simple!
|
|
|
|
- yes
|
|
</textarea>
|
|
</section>
|
|
<section data-markdown>
|
|
<textarea data-template>
|
|
## backend orchestration
|
|
|
|
- the how, what, and when of invoking LLVM
|
|
</textarea>
|
|
</section>
|
|
<section>
|
|
<h2>codegen units</h2>
|
|
<pre><code>
|
|
fn main() {}
|
|
</code></pre>
|
|
<div class="mermaid">
|
|
<pre>
|
|
%%{init: {'theme': 'dark', 'themeVariables': { 'darkMode': true, 'fontSize': '25px' }}}%%
|
|
flowchart LR
|
|
mainmir["main (MIR)"]
|
|
|
|
subgraph mycgu1[my CGU 1]
|
|
mainll["main (LLVM IR)"]
|
|
end
|
|
|
|
mycgu1 --> |LLVM| mycgu1.rcgu.o
|
|
|
|
mainmir --> mainll
|
|
|
|
mycgu1.rcgu.o --> my_binary
|
|
std["std (and others)"] --> my_binary
|
|
</pre>
|
|
</div>
|
|
</section>
|
|
<section>
|
|
<h2>codegen units (but more)</h2>
|
|
<pre><code>
|
|
fn main() {}
|
|
fn foo1() {}
|
|
fn foo2() {}
|
|
</code></pre>
|
|
<div class="mermaid">
|
|
<pre>
|
|
%%{init: {'theme': 'dark', 'themeVariables': { 'darkMode': true, 'fontSize': '25px' }}}%%
|
|
flowchart LR
|
|
mainmir["main (MIR)"]
|
|
foo1mir["foo1 (MIR)"]
|
|
foo2mir["foo2 (MIR)"]
|
|
|
|
subgraph mycgu1[my CGU 1]
|
|
mainll["main (LLVM IR)"]
|
|
end
|
|
subgraph mycgu2[my CGU 2]
|
|
foo1ll["foo1 (LLVM IR)"]
|
|
foo2ll["foo2 (LLVM IR)"]
|
|
end
|
|
|
|
mycgu1 --> mycgu1.rcgu.o
|
|
mycgu2 --> mycgu2.rcgu.o
|
|
|
|
mainmir --> mainll
|
|
foo1mir --> foo1ll
|
|
foo2mir --> foo2ll
|
|
|
|
mycgu1.rcgu.o --> my_binary
|
|
mycgu2.rcgu.o --> my_binary
|
|
std["std (and others)"] --> my_binary
|
|
</pre>
|
|
</div>
|
|
</section>
|
|
<section>
|
|
<h2>codegen units (cross-crate)</h2>
|
|
<div style="display: flex; flex-direction: row; gap: 16px">
|
|
<pre><code>
|
|
fn add() {}
|
|
</code></pre>
|
|
<pre><code>
|
|
fn main() { math::add() }
|
|
</code></pre>
|
|
</div>
|
|
<div class="mermaid">
|
|
<pre>
|
|
%%{init: {'theme': 'dark', 'themeVariables': { 'darkMode': true, 'fontSize': '25px' }}}%%
|
|
flowchart LR
|
|
subgraph crate math
|
|
addmir["add (MIR)"]
|
|
|
|
subgraph mathcgu1[math CGU 1]
|
|
addll["add (LLVM IR)"]
|
|
end
|
|
|
|
addmir --> addll
|
|
|
|
mathcgu1 --> mathcgu1.rcgu.o
|
|
|
|
mathcgu1.rcgu.o --> libmath.rlib
|
|
end
|
|
|
|
subgraph my crate
|
|
mainmir["main (MIR)"]
|
|
|
|
subgraph mycgu1[my CGU 1]
|
|
mainll["main (LLVM IR)"]
|
|
end
|
|
|
|
mycgu1 --> mycgu1.rcgu.o
|
|
|
|
mainmir --> mainll
|
|
|
|
mycgu1.rcgu.o --> my_binary
|
|
libmath.rlib --> my_binary
|
|
std["std (and others)"] --> my_binary
|
|
end
|
|
</pre>
|
|
</div>
|
|
</section>
|
|
<section data-markdown>
|
|
<textarea data-template>
|
|
## generics
|
|
|
|
```rust
|
|
fn add<T: Add>(a: T, b: T) -> T::Output {
|
|
a + b
|
|
}
|
|
|
|
add(0_u16, 0_u16); // creates add<u16> function
|
|
add(0_u32, 0_u32); // creates add<u32> function
|
|
```
|
|
</textarea>
|
|
</section>
|
|
<section>
|
|
<h2>instantiating generics</h2>
|
|
<pre><code data-trim class="language-rust">
|
|
fn add<T: Add>(a: T, b: T) -> T::Output { a + b }
|
|
fn main() {
|
|
add(0_u16, 0_u16);
|
|
add(0_u32, 0_u32);
|
|
}
|
|
</code></pre>
|
|
<div class="mermaid">
|
|
<pre>
|
|
%%{init: {'theme': 'dark', 'themeVariables': { 'darkMode': true, 'fontSize': '25px' }}}%%
|
|
flowchart LR
|
|
addmir["add (MIR)"]
|
|
useitmir["main (MIR)"]
|
|
|
|
subgraph mycgu1[my CGU 1]
|
|
addu16ll["add_u16 (LLVM IR)"]
|
|
addu32ll["add_u32 (LLVM IR)"]
|
|
useitll["main (LLVM IR)"]
|
|
end
|
|
|
|
mycgu1 --> mycgu1.rcgu.o
|
|
|
|
addmir -->|instantiate with T=u16| addu16ll
|
|
addmir -->|instantiate with T=u32| addu32ll
|
|
useitmir --> useitll
|
|
|
|
mycgu1.rcgu.o --> my_binary
|
|
std["std (and others)"] --> my_binary
|
|
</pre>
|
|
</div>
|
|
</section>
|
|
<section>
|
|
<h2>generics (cross-crate)</h2>
|
|
<div style="display: flex; flex-direction: row; gap: 16px">
|
|
<pre><code data-trim class="language-rust">
|
|
pub fn add<T: Add>(a: T, b: T) -> T::Output {
|
|
a + b
|
|
}
|
|
</code></pre>
|
|
<pre><code data-trim class="language-rust">
|
|
fn main() {
|
|
math::add(0_u16, 0_u16);
|
|
math::add(0_u32, 0_u32);
|
|
}
|
|
</code></pre>
|
|
</div>
|
|
<div class="mermaid">
|
|
<pre>
|
|
%%{init: {'theme': 'dark', 'themeVariables': { 'darkMode': true, 'fontSize': '25px' }}}%%
|
|
flowchart LR
|
|
subgraph crate math
|
|
addmir["add (MIR)"]
|
|
end
|
|
|
|
subgraph my crate
|
|
mainmir["main (MIR)"]
|
|
end
|
|
|
|
subgraph my crate
|
|
subgraph mycgu1[my CGU 1]
|
|
addu16ll["add_u16 (LLVM IR)"]
|
|
addu32ll["add_u32 (LLVM IR)"]
|
|
mainll["main (LLVM IR)"]
|
|
end
|
|
|
|
mainmir --> mainll
|
|
addmir --> addu16ll
|
|
addmir --> addu32ll
|
|
mycgu1 --> mycgu1.rcgu.o
|
|
mycgu1.rcgu.o --> my_binary
|
|
std["std (and others)"] --> my_binary
|
|
end
|
|
</pre>
|
|
</div>
|
|
</section>
|
|
<section data-markdown>
|
|
<textarea data-template>
|
|
## inlining
|
|
|
|
```rust
|
|
fn add(a: u8, b: u8) -> u8 {
|
|
a + b
|
|
}
|
|
|
|
fn main() {
|
|
let x = add(1, 4);
|
|
println!("{x}");
|
|
}
|
|
```
|
|
</textarea>
|
|
</section>
|
|
<section data-markdown>
|
|
<textarea data-template>
|
|
## let's inline it
|
|
|
|
```rust
|
|
fn add(a: u8, b: u8) -> u8 {
|
|
a + b
|
|
}
|
|
|
|
fn main() {
|
|
let x = {
|
|
let a = 1;
|
|
let b = 4;
|
|
a + b
|
|
};
|
|
println!("{x}");
|
|
}
|
|
```
|
|
</textarea>
|
|
</section>
|
|
<section data-markdown>
|
|
<textarea data-template>
|
|
## cross-crate inlining
|
|
|
|
```rust
|
|
pub fn add(a: u8, b: u8) -> u8 {
|
|
a + b
|
|
}
|
|
```
|
|
```rust
|
|
fn main() {
|
|
let x = math::add(1, 4); // what is the body?...
|
|
println!("{x}");
|
|
}
|
|
```
|
|
</textarea>
|
|
</section>
|
|
<section data-markdown>
|
|
<textarea data-template>
|
|
## #[inline] to the rescue
|
|
|
|
```rust
|
|
#[inline]
|
|
pub fn add(a: u8, b: u8) -> u8 {
|
|
a + b
|
|
}
|
|
```
|
|
```rust
|
|
fn main() {
|
|
let x = math::add(1, 4); // 💡 it's a + b
|
|
println!("{x}");
|
|
}
|
|
```
|
|
</textarea>
|
|
</section>
|
|
<section>
|
|
<div style="display: flex; flex-direction: row; gap: 16px">
|
|
<pre><code data-trim class="language-rust">
|
|
#[inline]
|
|
pub fn add(a: u8, b: u8) -> u8 {
|
|
a + b
|
|
}
|
|
</code></pre>
|
|
<pre><code data-trim class="language-rust">
|
|
fn main() {
|
|
let x = math::add(1, 4);
|
|
println!("{x}");
|
|
}
|
|
</code></pre>
|
|
</div>
|
|
<div class="mermaid">
|
|
<pre>
|
|
%%{init: {'theme': 'dark', 'themeVariables': { 'darkMode': true, 'fontSize': '25px' }}}%%
|
|
flowchart LR
|
|
subgraph crate math
|
|
addmir["add (MIR)"]
|
|
end
|
|
|
|
subgraph my crate
|
|
mainmir["main (MIR)"]
|
|
end
|
|
|
|
subgraph my crate
|
|
subgraph mycgu1[my CGU 1]
|
|
addll["add (LLVM IR)"]
|
|
mainll["main (LLVM IR)"]
|
|
end
|
|
|
|
mainmir --> mainll
|
|
addmir --> addll
|
|
mycgu1 --> mycgu1.rcgu.o
|
|
mycgu1.rcgu.o --> my_binary
|
|
std["std (and others)"] --> my_binary
|
|
end
|
|
</pre>
|
|
</div>
|
|
</section>
|
|
<section data-markdown>
|
|
<textarea data-template>
|
|
## `#[inline]`
|
|
- `#[inline]` enables cross-crate inlining of non-generic functions
|
|
- for very small functions, this happens automatically
|
|
- for other functions, it doesn't, because it would be slow (try with `-Zcross-crate-inline-threshold=always`)
|
|
- don't over-apply it in a library, but also don't forget about it
|
|
- benchmark!
|
|
</textarea>
|
|
</section>
|
|
<section data-markdown>
|
|
<textarea data-template>
|
|
## but i want maximal performance...
|
|
</textarea>
|
|
</section>
|
|
<section data-markdown>
|
|
<textarea data-template>
|
|
## link-time optimization (LTO)
|
|
|
|
- optimizes everything in your program together at the end
|
|
- breaks crate boundaries
|
|
- is awesome
|
|
- is slow
|
|
- comes in many forms
|
|
</textarea>
|
|
</section>
|
|
<section>
|
|
<h2>lto = "fat" (monolithic)</h2>
|
|
<div class="mermaid">
|
|
<pre>
|
|
%%{init: {'theme': 'dark', 'themeVariables': { 'darkMode': true, 'fontSize': '25px' }}}%%
|
|
flowchart LR
|
|
subgraph crate math
|
|
addmir["add (LLVM IR)"]
|
|
end
|
|
subgraph crate math2
|
|
submir["sub (LLVM IR)"]
|
|
end
|
|
|
|
subgraph my crate
|
|
mainmir["main (LLVM IR)"]
|
|
end
|
|
|
|
subgraph my crate
|
|
subgraph fatlto[fat LTO]
|
|
addll["add (LLVM IR)"]
|
|
subll["sub (LLVM IR)"]
|
|
mainll["main (LLVM IR)"]
|
|
end
|
|
|
|
mainmir --> mainll
|
|
addmir --> addll
|
|
submir --> subll
|
|
|
|
fatlto --> my_binary
|
|
end
|
|
</pre>
|
|
</div>
|
|
</section>
|
|
<section>
|
|
<h2>lto = "thin" (sharded)</h2>
|
|
<div class="mermaid">
|
|
<pre>
|
|
%%{init: {'theme': 'dark', 'themeVariables': { 'darkMode': true, 'fontSize': '25px' }}}%%
|
|
flowchart LR
|
|
subgraph crate math
|
|
addmir["add (LLVM IR)"]
|
|
end
|
|
subgraph crate math2
|
|
submir["sub (LLVM IR)"]
|
|
end
|
|
|
|
subgraph my crate
|
|
mainmir["main (LLVM IR)"]
|
|
end
|
|
|
|
subgraph my crate
|
|
subgraph thinltosummary[ThinLTO Summary]
|
|
end
|
|
|
|
subgraph thinlto1[ThinLTO 1]
|
|
addll["add (LLVM IR)"]
|
|
subll["sub (LLVM IR)"]
|
|
end
|
|
subgraph thinlto2[ThinLTO 2]
|
|
mainll["main (LLVM IR)"]
|
|
end
|
|
|
|
mainmir --> thinltosummary
|
|
addmir --> thinltosummary
|
|
submir --> thinltosummary
|
|
|
|
thinltosummary --> mainll
|
|
thinltosummary --> addll
|
|
thinltosummary --> subll
|
|
|
|
thinlto1 --> my_binary
|
|
thinlto2 --> my_binary
|
|
end
|
|
</pre>
|
|
</div>
|
|
</section>
|
|
<section data-markdown>
|
|
<textarea data-template>
|
|
## linker-plugin-lto
|
|
|
|
- fat LTO style and thin LTO style
|
|
- the merging is not done by rustc but by the linker
|
|
- works across languages (Rust (rustc) + C (clang))
|
|
- great for FFI
|
|
- annoying to set up
|
|
</textarea>
|
|
</section>
|
|
<section data-markdown>
|
|
<textarea data-template>
|
|
## inlining across codegen units in the same crate
|
|
|
|
- ThinLTO across different codegen units by default
|
|
</textarea>
|
|
</section>
|
|
<section data-markdown>
|
|
<textarea data-template>
|
|
## `Cargo.toml` config
|
|
|
|
```toml
|
|
[profile.release]
|
|
lto = "thin"
|
|
codegen-units = 1
|
|
```
|
|
</textarea>
|
|
</section>
|
|
<section data-markdown>
|
|
<textarea data-template>
|
|
## and why did `#[inline]` make the error go away?
|
|
|
|
```rust
|
|
pub fn error() {
|
|
// vvvvvvvvvvv post-mono error!
|
|
let _x: [u8; usize::MAX] = [0; usize::MAX];
|
|
}
|
|
```
|
|
</textarea>
|
|
</section>
|
|
<section data-markdown>
|
|
<textarea data-template>
|
|
## happy compiling
|
|
</textarea>
|
|
</section>
|
|
</div>
|
|
</div>
|
|
|
|
<script src="../dist/reveal.js"></script>
|
|
<script src="../plugin/notes/notes.js"></script>
|
|
<script src="../plugin/markdown/markdown.js"></script>
|
|
<script src="../plugin/highlight/highlight.js"></script>
|
|
|
|
<script src="./reveal.js-mermaid-plugin_11-6-0.js"></script>
|
|
|
|
<script>
|
|
// More info about initialization & config:
|
|
// - https://revealjs.com/initialization/
|
|
// - https://revealjs.com/config/
|
|
Reveal.initialize({
|
|
hash: true,
|
|
|
|
// Learn about plugins: https://revealjs.com/plugins/
|
|
plugins: [RevealMarkdown, RevealHighlight, RevealNotes, RevealMermaid],
|
|
});
|
|
</script>
|
|
</body>
|
|
</html>
|