Home My Page Projects Code Snippets Project Openings SML/NJ
Summary Activity Forums Tracker Lists Tasks Docs Surveys News SCM Files

SCM Repository

[smlnj] View of /sml/trunk/src/MLRISC/backpatch/spanDep.sml
ViewVC logotype

View of /sml/trunk/src/MLRISC/backpatch/spanDep.sml

Parent Directory Parent Directory | Revision Log Revision Log


Revision 244 - (download) (annotate)
Sat Apr 17 18:41:51 1999 UTC (20 years, 1 month ago) by monnier
File size: 14902 byte(s)
This commit was generated by cvs2svn to compensate for changes in r243,
which included commits to RCS files with non-trunk default branches.
(* 
 * This version of the span dependency resolution also fill delay slots
 * using a few simple strategies.
 * 
 * Allen
 *)

functor SpanDependencyResolution
    (structure Flowgraph : FLOWGRAPH
     structure Jumps : SDI_JUMPS
     structure Emitter : EMITTER_NEW
     structure DelaySlot : DELAY_SLOT_PROPERTIES
     structure Props : INSN_PROPERTIES
       sharing Emitter.P = Flowgraph.P
       sharing Flowgraph.I = Jumps.I = Emitter.I = DelaySlot.I = Props.I)
         : BBSCHED =
