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 Workerlet rec codegen_expr = function 16*9880d681SAndroid Build Coastguard Worker | Ast.Number n -> const_float double_type n 17*9880d681SAndroid Build Coastguard Worker | Ast.Variable name -> 18*9880d681SAndroid Build Coastguard Worker (try Hashtbl.find named_values name with 19*9880d681SAndroid Build Coastguard Worker | Not_found -> raise (Error "unknown variable name")) 20*9880d681SAndroid Build Coastguard Worker | Ast.Binary (op, lhs, rhs) -> 21*9880d681SAndroid Build Coastguard Worker let lhs_val = codegen_expr lhs in 22*9880d681SAndroid Build Coastguard Worker let rhs_val = codegen_expr rhs in 23*9880d681SAndroid Build Coastguard Worker begin 24*9880d681SAndroid Build Coastguard Worker match op with 25*9880d681SAndroid Build Coastguard Worker | '+' -> build_fadd lhs_val rhs_val "addtmp" builder 26*9880d681SAndroid Build Coastguard Worker | '-' -> build_fsub lhs_val rhs_val "subtmp" builder 27*9880d681SAndroid Build Coastguard Worker | '*' -> build_fmul lhs_val rhs_val "multmp" builder 28*9880d681SAndroid Build Coastguard Worker | '<' -> 29*9880d681SAndroid Build Coastguard Worker (* Convert bool 0/1 to double 0.0 or 1.0 *) 30*9880d681SAndroid Build Coastguard Worker let i = build_fcmp Fcmp.Ult lhs_val rhs_val "cmptmp" builder in 31*9880d681SAndroid Build Coastguard Worker build_uitofp i double_type "booltmp" builder 32*9880d681SAndroid Build Coastguard Worker | _ -> raise (Error "invalid binary operator") 33*9880d681SAndroid Build Coastguard Worker end 34*9880d681SAndroid Build Coastguard Worker | Ast.Call (callee, args) -> 35*9880d681SAndroid Build Coastguard Worker (* Look up the name in the module table. *) 36*9880d681SAndroid Build Coastguard Worker let callee = 37*9880d681SAndroid Build Coastguard Worker match lookup_function callee the_module with 38*9880d681SAndroid Build Coastguard Worker | Some callee -> callee 39*9880d681SAndroid Build Coastguard Worker | None -> raise (Error "unknown function referenced") 40*9880d681SAndroid Build Coastguard Worker in 41*9880d681SAndroid Build Coastguard Worker let params = params callee in 42*9880d681SAndroid Build Coastguard Worker 43*9880d681SAndroid Build Coastguard Worker (* If argument mismatch error. *) 44*9880d681SAndroid Build Coastguard Worker if Array.length params == Array.length args then () else 45*9880d681SAndroid Build Coastguard Worker raise (Error "incorrect # arguments passed"); 46*9880d681SAndroid Build Coastguard Worker let args = Array.map codegen_expr args in 47*9880d681SAndroid Build Coastguard Worker build_call callee args "calltmp" builder 48*9880d681SAndroid Build Coastguard Worker | Ast.If (cond, then_, else_) -> 49*9880d681SAndroid Build Coastguard Worker let cond = codegen_expr cond in 50*9880d681SAndroid Build Coastguard Worker 51*9880d681SAndroid Build Coastguard Worker (* Convert condition to a bool by comparing equal to 0.0 *) 52*9880d681SAndroid Build Coastguard Worker let zero = const_float double_type 0.0 in 53*9880d681SAndroid Build Coastguard Worker let cond_val = build_fcmp Fcmp.One cond zero "ifcond" builder in 54*9880d681SAndroid Build Coastguard Worker 55*9880d681SAndroid Build Coastguard Worker (* Grab the first block so that we might later add the conditional branch 56*9880d681SAndroid Build Coastguard Worker * to it at the end of the function. *) 57*9880d681SAndroid Build Coastguard Worker let start_bb = insertion_block builder in 58*9880d681SAndroid Build Coastguard Worker let the_function = block_parent start_bb in 59*9880d681SAndroid Build Coastguard Worker 60*9880d681SAndroid Build Coastguard Worker let then_bb = append_block context "then" the_function in 61*9880d681SAndroid Build Coastguard Worker 62*9880d681SAndroid Build Coastguard Worker (* Emit 'then' value. *) 63*9880d681SAndroid Build Coastguard Worker position_at_end then_bb builder; 64*9880d681SAndroid Build Coastguard Worker let then_val = codegen_expr then_ in 65*9880d681SAndroid Build Coastguard Worker 66*9880d681SAndroid Build Coastguard Worker (* Codegen of 'then' can change the current block, update then_bb for the 67*9880d681SAndroid Build Coastguard Worker * phi. We create a new name because one is used for the phi node, and the 68*9880d681SAndroid Build Coastguard Worker * other is used for the conditional branch. *) 69*9880d681SAndroid Build Coastguard Worker let new_then_bb = insertion_block builder in 70*9880d681SAndroid Build Coastguard Worker 71*9880d681SAndroid Build Coastguard Worker (* Emit 'else' value. *) 72*9880d681SAndroid Build Coastguard Worker let else_bb = append_block context "else" the_function in 73*9880d681SAndroid Build Coastguard Worker position_at_end else_bb builder; 74*9880d681SAndroid Build Coastguard Worker let else_val = codegen_expr else_ in 75*9880d681SAndroid Build Coastguard Worker 76*9880d681SAndroid Build Coastguard Worker (* Codegen of 'else' can change the current block, update else_bb for the 77*9880d681SAndroid Build Coastguard Worker * phi. *) 78*9880d681SAndroid Build Coastguard Worker let new_else_bb = insertion_block builder in 79*9880d681SAndroid Build Coastguard Worker 80*9880d681SAndroid Build Coastguard Worker (* Emit merge block. *) 81*9880d681SAndroid Build Coastguard Worker let merge_bb = append_block context "ifcont" the_function in 82*9880d681SAndroid Build Coastguard Worker position_at_end merge_bb builder; 83*9880d681SAndroid Build Coastguard Worker let incoming = [(then_val, new_then_bb); (else_val, new_else_bb)] in 84*9880d681SAndroid Build Coastguard Worker let phi = build_phi incoming "iftmp" builder in 85*9880d681SAndroid Build Coastguard Worker 86*9880d681SAndroid Build Coastguard Worker (* Return to the start block to add the conditional branch. *) 87*9880d681SAndroid Build Coastguard Worker position_at_end start_bb builder; 88*9880d681SAndroid Build Coastguard Worker ignore (build_cond_br cond_val then_bb else_bb builder); 89*9880d681SAndroid Build Coastguard Worker 90*9880d681SAndroid Build Coastguard Worker (* Set a unconditional branch at the end of the 'then' block and the 91*9880d681SAndroid Build Coastguard Worker * 'else' block to the 'merge' block. *) 92*9880d681SAndroid Build Coastguard Worker position_at_end new_then_bb builder; ignore (build_br merge_bb builder); 93*9880d681SAndroid Build Coastguard Worker position_at_end new_else_bb builder; ignore (build_br merge_bb builder); 94*9880d681SAndroid Build Coastguard Worker 95*9880d681SAndroid Build Coastguard Worker (* Finally, set the builder to the end of the merge block. *) 96*9880d681SAndroid Build Coastguard Worker position_at_end merge_bb builder; 97*9880d681SAndroid Build Coastguard Worker 98*9880d681SAndroid Build Coastguard Worker phi 99*9880d681SAndroid Build Coastguard Worker | Ast.For (var_name, start, end_, step, body) -> 100*9880d681SAndroid Build Coastguard Worker (* Emit the start code first, without 'variable' in scope. *) 101*9880d681SAndroid Build Coastguard Worker let start_val = codegen_expr start in 102*9880d681SAndroid Build Coastguard Worker 103*9880d681SAndroid Build Coastguard Worker (* Make the new basic block for the loop header, inserting after current 104*9880d681SAndroid Build Coastguard Worker * block. *) 105*9880d681SAndroid Build Coastguard Worker let preheader_bb = insertion_block builder in 106*9880d681SAndroid Build Coastguard Worker let the_function = block_parent preheader_bb in 107*9880d681SAndroid Build Coastguard Worker let loop_bb = append_block context "loop" the_function in 108*9880d681SAndroid Build Coastguard Worker 109*9880d681SAndroid Build Coastguard Worker (* Insert an explicit fall through from the current block to the 110*9880d681SAndroid Build Coastguard Worker * loop_bb. *) 111*9880d681SAndroid Build Coastguard Worker ignore (build_br loop_bb builder); 112*9880d681SAndroid Build Coastguard Worker 113*9880d681SAndroid Build Coastguard Worker (* Start insertion in loop_bb. *) 114*9880d681SAndroid Build Coastguard Worker position_at_end loop_bb builder; 115*9880d681SAndroid Build Coastguard Worker 116*9880d681SAndroid Build Coastguard Worker (* Start the PHI node with an entry for start. *) 117*9880d681SAndroid Build Coastguard Worker let variable = build_phi [(start_val, preheader_bb)] var_name builder in 118*9880d681SAndroid Build Coastguard Worker 119*9880d681SAndroid Build Coastguard Worker (* Within the loop, the variable is defined equal to the PHI node. If it 120*9880d681SAndroid Build Coastguard Worker * shadows an existing variable, we have to restore it, so save it 121*9880d681SAndroid Build Coastguard Worker * now. *) 122*9880d681SAndroid Build Coastguard Worker let old_val = 123*9880d681SAndroid Build Coastguard Worker try Some (Hashtbl.find named_values var_name) with Not_found -> None 124*9880d681SAndroid Build Coastguard Worker in 125*9880d681SAndroid Build Coastguard Worker Hashtbl.add named_values var_name variable; 126*9880d681SAndroid Build Coastguard Worker 127*9880d681SAndroid Build Coastguard Worker (* Emit the body of the loop. This, like any other expr, can change the 128*9880d681SAndroid Build Coastguard Worker * current BB. Note that we ignore the value computed by the body, but 129*9880d681SAndroid Build Coastguard Worker * don't allow an error *) 130*9880d681SAndroid Build Coastguard Worker ignore (codegen_expr body); 131*9880d681SAndroid Build Coastguard Worker 132*9880d681SAndroid Build Coastguard Worker (* Emit the step value. *) 133*9880d681SAndroid Build Coastguard Worker let step_val = 134*9880d681SAndroid Build Coastguard Worker match step with 135*9880d681SAndroid Build Coastguard Worker | Some step -> codegen_expr step 136*9880d681SAndroid Build Coastguard Worker (* If not specified, use 1.0. *) 137*9880d681SAndroid Build Coastguard Worker | None -> const_float double_type 1.0 138*9880d681SAndroid Build Coastguard Worker in 139*9880d681SAndroid Build Coastguard Worker 140*9880d681SAndroid Build Coastguard Worker let next_var = build_add variable step_val "nextvar" builder in 141*9880d681SAndroid Build Coastguard Worker 142*9880d681SAndroid Build Coastguard Worker (* Compute the end condition. *) 143*9880d681SAndroid Build Coastguard Worker let end_cond = codegen_expr end_ in 144*9880d681SAndroid Build Coastguard Worker 145*9880d681SAndroid Build Coastguard Worker (* Convert condition to a bool by comparing equal to 0.0. *) 146*9880d681SAndroid Build Coastguard Worker let zero = const_float double_type 0.0 in 147*9880d681SAndroid Build Coastguard Worker let end_cond = build_fcmp Fcmp.One end_cond zero "loopcond" builder in 148*9880d681SAndroid Build Coastguard Worker 149*9880d681SAndroid Build Coastguard Worker (* Create the "after loop" block and insert it. *) 150*9880d681SAndroid Build Coastguard Worker let loop_end_bb = insertion_block builder in 151*9880d681SAndroid Build Coastguard Worker let after_bb = append_block context "afterloop" the_function in 152*9880d681SAndroid Build Coastguard Worker 153*9880d681SAndroid Build Coastguard Worker (* Insert the conditional branch into the end of loop_end_bb. *) 154*9880d681SAndroid Build Coastguard Worker ignore (build_cond_br end_cond loop_bb after_bb builder); 155*9880d681SAndroid Build Coastguard Worker 156*9880d681SAndroid Build Coastguard Worker (* Any new code will be inserted in after_bb. *) 157*9880d681SAndroid Build Coastguard Worker position_at_end after_bb builder; 158*9880d681SAndroid Build Coastguard Worker 159*9880d681SAndroid Build Coastguard Worker (* Add a new entry to the PHI node for the backedge. *) 160*9880d681SAndroid Build Coastguard Worker add_incoming (next_var, loop_end_bb) variable; 161*9880d681SAndroid Build Coastguard Worker 162*9880d681SAndroid Build Coastguard Worker (* Restore the unshadowed variable. *) 163*9880d681SAndroid Build Coastguard Worker begin match old_val with 164*9880d681SAndroid Build Coastguard Worker | Some old_val -> Hashtbl.add named_values var_name old_val 165*9880d681SAndroid Build Coastguard Worker | None -> () 166*9880d681SAndroid Build Coastguard Worker end; 167*9880d681SAndroid Build Coastguard Worker 168*9880d681SAndroid Build Coastguard Worker (* for expr always returns 0.0. *) 169*9880d681SAndroid Build Coastguard Worker const_null double_type 170*9880d681SAndroid Build Coastguard Worker 171*9880d681SAndroid Build Coastguard Workerlet codegen_proto = function 172*9880d681SAndroid Build Coastguard Worker | Ast.Prototype (name, args) -> 173*9880d681SAndroid Build Coastguard Worker (* Make the function type: double(double,double) etc. *) 174*9880d681SAndroid Build Coastguard Worker let doubles = Array.make (Array.length args) double_type in 175*9880d681SAndroid Build Coastguard Worker let ft = function_type double_type doubles in 176*9880d681SAndroid Build Coastguard Worker let f = 177*9880d681SAndroid Build Coastguard Worker match lookup_function name the_module with 178*9880d681SAndroid Build Coastguard Worker | None -> declare_function name ft the_module 179*9880d681SAndroid Build Coastguard Worker 180*9880d681SAndroid Build Coastguard Worker (* If 'f' conflicted, there was already something named 'name'. If it 181*9880d681SAndroid Build Coastguard Worker * has a body, don't allow redefinition or reextern. *) 182*9880d681SAndroid Build Coastguard Worker | Some f -> 183*9880d681SAndroid Build Coastguard Worker (* If 'f' already has a body, reject this. *) 184*9880d681SAndroid Build Coastguard Worker if block_begin f <> At_end f then 185*9880d681SAndroid Build Coastguard Worker raise (Error "redefinition of function"); 186*9880d681SAndroid Build Coastguard Worker 187*9880d681SAndroid Build Coastguard Worker (* If 'f' took a different number of arguments, reject. *) 188*9880d681SAndroid Build Coastguard Worker if element_type (type_of f) <> ft then 189*9880d681SAndroid Build Coastguard Worker raise (Error "redefinition of function with different # args"); 190*9880d681SAndroid Build Coastguard Worker f 191*9880d681SAndroid Build Coastguard Worker in 192*9880d681SAndroid Build Coastguard Worker 193*9880d681SAndroid Build Coastguard Worker (* Set names for all arguments. *) 194*9880d681SAndroid Build Coastguard Worker Array.iteri (fun i a -> 195*9880d681SAndroid Build Coastguard Worker let n = args.(i) in 196*9880d681SAndroid Build Coastguard Worker set_value_name n a; 197*9880d681SAndroid Build Coastguard Worker Hashtbl.add named_values n a; 198*9880d681SAndroid Build Coastguard Worker ) (params f); 199*9880d681SAndroid Build Coastguard Worker f 200*9880d681SAndroid Build Coastguard Worker 201*9880d681SAndroid Build Coastguard Workerlet codegen_func the_fpm = function 202*9880d681SAndroid Build Coastguard Worker | Ast.Function (proto, body) -> 203*9880d681SAndroid Build Coastguard Worker Hashtbl.clear named_values; 204*9880d681SAndroid Build Coastguard Worker let the_function = codegen_proto proto in 205*9880d681SAndroid Build Coastguard Worker 206*9880d681SAndroid Build Coastguard Worker (* Create a new basic block to start insertion into. *) 207*9880d681SAndroid Build Coastguard Worker let bb = append_block context "entry" the_function in 208*9880d681SAndroid Build Coastguard Worker position_at_end bb builder; 209*9880d681SAndroid Build Coastguard Worker 210*9880d681SAndroid Build Coastguard Worker try 211*9880d681SAndroid Build Coastguard Worker let ret_val = codegen_expr body in 212*9880d681SAndroid Build Coastguard Worker 213*9880d681SAndroid Build Coastguard Worker (* Finish off the function. *) 214*9880d681SAndroid Build Coastguard Worker let _ = build_ret ret_val builder in 215*9880d681SAndroid Build Coastguard Worker 216*9880d681SAndroid Build Coastguard Worker (* Validate the generated code, checking for consistency. *) 217*9880d681SAndroid Build Coastguard Worker Llvm_analysis.assert_valid_function the_function; 218*9880d681SAndroid Build Coastguard Worker 219*9880d681SAndroid Build Coastguard Worker (* Optimize the function. *) 220*9880d681SAndroid Build Coastguard Worker let _ = PassManager.run_function the_function the_fpm in 221*9880d681SAndroid Build Coastguard Worker 222*9880d681SAndroid Build Coastguard Worker the_function 223*9880d681SAndroid Build Coastguard Worker with e -> 224*9880d681SAndroid Build Coastguard Worker delete_function the_function; 225*9880d681SAndroid Build Coastguard Worker raise e 226