Annotation of researchv10no/cmd/sml/src/coder/coder.sml, revision 1.1.1.1

1.1       root        1: (* Copyright 1989 by AT&T Bell Laboratories *)
                      2: (* coder.sml
                      3:  *
                      4:  * J.H. Reppy
                      5:  * Cornell University
                      6:  * Ithaca, NY 14853
                      7:  * [email protected]
                      8:  *
                      9:  * HISTORY:
                     10:  *   11/20/89  created
                     11:  *
                     12:  * This is a machine independent code scheduler for RISC machines with 32-bit
                     13:  * instructions.  We assume that the machine has delayed branches.
                     14:  *)
                     15: 
                     16: signature CODER =
                     17: sig
                     18:     eqtype label sharing type label = BaseCoder.label
                     19:     type instruction
                     20:     type sdi
                     21: 
                     22:     val baseLab : label   (* The symbolic base address of the current code block. *)
                     23: 
                     24:     val newLabel : unit -> label
                     25:     val define : label -> unit
                     26: 
                     27:     val emitLong : int -> unit
                     28:     val emitString : string -> unit
                     29:     val emitReal : string -> unit
                     30:     val emitLabel : (label * int) -> unit
                     31:        (* L3: emitLabel(L2, k) is equivalent to L3: emitLong(k+L2-L3) *)
                     32: 
                     33:     val mark : unit -> unit
                     34: 
                     35:     val emit : instruction -> unit
                     36:     val delay : instruction -> unit
                     37:     val emitSDI : sdi -> unit
                     38: 
                     39:     val comment : string -> unit
                     40: 
                     41:     val finish : unit -> unit
                     42: 
                     43: end (* signature CODER *)
                     44: 
                     45: functor Coder (
                     46:   structure M : MACHINSTR and E : EMITTER
                     47:   sharing type M.instruction = E.instruction
                     48:       and type M.label = E.label) : CODER =
                     49: struct
                     50: 
                     51:     open BaseCoder M
                     52: 
                     53:     datatype sdi_nd = SDI_ND of {
                     54:        instr : sdi,
                     55:        size : int ref
                     56:       }
                     57: 
                     58:     datatype data
                     59:       = LABEL of label
                     60:       | MARK
                     61:       | LONGconst of int
                     62:       | STRINGconst of string
                     63:       | REALconst of string
                     64:       | ADDRconst of (label * int)
                     65: 
                     66:     datatype blk_list
                     67:       = CODEBLK of (instruction list * blk_list)
                     68:       | SDI of (sdi_nd * blk_list)
                     69:       | DATABLK of (data list * blk_list)
                     70:       | NILBLK
                     71: 
                     72:     fun revCode l = let
                     73:          fun rev (NILBLK, l) = l
                     74:            | rev (CODEBLK(x, rest), l) = rev(rest, CODEBLK(x, l))
                     75:            | rev (SDI(x, rest), l) = rev(rest, SDI(x, l))
                     76:            | rev (DATABLK(x, rest), l) = rev(rest, DATABLK(x, l))
                     77:          in
                     78:            rev (l, NILBLK)
                     79:          end
                     80: 
                     81:     datatype codept
                     82:       = NILpt
                     83:       | LABELpt of (label * codept)
                     84:       | SDIpt of (sdi_nd * codept)
                     85: 
                     86:     val baseLab = newLabel()  (* The base address of the current code block. *)
                     87: 
                     88:     val codeList = ref (DATABLK([LABEL baseLab], NILBLK))
                     89:     val codePtList = ref NILpt
                     90:     val codeLen = ref 0
                     91:     val numSlots = ref 0
                     92:     val numNops = ref 0
                     93: 
                     94:     fun emitCode I = (codeList :=
                     95:          case !codeList
                     96:           of (CODEBLK(cl, rest)) => CODEBLK(I::cl, rest)
                     97:            | lst => CODEBLK([I], lst))
                     98: 
                     99:   (* Insert an instruction/nop pair into the code list.  If the instruction is a jump,
                    100:    * then start a DATABLK to insure that the jump is the end of a code block. *)
                    101:     fun emitDelay I = let
                    102:          val clst = case !codeList
                    103:               of (CODEBLK(cl, rest)) => CODEBLK(nop::I::cl, rest)
                    104:                | lst => CODEBLK([nop, I], lst)
                    105:          in
                    106:            codeList :=
                    107:              case (instrKind I) of IK_JUMP => DATABLK(nil, clst) | _ => clst
                    108:          end
                    109: 
                    110:     fun emitData D = (codeList :=
                    111:          case !codeList
                    112:           of (DATABLK(dl, rest)) => DATABLK(D::dl, rest)
                    113:            | lst => DATABLK([D], lst))
                    114: 
                    115:     fun reset () = (
                    116:          codeList := DATABLK([LABEL baseLab], NILBLK);
                    117:          codePtList := NILpt; codeLen := 0;
                    118:          numSlots := 0; numNops := 0)
                    119: 
                    120:     fun padString s = (case ((size s) mod 4)
                    121:           of 0 => s
                    122:            | 1 => (s ^ "\000\000\000")
                    123:            | 2 => (s ^ "\000\000")
                    124:            | 3 => (s ^ "\000"))
                    125: 
                    126:     fun emitLong i = (
                    127:          emitData (LONGconst i);
                    128:          codeLen := !codeLen + 4)
                    129: 
                    130:     fun emitString s = let
                    131:          val s' = padString s
                    132:          in
                    133:            emitData (STRINGconst s');
                    134:            codeLen := !codeLen + (size s')
                    135:          end
                    136: 
                    137:     fun emitReal r = (
                    138:          emitData (REALconst r);
                    139:          codeLen := !codeLen + 8)
                    140: 
                    141:     fun emitLabel args = (
                    142:          emitData (ADDRconst args);
                    143:          codeLen := !codeLen + 4)
                    144: 
                    145:     fun define (l as Label{addr, ...}) = (
                    146:          addr := !codeLen;
                    147:          codePtList := LABELpt(l, !codePtList);
                    148:          emitData (LABEL l))
                    149: 
                    150:     fun mark () = (emitData MARK; codeLen := !codeLen + 4)
                    151: 
                    152:     fun emit I = (emitCode I; codeLen := !codeLen + 4)
                    153:     fun delay I = (emitDelay I; codeLen := !codeLen + 8)
                    154: 
                    155:     fun emitSDI I = let
                    156:          val minSz = minSize I
                    157:          val nd = SDI_ND{instr = I, size = ref minSz}
                    158:          in
                    159:            codeList := SDI(nd, !codeList);
                    160:            codePtList := SDIpt(nd, !codePtList);
                    161:            codeLen := !codeLen + minSz
                    162:          end
                    163: 
                    164:     val comment = E.comment
                    165: 
                    166: 
                    167:     fun computeSizes () = let
                    168:          fun reverse l = let  (* reverse l and remove leading labels *)
                    169:                fun clean (LABELpt(_, rest)) = clean rest
                    170:                  | clean l = l
                    171:                fun rev (NILpt, l) = clean l
                    172:                  | rev (LABELpt(lab, rest), l) = rev(rest, LABELpt(lab, l))
                    173:                  | rev (SDIpt(lab, rest), l) = rev(rest, SDIpt(lab, l))
                    174:                in
                    175:                  rev (l, NILpt)
                    176:                end
                    177:          fun deltaSize (SDI_ND{instr, size}) = let
                    178:                val (isMax, newSz) = sizeOf instr
                    179:                val dsz = newSz - (!size)
                    180:                in
                    181:                  if (dsz > 0)
                    182:                    then (size := newSz; (isMax, dsz))
                    183:                    else (isMax, 0)
                    184:                end
                    185:          fun adjust (NILpt, 0, _) = ()
                    186:            | adjust (NILpt, delta, l) = (
                    187:                codeLen := !codeLen + delta;
                    188:                adjust (reverse l, 0, NILpt))
                    189:            | adjust (LABELpt(lab as Label{addr, ...}, rest), delta, l) = (
                    190:                addr := !addr + delta;
                    191:                adjust(rest, delta, LABELpt(lab, l)))
                    192:            | adjust (SDIpt(sdi, rest), delta, l) = (
                    193:                case (deltaSize sdi)
                    194:                 of (true, dsz) => adjust(rest, delta+dsz, l)
                    195:                  | (false, dsz) => adjust(rest, delta+dsz, SDIpt(sdi, l)))
                    196:            val codePts = reverse(!codePtList)
                    197:          in
                    198:            codePtList := NILpt;
                    199:            adjust (codePts, 0, NILpt)
                    200:          end (* computeSizes *)
                    201: 
                    202: 
                    203:   (** Instruction scheduling and machine code emission **)
                    204: 
                    205:     datatype instr_nd         (* Nodes in the resource dependency graph *)
                    206:       = IND of {
                    207:        id : int,               (* unique id for equality testing *)
                    208:        instr : instruction,    (* The instruction *)
                    209:        nsuccs : int,           (* The number of successors *)
                    210:        succs : instr_nd list,
                    211:        succlock : bool,        (* If this instruction has an interlock with one of *)
                    212:                                (* its successors, then this is true. *)
                    213:        maxpathlen : int,       (* The length of the longest path to a leaf. *)
                    214:        npreds : int ref        (* The number of predecessors.  This is incremented *)
                    215:                                (* when building the graph, and decremented as *)
                    216:                                (* each predecessor is scheduled. *)
                    217:       }
                    218: 
                    219:     fun member (IND{id = x, ...}, lst) = let
                    220:          fun mem nil = false
                    221:            | mem (IND{id = y, ...}::rest) = ((x = y) orelse (mem rest))
                    222:          in
                    223:            mem lst
                    224:          end
                    225: 
                    226:     fun merge (nil, lst) = lst
                    227:       | merge (nd :: rest, lst) = if (member(nd, lst))
                    228:          then merge (rest, lst)
                    229:          else merge (rest, nd :: lst)
                    230: 
                    231:     fun incPreds nil = ()
                    232:       | incPreds (IND{npreds, ...} :: rest) = (npreds := !npreds + 1; incPreds rest)
                    233: 
                    234:   (* Order a pair of instructions *)
                    235:     fun orderInstrPair (nd1 as IND a, nd2 as IND b) =
                    236:          if ((#succlock a) = (#succlock b))
                    237:            then let val n1 = (#nsuccs a) and n2 = (#nsuccs b)
                    238:              in
                    239:                if (n1 = n2)
                    240:                  then let val p1 = (#maxpathlen a) and p2 = (#maxpathlen b)
                    241:                    in
                    242:                      if ((p1 > p2) orelse ((p1 = p2) andalso ((#id a) > (#id b))))
                    243:                        then (nd1, nd2)
                    244:                        else (nd2, nd1)
                    245:                    end
                    246:                  else if (n1 > n2)
                    247:                    then (nd1, nd2)
                    248:                    else (nd2, nd1)
                    249: (********************************
                    250:                if ((n1 > n2)
                    251:                orelse ((n1 = n2) andalso ((#maxpathlen a) >= (#maxpathlen b))))
                    252:                  then (nd1, nd2)
                    253:                  else (nd2, nd1)
                    254: ********************************)
                    255:              end
                    256:            else if (#succlock a)
                    257:              then (nd1, nd2)
                    258:              else (nd2, nd1)
                    259: 
                    260:   (* Schedule and emit the instructions of a straight-line block of code. *)    
                    261:     fun schedBlock (exitInstr, blks) = let
                    262:          val exitDep = case exitInstr
                    263:                 of NONE => (fn _ => false)
                    264:                  | (SOME e) => let
                    265:                      val (exitUses, exitDefs) = rUseDef e
                    266:                      val f = exists (fn r => (exists (fn x => (r = x)) exitUses))
                    267:                      val g = exists (fn r => (exists (fn x => (r = x)) exitDefs))
                    268:                      in
                    269:                        fn I => let
                    270:                              val (u, d) = rUseDef I
                    271:                              in
                    272:                                (f d) orelse (g d) orelse (g u)
                    273:                              end
                    274:                      end
                    275:        (* make a new instr_nd *)
                    276:          fun mkINd (n, I, nil) =
                    277:                IND{id = n, instr = I,
                    278:                  nsuccs = 0, succs = nil, succlock = exitDep I,
                    279:                  maxpathlen = 0, npreds = ref 0}
                    280:            | mkINd (n, I, succLst) = let
                    281:                fun f (nil, len, lock, mpl) = (len, lock, mpl)
                    282:                  | f (IND{instr, maxpathlen, ...} :: rest, len, lock, mpl) =
                    283:                      f (rest, len+1, hazard (I, instr),
                    284:                        if (maxpathlen > mpl) then maxpathlen else mpl)
                    285:                val (len, lock, mpl) = f (succLst, 0, false, 0)
                    286:                in
                    287:                  IND{id = n, instr = I,
                    288:                    nsuccs = len, succs = succLst, succlock = lock,
                    289:                    maxpathlen = mpl+1, npreds = ref 0}
                    290:                end
                    291:        (* resource use/def vectors *)
                    292:          val lastUse = array (numResources, nil)
                    293:          val lastDef = array (numResources, nil)
                    294:        (* find resource dependencies *)
                    295:          fun findDeps rsrc = let
                    296:                fun add (nil, lst) = lst
                    297:                  | add (r :: rest, lst) = add (rest, merge(rsrc sub r, lst))
                    298:                in
                    299:                  add
                    300:                end
                    301:          val findUseDeps = findDeps lastUse
                    302:          val findDefDeps = findDeps lastDef
                    303:        (* update resource use/def vectors *)
                    304:          fun updateUseDefs nd = let
                    305:                val ndl = [nd]
                    306:                val updateUses =
                    307:                      app (fn r => update(lastUse, r, nd::(lastUse sub r)))
                    308:                val updateDefs =
                    309:                      app (fn r => (update(lastDef, r, ndl); update(lastUse, r, nil)))
                    310:                in
                    311:                  fn (ruses, rdefs) => (updateDefs rdefs; updateUses ruses)
                    312:                end
                    313:        (* extract the dependency graph roots from the use/def vectors *)
                    314:          fun roots () = let
                    315:                fun isRoot (IND{npreds, ...}) = (!npreds = 0)
                    316:                fun rootsOf (nil, lst) = lst
                    317:                  | rootsOf (nd::rest, lst) = if (isRoot nd)
                    318:                      then rootsOf (rest, nd::lst)
                    319:                      else rootsOf (rest, lst)
                    320:                fun mergeRoots (~1, lst) = lst
                    321:                  | mergeRoots (i, lst) = let
                    322:                      val rlst = rootsOf (merge (lastDef sub i, lastUse sub i), nil)
                    323:                      in
                    324:                        mergeRoots (i-1, merge (rlst, lst))
                    325:                      end
                    326:                in
                    327:                    mergeRoots (numResources-1, nil)
                    328:                end
                    329:        (* Build the dependency graph for a list of instructions, returning the list
                    330:         * of roots (instructions without predecessors). *)
                    331:          fun buildDepGraph blkList = let
                    332:                fun doInstrs (nil, n) = n
                    333:                  | doInstrs (I :: rest, n) = (
                    334:                      case (instrKind I)
                    335:                       of IK_NOP => (numSlots := !numSlots + 1)
                    336:                        | IK_INSTR => let
                    337:                            val (ruses, rdefs) = rUseDef I
                    338:                          (* find use/def, def/use and def/def dependencies *)
                    339:                            val succLst = findUseDeps (rdefs,
                    340:                                  findDefDeps (rdefs, findDefDeps (ruses, nil)))
                    341:                            val nd = mkINd (n, I, succLst)
                    342:                            in
                    343:                              incPreds succLst;
                    344:                              updateUseDefs nd (ruses, rdefs)
                    345:                            end
                    346:                        | IK_JUMP => (
                    347:                            ErrorMsg.impossible "[Coder.doInstrs: unexpected jump]")
                    348:                      (* end case *);
                    349:                      doInstrs (rest, n+1))
                    350:                fun build (NILBLK, _) = ()
                    351:                  | build (CODEBLK(instrs, rest), n) =
                    352:                      build (rest, doInstrs (instrs, n))
                    353:                  | build _ = ErrorMsg.impossible "[Coder.build: bad block]"
                    354:                in
                    355:                  build (blkList, 0)
                    356:                end (* buildDepGraph *)
                    357: 
                    358:        (* Choose the next instruction from a list of candidates.  Instructions that
                    359:         * don't interlock with the previously scheduled instruction are given
                    360:         * priority. *)
                    361:          fun chooseNextInstr (prev, (x :: rest)) = let
                    362:                val prevLock = case prev
                    363:                     of (NONE) => (fn _ => false)
                    364:                      | (SOME prev) => (fn (IND{instr, ...}) => hazard(prev, instr))
                    365:              (* choose1 & choose2 find the best instruction to schedule next.
                    366:               * choose1 is used as long as the current choice interlocks with prev,
                    367:               * choose2 is used after a non-interlocking choice is found. *)
                    368:                fun choose1 (choice, done, nil) = (choice, done)
                    369:                  | choose1 (choice, done, nd::rest) = if (prevLock nd)
                    370:                      then let
                    371:                        val (a, b) = orderInstrPair (choice, nd)
                    372:                        in
                    373:                          choose1 (a, b::done, rest)
                    374:                        end
                    375:                      else choose2 (nd, choice::done, rest)
                    376:                and choose2 (choice, done, nil) = (choice, done)
                    377:                  | choose2 (choice, done, nd::rest) = if (prevLock nd)
                    378:                      then choose2 (choice, nd::done, rest)
                    379:                      else let
                    380:                        val (a, b) = orderInstrPair (choice, nd)
                    381:                        in
                    382:                          choose2 (a, b::done, rest)
                    383:                        end
                    384:                val (IND{succs, instr, ...}, remainder) = if (prevLock x)
                    385:                      then choose1 (x, nil, rest)
                    386:                      else choose2 (x, nil, rest)
                    387:                fun addSuccs (nil, candidates) = candidates
                    388:                  | addSuccs ((nd as IND{npreds, ...}) :: rest, candidates) = let
                    389:                      val n = !npreds
                    390:                      in
                    391:                        npreds := n-1;
                    392:                        if (n = 1)
                    393:                          then addSuccs(rest, nd::candidates)
                    394:                          else addSuccs(rest, candidates)
                    395:                      end
                    396:                in
                    397:                  (instr, addSuccs(succs, remainder))
                    398:                end
                    399:            | chooseNextInstr _ = (ErrorMsg.impossible "[Coder.chooseNextInstr]")
                    400: 
                    401:        (* assign an order to the instructions, based on the dependency graph. *)
                    402:          fun assignOrder () = let
                    403:                fun emitNop () = (numNops := !numNops + 1; nop)
                    404:                fun checkLock (i1, i2, cl) = if (needsNop(i1, i2))
                    405:                      then (numNops := !numNops + 1; nop :: cl)
                    406:                      else cl
                    407:                fun order (NONE, nil, _) = let
                    408:                      val (SOME e) = exitInstr
                    409:                      in
                    410:                        numNops := !numNops + 1;
                    411:                        [nop, e]
                    412:                      end
                    413:                  | order (SOME prev, nil, cl) = (
                    414:                      case exitInstr
                    415:                       of NONE => (prev :: cl)
                    416:                        | (SOME e) => (
                    417:                            if (exitDep prev)
                    418:                              then (
                    419:                                numNops := !numNops + 1;
                    420:                                nop :: e :: checkLock(prev, e, prev :: cl))
                    421:                              else (prev :: e :: cl))
                    422:                      (* end case *))
                    423:                  | order (prev, rest, cl) = let
                    424:                      val (next, remainder) = chooseNextInstr (prev, rest)
                    425:                      val newCL = case prev
                    426:                           of (SOME x) => checkLock(x, next, (x :: cl))
                    427:                            | NONE => cl
                    428:                      in
                    429:                        order (SOME next, remainder, newCL)
                    430:                      end
                    431:                in
                    432:                  rev (order(NONE, roots(), nil))
                    433:                end (* assignOrder *)
                    434:          in
                    435:            buildDepGraph blks;
                    436:            assignOrder ()
                    437:          end (* schedBlock *)
                    438: 
                    439:     fun sched (NILBLK, blst) = blst
                    440:       | sched (DATABLK(dl, rest), blst) = let
                    441:          fun adjust (nil, dl) = dl
                    442:            | adjust ((lab as LABEL(Label{addr, ...})) :: rest, dl) = (
                    443:                addr := !addr - 4*(!numSlots - !numNops);
                    444:                adjust (rest, lab :: dl))
                    445:            | adjust (d :: rest, dl) = adjust(rest, d :: dl)
                    446:          in
                    447:            sched (rest, DATABLK(adjust (dl, nil), blst))
                    448:          end
                    449:       | sched (arg, blst) = let
                    450:          fun insertCode (nil, nil, bl) = bl
                    451:            | insertCode (nil, cl, bl) = CODEBLK(cl, bl)
                    452:            | insertCode (I::rest, cl, bl) = (
                    453:                case (instrKind I)
                    454:                 of IK_JUMP =>
                    455:                      insertCode ((tl rest), nil, DATABLK(nil, CODEBLK(nop::I::cl, bl)))
                    456:                  | _ => insertCode (rest, I::cl, bl))
                    457:          fun findBlk (CODEBLK(cl, rest), lst) = findBlk(rest, CODEBLK(cl, lst))
                    458:            | findBlk (SDI(SDI_ND{instr, size}, rest), lst) =
                    459:                findBlk (insertCode(expand (instr, !size), nil, rest), lst)
                    460:            | findBlk (rest, bl) = (rest, bl)
                    461:          val (rest, b as CODEBLK(cl, bl)) = findBlk (arg, NILBLK)
                    462:          val newCL = (case cl
                    463:                 of (i1 :: i2 :: instrs) => (case (instrKind i1, instrKind i2)
                    464:                     of (IK_NOP, IK_JUMP) => (
                    465:                          numSlots := !numSlots + 1;
                    466:                          schedBlock (SOME i2, CODEBLK(instrs, bl)))
                    467:                      | _ => schedBlock (NONE, b))
                    468:                  | _ => schedBlock (NONE, b))
                    469:          in
                    470:            sched (rest, CODEBLK(newCL, blst))
                    471:          end
                    472: 
                    473:   (* reverse the code list, while expanding SDIs and reversing instruction lists.
                    474:    * This pass is the alternative to the scheduling pass. *)
                    475:     fun noSched (NILBLK, bl) = bl
                    476:       | noSched (CODEBLK(cl, rest), bl) = noSched (rest, CODEBLK(rev cl, bl))
                    477:       | noSched (SDI(SDI_ND{instr, size}, rest), bl) =
                    478:          noSched (rest, CODEBLK(expand(instr, !size), bl))
                    479:       | noSched (DATABLK(dl, rest), bl) = noSched (rest, DATABLK(rev dl, bl))
                    480: 
                    481:     fun finish () = let
                    482:          val emitInstrs = app E.emitInstr
                    483:          fun emitDataList nil = ()
                    484:            | emitDataList (d :: rest) = (case d
                    485:                 of (LABEL lab) => E.define lab
                    486:                  | MARK => E.mark ()
                    487:                  | (LONGconst n) => E.emitLong n
                    488:                  | (STRINGconst s) => E.emitString s
                    489:                  | (REALconst r) => E.emitReal r
                    490:                  | (ADDRconst args) => E.emitAddr args
                    491:                (* end case *);
                    492:                emitDataList rest)
                    493:          fun emitBlk NILBLK = ()
                    494:            | emitBlk (CODEBLK(cl, rest)) = (emitInstrs cl; emitBlk rest)
                    495:            | emitBlk (DATABLK(dl, rest)) = (emitDataList dl; emitBlk rest)
                    496:            | emitBlk _ = (ErrorMsg.impossible "[Coder.finish.emitBlk]")
                    497:          fun schedule cl = if (!System.Control.CG.scheduling)
                    498:                then revCode (sched (revCode cl, NILBLK))
                    499:                else noSched (cl, NILBLK)
                    500:          val _ = computeSizes ()
                    501:          val newCL = schedule (!codeList before (codeList := NILBLK))
                    502:          in
                    503:            E.init (!codeLen - 4*(!numSlots - !numNops));
                    504:            emitBlk newCL;
                    505:            reset()
                    506:          end (* finish *)
                    507: 
                    508: end (* Coder *)

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.