1*9880d681SAndroid Build Coastguard Worker======================================================= 2*9880d681SAndroid Build Coastguard WorkerKaleidoscope: Extending the Language: Mutable Variables 3*9880d681SAndroid Build Coastguard Worker======================================================= 4*9880d681SAndroid Build Coastguard Worker 5*9880d681SAndroid Build Coastguard Worker.. contents:: 6*9880d681SAndroid Build Coastguard Worker :local: 7*9880d681SAndroid Build Coastguard Worker 8*9880d681SAndroid Build Coastguard WorkerChapter 7 Introduction 9*9880d681SAndroid Build Coastguard Worker====================== 10*9880d681SAndroid Build Coastguard Worker 11*9880d681SAndroid Build Coastguard WorkerWelcome to Chapter 7 of the "`Implementing a language with 12*9880d681SAndroid Build Coastguard WorkerLLVM <index.html>`_" tutorial. In chapters 1 through 6, we've built a 13*9880d681SAndroid Build Coastguard Workervery respectable, albeit simple, `functional programming 14*9880d681SAndroid Build Coastguard Workerlanguage <http://en.wikipedia.org/wiki/Functional_programming>`_. In our 15*9880d681SAndroid Build Coastguard Workerjourney, we learned some parsing techniques, how to build and represent 16*9880d681SAndroid Build Coastguard Workeran AST, how to build LLVM IR, and how to optimize the resultant code as 17*9880d681SAndroid Build Coastguard Workerwell as JIT compile it. 18*9880d681SAndroid Build Coastguard Worker 19*9880d681SAndroid Build Coastguard WorkerWhile Kaleidoscope is interesting as a functional language, the fact 20*9880d681SAndroid Build Coastguard Workerthat it is functional makes it "too easy" to generate LLVM IR for it. In 21*9880d681SAndroid Build Coastguard Workerparticular, a functional language makes it very easy to build LLVM IR 22*9880d681SAndroid Build Coastguard Workerdirectly in `SSA 23*9880d681SAndroid Build Coastguard Workerform <http://en.wikipedia.org/wiki/Static_single_assignment_form>`_. 24*9880d681SAndroid Build Coastguard WorkerSince LLVM requires that the input code be in SSA form, this is a very 25*9880d681SAndroid Build Coastguard Workernice property and it is often unclear to newcomers how to generate code 26*9880d681SAndroid Build Coastguard Workerfor an imperative language with mutable variables. 27*9880d681SAndroid Build Coastguard Worker 28*9880d681SAndroid Build Coastguard WorkerThe short (and happy) summary of this chapter is that there is no need 29*9880d681SAndroid Build Coastguard Workerfor your front-end to build SSA form: LLVM provides highly tuned and 30*9880d681SAndroid Build Coastguard Workerwell tested support for this, though the way it works is a bit 31*9880d681SAndroid Build Coastguard Workerunexpected for some. 32*9880d681SAndroid Build Coastguard Worker 33*9880d681SAndroid Build Coastguard WorkerWhy is this a hard problem? 34*9880d681SAndroid Build Coastguard Worker=========================== 35*9880d681SAndroid Build Coastguard Worker 36*9880d681SAndroid Build Coastguard WorkerTo understand why mutable variables cause complexities in SSA 37*9880d681SAndroid Build Coastguard Workerconstruction, consider this extremely simple C example: 38*9880d681SAndroid Build Coastguard Worker 39*9880d681SAndroid Build Coastguard Worker.. code-block:: c 40*9880d681SAndroid Build Coastguard Worker 41*9880d681SAndroid Build Coastguard Worker int G, H; 42*9880d681SAndroid Build Coastguard Worker int test(_Bool Condition) { 43*9880d681SAndroid Build Coastguard Worker int X; 44*9880d681SAndroid Build Coastguard Worker if (Condition) 45*9880d681SAndroid Build Coastguard Worker X = G; 46*9880d681SAndroid Build Coastguard Worker else 47*9880d681SAndroid Build Coastguard Worker X = H; 48*9880d681SAndroid Build Coastguard Worker return X; 49*9880d681SAndroid Build Coastguard Worker } 50*9880d681SAndroid Build Coastguard Worker 51*9880d681SAndroid Build Coastguard WorkerIn this case, we have the variable "X", whose value depends on the path 52*9880d681SAndroid Build Coastguard Workerexecuted in the program. Because there are two different possible values 53*9880d681SAndroid Build Coastguard Workerfor X before the return instruction, a PHI node is inserted to merge the 54*9880d681SAndroid Build Coastguard Workertwo values. The LLVM IR that we want for this example looks like this: 55*9880d681SAndroid Build Coastguard Worker 56*9880d681SAndroid Build Coastguard Worker.. code-block:: llvm 57*9880d681SAndroid Build Coastguard Worker 58*9880d681SAndroid Build Coastguard Worker @G = weak global i32 0 ; type of @G is i32* 59*9880d681SAndroid Build Coastguard Worker @H = weak global i32 0 ; type of @H is i32* 60*9880d681SAndroid Build Coastguard Worker 61*9880d681SAndroid Build Coastguard Worker define i32 @test(i1 %Condition) { 62*9880d681SAndroid Build Coastguard Worker entry: 63*9880d681SAndroid Build Coastguard Worker br i1 %Condition, label %cond_true, label %cond_false 64*9880d681SAndroid Build Coastguard Worker 65*9880d681SAndroid Build Coastguard Worker cond_true: 66*9880d681SAndroid Build Coastguard Worker %X.0 = load i32* @G 67*9880d681SAndroid Build Coastguard Worker br label %cond_next 68*9880d681SAndroid Build Coastguard Worker 69*9880d681SAndroid Build Coastguard Worker cond_false: 70*9880d681SAndroid Build Coastguard Worker %X.1 = load i32* @H 71*9880d681SAndroid Build Coastguard Worker br label %cond_next 72*9880d681SAndroid Build Coastguard Worker 73*9880d681SAndroid Build Coastguard Worker cond_next: 74*9880d681SAndroid Build Coastguard Worker %X.2 = phi i32 [ %X.1, %cond_false ], [ %X.0, %cond_true ] 75*9880d681SAndroid Build Coastguard Worker ret i32 %X.2 76*9880d681SAndroid Build Coastguard Worker } 77*9880d681SAndroid Build Coastguard Worker 78*9880d681SAndroid Build Coastguard WorkerIn this example, the loads from the G and H global variables are 79*9880d681SAndroid Build Coastguard Workerexplicit in the LLVM IR, and they live in the then/else branches of the 80*9880d681SAndroid Build Coastguard Workerif statement (cond\_true/cond\_false). In order to merge the incoming 81*9880d681SAndroid Build Coastguard Workervalues, the X.2 phi node in the cond\_next block selects the right value 82*9880d681SAndroid Build Coastguard Workerto use based on where control flow is coming from: if control flow comes 83*9880d681SAndroid Build Coastguard Workerfrom the cond\_false block, X.2 gets the value of X.1. Alternatively, if 84*9880d681SAndroid Build Coastguard Workercontrol flow comes from cond\_true, it gets the value of X.0. The intent 85*9880d681SAndroid Build Coastguard Workerof this chapter is not to explain the details of SSA form. For more 86*9880d681SAndroid Build Coastguard Workerinformation, see one of the many `online 87*9880d681SAndroid Build Coastguard Workerreferences <http://en.wikipedia.org/wiki/Static_single_assignment_form>`_. 88*9880d681SAndroid Build Coastguard Worker 89*9880d681SAndroid Build Coastguard WorkerThe question for this article is "who places the phi nodes when lowering 90*9880d681SAndroid Build Coastguard Workerassignments to mutable variables?". The issue here is that LLVM 91*9880d681SAndroid Build Coastguard Worker*requires* that its IR be in SSA form: there is no "non-ssa" mode for 92*9880d681SAndroid Build Coastguard Workerit. However, SSA construction requires non-trivial algorithms and data 93*9880d681SAndroid Build Coastguard Workerstructures, so it is inconvenient and wasteful for every front-end to 94*9880d681SAndroid Build Coastguard Workerhave to reproduce this logic. 95*9880d681SAndroid Build Coastguard Worker 96*9880d681SAndroid Build Coastguard WorkerMemory in LLVM 97*9880d681SAndroid Build Coastguard Worker============== 98*9880d681SAndroid Build Coastguard Worker 99*9880d681SAndroid Build Coastguard WorkerThe 'trick' here is that while LLVM does require all register values to 100*9880d681SAndroid Build Coastguard Workerbe in SSA form, it does not require (or permit) memory objects to be in 101*9880d681SAndroid Build Coastguard WorkerSSA form. In the example above, note that the loads from G and H are 102*9880d681SAndroid Build Coastguard Workerdirect accesses to G and H: they are not renamed or versioned. This 103*9880d681SAndroid Build Coastguard Workerdiffers from some other compiler systems, which do try to version memory 104*9880d681SAndroid Build Coastguard Workerobjects. In LLVM, instead of encoding dataflow analysis of memory into 105*9880d681SAndroid Build Coastguard Workerthe LLVM IR, it is handled with `Analysis 106*9880d681SAndroid Build Coastguard WorkerPasses <../WritingAnLLVMPass.html>`_ which are computed on demand. 107*9880d681SAndroid Build Coastguard Worker 108*9880d681SAndroid Build Coastguard WorkerWith this in mind, the high-level idea is that we want to make a stack 109*9880d681SAndroid Build Coastguard Workervariable (which lives in memory, because it is on the stack) for each 110*9880d681SAndroid Build Coastguard Workermutable object in a function. To take advantage of this trick, we need 111*9880d681SAndroid Build Coastguard Workerto talk about how LLVM represents stack variables. 112*9880d681SAndroid Build Coastguard Worker 113*9880d681SAndroid Build Coastguard WorkerIn LLVM, all memory accesses are explicit with load/store instructions, 114*9880d681SAndroid Build Coastguard Workerand it is carefully designed not to have (or need) an "address-of" 115*9880d681SAndroid Build Coastguard Workeroperator. Notice how the type of the @G/@H global variables is actually 116*9880d681SAndroid Build Coastguard Worker"i32\*" even though the variable is defined as "i32". What this means is 117*9880d681SAndroid Build Coastguard Workerthat @G defines *space* for an i32 in the global data area, but its 118*9880d681SAndroid Build Coastguard Worker*name* actually refers to the address for that space. Stack variables 119*9880d681SAndroid Build Coastguard Workerwork the same way, except that instead of being declared with global 120*9880d681SAndroid Build Coastguard Workervariable definitions, they are declared with the `LLVM alloca 121*9880d681SAndroid Build Coastguard Workerinstruction <../LangRef.html#alloca-instruction>`_: 122*9880d681SAndroid Build Coastguard Worker 123*9880d681SAndroid Build Coastguard Worker.. code-block:: llvm 124*9880d681SAndroid Build Coastguard Worker 125*9880d681SAndroid Build Coastguard Worker define i32 @example() { 126*9880d681SAndroid Build Coastguard Worker entry: 127*9880d681SAndroid Build Coastguard Worker %X = alloca i32 ; type of %X is i32*. 128*9880d681SAndroid Build Coastguard Worker ... 129*9880d681SAndroid Build Coastguard Worker %tmp = load i32* %X ; load the stack value %X from the stack. 130*9880d681SAndroid Build Coastguard Worker %tmp2 = add i32 %tmp, 1 ; increment it 131*9880d681SAndroid Build Coastguard Worker store i32 %tmp2, i32* %X ; store it back 132*9880d681SAndroid Build Coastguard Worker ... 133*9880d681SAndroid Build Coastguard Worker 134*9880d681SAndroid Build Coastguard WorkerThis code shows an example of how you can declare and manipulate a stack 135*9880d681SAndroid Build Coastguard Workervariable in the LLVM IR. Stack memory allocated with the alloca 136*9880d681SAndroid Build Coastguard Workerinstruction is fully general: you can pass the address of the stack slot 137*9880d681SAndroid Build Coastguard Workerto functions, you can store it in other variables, etc. In our example 138*9880d681SAndroid Build Coastguard Workerabove, we could rewrite the example to use the alloca technique to avoid 139*9880d681SAndroid Build Coastguard Workerusing a PHI node: 140*9880d681SAndroid Build Coastguard Worker 141*9880d681SAndroid Build Coastguard Worker.. code-block:: llvm 142*9880d681SAndroid Build Coastguard Worker 143*9880d681SAndroid Build Coastguard Worker @G = weak global i32 0 ; type of @G is i32* 144*9880d681SAndroid Build Coastguard Worker @H = weak global i32 0 ; type of @H is i32* 145*9880d681SAndroid Build Coastguard Worker 146*9880d681SAndroid Build Coastguard Worker define i32 @test(i1 %Condition) { 147*9880d681SAndroid Build Coastguard Worker entry: 148*9880d681SAndroid Build Coastguard Worker %X = alloca i32 ; type of %X is i32*. 149*9880d681SAndroid Build Coastguard Worker br i1 %Condition, label %cond_true, label %cond_false 150*9880d681SAndroid Build Coastguard Worker 151*9880d681SAndroid Build Coastguard Worker cond_true: 152*9880d681SAndroid Build Coastguard Worker %X.0 = load i32* @G 153*9880d681SAndroid Build Coastguard Worker store i32 %X.0, i32* %X ; Update X 154*9880d681SAndroid Build Coastguard Worker br label %cond_next 155*9880d681SAndroid Build Coastguard Worker 156*9880d681SAndroid Build Coastguard Worker cond_false: 157*9880d681SAndroid Build Coastguard Worker %X.1 = load i32* @H 158*9880d681SAndroid Build Coastguard Worker store i32 %X.1, i32* %X ; Update X 159*9880d681SAndroid Build Coastguard Worker br label %cond_next 160*9880d681SAndroid Build Coastguard Worker 161*9880d681SAndroid Build Coastguard Worker cond_next: 162*9880d681SAndroid Build Coastguard Worker %X.2 = load i32* %X ; Read X 163*9880d681SAndroid Build Coastguard Worker ret i32 %X.2 164*9880d681SAndroid Build Coastguard Worker } 165*9880d681SAndroid Build Coastguard Worker 166*9880d681SAndroid Build Coastguard WorkerWith this, we have discovered a way to handle arbitrary mutable 167*9880d681SAndroid Build Coastguard Workervariables without the need to create Phi nodes at all: 168*9880d681SAndroid Build Coastguard Worker 169*9880d681SAndroid Build Coastguard Worker#. Each mutable variable becomes a stack allocation. 170*9880d681SAndroid Build Coastguard Worker#. Each read of the variable becomes a load from the stack. 171*9880d681SAndroid Build Coastguard Worker#. Each update of the variable becomes a store to the stack. 172*9880d681SAndroid Build Coastguard Worker#. Taking the address of a variable just uses the stack address 173*9880d681SAndroid Build Coastguard Worker directly. 174*9880d681SAndroid Build Coastguard Worker 175*9880d681SAndroid Build Coastguard WorkerWhile this solution has solved our immediate problem, it introduced 176*9880d681SAndroid Build Coastguard Workeranother one: we have now apparently introduced a lot of stack traffic 177*9880d681SAndroid Build Coastguard Workerfor very simple and common operations, a major performance problem. 178*9880d681SAndroid Build Coastguard WorkerFortunately for us, the LLVM optimizer has a highly-tuned optimization 179*9880d681SAndroid Build Coastguard Workerpass named "mem2reg" that handles this case, promoting allocas like this 180*9880d681SAndroid Build Coastguard Workerinto SSA registers, inserting Phi nodes as appropriate. If you run this 181*9880d681SAndroid Build Coastguard Workerexample through the pass, for example, you'll get: 182*9880d681SAndroid Build Coastguard Worker 183*9880d681SAndroid Build Coastguard Worker.. code-block:: bash 184*9880d681SAndroid Build Coastguard Worker 185*9880d681SAndroid Build Coastguard Worker $ llvm-as < example.ll | opt -mem2reg | llvm-dis 186*9880d681SAndroid Build Coastguard Worker @G = weak global i32 0 187*9880d681SAndroid Build Coastguard Worker @H = weak global i32 0 188*9880d681SAndroid Build Coastguard Worker 189*9880d681SAndroid Build Coastguard Worker define i32 @test(i1 %Condition) { 190*9880d681SAndroid Build Coastguard Worker entry: 191*9880d681SAndroid Build Coastguard Worker br i1 %Condition, label %cond_true, label %cond_false 192*9880d681SAndroid Build Coastguard Worker 193*9880d681SAndroid Build Coastguard Worker cond_true: 194*9880d681SAndroid Build Coastguard Worker %X.0 = load i32* @G 195*9880d681SAndroid Build Coastguard Worker br label %cond_next 196*9880d681SAndroid Build Coastguard Worker 197*9880d681SAndroid Build Coastguard Worker cond_false: 198*9880d681SAndroid Build Coastguard Worker %X.1 = load i32* @H 199*9880d681SAndroid Build Coastguard Worker br label %cond_next 200*9880d681SAndroid Build Coastguard Worker 201*9880d681SAndroid Build Coastguard Worker cond_next: 202*9880d681SAndroid Build Coastguard Worker %X.01 = phi i32 [ %X.1, %cond_false ], [ %X.0, %cond_true ] 203*9880d681SAndroid Build Coastguard Worker ret i32 %X.01 204*9880d681SAndroid Build Coastguard Worker } 205*9880d681SAndroid Build Coastguard Worker 206*9880d681SAndroid Build Coastguard WorkerThe mem2reg pass implements the standard "iterated dominance frontier" 207*9880d681SAndroid Build Coastguard Workeralgorithm for constructing SSA form and has a number of optimizations 208*9880d681SAndroid Build Coastguard Workerthat speed up (very common) degenerate cases. The mem2reg optimization 209*9880d681SAndroid Build Coastguard Workerpass is the answer to dealing with mutable variables, and we highly 210*9880d681SAndroid Build Coastguard Workerrecommend that you depend on it. Note that mem2reg only works on 211*9880d681SAndroid Build Coastguard Workervariables in certain circumstances: 212*9880d681SAndroid Build Coastguard Worker 213*9880d681SAndroid Build Coastguard Worker#. mem2reg is alloca-driven: it looks for allocas and if it can handle 214*9880d681SAndroid Build Coastguard Worker them, it promotes them. It does not apply to global variables or heap 215*9880d681SAndroid Build Coastguard Worker allocations. 216*9880d681SAndroid Build Coastguard Worker#. mem2reg only looks for alloca instructions in the entry block of the 217*9880d681SAndroid Build Coastguard Worker function. Being in the entry block guarantees that the alloca is only 218*9880d681SAndroid Build Coastguard Worker executed once, which makes analysis simpler. 219*9880d681SAndroid Build Coastguard Worker#. mem2reg only promotes allocas whose uses are direct loads and stores. 220*9880d681SAndroid Build Coastguard Worker If the address of the stack object is passed to a function, or if any 221*9880d681SAndroid Build Coastguard Worker funny pointer arithmetic is involved, the alloca will not be 222*9880d681SAndroid Build Coastguard Worker promoted. 223*9880d681SAndroid Build Coastguard Worker#. mem2reg only works on allocas of `first 224*9880d681SAndroid Build Coastguard Worker class <../LangRef.html#first-class-types>`_ values (such as pointers, 225*9880d681SAndroid Build Coastguard Worker scalars and vectors), and only if the array size of the allocation is 226*9880d681SAndroid Build Coastguard Worker 1 (or missing in the .ll file). mem2reg is not capable of promoting 227*9880d681SAndroid Build Coastguard Worker structs or arrays to registers. Note that the "sroa" pass is 228*9880d681SAndroid Build Coastguard Worker more powerful and can promote structs, "unions", and arrays in many 229*9880d681SAndroid Build Coastguard Worker cases. 230*9880d681SAndroid Build Coastguard Worker 231*9880d681SAndroid Build Coastguard WorkerAll of these properties are easy to satisfy for most imperative 232*9880d681SAndroid Build Coastguard Workerlanguages, and we'll illustrate it below with Kaleidoscope. The final 233*9880d681SAndroid Build Coastguard Workerquestion you may be asking is: should I bother with this nonsense for my 234*9880d681SAndroid Build Coastguard Workerfront-end? Wouldn't it be better if I just did SSA construction 235*9880d681SAndroid Build Coastguard Workerdirectly, avoiding use of the mem2reg optimization pass? In short, we 236*9880d681SAndroid Build Coastguard Workerstrongly recommend that you use this technique for building SSA form, 237*9880d681SAndroid Build Coastguard Workerunless there is an extremely good reason not to. Using this technique 238*9880d681SAndroid Build Coastguard Workeris: 239*9880d681SAndroid Build Coastguard Worker 240*9880d681SAndroid Build Coastguard Worker- Proven and well tested: clang uses this technique 241*9880d681SAndroid Build Coastguard Worker for local mutable variables. As such, the most common clients of LLVM 242*9880d681SAndroid Build Coastguard Worker are using this to handle a bulk of their variables. You can be sure 243*9880d681SAndroid Build Coastguard Worker that bugs are found fast and fixed early. 244*9880d681SAndroid Build Coastguard Worker- Extremely Fast: mem2reg has a number of special cases that make it 245*9880d681SAndroid Build Coastguard Worker fast in common cases as well as fully general. For example, it has 246*9880d681SAndroid Build Coastguard Worker fast-paths for variables that are only used in a single block, 247*9880d681SAndroid Build Coastguard Worker variables that only have one assignment point, good heuristics to 248*9880d681SAndroid Build Coastguard Worker avoid insertion of unneeded phi nodes, etc. 249*9880d681SAndroid Build Coastguard Worker- Needed for debug info generation: `Debug information in 250*9880d681SAndroid Build Coastguard Worker LLVM <../SourceLevelDebugging.html>`_ relies on having the address of 251*9880d681SAndroid Build Coastguard Worker the variable exposed so that debug info can be attached to it. This 252*9880d681SAndroid Build Coastguard Worker technique dovetails very naturally with this style of debug info. 253*9880d681SAndroid Build Coastguard Worker 254*9880d681SAndroid Build Coastguard WorkerIf nothing else, this makes it much easier to get your front-end up and 255*9880d681SAndroid Build Coastguard Workerrunning, and is very simple to implement. Lets extend Kaleidoscope with 256*9880d681SAndroid Build Coastguard Workermutable variables now! 257*9880d681SAndroid Build Coastguard Worker 258*9880d681SAndroid Build Coastguard WorkerMutable Variables in Kaleidoscope 259*9880d681SAndroid Build Coastguard Worker================================= 260*9880d681SAndroid Build Coastguard Worker 261*9880d681SAndroid Build Coastguard WorkerNow that we know the sort of problem we want to tackle, lets see what 262*9880d681SAndroid Build Coastguard Workerthis looks like in the context of our little Kaleidoscope language. 263*9880d681SAndroid Build Coastguard WorkerWe're going to add two features: 264*9880d681SAndroid Build Coastguard Worker 265*9880d681SAndroid Build Coastguard Worker#. The ability to mutate variables with the '=' operator. 266*9880d681SAndroid Build Coastguard Worker#. The ability to define new variables. 267*9880d681SAndroid Build Coastguard Worker 268*9880d681SAndroid Build Coastguard WorkerWhile the first item is really what this is about, we only have 269*9880d681SAndroid Build Coastguard Workervariables for incoming arguments as well as for induction variables, and 270*9880d681SAndroid Build Coastguard Workerredefining those only goes so far :). Also, the ability to define new 271*9880d681SAndroid Build Coastguard Workervariables is a useful thing regardless of whether you will be mutating 272*9880d681SAndroid Build Coastguard Workerthem. Here's a motivating example that shows how we could use these: 273*9880d681SAndroid Build Coastguard Worker 274*9880d681SAndroid Build Coastguard Worker:: 275*9880d681SAndroid Build Coastguard Worker 276*9880d681SAndroid Build Coastguard Worker # Define ':' for sequencing: as a low-precedence operator that ignores operands 277*9880d681SAndroid Build Coastguard Worker # and just returns the RHS. 278*9880d681SAndroid Build Coastguard Worker def binary : 1 (x y) y; 279*9880d681SAndroid Build Coastguard Worker 280*9880d681SAndroid Build Coastguard Worker # Recursive fib, we could do this before. 281*9880d681SAndroid Build Coastguard Worker def fib(x) 282*9880d681SAndroid Build Coastguard Worker if (x < 3) then 283*9880d681SAndroid Build Coastguard Worker 1 284*9880d681SAndroid Build Coastguard Worker else 285*9880d681SAndroid Build Coastguard Worker fib(x-1)+fib(x-2); 286*9880d681SAndroid Build Coastguard Worker 287*9880d681SAndroid Build Coastguard Worker # Iterative fib. 288*9880d681SAndroid Build Coastguard Worker def fibi(x) 289*9880d681SAndroid Build Coastguard Worker var a = 1, b = 1, c in 290*9880d681SAndroid Build Coastguard Worker (for i = 3, i < x in 291*9880d681SAndroid Build Coastguard Worker c = a + b : 292*9880d681SAndroid Build Coastguard Worker a = b : 293*9880d681SAndroid Build Coastguard Worker b = c) : 294*9880d681SAndroid Build Coastguard Worker b; 295*9880d681SAndroid Build Coastguard Worker 296*9880d681SAndroid Build Coastguard Worker # Call it. 297*9880d681SAndroid Build Coastguard Worker fibi(10); 298*9880d681SAndroid Build Coastguard Worker 299*9880d681SAndroid Build Coastguard WorkerIn order to mutate variables, we have to change our existing variables 300*9880d681SAndroid Build Coastguard Workerto use the "alloca trick". Once we have that, we'll add our new 301*9880d681SAndroid Build Coastguard Workeroperator, then extend Kaleidoscope to support new variable definitions. 302*9880d681SAndroid Build Coastguard Worker 303*9880d681SAndroid Build Coastguard WorkerAdjusting Existing Variables for Mutation 304*9880d681SAndroid Build Coastguard Worker========================================= 305*9880d681SAndroid Build Coastguard Worker 306*9880d681SAndroid Build Coastguard WorkerThe symbol table in Kaleidoscope is managed at code generation time by 307*9880d681SAndroid Build Coastguard Workerthe '``named_values``' map. This map currently keeps track of the LLVM 308*9880d681SAndroid Build Coastguard Worker"Value\*" that holds the double value for the named variable. In order 309*9880d681SAndroid Build Coastguard Workerto support mutation, we need to change this slightly, so that it 310*9880d681SAndroid Build Coastguard Worker``named_values`` holds the *memory location* of the variable in 311*9880d681SAndroid Build Coastguard Workerquestion. Note that this change is a refactoring: it changes the 312*9880d681SAndroid Build Coastguard Workerstructure of the code, but does not (by itself) change the behavior of 313*9880d681SAndroid Build Coastguard Workerthe compiler. All of these changes are isolated in the Kaleidoscope code 314*9880d681SAndroid Build Coastguard Workergenerator. 315*9880d681SAndroid Build Coastguard Worker 316*9880d681SAndroid Build Coastguard WorkerAt this point in Kaleidoscope's development, it only supports variables 317*9880d681SAndroid Build Coastguard Workerfor two things: incoming arguments to functions and the induction 318*9880d681SAndroid Build Coastguard Workervariable of 'for' loops. For consistency, we'll allow mutation of these 319*9880d681SAndroid Build Coastguard Workervariables in addition to other user-defined variables. This means that 320*9880d681SAndroid Build Coastguard Workerthese will both need memory locations. 321*9880d681SAndroid Build Coastguard Worker 322*9880d681SAndroid Build Coastguard WorkerTo start our transformation of Kaleidoscope, we'll change the 323*9880d681SAndroid Build Coastguard Worker``named_values`` map so that it maps to AllocaInst\* instead of Value\*. 324*9880d681SAndroid Build Coastguard WorkerOnce we do this, the C++ compiler will tell us what parts of the code we 325*9880d681SAndroid Build Coastguard Workerneed to update: 326*9880d681SAndroid Build Coastguard Worker 327*9880d681SAndroid Build Coastguard Worker**Note:** the ocaml bindings currently model both ``Value*``'s and 328*9880d681SAndroid Build Coastguard Worker``AllocInst*``'s as ``Llvm.llvalue``'s, but this may change in the future 329*9880d681SAndroid Build Coastguard Workerto be more type safe. 330*9880d681SAndroid Build Coastguard Worker 331*9880d681SAndroid Build Coastguard Worker.. code-block:: ocaml 332*9880d681SAndroid Build Coastguard Worker 333*9880d681SAndroid Build Coastguard Worker let named_values:(string, llvalue) Hashtbl.t = Hashtbl.create 10 334*9880d681SAndroid Build Coastguard Worker 335*9880d681SAndroid Build Coastguard WorkerAlso, since we will need to create these alloca's, we'll use a helper 336*9880d681SAndroid Build Coastguard Workerfunction that ensures that the allocas are created in the entry block of 337*9880d681SAndroid Build Coastguard Workerthe function: 338*9880d681SAndroid Build Coastguard Worker 339*9880d681SAndroid Build Coastguard Worker.. code-block:: ocaml 340*9880d681SAndroid Build Coastguard Worker 341*9880d681SAndroid Build Coastguard Worker (* Create an alloca instruction in the entry block of the function. This 342*9880d681SAndroid Build Coastguard Worker * is used for mutable variables etc. *) 343*9880d681SAndroid Build Coastguard Worker let create_entry_block_alloca the_function var_name = 344*9880d681SAndroid Build Coastguard Worker let builder = builder_at (instr_begin (entry_block the_function)) in 345*9880d681SAndroid Build Coastguard Worker build_alloca double_type var_name builder 346*9880d681SAndroid Build Coastguard Worker 347*9880d681SAndroid Build Coastguard WorkerThis funny looking code creates an ``Llvm.llbuilder`` object that is 348*9880d681SAndroid Build Coastguard Workerpointing at the first instruction of the entry block. It then creates an 349*9880d681SAndroid Build Coastguard Workeralloca with the expected name and returns it. Because all values in 350*9880d681SAndroid Build Coastguard WorkerKaleidoscope are doubles, there is no need to pass in a type to use. 351*9880d681SAndroid Build Coastguard Worker 352*9880d681SAndroid Build Coastguard WorkerWith this in place, the first functionality change we want to make is to 353*9880d681SAndroid Build Coastguard Workervariable references. In our new scheme, variables live on the stack, so 354*9880d681SAndroid Build Coastguard Workercode generating a reference to them actually needs to produce a load 355*9880d681SAndroid Build Coastguard Workerfrom the stack slot: 356*9880d681SAndroid Build Coastguard Worker 357*9880d681SAndroid Build Coastguard Worker.. code-block:: ocaml 358*9880d681SAndroid Build Coastguard Worker 359*9880d681SAndroid Build Coastguard Worker let rec codegen_expr = function 360*9880d681SAndroid Build Coastguard Worker ... 361*9880d681SAndroid Build Coastguard Worker | Ast.Variable name -> 362*9880d681SAndroid Build Coastguard Worker let v = try Hashtbl.find named_values name with 363*9880d681SAndroid Build Coastguard Worker | Not_found -> raise (Error "unknown variable name") 364*9880d681SAndroid Build Coastguard Worker in 365*9880d681SAndroid Build Coastguard Worker (* Load the value. *) 366*9880d681SAndroid Build Coastguard Worker build_load v name builder 367*9880d681SAndroid Build Coastguard Worker 368*9880d681SAndroid Build Coastguard WorkerAs you can see, this is pretty straightforward. Now we need to update 369*9880d681SAndroid Build Coastguard Workerthe things that define the variables to set up the alloca. We'll start 370*9880d681SAndroid Build Coastguard Workerwith ``codegen_expr Ast.For ...`` (see the `full code listing <#id1>`_ 371*9880d681SAndroid Build Coastguard Workerfor the unabridged code): 372*9880d681SAndroid Build Coastguard Worker 373*9880d681SAndroid Build Coastguard Worker.. code-block:: ocaml 374*9880d681SAndroid Build Coastguard Worker 375*9880d681SAndroid Build Coastguard Worker | Ast.For (var_name, start, end_, step, body) -> 376*9880d681SAndroid Build Coastguard Worker let the_function = block_parent (insertion_block builder) in 377*9880d681SAndroid Build Coastguard Worker 378*9880d681SAndroid Build Coastguard Worker (* Create an alloca for the variable in the entry block. *) 379*9880d681SAndroid Build Coastguard Worker let alloca = create_entry_block_alloca the_function var_name in 380*9880d681SAndroid Build Coastguard Worker 381*9880d681SAndroid Build Coastguard Worker (* Emit the start code first, without 'variable' in scope. *) 382*9880d681SAndroid Build Coastguard Worker let start_val = codegen_expr start in 383*9880d681SAndroid Build Coastguard Worker 384*9880d681SAndroid Build Coastguard Worker (* Store the value into the alloca. *) 385*9880d681SAndroid Build Coastguard Worker ignore(build_store start_val alloca builder); 386*9880d681SAndroid Build Coastguard Worker 387*9880d681SAndroid Build Coastguard Worker ... 388*9880d681SAndroid Build Coastguard Worker 389*9880d681SAndroid Build Coastguard Worker (* Within the loop, the variable is defined equal to the PHI node. If it 390*9880d681SAndroid Build Coastguard Worker * shadows an existing variable, we have to restore it, so save it 391*9880d681SAndroid Build Coastguard Worker * now. *) 392*9880d681SAndroid Build Coastguard Worker let old_val = 393*9880d681SAndroid Build Coastguard Worker try Some (Hashtbl.find named_values var_name) with Not_found -> None 394*9880d681SAndroid Build Coastguard Worker in 395*9880d681SAndroid Build Coastguard Worker Hashtbl.add named_values var_name alloca; 396*9880d681SAndroid Build Coastguard Worker 397*9880d681SAndroid Build Coastguard Worker ... 398*9880d681SAndroid Build Coastguard Worker 399*9880d681SAndroid Build Coastguard Worker (* Compute the end condition. *) 400*9880d681SAndroid Build Coastguard Worker let end_cond = codegen_expr end_ in 401*9880d681SAndroid Build Coastguard Worker 402*9880d681SAndroid Build Coastguard Worker (* Reload, increment, and restore the alloca. This handles the case where 403*9880d681SAndroid Build Coastguard Worker * the body of the loop mutates the variable. *) 404*9880d681SAndroid Build Coastguard Worker let cur_var = build_load alloca var_name builder in 405*9880d681SAndroid Build Coastguard Worker let next_var = build_add cur_var step_val "nextvar" builder in 406*9880d681SAndroid Build Coastguard Worker ignore(build_store next_var alloca builder); 407*9880d681SAndroid Build Coastguard Worker ... 408*9880d681SAndroid Build Coastguard Worker 409*9880d681SAndroid Build Coastguard WorkerThis code is virtually identical to the code `before we allowed mutable 410*9880d681SAndroid Build Coastguard Workervariables <OCamlLangImpl5.html#code-generation-for-the-for-loop>`_. The big difference is that 411*9880d681SAndroid Build Coastguard Workerwe no longer have to construct a PHI node, and we use load/store to 412*9880d681SAndroid Build Coastguard Workeraccess the variable as needed. 413*9880d681SAndroid Build Coastguard Worker 414*9880d681SAndroid Build Coastguard WorkerTo support mutable argument variables, we need to also make allocas for 415*9880d681SAndroid Build Coastguard Workerthem. The code for this is also pretty simple: 416*9880d681SAndroid Build Coastguard Worker 417*9880d681SAndroid Build Coastguard Worker.. code-block:: ocaml 418*9880d681SAndroid Build Coastguard Worker 419*9880d681SAndroid Build Coastguard Worker (* Create an alloca for each argument and register the argument in the symbol 420*9880d681SAndroid Build Coastguard Worker * table so that references to it will succeed. *) 421*9880d681SAndroid Build Coastguard Worker let create_argument_allocas the_function proto = 422*9880d681SAndroid Build Coastguard Worker let args = match proto with 423*9880d681SAndroid Build Coastguard Worker | Ast.Prototype (_, args) | Ast.BinOpPrototype (_, args, _) -> args 424*9880d681SAndroid Build Coastguard Worker in 425*9880d681SAndroid Build Coastguard Worker Array.iteri (fun i ai -> 426*9880d681SAndroid Build Coastguard Worker let var_name = args.(i) in 427*9880d681SAndroid Build Coastguard Worker (* Create an alloca for this variable. *) 428*9880d681SAndroid Build Coastguard Worker let alloca = create_entry_block_alloca the_function var_name in 429*9880d681SAndroid Build Coastguard Worker 430*9880d681SAndroid Build Coastguard Worker (* Store the initial value into the alloca. *) 431*9880d681SAndroid Build Coastguard Worker ignore(build_store ai alloca builder); 432*9880d681SAndroid Build Coastguard Worker 433*9880d681SAndroid Build Coastguard Worker (* Add arguments to variable symbol table. *) 434*9880d681SAndroid Build Coastguard Worker Hashtbl.add named_values var_name alloca; 435*9880d681SAndroid Build Coastguard Worker ) (params the_function) 436*9880d681SAndroid Build Coastguard Worker 437*9880d681SAndroid Build Coastguard WorkerFor each argument, we make an alloca, store the input value to the 438*9880d681SAndroid Build Coastguard Workerfunction into the alloca, and register the alloca as the memory location 439*9880d681SAndroid Build Coastguard Workerfor the argument. This method gets invoked by ``Codegen.codegen_func`` 440*9880d681SAndroid Build Coastguard Workerright after it sets up the entry block for the function. 441*9880d681SAndroid Build Coastguard Worker 442*9880d681SAndroid Build Coastguard WorkerThe final missing piece is adding the mem2reg pass, which allows us to 443*9880d681SAndroid Build Coastguard Workerget good codegen once again: 444*9880d681SAndroid Build Coastguard Worker 445*9880d681SAndroid Build Coastguard Worker.. code-block:: ocaml 446*9880d681SAndroid Build Coastguard Worker 447*9880d681SAndroid Build Coastguard Worker let main () = 448*9880d681SAndroid Build Coastguard Worker ... 449*9880d681SAndroid Build Coastguard Worker let the_fpm = PassManager.create_function Codegen.the_module in 450*9880d681SAndroid Build Coastguard Worker 451*9880d681SAndroid Build Coastguard Worker (* Set up the optimizer pipeline. Start with registering info about how the 452*9880d681SAndroid Build Coastguard Worker * target lays out data structures. *) 453*9880d681SAndroid Build Coastguard Worker DataLayout.add (ExecutionEngine.target_data the_execution_engine) the_fpm; 454*9880d681SAndroid Build Coastguard Worker 455*9880d681SAndroid Build Coastguard Worker (* Promote allocas to registers. *) 456*9880d681SAndroid Build Coastguard Worker add_memory_to_register_promotion the_fpm; 457*9880d681SAndroid Build Coastguard Worker 458*9880d681SAndroid Build Coastguard Worker (* Do simple "peephole" optimizations and bit-twiddling optzn. *) 459*9880d681SAndroid Build Coastguard Worker add_instruction_combining the_fpm; 460*9880d681SAndroid Build Coastguard Worker 461*9880d681SAndroid Build Coastguard Worker (* reassociate expressions. *) 462*9880d681SAndroid Build Coastguard Worker add_reassociation the_fpm; 463*9880d681SAndroid Build Coastguard Worker 464*9880d681SAndroid Build Coastguard WorkerIt is interesting to see what the code looks like before and after the 465*9880d681SAndroid Build Coastguard Workermem2reg optimization runs. For example, this is the before/after code 466*9880d681SAndroid Build Coastguard Workerfor our recursive fib function. Before the optimization: 467*9880d681SAndroid Build Coastguard Worker 468*9880d681SAndroid Build Coastguard Worker.. code-block:: llvm 469*9880d681SAndroid Build Coastguard Worker 470*9880d681SAndroid Build Coastguard Worker define double @fib(double %x) { 471*9880d681SAndroid Build Coastguard Worker entry: 472*9880d681SAndroid Build Coastguard Worker %x1 = alloca double 473*9880d681SAndroid Build Coastguard Worker store double %x, double* %x1 474*9880d681SAndroid Build Coastguard Worker %x2 = load double* %x1 475*9880d681SAndroid Build Coastguard Worker %cmptmp = fcmp ult double %x2, 3.000000e+00 476*9880d681SAndroid Build Coastguard Worker %booltmp = uitofp i1 %cmptmp to double 477*9880d681SAndroid Build Coastguard Worker %ifcond = fcmp one double %booltmp, 0.000000e+00 478*9880d681SAndroid Build Coastguard Worker br i1 %ifcond, label %then, label %else 479*9880d681SAndroid Build Coastguard Worker 480*9880d681SAndroid Build Coastguard Worker then: ; preds = %entry 481*9880d681SAndroid Build Coastguard Worker br label %ifcont 482*9880d681SAndroid Build Coastguard Worker 483*9880d681SAndroid Build Coastguard Worker else: ; preds = %entry 484*9880d681SAndroid Build Coastguard Worker %x3 = load double* %x1 485*9880d681SAndroid Build Coastguard Worker %subtmp = fsub double %x3, 1.000000e+00 486*9880d681SAndroid Build Coastguard Worker %calltmp = call double @fib(double %subtmp) 487*9880d681SAndroid Build Coastguard Worker %x4 = load double* %x1 488*9880d681SAndroid Build Coastguard Worker %subtmp5 = fsub double %x4, 2.000000e+00 489*9880d681SAndroid Build Coastguard Worker %calltmp6 = call double @fib(double %subtmp5) 490*9880d681SAndroid Build Coastguard Worker %addtmp = fadd double %calltmp, %calltmp6 491*9880d681SAndroid Build Coastguard Worker br label %ifcont 492*9880d681SAndroid Build Coastguard Worker 493*9880d681SAndroid Build Coastguard Worker ifcont: ; preds = %else, %then 494*9880d681SAndroid Build Coastguard Worker %iftmp = phi double [ 1.000000e+00, %then ], [ %addtmp, %else ] 495*9880d681SAndroid Build Coastguard Worker ret double %iftmp 496*9880d681SAndroid Build Coastguard Worker } 497*9880d681SAndroid Build Coastguard Worker 498*9880d681SAndroid Build Coastguard WorkerHere there is only one variable (x, the input argument) but you can 499*9880d681SAndroid Build Coastguard Workerstill see the extremely simple-minded code generation strategy we are 500*9880d681SAndroid Build Coastguard Workerusing. In the entry block, an alloca is created, and the initial input 501*9880d681SAndroid Build Coastguard Workervalue is stored into it. Each reference to the variable does a reload 502*9880d681SAndroid Build Coastguard Workerfrom the stack. Also, note that we didn't modify the if/then/else 503*9880d681SAndroid Build Coastguard Workerexpression, so it still inserts a PHI node. While we could make an 504*9880d681SAndroid Build Coastguard Workeralloca for it, it is actually easier to create a PHI node for it, so we 505*9880d681SAndroid Build Coastguard Workerstill just make the PHI. 506*9880d681SAndroid Build Coastguard Worker 507*9880d681SAndroid Build Coastguard WorkerHere is the code after the mem2reg pass runs: 508*9880d681SAndroid Build Coastguard Worker 509*9880d681SAndroid Build Coastguard Worker.. code-block:: llvm 510*9880d681SAndroid Build Coastguard Worker 511*9880d681SAndroid Build Coastguard Worker define double @fib(double %x) { 512*9880d681SAndroid Build Coastguard Worker entry: 513*9880d681SAndroid Build Coastguard Worker %cmptmp = fcmp ult double %x, 3.000000e+00 514*9880d681SAndroid Build Coastguard Worker %booltmp = uitofp i1 %cmptmp to double 515*9880d681SAndroid Build Coastguard Worker %ifcond = fcmp one double %booltmp, 0.000000e+00 516*9880d681SAndroid Build Coastguard Worker br i1 %ifcond, label %then, label %else 517*9880d681SAndroid Build Coastguard Worker 518*9880d681SAndroid Build Coastguard Worker then: 519*9880d681SAndroid Build Coastguard Worker br label %ifcont 520*9880d681SAndroid Build Coastguard Worker 521*9880d681SAndroid Build Coastguard Worker else: 522*9880d681SAndroid Build Coastguard Worker %subtmp = fsub double %x, 1.000000e+00 523*9880d681SAndroid Build Coastguard Worker %calltmp = call double @fib(double %subtmp) 524*9880d681SAndroid Build Coastguard Worker %subtmp5 = fsub double %x, 2.000000e+00 525*9880d681SAndroid Build Coastguard Worker %calltmp6 = call double @fib(double %subtmp5) 526*9880d681SAndroid Build Coastguard Worker %addtmp = fadd double %calltmp, %calltmp6 527*9880d681SAndroid Build Coastguard Worker br label %ifcont 528*9880d681SAndroid Build Coastguard Worker 529*9880d681SAndroid Build Coastguard Worker ifcont: ; preds = %else, %then 530*9880d681SAndroid Build Coastguard Worker %iftmp = phi double [ 1.000000e+00, %then ], [ %addtmp, %else ] 531*9880d681SAndroid Build Coastguard Worker ret double %iftmp 532*9880d681SAndroid Build Coastguard Worker } 533*9880d681SAndroid Build Coastguard Worker 534*9880d681SAndroid Build Coastguard WorkerThis is a trivial case for mem2reg, since there are no redefinitions of 535*9880d681SAndroid Build Coastguard Workerthe variable. The point of showing this is to calm your tension about 536*9880d681SAndroid Build Coastguard Workerinserting such blatent inefficiencies :). 537*9880d681SAndroid Build Coastguard Worker 538*9880d681SAndroid Build Coastguard WorkerAfter the rest of the optimizers run, we get: 539*9880d681SAndroid Build Coastguard Worker 540*9880d681SAndroid Build Coastguard Worker.. code-block:: llvm 541*9880d681SAndroid Build Coastguard Worker 542*9880d681SAndroid Build Coastguard Worker define double @fib(double %x) { 543*9880d681SAndroid Build Coastguard Worker entry: 544*9880d681SAndroid Build Coastguard Worker %cmptmp = fcmp ult double %x, 3.000000e+00 545*9880d681SAndroid Build Coastguard Worker %booltmp = uitofp i1 %cmptmp to double 546*9880d681SAndroid Build Coastguard Worker %ifcond = fcmp ueq double %booltmp, 0.000000e+00 547*9880d681SAndroid Build Coastguard Worker br i1 %ifcond, label %else, label %ifcont 548*9880d681SAndroid Build Coastguard Worker 549*9880d681SAndroid Build Coastguard Worker else: 550*9880d681SAndroid Build Coastguard Worker %subtmp = fsub double %x, 1.000000e+00 551*9880d681SAndroid Build Coastguard Worker %calltmp = call double @fib(double %subtmp) 552*9880d681SAndroid Build Coastguard Worker %subtmp5 = fsub double %x, 2.000000e+00 553*9880d681SAndroid Build Coastguard Worker %calltmp6 = call double @fib(double %subtmp5) 554*9880d681SAndroid Build Coastguard Worker %addtmp = fadd double %calltmp, %calltmp6 555*9880d681SAndroid Build Coastguard Worker ret double %addtmp 556*9880d681SAndroid Build Coastguard Worker 557*9880d681SAndroid Build Coastguard Worker ifcont: 558*9880d681SAndroid Build Coastguard Worker ret double 1.000000e+00 559*9880d681SAndroid Build Coastguard Worker } 560*9880d681SAndroid Build Coastguard Worker 561*9880d681SAndroid Build Coastguard WorkerHere we see that the simplifycfg pass decided to clone the return 562*9880d681SAndroid Build Coastguard Workerinstruction into the end of the 'else' block. This allowed it to 563*9880d681SAndroid Build Coastguard Workereliminate some branches and the PHI node. 564*9880d681SAndroid Build Coastguard Worker 565*9880d681SAndroid Build Coastguard WorkerNow that all symbol table references are updated to use stack variables, 566*9880d681SAndroid Build Coastguard Workerwe'll add the assignment operator. 567*9880d681SAndroid Build Coastguard Worker 568*9880d681SAndroid Build Coastguard WorkerNew Assignment Operator 569*9880d681SAndroid Build Coastguard Worker======================= 570*9880d681SAndroid Build Coastguard Worker 571*9880d681SAndroid Build Coastguard WorkerWith our current framework, adding a new assignment operator is really 572*9880d681SAndroid Build Coastguard Workersimple. We will parse it just like any other binary operator, but handle 573*9880d681SAndroid Build Coastguard Workerit internally (instead of allowing the user to define it). The first 574*9880d681SAndroid Build Coastguard Workerstep is to set a precedence: 575*9880d681SAndroid Build Coastguard Worker 576*9880d681SAndroid Build Coastguard Worker.. code-block:: ocaml 577*9880d681SAndroid Build Coastguard Worker 578*9880d681SAndroid Build Coastguard Worker let main () = 579*9880d681SAndroid Build Coastguard Worker (* Install standard binary operators. 580*9880d681SAndroid Build Coastguard Worker * 1 is the lowest precedence. *) 581*9880d681SAndroid Build Coastguard Worker Hashtbl.add Parser.binop_precedence '=' 2; 582*9880d681SAndroid Build Coastguard Worker Hashtbl.add Parser.binop_precedence '<' 10; 583*9880d681SAndroid Build Coastguard Worker Hashtbl.add Parser.binop_precedence '+' 20; 584*9880d681SAndroid Build Coastguard Worker Hashtbl.add Parser.binop_precedence '-' 20; 585*9880d681SAndroid Build Coastguard Worker ... 586*9880d681SAndroid Build Coastguard Worker 587*9880d681SAndroid Build Coastguard WorkerNow that the parser knows the precedence of the binary operator, it 588*9880d681SAndroid Build Coastguard Workertakes care of all the parsing and AST generation. We just need to 589*9880d681SAndroid Build Coastguard Workerimplement codegen for the assignment operator. This looks like: 590*9880d681SAndroid Build Coastguard Worker 591*9880d681SAndroid Build Coastguard Worker.. code-block:: ocaml 592*9880d681SAndroid Build Coastguard Worker 593*9880d681SAndroid Build Coastguard Worker let rec codegen_expr = function 594*9880d681SAndroid Build Coastguard Worker begin match op with 595*9880d681SAndroid Build Coastguard Worker | '=' -> 596*9880d681SAndroid Build Coastguard Worker (* Special case '=' because we don't want to emit the LHS as an 597*9880d681SAndroid Build Coastguard Worker * expression. *) 598*9880d681SAndroid Build Coastguard Worker let name = 599*9880d681SAndroid Build Coastguard Worker match lhs with 600*9880d681SAndroid Build Coastguard Worker | Ast.Variable name -> name 601*9880d681SAndroid Build Coastguard Worker | _ -> raise (Error "destination of '=' must be a variable") 602*9880d681SAndroid Build Coastguard Worker in 603*9880d681SAndroid Build Coastguard Worker 604*9880d681SAndroid Build Coastguard WorkerUnlike the rest of the binary operators, our assignment operator doesn't 605*9880d681SAndroid Build Coastguard Workerfollow the "emit LHS, emit RHS, do computation" model. As such, it is 606*9880d681SAndroid Build Coastguard Workerhandled as a special case before the other binary operators are handled. 607*9880d681SAndroid Build Coastguard WorkerThe other strange thing is that it requires the LHS to be a variable. It 608*9880d681SAndroid Build Coastguard Workeris invalid to have "(x+1) = expr" - only things like "x = expr" are 609*9880d681SAndroid Build Coastguard Workerallowed. 610*9880d681SAndroid Build Coastguard Worker 611*9880d681SAndroid Build Coastguard Worker.. code-block:: ocaml 612*9880d681SAndroid Build Coastguard Worker 613*9880d681SAndroid Build Coastguard Worker (* Codegen the rhs. *) 614*9880d681SAndroid Build Coastguard Worker let val_ = codegen_expr rhs in 615*9880d681SAndroid Build Coastguard Worker 616*9880d681SAndroid Build Coastguard Worker (* Lookup the name. *) 617*9880d681SAndroid Build Coastguard Worker let variable = try Hashtbl.find named_values name with 618*9880d681SAndroid Build Coastguard Worker | Not_found -> raise (Error "unknown variable name") 619*9880d681SAndroid Build Coastguard Worker in 620*9880d681SAndroid Build Coastguard Worker ignore(build_store val_ variable builder); 621*9880d681SAndroid Build Coastguard Worker val_ 622*9880d681SAndroid Build Coastguard Worker | _ -> 623*9880d681SAndroid Build Coastguard Worker ... 624*9880d681SAndroid Build Coastguard Worker 625*9880d681SAndroid Build Coastguard WorkerOnce we have the variable, codegen'ing the assignment is 626*9880d681SAndroid Build Coastguard Workerstraightforward: we emit the RHS of the assignment, create a store, and 627*9880d681SAndroid Build Coastguard Workerreturn the computed value. Returning a value allows for chained 628*9880d681SAndroid Build Coastguard Workerassignments like "X = (Y = Z)". 629*9880d681SAndroid Build Coastguard Worker 630*9880d681SAndroid Build Coastguard WorkerNow that we have an assignment operator, we can mutate loop variables 631*9880d681SAndroid Build Coastguard Workerand arguments. For example, we can now run code like this: 632*9880d681SAndroid Build Coastguard Worker 633*9880d681SAndroid Build Coastguard Worker:: 634*9880d681SAndroid Build Coastguard Worker 635*9880d681SAndroid Build Coastguard Worker # Function to print a double. 636*9880d681SAndroid Build Coastguard Worker extern printd(x); 637*9880d681SAndroid Build Coastguard Worker 638*9880d681SAndroid Build Coastguard Worker # Define ':' for sequencing: as a low-precedence operator that ignores operands 639*9880d681SAndroid Build Coastguard Worker # and just returns the RHS. 640*9880d681SAndroid Build Coastguard Worker def binary : 1 (x y) y; 641*9880d681SAndroid Build Coastguard Worker 642*9880d681SAndroid Build Coastguard Worker def test(x) 643*9880d681SAndroid Build Coastguard Worker printd(x) : 644*9880d681SAndroid Build Coastguard Worker x = 4 : 645*9880d681SAndroid Build Coastguard Worker printd(x); 646*9880d681SAndroid Build Coastguard Worker 647*9880d681SAndroid Build Coastguard Worker test(123); 648*9880d681SAndroid Build Coastguard Worker 649*9880d681SAndroid Build Coastguard WorkerWhen run, this example prints "123" and then "4", showing that we did 650*9880d681SAndroid Build Coastguard Workeractually mutate the value! Okay, we have now officially implemented our 651*9880d681SAndroid Build Coastguard Workergoal: getting this to work requires SSA construction in the general 652*9880d681SAndroid Build Coastguard Workercase. However, to be really useful, we want the ability to define our 653*9880d681SAndroid Build Coastguard Workerown local variables, lets add this next! 654*9880d681SAndroid Build Coastguard Worker 655*9880d681SAndroid Build Coastguard WorkerUser-defined Local Variables 656*9880d681SAndroid Build Coastguard Worker============================ 657*9880d681SAndroid Build Coastguard Worker 658*9880d681SAndroid Build Coastguard WorkerAdding var/in is just like any other other extensions we made to 659*9880d681SAndroid Build Coastguard WorkerKaleidoscope: we extend the lexer, the parser, the AST and the code 660*9880d681SAndroid Build Coastguard Workergenerator. The first step for adding our new 'var/in' construct is to 661*9880d681SAndroid Build Coastguard Workerextend the lexer. As before, this is pretty trivial, the code looks like 662*9880d681SAndroid Build Coastguard Workerthis: 663*9880d681SAndroid Build Coastguard Worker 664*9880d681SAndroid Build Coastguard Worker.. code-block:: ocaml 665*9880d681SAndroid Build Coastguard Worker 666*9880d681SAndroid Build Coastguard Worker type token = 667*9880d681SAndroid Build Coastguard Worker ... 668*9880d681SAndroid Build Coastguard Worker (* var definition *) 669*9880d681SAndroid Build Coastguard Worker | Var 670*9880d681SAndroid Build Coastguard Worker 671*9880d681SAndroid Build Coastguard Worker ... 672*9880d681SAndroid Build Coastguard Worker 673*9880d681SAndroid Build Coastguard Worker and lex_ident buffer = parser 674*9880d681SAndroid Build Coastguard Worker ... 675*9880d681SAndroid Build Coastguard Worker | "in" -> [< 'Token.In; stream >] 676*9880d681SAndroid Build Coastguard Worker | "binary" -> [< 'Token.Binary; stream >] 677*9880d681SAndroid Build Coastguard Worker | "unary" -> [< 'Token.Unary; stream >] 678*9880d681SAndroid Build Coastguard Worker | "var" -> [< 'Token.Var; stream >] 679*9880d681SAndroid Build Coastguard Worker ... 680*9880d681SAndroid Build Coastguard Worker 681*9880d681SAndroid Build Coastguard WorkerThe next step is to define the AST node that we will construct. For 682*9880d681SAndroid Build Coastguard Workervar/in, it looks like this: 683*9880d681SAndroid Build Coastguard Worker 684*9880d681SAndroid Build Coastguard Worker.. code-block:: ocaml 685*9880d681SAndroid Build Coastguard Worker 686*9880d681SAndroid Build Coastguard Worker type expr = 687*9880d681SAndroid Build Coastguard Worker ... 688*9880d681SAndroid Build Coastguard Worker (* variant for var/in. *) 689*9880d681SAndroid Build Coastguard Worker | Var of (string * expr option) array * expr 690*9880d681SAndroid Build Coastguard Worker ... 691*9880d681SAndroid Build Coastguard Worker 692*9880d681SAndroid Build Coastguard Workervar/in allows a list of names to be defined all at once, and each name 693*9880d681SAndroid Build Coastguard Workercan optionally have an initializer value. As such, we capture this 694*9880d681SAndroid Build Coastguard Workerinformation in the VarNames vector. Also, var/in has a body, this body 695*9880d681SAndroid Build Coastguard Workeris allowed to access the variables defined by the var/in. 696*9880d681SAndroid Build Coastguard Worker 697*9880d681SAndroid Build Coastguard WorkerWith this in place, we can define the parser pieces. The first thing we 698*9880d681SAndroid Build Coastguard Workerdo is add it as a primary expression: 699*9880d681SAndroid Build Coastguard Worker 700*9880d681SAndroid Build Coastguard Worker.. code-block:: ocaml 701*9880d681SAndroid Build Coastguard Worker 702*9880d681SAndroid Build Coastguard Worker (* primary 703*9880d681SAndroid Build Coastguard Worker * ::= identifier 704*9880d681SAndroid Build Coastguard Worker * ::= numberexpr 705*9880d681SAndroid Build Coastguard Worker * ::= parenexpr 706*9880d681SAndroid Build Coastguard Worker * ::= ifexpr 707*9880d681SAndroid Build Coastguard Worker * ::= forexpr 708*9880d681SAndroid Build Coastguard Worker * ::= varexpr *) 709*9880d681SAndroid Build Coastguard Worker let rec parse_primary = parser 710*9880d681SAndroid Build Coastguard Worker ... 711*9880d681SAndroid Build Coastguard Worker (* varexpr 712*9880d681SAndroid Build Coastguard Worker * ::= 'var' identifier ('=' expression? 713*9880d681SAndroid Build Coastguard Worker * (',' identifier ('=' expression)?)* 'in' expression *) 714*9880d681SAndroid Build Coastguard Worker | [< 'Token.Var; 715*9880d681SAndroid Build Coastguard Worker (* At least one variable name is required. *) 716*9880d681SAndroid Build Coastguard Worker 'Token.Ident id ?? "expected identifier after var"; 717*9880d681SAndroid Build Coastguard Worker init=parse_var_init; 718*9880d681SAndroid Build Coastguard Worker var_names=parse_var_names [(id, init)]; 719*9880d681SAndroid Build Coastguard Worker (* At this point, we have to have 'in'. *) 720*9880d681SAndroid Build Coastguard Worker 'Token.In ?? "expected 'in' keyword after 'var'"; 721*9880d681SAndroid Build Coastguard Worker body=parse_expr >] -> 722*9880d681SAndroid Build Coastguard Worker Ast.Var (Array.of_list (List.rev var_names), body) 723*9880d681SAndroid Build Coastguard Worker 724*9880d681SAndroid Build Coastguard Worker ... 725*9880d681SAndroid Build Coastguard Worker 726*9880d681SAndroid Build Coastguard Worker and parse_var_init = parser 727*9880d681SAndroid Build Coastguard Worker (* read in the optional initializer. *) 728*9880d681SAndroid Build Coastguard Worker | [< 'Token.Kwd '='; e=parse_expr >] -> Some e 729*9880d681SAndroid Build Coastguard Worker | [< >] -> None 730*9880d681SAndroid Build Coastguard Worker 731*9880d681SAndroid Build Coastguard Worker and parse_var_names accumulator = parser 732*9880d681SAndroid Build Coastguard Worker | [< 'Token.Kwd ','; 733*9880d681SAndroid Build Coastguard Worker 'Token.Ident id ?? "expected identifier list after var"; 734*9880d681SAndroid Build Coastguard Worker init=parse_var_init; 735*9880d681SAndroid Build Coastguard Worker e=parse_var_names ((id, init) :: accumulator) >] -> e 736*9880d681SAndroid Build Coastguard Worker | [< >] -> accumulator 737*9880d681SAndroid Build Coastguard Worker 738*9880d681SAndroid Build Coastguard WorkerNow that we can parse and represent the code, we need to support 739*9880d681SAndroid Build Coastguard Workeremission of LLVM IR for it. This code starts out with: 740*9880d681SAndroid Build Coastguard Worker 741*9880d681SAndroid Build Coastguard Worker.. code-block:: ocaml 742*9880d681SAndroid Build Coastguard Worker 743*9880d681SAndroid Build Coastguard Worker let rec codegen_expr = function 744*9880d681SAndroid Build Coastguard Worker ... 745*9880d681SAndroid Build Coastguard Worker | Ast.Var (var_names, body) 746*9880d681SAndroid Build Coastguard Worker let old_bindings = ref [] in 747*9880d681SAndroid Build Coastguard Worker 748*9880d681SAndroid Build Coastguard Worker let the_function = block_parent (insertion_block builder) in 749*9880d681SAndroid Build Coastguard Worker 750*9880d681SAndroid Build Coastguard Worker (* Register all variables and emit their initializer. *) 751*9880d681SAndroid Build Coastguard Worker Array.iter (fun (var_name, init) -> 752*9880d681SAndroid Build Coastguard Worker 753*9880d681SAndroid Build Coastguard WorkerBasically it loops over all the variables, installing them one at a 754*9880d681SAndroid Build Coastguard Workertime. For each variable we put into the symbol table, we remember the 755*9880d681SAndroid Build Coastguard Workerprevious value that we replace in OldBindings. 756*9880d681SAndroid Build Coastguard Worker 757*9880d681SAndroid Build Coastguard Worker.. code-block:: ocaml 758*9880d681SAndroid Build Coastguard Worker 759*9880d681SAndroid Build Coastguard Worker (* Emit the initializer before adding the variable to scope, this 760*9880d681SAndroid Build Coastguard Worker * prevents the initializer from referencing the variable itself, and 761*9880d681SAndroid Build Coastguard Worker * permits stuff like this: 762*9880d681SAndroid Build Coastguard Worker * var a = 1 in 763*9880d681SAndroid Build Coastguard Worker * var a = a in ... # refers to outer 'a'. *) 764*9880d681SAndroid Build Coastguard Worker let init_val = 765*9880d681SAndroid Build Coastguard Worker match init with 766*9880d681SAndroid Build Coastguard Worker | Some init -> codegen_expr init 767*9880d681SAndroid Build Coastguard Worker (* If not specified, use 0.0. *) 768*9880d681SAndroid Build Coastguard Worker | None -> const_float double_type 0.0 769*9880d681SAndroid Build Coastguard Worker in 770*9880d681SAndroid Build Coastguard Worker 771*9880d681SAndroid Build Coastguard Worker let alloca = create_entry_block_alloca the_function var_name in 772*9880d681SAndroid Build Coastguard Worker ignore(build_store init_val alloca builder); 773*9880d681SAndroid Build Coastguard Worker 774*9880d681SAndroid Build Coastguard Worker (* Remember the old variable binding so that we can restore the binding 775*9880d681SAndroid Build Coastguard Worker * when we unrecurse. *) 776*9880d681SAndroid Build Coastguard Worker 777*9880d681SAndroid Build Coastguard Worker begin 778*9880d681SAndroid Build Coastguard Worker try 779*9880d681SAndroid Build Coastguard Worker let old_value = Hashtbl.find named_values var_name in 780*9880d681SAndroid Build Coastguard Worker old_bindings := (var_name, old_value) :: !old_bindings; 781*9880d681SAndroid Build Coastguard Worker with Not_found > () 782*9880d681SAndroid Build Coastguard Worker end; 783*9880d681SAndroid Build Coastguard Worker 784*9880d681SAndroid Build Coastguard Worker (* Remember this binding. *) 785*9880d681SAndroid Build Coastguard Worker Hashtbl.add named_values var_name alloca; 786*9880d681SAndroid Build Coastguard Worker ) var_names; 787*9880d681SAndroid Build Coastguard Worker 788*9880d681SAndroid Build Coastguard WorkerThere are more comments here than code. The basic idea is that we emit 789*9880d681SAndroid Build Coastguard Workerthe initializer, create the alloca, then update the symbol table to 790*9880d681SAndroid Build Coastguard Workerpoint to it. Once all the variables are installed in the symbol table, 791*9880d681SAndroid Build Coastguard Workerwe evaluate the body of the var/in expression: 792*9880d681SAndroid Build Coastguard Worker 793*9880d681SAndroid Build Coastguard Worker.. code-block:: ocaml 794*9880d681SAndroid Build Coastguard Worker 795*9880d681SAndroid Build Coastguard Worker (* Codegen the body, now that all vars are in scope. *) 796*9880d681SAndroid Build Coastguard Worker let body_val = codegen_expr body in 797*9880d681SAndroid Build Coastguard Worker 798*9880d681SAndroid Build Coastguard WorkerFinally, before returning, we restore the previous variable bindings: 799*9880d681SAndroid Build Coastguard Worker 800*9880d681SAndroid Build Coastguard Worker.. code-block:: ocaml 801*9880d681SAndroid Build Coastguard Worker 802*9880d681SAndroid Build Coastguard Worker (* Pop all our variables from scope. *) 803*9880d681SAndroid Build Coastguard Worker List.iter (fun (var_name, old_value) -> 804*9880d681SAndroid Build Coastguard Worker Hashtbl.add named_values var_name old_value 805*9880d681SAndroid Build Coastguard Worker ) !old_bindings; 806*9880d681SAndroid Build Coastguard Worker 807*9880d681SAndroid Build Coastguard Worker (* Return the body computation. *) 808*9880d681SAndroid Build Coastguard Worker body_val 809*9880d681SAndroid Build Coastguard Worker 810*9880d681SAndroid Build Coastguard WorkerThe end result of all of this is that we get properly scoped variable 811*9880d681SAndroid Build Coastguard Workerdefinitions, and we even (trivially) allow mutation of them :). 812*9880d681SAndroid Build Coastguard Worker 813*9880d681SAndroid Build Coastguard WorkerWith this, we completed what we set out to do. Our nice iterative fib 814*9880d681SAndroid Build Coastguard Workerexample from the intro compiles and runs just fine. The mem2reg pass 815*9880d681SAndroid Build Coastguard Workeroptimizes all of our stack variables into SSA registers, inserting PHI 816*9880d681SAndroid Build Coastguard Workernodes where needed, and our front-end remains simple: no "iterated 817*9880d681SAndroid Build Coastguard Workerdominance frontier" computation anywhere in sight. 818*9880d681SAndroid Build Coastguard Worker 819*9880d681SAndroid Build Coastguard WorkerFull Code Listing 820*9880d681SAndroid Build Coastguard Worker================= 821*9880d681SAndroid Build Coastguard Worker 822*9880d681SAndroid Build Coastguard WorkerHere is the complete code listing for our running example, enhanced with 823*9880d681SAndroid Build Coastguard Workermutable variables and var/in support. To build this example, use: 824*9880d681SAndroid Build Coastguard Worker 825*9880d681SAndroid Build Coastguard Worker.. code-block:: bash 826*9880d681SAndroid Build Coastguard Worker 827*9880d681SAndroid Build Coastguard Worker # Compile 828*9880d681SAndroid Build Coastguard Worker ocamlbuild toy.byte 829*9880d681SAndroid Build Coastguard Worker # Run 830*9880d681SAndroid Build Coastguard Worker ./toy.byte 831*9880d681SAndroid Build Coastguard Worker 832*9880d681SAndroid Build Coastguard WorkerHere is the code: 833*9880d681SAndroid Build Coastguard Worker 834*9880d681SAndroid Build Coastguard Worker\_tags: 835*9880d681SAndroid Build Coastguard Worker :: 836*9880d681SAndroid Build Coastguard Worker 837*9880d681SAndroid Build Coastguard Worker <{lexer,parser}.ml>: use_camlp4, pp(camlp4of) 838*9880d681SAndroid Build Coastguard Worker <*.{byte,native}>: g++, use_llvm, use_llvm_analysis 839*9880d681SAndroid Build Coastguard Worker <*.{byte,native}>: use_llvm_executionengine, use_llvm_target 840*9880d681SAndroid Build Coastguard Worker <*.{byte,native}>: use_llvm_scalar_opts, use_bindings 841*9880d681SAndroid Build Coastguard Worker 842*9880d681SAndroid Build Coastguard Workermyocamlbuild.ml: 843*9880d681SAndroid Build Coastguard Worker .. code-block:: ocaml 844*9880d681SAndroid Build Coastguard Worker 845*9880d681SAndroid Build Coastguard Worker open Ocamlbuild_plugin;; 846*9880d681SAndroid Build Coastguard Worker 847*9880d681SAndroid Build Coastguard Worker ocaml_lib ~extern:true "llvm";; 848*9880d681SAndroid Build Coastguard Worker ocaml_lib ~extern:true "llvm_analysis";; 849*9880d681SAndroid Build Coastguard Worker ocaml_lib ~extern:true "llvm_executionengine";; 850*9880d681SAndroid Build Coastguard Worker ocaml_lib ~extern:true "llvm_target";; 851*9880d681SAndroid Build Coastguard Worker ocaml_lib ~extern:true "llvm_scalar_opts";; 852*9880d681SAndroid Build Coastguard Worker 853*9880d681SAndroid Build Coastguard Worker flag ["link"; "ocaml"; "g++"] (S[A"-cc"; A"g++"; A"-cclib"; A"-rdynamic"]);; 854*9880d681SAndroid Build Coastguard Worker dep ["link"; "ocaml"; "use_bindings"] ["bindings.o"];; 855*9880d681SAndroid Build Coastguard Worker 856*9880d681SAndroid Build Coastguard Workertoken.ml: 857*9880d681SAndroid Build Coastguard Worker .. code-block:: ocaml 858*9880d681SAndroid Build Coastguard Worker 859*9880d681SAndroid Build Coastguard Worker (*===----------------------------------------------------------------------=== 860*9880d681SAndroid Build Coastguard Worker * Lexer Tokens 861*9880d681SAndroid Build Coastguard Worker *===----------------------------------------------------------------------===*) 862*9880d681SAndroid Build Coastguard Worker 863*9880d681SAndroid Build Coastguard Worker (* The lexer returns these 'Kwd' if it is an unknown character, otherwise one of 864*9880d681SAndroid Build Coastguard Worker * these others for known things. *) 865*9880d681SAndroid Build Coastguard Worker type token = 866*9880d681SAndroid Build Coastguard Worker (* commands *) 867*9880d681SAndroid Build Coastguard Worker | Def | Extern 868*9880d681SAndroid Build Coastguard Worker 869*9880d681SAndroid Build Coastguard Worker (* primary *) 870*9880d681SAndroid Build Coastguard Worker | Ident of string | Number of float 871*9880d681SAndroid Build Coastguard Worker 872*9880d681SAndroid Build Coastguard Worker (* unknown *) 873*9880d681SAndroid Build Coastguard Worker | Kwd of char 874*9880d681SAndroid Build Coastguard Worker 875*9880d681SAndroid Build Coastguard Worker (* control *) 876*9880d681SAndroid Build Coastguard Worker | If | Then | Else 877*9880d681SAndroid Build Coastguard Worker | For | In 878*9880d681SAndroid Build Coastguard Worker 879*9880d681SAndroid Build Coastguard Worker (* operators *) 880*9880d681SAndroid Build Coastguard Worker | Binary | Unary 881*9880d681SAndroid Build Coastguard Worker 882*9880d681SAndroid Build Coastguard Worker (* var definition *) 883*9880d681SAndroid Build Coastguard Worker | Var 884*9880d681SAndroid Build Coastguard Worker 885*9880d681SAndroid Build Coastguard Workerlexer.ml: 886*9880d681SAndroid Build Coastguard Worker .. code-block:: ocaml 887*9880d681SAndroid Build Coastguard Worker 888*9880d681SAndroid Build Coastguard Worker (*===----------------------------------------------------------------------=== 889*9880d681SAndroid Build Coastguard Worker * Lexer 890*9880d681SAndroid Build Coastguard Worker *===----------------------------------------------------------------------===*) 891*9880d681SAndroid Build Coastguard Worker 892*9880d681SAndroid Build Coastguard Worker let rec lex = parser 893*9880d681SAndroid Build Coastguard Worker (* Skip any whitespace. *) 894*9880d681SAndroid Build Coastguard Worker | [< ' (' ' | '\n' | '\r' | '\t'); stream >] -> lex stream 895*9880d681SAndroid Build Coastguard Worker 896*9880d681SAndroid Build Coastguard Worker (* identifier: [a-zA-Z][a-zA-Z0-9] *) 897*9880d681SAndroid Build Coastguard Worker | [< ' ('A' .. 'Z' | 'a' .. 'z' as c); stream >] -> 898*9880d681SAndroid Build Coastguard Worker let buffer = Buffer.create 1 in 899*9880d681SAndroid Build Coastguard Worker Buffer.add_char buffer c; 900*9880d681SAndroid Build Coastguard Worker lex_ident buffer stream 901*9880d681SAndroid Build Coastguard Worker 902*9880d681SAndroid Build Coastguard Worker (* number: [0-9.]+ *) 903*9880d681SAndroid Build Coastguard Worker | [< ' ('0' .. '9' as c); stream >] -> 904*9880d681SAndroid Build Coastguard Worker let buffer = Buffer.create 1 in 905*9880d681SAndroid Build Coastguard Worker Buffer.add_char buffer c; 906*9880d681SAndroid Build Coastguard Worker lex_number buffer stream 907*9880d681SAndroid Build Coastguard Worker 908*9880d681SAndroid Build Coastguard Worker (* Comment until end of line. *) 909*9880d681SAndroid Build Coastguard Worker | [< ' ('#'); stream >] -> 910*9880d681SAndroid Build Coastguard Worker lex_comment stream 911*9880d681SAndroid Build Coastguard Worker 912*9880d681SAndroid Build Coastguard Worker (* Otherwise, just return the character as its ascii value. *) 913*9880d681SAndroid Build Coastguard Worker | [< 'c; stream >] -> 914*9880d681SAndroid Build Coastguard Worker [< 'Token.Kwd c; lex stream >] 915*9880d681SAndroid Build Coastguard Worker 916*9880d681SAndroid Build Coastguard Worker (* end of stream. *) 917*9880d681SAndroid Build Coastguard Worker | [< >] -> [< >] 918*9880d681SAndroid Build Coastguard Worker 919*9880d681SAndroid Build Coastguard Worker and lex_number buffer = parser 920*9880d681SAndroid Build Coastguard Worker | [< ' ('0' .. '9' | '.' as c); stream >] -> 921*9880d681SAndroid Build Coastguard Worker Buffer.add_char buffer c; 922*9880d681SAndroid Build Coastguard Worker lex_number buffer stream 923*9880d681SAndroid Build Coastguard Worker | [< stream=lex >] -> 924*9880d681SAndroid Build Coastguard Worker [< 'Token.Number (float_of_string (Buffer.contents buffer)); stream >] 925*9880d681SAndroid Build Coastguard Worker 926*9880d681SAndroid Build Coastguard Worker and lex_ident buffer = parser 927*9880d681SAndroid Build Coastguard Worker | [< ' ('A' .. 'Z' | 'a' .. 'z' | '0' .. '9' as c); stream >] -> 928*9880d681SAndroid Build Coastguard Worker Buffer.add_char buffer c; 929*9880d681SAndroid Build Coastguard Worker lex_ident buffer stream 930*9880d681SAndroid Build Coastguard Worker | [< stream=lex >] -> 931*9880d681SAndroid Build Coastguard Worker match Buffer.contents buffer with 932*9880d681SAndroid Build Coastguard Worker | "def" -> [< 'Token.Def; stream >] 933*9880d681SAndroid Build Coastguard Worker | "extern" -> [< 'Token.Extern; stream >] 934*9880d681SAndroid Build Coastguard Worker | "if" -> [< 'Token.If; stream >] 935*9880d681SAndroid Build Coastguard Worker | "then" -> [< 'Token.Then; stream >] 936*9880d681SAndroid Build Coastguard Worker | "else" -> [< 'Token.Else; stream >] 937*9880d681SAndroid Build Coastguard Worker | "for" -> [< 'Token.For; stream >] 938*9880d681SAndroid Build Coastguard Worker | "in" -> [< 'Token.In; stream >] 939*9880d681SAndroid Build Coastguard Worker | "binary" -> [< 'Token.Binary; stream >] 940*9880d681SAndroid Build Coastguard Worker | "unary" -> [< 'Token.Unary; stream >] 941*9880d681SAndroid Build Coastguard Worker | "var" -> [< 'Token.Var; stream >] 942*9880d681SAndroid Build Coastguard Worker | id -> [< 'Token.Ident id; stream >] 943*9880d681SAndroid Build Coastguard Worker 944*9880d681SAndroid Build Coastguard Worker and lex_comment = parser 945*9880d681SAndroid Build Coastguard Worker | [< ' ('\n'); stream=lex >] -> stream 946*9880d681SAndroid Build Coastguard Worker | [< 'c; e=lex_comment >] -> e 947*9880d681SAndroid Build Coastguard Worker | [< >] -> [< >] 948*9880d681SAndroid Build Coastguard Worker 949*9880d681SAndroid Build Coastguard Workerast.ml: 950*9880d681SAndroid Build Coastguard Worker .. code-block:: ocaml 951*9880d681SAndroid Build Coastguard Worker 952*9880d681SAndroid Build Coastguard Worker (*===----------------------------------------------------------------------=== 953*9880d681SAndroid Build Coastguard Worker * Abstract Syntax Tree (aka Parse Tree) 954*9880d681SAndroid Build Coastguard Worker *===----------------------------------------------------------------------===*) 955*9880d681SAndroid Build Coastguard Worker 956*9880d681SAndroid Build Coastguard Worker (* expr - Base type for all expression nodes. *) 957*9880d681SAndroid Build Coastguard Worker type expr = 958*9880d681SAndroid Build Coastguard Worker (* variant for numeric literals like "1.0". *) 959*9880d681SAndroid Build Coastguard Worker | Number of float 960*9880d681SAndroid Build Coastguard Worker 961*9880d681SAndroid Build Coastguard Worker (* variant for referencing a variable, like "a". *) 962*9880d681SAndroid Build Coastguard Worker | Variable of string 963*9880d681SAndroid Build Coastguard Worker 964*9880d681SAndroid Build Coastguard Worker (* variant for a unary operator. *) 965*9880d681SAndroid Build Coastguard Worker | Unary of char * expr 966*9880d681SAndroid Build Coastguard Worker 967*9880d681SAndroid Build Coastguard Worker (* variant for a binary operator. *) 968*9880d681SAndroid Build Coastguard Worker | Binary of char * expr * expr 969*9880d681SAndroid Build Coastguard Worker 970*9880d681SAndroid Build Coastguard Worker (* variant for function calls. *) 971*9880d681SAndroid Build Coastguard Worker | Call of string * expr array 972*9880d681SAndroid Build Coastguard Worker 973*9880d681SAndroid Build Coastguard Worker (* variant for if/then/else. *) 974*9880d681SAndroid Build Coastguard Worker | If of expr * expr * expr 975*9880d681SAndroid Build Coastguard Worker 976*9880d681SAndroid Build Coastguard Worker (* variant for for/in. *) 977*9880d681SAndroid Build Coastguard Worker | For of string * expr * expr * expr option * expr 978*9880d681SAndroid Build Coastguard Worker 979*9880d681SAndroid Build Coastguard Worker (* variant for var/in. *) 980*9880d681SAndroid Build Coastguard Worker | Var of (string * expr option) array * expr 981*9880d681SAndroid Build Coastguard Worker 982*9880d681SAndroid Build Coastguard Worker (* proto - This type represents the "prototype" for a function, which captures 983*9880d681SAndroid Build Coastguard Worker * its name, and its argument names (thus implicitly the number of arguments the 984*9880d681SAndroid Build Coastguard Worker * function takes). *) 985*9880d681SAndroid Build Coastguard Worker type proto = 986*9880d681SAndroid Build Coastguard Worker | Prototype of string * string array 987*9880d681SAndroid Build Coastguard Worker | BinOpPrototype of string * string array * int 988*9880d681SAndroid Build Coastguard Worker 989*9880d681SAndroid Build Coastguard Worker (* func - This type represents a function definition itself. *) 990*9880d681SAndroid Build Coastguard Worker type func = Function of proto * expr 991*9880d681SAndroid Build Coastguard Worker 992*9880d681SAndroid Build Coastguard Workerparser.ml: 993*9880d681SAndroid Build Coastguard Worker .. code-block:: ocaml 994*9880d681SAndroid Build Coastguard Worker 995*9880d681SAndroid Build Coastguard Worker (*===---------------------------------------------------------------------=== 996*9880d681SAndroid Build Coastguard Worker * Parser 997*9880d681SAndroid Build Coastguard Worker *===---------------------------------------------------------------------===*) 998*9880d681SAndroid Build Coastguard Worker 999*9880d681SAndroid Build Coastguard Worker (* binop_precedence - This holds the precedence for each binary operator that is 1000*9880d681SAndroid Build Coastguard Worker * defined *) 1001*9880d681SAndroid Build Coastguard Worker let binop_precedence:(char, int) Hashtbl.t = Hashtbl.create 10 1002*9880d681SAndroid Build Coastguard Worker 1003*9880d681SAndroid Build Coastguard Worker (* precedence - Get the precedence of the pending binary operator token. *) 1004*9880d681SAndroid Build Coastguard Worker let precedence c = try Hashtbl.find binop_precedence c with Not_found -> -1 1005*9880d681SAndroid Build Coastguard Worker 1006*9880d681SAndroid Build Coastguard Worker (* primary 1007*9880d681SAndroid Build Coastguard Worker * ::= identifier 1008*9880d681SAndroid Build Coastguard Worker * ::= numberexpr 1009*9880d681SAndroid Build Coastguard Worker * ::= parenexpr 1010*9880d681SAndroid Build Coastguard Worker * ::= ifexpr 1011*9880d681SAndroid Build Coastguard Worker * ::= forexpr 1012*9880d681SAndroid Build Coastguard Worker * ::= varexpr *) 1013*9880d681SAndroid Build Coastguard Worker let rec parse_primary = parser 1014*9880d681SAndroid Build Coastguard Worker (* numberexpr ::= number *) 1015*9880d681SAndroid Build Coastguard Worker | [< 'Token.Number n >] -> Ast.Number n 1016*9880d681SAndroid Build Coastguard Worker 1017*9880d681SAndroid Build Coastguard Worker (* parenexpr ::= '(' expression ')' *) 1018*9880d681SAndroid Build Coastguard Worker | [< 'Token.Kwd '('; e=parse_expr; 'Token.Kwd ')' ?? "expected ')'" >] -> e 1019*9880d681SAndroid Build Coastguard Worker 1020*9880d681SAndroid Build Coastguard Worker (* identifierexpr 1021*9880d681SAndroid Build Coastguard Worker * ::= identifier 1022*9880d681SAndroid Build Coastguard Worker * ::= identifier '(' argumentexpr ')' *) 1023*9880d681SAndroid Build Coastguard Worker | [< 'Token.Ident id; stream >] -> 1024*9880d681SAndroid Build Coastguard Worker let rec parse_args accumulator = parser 1025*9880d681SAndroid Build Coastguard Worker | [< e=parse_expr; stream >] -> 1026*9880d681SAndroid Build Coastguard Worker begin parser 1027*9880d681SAndroid Build Coastguard Worker | [< 'Token.Kwd ','; e=parse_args (e :: accumulator) >] -> e 1028*9880d681SAndroid Build Coastguard Worker | [< >] -> e :: accumulator 1029*9880d681SAndroid Build Coastguard Worker end stream 1030*9880d681SAndroid Build Coastguard Worker | [< >] -> accumulator 1031*9880d681SAndroid Build Coastguard Worker in 1032*9880d681SAndroid Build Coastguard Worker let rec parse_ident id = parser 1033*9880d681SAndroid Build Coastguard Worker (* Call. *) 1034*9880d681SAndroid Build Coastguard Worker | [< 'Token.Kwd '('; 1035*9880d681SAndroid Build Coastguard Worker args=parse_args []; 1036*9880d681SAndroid Build Coastguard Worker 'Token.Kwd ')' ?? "expected ')'">] -> 1037*9880d681SAndroid Build Coastguard Worker Ast.Call (id, Array.of_list (List.rev args)) 1038*9880d681SAndroid Build Coastguard Worker 1039*9880d681SAndroid Build Coastguard Worker (* Simple variable ref. *) 1040*9880d681SAndroid Build Coastguard Worker | [< >] -> Ast.Variable id 1041*9880d681SAndroid Build Coastguard Worker in 1042*9880d681SAndroid Build Coastguard Worker parse_ident id stream 1043*9880d681SAndroid Build Coastguard Worker 1044*9880d681SAndroid Build Coastguard Worker (* ifexpr ::= 'if' expr 'then' expr 'else' expr *) 1045*9880d681SAndroid Build Coastguard Worker | [< 'Token.If; c=parse_expr; 1046*9880d681SAndroid Build Coastguard Worker 'Token.Then ?? "expected 'then'"; t=parse_expr; 1047*9880d681SAndroid Build Coastguard Worker 'Token.Else ?? "expected 'else'"; e=parse_expr >] -> 1048*9880d681SAndroid Build Coastguard Worker Ast.If (c, t, e) 1049*9880d681SAndroid Build Coastguard Worker 1050*9880d681SAndroid Build Coastguard Worker (* forexpr 1051*9880d681SAndroid Build Coastguard Worker ::= 'for' identifier '=' expr ',' expr (',' expr)? 'in' expression *) 1052*9880d681SAndroid Build Coastguard Worker | [< 'Token.For; 1053*9880d681SAndroid Build Coastguard Worker 'Token.Ident id ?? "expected identifier after for"; 1054*9880d681SAndroid Build Coastguard Worker 'Token.Kwd '=' ?? "expected '=' after for"; 1055*9880d681SAndroid Build Coastguard Worker stream >] -> 1056*9880d681SAndroid Build Coastguard Worker begin parser 1057*9880d681SAndroid Build Coastguard Worker | [< 1058*9880d681SAndroid Build Coastguard Worker start=parse_expr; 1059*9880d681SAndroid Build Coastguard Worker 'Token.Kwd ',' ?? "expected ',' after for"; 1060*9880d681SAndroid Build Coastguard Worker end_=parse_expr; 1061*9880d681SAndroid Build Coastguard Worker stream >] -> 1062*9880d681SAndroid Build Coastguard Worker let step = 1063*9880d681SAndroid Build Coastguard Worker begin parser 1064*9880d681SAndroid Build Coastguard Worker | [< 'Token.Kwd ','; step=parse_expr >] -> Some step 1065*9880d681SAndroid Build Coastguard Worker | [< >] -> None 1066*9880d681SAndroid Build Coastguard Worker end stream 1067*9880d681SAndroid Build Coastguard Worker in 1068*9880d681SAndroid Build Coastguard Worker begin parser 1069*9880d681SAndroid Build Coastguard Worker | [< 'Token.In; body=parse_expr >] -> 1070*9880d681SAndroid Build Coastguard Worker Ast.For (id, start, end_, step, body) 1071*9880d681SAndroid Build Coastguard Worker | [< >] -> 1072*9880d681SAndroid Build Coastguard Worker raise (Stream.Error "expected 'in' after for") 1073*9880d681SAndroid Build Coastguard Worker end stream 1074*9880d681SAndroid Build Coastguard Worker | [< >] -> 1075*9880d681SAndroid Build Coastguard Worker raise (Stream.Error "expected '=' after for") 1076*9880d681SAndroid Build Coastguard Worker end stream 1077*9880d681SAndroid Build Coastguard Worker 1078*9880d681SAndroid Build Coastguard Worker (* varexpr 1079*9880d681SAndroid Build Coastguard Worker * ::= 'var' identifier ('=' expression? 1080*9880d681SAndroid Build Coastguard Worker * (',' identifier ('=' expression)?)* 'in' expression *) 1081*9880d681SAndroid Build Coastguard Worker | [< 'Token.Var; 1082*9880d681SAndroid Build Coastguard Worker (* At least one variable name is required. *) 1083*9880d681SAndroid Build Coastguard Worker 'Token.Ident id ?? "expected identifier after var"; 1084*9880d681SAndroid Build Coastguard Worker init=parse_var_init; 1085*9880d681SAndroid Build Coastguard Worker var_names=parse_var_names [(id, init)]; 1086*9880d681SAndroid Build Coastguard Worker (* At this point, we have to have 'in'. *) 1087*9880d681SAndroid Build Coastguard Worker 'Token.In ?? "expected 'in' keyword after 'var'"; 1088*9880d681SAndroid Build Coastguard Worker body=parse_expr >] -> 1089*9880d681SAndroid Build Coastguard Worker Ast.Var (Array.of_list (List.rev var_names), body) 1090*9880d681SAndroid Build Coastguard Worker 1091*9880d681SAndroid Build Coastguard Worker | [< >] -> raise (Stream.Error "unknown token when expecting an expression.") 1092*9880d681SAndroid Build Coastguard Worker 1093*9880d681SAndroid Build Coastguard Worker (* unary 1094*9880d681SAndroid Build Coastguard Worker * ::= primary 1095*9880d681SAndroid Build Coastguard Worker * ::= '!' unary *) 1096*9880d681SAndroid Build Coastguard Worker and parse_unary = parser 1097*9880d681SAndroid Build Coastguard Worker (* If this is a unary operator, read it. *) 1098*9880d681SAndroid Build Coastguard Worker | [< 'Token.Kwd op when op != '(' && op != ')'; operand=parse_expr >] -> 1099*9880d681SAndroid Build Coastguard Worker Ast.Unary (op, operand) 1100*9880d681SAndroid Build Coastguard Worker 1101*9880d681SAndroid Build Coastguard Worker (* If the current token is not an operator, it must be a primary expr. *) 1102*9880d681SAndroid Build Coastguard Worker | [< stream >] -> parse_primary stream 1103*9880d681SAndroid Build Coastguard Worker 1104*9880d681SAndroid Build Coastguard Worker (* binoprhs 1105*9880d681SAndroid Build Coastguard Worker * ::= ('+' primary)* *) 1106*9880d681SAndroid Build Coastguard Worker and parse_bin_rhs expr_prec lhs stream = 1107*9880d681SAndroid Build Coastguard Worker match Stream.peek stream with 1108*9880d681SAndroid Build Coastguard Worker (* If this is a binop, find its precedence. *) 1109*9880d681SAndroid Build Coastguard Worker | Some (Token.Kwd c) when Hashtbl.mem binop_precedence c -> 1110*9880d681SAndroid Build Coastguard Worker let token_prec = precedence c in 1111*9880d681SAndroid Build Coastguard Worker 1112*9880d681SAndroid Build Coastguard Worker (* If this is a binop that binds at least as tightly as the current binop, 1113*9880d681SAndroid Build Coastguard Worker * consume it, otherwise we are done. *) 1114*9880d681SAndroid Build Coastguard Worker if token_prec < expr_prec then lhs else begin 1115*9880d681SAndroid Build Coastguard Worker (* Eat the binop. *) 1116*9880d681SAndroid Build Coastguard Worker Stream.junk stream; 1117*9880d681SAndroid Build Coastguard Worker 1118*9880d681SAndroid Build Coastguard Worker (* Parse the primary expression after the binary operator. *) 1119*9880d681SAndroid Build Coastguard Worker let rhs = parse_unary stream in 1120*9880d681SAndroid Build Coastguard Worker 1121*9880d681SAndroid Build Coastguard Worker (* Okay, we know this is a binop. *) 1122*9880d681SAndroid Build Coastguard Worker let rhs = 1123*9880d681SAndroid Build Coastguard Worker match Stream.peek stream with 1124*9880d681SAndroid Build Coastguard Worker | Some (Token.Kwd c2) -> 1125*9880d681SAndroid Build Coastguard Worker (* If BinOp binds less tightly with rhs than the operator after 1126*9880d681SAndroid Build Coastguard Worker * rhs, let the pending operator take rhs as its lhs. *) 1127*9880d681SAndroid Build Coastguard Worker let next_prec = precedence c2 in 1128*9880d681SAndroid Build Coastguard Worker if token_prec < next_prec 1129*9880d681SAndroid Build Coastguard Worker then parse_bin_rhs (token_prec + 1) rhs stream 1130*9880d681SAndroid Build Coastguard Worker else rhs 1131*9880d681SAndroid Build Coastguard Worker | _ -> rhs 1132*9880d681SAndroid Build Coastguard Worker in 1133*9880d681SAndroid Build Coastguard Worker 1134*9880d681SAndroid Build Coastguard Worker (* Merge lhs/rhs. *) 1135*9880d681SAndroid Build Coastguard Worker let lhs = Ast.Binary (c, lhs, rhs) in 1136*9880d681SAndroid Build Coastguard Worker parse_bin_rhs expr_prec lhs stream 1137*9880d681SAndroid Build Coastguard Worker end 1138*9880d681SAndroid Build Coastguard Worker | _ -> lhs 1139*9880d681SAndroid Build Coastguard Worker 1140*9880d681SAndroid Build Coastguard Worker and parse_var_init = parser 1141*9880d681SAndroid Build Coastguard Worker (* read in the optional initializer. *) 1142*9880d681SAndroid Build Coastguard Worker | [< 'Token.Kwd '='; e=parse_expr >] -> Some e 1143*9880d681SAndroid Build Coastguard Worker | [< >] -> None 1144*9880d681SAndroid Build Coastguard Worker 1145*9880d681SAndroid Build Coastguard Worker and parse_var_names accumulator = parser 1146*9880d681SAndroid Build Coastguard Worker | [< 'Token.Kwd ','; 1147*9880d681SAndroid Build Coastguard Worker 'Token.Ident id ?? "expected identifier list after var"; 1148*9880d681SAndroid Build Coastguard Worker init=parse_var_init; 1149*9880d681SAndroid Build Coastguard Worker e=parse_var_names ((id, init) :: accumulator) >] -> e 1150*9880d681SAndroid Build Coastguard Worker | [< >] -> accumulator 1151*9880d681SAndroid Build Coastguard Worker 1152*9880d681SAndroid Build Coastguard Worker (* expression 1153*9880d681SAndroid Build Coastguard Worker * ::= primary binoprhs *) 1154*9880d681SAndroid Build Coastguard Worker and parse_expr = parser 1155*9880d681SAndroid Build Coastguard Worker | [< lhs=parse_unary; stream >] -> parse_bin_rhs 0 lhs stream 1156*9880d681SAndroid Build Coastguard Worker 1157*9880d681SAndroid Build Coastguard Worker (* prototype 1158*9880d681SAndroid Build Coastguard Worker * ::= id '(' id* ')' 1159*9880d681SAndroid Build Coastguard Worker * ::= binary LETTER number? (id, id) 1160*9880d681SAndroid Build Coastguard Worker * ::= unary LETTER number? (id) *) 1161*9880d681SAndroid Build Coastguard Worker let parse_prototype = 1162*9880d681SAndroid Build Coastguard Worker let rec parse_args accumulator = parser 1163*9880d681SAndroid Build Coastguard Worker | [< 'Token.Ident id; e=parse_args (id::accumulator) >] -> e 1164*9880d681SAndroid Build Coastguard Worker | [< >] -> accumulator 1165*9880d681SAndroid Build Coastguard Worker in 1166*9880d681SAndroid Build Coastguard Worker let parse_operator = parser 1167*9880d681SAndroid Build Coastguard Worker | [< 'Token.Unary >] -> "unary", 1 1168*9880d681SAndroid Build Coastguard Worker | [< 'Token.Binary >] -> "binary", 2 1169*9880d681SAndroid Build Coastguard Worker in 1170*9880d681SAndroid Build Coastguard Worker let parse_binary_precedence = parser 1171*9880d681SAndroid Build Coastguard Worker | [< 'Token.Number n >] -> int_of_float n 1172*9880d681SAndroid Build Coastguard Worker | [< >] -> 30 1173*9880d681SAndroid Build Coastguard Worker in 1174*9880d681SAndroid Build Coastguard Worker parser 1175*9880d681SAndroid Build Coastguard Worker | [< 'Token.Ident id; 1176*9880d681SAndroid Build Coastguard Worker 'Token.Kwd '(' ?? "expected '(' in prototype"; 1177*9880d681SAndroid Build Coastguard Worker args=parse_args []; 1178*9880d681SAndroid Build Coastguard Worker 'Token.Kwd ')' ?? "expected ')' in prototype" >] -> 1179*9880d681SAndroid Build Coastguard Worker (* success. *) 1180*9880d681SAndroid Build Coastguard Worker Ast.Prototype (id, Array.of_list (List.rev args)) 1181*9880d681SAndroid Build Coastguard Worker | [< (prefix, kind)=parse_operator; 1182*9880d681SAndroid Build Coastguard Worker 'Token.Kwd op ?? "expected an operator"; 1183*9880d681SAndroid Build Coastguard Worker (* Read the precedence if present. *) 1184*9880d681SAndroid Build Coastguard Worker binary_precedence=parse_binary_precedence; 1185*9880d681SAndroid Build Coastguard Worker 'Token.Kwd '(' ?? "expected '(' in prototype"; 1186*9880d681SAndroid Build Coastguard Worker args=parse_args []; 1187*9880d681SAndroid Build Coastguard Worker 'Token.Kwd ')' ?? "expected ')' in prototype" >] -> 1188*9880d681SAndroid Build Coastguard Worker let name = prefix ^ (String.make 1 op) in 1189*9880d681SAndroid Build Coastguard Worker let args = Array.of_list (List.rev args) in 1190*9880d681SAndroid Build Coastguard Worker 1191*9880d681SAndroid Build Coastguard Worker (* Verify right number of arguments for operator. *) 1192*9880d681SAndroid Build Coastguard Worker if Array.length args != kind 1193*9880d681SAndroid Build Coastguard Worker then raise (Stream.Error "invalid number of operands for operator") 1194*9880d681SAndroid Build Coastguard Worker else 1195*9880d681SAndroid Build Coastguard Worker if kind == 1 then 1196*9880d681SAndroid Build Coastguard Worker Ast.Prototype (name, args) 1197*9880d681SAndroid Build Coastguard Worker else 1198*9880d681SAndroid Build Coastguard Worker Ast.BinOpPrototype (name, args, binary_precedence) 1199*9880d681SAndroid Build Coastguard Worker | [< >] -> 1200*9880d681SAndroid Build Coastguard Worker raise (Stream.Error "expected function name in prototype") 1201*9880d681SAndroid Build Coastguard Worker 1202*9880d681SAndroid Build Coastguard Worker (* definition ::= 'def' prototype expression *) 1203*9880d681SAndroid Build Coastguard Worker let parse_definition = parser 1204*9880d681SAndroid Build Coastguard Worker | [< 'Token.Def; p=parse_prototype; e=parse_expr >] -> 1205*9880d681SAndroid Build Coastguard Worker Ast.Function (p, e) 1206*9880d681SAndroid Build Coastguard Worker 1207*9880d681SAndroid Build Coastguard Worker (* toplevelexpr ::= expression *) 1208*9880d681SAndroid Build Coastguard Worker let parse_toplevel = parser 1209*9880d681SAndroid Build Coastguard Worker | [< e=parse_expr >] -> 1210*9880d681SAndroid Build Coastguard Worker (* Make an anonymous proto. *) 1211*9880d681SAndroid Build Coastguard Worker Ast.Function (Ast.Prototype ("", [||]), e) 1212*9880d681SAndroid Build Coastguard Worker 1213*9880d681SAndroid Build Coastguard Worker (* external ::= 'extern' prototype *) 1214*9880d681SAndroid Build Coastguard Worker let parse_extern = parser 1215*9880d681SAndroid Build Coastguard Worker | [< 'Token.Extern; e=parse_prototype >] -> e 1216*9880d681SAndroid Build Coastguard Worker 1217*9880d681SAndroid Build Coastguard Workercodegen.ml: 1218*9880d681SAndroid Build Coastguard Worker .. code-block:: ocaml 1219*9880d681SAndroid Build Coastguard Worker 1220*9880d681SAndroid Build Coastguard Worker (*===----------------------------------------------------------------------=== 1221*9880d681SAndroid Build Coastguard Worker * Code Generation 1222*9880d681SAndroid Build Coastguard Worker *===----------------------------------------------------------------------===*) 1223*9880d681SAndroid Build Coastguard Worker 1224*9880d681SAndroid Build Coastguard Worker open Llvm 1225*9880d681SAndroid Build Coastguard Worker 1226*9880d681SAndroid Build Coastguard Worker exception Error of string 1227*9880d681SAndroid Build Coastguard Worker 1228*9880d681SAndroid Build Coastguard Worker let context = global_context () 1229*9880d681SAndroid Build Coastguard Worker let the_module = create_module context "my cool jit" 1230*9880d681SAndroid Build Coastguard Worker let builder = builder context 1231*9880d681SAndroid Build Coastguard Worker let named_values:(string, llvalue) Hashtbl.t = Hashtbl.create 10 1232*9880d681SAndroid Build Coastguard Worker let double_type = double_type context 1233*9880d681SAndroid Build Coastguard Worker 1234*9880d681SAndroid Build Coastguard Worker (* Create an alloca instruction in the entry block of the function. This 1235*9880d681SAndroid Build Coastguard Worker * is used for mutable variables etc. *) 1236*9880d681SAndroid Build Coastguard Worker let create_entry_block_alloca the_function var_name = 1237*9880d681SAndroid Build Coastguard Worker let builder = builder_at context (instr_begin (entry_block the_function)) in 1238*9880d681SAndroid Build Coastguard Worker build_alloca double_type var_name builder 1239*9880d681SAndroid Build Coastguard Worker 1240*9880d681SAndroid Build Coastguard Worker let rec codegen_expr = function 1241*9880d681SAndroid Build Coastguard Worker | Ast.Number n -> const_float double_type n 1242*9880d681SAndroid Build Coastguard Worker | Ast.Variable name -> 1243*9880d681SAndroid Build Coastguard Worker let v = try Hashtbl.find named_values name with 1244*9880d681SAndroid Build Coastguard Worker | Not_found -> raise (Error "unknown variable name") 1245*9880d681SAndroid Build Coastguard Worker in 1246*9880d681SAndroid Build Coastguard Worker (* Load the value. *) 1247*9880d681SAndroid Build Coastguard Worker build_load v name builder 1248*9880d681SAndroid Build Coastguard Worker | Ast.Unary (op, operand) -> 1249*9880d681SAndroid Build Coastguard Worker let operand = codegen_expr operand in 1250*9880d681SAndroid Build Coastguard Worker let callee = "unary" ^ (String.make 1 op) in 1251*9880d681SAndroid Build Coastguard Worker let callee = 1252*9880d681SAndroid Build Coastguard Worker match lookup_function callee the_module with 1253*9880d681SAndroid Build Coastguard Worker | Some callee -> callee 1254*9880d681SAndroid Build Coastguard Worker | None -> raise (Error "unknown unary operator") 1255*9880d681SAndroid Build Coastguard Worker in 1256*9880d681SAndroid Build Coastguard Worker build_call callee [|operand|] "unop" builder 1257*9880d681SAndroid Build Coastguard Worker | Ast.Binary (op, lhs, rhs) -> 1258*9880d681SAndroid Build Coastguard Worker begin match op with 1259*9880d681SAndroid Build Coastguard Worker | '=' -> 1260*9880d681SAndroid Build Coastguard Worker (* Special case '=' because we don't want to emit the LHS as an 1261*9880d681SAndroid Build Coastguard Worker * expression. *) 1262*9880d681SAndroid Build Coastguard Worker let name = 1263*9880d681SAndroid Build Coastguard Worker match lhs with 1264*9880d681SAndroid Build Coastguard Worker | Ast.Variable name -> name 1265*9880d681SAndroid Build Coastguard Worker | _ -> raise (Error "destination of '=' must be a variable") 1266*9880d681SAndroid Build Coastguard Worker in 1267*9880d681SAndroid Build Coastguard Worker 1268*9880d681SAndroid Build Coastguard Worker (* Codegen the rhs. *) 1269*9880d681SAndroid Build Coastguard Worker let val_ = codegen_expr rhs in 1270*9880d681SAndroid Build Coastguard Worker 1271*9880d681SAndroid Build Coastguard Worker (* Lookup the name. *) 1272*9880d681SAndroid Build Coastguard Worker let variable = try Hashtbl.find named_values name with 1273*9880d681SAndroid Build Coastguard Worker | Not_found -> raise (Error "unknown variable name") 1274*9880d681SAndroid Build Coastguard Worker in 1275*9880d681SAndroid Build Coastguard Worker ignore(build_store val_ variable builder); 1276*9880d681SAndroid Build Coastguard Worker val_ 1277*9880d681SAndroid Build Coastguard Worker | _ -> 1278*9880d681SAndroid Build Coastguard Worker let lhs_val = codegen_expr lhs in 1279*9880d681SAndroid Build Coastguard Worker let rhs_val = codegen_expr rhs in 1280*9880d681SAndroid Build Coastguard Worker begin 1281*9880d681SAndroid Build Coastguard Worker match op with 1282*9880d681SAndroid Build Coastguard Worker | '+' -> build_add lhs_val rhs_val "addtmp" builder 1283*9880d681SAndroid Build Coastguard Worker | '-' -> build_sub lhs_val rhs_val "subtmp" builder 1284*9880d681SAndroid Build Coastguard Worker | '*' -> build_mul lhs_val rhs_val "multmp" builder 1285*9880d681SAndroid Build Coastguard Worker | '<' -> 1286*9880d681SAndroid Build Coastguard Worker (* Convert bool 0/1 to double 0.0 or 1.0 *) 1287*9880d681SAndroid Build Coastguard Worker let i = build_fcmp Fcmp.Ult lhs_val rhs_val "cmptmp" builder in 1288*9880d681SAndroid Build Coastguard Worker build_uitofp i double_type "booltmp" builder 1289*9880d681SAndroid Build Coastguard Worker | _ -> 1290*9880d681SAndroid Build Coastguard Worker (* If it wasn't a builtin binary operator, it must be a user defined 1291*9880d681SAndroid Build Coastguard Worker * one. Emit a call to it. *) 1292*9880d681SAndroid Build Coastguard Worker let callee = "binary" ^ (String.make 1 op) in 1293*9880d681SAndroid Build Coastguard Worker let callee = 1294*9880d681SAndroid Build Coastguard Worker match lookup_function callee the_module with 1295*9880d681SAndroid Build Coastguard Worker | Some callee -> callee 1296*9880d681SAndroid Build Coastguard Worker | None -> raise (Error "binary operator not found!") 1297*9880d681SAndroid Build Coastguard Worker in 1298*9880d681SAndroid Build Coastguard Worker build_call callee [|lhs_val; rhs_val|] "binop" builder 1299*9880d681SAndroid Build Coastguard Worker end 1300*9880d681SAndroid Build Coastguard Worker end 1301*9880d681SAndroid Build Coastguard Worker | Ast.Call (callee, args) -> 1302*9880d681SAndroid Build Coastguard Worker (* Look up the name in the module table. *) 1303*9880d681SAndroid Build Coastguard Worker let callee = 1304*9880d681SAndroid Build Coastguard Worker match lookup_function callee the_module with 1305*9880d681SAndroid Build Coastguard Worker | Some callee -> callee 1306*9880d681SAndroid Build Coastguard Worker | None -> raise (Error "unknown function referenced") 1307*9880d681SAndroid Build Coastguard Worker in 1308*9880d681SAndroid Build Coastguard Worker let params = params callee in 1309*9880d681SAndroid Build Coastguard Worker 1310*9880d681SAndroid Build Coastguard Worker (* If argument mismatch error. *) 1311*9880d681SAndroid Build Coastguard Worker if Array.length params == Array.length args then () else 1312*9880d681SAndroid Build Coastguard Worker raise (Error "incorrect # arguments passed"); 1313*9880d681SAndroid Build Coastguard Worker let args = Array.map codegen_expr args in 1314*9880d681SAndroid Build Coastguard Worker build_call callee args "calltmp" builder 1315*9880d681SAndroid Build Coastguard Worker | Ast.If (cond, then_, else_) -> 1316*9880d681SAndroid Build Coastguard Worker let cond = codegen_expr cond in 1317*9880d681SAndroid Build Coastguard Worker 1318*9880d681SAndroid Build Coastguard Worker (* Convert condition to a bool by comparing equal to 0.0 *) 1319*9880d681SAndroid Build Coastguard Worker let zero = const_float double_type 0.0 in 1320*9880d681SAndroid Build Coastguard Worker let cond_val = build_fcmp Fcmp.One cond zero "ifcond" builder in 1321*9880d681SAndroid Build Coastguard Worker 1322*9880d681SAndroid Build Coastguard Worker (* Grab the first block so that we might later add the conditional branch 1323*9880d681SAndroid Build Coastguard Worker * to it at the end of the function. *) 1324*9880d681SAndroid Build Coastguard Worker let start_bb = insertion_block builder in 1325*9880d681SAndroid Build Coastguard Worker let the_function = block_parent start_bb in 1326*9880d681SAndroid Build Coastguard Worker 1327*9880d681SAndroid Build Coastguard Worker let then_bb = append_block context "then" the_function in 1328*9880d681SAndroid Build Coastguard Worker 1329*9880d681SAndroid Build Coastguard Worker (* Emit 'then' value. *) 1330*9880d681SAndroid Build Coastguard Worker position_at_end then_bb builder; 1331*9880d681SAndroid Build Coastguard Worker let then_val = codegen_expr then_ in 1332*9880d681SAndroid Build Coastguard Worker 1333*9880d681SAndroid Build Coastguard Worker (* Codegen of 'then' can change the current block, update then_bb for the 1334*9880d681SAndroid Build Coastguard Worker * phi. We create a new name because one is used for the phi node, and the 1335*9880d681SAndroid Build Coastguard Worker * other is used for the conditional branch. *) 1336*9880d681SAndroid Build Coastguard Worker let new_then_bb = insertion_block builder in 1337*9880d681SAndroid Build Coastguard Worker 1338*9880d681SAndroid Build Coastguard Worker (* Emit 'else' value. *) 1339*9880d681SAndroid Build Coastguard Worker let else_bb = append_block context "else" the_function in 1340*9880d681SAndroid Build Coastguard Worker position_at_end else_bb builder; 1341*9880d681SAndroid Build Coastguard Worker let else_val = codegen_expr else_ in 1342*9880d681SAndroid Build Coastguard Worker 1343*9880d681SAndroid Build Coastguard Worker (* Codegen of 'else' can change the current block, update else_bb for the 1344*9880d681SAndroid Build Coastguard Worker * phi. *) 1345*9880d681SAndroid Build Coastguard Worker let new_else_bb = insertion_block builder in 1346*9880d681SAndroid Build Coastguard Worker 1347*9880d681SAndroid Build Coastguard Worker (* Emit merge block. *) 1348*9880d681SAndroid Build Coastguard Worker let merge_bb = append_block context "ifcont" the_function in 1349*9880d681SAndroid Build Coastguard Worker position_at_end merge_bb builder; 1350*9880d681SAndroid Build Coastguard Worker let incoming = [(then_val, new_then_bb); (else_val, new_else_bb)] in 1351*9880d681SAndroid Build Coastguard Worker let phi = build_phi incoming "iftmp" builder in 1352*9880d681SAndroid Build Coastguard Worker 1353*9880d681SAndroid Build Coastguard Worker (* Return to the start block to add the conditional branch. *) 1354*9880d681SAndroid Build Coastguard Worker position_at_end start_bb builder; 1355*9880d681SAndroid Build Coastguard Worker ignore (build_cond_br cond_val then_bb else_bb builder); 1356*9880d681SAndroid Build Coastguard Worker 1357*9880d681SAndroid Build Coastguard Worker (* Set a unconditional branch at the end of the 'then' block and the 1358*9880d681SAndroid Build Coastguard Worker * 'else' block to the 'merge' block. *) 1359*9880d681SAndroid Build Coastguard Worker position_at_end new_then_bb builder; ignore (build_br merge_bb builder); 1360*9880d681SAndroid Build Coastguard Worker position_at_end new_else_bb builder; ignore (build_br merge_bb builder); 1361*9880d681SAndroid Build Coastguard Worker 1362*9880d681SAndroid Build Coastguard Worker (* Finally, set the builder to the end of the merge block. *) 1363*9880d681SAndroid Build Coastguard Worker position_at_end merge_bb builder; 1364*9880d681SAndroid Build Coastguard Worker 1365*9880d681SAndroid Build Coastguard Worker phi 1366*9880d681SAndroid Build Coastguard Worker | Ast.For (var_name, start, end_, step, body) -> 1367*9880d681SAndroid Build Coastguard Worker (* Output this as: 1368*9880d681SAndroid Build Coastguard Worker * var = alloca double 1369*9880d681SAndroid Build Coastguard Worker * ... 1370*9880d681SAndroid Build Coastguard Worker * start = startexpr 1371*9880d681SAndroid Build Coastguard Worker * store start -> var 1372*9880d681SAndroid Build Coastguard Worker * goto loop 1373*9880d681SAndroid Build Coastguard Worker * loop: 1374*9880d681SAndroid Build Coastguard Worker * ... 1375*9880d681SAndroid Build Coastguard Worker * bodyexpr 1376*9880d681SAndroid Build Coastguard Worker * ... 1377*9880d681SAndroid Build Coastguard Worker * loopend: 1378*9880d681SAndroid Build Coastguard Worker * step = stepexpr 1379*9880d681SAndroid Build Coastguard Worker * endcond = endexpr 1380*9880d681SAndroid Build Coastguard Worker * 1381*9880d681SAndroid Build Coastguard Worker * curvar = load var 1382*9880d681SAndroid Build Coastguard Worker * nextvar = curvar + step 1383*9880d681SAndroid Build Coastguard Worker * store nextvar -> var 1384*9880d681SAndroid Build Coastguard Worker * br endcond, loop, endloop 1385*9880d681SAndroid Build Coastguard Worker * outloop: *) 1386*9880d681SAndroid Build Coastguard Worker 1387*9880d681SAndroid Build Coastguard Worker let the_function = block_parent (insertion_block builder) in 1388*9880d681SAndroid Build Coastguard Worker 1389*9880d681SAndroid Build Coastguard Worker (* Create an alloca for the variable in the entry block. *) 1390*9880d681SAndroid Build Coastguard Worker let alloca = create_entry_block_alloca the_function var_name in 1391*9880d681SAndroid Build Coastguard Worker 1392*9880d681SAndroid Build Coastguard Worker (* Emit the start code first, without 'variable' in scope. *) 1393*9880d681SAndroid Build Coastguard Worker let start_val = codegen_expr start in 1394*9880d681SAndroid Build Coastguard Worker 1395*9880d681SAndroid Build Coastguard Worker (* Store the value into the alloca. *) 1396*9880d681SAndroid Build Coastguard Worker ignore(build_store start_val alloca builder); 1397*9880d681SAndroid Build Coastguard Worker 1398*9880d681SAndroid Build Coastguard Worker (* Make the new basic block for the loop header, inserting after current 1399*9880d681SAndroid Build Coastguard Worker * block. *) 1400*9880d681SAndroid Build Coastguard Worker let loop_bb = append_block context "loop" the_function in 1401*9880d681SAndroid Build Coastguard Worker 1402*9880d681SAndroid Build Coastguard Worker (* Insert an explicit fall through from the current block to the 1403*9880d681SAndroid Build Coastguard Worker * loop_bb. *) 1404*9880d681SAndroid Build Coastguard Worker ignore (build_br loop_bb builder); 1405*9880d681SAndroid Build Coastguard Worker 1406*9880d681SAndroid Build Coastguard Worker (* Start insertion in loop_bb. *) 1407*9880d681SAndroid Build Coastguard Worker position_at_end loop_bb builder; 1408*9880d681SAndroid Build Coastguard Worker 1409*9880d681SAndroid Build Coastguard Worker (* Within the loop, the variable is defined equal to the PHI node. If it 1410*9880d681SAndroid Build Coastguard Worker * shadows an existing variable, we have to restore it, so save it 1411*9880d681SAndroid Build Coastguard Worker * now. *) 1412*9880d681SAndroid Build Coastguard Worker let old_val = 1413*9880d681SAndroid Build Coastguard Worker try Some (Hashtbl.find named_values var_name) with Not_found -> None 1414*9880d681SAndroid Build Coastguard Worker in 1415*9880d681SAndroid Build Coastguard Worker Hashtbl.add named_values var_name alloca; 1416*9880d681SAndroid Build Coastguard Worker 1417*9880d681SAndroid Build Coastguard Worker (* Emit the body of the loop. This, like any other expr, can change the 1418*9880d681SAndroid Build Coastguard Worker * current BB. Note that we ignore the value computed by the body, but 1419*9880d681SAndroid Build Coastguard Worker * don't allow an error *) 1420*9880d681SAndroid Build Coastguard Worker ignore (codegen_expr body); 1421*9880d681SAndroid Build Coastguard Worker 1422*9880d681SAndroid Build Coastguard Worker (* Emit the step value. *) 1423*9880d681SAndroid Build Coastguard Worker let step_val = 1424*9880d681SAndroid Build Coastguard Worker match step with 1425*9880d681SAndroid Build Coastguard Worker | Some step -> codegen_expr step 1426*9880d681SAndroid Build Coastguard Worker (* If not specified, use 1.0. *) 1427*9880d681SAndroid Build Coastguard Worker | None -> const_float double_type 1.0 1428*9880d681SAndroid Build Coastguard Worker in 1429*9880d681SAndroid Build Coastguard Worker 1430*9880d681SAndroid Build Coastguard Worker (* Compute the end condition. *) 1431*9880d681SAndroid Build Coastguard Worker let end_cond = codegen_expr end_ in 1432*9880d681SAndroid Build Coastguard Worker 1433*9880d681SAndroid Build Coastguard Worker (* Reload, increment, and restore the alloca. This handles the case where 1434*9880d681SAndroid Build Coastguard Worker * the body of the loop mutates the variable. *) 1435*9880d681SAndroid Build Coastguard Worker let cur_var = build_load alloca var_name builder in 1436*9880d681SAndroid Build Coastguard Worker let next_var = build_add cur_var step_val "nextvar" builder in 1437*9880d681SAndroid Build Coastguard Worker ignore(build_store next_var alloca builder); 1438*9880d681SAndroid Build Coastguard Worker 1439*9880d681SAndroid Build Coastguard Worker (* Convert condition to a bool by comparing equal to 0.0. *) 1440*9880d681SAndroid Build Coastguard Worker let zero = const_float double_type 0.0 in 1441*9880d681SAndroid Build Coastguard Worker let end_cond = build_fcmp Fcmp.One end_cond zero "loopcond" builder in 1442*9880d681SAndroid Build Coastguard Worker 1443*9880d681SAndroid Build Coastguard Worker (* Create the "after loop" block and insert it. *) 1444*9880d681SAndroid Build Coastguard Worker let after_bb = append_block context "afterloop" the_function in 1445*9880d681SAndroid Build Coastguard Worker 1446*9880d681SAndroid Build Coastguard Worker (* Insert the conditional branch into the end of loop_end_bb. *) 1447*9880d681SAndroid Build Coastguard Worker ignore (build_cond_br end_cond loop_bb after_bb builder); 1448*9880d681SAndroid Build Coastguard Worker 1449*9880d681SAndroid Build Coastguard Worker (* Any new code will be inserted in after_bb. *) 1450*9880d681SAndroid Build Coastguard Worker position_at_end after_bb builder; 1451*9880d681SAndroid Build Coastguard Worker 1452*9880d681SAndroid Build Coastguard Worker (* Restore the unshadowed variable. *) 1453*9880d681SAndroid Build Coastguard Worker begin match old_val with 1454*9880d681SAndroid Build Coastguard Worker | Some old_val -> Hashtbl.add named_values var_name old_val 1455*9880d681SAndroid Build Coastguard Worker | None -> () 1456*9880d681SAndroid Build Coastguard Worker end; 1457*9880d681SAndroid Build Coastguard Worker 1458*9880d681SAndroid Build Coastguard Worker (* for expr always returns 0.0. *) 1459*9880d681SAndroid Build Coastguard Worker const_null double_type 1460*9880d681SAndroid Build Coastguard Worker | Ast.Var (var_names, body) -> 1461*9880d681SAndroid Build Coastguard Worker let old_bindings = ref [] in 1462*9880d681SAndroid Build Coastguard Worker 1463*9880d681SAndroid Build Coastguard Worker let the_function = block_parent (insertion_block builder) in 1464*9880d681SAndroid Build Coastguard Worker 1465*9880d681SAndroid Build Coastguard Worker (* Register all variables and emit their initializer. *) 1466*9880d681SAndroid Build Coastguard Worker Array.iter (fun (var_name, init) -> 1467*9880d681SAndroid Build Coastguard Worker (* Emit the initializer before adding the variable to scope, this 1468*9880d681SAndroid Build Coastguard Worker * prevents the initializer from referencing the variable itself, and 1469*9880d681SAndroid Build Coastguard Worker * permits stuff like this: 1470*9880d681SAndroid Build Coastguard Worker * var a = 1 in 1471*9880d681SAndroid Build Coastguard Worker * var a = a in ... # refers to outer 'a'. *) 1472*9880d681SAndroid Build Coastguard Worker let init_val = 1473*9880d681SAndroid Build Coastguard Worker match init with 1474*9880d681SAndroid Build Coastguard Worker | Some init -> codegen_expr init 1475*9880d681SAndroid Build Coastguard Worker (* If not specified, use 0.0. *) 1476*9880d681SAndroid Build Coastguard Worker | None -> const_float double_type 0.0 1477*9880d681SAndroid Build Coastguard Worker in 1478*9880d681SAndroid Build Coastguard Worker 1479*9880d681SAndroid Build Coastguard Worker let alloca = create_entry_block_alloca the_function var_name in 1480*9880d681SAndroid Build Coastguard Worker ignore(build_store init_val alloca builder); 1481*9880d681SAndroid Build Coastguard Worker 1482*9880d681SAndroid Build Coastguard Worker (* Remember the old variable binding so that we can restore the binding 1483*9880d681SAndroid Build Coastguard Worker * when we unrecurse. *) 1484*9880d681SAndroid Build Coastguard Worker begin 1485*9880d681SAndroid Build Coastguard Worker try 1486*9880d681SAndroid Build Coastguard Worker let old_value = Hashtbl.find named_values var_name in 1487*9880d681SAndroid Build Coastguard Worker old_bindings := (var_name, old_value) :: !old_bindings; 1488*9880d681SAndroid Build Coastguard Worker with Not_found -> () 1489*9880d681SAndroid Build Coastguard Worker end; 1490*9880d681SAndroid Build Coastguard Worker 1491*9880d681SAndroid Build Coastguard Worker (* Remember this binding. *) 1492*9880d681SAndroid Build Coastguard Worker Hashtbl.add named_values var_name alloca; 1493*9880d681SAndroid Build Coastguard Worker ) var_names; 1494*9880d681SAndroid Build Coastguard Worker 1495*9880d681SAndroid Build Coastguard Worker (* Codegen the body, now that all vars are in scope. *) 1496*9880d681SAndroid Build Coastguard Worker let body_val = codegen_expr body in 1497*9880d681SAndroid Build Coastguard Worker 1498*9880d681SAndroid Build Coastguard Worker (* Pop all our variables from scope. *) 1499*9880d681SAndroid Build Coastguard Worker List.iter (fun (var_name, old_value) -> 1500*9880d681SAndroid Build Coastguard Worker Hashtbl.add named_values var_name old_value 1501*9880d681SAndroid Build Coastguard Worker ) !old_bindings; 1502*9880d681SAndroid Build Coastguard Worker 1503*9880d681SAndroid Build Coastguard Worker (* Return the body computation. *) 1504*9880d681SAndroid Build Coastguard Worker body_val 1505*9880d681SAndroid Build Coastguard Worker 1506*9880d681SAndroid Build Coastguard Worker let codegen_proto = function 1507*9880d681SAndroid Build Coastguard Worker | Ast.Prototype (name, args) | Ast.BinOpPrototype (name, args, _) -> 1508*9880d681SAndroid Build Coastguard Worker (* Make the function type: double(double,double) etc. *) 1509*9880d681SAndroid Build Coastguard Worker let doubles = Array.make (Array.length args) double_type in 1510*9880d681SAndroid Build Coastguard Worker let ft = function_type double_type doubles in 1511*9880d681SAndroid Build Coastguard Worker let f = 1512*9880d681SAndroid Build Coastguard Worker match lookup_function name the_module with 1513*9880d681SAndroid Build Coastguard Worker | None -> declare_function name ft the_module 1514*9880d681SAndroid Build Coastguard Worker 1515*9880d681SAndroid Build Coastguard Worker (* If 'f' conflicted, there was already something named 'name'. If it 1516*9880d681SAndroid Build Coastguard Worker * has a body, don't allow redefinition or reextern. *) 1517*9880d681SAndroid Build Coastguard Worker | Some f -> 1518*9880d681SAndroid Build Coastguard Worker (* If 'f' already has a body, reject this. *) 1519*9880d681SAndroid Build Coastguard Worker if block_begin f <> At_end f then 1520*9880d681SAndroid Build Coastguard Worker raise (Error "redefinition of function"); 1521*9880d681SAndroid Build Coastguard Worker 1522*9880d681SAndroid Build Coastguard Worker (* If 'f' took a different number of arguments, reject. *) 1523*9880d681SAndroid Build Coastguard Worker if element_type (type_of f) <> ft then 1524*9880d681SAndroid Build Coastguard Worker raise (Error "redefinition of function with different # args"); 1525*9880d681SAndroid Build Coastguard Worker f 1526*9880d681SAndroid Build Coastguard Worker in 1527*9880d681SAndroid Build Coastguard Worker 1528*9880d681SAndroid Build Coastguard Worker (* Set names for all arguments. *) 1529*9880d681SAndroid Build Coastguard Worker Array.iteri (fun i a -> 1530*9880d681SAndroid Build Coastguard Worker let n = args.(i) in 1531*9880d681SAndroid Build Coastguard Worker set_value_name n a; 1532*9880d681SAndroid Build Coastguard Worker Hashtbl.add named_values n a; 1533*9880d681SAndroid Build Coastguard Worker ) (params f); 1534*9880d681SAndroid Build Coastguard Worker f 1535*9880d681SAndroid Build Coastguard Worker 1536*9880d681SAndroid Build Coastguard Worker (* Create an alloca for each argument and register the argument in the symbol 1537*9880d681SAndroid Build Coastguard Worker * table so that references to it will succeed. *) 1538*9880d681SAndroid Build Coastguard Worker let create_argument_allocas the_function proto = 1539*9880d681SAndroid Build Coastguard Worker let args = match proto with 1540*9880d681SAndroid Build Coastguard Worker | Ast.Prototype (_, args) | Ast.BinOpPrototype (_, args, _) -> args 1541*9880d681SAndroid Build Coastguard Worker in 1542*9880d681SAndroid Build Coastguard Worker Array.iteri (fun i ai -> 1543*9880d681SAndroid Build Coastguard Worker let var_name = args.(i) in 1544*9880d681SAndroid Build Coastguard Worker (* Create an alloca for this variable. *) 1545*9880d681SAndroid Build Coastguard Worker let alloca = create_entry_block_alloca the_function var_name in 1546*9880d681SAndroid Build Coastguard Worker 1547*9880d681SAndroid Build Coastguard Worker (* Store the initial value into the alloca. *) 1548*9880d681SAndroid Build Coastguard Worker ignore(build_store ai alloca builder); 1549*9880d681SAndroid Build Coastguard Worker 1550*9880d681SAndroid Build Coastguard Worker (* Add arguments to variable symbol table. *) 1551*9880d681SAndroid Build Coastguard Worker Hashtbl.add named_values var_name alloca; 1552*9880d681SAndroid Build Coastguard Worker ) (params the_function) 1553*9880d681SAndroid Build Coastguard Worker 1554*9880d681SAndroid Build Coastguard Worker let codegen_func the_fpm = function 1555*9880d681SAndroid Build Coastguard Worker | Ast.Function (proto, body) -> 1556*9880d681SAndroid Build Coastguard Worker Hashtbl.clear named_values; 1557*9880d681SAndroid Build Coastguard Worker let the_function = codegen_proto proto in 1558*9880d681SAndroid Build Coastguard Worker 1559*9880d681SAndroid Build Coastguard Worker (* If this is an operator, install it. *) 1560*9880d681SAndroid Build Coastguard Worker begin match proto with 1561*9880d681SAndroid Build Coastguard Worker | Ast.BinOpPrototype (name, args, prec) -> 1562*9880d681SAndroid Build Coastguard Worker let op = name.[String.length name - 1] in 1563*9880d681SAndroid Build Coastguard Worker Hashtbl.add Parser.binop_precedence op prec; 1564*9880d681SAndroid Build Coastguard Worker | _ -> () 1565*9880d681SAndroid Build Coastguard Worker end; 1566*9880d681SAndroid Build Coastguard Worker 1567*9880d681SAndroid Build Coastguard Worker (* Create a new basic block to start insertion into. *) 1568*9880d681SAndroid Build Coastguard Worker let bb = append_block context "entry" the_function in 1569*9880d681SAndroid Build Coastguard Worker position_at_end bb builder; 1570*9880d681SAndroid Build Coastguard Worker 1571*9880d681SAndroid Build Coastguard Worker try 1572*9880d681SAndroid Build Coastguard Worker (* Add all arguments to the symbol table and create their allocas. *) 1573*9880d681SAndroid Build Coastguard Worker create_argument_allocas the_function proto; 1574*9880d681SAndroid Build Coastguard Worker 1575*9880d681SAndroid Build Coastguard Worker let ret_val = codegen_expr body in 1576*9880d681SAndroid Build Coastguard Worker 1577*9880d681SAndroid Build Coastguard Worker (* Finish off the function. *) 1578*9880d681SAndroid Build Coastguard Worker let _ = build_ret ret_val builder in 1579*9880d681SAndroid Build Coastguard Worker 1580*9880d681SAndroid Build Coastguard Worker (* Validate the generated code, checking for consistency. *) 1581*9880d681SAndroid Build Coastguard Worker Llvm_analysis.assert_valid_function the_function; 1582*9880d681SAndroid Build Coastguard Worker 1583*9880d681SAndroid Build Coastguard Worker (* Optimize the function. *) 1584*9880d681SAndroid Build Coastguard Worker let _ = PassManager.run_function the_function the_fpm in 1585*9880d681SAndroid Build Coastguard Worker 1586*9880d681SAndroid Build Coastguard Worker the_function 1587*9880d681SAndroid Build Coastguard Worker with e -> 1588*9880d681SAndroid Build Coastguard Worker delete_function the_function; 1589*9880d681SAndroid Build Coastguard Worker raise e 1590*9880d681SAndroid Build Coastguard Worker 1591*9880d681SAndroid Build Coastguard Workertoplevel.ml: 1592*9880d681SAndroid Build Coastguard Worker .. code-block:: ocaml 1593*9880d681SAndroid Build Coastguard Worker 1594*9880d681SAndroid Build Coastguard Worker (*===----------------------------------------------------------------------=== 1595*9880d681SAndroid Build Coastguard Worker * Top-Level parsing and JIT Driver 1596*9880d681SAndroid Build Coastguard Worker *===----------------------------------------------------------------------===*) 1597*9880d681SAndroid Build Coastguard Worker 1598*9880d681SAndroid Build Coastguard Worker open Llvm 1599*9880d681SAndroid Build Coastguard Worker open Llvm_executionengine 1600*9880d681SAndroid Build Coastguard Worker 1601*9880d681SAndroid Build Coastguard Worker (* top ::= definition | external | expression | ';' *) 1602*9880d681SAndroid Build Coastguard Worker let rec main_loop the_fpm the_execution_engine stream = 1603*9880d681SAndroid Build Coastguard Worker match Stream.peek stream with 1604*9880d681SAndroid Build Coastguard Worker | None -> () 1605*9880d681SAndroid Build Coastguard Worker 1606*9880d681SAndroid Build Coastguard Worker (* ignore top-level semicolons. *) 1607*9880d681SAndroid Build Coastguard Worker | Some (Token.Kwd ';') -> 1608*9880d681SAndroid Build Coastguard Worker Stream.junk stream; 1609*9880d681SAndroid Build Coastguard Worker main_loop the_fpm the_execution_engine stream 1610*9880d681SAndroid Build Coastguard Worker 1611*9880d681SAndroid Build Coastguard Worker | Some token -> 1612*9880d681SAndroid Build Coastguard Worker begin 1613*9880d681SAndroid Build Coastguard Worker try match token with 1614*9880d681SAndroid Build Coastguard Worker | Token.Def -> 1615*9880d681SAndroid Build Coastguard Worker let e = Parser.parse_definition stream in 1616*9880d681SAndroid Build Coastguard Worker print_endline "parsed a function definition."; 1617*9880d681SAndroid Build Coastguard Worker dump_value (Codegen.codegen_func the_fpm e); 1618*9880d681SAndroid Build Coastguard Worker | Token.Extern -> 1619*9880d681SAndroid Build Coastguard Worker let e = Parser.parse_extern stream in 1620*9880d681SAndroid Build Coastguard Worker print_endline "parsed an extern."; 1621*9880d681SAndroid Build Coastguard Worker dump_value (Codegen.codegen_proto e); 1622*9880d681SAndroid Build Coastguard Worker | _ -> 1623*9880d681SAndroid Build Coastguard Worker (* Evaluate a top-level expression into an anonymous function. *) 1624*9880d681SAndroid Build Coastguard Worker let e = Parser.parse_toplevel stream in 1625*9880d681SAndroid Build Coastguard Worker print_endline "parsed a top-level expr"; 1626*9880d681SAndroid Build Coastguard Worker let the_function = Codegen.codegen_func the_fpm e in 1627*9880d681SAndroid Build Coastguard Worker dump_value the_function; 1628*9880d681SAndroid Build Coastguard Worker 1629*9880d681SAndroid Build Coastguard Worker (* JIT the function, returning a function pointer. *) 1630*9880d681SAndroid Build Coastguard Worker let result = ExecutionEngine.run_function the_function [||] 1631*9880d681SAndroid Build Coastguard Worker the_execution_engine in 1632*9880d681SAndroid Build Coastguard Worker 1633*9880d681SAndroid Build Coastguard Worker print_string "Evaluated to "; 1634*9880d681SAndroid Build Coastguard Worker print_float (GenericValue.as_float Codegen.double_type result); 1635*9880d681SAndroid Build Coastguard Worker print_newline (); 1636*9880d681SAndroid Build Coastguard Worker with Stream.Error s | Codegen.Error s -> 1637*9880d681SAndroid Build Coastguard Worker (* Skip token for error recovery. *) 1638*9880d681SAndroid Build Coastguard Worker Stream.junk stream; 1639*9880d681SAndroid Build Coastguard Worker print_endline s; 1640*9880d681SAndroid Build Coastguard Worker end; 1641*9880d681SAndroid Build Coastguard Worker print_string "ready> "; flush stdout; 1642*9880d681SAndroid Build Coastguard Worker main_loop the_fpm the_execution_engine stream 1643*9880d681SAndroid Build Coastguard Worker 1644*9880d681SAndroid Build Coastguard Workertoy.ml: 1645*9880d681SAndroid Build Coastguard Worker .. code-block:: ocaml 1646*9880d681SAndroid Build Coastguard Worker 1647*9880d681SAndroid Build Coastguard Worker (*===----------------------------------------------------------------------=== 1648*9880d681SAndroid Build Coastguard Worker * Main driver code. 1649*9880d681SAndroid Build Coastguard Worker *===----------------------------------------------------------------------===*) 1650*9880d681SAndroid Build Coastguard Worker 1651*9880d681SAndroid Build Coastguard Worker open Llvm 1652*9880d681SAndroid Build Coastguard Worker open Llvm_executionengine 1653*9880d681SAndroid Build Coastguard Worker open Llvm_target 1654*9880d681SAndroid Build Coastguard Worker open Llvm_scalar_opts 1655*9880d681SAndroid Build Coastguard Worker 1656*9880d681SAndroid Build Coastguard Worker let main () = 1657*9880d681SAndroid Build Coastguard Worker ignore (initialize_native_target ()); 1658*9880d681SAndroid Build Coastguard Worker 1659*9880d681SAndroid Build Coastguard Worker (* Install standard binary operators. 1660*9880d681SAndroid Build Coastguard Worker * 1 is the lowest precedence. *) 1661*9880d681SAndroid Build Coastguard Worker Hashtbl.add Parser.binop_precedence '=' 2; 1662*9880d681SAndroid Build Coastguard Worker Hashtbl.add Parser.binop_precedence '<' 10; 1663*9880d681SAndroid Build Coastguard Worker Hashtbl.add Parser.binop_precedence '+' 20; 1664*9880d681SAndroid Build Coastguard Worker Hashtbl.add Parser.binop_precedence '-' 20; 1665*9880d681SAndroid Build Coastguard Worker Hashtbl.add Parser.binop_precedence '*' 40; (* highest. *) 1666*9880d681SAndroid Build Coastguard Worker 1667*9880d681SAndroid Build Coastguard Worker (* Prime the first token. *) 1668*9880d681SAndroid Build Coastguard Worker print_string "ready> "; flush stdout; 1669*9880d681SAndroid Build Coastguard Worker let stream = Lexer.lex (Stream.of_channel stdin) in 1670*9880d681SAndroid Build Coastguard Worker 1671*9880d681SAndroid Build Coastguard Worker (* Create the JIT. *) 1672*9880d681SAndroid Build Coastguard Worker let the_execution_engine = ExecutionEngine.create Codegen.the_module in 1673*9880d681SAndroid Build Coastguard Worker let the_fpm = PassManager.create_function Codegen.the_module in 1674*9880d681SAndroid Build Coastguard Worker 1675*9880d681SAndroid Build Coastguard Worker (* Set up the optimizer pipeline. Start with registering info about how the 1676*9880d681SAndroid Build Coastguard Worker * target lays out data structures. *) 1677*9880d681SAndroid Build Coastguard Worker DataLayout.add (ExecutionEngine.target_data the_execution_engine) the_fpm; 1678*9880d681SAndroid Build Coastguard Worker 1679*9880d681SAndroid Build Coastguard Worker (* Promote allocas to registers. *) 1680*9880d681SAndroid Build Coastguard Worker add_memory_to_register_promotion the_fpm; 1681*9880d681SAndroid Build Coastguard Worker 1682*9880d681SAndroid Build Coastguard Worker (* Do simple "peephole" optimizations and bit-twiddling optzn. *) 1683*9880d681SAndroid Build Coastguard Worker add_instruction_combination the_fpm; 1684*9880d681SAndroid Build Coastguard Worker 1685*9880d681SAndroid Build Coastguard Worker (* reassociate expressions. *) 1686*9880d681SAndroid Build Coastguard Worker add_reassociation the_fpm; 1687*9880d681SAndroid Build Coastguard Worker 1688*9880d681SAndroid Build Coastguard Worker (* Eliminate Common SubExpressions. *) 1689*9880d681SAndroid Build Coastguard Worker add_gvn the_fpm; 1690*9880d681SAndroid Build Coastguard Worker 1691*9880d681SAndroid Build Coastguard Worker (* Simplify the control flow graph (deleting unreachable blocks, etc). *) 1692*9880d681SAndroid Build Coastguard Worker add_cfg_simplification the_fpm; 1693*9880d681SAndroid Build Coastguard Worker 1694*9880d681SAndroid Build Coastguard Worker ignore (PassManager.initialize the_fpm); 1695*9880d681SAndroid Build Coastguard Worker 1696*9880d681SAndroid Build Coastguard Worker (* Run the main "interpreter loop" now. *) 1697*9880d681SAndroid Build Coastguard Worker Toplevel.main_loop the_fpm the_execution_engine stream; 1698*9880d681SAndroid Build Coastguard Worker 1699*9880d681SAndroid Build Coastguard Worker (* Print out all the generated code. *) 1700*9880d681SAndroid Build Coastguard Worker dump_module Codegen.the_module 1701*9880d681SAndroid Build Coastguard Worker ;; 1702*9880d681SAndroid Build Coastguard Worker 1703*9880d681SAndroid Build Coastguard Worker main () 1704*9880d681SAndroid Build Coastguard Worker 1705*9880d681SAndroid Build Coastguard Workerbindings.c 1706*9880d681SAndroid Build Coastguard Worker .. code-block:: c 1707*9880d681SAndroid Build Coastguard Worker 1708*9880d681SAndroid Build Coastguard Worker #include <stdio.h> 1709*9880d681SAndroid Build Coastguard Worker 1710*9880d681SAndroid Build Coastguard Worker /* putchard - putchar that takes a double and returns 0. */ 1711*9880d681SAndroid Build Coastguard Worker extern double putchard(double X) { 1712*9880d681SAndroid Build Coastguard Worker putchar((char)X); 1713*9880d681SAndroid Build Coastguard Worker return 0; 1714*9880d681SAndroid Build Coastguard Worker } 1715*9880d681SAndroid Build Coastguard Worker 1716*9880d681SAndroid Build Coastguard Worker /* printd - printf that takes a double prints it as "%f\n", returning 0. */ 1717*9880d681SAndroid Build Coastguard Worker extern double printd(double X) { 1718*9880d681SAndroid Build Coastguard Worker printf("%f\n", X); 1719*9880d681SAndroid Build Coastguard Worker return 0; 1720*9880d681SAndroid Build Coastguard Worker } 1721*9880d681SAndroid Build Coastguard Worker 1722*9880d681SAndroid Build Coastguard Worker`Next: Conclusion and other useful LLVM tidbits <OCamlLangImpl8.html>`_ 1723*9880d681SAndroid Build Coastguard Worker 1724