Assignment
Mutation of existing variables is also quite simple. We’ll add a special case to our code generator for the “=” operator to add internal logic for looking up the LHS variable and assign it the right hand side using the store
operation.
cgen (S.BinaryOp "=" (S.Var var) val) = do
a <- getvar var
cval <- cgen val
store a cval
return cval
Testing this out for a trivial example we find that we can now update variables.
ready> def main(x) x = 1;
; ModuleID = 'my cool jit'
define double @main(double %x) {
entry:
%0 = alloca double
store double %x, double* %0
store double 1.000000e+00, double* %0
ret double 1.000000e+00
}
Evaluated to: 1.0
Finally we can write down our Fibonacci example using mutable updates.
def fibi(x)
var a = 1, b = 1, c = 0 in
(for i = 3, i < x, 1.0 in
c = (a + b) :
a = b :
b = c
): b;
fibi(10);
With this, we completed what we set out to do. Our nice iterative fib example from the intro compiles and runs just fine. The mem2reg pass optimizes all of our stack variables into SSA registers, inserting PHI nodes where needed, and our front-end remains simple: no “iterated dominance frontier” computation anywhere in sight.
define double @fibi(double %x) #0 {
entry:
br label %for.loop
for.loop: ; preds = %for.loop, %entry
%0 = phi double [ %4, %for.loop ], [ 3.000000e+00, %entry ]
%1 = phi double [ %3, %for.loop ], [ 1.000000e+00, %entry ]
%2 = phi double [ %1, %for.loop ], [ 1.000000e+00, %entry ]
%3 = fadd double %2, %1
%4 = fadd double %0, 1.000000e+00
%5 = fcmp ult double %4, %x
br i1 %5, label %for.loop, label %for.exit
for.exit: ; preds = %for.loop
%6 = call double @"binary:"(double 0.000000e+00, double %3)
ret double %6
}
Running the optimizations we see that we get nicely optimal assembly code for our loop. The auto-vectorizer pass has also rewriten our naive code to used SIMD instructions which yield much faster execution.
fibi: # @fibi
# BB#0: # %entry
vmovsd .LCPI2_0(%rip), %xmm2
vmovsd .LCPI2_1(%rip), %xmm3
vmovaps %xmm2, %xmm1
vmovaps %xmm2, %xmm4
.align 16, 0x90
.LBB2_1: # %for.loop
vmovaps %xmm1, %xmm5
vaddsd %xmm4, %xmm5, %xmm1
vaddsd %xmm2, %xmm3, %xmm3
vucomisd %xmm0, %xmm3
vmovaps %xmm5, %xmm4
jb .LBB2_1
# BB#2: # %for.exit
vmovaps %xmm1, %xmm0
ret