]>
Commit | Line | Data |
---|---|---|
6ade8b0a | 1 | (* L3 Compiler |
12aa4087 JW |
2 | * AST -> IR Translator |
3 | * Author: Kaustuv Chaudhuri <kaustuv+@cs.cmu.edu> | |
4 | * Modified by: Alex Vaynberg <alv@andrew.cmu.edu> | |
5 | * Modified: Frank Pfenning <fp@cs.cmu.edu> | |
0a24e44d JW |
6 | * Modified: Chris Lu <czl@andrew.cmu.edu> |
7 | * Modified: Joshua Wise <jwise@andrew.cmu.edu> | |
12aa4087 JW |
8 | *) |
9 | ||
10 | signature TRANS = | |
11 | sig | |
12 | (* translate abstract syntax tree to IR tree *) | |
5c79bb68 | 13 | val translate : Ast.program -> Tree.program |
12aa4087 JW |
14 | end |
15 | ||
16 | structure Trans :> TRANS = | |
17 | struct | |
18 | ||
19 | structure A = Ast | |
20 | structure T = Tree | |
0a24e44d | 21 | |
12aa4087 JW |
22 | fun trans_oper A.PLUS = T.ADD |
23 | | trans_oper A.MINUS = T.SUB | |
24 | | trans_oper A.TIMES = T.MUL | |
25 | | trans_oper A.DIVIDEDBY = T.DIV | |
26 | | trans_oper A.MODULO = T.MOD | |
0a24e44d JW |
27 | | trans_oper A.LSH = T.LSH |
28 | | trans_oper A.RSH = T.RSH | |
29 | | trans_oper A.LOGOR = T.LOGOR | |
30 | | trans_oper A.LOGAND = T.LOGAND | |
31 | | trans_oper A.BITOR = T.BITOR | |
32 | | trans_oper A.BITXOR = T.BITXOR | |
33 | | trans_oper A.BITAND = T.BITAND | |
34 | | trans_oper A.NEQ = T.NEQ | |
35 | | trans_oper A.EQ = T.EQ | |
36 | | trans_oper A.LT = T.LT | |
37 | | trans_oper A.LE = T.LE | |
38 | | trans_oper A.GE = T.GE | |
39 | | trans_oper A.GT = T.GT | |
40 | | trans_oper _ = raise ErrorMsg.InternalError "expected AST binop, got AST unop" | |
12aa4087 | 41 | |
1144856b | 42 | fun translate (defs, funcs) = |
6ade8b0a | 43 | let |
1144856b | 44 | val funclist = Symbol.elemsi funcs |
5c79bb68 JW |
45 | val _ = Type.alignment_reset() |
46 | val _ = Type.sizeof_reset() | |
47 | fun sizeof a = Type.sizeof defs a | |
48 | fun alignment a = Type.alignment defs a | |
49 | fun align t curpos = Type.align defs t curpos | |
1144856b | 50 | |
5c79bb68 | 51 | fun offset_s id (Type.Typedef(id')) = |
1144856b JW |
52 | let |
53 | val shit = Symbol.look' defs id' | |
5c79bb68 JW |
54 | fun eat (Type.Struct(l)) = l |
55 | | eat (Type.MarkedTypedef(a)) = eat (Mark.data a) | |
1144856b JW |
56 | fun offset_s' ((id1,t)::l') curofs = |
57 | let | |
58 | val a = align t curofs | |
59 | in | |
60 | if Symbol.compare(id,id1) = EQUAL | |
61 | then a | |
5c79bb68 | 62 | else offset_s' l' (a + sizeof t) |
1144856b JW |
63 | end |
64 | | offset_s' nil _ = raise ErrorMsg.InternalError "looking for offset of something that isn't in the structure" | |
65 | in | |
66 | offset_s' (eat shit) 0 | |
67 | end | |
68 | | offset_s _ _ = raise ErrorMsg.InternalError "cannot find offset into non-typedef" | |
69 | ||
5c79bb68 | 70 | fun type_s id (Type.Typedef id') = |
1144856b JW |
71 | let |
72 | val td = | |
5c79bb68 JW |
73 | case Type.defdata (Symbol.look' defs id') |
74 | of Type.Struct d => d | |
1144856b JW |
75 | | _ => raise ErrorMsg.InternalError "data didn't return struct" |
76 | fun type_s' ((id',t)::l) = | |
77 | if (Symbol.compare (id, id') = EQUAL) | |
78 | then t | |
79 | else type_s' l | |
80 | | type_s' nil = raise ErrorMsg.InternalError "struct member not found in type_s" | |
81 | in | |
82 | type_s' td | |
83 | end | |
84 | | type_s id _ = raise ErrorMsg.InternalError "cannot find internal type non-typedef" | |
85 | ||
5c79bb68 JW |
86 | fun deref (Type.Pointer i) = i |
87 | | deref (Type.Array i) = i | |
1144856b | 88 | | deref _ = raise ErrorMsg.InternalError "cannot deref non-pointer" |
6ade8b0a JW |
89 | |
90 | fun trans_unop A.NEGATIVE = T.NEG | |
91 | | trans_unop A.BITNOT = T.BITNOT | |
92 | | trans_unop A.BANG = T.BANG | |
93 | | trans_unop _ = raise ErrorMsg.InternalError "expected AST unop, got AST binop" | |
1144856b JW |
94 | |
95 | fun typeof' vartypes exp = TypeChecker.typeof (defs, funcs) vartypes NONE exp | |
6ade8b0a | 96 | |
1144856b | 97 | fun trans_exp env vartypes (A.Var(id)) = |
6ade8b0a JW |
98 | (* after type-checking, id must be declared; do not guard lookup *) |
99 | T.TEMP (Symbol.look' env id) | |
1144856b | 100 | | trans_exp env vartypes (A.ConstExp c) = T.CONST(c) |
a83f1d60 | 101 | | trans_exp env vartypes (A.StringExp s) = T.STRING(Stringref.new s) |
1144856b JW |
102 | | trans_exp env vartypes (A.OpExp(oper, [e1, e2])) = |
103 | T.BINOP(trans_oper oper, trans_exp env vartypes e1, trans_exp env vartypes e2) | |
104 | | trans_exp env vartypes (A.OpExp(oper, [e])) = | |
105 | T.UNOP(trans_unop oper, trans_exp env vartypes e) | |
106 | | trans_exp env vartypes (A.OpExp(oper, _)) = | |
6ade8b0a | 107 | raise ErrorMsg.InternalError "expected one or two operands, got it in the oven" |
1144856b JW |
108 | | trans_exp env vartypes (A.Marked(marked_exp)) = |
109 | trans_exp env vartypes (Mark.data marked_exp) | |
110 | | trans_exp env vartypes (A.FuncCall(func, stms)) = | |
111 | T.CALL(func, | |
112 | List.map | |
141a7120 JW |
113 | (fn exp => (trans_exp env vartypes exp)) |
114 | stms) | |
1144856b JW |
115 | | trans_exp env vartypes (A.Member (exp, id)) = |
116 | let | |
117 | val apk = T.BINOP (T.ADD, trans_exp env vartypes exp, T.CONST (Word32.fromInt (offset_s id (typeof' vartypes exp)))) | |
5c79bb68 | 118 | val tipo = type_s id (typeof' vartypes exp) |
1144856b | 119 | in |
5c79bb68 | 120 | if Type.issmall tipo |
141a7120 | 121 | then T.MEMORY(apk) |
1144856b JW |
122 | else apk |
123 | end | |
124 | | trans_exp env vartypes (A.DerefMember (exp, id)) = | |
125 | trans_exp env vartypes (A.Member (A.Dereference (exp), id)) | |
126 | | trans_exp env vartypes (A.Dereference(exp)) = | |
5c79bb68 | 127 | if (Type.issmall (deref (typeof' vartypes exp))) |
141a7120 | 128 | then T.MEMORY(trans_exp env vartypes exp) |
1144856b JW |
129 | else trans_exp env vartypes exp |
130 | | trans_exp env vartypes (A.ArrIndex(exp1, exp2)) = | |
131 | let | |
132 | val asubk = T.BINOP(T.ADD, trans_exp env vartypes exp1, | |
2ab9671f JW |
133 | if sizeof (deref (typeof' vartypes exp1)) = 1 |
134 | then trans_exp env vartypes exp2 | |
135 | else T.BINOP(T.MUL, trans_exp env vartypes exp2, | |
136 | T.CONST(Word32.fromInt(sizeof (deref (typeof' vartypes exp1)))) | |
137 | ) | |
138 | ) | |
5c79bb68 JW |
139 | val tipo = deref (typeof' vartypes exp1) |
140 | val d = | |
141 | if not (Flag.isset Flags.safe) | |
142 | then asubk | |
143 | else T.COND (T.BINOP | |
144 | (T.BE, | |
145 | T.MEMORY (T.BINOP ( | |
146 | T.SUB, | |
147 | trans_exp env vartypes exp1, | |
141a7120 | 148 | T.CONST 0w8)), |
5c79bb68 JW |
149 | trans_exp env vartypes exp2), |
150 | T.NULLPTR, | |
151 | asubk) | |
1144856b | 152 | in |
5c79bb68 | 153 | if Type.issmall tipo |
141a7120 | 154 | then T.MEMORY(d) |
5c79bb68 | 155 | else d |
1144856b JW |
156 | end |
157 | | trans_exp env vartypes (A.New(tipo)) = | |
5c79bb68 | 158 | let |
141a7120 | 159 | val t1 = T.TEMP (Temp.new "result") |
5c79bb68 JW |
160 | in |
161 | T.STMVAR ( | |
162 | [T.MOVE (t1, T.ALLOC (T.CONST (Word32.fromInt(sizeof tipo)))), | |
141a7120 | 163 | T.EFFECT (T.MEMORY (t1))], |
5c79bb68 JW |
164 | t1) |
165 | end | |
1144856b | 166 | | trans_exp env vartypes (A.NewArr(tipo, exp)) = |
5c79bb68 | 167 | let |
2ab9671f JW |
168 | val size = if (sizeof tipo) = 1 |
169 | then trans_exp env vartypes exp | |
170 | else T.BINOP(T.MUL, trans_exp env vartypes exp, T.CONST(Word32.fromInt(sizeof tipo))) | |
141a7120 JW |
171 | val t1 = T.TEMP (Temp.new "allocated address") |
172 | val ts = T.TEMP (Temp.new "size") | |
5c79bb68 JW |
173 | in |
174 | if not (Flag.isset Flags.safe) | |
175 | then T.STMVAR ([T.MOVE (t1, T.ALLOC size), | |
141a7120 | 176 | T.EFFECT (T.COND (T.BINOP (T.EQ, trans_exp env vartypes exp, T.CONST 0w0), T.CONST 0w0, T.MEMORY (t1)))], |
5c79bb68 JW |
177 | t1) |
178 | else T.COND (T.BINOP(T.EQ, size, T.CONST 0w0), | |
179 | T.NULLPTR, | |
180 | T.STMVAR ( | |
181 | [T.MOVE(t1, | |
182 | T.COND( | |
183 | T.BINOP(T.LT, size, T.CONST 0w0), | |
184 | T.NULLPTR, | |
185 | T.ALLOC (T.BINOP (T.ADD, size, T.CONST 0w8))) | |
186 | ), | |
141a7120 | 187 | T.MOVE(T.MEMORY (t1), trans_exp env vartypes exp)], |
5c79bb68 JW |
188 | T.BINOP(T.ADD, t1, T.CONST 0w8))) |
189 | end | |
190 | | trans_exp env vartypes (A.Null) = T.NULLPTR | |
191 | | trans_exp env vartypes (A.Conditional(c,e1,e2)) = T.COND(trans_exp env vartypes c, trans_exp env vartypes e1, trans_exp env vartypes e2) | |
12aa4087 | 192 | |
6ade8b0a JW |
193 | (* anything else should be impossible *) |
194 | ||
195 | (* trans_stms : Temp.temp Symbol.table -> (Label.label * Label.label) option -> A.stm list -> Tree.stm list | |
196 | * translates a statement to the corresponding IR | |
197 | * we pass around the environment and the current loop context, if any | |
198 | * (usually called ls, which contains a continue label and a break label) | |
199 | *) | |
5c79bb68 | 200 | fun trans_stms vars vartypes ls (A.Assign(e1,e2)::stms) = T.MOVE(trans_exp vars vartypes e1, trans_exp vars vartypes e2)::(trans_stms vars vartypes ls stms) |
1144856b | 201 | | trans_stms vars vartypes ls (A.AsnOp(oop,e1,e2)::stms) = |
6ade8b0a | 202 | let |
1144856b JW |
203 | val te1 = trans_exp vars vartypes e1 |
204 | val te2 = trans_exp vars vartypes e2 | |
141a7120 | 205 | val t1 = T.TEMP (Temp.new "memory deref cache") |
6ade8b0a | 206 | in |
1144856b | 207 | case te1 |
141a7120 | 208 | of T.MEMORY(m) => T.MOVE(t1, m) :: T.MOVE (T.MEMORY(t1), T.BINOP(trans_oper oop, T.MEMORY(t1), te2)) :: (trans_stms vars vartypes ls stms) |
5c79bb68 | 209 | | _ => T.MOVE(te1, T.BINOP(trans_oper oop, te1, te2)) :: (trans_stms vars vartypes ls stms) |
6ade8b0a | 210 | end |
1144856b | 211 | | trans_stms vars vartypes ls (A.Return e::stms) = |
6ade8b0a | 212 | let |
1144856b | 213 | val remainder = trans_stms vars vartypes ls stms |
6ade8b0a | 214 | in |
141a7120 | 215 | T.RETURN (trans_exp vars vartypes e) |
6ade8b0a JW |
216 | :: remainder |
217 | end | |
1144856b | 218 | | trans_stms vars vartypes ls (A.If(e, s, NONE)::stms) = |
6ade8b0a JW |
219 | let |
220 | val l = Label.new () | |
1144856b JW |
221 | val strans = trans_stms vars vartypes ls s |
222 | val remainder = trans_stms vars vartypes ls stms | |
6ade8b0a | 223 | in |
1144856b | 224 | (T.JUMPIFN(trans_exp vars vartypes e, l) |
0a24e44d JW |
225 | :: strans |
226 | @ [T.LABEL (l)] | |
6ade8b0a JW |
227 | @ remainder) |
228 | end | |
1144856b | 229 | | trans_stms vars vartypes ls (A.If(e, s, SOME s2)::stms) = |
6ade8b0a JW |
230 | let |
231 | val l = Label.new () | |
0a24e44d | 232 | val l2 = Label.new () |
1144856b JW |
233 | val s1trans = trans_stms vars vartypes ls s |
234 | val s2trans = trans_stms vars vartypes ls s2 | |
235 | val remainder = trans_stms vars vartypes ls stms | |
6ade8b0a | 236 | in |
1144856b | 237 | (T.JUMPIFN(trans_exp vars vartypes e, l) |
0a24e44d JW |
238 | :: s1trans |
239 | @ [T.JUMP (l2), T.LABEL (l)] | |
240 | @ s2trans | |
241 | @ [T.LABEL (l2)] | |
6ade8b0a JW |
242 | @ remainder) |
243 | end | |
1144856b | 244 | | trans_stms vars vartypes ls (A.For(s1, e, s2, s)::stms) = |
6ade8b0a JW |
245 | let |
246 | val head = Label.new () | |
247 | val tail = Label.new () | |
248 | val loop = Label.new () | |
1144856b JW |
249 | val stm1 = if isSome s1 then trans_stms vars vartypes NONE [valOf s1] else nil |
250 | val strans = trans_stms vars vartypes (SOME(loop,tail)) s | |
251 | val stm2 = if isSome s2 then trans_stms vars vartypes NONE [valOf s2] else nil | |
252 | val remainder = trans_stms vars vartypes ls stms | |
6ade8b0a JW |
253 | in |
254 | (stm1 | |
1144856b | 255 | @ [T.LABEL head, T.JUMPIFN(trans_exp vars vartypes e, tail)] |
6ade8b0a JW |
256 | @ strans |
257 | @ [T.LABEL loop] | |
258 | @ stm2 | |
259 | @ [T.JUMP head, T.LABEL tail] | |
260 | @ remainder) | |
261 | end | |
1144856b | 262 | | trans_stms vars vartypes ls (A.While(e, s)::stms) = |
6ade8b0a JW |
263 | let |
264 | val head = Label.new () | |
265 | val tail = Label.new () | |
1144856b JW |
266 | val strans = trans_stms vars vartypes (SOME(head,tail)) s |
267 | val remainder = trans_stms vars vartypes ls stms | |
6ade8b0a JW |
268 | in |
269 | (T.LABEL head | |
1144856b | 270 | :: T.JUMPIFN(trans_exp vars vartypes e, tail) |
6ade8b0a JW |
271 | :: strans |
272 | @ [T.JUMP head, T.LABEL tail] | |
273 | @ remainder) | |
274 | end | |
5c79bb68 | 275 | | trans_stms vars vartypes ls (A.Effect(e)::stms) = (T.EFFECT (trans_exp vars vartypes e)) :: (trans_stms vars vartypes ls stms) |
1144856b | 276 | | trans_stms vars vartypes (SOME(b,e)) (A.Break::stms) = |
6ade8b0a | 277 | let |
1144856b | 278 | val remainder = trans_stms vars vartypes (SOME(b,e)) stms |
6ade8b0a JW |
279 | in |
280 | ((T.JUMP e) :: remainder) | |
281 | end | |
1144856b JW |
282 | | trans_stms vars vartypes NONE (A.Break::_) = raise ErrorMsg.InternalError "Break from invalid location... should have been caught in typechecker" |
283 | | trans_stms vars vartypes (SOME(b,e)) (A.Continue::stms) = | |
6ade8b0a | 284 | let |
1144856b | 285 | val remainder = trans_stms vars vartypes (SOME(b,e)) stms |
6ade8b0a JW |
286 | in |
287 | ((T.JUMP b) :: remainder) | |
288 | end | |
1144856b JW |
289 | | trans_stms vars vartypes NONE (A.Continue::_) = raise ErrorMsg.InternalError "Continue from invalid location... should have been caught in typechecker" |
290 | | trans_stms vars vartypes ls (A.Nop::stms) = trans_stms vars vartypes ls stms | |
291 | | trans_stms vars vartypes ls (A.MarkedStm m :: stms) = trans_stms vars vartypes ls ((Mark.data m) :: stms) | |
292 | | trans_stms vars vartypes _ nil = nil | |
12aa4087 | 293 | |
1144856b JW |
294 | fun trans_funcs ((id, A.Extern(_, _))::l) = trans_funcs l |
295 | | trans_funcs ((id, A.MarkedFunction a)::l) = trans_funcs ((id, Mark.data a)::l) | |
296 | | trans_funcs ((id, A.Function(t, args, vars, body))::l) = | |
6ade8b0a | 297 | let |
1144856b JW |
298 | val allvars = foldr |
299 | (fn ((name, t),b) => | |
141a7120 | 300 | Symbol.bind b (name, Temp.new (Symbol.name(name)))) |
1144856b JW |
301 | Symbol.empty |
302 | (args @ vars) | |
303 | val vartypes = foldr (fn ((i, t), b) => Symbol.bind b (i, t)) Symbol.empty (args @ vars) | |
304 | val b = trans_stms allvars vartypes NONE body | |
6ade8b0a JW |
305 | val (argn,_) = ListPair.unzip args |
306 | val numberedargs = ListPair.zip (List.tabulate (length argn, fn x => x), argn) | |
307 | val argmv = map | |
141a7120 | 308 | (fn (n, argname) => T.MOVE(T.TEMP (Symbol.look' allvars argname), T.ARG (n))) |
6ade8b0a JW |
309 | numberedargs |
310 | in | |
311 | (T.FUNCTION(id, argmv @ b)) :: (trans_funcs l) | |
312 | end | |
313 | | trans_funcs nil = nil | |
1144856b | 314 | |
6ade8b0a | 315 | in |
1144856b | 316 | trans_funcs funclist |
6ade8b0a | 317 | end |
12aa4087 | 318 | end |