-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathops.ml
More file actions
353 lines (275 loc) · 11 KB
/
ops.ml
File metadata and controls
353 lines (275 loc) · 11 KB
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
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
(* ------------------------------------------------------------------------------------ *)
(* Operation Selection x86-64 *)
(* ------------------------------------------------------------------------------------ *)
open Ttree
(* ------------------------------------------------------------------------------------ *)
(* Inductive langage definition *)
(* ------------------------------------------------------------------------------------ *)
type ident = string
(* Expression *)
type expr =
| Mconst of int32
| Maccess of ident
| Massign of ident * expr
| Mload of int * expr
| Mstore of int * expr * expr
| Mbinop of mbinop * expr * expr
| Munop of munop * expr
| Mcall of ident * expr list
(* Unary operators *)
and munop =
| Maddi of int32
| Msetei of int32
| Msetnei of int32
(* Binary operators *)
and mbinop =
| Mmov
| Madd
| Msub
| Mmul
| Mdiv
| Msete
| Msetne
| Msetl
| Msetle
| Msetg
| Msetge
(* Unary branch operations *)
type mubranch =
| Mjz
| Mjnz
| Mjlei of int32
| Mjgi of int32
(* Binary branch operations *)
type mbbranch =
| Mjl
| Mjle
(* Statement *)
type stmt =
| Mskip
| Mexpr of expr
| Mif of expr * stmt * stmt
| Mwhile of expr * stmt
| Mreturn of expr
| Mblock of ident list * stmt list (* we remeber the variables with the same ident *)
(* Function definiton *)
type decl_fun = {
fun_name : ident;
fun_formals: ident list;
fun_locals : ident list;
fun_body : stmt list
}
(* Program *)
type file = {
funs: decl_fun list;
}
(* ------------------------------------------------------------------------------------ *)
(* Translation: Ttree -> Ops *)
(* ------------------------------------------------------------------------------------ *)
module S = Set.Make(String)
let locals = ref S.empty
let zero = Int32.zero
let one = Int32.one
let rec pure = function
| Mconst _ -> true
| Maccess _ -> true
| Massign _ -> false
| Mload _ -> false
| Mstore _ -> false
| Mbinop (_, e1, e2) -> (pure e1) && (pure e2)
| Munop (_, e) -> pure e
| Mcall _ -> false
(* ------------------------------------------------------------------------------------ *)
(* Smart constructors for unary operations *)
(* ------------------------------------------------------------------------------------ *)
let mkNeg = function
| Mconst i -> Mconst (Int32.neg i)
| _ as e -> Mbinop (Msub, Mconst zero, e)
let mkNot = function
| Mconst i -> Mconst (if i = zero then one else zero)
| _ as e -> Munop (Msetei zero, e)
let mkUnop op e =
match op with
| Ptree.Uminus -> mkNeg e
| Ptree.Unot -> mkNot e
(* ------------------------------------------------------------------------------------ *)
(* Smart constructors for binary operations *)
(* ------------------------------------------------------------------------------------ *)
let rec mkAdd e1 e2 =
match e1, e2 with
| Mconst i1, Mconst i2 -> Mconst (Int32.add i1 i2)
| Mconst i, (_ as e) | (_ as e), Mconst i ->
if i = zero then e else
begin match e with
| Munop ((Maddi i'), e') -> mkAdd (Mconst (Int32.add i i')) e'
| _ -> Munop ((Maddi i), e)
end
| _ -> Mbinop (Madd, e1, e2)
let rec mkSub e1 e2 =
match e1, e2 with
| Mconst i1, Mconst i2 -> Mconst (Int32.sub i1 i2)
| _, Mconst i ->
begin match e1 with
| Munop ((Maddi i'), e') -> mkAdd e' (Mconst (Int32.sub i' i))
| _ -> if i = zero then e1 else Munop ((Maddi (Int32.neg i)), e1)
end
| Mconst i, _ ->
begin match e2 with
| Munop ((Maddi i'), e') -> mkSub (Mconst (Int32.sub i i')) e'
| _ -> if i = zero then mkNot e2 else Munop (Maddi i, mkNeg e2)
end
| _ -> Mbinop (Msub, e1, e2)
let rec mkMul e1 e2 =
match e1, e2 with
| Mconst i1, Mconst i2 -> Mconst (Int32.mul i1 i2)
| Mconst i, (_ as e) | (_ as e), Mconst i ->
if i = zero && pure e then Mconst zero else
if i = one then e else
begin match e with
| Munop ((Maddi i'), e') -> mkAdd (Mconst (Int32.mul i i')) (mkMul e' (Mconst i))
| _ -> Mbinop (Mmul, e1, e2)
end
| _ -> Mbinop (Mmul, e1, e2)
let mkDiv e1 e2 =
match e1, e2 with
| Mconst i1, Mconst i2 when i2 <> zero -> Mconst (Int32.div i1 i2)
| _, Mconst i when i = one -> e1
| _ -> Mbinop (Mdiv, e1, e2)
let mkAnd e1 e2 =
match e1, e2 with
| Mconst i1, Mconst i2 ->
let value = if i1 <> zero && i2 <> zero then one else zero in
Mconst value
| Mconst i, (_ as e) | (_ as e), Mconst i ->
if i = zero then Mconst zero else Munop (Msetnei zero, e)
| _ -> Munop (Msetnei zero, mkMul e1 e2) (* Msetnei implies value equals to 0 or 1 *)
let mkOr e1 e2 =
match e1, e2 with
| Mconst i1, Mconst i2 ->
let value = if i1 <> zero || i2 <> zero then one else zero in
Mconst value
| Mconst i, (_ as e) | (_ as e), Mconst i ->
if i <> zero then Mconst one else Munop (Msetnei zero, e)
| _ -> mkNot (mkMul (mkNot e1) (mkNot e2))
let rec mkLt e1 e2 =
match e1, e2 with
| Mconst i1, Mconst i2 ->
let value = if i1 < i2 then one else zero in
Mconst value
(* With signed integers: i < e' + i' <=> i - i' < e' *)
| Mconst i, Munop (Maddi i', e') -> mkLt (Mconst (Int32.sub i i')) e'
| Munop (Maddi i', e'), Mconst i -> mkLt e' (Mconst (Int32.sub i i'))
| _ -> Mbinop (Msetl, e1, e2)
let rec mkLe e1 e2 =
match e1, e2 with
| Mconst i1, Mconst i2 ->
let value = if i1 <= i2 then one else zero in
Mconst value
(* With signed integers: i <= e' + i' <=> i - i' <= e' *)
| Mconst i, Munop (Maddi i', e') -> mkLe (Mconst (Int32.sub i i')) e'
| Munop (Maddi i', e'), Mconst i -> mkLe e' (Mconst (Int32.sub i i'))
| _ -> Mbinop (Msetle, e1, e2)
let rec mkSete e1 e2 =
match e1, e2 with
| Mconst i1, Mconst i2 -> Mconst (if i1 = i2 then one else zero)
| Mconst i, (_ as e) | (_ as e), Mconst i ->
begin match e with
| Munop (Maddi i', e') -> mkSete (Mconst (Int32.sub i i')) e'
| _ -> Munop (Msetei i, e)
end
| _ -> Mbinop (Msete, e1, e2)
let rec mkSetne e1 e2 =
match e1, e2 with
| Mconst i1, Mconst i2 -> Mconst (if i1 <> i2 then one else zero)
| Mconst i, (_ as e) | (_ as e), Mconst i ->
begin match e with
| Munop (Maddi i', e') -> mkSetne (Mconst (Int32.sub i i')) e'
| _ -> Munop (Msetnei i, e)
end
| _ -> Mbinop (Msetne, e1, e2)
let rec mkBinop op e1 e2 =
match op with
| Ptree.Beq -> mkSete e1 e2
| Ptree.Bneq -> mkSetne e1 e2
| Ptree.Blt -> mkLt e1 e2
| Ptree.Ble -> mkLe e1 e2
| Ptree.Bgt -> mkLt e2 e1
| Ptree.Bge -> mkLe e2 e1
| Ptree.Badd -> mkAdd e1 e2
| Ptree.Bsub -> mkSub e1 e2
| Ptree.Bmul -> mkMul e1 e2
| Ptree.Bdiv -> mkDiv e1 e2
| Ptree.Band -> mkAnd e1 e2
| Ptree.Bor -> mkOr e1 e2
(* ------------------------------------------------------------------------------------ *)
(* Operation selection for expressions *)
(* ------------------------------------------------------------------------------------ *)
let rec op_expr { expr_node; expr_typ } =
match expr_node with
| Ttree.Econst i -> Mconst i
| Ttree.Eaccess_local id -> Maccess id
| Ttree.Eaccess_field (e, f) -> Mload (f.field_pos, op_expr e)
| Ttree.Eassign_local (id, e) -> Massign (id, op_expr e)
| Ttree.Eassign_field (e1, f, e2) -> Mstore (f.field_pos, op_expr e1, op_expr e2)
| Ttree.Eunop (op, e) -> mkUnop op (op_expr e)
| Ttree.Ebinop (op, e1, e2) -> mkBinop op (op_expr e1) (op_expr e2)
| Ttree.Ecall (id, expr_list) -> Mcall (id, List.map op_expr expr_list)
| Ttree.Esizeof s -> Mconst (Int32.of_int s.str_size)
(* ------------------------------------------------------------------------------------ *)
(* Operation selection for statements *)
(* ------------------------------------------------------------------------------------ *)
let rec op_stmt = function
| Ttree.Sskip -> Mskip
| Ttree.Sexpr e -> Mexpr (op_expr e)
| Ttree.Sif (e, s1, s2) -> Mif (op_expr e, op_stmt s1, op_stmt s2)
| Ttree.Swhile (e, s) -> Mwhile (op_expr e, op_stmt s)
| Ttree.Sblock (decl_list, stmt_list) ->
let repeated_ids =
let aux acc (_, id) = if S.mem id !locals then (id :: acc) else acc in
List.fold_left aux [] decl_list in
locals := List.fold_left (fun set (_, id) -> S.add id set) !locals decl_list;
Mblock (repeated_ids, List.map op_stmt stmt_list)
| Ttree.Sreturn e -> Mreturn (op_expr e)
(* ------------------------------------------------------------------------------------ *)
(* Operation selection for functions *)
(* ------------------------------------------------------------------------------------ *)
let op_fun { fun_typ; fun_name; fun_formals; fun_body } =
let fun_formals = List.map (fun (_, id) -> id) fun_formals in
let fun_body = match op_stmt (Ttree.Sblock fun_body) with
| Mblock (_, s_list) -> s_list
| _ -> assert false in
let fun_locals = S.elements !locals in
locals := S.empty;
{ fun_name; fun_formals; fun_locals; fun_body }
(* ------------------------------------------------------------------------------------ *)
(* Operation selection of a program *)
(* ------------------------------------------------------------------------------------ *)
let program ({ funs } : Ttree.file) = { funs = List.map op_fun funs }
(* ------------------------------------------------------------------------------------ *)
(* Print functions *)
(* ------------------------------------------------------------------------------------ *)
open Format
let print_munop fmt = function
| Maddi i -> fprintf fmt "add $%ld" i
| Msetei i -> fprintf fmt "sete $%ld" i
| Msetnei i -> fprintf fmt "setne $%ld" i
let print_mbinop fmt = function
| Mmov -> fprintf fmt "mov"
| Madd -> fprintf fmt "add"
| Msub -> fprintf fmt "sub"
| Mmul -> fprintf fmt "imul"
| Mdiv -> fprintf fmt "idiv"
| Msete -> fprintf fmt "sete"
| Msetne -> fprintf fmt "setne"
| Msetl -> fprintf fmt "setl"
| Msetle -> fprintf fmt "setle"
| Msetg -> fprintf fmt "setg"
| Msetge -> fprintf fmt "setge"
let print_mubranch fmt = function
| Mjz -> fprintf fmt "jz"
| Mjnz -> fprintf fmt "jnz"
| Mjlei n -> fprintf fmt "jle $%ld" n
| Mjgi n -> fprintf fmt "jg $%ld" n
let print_mbbranch fmt = function
| Mjl -> fprintf fmt "jl"
| Mjle -> fprintf fmt "jle"