Generate code for for loops
authorLuke Lau <luke_lau@icloud.com>
Thu, 7 Nov 2019 17:53:54 +0000 (17:53 +0000)
committerLuke Lau <luke_lau@icloud.com>
Fri, 8 Nov 2019 15:07:39 +0000 (15:07 +0000)
Our for loops are like C style for loops, with an initial value,
condition and step.

We begin generating code by setting up the loop in the preheader. Here
we generate the initial value and compare it to the condition, finishing
early if we need to.

The main loop begins with choosing either the initial value, or the
incremented value for the loop variable (usually called the induction
variable). We can then put this inside the binding environment whenever
we generate the body expression with the `runReaderT` function: This
lets the body access the induction variable with the associated name,
without having to change our Reader transformer into a State
transformer.

Once we've generated the body, we just need to increment the induction
variable by the step, and check if the condition is met. Then depending
on the result of that we either branch back up to the top of the loop,
or to the after block to exit.

You might have noticed that we don't have any side-effects at the
moment, so you can't tell what went on inside a loop - it always
evaluates to zero. We're going to add something to do inside these loops
next.

Main.hs

diff --git a/Main.hs b/Main.hs
index 749f77188172479f341a8018650af7549c2d0c02..97407fee2fbf6ef7907f3f45a934e737fa29d593 100644 (file)
--- a/Main.hs
+++ b/Main.hs
@@ -163,3 +163,39 @@ buildExpr (If cond thenE elseE) = mdo
 
   mergeB <- block `named` "ifcont"
   phi [(thenOp, thenB), (elseOp, elseB)]
+
+buildExpr (For name init cond mStep body) = mdo
+  preheaderB <- block `named` "preheader"
+
+  initV <- buildExpr init `named` "init"
+  
+  -- build the condition expression with 'i' in the bindings
+  initCondV <- withReaderT (Map.insert name initV) $
+                (buildExpr cond >>= fcmp ONE zero) `named` "initcond"
+
+  -- skip the loop if we don't meet the condition with the init
+  condBr initCondV loopB afterB
+
+  loopB <- block `named` "loop"
+  i <- phi [(initV, preheaderB), (nextVar, loopB)] `named` "i"
+
+  -- build the body expression with 'i' in the bindings
+  withReaderT (Map.insert name i) $ buildExpr body `named` "body"
+
+  -- default to 1 if there's no step defined
+  stepV <- case mStep of
+    Just step -> buildExpr step
+    Nothing -> return $ ConstantOperand (Float (Double 1))
+
+  nextVar <- fadd i stepV `named` "nextvar"
+
+  let zero = ConstantOperand (Float (Double 0))
+  -- again we need 'i' in the bindings
+  condV <- withReaderT (Map.insert name i) $
+            (buildExpr cond >>= fcmp ONE zero) `named` "cond"
+  condBr condV loopB afterB
+
+  afterB <- block `named` "after"
+  -- since a for loop doesn't really have a value, return 0
+  return $ ConstantOperand (Float (Double 0))
+