You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Now we can recreate our `foo` macro. It's a little more verbose since simple symbols like `*` are resolved to `GlobalRef`s in lowered code, but it's broadly the same as our macro.
89
89
90
-
```jldoctest main
91
-
julia> using MacroTools
90
+
```@meta
91
+
DocTestSetup = quote
92
+
using IRTools
93
+
using IRTools: @dynamo, IR
94
+
95
+
mul(a, b) = a * b
96
+
end
97
+
```
98
+
99
+
```jldoctest main2
100
+
julia> using MacroTools, IRTools
101
+
102
+
julia> using IRTools: @dynamo, IR
92
103
93
104
julia> @dynamo function foo(a...)
94
105
ir = IR(a...)
@@ -100,9 +111,13 @@ julia> @dynamo function foo(a...)
100
111
end
101
112
```
102
113
114
+
```@meta
115
+
DocTestSetup = nothing
116
+
```
117
+
103
118
It behaves identically, too.
104
119
105
-
```jldoctestmain
120
+
```jldoctestmain2
106
121
julia> foo() do
107
122
10*5
108
123
end
@@ -122,7 +137,7 @@ A key difference between macros and dynamos is that dynamos get passed *function
122
137
123
138
So what if `foo` actually inserted calls to itself when modifying a function? In other words, `prod([1, 2, 3])` would become `foo(prod, [1, 2, 3])`, and so on for each call inside a function. This lets us get the "dynamic extent" property that we talked about earlier.
julia> foo() do # Does not work (since there is no literal `*` here)
166
181
mul(5, 10)
167
182
end
@@ -185,6 +200,8 @@ This, we have rewritten the `prod` function to actually calculate `sum`, by *int
185
200
We can make our `foo2` dynamo simpler in a couple of ways. Firstly, IRTools provides a built-in utility `recurse!` which makes it easy to recurse into code.
Copy file name to clipboardExpand all lines: docs/src/index.md
+18-10Lines changed: 18 additions & 10 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -14,7 +14,7 @@ Note that before even attempting to understand IRTools, you should have a good h
14
14
15
15
It's easiest to understand the IRTools IR by seeing some examples. We provide the macro `@code_ir` which behaves much like `@code_lowered`.
16
16
17
-
```jldoctest main
17
+
```jldoctest
18
18
julia> using IRTools
19
19
20
20
julia> f(x) = x+x
@@ -30,7 +30,9 @@ First things first. All variables are numbered (`%1`, `%2`, `%3` ...). IR will u
30
30
31
31
The main reason that there are a lot of intermediates is that, in IR, we only allow one function call per line. You can see how a nested Julia expression becomes a sequence of single instructions, kind of like an assembly language.
32
32
33
-
```jldoctest main
33
+
```jldoctest
34
+
julia> using IRTools
35
+
34
36
julia> f(x) = 3x*x + 2x + 1
35
37
f (generic function with 1 method)
36
38
@@ -51,7 +53,9 @@ Beyond that, this is essentially just very verbosely-written Julia code.
51
53
52
54
The most significant difference between `IR` and `Expr` is how control flow is handled. There are no such thing as nested if statements, while loops and so on in IR, only *branches*.
53
55
54
-
```jldoctest main
56
+
```jldoctest
57
+
julia> using IRTools
58
+
55
59
julia> f(x) = x > 0 ? x : 0
56
60
f (generic function with 1 method)
57
61
@@ -70,7 +74,9 @@ IR is composed of a series of *basic blocks* that jump between each other like t
70
74
71
75
Here's a more interesting example.
72
76
73
-
```jldoctest main
77
+
```jldoctest
78
+
julia> using IRTools
79
+
74
80
julia> function f(x)
75
81
if x < 0
76
82
x = -x
@@ -97,7 +103,9 @@ Why not just write this as `%2 = -%2`? It's important to understand that variabl
97
103
98
104
Loops work this way too: they are visible in the IR by branches that jump backwards, i.e. the `br 2` here. Variables that were modified inside the loop in the original code are explicitly passed between blocks.
99
105
100
-
```jldoctest main
106
+
```jldoctest envpow
107
+
julia> using IRTools
108
+
101
109
julia> function pow(x, n)
102
110
r = 1
103
111
while n > 0
@@ -129,7 +137,7 @@ julia> @code_ir pow(1, 1)
129
137
130
138
It's easy to get started by creating an empty fragment of IR.
131
139
132
-
```jldoctestmain
140
+
```jldoctestir_example
133
141
julia> using IRTools: IR, var, argument!, xcall
134
142
135
143
julia> ir = IR()
@@ -138,7 +146,7 @@ julia> ir = IR()
138
146
139
147
We can push new statements into the IR. `push!` returns a variable name that we can reuse later on.
140
148
141
-
```jldoctestmain
149
+
```jldoctestir_example
142
150
julia> x = argument!(ir)
143
151
%1
144
152
@@ -152,7 +160,7 @@ julia> ir
152
160
153
161
The IR can be viewed as a mapping from variables to statements, and indexing and iteration are consistent with that.
154
162
155
-
```julia
163
+
```julia ir_example
156
164
julia> ir[var(2)]
157
165
IRTools.Statement(:(%1*%1), Any, 0)
158
166
@@ -167,7 +175,7 @@ There are a few other functions that do obvious things: `pushfirst!`, `insert!`,
167
175
168
176
In most cases you won't build IR from scratch, but will start from an existing function and modify its IR.
169
177
170
-
```jldoctestmain
178
+
```jldoctestenvpow
171
179
julia> ir = @code_ir pow(1, 1)
172
180
1: (%1, %2, %3)
173
181
br 2 (%3, 1)
@@ -187,7 +195,7 @@ julia> ir = @code_ir pow(1, 1)
187
195
188
196
You can work with a block at a time with `block(ir, n)` (all of them with `blocks(ir)`). Blocks similarly support functions like `push!`.
0 commit comments