Adding loops (MPC -> LLVM for the Neil Language #5)
This is part of a series, the first four parts of the series can be found at:
- Hooking up MPC & LLVM
- Cleaning up the parser
- Adding type identifiers
- Adding branching
In this post, we’ll cover how to add loops to our little toy language I’m calling Neil - Not Exactly an Intermediate Language.
To keep things simple, I’ve decided to add loops of the form:
Grammar Changes⌗
We need to add a new kind of statement to the grammar, one for our while loops:
And with this one change, because we have already handled boolean expression in the additions for branching, we can handle our loops.
How to Handle Loops⌗
Loops are basically branching - the only caveat is that we are going to branch backwards to previous, already executed, basic blocks.
For every while statement we create two new basic blocks. Whatever basic block we are in (in the above example one called ‘entry’) will then conditionally enter the loop by branching either to the ‘while_body’ block (that will contain any statements within the while loop), or by branching to the ‘while_merge’ basic block. Within the body of the loop, the ‘while_body’ basic block will then conditionally (based on the bexp part of the grammar change) loop back to itself, or to the ‘while_merge’. This means that all loops converge as the loop finishes - they will always execute ‘while_merge’ whether the loop is entered or not.
Handling Whiles⌗
To handle while statements:
- we get an LLVMValueRef for the boolean expression - using LLVMBuildICmp or LLVMBuildFCmp to do so
- once we have our expression, we increment the scope as all symbols need to be in the new scope level
- we create two new basic blocks, one for ‘while_body’ and one for ‘while_merge'
- we use LLVMBuildCondBr to branch, based on the LLVMValueRef for the condition, to either ‘while_body’ or ‘while_merge'
- we then set the LLVMBuilderRef that we are using to build in the ‘while_body’ basic block
- then we lower the statements in the while statement (which will all be placed within the ‘while_body’ basic block)
- and after all statements in the while statement have been processed, we re-evaluate the boolean expression for the while loop, then use LLVMBuildCondBr to conditionally branch to ‘while_merge’, or back to ‘while_body’ if the while loop had more iterations required
- and lastly set the LLVMBuilderRef to add any new statements into the ‘while_merge’ basic block
And it really is that simple! All the changes we made previously to handle if statements meant that this was a really easy change to add to the language.
Result⌗
Now our simple example looks like so:
And turns into the following LLVM IR:
You can check out the full GitHub pull request for the feature here.
In the next post, we’ll look into how we can add support for pointers to the language, stay tuned!