-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcodegen.ml
194 lines (161 loc) · 7.31 KB
/
codegen.ml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
(* Code generation: translate takes a semantically checked AST and
produces LLVM IR
LLVM tutorial: Make sure to read the OCaml version of the tutorial
http://llvm.org/docs/tutorial/index.html
Detailed documentation on the OCaml LLVM library:
http://llvm.moe/
http://llvm.moe/ocaml/
*)
module L = Llvm
module A = Ast
module StringMap = Map.Make(String)
let translate (globals, functions) =
let context = L.global_context () in
let the_module = L.create_module context "TPL"
and i32_t = L.i32_type context
and i8_t = L.i8_type context
and i1_t = L.i1_type context
and void_t = L.void_type context
(* and string_t = ???? context TODO *)
and float_t = L.double_type context in
let ltype_of_typ = function
A.Int -> i32_t
| A.Bool -> i1_t
| A.Void -> void_t
| A.Float -> float_t
(*| A.String -> string_t TODO *)
in
(* Declare each global variable; remember its value in a map *)
let global_vars =
let global_var m (t, n) =
let init = L.const_int (ltype_of_typ t) 0
in StringMap.add n (L.define_global n init the_module) m in
List.fold_left global_var StringMap.empty globals in
(* Declare printf(), which the print built-in function will call *)
let printf_t = L.var_arg_function_type i32_t [| L.pointer_type i8_t |] in
let printf_func = L.declare_function "printf" printf_t the_module in
(* Define each function (arguments and return type) so we can call it *)
let function_decls =
let function_decl m fdecl =
let name = fdecl.A.fname
and formal_types =
Array.of_list (List.map (fun (t,_) -> ltype_of_typ t) fdecl.A.formals)
in let ftype = L.function_type (ltype_of_typ fdecl.A.typ) formal_types in
StringMap.add name (L.define_function name ftype the_module, fdecl) m in
List.fold_left function_decl StringMap.empty functions in
(* Fill in the body of the given function *)
let build_function_body fdecl =
let (the_function, _) = StringMap.find fdecl.A.fname function_decls in
let builder = L.builder_at_end context (L.entry_block the_function) in
let int_format_str = L.build_global_stringptr "%d\n" "fmt_integer" builder in
let float_format_str = L.build_global_stringptr "%.2f\n" "fmt_float" builder in
(* Construct the function's "locals": formal arguments and locally
declared variables. Allocate each on the stack, initialize their
value, if appropriate, and remember their values in the "locals" map *)
let local_vars =
let add_formal m (t, n) p = L.set_value_name n p;
let local = L.build_alloca (ltype_of_typ t) n builder in
ignore (L.build_store p local builder);
StringMap.add n local m in
let add_local m (t, n) =
let local_var = L.build_alloca (ltype_of_typ t) n builder
in StringMap.add n local_var m in
let formals = List.fold_left2 add_formal StringMap.empty fdecl.A.formals
(Array.to_list (L.params the_function)) in
List.fold_left add_local formals fdecl.A.locals in
(* Return the value for a variable or formal argument *)
let lookup n = try StringMap.find n local_vars
with Not_found -> StringMap.find n global_vars
in
(* Construct code for an expression; return its value *)
let rec expr builder = function
A.Literal i -> L.const_int i32_t i
| A.Floatliteral f -> L.const_float float_t f
| A.BoolLit b -> L.const_int i1_t (if b then 1 else 0)
| A.Noexpr -> L.const_int i32_t 0
| A.Id s -> L.build_load (lookup s) s builder
| A.Binop (e1, op, e2) ->
let e1' = expr builder e1
and e2' = expr builder e2 in
(match op with
A.Add -> if (true) then (L.build_add) else (L.build_fadd)
| A.Sub -> if (true) then L.build_sub else L.build_fsub
| A.Mult -> if (true) then L.build_mul else L.build_fmul
| A.Div -> if (true) then L.build_sdiv else L.build_fdiv
| A.And -> L.build_and
| A.Or -> L.build_or
| A.Equal -> L.build_icmp L.Icmp.Eq
| A.Neq -> L.build_icmp L.Icmp.Ne
| A.Less -> L.build_icmp L.Icmp.Slt
| A.Leq -> L.build_icmp L.Icmp.Sle
| A.Greater -> L.build_icmp L.Icmp.Sgt
| A.Geq -> L.build_icmp L.Icmp.Sge
) e1' e2' "tmp" builder
| A.Unop(op, e) ->
let e' = expr builder e in
(match op with
A.Neg -> L.build_neg
| A.Not -> L.build_not) e' "tmp" builder
| A.Assign (s, e) -> let e' = expr builder e in
ignore (L.build_store e' (lookup s) builder); e'
| A.Call ("print", [e]) | A.Call ("printb", [e]) ->
L.build_call printf_func [| int_format_str ; (expr builder e) |]
"printf" builder
| A.Call ("printfloat", [e]) ->
L.build_call printf_func [| float_format_str ; (expr builder e) |]
"printf" builder
| A.Call (f, act) ->
let (fdef, fdecl) = StringMap.find f function_decls in
let actuals = List.rev (List.map (expr builder) (List.rev act)) in
let result = (match fdecl.A.typ with A.Void -> ""
| _ -> f ^ "_result") in
L.build_call fdef (Array.of_list actuals) result builder
in
(* Invoke "f builder" if the current block doesn't already
have a terminal (e.g., a branch). *)
let add_terminal builder f =
match L.block_terminator (L.insertion_block builder) with
Some _ -> ()
| None -> ignore (f builder) in
(* Build the code for the given statement; return the builder for
the statement's successor *)
let rec stmt builder = function
A.Block sl -> List.fold_left stmt builder sl
| A.Expr e -> ignore (expr builder e); builder
| A.Return e -> ignore (match fdecl.A.typ with
A.Void -> L.build_ret_void builder
| _ -> L.build_ret (expr builder e) builder); builder
| A.If (predicate, then_stmt, else_stmt) ->
let bool_val = expr builder predicate in
let merge_bb = L.append_block context "merge" the_function in
let then_bb = L.append_block context "then" the_function in
add_terminal (stmt (L.builder_at_end context then_bb) then_stmt)
(L.build_br merge_bb);
let else_bb = L.append_block context "else" the_function in
add_terminal (stmt (L.builder_at_end context else_bb) else_stmt)
(L.build_br merge_bb);
ignore (L.build_cond_br bool_val then_bb else_bb builder);
L.builder_at_end context merge_bb
| A.While (predicate, body) ->
let pred_bb = L.append_block context "while" the_function in
ignore (L.build_br pred_bb builder);
let body_bb = L.append_block context "while_body" the_function in
add_terminal (stmt (L.builder_at_end context body_bb) body)
(L.build_br pred_bb);
let pred_builder = L.builder_at_end context pred_bb in
let bool_val = expr pred_builder predicate in
let merge_bb = L.append_block context "merge" the_function in
ignore (L.build_cond_br bool_val body_bb merge_bb pred_builder);
L.builder_at_end context merge_bb
| A.For (e1, e2, e3, body) -> stmt builder
( A.Block [A.Expr e1 ; A.While (e2, A.Block [body ; A.Expr e3]) ] )
in
(* Build the code for each statement in the function *)
let builder = stmt builder (A.Block fdecl.A.body) in
(* Add a return if the last block falls off the end *)
add_terminal builder (match fdecl.A.typ with
A.Void -> L.build_ret_void
| t -> L.build_ret (L.const_int (ltype_of_typ t) 0))
in
List.iter build_function_body functions;
the_module