Skip to content

Commit 37d26cc

Browse files
authored
Update links in README (#51)
resolves #38
1 parent 562ddd5 commit 37d26cc

1 file changed

Lines changed: 101 additions & 128 deletions

File tree

‎README.md‎

Lines changed: 101 additions & 128 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ Hello!
33
This is a simple demo that JIT-compiles a toy language, using Cranelift.
44

55
It uses the new SimpleJIT interface in development
6-
[here](https://github.com/bytecodealliance/wasmtime/tree/main/cranelift/simplejit). SimpleJIT takes care
6+
[here](https://github.com/bytecodealliance/wasmtime/tree/main/cranelift/jit). SimpleJIT takes care
77
of managing a symbol table, allocating memory, and performing relocations, offering
88
a relatively simple API.
99

@@ -34,13 +34,13 @@ is being designed to support many other kinds of platforms in the future.
3434

3535
### A walkthrough
3636

37-
First, let's take a quick look at the toy language in use. It's a very
38-
simple language, in which all variables have type `isize`. (Cranelift does have
39-
full support for other integer and floating-point types, so this is just to
40-
keep the toy language simple).
37+
First, let's take a quick look at the toy language in use. It's a very simple
38+
language, in which all variables have type `isize`. (Cranelift does have full
39+
support for other integer and floating-point types, so this is just to keep the
40+
toy language simple).
4141

4242
For a quick flavor, here's our
43-
[first example](./src/toy.rs#L21)
43+
[first example](./src/bin/toy.rs#L63)
4444
in the toy language:
4545

4646
```
@@ -58,11 +58,12 @@ in the toy language:
5858
}
5959
```
6060

61-
The grammar for this toy language is defined [here](./src/frontend.rs#L23),
62-
and this demo uses the [peg](https://crates.io/crates/peg) parser generator library
61+
The grammar for this toy language is defined [here](./src/frontend.rs#L23), and
62+
this demo uses the [peg](https://crates.io/crates/peg) parser generator library
6363
to generate actual parser code for it.
6464

6565
The output of parsing is a [custom AST type](./src/frontend.rs#L1):
66+
6667
```rust
6768
pub enum Expr {
6869
Literal(String),
@@ -85,19 +86,17 @@ pub enum Expr {
8586
}
8687
```
8788

88-
It's pretty minimal and straightforward. The `IfElse` can return a value, to show
89-
how that's done in Cranelift (see below).
89+
It's pretty minimal and straightforward. The `IfElse` can return a value, to
90+
show how that's done in Cranelift (see below).
91+
92+
The [first thing we do](./src/bin/toy.rs#L6) is create an instance of our `JIT`:
9093

91-
The
92-
[first thing we do](./src/toy.rs#L13)
93-
is create an instance of our `JIT`:
9494
```rust
9595
let mut jit = jit::JIT::new();
9696
```
9797

98-
The `JIT` class is defined
99-
[here](./src/jit.rs#L10)
100-
and contains several fields:
98+
The `JIT` class is defined [here](./src/jit.rs#L9) and contains several fields:
99+
101100
- `builder_context` - Cranelift uses this to reuse dynamic allocations between
102101
compiling multiple functions.
103102
- `ctx` - This is the main `Context` object for compiling functions.
@@ -116,61 +115,46 @@ Both functions and data objects can contain references to other functions and
116115
data objects. Cranelift is designed to allow the low-level parts operate on each
117116
function and data object independently, so each function and data object maintains
118117
its own individual namespace of imported names. The
119-
[`Module`](https://docs.rs/cranelift-module/latest/cranelift_module/struct.Module.html)
118+
[`Module`](https://docs.rs/cranelift-module/0.6.8/cranelift_module/trait.Module.html)
120119
struct takes care of maintaining a set of declarations for use across multiple
121120
functions and data objects.
122121

123122
These concepts are sufficiently general that they're applicable to JITing as
124123
well as native object files (more discussion below!), and `Module` provides an
125-
interface which abstracts over both. It is parameterized with a
126-
[`Backend`](https://docs.rs/cranelift-module/latest/cranelift_module/trait.Backend.html)
127-
trait, which allows users to specify what underlying implementation they want to use.
128-
129-
Once we've
130-
[initialized the JIT data structures](./src/jit.rs#L29),
131-
we then use our `JIT` to
132-
[compile](./src/jit.rs#L46)
133-
some functions.
134-
135-
The `JIT`'s `compile` function takes a string containing a function in the
136-
toy language. It
137-
[parses](./src/jit.rs#L48)
138-
the string into an AST, and then
139-
[translates](./src/jit.rs#L52)
140-
the AST into Cranelift IR.
141-
142-
Our toy language only supports one type, so we start by
143-
[declaring that type](./src/jit.rs#L117)
144-
for convenience.
145-
146-
We then start translating the function by adding
147-
[the function parameters](./src/jit.rs#L121)
148-
and
149-
[return types](./src/jit.rs#L125)
150-
to the Cranelift function signature.
151-
152-
Then we
153-
[create](./src/jit.rs#L129)
154-
a
124+
interface which abstracts over both.
125+
126+
Once we've [initialized the JIT data structures](./src/jit.rs#L29), we then use
127+
our `JIT` to [compile](./src/jit.rs#L42) some functions.
128+
129+
The `JIT`'s `compile` function takes a string containing a function in the toy
130+
language. It [parses](./src/jit.rs#L44) the string into an AST, and then
131+
[translates](./src/jit.rs#L48) the AST into Cranelift IR.
132+
133+
Our toy language only supports one type, so we start by [declaring that
134+
type](./src/jit.rs#L133) for convenience.
135+
136+
We then start translating the function by adding [the function
137+
parameters](./src/jit.rs#L115) and [return types](./src/jit.rs#L121) to the
138+
Cranelift function signature.
139+
140+
Then we [create](./src/jit.rs#L124) a
155141
[FunctionBuilder](https://docs.rs/cranelift-frontend/latest/cranelift_frontend/struct.FunctionBuilder.html)
156-
which is a utility for building up the contents of a Cranelift IR function. As we'll
157-
see below, `FunctionBuilder` includes functionality for constructing SSA form
158-
automatically so that users don't have to worry about it.
142+
which is a utility for building up the contents of a Cranelift IR function. As
143+
we'll see below, `FunctionBuilder` includes functionality for constructing SSA
144+
form automatically so that users don't have to worry about it.
159145

160-
Next, we
161-
[start](./src/jit.rs#L132)
162-
an initial basic block (block), which is the entry block of the function, and
163-
the place where we'll insert some code.
146+
Next, we [start](./src/jit.rs#L127) an initial basic block (block), which is the
147+
entry block of the function, and the place where we'll insert some code.
164148

165149
- A basic block is a sequence of IR instructions which have a single entry
166150
point, and no branches until the very end, so execution always starts at the
167151
top and proceeds straight through to the end.
168152

169-
Cranelift's basic blocks can have parameters. These take the place of
170-
PHI functions in other IRs.
153+
Cranelift's basic blocks can have parameters. These take the place of PHI
154+
functions in other IRs.
171155

172-
Here's an example of a block, showing branches (`brif` and `jump`) that are at the end of the block,
173-
and demonstrating some block parameters.
156+
Here's an example of a block, showing branches (`brif` and `jump`) that are at
157+
the end of the block, and demonstrating some block parameters.
174158

175159
```
176160
block0(v0: i32, v1: i32, v2: i32, v507: i64):
@@ -183,47 +167,43 @@ block0(v0: i32, v1: i32, v2: i32, v507: i64):
183167
jump block29(v508)
184168
```
185169

186-
The `FunctionBuilder` library will take care of
187-
inserting block parameters automatically, so frontends that don't need to use
188-
them directly generally don't need to worry about them, though one place they
189-
do come up is that incoming arguments to a function are represented as
190-
block parameters to the entry block. We must tell Cranelift to add the parameters,
191-
using
170+
The `FunctionBuilder` library will take care of inserting block parameters
171+
automatically, so frontends that don't need to use them directly generally don't
172+
need to worry about them, though one place they do come up is that incoming
173+
arguments to a function are represented as block parameters to the entry
174+
block. We must tell Cranelift to add the parameters, using
192175
[`append_block_params_for_function_params`](https://docs.rs/cranelift-frontend/latest/cranelift_frontend/struct.FunctionBuilder.html#method.append_block_params_for_function_params)
193-
like
194-
[so](./src/jit.rs#L135).
176+
like [so](./src/jit.rs#L133).
195177

196178
The `FunctionBuilder` keeps track of a "current" block that new instructions are
197-
to be inserted into; we next
198-
[inform](./src/jit.rs#L141)
199-
it of our new block, using
179+
to be inserted into; we next [inform](./src/jit.rs#L136) it of our new block,
180+
using
200181
[`switch_to_block`](https://docs.rs/cranelift-frontend/latest/cranelift_frontend/struct.FunctionBuilder.html#method.switch_to_block),
201-
so that we can start
202-
inserting instructions into it.
182+
so that we can start inserting instructions into it.
203183

204184
The one major concept about blocks is that the `FunctionBuilder` wants to know when
205185
all branches which could branch to a block have been seen, at which point it can
206186
*seal* the block, which allows it to perform SSA construction. All blocks must be
207187
sealed by the end of the function. We
208-
[seal](./src/jit.rs#L144)
188+
[seal](./src/jit.rs#L141)
209189
a block with
210190
[`seal_block`](https://docs.rs/cranelift-frontend/latest/cranelift_frontend/struct.FunctionBuilder.html#method.seal_block).
211191

212192
Next, our toy language doesn't have explicit variable declarations, so we walk the
213193
AST to discover all the variables, so that we can
214-
[declare](./src/jit.rs#L149)
194+
[declare](./src/jit.rs#L146)
215195
then to the `FunctionBuilder`. These variables need not be in SSA form; the
216196
`FunctionBuilder` will take care of constructing SSA form internally.
217197

218198
For convenience when walking the function body, the demo here
219-
[uses](./src/jit.rs#L154)
199+
[uses](./src/jit.rs#L176)
220200
a `FunctionTranslator` object, which holds the `FunctionBuilder`, the current
221201
`Module`, as well as the symbol table for looking up variables. Now we can start
222-
[walking the function body](./src/jit.rs#L161).
202+
[walking the function body](./src/jit.rs#L156).
223203

224-
[AST translation](./src/jit.rs#L189)
225-
utilizes the instruction-building features of `FunctionBuilder`. Let's start with
226-
a simple example translating integer literals:
204+
[AST translation](./src/jit.rs#L186) utilizes the instruction-building features
205+
of `FunctionBuilder`. Let's start with a simple example translating integer
206+
literals:
227207

228208
```rust
229209
Expr::Literal(literal) => {
@@ -232,23 +212,22 @@ a simple example translating integer literals:
232212
}
233213
```
234214

235-
The first part is just extracting the integer value from the AST. The next
236-
line is the builder line:
215+
The first part is just extracting the integer value from the AST. The next line
216+
is the builder line:
237217

238218
- The `.ins()` returns an "insertion object", which allows inserting an
239219
instruction at the end of the currently active block.
240-
- `iconst` is the name of the builder routine for creating
241-
[integer constants](https://cranelift.readthedocs.io/en/latest/langref.html#inst-iconst)
242-
in Cranelift. Every instruction in the IR can be created directly through such
243-
a function call.
244-
245-
Translation of
246-
[Add nodes](./src/jit.rs#L199)
247-
and other arithmetic operations is similarly straightforward.
248-
249-
Translation of
250-
[variable references](./src/jit.rs#L275)
251-
is mostly handled by `FunctionBuilder`'s `use_var` function:
220+
- `iconst` is the name of the builder routine for creating [integer
221+
constants](https://docs.rs/cranelift-codegen/0.66.0/cranelift_codegen/ir/trait.InstBuilder.html#method.iconst)
222+
in Cranelift. Every instruction in the IR can be created directly through
223+
such a function call.
224+
225+
Translation of [Add nodes](./src/jit.rs#L193) and other arithmetic operations is
226+
similarly straightforward.
227+
228+
Translation of [variable references](./src/jit.rs#L230) is mostly handled by
229+
`FunctionBuilder`'s `use_var` function:
230+
252231
```rust
253232
Expr::Identifier(name) => {
254233
// `use_var` is used to read the value of a variable.
@@ -261,8 +240,9 @@ is mostly handled by `FunctionBuilder`'s `use_var` function:
261240

262241
Its companion is `def_var`, which is used to write the value of a (non-SSA)
263242
variable, which we use to implement assignment:
243+
264244
```rust
265-
Expr::Assign(name, expr) => {
245+
fn translate_assign(&mut self, name: String, expr: Expr) -> Value {
266246
// `def_var` is used to write the value of a variable. Note that
267247
// variables can have multiple definitions. Cranelift will
268248
// convert them into SSA form for itself automatically.
@@ -273,19 +253,17 @@ variable, which we use to implement assignment:
273253
}
274254
```
275255

276-
Next, let's dive into
277-
[if-else](./src/jit.rs#L291)
278-
expressions. In order to demonstrate explicit SSA construction, this demo gives
279-
if-else expressions return values. The way this looks in Cranelift is that
280-
the true and false arms of the if-else both have branches to a common merge point,
281-
and they each pass their "return value" as a block parameter to the merge point.
256+
Next, let's dive into [if-else](./src/jit.rs#L231) expressions. In order to
257+
demonstrate explicit SSA construction, this demo gives if-else expressions
258+
return values. The way this looks in Cranelift is that the true and false arms
259+
of the if-else both have branches to a common merge point, and they each pass
260+
their "return value" as a block parameter to the merge point.
282261

283262
Note that we seal the blocks we create once we know we'll have no more predecessors,
284263
which is something that a typical AST makes it easy to know.
285264

286265
Putting it all together, here's the Cranelift IR for the function named
287-
[foo](./src/toy.rs#L15)
288-
in the demo program, which contains multiple ifs:
266+
[foo](./src/toy.rs#L63) in the demo program, which contains multiple ifs:
289267

290268
```
291269
function u0:0(i64, i64) -> i64 system_v {
@@ -324,10 +302,9 @@ block3(v3: i64):
324302
}
325303
```
326304

327-
The [while loop](./src/jit.rs#L338)
328-
translation is also straightforward.
305+
The [while loop](./src/jit.rs#L314) translation is also straightforward.
329306

330-
Here's the Cranelift IR for the function named [iterative_fib](./src/toy.rs#L81)
307+
Here's the Cranelift IR for the function named [iterative_fib](./src/toy.rs#L94)
331308
in the demo program, which contains a while loop:
332309

333310
```
@@ -375,33 +352,29 @@ block3(v5: i64, v23: i64):
375352
}
376353
```
377354

378-
For
379-
[calls](./src/jit.rs#L365),
380-
the basic steps are to determine the call signature, declare the function to be
381-
called, put the values to be passed in an array, and then call the `call` function.
355+
For [calls](./src/jit.rs#L345), the basic steps are to determine the call
356+
signature, declare the function to be called, put the values to be passed in an
357+
array, and then call the `call` function.
382358

383-
The translation for
384-
[global data symbols](./src/jit.rs#L393),
385-
is similar; first declare the symbol to the module, then declare it to the current
386-
function, and then use the `symbol_value` instruction to produce the value.
359+
The translation for [global data symbols](./src/jit.rs#L373), is similar; first
360+
declare the symbol to the module, then declare it to the current function, and
361+
then use the `symbol_value` instruction to produce the value.
387362

388363
And with that, we can return to our main `toy.rs` file and run some more examples.
389364
There are examples of recursive and iterative fibonacci, which demonstrate more use
390365
of calls and control flow.
391366

392367
And there's a hello world example which demonstrates several other features.
393368

394-
This program needs to allocate some
395-
[data](./src/toy.rs#L120)
396-
to hold the string data. Inside jit.rs,
397-
[`create_data`](./src/jit.rs#L90)
398-
we initialize a `DataContext` with the contents of the hello string, and also
399-
declare a data object. Then we use the `DataContext` object to define the object.
400-
At that point, we're done with the `DataContext` object and can clear it. We
401-
then call `finalize_data` to perform linking (although our simple hello string
402-
doesn't make any references so there isn't anything to do) and to obtain the
403-
final runtime address of the data, which we then convert back into a Rust slice
404-
for convenience.
369+
This program needs to allocate some [data](./src/toy.rs#L35) to hold the string
370+
data. Inside jit.rs, [`create_data`](./src/jit.rs#L85) we initialize a
371+
`DataContext` with the contents of the hello string, and also declare a data
372+
object. Then we use the `DataContext` object to define the object. At that
373+
point, we're done with the `DataContext` object and can clear it. We then call
374+
`finalize_data` to perform linking (although our simple hello string doesn't
375+
make any references so there isn't anything to do) and to obtain the final
376+
runtime address of the data, which we then convert back into a Rust slice for
377+
convenience.
405378

406379
And to show off a handy feature of the simplejit backend, it can look up symbols
407380
with `libc::dlsym`, so you can call libc functions such as `puts` (being careful
@@ -423,14 +396,14 @@ including printing "hello world!".
423396
Another branch [here](https://github.com/bytecodealliance/simplejit-demo/tree/faerie-macho)
424397
shows how to write Mach-O object files.
425398

426-
Object files are written using the
427-
[faerie](https://github.com/m4b/faerie) library.
399+
Object files are written using the [faerie](https://github.com/m4b/faerie)
400+
library.
428401

429402
### Have fun!
430403

431404
Cranelift is still evolving, so if there are things here which are confusing or
432-
awkward, please let us know, via
433-
[github issues](https://github.com/bytecodealliance/cranelift/issues) or
434-
just stop by the [gitter chat](https://gitter.im/CraneStation/Lobby/~chat).
405+
awkward, please let us know, via [github
406+
issues](https://github.com/bytecodealliance/wasmtime/issues?q=is%3Aissue+is%3Aopen+label%3Acranelift)
407+
or just stop by the [gitter chat](https://gitter.im/CraneStation/Lobby/~chat).
435408
Very few things in Cranelift's design are set in stone at this time, and we're
436409
really interested to hear from people about what makes sense what doesn't.

0 commit comments

Comments
 (0)