1*9880d681SAndroid Build Coastguard Worker(*===----------------------------------------------------------------------=== 2*9880d681SAndroid Build Coastguard Worker * Code Generation 3*9880d681SAndroid Build Coastguard Worker *===----------------------------------------------------------------------===*) 4*9880d681SAndroid Build Coastguard Worker 5*9880d681SAndroid Build Coastguard Workeropen Llvm 6*9880d681SAndroid Build Coastguard Worker 7*9880d681SAndroid Build Coastguard Workerexception Error of string 8*9880d681SAndroid Build Coastguard Worker 9*9880d681SAndroid Build Coastguard Workerlet context = global_context () 10*9880d681SAndroid Build Coastguard Workerlet the_module = create_module context "my cool jit" 11*9880d681SAndroid Build Coastguard Workerlet builder = builder context 12*9880d681SAndroid Build Coastguard Workerlet named_values:(string, llvalue) Hashtbl.t = Hashtbl.create 10 13*9880d681SAndroid Build Coastguard Workerlet double_type = double_type context 14*9880d681SAndroid Build Coastguard Worker 15*9880d681SAndroid Build Coastguard Worker(* Create an alloca instruction in the entry block of the function. This 16*9880d681SAndroid Build Coastguard Worker * is used for mutable variables etc. *) 17*9880d681SAndroid Build Coastguard Workerlet create_entry_block_alloca the_function var_name = 18*9880d681SAndroid Build Coastguard Worker let builder = builder_at context (instr_begin (entry_block the_function)) in 19*9880d681SAndroid Build Coastguard Worker build_alloca double_type var_name builder 20*9880d681SAndroid Build Coastguard Worker 21*9880d681SAndroid Build Coastguard Workerlet rec codegen_expr = function 22*9880d681SAndroid Build Coastguard Worker | Ast.Number n -> const_float double_type n 23*9880d681SAndroid Build Coastguard Worker | Ast.Variable name -> 24*9880d681SAndroid Build Coastguard Worker let v = try Hashtbl.find named_values name with 25*9880d681SAndroid Build Coastguard Worker | Not_found -> raise (Error "unknown variable name") 26*9880d681SAndroid Build Coastguard Worker in 27*9880d681SAndroid Build Coastguard Worker (* Load the value. *) 28*9880d681SAndroid Build Coastguard Worker build_load v name builder 29*9880d681SAndroid Build Coastguard Worker | Ast.Unary (op, operand) -> 30*9880d681SAndroid Build Coastguard Worker let operand = codegen_expr operand in 31*9880d681SAndroid Build Coastguard Worker let callee = "unary" ^ (String.make 1 op) in 32*9880d681SAndroid Build Coastguard Worker let callee = 33*9880d681SAndroid Build Coastguard Worker match lookup_function callee the_module with 34*9880d681SAndroid Build Coastguard Worker | Some callee -> callee 35*9880d681SAndroid Build Coastguard Worker | None -> raise (Error "unknown unary operator") 36*9880d681SAndroid Build Coastguard Worker in 37*9880d681SAndroid Build Coastguard Worker build_call callee [|operand|] "unop" builder 38*9880d681SAndroid Build Coastguard Worker | Ast.Binary (op, lhs, rhs) -> 39*9880d681SAndroid Build Coastguard Worker begin match op with 40*9880d681SAndroid Build Coastguard Worker | '=' -> 41*9880d681SAndroid Build Coastguard Worker (* Special case '=' because we don't want to emit the LHS as an 42*9880d681SAndroid Build Coastguard Worker * expression. *) 43*9880d681SAndroid Build Coastguard Worker let name = 44*9880d681SAndroid Build Coastguard Worker match lhs with 45*9880d681SAndroid Build Coastguard Worker | Ast.Variable name -> name 46*9880d681SAndroid Build Coastguard Worker | _ -> raise (Error "destination of '=' must be a variable") 47*9880d681SAndroid Build Coastguard Worker in 48*9880d681SAndroid Build Coastguard Worker 49*9880d681SAndroid Build Coastguard Worker (* Codegen the rhs. *) 50*9880d681SAndroid Build Coastguard Worker let val_ = codegen_expr rhs in 51*9880d681SAndroid Build Coastguard Worker 52*9880d681SAndroid Build Coastguard Worker (* Lookup the name. *) 53*9880d681SAndroid Build Coastguard Worker let variable = try Hashtbl.find named_values name with 54*9880d681SAndroid Build Coastguard Worker | Not_found -> raise (Error "unknown variable name") 55*9880d681SAndroid Build Coastguard Worker in 56*9880d681SAndroid Build Coastguard Worker ignore(build_store val_ variable builder); 57*9880d681SAndroid Build Coastguard Worker val_ 58*9880d681SAndroid Build Coastguard Worker | _ -> 59*9880d681SAndroid Build Coastguard Worker let lhs_val = codegen_expr lhs in 60*9880d681SAndroid Build Coastguard Worker let rhs_val = codegen_expr rhs in 61*9880d681SAndroid Build Coastguard Worker begin 62*9880d681SAndroid Build Coastguard Worker match op with 63*9880d681SAndroid Build Coastguard Worker | '+' -> build_fadd lhs_val rhs_val "addtmp" builder 64*9880d681SAndroid Build Coastguard Worker | '-' -> build_fsub lhs_val rhs_val "subtmp" builder 65*9880d681SAndroid Build Coastguard Worker | '*' -> build_fmul lhs_val rhs_val "multmp" builder 66*9880d681SAndroid Build Coastguard Worker | '<' -> 67*9880d681SAndroid Build Coastguard Worker (* Convert bool 0/1 to double 0.0 or 1.0 *) 68*9880d681SAndroid Build Coastguard Worker let i = build_fcmp Fcmp.Ult lhs_val rhs_val "cmptmp" builder in 69*9880d681SAndroid Build Coastguard Worker build_uitofp i double_type "booltmp" builder 70*9880d681SAndroid Build Coastguard Worker | _ -> 71*9880d681SAndroid Build Coastguard Worker (* If it wasn't a builtin binary operator, it must be a user defined 72*9880d681SAndroid Build Coastguard Worker * one. Emit a call to it. *) 73*9880d681SAndroid Build Coastguard Worker let callee = "binary" ^ (String.make 1 op) in 74*9880d681SAndroid Build Coastguard Worker let callee = 75*9880d681SAndroid Build Coastguard Worker match lookup_function callee the_module with 76*9880d681SAndroid Build Coastguard Worker | Some callee -> callee 77*9880d681SAndroid Build Coastguard Worker | None -> raise (Error "binary operator not found!") 78*9880d681SAndroid Build Coastguard Worker in 79*9880d681SAndroid Build Coastguard Worker build_call callee [|lhs_val; rhs_val|] "binop" builder 80*9880d681SAndroid Build Coastguard Worker end 81*9880d681SAndroid Build Coastguard Worker end 82*9880d681SAndroid Build Coastguard Worker | Ast.Call (callee, args) -> 83*9880d681SAndroid Build Coastguard Worker (* Look up the name in the module table. *) 84*9880d681SAndroid Build Coastguard Worker let callee = 85*9880d681SAndroid Build Coastguard Worker match lookup_function callee the_module with 86*9880d681SAndroid Build Coastguard Worker | Some callee -> callee 87*9880d681SAndroid Build Coastguard Worker | None -> raise (Error "unknown function referenced") 88*9880d681SAndroid Build Coastguard Worker in 89*9880d681SAndroid Build Coastguard Worker let params = params callee in 90*9880d681SAndroid Build Coastguard Worker 91*9880d681SAndroid Build Coastguard Worker (* If argument mismatch error. *) 92*9880d681SAndroid Build Coastguard Worker if Array.length params == Array.length args then () else 93*9880d681SAndroid Build Coastguard Worker raise (Error "incorrect # arguments passed"); 94*9880d681SAndroid Build Coastguard Worker let args = Array.map codegen_expr args in 95*9880d681SAndroid Build Coastguard Worker build_call callee args "calltmp" builder 96*9880d681SAndroid Build Coastguard Worker | Ast.If (cond, then_, else_) -> 97*9880d681SAndroid Build Coastguard Worker let cond = codegen_expr cond in 98*9880d681SAndroid Build Coastguard Worker 99*9880d681SAndroid Build Coastguard Worker (* Convert condition to a bool by comparing equal to 0.0 *) 100*9880d681SAndroid Build Coastguard Worker let zero = const_float double_type 0.0 in 101*9880d681SAndroid Build Coastguard Worker let cond_val = build_fcmp Fcmp.One cond zero "ifcond" builder in 102*9880d681SAndroid Build Coastguard Worker 103*9880d681SAndroid Build Coastguard Worker (* Grab the first block so that we might later add the conditional branch 104*9880d681SAndroid Build Coastguard Worker * to it at the end of the function. *) 105*9880d681SAndroid Build Coastguard Worker let start_bb = insertion_block builder in 106*9880d681SAndroid Build Coastguard Worker let the_function = block_parent start_bb in 107*9880d681SAndroid Build Coastguard Worker 108*9880d681SAndroid Build Coastguard Worker let then_bb = append_block context "then" the_function in 109*9880d681SAndroid Build Coastguard Worker 110*9880d681SAndroid Build Coastguard Worker (* Emit 'then' value. *) 111*9880d681SAndroid Build Coastguard Worker position_at_end then_bb builder; 112*9880d681SAndroid Build Coastguard Worker let then_val = codegen_expr then_ in 113*9880d681SAndroid Build Coastguard Worker 114*9880d681SAndroid Build Coastguard Worker (* Codegen of 'then' can change the current block, update then_bb for the 115*9880d681SAndroid Build Coastguard Worker * phi. We create a new name because one is used for the phi node, and the 116*9880d681SAndroid Build Coastguard Worker * other is used for the conditional branch. *) 117*9880d681SAndroid Build Coastguard Worker let new_then_bb = insertion_block builder in 118*9880d681SAndroid Build Coastguard Worker 119*9880d681SAndroid Build Coastguard Worker (* Emit 'else' value. *) 120*9880d681SAndroid Build Coastguard Worker let else_bb = append_block context "else" the_function in 121*9880d681SAndroid Build Coastguard Worker position_at_end else_bb builder; 122*9880d681SAndroid Build Coastguard Worker let else_val = codegen_expr else_ in 123*9880d681SAndroid Build Coastguard Worker 124*9880d681SAndroid Build Coastguard Worker (* Codegen of 'else' can change the current block, update else_bb for the 125*9880d681SAndroid Build Coastguard Worker * phi. *) 126*9880d681SAndroid Build Coastguard Worker let new_else_bb = insertion_block builder in 127*9880d681SAndroid Build Coastguard Worker 128*9880d681SAndroid Build Coastguard Worker (* Emit merge block. *) 129*9880d681SAndroid Build Coastguard Worker let merge_bb = append_block context "ifcont" the_function in 130*9880d681SAndroid Build Coastguard Worker position_at_end merge_bb builder; 131*9880d681SAndroid Build Coastguard Worker let incoming = [(then_val, new_then_bb); (else_val, new_else_bb)] in 132*9880d681SAndroid Build Coastguard Worker let phi = build_phi incoming "iftmp" builder in 133*9880d681SAndroid Build Coastguard Worker 134*9880d681SAndroid Build Coastguard Worker (* Return to the start block to add the conditional branch. *) 135*9880d681SAndroid Build Coastguard Worker position_at_end start_bb builder; 136*9880d681SAndroid Build Coastguard Worker ignore (build_cond_br cond_val then_bb else_bb builder); 137*9880d681SAndroid Build Coastguard Worker 138*9880d681SAndroid Build Coastguard Worker (* Set a unconditional branch at the end of the 'then' block and the 139*9880d681SAndroid Build Coastguard Worker * 'else' block to the 'merge' block. *) 140*9880d681SAndroid Build Coastguard Worker position_at_end new_then_bb builder; ignore (build_br merge_bb builder); 141*9880d681SAndroid Build Coastguard Worker position_at_end new_else_bb builder; ignore (build_br merge_bb builder); 142*9880d681SAndroid Build Coastguard Worker 143*9880d681SAndroid Build Coastguard Worker (* Finally, set the builder to the end of the merge block. *) 144*9880d681SAndroid Build Coastguard Worker position_at_end merge_bb builder; 145*9880d681SAndroid Build Coastguard Worker 146*9880d681SAndroid Build Coastguard Worker phi 147*9880d681SAndroid Build Coastguard Worker | Ast.For (var_name, start, end_, step, body) -> 148*9880d681SAndroid Build Coastguard Worker (* Output this as: 149*9880d681SAndroid Build Coastguard Worker * var = alloca double 150*9880d681SAndroid Build Coastguard Worker * ... 151*9880d681SAndroid Build Coastguard Worker * start = startexpr 152*9880d681SAndroid Build Coastguard Worker * store start -> var 153*9880d681SAndroid Build Coastguard Worker * goto loop 154*9880d681SAndroid Build Coastguard Worker * loop: 155*9880d681SAndroid Build Coastguard Worker * ... 156*9880d681SAndroid Build Coastguard Worker * bodyexpr 157*9880d681SAndroid Build Coastguard Worker * ... 158*9880d681SAndroid Build Coastguard Worker * loopend: 159*9880d681SAndroid Build Coastguard Worker * step = stepexpr 160*9880d681SAndroid Build Coastguard Worker * endcond = endexpr 161*9880d681SAndroid Build Coastguard Worker * 162*9880d681SAndroid Build Coastguard Worker * curvar = load var 163*9880d681SAndroid Build Coastguard Worker * nextvar = curvar + step 164*9880d681SAndroid Build Coastguard Worker * store nextvar -> var 165*9880d681SAndroid Build Coastguard Worker * br endcond, loop, endloop 166*9880d681SAndroid Build Coastguard Worker * outloop: *) 167*9880d681SAndroid Build Coastguard Worker 168*9880d681SAndroid Build Coastguard Worker let the_function = block_parent (insertion_block builder) in 169*9880d681SAndroid Build Coastguard Worker 170*9880d681SAndroid Build Coastguard Worker (* Create an alloca for the variable in the entry block. *) 171*9880d681SAndroid Build Coastguard Worker let alloca = create_entry_block_alloca the_function var_name in 172*9880d681SAndroid Build Coastguard Worker 173*9880d681SAndroid Build Coastguard Worker (* Emit the start code first, without 'variable' in scope. *) 174*9880d681SAndroid Build Coastguard Worker let start_val = codegen_expr start in 175*9880d681SAndroid Build Coastguard Worker 176*9880d681SAndroid Build Coastguard Worker (* Store the value into the alloca. *) 177*9880d681SAndroid Build Coastguard Worker ignore(build_store start_val alloca builder); 178*9880d681SAndroid Build Coastguard Worker 179*9880d681SAndroid Build Coastguard Worker (* Make the new basic block for the loop header, inserting after current 180*9880d681SAndroid Build Coastguard Worker * block. *) 181*9880d681SAndroid Build Coastguard Worker let loop_bb = append_block context "loop" the_function in 182*9880d681SAndroid Build Coastguard Worker 183*9880d681SAndroid Build Coastguard Worker (* Insert an explicit fall through from the current block to the 184*9880d681SAndroid Build Coastguard Worker * loop_bb. *) 185*9880d681SAndroid Build Coastguard Worker ignore (build_br loop_bb builder); 186*9880d681SAndroid Build Coastguard Worker 187*9880d681SAndroid Build Coastguard Worker (* Start insertion in loop_bb. *) 188*9880d681SAndroid Build Coastguard Worker position_at_end loop_bb builder; 189*9880d681SAndroid Build Coastguard Worker 190*9880d681SAndroid Build Coastguard Worker (* Within the loop, the variable is defined equal to the PHI node. If it 191*9880d681SAndroid Build Coastguard Worker * shadows an existing variable, we have to restore it, so save it 192*9880d681SAndroid Build Coastguard Worker * now. *) 193*9880d681SAndroid Build Coastguard Worker let old_val = 194*9880d681SAndroid Build Coastguard Worker try Some (Hashtbl.find named_values var_name) with Not_found -> None 195*9880d681SAndroid Build Coastguard Worker in 196*9880d681SAndroid Build Coastguard Worker Hashtbl.add named_values var_name alloca; 197*9880d681SAndroid Build Coastguard Worker 198*9880d681SAndroid Build Coastguard Worker (* Emit the body of the loop. This, like any other expr, can change the 199*9880d681SAndroid Build Coastguard Worker * current BB. Note that we ignore the value computed by the body, but 200*9880d681SAndroid Build Coastguard Worker * don't allow an error *) 201*9880d681SAndroid Build Coastguard Worker ignore (codegen_expr body); 202*9880d681SAndroid Build Coastguard Worker 203*9880d681SAndroid Build Coastguard Worker (* Emit the step value. *) 204*9880d681SAndroid Build Coastguard Worker let step_val = 205*9880d681SAndroid Build Coastguard Worker match step with 206*9880d681SAndroid Build Coastguard Worker | Some step -> codegen_expr step 207*9880d681SAndroid Build Coastguard Worker (* If not specified, use 1.0. *) 208*9880d681SAndroid Build Coastguard Worker | None -> const_float double_type 1.0 209*9880d681SAndroid Build Coastguard Worker in 210*9880d681SAndroid Build Coastguard Worker 211*9880d681SAndroid Build Coastguard Worker (* Compute the end condition. *) 212*9880d681SAndroid Build Coastguard Worker let end_cond = codegen_expr end_ in 213*9880d681SAndroid Build Coastguard Worker 214*9880d681SAndroid Build Coastguard Worker (* Reload, increment, and restore the alloca. This handles the case where 215*9880d681SAndroid Build Coastguard Worker * the body of the loop mutates the variable. *) 216*9880d681SAndroid Build Coastguard Worker let cur_var = build_load alloca var_name builder in 217*9880d681SAndroid Build Coastguard Worker let next_var = build_add cur_var step_val "nextvar" builder in 218*9880d681SAndroid Build Coastguard Worker ignore(build_store next_var alloca builder); 219*9880d681SAndroid Build Coastguard Worker 220*9880d681SAndroid Build Coastguard Worker (* Convert condition to a bool by comparing equal to 0.0. *) 221*9880d681SAndroid Build Coastguard Worker let zero = const_float double_type 0.0 in 222*9880d681SAndroid Build Coastguard Worker let end_cond = build_fcmp Fcmp.One end_cond zero "loopcond" builder in 223*9880d681SAndroid Build Coastguard Worker 224*9880d681SAndroid Build Coastguard Worker (* Create the "after loop" block and insert it. *) 225*9880d681SAndroid Build Coastguard Worker let after_bb = append_block context "afterloop" the_function in 226*9880d681SAndroid Build Coastguard Worker 227*9880d681SAndroid Build Coastguard Worker (* Insert the conditional branch into the end of loop_end_bb. *) 228*9880d681SAndroid Build Coastguard Worker ignore (build_cond_br end_cond loop_bb after_bb builder); 229*9880d681SAndroid Build Coastguard Worker 230*9880d681SAndroid Build Coastguard Worker (* Any new code will be inserted in after_bb. *) 231*9880d681SAndroid Build Coastguard Worker position_at_end after_bb builder; 232*9880d681SAndroid Build Coastguard Worker 233*9880d681SAndroid Build Coastguard Worker (* Restore the unshadowed variable. *) 234*9880d681SAndroid Build Coastguard Worker begin match old_val with 235*9880d681SAndroid Build Coastguard Worker | Some old_val -> Hashtbl.add named_values var_name old_val 236*9880d681SAndroid Build Coastguard Worker | None -> () 237*9880d681SAndroid Build Coastguard Worker end; 238*9880d681SAndroid Build Coastguard Worker 239*9880d681SAndroid Build Coastguard Worker (* for expr always returns 0.0. *) 240*9880d681SAndroid Build Coastguard Worker const_null double_type 241*9880d681SAndroid Build Coastguard Worker | Ast.Var (var_names, body) -> 242*9880d681SAndroid Build Coastguard Worker let old_bindings = ref [] in 243*9880d681SAndroid Build Coastguard Worker 244*9880d681SAndroid Build Coastguard Worker let the_function = block_parent (insertion_block builder) in 245*9880d681SAndroid Build Coastguard Worker 246*9880d681SAndroid Build Coastguard Worker (* Register all variables and emit their initializer. *) 247*9880d681SAndroid Build Coastguard Worker Array.iter (fun (var_name, init) -> 248*9880d681SAndroid Build Coastguard Worker (* Emit the initializer before adding the variable to scope, this 249*9880d681SAndroid Build Coastguard Worker * prevents the initializer from referencing the variable itself, and 250*9880d681SAndroid Build Coastguard Worker * permits stuff like this: 251*9880d681SAndroid Build Coastguard Worker * var a = 1 in 252*9880d681SAndroid Build Coastguard Worker * var a = a in ... # refers to outer 'a'. *) 253*9880d681SAndroid Build Coastguard Worker let init_val = 254*9880d681SAndroid Build Coastguard Worker match init with 255*9880d681SAndroid Build Coastguard Worker | Some init -> codegen_expr init 256*9880d681SAndroid Build Coastguard Worker (* If not specified, use 0.0. *) 257*9880d681SAndroid Build Coastguard Worker | None -> const_float double_type 0.0 258*9880d681SAndroid Build Coastguard Worker in 259*9880d681SAndroid Build Coastguard Worker 260*9880d681SAndroid Build Coastguard Worker let alloca = create_entry_block_alloca the_function var_name in 261*9880d681SAndroid Build Coastguard Worker ignore(build_store init_val alloca builder); 262*9880d681SAndroid Build Coastguard Worker 263*9880d681SAndroid Build Coastguard Worker (* Remember the old variable binding so that we can restore the binding 264*9880d681SAndroid Build Coastguard Worker * when we unrecurse. *) 265*9880d681SAndroid Build Coastguard Worker begin 266*9880d681SAndroid Build Coastguard Worker try 267*9880d681SAndroid Build Coastguard Worker let old_value = Hashtbl.find named_values var_name in 268*9880d681SAndroid Build Coastguard Worker old_bindings := (var_name, old_value) :: !old_bindings; 269*9880d681SAndroid Build Coastguard Worker with Not_found -> () 270*9880d681SAndroid Build Coastguard Worker end; 271*9880d681SAndroid Build Coastguard Worker 272*9880d681SAndroid Build Coastguard Worker (* Remember this binding. *) 273*9880d681SAndroid Build Coastguard Worker Hashtbl.add named_values var_name alloca; 274*9880d681SAndroid Build Coastguard Worker ) var_names; 275*9880d681SAndroid Build Coastguard Worker 276*9880d681SAndroid Build Coastguard Worker (* Codegen the body, now that all vars are in scope. *) 277*9880d681SAndroid Build Coastguard Worker let body_val = codegen_expr body in 278*9880d681SAndroid Build Coastguard Worker 279*9880d681SAndroid Build Coastguard Worker (* Pop all our variables from scope. *) 280*9880d681SAndroid Build Coastguard Worker List.iter (fun (var_name, old_value) -> 281*9880d681SAndroid Build Coastguard Worker Hashtbl.add named_values var_name old_value 282*9880d681SAndroid Build Coastguard Worker ) !old_bindings; 283*9880d681SAndroid Build Coastguard Worker 284*9880d681SAndroid Build Coastguard Worker (* Return the body computation. *) 285*9880d681SAndroid Build Coastguard Worker body_val 286*9880d681SAndroid Build Coastguard Worker 287*9880d681SAndroid Build Coastguard Workerlet codegen_proto = function 288*9880d681SAndroid Build Coastguard Worker | Ast.Prototype (name, args) | Ast.BinOpPrototype (name, args, _) -> 289*9880d681SAndroid Build Coastguard Worker (* Make the function type: double(double,double) etc. *) 290*9880d681SAndroid Build Coastguard Worker let doubles = Array.make (Array.length args) double_type in 291*9880d681SAndroid Build Coastguard Worker let ft = function_type double_type doubles in 292*9880d681SAndroid Build Coastguard Worker let f = 293*9880d681SAndroid Build Coastguard Worker match lookup_function name the_module with 294*9880d681SAndroid Build Coastguard Worker | None -> declare_function name ft the_module 295*9880d681SAndroid Build Coastguard Worker 296*9880d681SAndroid Build Coastguard Worker (* If 'f' conflicted, there was already something named 'name'. If it 297*9880d681SAndroid Build Coastguard Worker * has a body, don't allow redefinition or reextern. *) 298*9880d681SAndroid Build Coastguard Worker | Some f -> 299*9880d681SAndroid Build Coastguard Worker (* If 'f' already has a body, reject this. *) 300*9880d681SAndroid Build Coastguard Worker if block_begin f <> At_end f then 301*9880d681SAndroid Build Coastguard Worker raise (Error "redefinition of function"); 302*9880d681SAndroid Build Coastguard Worker 303*9880d681SAndroid Build Coastguard Worker (* If 'f' took a different number of arguments, reject. *) 304*9880d681SAndroid Build Coastguard Worker if element_type (type_of f) <> ft then 305*9880d681SAndroid Build Coastguard Worker raise (Error "redefinition of function with different # args"); 306*9880d681SAndroid Build Coastguard Worker f 307*9880d681SAndroid Build Coastguard Worker in 308*9880d681SAndroid Build Coastguard Worker 309*9880d681SAndroid Build Coastguard Worker (* Set names for all arguments. *) 310*9880d681SAndroid Build Coastguard Worker Array.iteri (fun i a -> 311*9880d681SAndroid Build Coastguard Worker let n = args.(i) in 312*9880d681SAndroid Build Coastguard Worker set_value_name n a; 313*9880d681SAndroid Build Coastguard Worker Hashtbl.add named_values n a; 314*9880d681SAndroid Build Coastguard Worker ) (params f); 315*9880d681SAndroid Build Coastguard Worker f 316*9880d681SAndroid Build Coastguard Worker 317*9880d681SAndroid Build Coastguard Worker(* Create an alloca for each argument and register the argument in the symbol 318*9880d681SAndroid Build Coastguard Worker * table so that references to it will succeed. *) 319*9880d681SAndroid Build Coastguard Workerlet create_argument_allocas the_function proto = 320*9880d681SAndroid Build Coastguard Worker let args = match proto with 321*9880d681SAndroid Build Coastguard Worker | Ast.Prototype (_, args) | Ast.BinOpPrototype (_, args, _) -> args 322*9880d681SAndroid Build Coastguard Worker in 323*9880d681SAndroid Build Coastguard Worker Array.iteri (fun i ai -> 324*9880d681SAndroid Build Coastguard Worker let var_name = args.(i) in 325*9880d681SAndroid Build Coastguard Worker (* Create an alloca for this variable. *) 326*9880d681SAndroid Build Coastguard Worker let alloca = create_entry_block_alloca the_function var_name in 327*9880d681SAndroid Build Coastguard Worker 328*9880d681SAndroid Build Coastguard Worker (* Store the initial value into the alloca. *) 329*9880d681SAndroid Build Coastguard Worker ignore(build_store ai alloca builder); 330*9880d681SAndroid Build Coastguard Worker 331*9880d681SAndroid Build Coastguard Worker (* Add arguments to variable symbol table. *) 332*9880d681SAndroid Build Coastguard Worker Hashtbl.add named_values var_name alloca; 333*9880d681SAndroid Build Coastguard Worker ) (params the_function) 334*9880d681SAndroid Build Coastguard Worker 335*9880d681SAndroid Build Coastguard Workerlet codegen_func the_fpm = function 336*9880d681SAndroid Build Coastguard Worker | Ast.Function (proto, body) -> 337*9880d681SAndroid Build Coastguard Worker Hashtbl.clear named_values; 338*9880d681SAndroid Build Coastguard Worker let the_function = codegen_proto proto in 339*9880d681SAndroid Build Coastguard Worker 340*9880d681SAndroid Build Coastguard Worker (* If this is an operator, install it. *) 341*9880d681SAndroid Build Coastguard Worker begin match proto with 342*9880d681SAndroid Build Coastguard Worker | Ast.BinOpPrototype (name, args, prec) -> 343*9880d681SAndroid Build Coastguard Worker let op = name.[String.length name - 1] in 344*9880d681SAndroid Build Coastguard Worker Hashtbl.add Parser.binop_precedence op prec; 345*9880d681SAndroid Build Coastguard Worker | _ -> () 346*9880d681SAndroid Build Coastguard Worker end; 347*9880d681SAndroid Build Coastguard Worker 348*9880d681SAndroid Build Coastguard Worker (* Create a new basic block to start insertion into. *) 349*9880d681SAndroid Build Coastguard Worker let bb = append_block context "entry" the_function in 350*9880d681SAndroid Build Coastguard Worker position_at_end bb builder; 351*9880d681SAndroid Build Coastguard Worker 352*9880d681SAndroid Build Coastguard Worker try 353*9880d681SAndroid Build Coastguard Worker (* Add all arguments to the symbol table and create their allocas. *) 354*9880d681SAndroid Build Coastguard Worker create_argument_allocas the_function proto; 355*9880d681SAndroid Build Coastguard Worker 356*9880d681SAndroid Build Coastguard Worker let ret_val = codegen_expr body in 357*9880d681SAndroid Build Coastguard Worker 358*9880d681SAndroid Build Coastguard Worker (* Finish off the function. *) 359*9880d681SAndroid Build Coastguard Worker let _ = build_ret ret_val builder in 360*9880d681SAndroid Build Coastguard Worker 361*9880d681SAndroid Build Coastguard Worker (* Validate the generated code, checking for consistency. *) 362*9880d681SAndroid Build Coastguard Worker Llvm_analysis.assert_valid_function the_function; 363*9880d681SAndroid Build Coastguard Worker 364*9880d681SAndroid Build Coastguard Worker (* Optimize the function. *) 365*9880d681SAndroid Build Coastguard Worker let _ = PassManager.run_function the_function the_fpm in 366*9880d681SAndroid Build Coastguard Worker 367*9880d681SAndroid Build Coastguard Worker the_function 368*9880d681SAndroid Build Coastguard Worker with e -> 369*9880d681SAndroid Build Coastguard Worker delete_function the_function; 370*9880d681SAndroid Build Coastguard Worker raise e 371