struct

  structure F = Flowgraph
  structure I = F.I
  structure C = I.C
  structure E = Emitter
  structure J = Jumps
  structure P = Flowgraph.P
  structure D = DelaySlot
  structure A = Array

  fun error msg = MLRiscErrorMsg.impossible ("SpanDependencyResolution."^msg)

  datatype code =
      SDI of {size : int ref,		(* variable sized *)
	      insn : I.instruction}
    | FIXED of {size: int,		(* size of fixed instructions *)
		insns: I.instruction list}
    | BRANCH of {insn : code list,      (* instruction with delay slot*)
                 branchSize : int,
                 fillSlot : bool ref} 
    | DELAYSLOT of {insn : code list,    (* instruction in delay slot *)
                    fillSlot : bool ref}
    | CANDIDATE of (* two alternatives *)
      { oldInsns  : code list, (* without delay slot filling *)
        newInsns  : code list, (* when delay slot is filled *)
        fillSlot  : bool ref   (* should we fill the delay slot? *)
      }
   
  datatype compressed = 
      PSEUDO of P.pseudo_op
    | LABEL  of Label.label
    | CODE of Label.label * code list
    | CLUSTER of {comp : compressed list, regmap : int Intmap.intmap}

  val clusterList : compressed list ref = ref []
  fun cleanUp() = clusterList := []

  fun bbsched(cluster as F.CLUSTER{blocks, regmap, blkCounter, ...}) = 
  let fun lookup r = Intmap.map regmap r handle _ => r

      fun blknumOf(F.BBLOCK{blknum,...}) = blknum
        | blknumOf(F.EXIT{blknum,...}) = blknum
        | blknumOf _ = error "blknumOf"

      fun noPseudo [] = true
        | noPseudo (F.BBLOCK _::_) = true
        | noPseudo (F.LABEL _::rest) = noPseudo rest
        | noPseudo (F.ORDERED l::rest) = noPseudo(l@rest)
        | noPseudo (F.PSEUDO _::_) = false

      (* Maps blknum -> label at the position of the second instruction *)
      val dummy = Label.newLabel ""
      val labelMap = A.array(!blkCounter,dummy)

      (* enter labels into the labelMap *)
      fun enterLabels([]) = ()
        | enterLabels(F.PSEUDO _::rest) = enterLabels rest
        | enterLabels(F.LABEL _::rest) = enterLabels rest
        | enterLabels(F.ORDERED blks::rest) = enterLabels(blks@rest)
        | enterLabels(F.BBLOCK{blknum,...}::rest) = 
             (A.update(labelMap,blknum,Label.newLabel ""); enterLabels rest)
        | enterLabels _ = error "enterLabels"

      (* 
       * Find the branch target of block blknum, return the first instruction
       * in the target block and its associated label. 
       *)
      fun findTarget(blknum,[F.BBLOCK{blknum=x,insns=insns1,...},
                             F.BBLOCK{blknum=y,insns=insns2,...}]) =
          let fun extract(blknum,[]) = NONE
                | extract(blknum,[_]) = NONE
                | extract(blknum,[_,_]) = NONE
                | extract(blknum,insns) = 
                     SOME(List.last insns,A.sub(labelMap,blknum))
          in  if x = blknum + 1 then extract(y,!insns2)
              else if y = blknum + 1 then extract(x,!insns1)
              else NONE 
          end
        | findTarget _ = NONE


      (* Convert a cluster into compressed form *)
      fun compress(F.PSEUDO pOp::rest) = PSEUDO pOp::compress rest
        | compress(F.LABEL lab::rest) = LABEL lab:: compress rest
        | compress(F.ORDERED blks::rest) = compress(blks@rest)
        | compress(F.BBLOCK{blknum,insns,succ,...}::rest) = 
	let 
            val backward = List.exists (fn b => blknumOf b <= blknum) (!succ) 

            (* build the code list *)
            fun scan([],nonSdiInstrs,nonSdiSize,code) = 
                   group(nonSdiSize,nonSdiInstrs,code)
              | scan(instr::instrs,nonSdiInstrs,nonSdiSize,code) =
                let val {n,nOn,nOff,nop} = D.delaySlot{instr=instr,backward=backward}
                in  case (nOff,instrs) of
                        (D.D_ALWAYS,delaySlot::rest) => 
                        if D.delaySlotCandidate{jmp=instr,
                                                delaySlot=delaySlot} andalso
                           not(D.conflict{regmap=lookup,src=delaySlot,dst=instr}) 
                        then scan(rest,[],0,
                                  mkCandidate1(instr,delaySlot)::
                                  group(nonSdiSize,nonSdiInstrs,code))
                        else scanSdi(instr,instrs,nonSdiInstrs,nonSdiSize,code)
                    |  _ =>  scanSdi(instr,instrs,nonSdiInstrs,nonSdiSize,code)
                end
            and scanSdi(instr,instrs,nonSdiInstrs,nonSdiSize,code) =
                let val s = J.minSize instr
                in  if J.isSdi instr then
                         scan(instrs,[],0,SDI{size=ref s,insn=instr}::
                              group(nonSdiSize,nonSdiInstrs,code))
                    else scan(instrs,instr::nonSdiInstrs,nonSdiSize+s,code)
                end
            and group(0,[],code) = code
	      | group(size,insns,code) = FIXED{size=size,insns=insns}::code

            and buildList instrs = scan'(instrs,[],0,[])

            and scan'([],nonSdiInstrs,nonSdiSize,code) = 
                   group(nonSdiSize,nonSdiInstrs,code)
              | scan'(instr::instrs,nonSdiInstrs,nonSdiSize,code) =
                let val s = J.minSize instr
                in  if J.isSdi instr then
                         scan'(instrs,[],0,SDI{size=ref s,insn=instr}::
                               group(nonSdiSize,nonSdiInstrs,code))
                    else scan'(instrs,instr::nonSdiInstrs,nonSdiSize+s,code)
                end

            (* 
             * Create a branch delay slot candidate sequence.
             * jmp is the normal jump instruction; jmp' is the
             * jump instruction when the delay slot is active.
             *)
            and mkCandidate1(jmp,delaySlot) = 
                let val fillSlot = ref true
                    val jmp' = D.enableDelaySlot{n=false,nop=false,instr=jmp}
                in  CANDIDATE{newInsns= 
                                [BRANCH{branchSize=J.minSize jmp',
                                        insn=buildList [jmp'],
                                        fillSlot=fillSlot},
                                 DELAYSLOT{insn=buildList [delaySlot],
                                           fillSlot=fillSlot}],
                              oldInsns=buildList [jmp,delaySlot],
                              fillSlot=fillSlot}
                end 

            (* 
             * Create a branch delay slot candidate sequence.
             * jmp is the normal jump instruction; jmp' is the
             * jump instruction when the delay slot is active.
             *)
            and mkCandidate2(jmp,delaySlot,label) = 
                let val fillSlot = ref true
                    val jmp' = D.setTarget(
                                D.enableDelaySlot{n=true,nop=false,instr=jmp},
                                label)
                in  CANDIDATE{newInsns= 
                                [BRANCH{branchSize=J.minSize jmp',
                                        insn=buildList [jmp'],
                                        fillSlot=fillSlot},
                                 DELAYSLOT{insn=buildList [delaySlot],
                                           fillSlot=fillSlot}],
                              oldInsns=buildList [jmp],
                              fillSlot=fillSlot}
                end 

            (*
             * Try different strategies for delay slot filling
             *)
            and fitDelaySlot(jmp,body,instrs) =
            let val {n,nOn,nOff,nop} = D.delaySlot{instr=jmp,backward=backward}
                (* 
                 * Use the previous instruction to fill the delay slot 
                 *)
                fun strategy1() =
                    case (nOff,body) of
                       (D.D_ALWAYS,delaySlot::body) => 
                        if not(D.delaySlotCandidate{jmp=jmp,
                                                   delaySlot=delaySlot}) orelse
                           D.conflict{regmap=lookup,src=delaySlot,dst=jmp} 
                        then strategy2()
                        else scan(body,[],0,[mkCandidate1(jmp,delaySlot)])
                    | _ => strategy2()
                (* 
                 * Use the first instruction in the target block to fill
                 * the delay slot 
                 *)
                and strategy2() =
                    case (nOn,findTarget(blknum,!succ)) of
                      (D.D_TAKEN,SOME(delaySlot,label)) => 
                        if not(D.delaySlotCandidate{jmp=jmp,
                                                   delaySlot=delaySlot}) orelse
                           D.conflict{regmap=lookup,src=delaySlot,dst=jmp}
                        then strategy3()
                        else scan(body,[],0,[mkCandidate2(jmp,delaySlot,label)])
                    | _ => strategy3()
                (*
                 * No delay slot filling
                 *)
                and strategy3() = scan(instrs,[],0,[])
            in  strategy1()
            end

            (*
             * Try to remove the branch if it is unnecessary 
             *)
            and processBranch(jmp,body,instrs) =
                  case (!succ, noPseudo rest) of
                     ([F.BBLOCK{blknum=id,...}],true) =>
                        if id = blknum + 1 then scan(body,[],0,[])
                        else fitDelaySlot(jmp,body,instrs)
                  |  _ => fitDelaySlot(jmp,body,instrs)

            and process([],others) = others
              | process(instrs as jmp::body,others) =
                CODE(A.sub(labelMap,blknum),
                     case Props.instrKind jmp of
                       Props.IK_JUMP => processBranch(jmp,body,instrs)
                     | _ => scan(instrs,[],0,[])
                    )::others
	in 
	    process(!insns,compress rest)
	end
      | compress [] = []
  in  enterLabels blocks;
      clusterList:=CLUSTER{comp = compress blocks, regmap=regmap}:: 
		    (!clusterList)
  end

  fun finish() = let
    fun labels(PSEUDO pOp::rest, pos) = 
          (P.adjustLabels(pOp, pos); labels(rest, pos+P.sizeOf(pOp,pos)))
      | labels(LABEL lab::rest, pos) = 
	 (Label.setAddr(lab,pos); labels(rest, pos))
      | labels(CODE(lab,code)::rest, pos) = let
	  fun size(FIXED{size, ...}) = size
	    | size(SDI{size, ...}) = !size
            | size(BRANCH{insn,...}) = sizeList(insn,0)
            | size(DELAYSLOT{insn,...}) = sizeList(insn,0)
            | size(CANDIDATE{oldInsns,newInsns,fillSlot,...}) =
                sizeList(if !fillSlot then newInsns else oldInsns,0)
          and sizeList([],n) = n
            | sizeList(code::rest,n) = sizeList(rest,size code + n)
	in  Label.setAddr(lab,pos+4);
            labels(rest, sizeList(code,pos))
	end
      | labels(CLUSTER{comp, ...}::rest, pos) = labels(rest, labels(comp,pos))
      | labels([], pos) = pos

    val delaySlotSize = D.delaySlotSize

    fun adjust(CLUSTER{comp, regmap}::cluster, pos, changed) = 
    let fun scan(PSEUDO pOp::rest, pos, changed) = 
              scan(rest, pos+P.sizeOf(pOp,pos), changed)
	  | scan(LABEL _::rest, pos, changed) = scan(rest, pos, changed)
	  | scan(CODE(_,code)::rest, pos, changed) = 
              let val (pos,changed) = doCode(code,pos,changed)
              in  scan(rest,pos,changed) end
	  | scan([], pos, changed) = adjust(cluster, pos, changed)
        and doCode([],pos,changed) = (pos,changed)
          | doCode(code::rest,pos,changed) =
            case code of
              FIXED{size,...} => doCode(rest,pos+size,changed)
            | SDI{size, insn} =>
              let val newSize = J.sdiSize(insn, regmap, Label.addrOf, pos)
 	      in  if newSize <= !size then 
                     doCode(rest,!size + pos,changed)
		  else (size:=newSize; doCode(rest, newSize+pos, true))
              end
            | DELAYSLOT{insn,fillSlot,...} => 
                let val (newPos,changed) = doCode(insn,pos,changed)
                in  doCode(rest, newPos,
                           if newPos - pos <> delaySlotSize then 
                           (fillSlot := false; true) else changed)
                end
            | BRANCH{insn,branchSize,fillSlot,...} => 
                let val (newPos,changed) = doCode(insn,pos,changed)
                in  doCode(rest, newPos,
                           if newPos - pos <> branchSize then
                           (fillSlot := false; true) else changed)
                end
            | CANDIDATE{oldInsns,newInsns,fillSlot,...} =>
                doCode((if !fillSlot then newInsns else oldInsns) @ rest,
                       pos,changed)
    in  scan(comp, pos, changed)
    end
      | adjust(_::_, _, _) = error "adjust"
      | adjust([], _, changed) = changed

    fun fixpoint zl = let 
      val size = labels(zl, 0)
    in if adjust(zl, 0, false) then fixpoint zl else size
    end

    fun emitCluster(CLUSTER{comp, regmap}, loc) = let
      fun emit(PSEUDO pOp, loc) = (E.pseudoOp pOp; loc+P.sizeOf(pOp, loc))
	| emit(LABEL lab, loc) = (E.defineLabel lab; loc)
	| emit(CODE(_,code), loc) = let
	    val emitInstrs = app (fn i => E.emitInstr(i, regmap)) 
	    fun e(FIXED{insns, size, ...}, loc) = (emitInstrs insns; loc+size)
	      | e(SDI{size, insn}, loc) = 
	         (emitInstrs(J.expand(insn, !size, loc)); !size+loc)
              | e(BRANCH{insn,...}, loc) =  List.foldl e loc insn
              | e(DELAYSLOT{insn,...}, loc) = List.foldl e loc insn
              | e(CANDIDATE{newInsns,oldInsns,fillSlot,...}, loc) =
		 List.foldl e loc (if !fillSlot then  newInsns else oldInsns)
	  in List.foldl e loc code
	  end
    in List.foldl emit loc comp
    end

    val compressed = (rev (!clusterList)) before cleanUp()
  in
    E.init(fixpoint compressed);
    List.foldl emitCluster 0 compressed handle e => raise e;
    ()
  end (*finish*)

end (* spanDep.sml *)

(*
 * $Log: spanDep.sml,v $
 * Revision 1.1.1.1  1998/11/16 21:47:14  george
 *   Version 110.10
 *
 * Revision 1.3  1998/10/06 14:07:49  george
 * Flowgraph has been removed from modules that do not need it.
 * Changes to compiler/CodeGen/*/*{MLTree,CG}.sml necessary.
 * 						[leunga]
 *
 * Revision 1.2  1998/08/12 13:36:09  leunga
 *   Fixed the 2.0 + 2.0 == nan bug by treating FCMP as instrs with delay slots
 *
 * Revision 1.1  1998/08/05 19:47:21  george
 *   Changes to support the SPARC back end
 *
 *)

root@smlnj-gforge.cs.uchicago.edu
ViewVC Help
Powered by ViewVC 1.0.0