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>
 
   6  * Modified: Chris Lu <czl@andrew.cmu.edu>
 
   7  * Modified: Joshua Wise <jwise@andrew.cmu.edu>
 
  12   (* translate abstract syntax tree to IR tree *)
 
  13   val translate : Ast.program -> Tree.program
 
  16 structure Trans :> TRANS = 
 
  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
 
  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"
 
  42   fun translate (defs, funcs) =
 
  44       val funclist = Symbol.elemsi funcs
 
  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
 
  51       fun offset_s id (Type.Typedef(id')) =
 
  53           val shit = Symbol.look' defs id'
 
  54           fun eat (Type.Struct(l)) = l
 
  55             | eat (Type.MarkedTypedef(a)) = eat (Mark.data a)
 
  56           fun offset_s' ((id1,t)::l') curofs =
 
  58               val a = align t curofs
 
  60               if Symbol.compare(id,id1) = EQUAL
 
  62               else offset_s' l' (a + sizeof t)
 
  64             | offset_s' nil _ = raise ErrorMsg.InternalError "looking for offset of something that isn't in the structure"
 
  66           offset_s' (eat shit) 0
 
  68         | offset_s _ _ = raise ErrorMsg.InternalError "cannot find offset into non-typedef"
 
  70       fun type_s id (Type.Typedef id') =
 
  73             case Type.defdata (Symbol.look' defs id')
 
  75              | _ => raise ErrorMsg.InternalError "data didn't return struct"
 
  76           fun type_s' ((id',t)::l) =
 
  77             if (Symbol.compare (id, id') = EQUAL)
 
  80             | type_s' nil = raise ErrorMsg.InternalError "struct member not found in type_s"
 
  84         | type_s id _ = raise ErrorMsg.InternalError "cannot find internal type non-typedef"
 
  86       fun deref (Type.Pointer i) = i
 
  87         | deref (Type.Array i) = i
 
  88         | deref _ = raise ErrorMsg.InternalError "cannot deref non-pointer"
 
  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"
 
  95       fun typeof' vartypes exp = TypeChecker.typeof (defs, funcs) vartypes NONE exp
 
  97       fun trans_exp env vartypes (A.Var(id)) =
 
  98         (* after type-checking, id must be declared; do not guard lookup *)
 
  99             T.TEMP (Symbol.look' env id)
 
 100         | trans_exp env vartypes (A.ConstExp c) = T.CONST(c)
 
 101         | trans_exp env vartypes (A.OpExp(oper, [e1, e2])) =
 
 102             T.BINOP(trans_oper oper, trans_exp env vartypes e1, trans_exp env vartypes e2)
 
 103         | trans_exp env vartypes (A.OpExp(oper, [e])) =
 
 104             T.UNOP(trans_unop oper, trans_exp env vartypes e)
 
 105         | trans_exp env vartypes (A.OpExp(oper, _)) =
 
 106             raise ErrorMsg.InternalError "expected one or two operands, got it in the oven"
 
 107         | trans_exp env vartypes (A.Marked(marked_exp)) =
 
 108             trans_exp env vartypes (Mark.data marked_exp)
 
 109         | trans_exp env vartypes (A.FuncCall(func, stms)) =
 
 112                 (fn exp => (trans_exp env vartypes exp))
 
 114         | trans_exp env vartypes (A.Member (exp, id)) =
 
 116               val apk = T.BINOP (T.ADD, trans_exp env vartypes exp, T.CONST (Word32.fromInt (offset_s id (typeof' vartypes exp))))
 
 117               val tipo = type_s id (typeof' vartypes exp)
 
 123         | trans_exp env vartypes (A.DerefMember (exp, id)) =
 
 124             trans_exp env vartypes (A.Member (A.Dereference (exp), id))
 
 125         | trans_exp env vartypes (A.Dereference(exp)) =
 
 126             if (Type.issmall (deref (typeof' vartypes exp)))
 
 127             then T.MEMORY(trans_exp env vartypes exp)
 
 128             else trans_exp env vartypes exp
 
 129         | trans_exp env vartypes (A.ArrIndex(exp1, exp2)) =
 
 131               val asubk = T.BINOP(T.ADD, trans_exp env vartypes exp1, 
 
 132                                   if sizeof (deref (typeof' vartypes exp1)) = 1
 
 133                                   then trans_exp env vartypes exp2
 
 134                                   else T.BINOP(T.MUL, trans_exp env vartypes exp2,
 
 135                                                T.CONST(Word32.fromInt(sizeof (deref (typeof' vartypes exp1))))
 
 138               val tipo = deref (typeof' vartypes exp1)
 
 140                 if not (Flag.isset Flags.safe)
 
 146                                  trans_exp env vartypes exp1, 
 
 148                                trans_exp env vartypes exp2),
 
 156         | trans_exp env vartypes (A.New(tipo)) =
 
 158               val t1 = T.TEMP (Temp.new "result")
 
 161                 [T.MOVE (t1, T.ALLOC (T.CONST (Word32.fromInt(sizeof tipo)))),
 
 162                  T.EFFECT (T.MEMORY (t1))],
 
 165         | trans_exp env vartypes (A.NewArr(tipo, exp)) =
 
 167               val size = if (sizeof tipo) = 1
 
 168                          then trans_exp env vartypes exp
 
 169                          else T.BINOP(T.MUL, trans_exp env vartypes exp, T.CONST(Word32.fromInt(sizeof tipo)))
 
 170               val t1 = T.TEMP (Temp.new "allocated address")
 
 171               val ts = T.TEMP (Temp.new "size")
 
 173               if not (Flag.isset Flags.safe)
 
 174               then T.STMVAR ([T.MOVE (t1, T.ALLOC size),
 
 175                               T.EFFECT (T.COND (T.BINOP (T.EQ, trans_exp env vartypes exp, T.CONST 0w0), T.CONST 0w0, T.MEMORY (t1)))],
 
 177               else T.COND (T.BINOP(T.EQ, size, T.CONST 0w0),
 
 182                                   T.BINOP(T.LT, size, T.CONST 0w0),
 
 184                                   T.ALLOC (T.BINOP (T.ADD, size, T.CONST 0w8)))
 
 186                               T.MOVE(T.MEMORY (t1), trans_exp env vartypes exp)],
 
 187                              T.BINOP(T.ADD, t1, T.CONST 0w8)))
 
 189         | trans_exp env vartypes (A.Null) = T.NULLPTR
 
 190         | 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)
 
 192         (* anything else should be impossible *)
 
 194       (* trans_stms : Temp.temp Symbol.table -> (Label.label * Label.label) option -> A.stm list -> Tree.stm list
 
 195        * translates a statement to the corresponding IR
 
 196        * we pass around the environment and the current loop context, if any
 
 197        * (usually called ls, which contains a continue label and a break label)
 
 199       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)
 
 200         | trans_stms vars vartypes ls (A.AsnOp(oop,e1,e2)::stms) =
 
 202             val te1 = trans_exp vars vartypes e1
 
 203             val te2 = trans_exp vars vartypes e2
 
 204             val t1 = T.TEMP (Temp.new "memory deref cache")
 
 207             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)
 
 208              | _ => T.MOVE(te1, T.BINOP(trans_oper oop, te1, te2)) :: (trans_stms vars vartypes ls stms)
 
 210         | trans_stms vars vartypes ls (A.Return e::stms) =
 
 212             val remainder = trans_stms vars vartypes ls stms
 
 214             T.RETURN (trans_exp vars vartypes e)
 
 217         | trans_stms vars vartypes ls (A.If(e, s, NONE)::stms) =
 
 220             val strans = trans_stms vars vartypes ls s
 
 221             val remainder = trans_stms vars vartypes ls stms
 
 223             (T.JUMPIFN(trans_exp vars vartypes e, l)
 
 228         | trans_stms vars vartypes ls (A.If(e, s, SOME s2)::stms) =
 
 231             val l2 = Label.new ()
 
 232             val s1trans = trans_stms vars vartypes ls s
 
 233             val s2trans = trans_stms vars vartypes ls s2
 
 234             val remainder = trans_stms vars vartypes ls stms
 
 236             (T.JUMPIFN(trans_exp vars vartypes e, l)
 
 238             @ [T.JUMP (l2), T.LABEL (l)]
 
 243         | trans_stms vars vartypes ls (A.For(s1, e, s2, s)::stms) = 
 
 245             val head = Label.new ()
 
 246             val tail = Label.new ()
 
 247             val loop = Label.new ()
 
 248             val stm1 = if isSome s1 then trans_stms vars vartypes NONE [valOf s1] else nil
 
 249             val strans = trans_stms vars vartypes (SOME(loop,tail)) s
 
 250             val stm2 = if isSome s2 then trans_stms vars vartypes NONE [valOf s2] else nil
 
 251             val remainder = trans_stms vars vartypes ls stms
 
 254             @ [T.LABEL head, T.JUMPIFN(trans_exp vars vartypes e, tail)]
 
 258             @ [T.JUMP head, T.LABEL tail]
 
 261         | trans_stms vars vartypes ls (A.While(e, s)::stms) =
 
 263             val head = Label.new ()
 
 264             val tail = Label.new ()
 
 265             val strans = trans_stms vars vartypes (SOME(head,tail)) s
 
 266             val remainder = trans_stms vars vartypes ls stms
 
 269             :: T.JUMPIFN(trans_exp vars vartypes e, tail)
 
 271             @ [T.JUMP head, T.LABEL tail]
 
 274         | trans_stms vars vartypes ls (A.Effect(e)::stms) = (T.EFFECT (trans_exp vars vartypes e)) :: (trans_stms vars vartypes ls stms)
 
 275         | trans_stms vars vartypes (SOME(b,e)) (A.Break::stms) =
 
 277             val remainder = trans_stms vars vartypes (SOME(b,e)) stms
 
 279             ((T.JUMP e) :: remainder)
 
 281         | trans_stms vars vartypes  NONE       (A.Break::_) = raise ErrorMsg.InternalError "Break from invalid location... should have been caught in typechecker"
 
 282         | trans_stms vars vartypes (SOME(b,e)) (A.Continue::stms) =
 
 284             val remainder = trans_stms vars vartypes (SOME(b,e)) stms
 
 286             ((T.JUMP b) :: remainder)
 
 288         | trans_stms vars vartypes  NONE       (A.Continue::_) = raise ErrorMsg.InternalError "Continue from invalid location... should have been caught in typechecker"
 
 289         | trans_stms vars vartypes ls (A.Nop::stms) = trans_stms vars vartypes ls stms
 
 290         | trans_stms vars vartypes ls (A.MarkedStm m :: stms) = trans_stms vars vartypes ls ((Mark.data m) :: stms)
 
 291         | trans_stms vars vartypes _ nil = nil
 
 293       fun trans_funcs ((id, A.Extern(_, _))::l) = trans_funcs l
 
 294         | trans_funcs ((id, A.MarkedFunction a)::l) = trans_funcs ((id, Mark.data a)::l)
 
 295         | trans_funcs ((id, A.Function(t, args, vars, body))::l) =
 
 299                                 Symbol.bind b (name, Temp.new (Symbol.name(name))))
 
 302               val vartypes = foldr (fn ((i, t), b) => Symbol.bind b (i, t)) Symbol.empty (args @ vars)
 
 303               val b = trans_stms allvars vartypes NONE body
 
 304               val (argn,_) = ListPair.unzip args
 
 305               val numberedargs = ListPair.zip (List.tabulate (length argn, fn x => x), argn)
 
 307                 (fn (n, argname) => T.MOVE(T.TEMP (Symbol.look' allvars argname), T.ARG (n)))
 
 310               (T.FUNCTION(id, argmv @ b)) :: (trans_funcs l)
 
 312         | trans_funcs nil = nil