Skip to content

Commit 1c3f870

Browse files
committed
Whoops. Forgot to add codegen.ml
1 parent dbcc5cb commit 1c3f870

File tree

1 file changed

+101
-0
lines changed

1 file changed

+101
-0
lines changed

codegen.ml

+101
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
(*===----------------------------------------------------------------------===
2+
* Code Generation
3+
*===----------------------------------------------------------------------===*)
4+
5+
open Llvm
6+
7+
exception Error of string
8+
9+
let context = global_context ()
10+
let the_module = create_module context "my cool jit"
11+
let builder = builder context
12+
let named_values:(string, llvalue) Hashtbl.t = Hashtbl.create 10
13+
let double_type = double_type context
14+
15+
let rec codegen_expr = function
16+
| Ast.Number n -> const_float double_type n
17+
| Ast.Variable name ->
18+
(try Hashtbl.find named_values name with
19+
| Not_found -> raise (Error "unknown variable name"))
20+
| Ast.Binary (op, lhs, rhs) ->
21+
let lhs_val = codegen_expr lhs in
22+
let rhs_val = codegen_expr rhs in
23+
begin
24+
match op with
25+
| '+' -> build_fadd lhs_val rhs_val "addtmp" builder
26+
| '-' -> build_fsub lhs_val rhs_val "subtmp" builder
27+
| '/' -> build_fsub lhs_val rhs_val "divtmp" builder
28+
| '*' -> build_fmul lhs_val rhs_val "multmp" builder
29+
| '<' ->
30+
(* Convert bool 0/1 to double 0.0 or 1.0 *)
31+
let i = build_fcmp Fcmp.Ult lhs_val rhs_val "cmptmp" builder in
32+
build_uitofp i double_type "booltmp" builder
33+
| _ -> raise (Error "invalid binary operator")
34+
end
35+
| Ast.Call (callee, args) ->
36+
(* Look up the name in the module table. *)
37+
let callee =
38+
match lookup_function callee the_module with
39+
| Some callee -> callee
40+
| None -> raise (Error "unknown function referenced")
41+
in
42+
let params = params callee in
43+
44+
(* If argument mismatch error. *)
45+
if Array.length params == Array.length args then () else
46+
raise (Error "incorrect # arguments passed");
47+
let args = Array.map codegen_expr args in
48+
build_call callee args "calltmp" builder
49+
50+
let codegen_proto = function
51+
| Ast.Prototype (name, args) ->
52+
(* Make the function type: double(double,double) etc. *)
53+
let doubles = Array.make (Array.length args) double_type in
54+
let ft = function_type double_type doubles in
55+
let f =
56+
match lookup_function name the_module with
57+
| None -> declare_function name ft the_module
58+
59+
(* If 'f' conflicted, there was already something named 'name'. If it
60+
* has a body, don't allow redefinition or reextern. *)
61+
| Some f ->
62+
(* If 'f' already has a body, reject this. *)
63+
if block_begin f <> At_end f then
64+
raise (Error "redefinition of function");
65+
66+
(* If 'f' took a different number of arguments, reject. *)
67+
if element_type (type_of f) <> ft then
68+
raise (Error "redefinition of function with different # args");
69+
f
70+
in
71+
72+
(* Set names for all arguments. *)
73+
Array.iteri (fun i a ->
74+
let n = args.(i) in
75+
set_value_name n a;
76+
Hashtbl.add named_values n a;
77+
) (params f);
78+
f
79+
80+
let codegen_func = function
81+
| Ast.Function (proto, body) ->
82+
Hashtbl.clear named_values;
83+
let the_function = codegen_proto proto in
84+
85+
(* Create a new basic block to start insertion into. *)
86+
let bb = append_block context "entry" the_function in
87+
position_at_end bb builder;
88+
89+
try
90+
let ret_val = codegen_expr body in
91+
92+
(* Finish off the function. *)
93+
let _ = build_ret ret_val builder in
94+
95+
(* Validate the generated code, checking for consistency. *)
96+
Llvm_analysis.assert_valid_function the_function;
97+
98+
the_function
99+
with e ->
100+
delete_function the_function;
101+
raise e

0 commit comments

Comments
 (0)