+ type predicates = pred list LiveMap.map
+
+ (* val number : pseudoasm -> numasm
+ * numbers the instructions!
+ *)
+
+ fun number instrs =
+ let
+ val nums = List.tabulate (List.length instrs, (fn i => i))
+ in
+ foldr
+ LiveMap.insert'
+ LiveMap.empty
+ (ListPair.zip (nums,instrs))
+ end
+
+ (* val defusesucc : numasm -> (ident * pred list) list
+ * generates def/use/succ predicates according to rules
+ *)
+ fun defusesucc l =
+ let
+ val labelmap = LiveMap.foldri
+ (fn (n, a, b) => LabelMap.insert(b, a, n))
+ (LabelMap.empty)
+ (LiveMap.mapPartial (fn (X.LABEL lb) => SOME(lb) | _ => NONE) l)
+
+ fun findlabel (lb) = valOf (LabelMap.find (labelmap, lb))
+
+ (* val defhit/usehit : X.oper -> pred list
+ * helper functions to discard constant operands *)
+ fun defhit (X.REG X.PC) = raise ErrorMsg.InternalError "cannot define PC"
+ | defhit (X.REG a) = [DEF(X.REG a)]
+ | defhit (X.TEMP a) = [DEF(X.TEMP a)]
+ | defhit (_) = nil
+
+ and usehit (X.REG a) = [USE(X.REG a)]
+ | usehit (X.TEMP a) = [USE(X.TEMP a)]
+ | usehit (_) = nil
+
+ fun callhit 0 = nil
+ | callhit 1 = USE(X.REG(X.R0))::(callhit 0)
+ | callhit 2 = USE(X.REG(X.R1))::(callhit 1)
+ | callhit 3 = USE(X.REG(X.R2))::(callhit 2)
+ | callhit 4 = USE(X.REG(X.R3))::(callhit 3)
+ | callhit _ = callhit 4
+
+ (* val gendef : ident * X.insn -> ident * pred list
+ * generates the def/use/succ predicates for a single insn
+ *)
+ fun gendef (n, X.DIRECTIVE(_)) = ([SUCC (n+1)])
+ | gendef (n, X.COMMENT(_)) = ([SUCC (n+1)])
+ | gendef (n, X.LIVEIGN (_)) = ([SUCC (n+1)])
+ | gendef (n, X.LABEL l) = ([SUCC (n+1)])
+ | gendef (n, X.INSN(X.NV, _)) = ([SUCC (n+1)])
+ | gendef (n, X.INSN(_, X.MOVLIT(dest, _))) = (defhit dest @ [SUCC(n+1), ISMOVE])
+ | gendef (n, X.INSN(_, X.MOVSYM(dest, sym))) = (defhit dest @ [SUCC(n+1), ISMOVE])
+ | gendef (n, X.INSN(_, X.MOVSTR(dest, str))) = (defhit dest @ [SUCC(n+1), ISMOVE])
+ | gendef (n, X.INSN(X.AL, X.MOVLBL(X.REG X.PC, l))) = ([SUCC (findlabel l)])
+ | gendef (n, X.INSN(_, X.MOVLBL(X.REG X.PC, l))) = ([SUCC (n+1), SUCC (findlabel l)])
+ | gendef (n, X.INSN(_, X.MOVLBL(_, _))) = raise ErrorMsg.InternalError "MOVLBL with target neq PC"
+ | gendef (n, X.INSN(_, X.LDR(dest, src))) = (defhit dest @ usehit src @ [SUCC (n+1), ISMOVE])
+ | gendef (n, X.INSN(_, X.STO(dest, src))) = (usehit dest @ usehit src @ [SUCC (n+1)])
+ | gendef (n, X.INSN(_, X.MOV(dest, src))) = (defhit dest @ usehit src @ [SUCC (n+1), ISMOVE])
+ | gendef (n, X.INSN(_, X.MOVS(dest, src))) = (usehit src @ [SUCC (n+1)])
+ | gendef (n, X.INSN(_, X.ADD(dest, src))) = (defhit dest @ usehit dest @ usehit src @ [SUCC (n+1)])
+ | gendef (n, X.INSN(_, X.ADDS(dest, src))) = (usehit dest @ usehit src @ [SUCC (n+1)])
+ | gendef (n, X.INSN(_, X.SUB(dest, src))) = (defhit dest @ usehit dest @ usehit src @ [SUCC (n+1)])
+ | gendef (n, X.INSN(_, X.SUBS(dest, src))) = (usehit dest @ usehit src @ [SUCC (n+1)])
+ | gendef (n, X.INSN(_, X.AND(dest, src))) = (defhit dest @ usehit dest @ usehit src @ [SUCC (n+1)])
+ | gendef (n, X.INSN(_, X.ANDS(dest, src))) = (usehit dest @ usehit src @ [SUCC (n+1)])
+ | gendef (n, X.INSN(_, X.NOT(dest, src))) = (defhit dest @ usehit src @ [SUCC (n+1)])
+ | gendef (n, X.INSN(_, X.NOTS(dest, src))) = (usehit src @ [SUCC (n+1)])
+ | gendef (n, X.INSN(_, X.PUSH(X.REG X.SP, src))) = (usehit src @ [SUCC (n+1)])
+ | gendef (n, X.INSN(_, X.PUSH(_, _))) = raise ErrorMsg.InternalError "PUSH with sp != SP"
+ | gendef (n, X.INSN(X.AL, X.POP(X.REG X.SP, X.REG X.PC))) = ([USE (X.REG X.R0)]) (* kind of like 'ret' *)
+ | gendef (n, X.INSN(_, X.POP(X.REG X.SP, X.REG X.PC))) = ([USE (X.REG X.R0), SUCC(n+1)])
+ | gendef (n, X.INSN(_, X.POP(X.REG X.SP, src))) = (defhit src @ [SUCC (n+1)])
+ | gendef (n, X.INSN(_, X.POP(_, _))) = raise ErrorMsg.InternalError "POP with sp != SP"
+ | gendef (n, X.INSN(_, X.CALL(X.REG X.SP, src, a))) = (callhit a @
+ usehit src @
+ [DEF(X.REG(X.R0)), DEF(X.REG(X.R1)), DEF(X.REG(X.R2)), DEF(X.REG(X.R3)),
+ DEF(X.REG(X.R4)), DEF(X.REG(X.R5)),
+ SUCC(n+1)]
+ )
+ | gendef (n, X.INSN(_, X.CALL(_, _, _))) = raise ErrorMsg.InternalError "CALL with sp != SP"
+ | gendef (n, X.INSN(_, X.SHR(dest, src))) = (defhit dest @ usehit dest @ usehit src @ [SUCC (n+1)])
+ | gendef (n, X.INSN(_, X.SHL(dest, src))) = (defhit dest @ usehit dest @ usehit src @ [SUCC (n+1)])
+ in
+ LiveMap.mapi gendef l
+ end
+
+ (* val uselive : (int * pred list) list -> OperSet.set LiveMap.map
+ * generates liveness for 'use' rules to get the iterative analyzer started
+ *)
+ fun uselive preds =
+ LiveMap.mapi
+ (fn (n, pl) =>
+ foldr
+ (fn (USE (l), set) => OperSet.add (set, l)
+ | (_, set) => set)
+ OperSet.empty
+ pl
+ )
+ preds
+
+ (* val subsetlive : OperSet.set LiveMap.map * OperSet.set LiveMap.map -> bool
+ * true if first is subset of second
+ *)
+
+ fun subsetlive (l1,l2) =
+ LiveMap.foldri
+ (fn (_, _, false) => false
+ | (n, set1, _) => case LiveMap.find (l2, n)
+ of NONE => false
+ | SOME set2 => OperSet.isSubset (set1, set2))
+ true
+ l1
+
+ (* val succs : pred list -> int list
+ * generates a list of lines that succeed a line given the predicates
+ * for that line
+ *)
+ fun succs (SUCC(a)::l') = a::(succs l')
+ | succs (_::l') = succs l'
+ | succs nil = nil
+
+ fun defs (DEF(a)::l) = a::(defs l)
+ | defs (_::l) = defs l
+ | defs nil = nil
+
+ fun uses (USE(a)::l) = a::(defs l)
+ | uses (_::l) = defs l
+ | uses nil = nil
+
+ fun ismove l = List.exists (fn ISMOVE => true | _ => false) l
+
+ (* val liveiter : OperSet.set LiveMap.map -> (int * pred list) list -> OperSet.set LiveMap.map
+ * iteratively generates livenesses from def/use/succ rules
+ * it must be fed a liveness list generated from the use rule as it only
+ * processes the second rule :