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