1 (*===----------------------------------------------------------------------===
3 *===----------------------------------------------------------------------===*)
7 exception Error
of string
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
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
25 | '
+'
-> build_fadd
lhs_val rhs_val "addtmp" builder
26 | '
-'
-> build_fsub
lhs_val rhs_val "subtmp" builder
27 | '
*'
-> build_fmul
lhs_val rhs_val "multmp" builder
29 (* Convert bool 0/1 to double 0.0 or 1.0 *)
30 let i = build_fcmp
Fcmp.Ult
lhs_val rhs_val "cmptmp" builder in
31 build_uitofp
i double_type "booltmp" builder
32 | _
-> raise
(Error
"invalid binary operator")
34 | Ast.Call
(callee
, args
) ->
35 (* Look up the name in the module table. *)
37 match lookup_function
callee the_module with
38 | Some
callee -> callee
39 | None
-> raise
(Error
"unknown function referenced")
41 let params = params callee in
43 (* If argument mismatch error. *)
44 if Array.length
params == Array.length args
then () else
45 raise
(Error
"incorrect # arguments passed");
46 let args = Array.map
codegen_expr args in
47 build_call
callee args "calltmp" builder
49 let codegen_proto = function
50 | Ast.Prototype
(name
, args) ->
51 (* Make the function type: double(double,double) etc. *)
52 let doubles = Array.make
(Array.length
args) double_type in
53 let ft = function_type
double_type doubles in
55 match lookup_function name
the_module with
56 | None
-> declare_function name
ft the_module
58 (* If 'f' conflicted, there was already something named 'name'. If it
59 * has a body, don't allow redefinition or reextern. *)
61 (* If 'f' already has a body, reject this. *)
62 if block_begin
f <> At_end
f then
63 raise
(Error
"redefinition of function");
65 (* If 'f' took a different number of arguments, reject. *)
66 if element_type
(type_of
f) <> ft then
67 raise
(Error
"redefinition of function with different # args");
71 (* Set names for all arguments. *)
72 Array.iteri
(fun i a
->
75 Hashtbl.add
named_values n a
;
79 let codegen_func the_fpm
= function
80 | Ast.Function
(proto
, body
) ->
81 Hashtbl.clear
named_values;
82 let the_function = codegen_proto proto
in
84 (* Create a new basic block to start insertion into. *)
85 let bb = append_block
context "entry" the_function in
86 position_at_end
bb builder;
89 let ret_val = codegen_expr body
in
91 (* Finish off the function. *)
92 let _ = build_ret
ret_val builder in
94 (* Validate the generated code, checking for consistency. *)
95 Llvm_analysis.assert_valid_function
the_function;
97 (* Optimize the function. *)
98 let _ = PassManager.run_function
the_function the_fpm
in
102 delete_function
the_function;