typed language with an expressive type system. WHY OCAML? WHY OCAML? Supports Algebraic Data Types (ADT), Pattern matching and type inference. Mature tools for programming language development like ocamllex, ocamlyacc and LLVM bindings.
reusable compiler and toolchain technologies. WHY LLVM? WHY LLVM? Typed bytecode which can be compiled to multiple backends. Highlevel constructs like functions, variables and basic blocks. Provides compiler optimizations for free.
Function Def nition Body (if) Expression List Formal Parameters (int, c) (ID,ID) List Name (factorial) ID Type (int) ID In Ocaml can be represented as def factorial(int c): int = { if (c == 1) { return 1 } else { return c*factorial(c-1) } } type op = Add | Mul | Div | Sub | Equal type typ = Bool | Int type bind = typ * string type func_decl = { ftype: typ; fname: string; formals: bind list; body: expr list; }
a list of expressions. In ocaml an expression can be represented as expr = Literal of int | BoolLit of bool | Id of string | Binop of expr * op * expr | Func of func_decl | Assign of string * expr | Call of string * expr list | If of expr * expr list * expr list | Return of expr | ExprList of expr list
Else (Return 20) Expression List Then (Return 10) Expression List Condition (x == 1) Expression if (x == 1) { return 10 } else { return 20 } If of expr * expr list * expr list
Function Def nition Expression List If Expression BinaryOp * Function Call BinaryOp - 1 Literal c ID factorial ID c ID Return 1 Expression BinaryOp == 1 Expression c Expression (Int,c) (ID,ID) List factorial ID Int ID def factorial(int c): int = { if (c == 1) { return 1 } else { return c*factorial(c-1) } }
FUNCTION DEFINITION Draw picture for AST of this function Expressed in LLVM bytecode def add (int a, int b): int = { return a+b } define i32 @add(i32 %a, i32 %b) { entry: %a1 = alloca i32 ; allocate local var a1 store i32 %a, i32* %a1 ; store param a to a1 %b2 = alloca i32 ; allocate local var b2 store i32 %b, i32* %b2 ; store param b to b2 %a3 = load i32, i32* %a1 ; load a1 to a2 %b4 = load i32, i32* %b2 ; local b2 to b4 %tmp = add i32 %a3, %b4 ; add a3 to b4 and store in tmp ret i32 %tmp ; return tmp }
= function A.Literal i -> L.const_int i32_t i | A.BoolLit b -> L.const_int i1_t (if b then 1 else 0) | A.Id s -> L.build_load (lookup s) s builder | A.Binop (e1, op, e2) -> let e1' = expr builder e1 and e2' = expr builder e2 in (match op with A.Add -> L.build_add | A.Sub -> L.build_sub | A.Mul -> L.build_mul | A.Div -> L.build_sdiv | A.Equal -> L.build_icmp L.Icmp.Eq ) e1' e2' "tmp" builder | A.Assign (s, e) -> let e' = expr builder e in ignore (L.build_store e' (lookup s) builder); e' | A.Call (f, act) -> let (fdef, fdecl) = StringMap.find function_decls f in let actuals = List.rev (List.map (expr builder) (List.rev act)) in let result = f ^ "_result") in L.build_call fdef (Array.of_list actuals) result builder
expr builder = function | A.If (c, tl , el) -> (* both then and else branches merge at a single point *) let bool_val = expr builder c in let merge_bb = L.append_block context "merge" the_function in let then_bb = L.append_block context "then" the_function in add_terminal (expr (L.builder_at_end context then_bb) (A.ExprList tl) L.builder_at_end context then_bb) (L.build_br merge_bb); let else_bb = L.append_block context "else" the_function in add_terminal (expr (L.builder_at_end context else_bb) (A.ExprList el) L.builder_at_end context else_bb) (L.build_br merge_bb); let merger = L.build_cond_br bool_val then_bb else_bb builder in L.position_at_end merge_bb builder; merger | A.Return e -> L.build_ret (expr builder e) builder | A.ExprList el -> let k = List.fold_left expr_build_returner builder el in let g = L.block_terminator (L.insertion_block k) in match g with Some x -> x | None -> L.const_int i32_t 0