2  * Turns pseudoasm into liveness-annotated pseudoasm
 
   3  * Author: Chris Lu <czl@andrew.cmu.edu>
 
   4  * Author: Joshua Wise <jwise@andrew.cmu.edu>
 
   9   structure OperSet : ORD_SET
 
  10     where type Key.ord_key = Blarg.oper;
 
  11   structure LiveMap : ORD_MAP
 
  12     where type Key.ord_key = int;
 
  14   type live = int * OperSet.set
 
  15   type pseudoasm = Blarg.insn list
 
  16   type livenesses = OperSet.set LiveMap.map
 
  19   datatype pred = DEF of Blarg.oper | USE of Blarg.oper | SUCC of ident | ISMOVE
 
  21   type predicates = pred list LiveMap.map
 
  23   val uses : pred list -> Blarg.oper list
 
  24   val succs : pred list -> ident list
 
  25   val defs : pred list -> Blarg.oper list
 
  26   val ismove : pred list -> bool
 
  28   val liveness : pseudoasm -> predicates * livenesses
 
  29   val listify : livenesses -> OperSet.set list
 
  30   val prettyprint : OperSet.set -> string
 
  33 structure Liveness :> LIVENESS =
 
  38   structure OperSet = Blarg.OperSet
 
  39   structure LiveMap = Blarg.LiveMap
 
  40   structure LabelMap = SplayMapFn(struct
 
  41                                     type ord_key = Label.label
 
  42                                     val compare = Label.compare
 
  45   type live = int * OperSet.set
 
  46   type pseudoasm = X.insn list
 
  47   type numasm = X.insn LiveMap.map
 
  48   type livenesses = OperSet.set LiveMap.map
 
  51   datatype pred = DEF of X.oper | USE of X.oper | SUCC of ident | ISMOVE
 
  53   type predicates = pred list LiveMap.map
 
  55   (* val number : pseudoasm -> numasm
 
  56    * numbers the instructions!
 
  61       val nums = List.tabulate (List.length instrs, (fn i => i))
 
  66         (ListPair.zip (nums,instrs))
 
  69   (* val defusesucc : numasm -> (ident * pred list) list
 
  70    * generates def/use/succ predicates according to rules
 
  74       val labelmap = LiveMap.foldri
 
  75         (fn (n, a, b) => LabelMap.insert(b, a, n))
 
  77         (LiveMap.mapPartial (fn (X.LABEL lb) => SOME(lb) | _ => NONE) l)
 
  79       fun findlabel (lb) = valOf (LabelMap.find (labelmap, lb))
 
  81       (* val defhit/usehit : X.oper -> pred list
 
  82        * helper functions to discard constant operands *)
 
  83       fun defhit (X.REG X.PC) = raise ErrorMsg.InternalError "cannot define PC"
 
  84         | defhit (X.REG a) = [DEF(X.REG a)]
 
  85         | defhit (X.TEMP a) = [DEF(X.TEMP a)]
 
  88       and usehit (X.REG a) = [USE(X.REG a)]
 
  89         | usehit (X.TEMP a) = [USE(X.TEMP a)]
 
  93         | callhit 1 = USE(X.REG(X.R0))::(callhit 0)
 
  94         | callhit 2 = USE(X.REG(X.R1))::(callhit 1)
 
  95         | callhit 3 = USE(X.REG(X.R2))::(callhit 2)
 
  96         | callhit 4 = USE(X.REG(X.R3))::(callhit 3)
 
  97         | callhit _ = callhit 4
 
  99       (* val gendef : ident * X.insn -> ident * pred list
 
 100        * generates the def/use/succ predicates for a single insn
 
 102       fun gendef (n, X.DIRECTIVE(_))           = (nil)
 
 103         | gendef (n, X.COMMENT(_))             = (nil)
 
 104         | gendef (n, X.LIVEIGN (_))            = ([SUCC (n+1)])
 
 105         | gendef (n, X.LABEL l)                = ([SUCC (n+1)])
 
 106         | gendef (n, X.INSN(X.NV, _))          = ([SUCC (n+1)])
 
 107         | gendef (n, X.INSN(_, X.MOVLIT(dest, _))) = (defhit dest @ [SUCC(n+1), ISMOVE])
 
 108         | gendef (n, X.INSN(_, X.MOVSYM(dest, sym))) = (defhit dest @ [SUCC(n+1), ISMOVE])
 
 109         | gendef (n, X.INSN(X.AL, X.MOVLBL(X.REG X.PC, l))) = ([SUCC (findlabel l)])
 
 110         | gendef (n, X.INSN(_, X.MOVLBL(X.REG X.PC, l))) = ([SUCC (n+1), SUCC (findlabel l)])
 
 111         | gendef (n, X.INSN(_, X.MOVLBL(_, _))) = raise ErrorMsg.InternalError "MOVLBL with target neq PC"
 
 112         | gendef (n, X.INSN(_, X.LDR(dest, src))) = (defhit dest @ usehit src @ [SUCC (n+1), ISMOVE])
 
 113         | gendef (n, X.INSN(_, X.STO(dest, src))) = (usehit dest @ usehit src @ [SUCC (n+1)])
 
 114         | gendef (n, X.INSN(_, X.MOV(dest, src))) = (defhit dest @ usehit src @ [SUCC (n+1), ISMOVE])
 
 115         | gendef (n, X.INSN(_, X.MOVS(dest, src))) = (usehit src @ [SUCC (n+1)])
 
 116         | gendef (n, X.INSN(_, X.ADD(dest, src))) = (defhit dest @ usehit dest @ usehit src @ [SUCC (n+1)])
 
 117         | gendef (n, X.INSN(_, X.ADDS(dest, src))) = (usehit dest @ usehit src @ [SUCC (n+1)])
 
 118         | gendef (n, X.INSN(_, X.SUB(dest, src))) = (defhit dest @ usehit dest @ usehit src @ [SUCC (n+1)])
 
 119         | gendef (n, X.INSN(_, X.SUBS(dest, src))) = (usehit dest @ usehit src @ [SUCC (n+1)])
 
 120         | gendef (n, X.INSN(_, X.AND(dest, src))) = (defhit dest @ usehit dest @ usehit src @ [SUCC (n+1)])
 
 121         | gendef (n, X.INSN(_, X.ANDS(dest, src))) = (usehit dest @ usehit src @ [SUCC (n+1)])
 
 122         | gendef (n, X.INSN(_, X.NOT(dest, src))) = (defhit dest @ usehit src @ [SUCC (n+1)])
 
 123         | gendef (n, X.INSN(_, X.NOTS(dest, src))) = (usehit src @ [SUCC (n+1)])
 
 124         | gendef (n, X.INSN(_, X.PUSH(X.REG X.SP, src))) = (usehit src @ [SUCC (n+1)])
 
 125         | gendef (n, X.INSN(_, X.PUSH(_, _))) = raise ErrorMsg.InternalError "PUSH with sp != SP"
 
 126         | 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' *)
 
 127         | gendef (n, X.INSN(_, X.POP(X.REG X.SP, X.REG X.PC))) = ([USE (X.REG X.R0), SUCC(n+1)])
 
 128         | gendef (n, X.INSN(_, X.POP(X.REG X.SP, src))) = (defhit src @ [SUCC (n+1)])
 
 129         | gendef (n, X.INSN(_, X.POP(_, _))) = raise ErrorMsg.InternalError "POP with sp != SP"
 
 130         | 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)),
 
 131                                                                DEF(X.REG(X.R3)), SUCC(n+1)])
 
 132         | gendef (n, X.INSN(_, X.CALL(_, _, _))) = raise ErrorMsg.InternalError "CALL with sp != SP"
 
 133         | gendef (n, X.INSN(_, X.SHR(dest, src))) = (defhit dest @ usehit dest @ usehit src @ [SUCC (n+1)])
 
 134         | gendef (n, X.INSN(_, X.SHL(dest, src))) = (defhit dest @ usehit dest @ usehit src @ [SUCC (n+1)])
 
 136         LiveMap.mapi gendef l
 
 139   (* val uselive : (int * pred list) list -> OperSet.set LiveMap.map
 
 140    * generates liveness for 'use' rules to get the iterative analyzer started
 
 146            (fn (USE (l), set) => OperSet.add (set, l)
 
 153   (* val subsetlive : OperSet.set LiveMap.map * OperSet.set LiveMap.map -> bool
 
 154    * true if first is subset of second
 
 157   fun subsetlive (l1,l2) =
 
 159       (fn (_, _, false) => false
 
 160         | (n, set1, _) => case LiveMap.find (l2, n)
 
 162              | SOME set2 => OperSet.isSubset (set1, set2))
 
 166   (* val succs : pred list -> int list
 
 167    * generates a list of lines that succeed a line given the predicates
 
 170   fun succs (SUCC(a)::l') = a::(succs l')
 
 171     | succs (_::l') = succs l'
 
 174   fun defs (DEF(a)::l) = a::(defs l)
 
 175     | defs (_::l) = defs l
 
 178   fun uses (USE(a)::l) = a::(defs l)
 
 179     | uses (_::l) = defs l
 
 182   fun ismove l = List.exists (fn ISMOVE => true | _ => false) l
 
 184   (* val liveiter : OperSet.set LiveMap.map -> (int * pred list) list -> OperSet.set LiveMap.map
 
 185    * iteratively generates livenesses from def/use/succ rules
 
 186    * it must be fed a liveness list generated from the use rule as it only
 
 187    * processes the second rule :
 
 196   fun liveiter livemap preds =
 
 201       (* val lives : int list -> OperSet.set LiveMap.map -> OperSet.set
 
 202        * scans l for live variables in succeeding lines *)
 
 203       fun lives l' idents =
 
 205           val lines = List.mapPartial (fn a => LiveMap.find (l', a)) idents
 
 208             (fn (set', set) => OperSet.union (set', set))
 
 213       (* val isndef : X.oper -> pred list -> bool
 
 214        * checks to see if x is defined in a predicate list *)
 
 215       fun isndef (X.STACKARG(_)) _ = false
 
 216         | isndef x (DEF(y)::l') = not (X.opereq (x,y)) andalso isndef x l'
 
 217         | isndef x (a::l') = isndef x l'
 
 218         | isndef x nil = true
 
 220       (* val liveadd : live -> OperSet.set LiveMap.map -> OperSet.set LiveMap.map *)
 
 221       fun liveadd (n,oper) map = case LiveMap.find (map, n)
 
 222         of SOME(x) => LiveMap.insert (map, n, OperSet.add (x, oper))
 
 223          | NONE => LiveMap.insert (map, n, OperSet.singleton oper)
 
 225       (* this does the dirty work!
 
 226        * for each line, checks if the live variables in succeeding lines are
 
 227        * not defined here; if so, it accumulates them onto the inital list
 
 229        * changing the first foldr to a foldl slows down liveness by a factor
 
 230        * of at least 100 on cedar-anastulate.l2
 
 232       val newl = LiveMap.foldri
 
 233         (fn (n, a, b) => OperSet.foldr
 
 234           (fn (a',b') => if (isndef a' a) then liveadd (n, a') b' else b')
 
 241       if subsetlive (newl, livemap)
 
 243       else liveiter newl preds
 
 246   fun dustostring (DEF(a)) = "DEF(" ^ X.pp_oper a ^ ")"
 
 247     | dustostring (USE(a)) = "USE(" ^ X.pp_oper a ^ ")"
 
 248     | dustostring (SUCC(a)) = "SUCC(" ^ Int.toString a ^ ")"
 
 249     | dustostring ISMOVE = "ISMOVE"
 
 251   (* val liveness : pseudoasm -> livenesses
 
 252    * analyzes liveness of variables in the given pseudo-asm
 
 255   fun liveness instrs =
 
 257       val preds = defusesucc (number instrs)
 
 258 (*      val (_,l) = ListPair.unzip preds
 
 260         String.concatWith "\n" (
 
 262             (fn a => String.concatWith ", " (List.map dustostring a))
 
 266       val init = uselive preds
 
 267       val initmap = LiveMap.foldri (fn (n,a,b) => LiveMap.insert (b, n, a)) LiveMap.empty init
 
 269       (preds, liveiter initmap preds)
 
 272   fun prettyprint (set) =
 
 274       (fn (oper, s) => (X.pp_oper oper) ^ ", " ^ s)
 
 280       val maxln = LiveMap.foldri (fn (a, _, b) => Int.max (a, b)) 0 map
 
 281       val nums = List.tabulate (maxln+1, fn x => x)
 
 283       List.map (fn num => valOf (LiveMap.find (map, num)) handle Option => OperSet.empty) nums