From: Luke Lau Date: Wed, 5 Jun 2019 21:31:04 +0000 (+0100) Subject: Generate code for if statements X-Git-Url: http://git.lukelau.me/?p=kaleidoscope-hs.git;a=commitdiff_plain;h=e3ba36b0fd73d28d041de61ed7d6bf590ef34f18 Generate code for if statements Hopefully you found this addition straightforward and enjoyable, now that we have all the infrastructure in place. Let's walk through this step by step. We first start off our loop by creating a basic block called "if". A basic block is a chunk of code that has a single entry and exit point, and in this block we're putting in the condition expression. Since everything in Kaleidoscope is a double (yuck), we need to compare it to zero to get a boolean that we can actually branch with. After branching we create two other basic blocks labelled "then" and "else", containing the then and else expressions of the branch respectively. They both branch back to the final basic block, "ifcont". Now since LLVM IR is in SSA (single static assignment) form, the then and else branches both write to separate variables: We can't write to the same variable twice. In order to actually differentiate between the then expression and the else expression, we use a phi node in the merge block. Depending on what basic block it arrived from, it will use either one of two operands that we've passed to it. In this case, we use it to return the then expression if the then branch was taken, or the else expression if the else branch was taken. Phi nodes are very common in LLVM IR, and open up lots of optimisations by allowing us to stay in SSA form. You might have also noticed that unlike the C++ tutorial, we didn't need to rewind our builder back and generate the "mergeB" block first. In fact, we actually end up referencing mergeB before it is even declared! How can this be possible? Through recursive do! The MonadFix instance on IRBuilder allow us to exploit laziness and use mdo to refer to variables that haven't yet been evaluated. --- diff --git a/Main.hs b/Main.hs index 468573d..749f771 100644 --- a/Main.hs +++ b/Main.hs @@ -1,4 +1,5 @@ {-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE RecursiveDo #-} import AST as K -- K for Kaleidoscope import Utils @@ -141,3 +142,24 @@ buildExpr (Call callee params) = do ptrTyp = Type.PointerType typ (AddrSpace 0) ref = GlobalReference ptrTyp nam call (ConstantOperand ref) (zip paramOps (repeat [])) + +buildExpr (If cond thenE elseE) = mdo + _ifB <- block `named` "if" + + -- since everything is a double, false == 0 + let zero = ConstantOperand (Float (Double 0)) + condV <- buildExpr cond + cmp <- fcmp ONE zero condV `named` "cmp" + + condBr cmp thenB elseB + + thenB <- block `named` "then" + thenOp <- buildExpr thenE + br mergeB + + elseB <- block `named` "else" + elseOp <- buildExpr elseE + br mergeB + + mergeB <- block `named` "ifcont" + phi [(thenOp, thenB), (elseOp, elseB)]