File:  [Research Unix] / researchv10no / cmd / sml / src / sparc / sparc.sml
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 17:21:34 2018 UTC (8 years, 1 month ago) by root
Branches: belllabs, MAIN
CVS tags: researchv10, HEAD
researchv10 Norman

(* Copyright 1989 by AT&T Bell Laboratories *)
(* sparc.sml
 *
 * J.H. Reppy
 * Cornell University
 * Ithaca, NY 14853
 * [email protected]
 *
 * HISTORY:
 *   11/20/89  created
 *)

functor SparcCM (
  structure C : CODER
  sharing type C.instruction = SparcInstr.instruction
      and type C.sdi = SparcInstr.sdi
      and type C.label = SparcInstr.label) : CMACHINE =
struct

    structure C' : sig
	eqtype label
	val newLabel : unit -> label
	val emitLong : int -> unit
	val emitString : string -> unit
	val emitReal : string -> unit
	val emitLabel : (label * int) -> unit
	val mark : unit -> unit
	val comment : string -> unit
    end = C
    open C'

    structure S' : sig
	eqtype label
	datatype register = REG of int
	datatype fregister = FREG of int
	datatype labelexp
	  = LABELexp of {           (* An offset relative to a label.  The value of a *)
	      base : label,         (* label expression is ((dst - base) + offset). *)
	      dst : label,
	      offset : int
	    }
	datatype operand
	  = REGrand of register     (* A register value *)
	  | IMrand of int           (* A small integer constant (13 bits) *)
	  | LABrand of labelexp     (* A small valued label expression (13 bits) *)
	  | HIrand of labelexp      (* The high 22 bits of a label expression *)
	  | LOrand of labelexp      (* The low 10 bits of a label expression *)
	datatype condition = EQL | NEQ | GTR | GEQ | LSS | LEQ
      end = SparcInstr
    open S'

    val zeroR = REG 0                       (* %g0 *)
    val zeroRand = REGrand zeroR

    local

      fun emit_ld args = C.emit (SparcInstr.I_ld args)
      fun emit_ldb args = C.emit (SparcInstr.I_ldb args)
      fun emit_ldf args = C.emit (SparcInstr.I_ldf args)
      fun emit_st args = C.emit (SparcInstr.I_st args)
      fun emit_stb args = C.emit (SparcInstr.I_stb args)
      fun emit_stf args = C.emit (SparcInstr.I_stf args)
      fun emit_sethi args = C.emit (SparcInstr.I_sethi args)
      fun emit_ba args = C.delay (SparcInstr.I_ba args)
      fun emit_bcc args = C.delay (SparcInstr.I_bcc args)
      fun emit_fbcc args = C.delay (SparcInstr.I_fbcc args)
      fun emit_jmpl args = C.delay (SparcInstr.I_jmpl args)
      fun emit_jmp (r, offset) = C.delay (SparcInstr.I_jmpl(r, offset, zeroR))
      fun emit_add args = C.emit (SparcInstr.I_add args)
      fun emit_addcc args = C.emit (SparcInstr.I_addcc args)
      fun emit_taddcctv args = C.emit (SparcInstr.I_taddcctv args)
      fun emit_sub args = C.emit (SparcInstr.I_sub args)
      fun emit_subcc args = C.emit (SparcInstr.I_subcc args)
      fun emit_sra args = C.emit (SparcInstr.I_sra args)
      fun emit_sll args = C.emit (SparcInstr.I_sll args)
      fun emit_and args = C.emit (SparcInstr.I_and args)
      fun emit_andcc args = C.emit (SparcInstr.I_andcc args)
      fun emit_or args = C.emit (SparcInstr.I_or args)
      fun emit_xor args = C.emit (SparcInstr.I_xor args)
      fun emit_not args = C.emit (SparcInstr.I_not args)
      fun emit_tvs () = C.emit SparcInstr.I_tvs
      fun emit_fadd args = C.emit (SparcInstr.I_fadd args)
      fun emit_fsub args = C.emit (SparcInstr.I_fsub args)
      fun emit_fmul args = C.emit (SparcInstr.I_fmul args)
      fun emit_fdiv args = C.emit (SparcInstr.I_fdiv args)
      fun emit_fneg args = C.emit (SparcInstr.I_fneg args)
      fun emit_fcmp args = C.delay (SparcInstr.I_fcmp args)

      local
	fun mkLabExp (lab, n) = LABELexp{base= C.baseLab, dst= lab, offset= (n-4096)}
      in

      fun setBaseAddr (contReg, lab, tmpR) = C.emitSDI (
	    SparcInstr.SetBaseAddr(ref true, contReg, mkLabExp(lab, 0), tmpR))

      fun loadAddr (lab, n, dst, tmpR) = C.emitSDI (
	    SparcInstr.LoadAddr(mkLabExp(lab, n), dst, tmpR))

      fun load (lab, n, dst, tmpR) = C.emitSDI (
	    SparcInstr.Load(mkLabExp(lab, n), dst, tmpR))

      fun loadF (lab, n, dst, tmpR) = C.emitSDI (
	    SparcInstr.LoadF(mkLabExp(lab, n), dst, tmpR))

      end (* local *)

    in

    datatype EA
      = Immed of int
      | ImmedLab of label
      | Direct of register

    val immed = Immed
    fun isimmed (Immed n) = SOME n | isimmed _ = NONE
    fun isreg (Direct(REG i)) = SOME i | isreg _ = NONE
    fun eqreg (a : EA) b = (a = b)

  (** Dedicated registers **)
    val exnptr = Direct(REG 7)              (* %g7 *)
    val storeptr = Direct(REG 5)            (* %g5 *)
    val arithtemp = Direct(REG 8)           (* %o0 *)
    val arithtemp2 = Direct(REG 9)          (* %o1 *)
    val standardclosure = Direct(REG 26)    (* %i2 *)
    val standardarg = Direct(REG 24)        (* %i0 *)
    val standardcont = Direct(REG 25)       (* %i1 *)
    val miscregs = map (Direct o REG) [     (* %g1-%g3, %l0-%l7, %i4-%i5 *)
	  1, 2, 3, 16, 17, 18, 19, 20, 21, 22, 23, 28, 29
	  ]

    val dataptrR = REG 6                    (* %g6 *)
    val limitptrR = REG 4                   (* %g4 *)
    val limitptrRand = REGrand limitptrR
    val arithtempRand = REGrand(REG 8)
    val spR = REG 14                        (* %sp (%o6) *)
    val linkR = REG 15                      (* %o7, link register *)

  (** Temporary registers **
   * We use registers %o2-%o5 as temporaries.  They are used in a round-robin
   * order to facilitate instruction scheduling.
   *)
    local
      val rear = ref 0 and queue = ref 0
      fun ins i = let
	    val r = !rear
	    in
	      queue := Bits.orb(Bits.lshift(i, r), !queue);
	      rear := r + 5
	    end
      fun remove () = let
	    val q = !queue
	    val x = Bits.andb (q, 31)
	    in
	      queue := Bits.rshift (q, 5);
	      rear := !rear - 5;
	      x
	    end
      val _ = app ins [10, 11, 12, 13]      (* %o2-%o5 *)
    in

  (* Registers %o2, %o3 & %o4 are also used to call ml_mul and ml_div. *)
    val arg1EA = Direct(REG 10) and arg2EA = Direct(REG 11)
    val opAddrR = REG 12

  (* Get a temporary register. *)
    fun getTmpReg () = REG(remove())

   (* If r is a temporary register, then free it. *)
    fun freeReg (REG r) = if ((9 < r) andalso (r < 14)) then (ins r) else ()

  (* Free a temporary register. *)
    fun freeTmpReg (REG r) = ins r

    end (* local *)


  (* align is a nop, since strings are automatically padded. *)
    fun align () = ()

    val mark = mark

    val emitlong = emitLong
    val realconst = emitReal
    val emitstring = emitString

    fun emitlab (n, ImmedLab lab) = emitLabel (lab, n)
      | emitlab _ = ErrorMsg.impossible "[SparcCM.emitlab]"

    val newlabel = ImmedLab o newLabel
    fun define (ImmedLab lab) = C.define lab
      | define _ = ErrorMsg.impossible "[SparcCM.define]"

    datatype immed_size = Immed13 | Immed32

    fun sizeImmed n = if (~4096 <= n) andalso (n < 4096) then Immed13 else Immed32


  (** Utility operations **)

    fun emitMove (src, dst) = emit_or (zeroR, REGrand src, dst)

    fun loadImmed32 (n, r) = let
	  val lo10 = Bits.andb(n, 1023)
	  in
	    emit_sethi (IMrand(Bits.rshift(n, 10)), r);
	    if (lo10 <> 0) then emit_or(r, IMrand lo10, r) else ()
	  end

    fun loadImmed (n, r) = (
	  case (sizeImmed n)
	   of Immed13 => emit_or(zeroR, IMrand n, r)
	    | Immed32 => loadImmed32 (n, r))

    fun op32 f (r1, n, r2) = let val tmpR = getTmpReg()
	  in
	    loadImmed32 (n, tmpR);
	    f (r1, REGrand tmpR, r2);
	    freeTmpReg tmpR
	  end

    fun loadReg(r, offset, dst) = (
	  case (sizeImmed offset)
	   of Immed13 => emit_ld (r, IMrand offset, dst)
	    | Immed32 => (op32 emit_ld) (r, offset, dst))

    fun store (src, r, offset) = (
	  case (sizeImmed offset)
	   of Immed13 => emit_st (r, IMrand offset, src)
	    | Immed32 => (op32 emit_st) (r, offset, src))

    fun addImmed (r, n, dst) = (
	  case (sizeImmed n)
	   of Immed13 => emit_add (r, IMrand n, dst)
	    | Immed32 => (op32 emit_add) (r, n, dst))

    fun compareImmed (r, n) = (
	  case (sizeImmed n)
	   of Immed13 => emit_subcc (r, IMrand n, zeroR)
	    | Immed32 => (op32 emit_subcc) (r, n, zeroR))


  (** CMachine instructions **)

  (* move (src, dst) *)
    fun move (Immed n, Direct r) = loadImmed (n, r)
      | move (ImmedLab lab, Direct r) = let val tmpR = getTmpReg()
	  in
	    loadAddr (lab, 0, r, tmpR);
	    freeTmpReg tmpR
	  end
      | move (Direct r1, Direct r2) = emitMove (r1, r2)
      | move _ = ErrorMsg.impossible "[SparcCM.move]"

  (* checkLimit (n):
   * Generate code to check the heap limit to see if there is enough free space
   * to allocate n bytes.
   * NOTE: The handler in "runtime/SPARC.dep.c" is sensitive to the code
   * sequences generated here.
   *)
    fun checkLimit maxAllocSize = (
	  if (maxAllocSize <= 4096)
	    then emit_taddcctv (dataptrR, limitptrRand, zeroR)
	    else let
	      val n = maxAllocSize - 4096
	      val tmpR = getTmpReg()
	      in
		if (n < 2048)
		  then (
		    emit_add (limitptrR, IMrand n, tmpR);
		    emit_taddcctv (dataptrR, REGrand tmpR, zeroR))
		  else (
		    emit_sethi (IMrand(Bits.rshift(n, 10)), tmpR);
		    emit_or (tmpR, IMrand(Bits.andb(n, 1023)), tmpR);
		    emit_add (limitptrR, REGrand tmpR, tmpR);
		    emit_taddcctv (dataptrR, REGrand tmpR, zeroR));
		freeTmpReg tmpR
	      end)

  (* beginStdFn (cl, lab):
   * Note the beginning of a standard function with entry label lab, and
   * register cl containing its closure.  This requires generating code to
   * load the base code block address into baseCodePtr.
   *)
    fun beginStdFn (Direct closureReg, ImmedLab lab) = let val tmpR = getTmpReg()
	  in
	    setBaseAddr (closureReg, lab, tmpR);
	    freeTmpReg tmpR
	  end
      | beginStdFn _ = ErrorMsg.impossible "[SparcCM.beginStdFn]"

  (* jmp (dst):
   * Unconditional jump to destination.
   *)
    fun jmp (ImmedLab lab) = emit_ba lab
      | jmp (Direct r) = emit_jmp (r, zeroRand)
      | jmp _ = ErrorMsg.impossible "[SparcCM.jmp]"

  (* record (vl, dst):
   * makes a new record, puts address of it into the destination specified
   * by the second arg. The contents are numbered from ~1 and up.
   *)
    fun record (vl : (EA * CPS.accesspath) list, Direct dst) = let
	  val len = length vl
	  val minBlockSize = 6
	(* generate code to move one or more adjacent fields from one record into
	 * adjacent fields in the new record.  If the block is big enough, then
	 * use a block copy loop.
	 *)
	  fun blockMove (srcR, startindx, path, offset) = let
	      (* check a CPS path to see how large the block is *)
		fun chkpath (cnt, i,
		    path as (Direct r, CPS.SELp(j, CPS.OFFp 0)) :: rest) =
		      if (r = srcR) andalso (i+offset = j)
			then chkpath (cnt+1, i-1, rest)
			else (cnt, path)
		  | chkpath (cnt, _, rest) = (cnt, rest)
	      (* generate code to move fields individually *)
		fun moveFields (0, _) = ()
		  | moveFields (n, indx) = let val tmpR = getTmpReg()
		      in
			loadReg(srcR, (indx+offset)*4, tmpR);
			store (tmpR, dataptrR, indx*4);
			freeTmpReg tmpR;
			moveFields(n-1, indx-1)
		      end
		val (blksz, rest) = chkpath(1, startindx-1, path)
		in
		  if (blksz < minBlockSize)
		    then moveFields(blksz, startindx)
		    else if (offset = 0)
		      then let
			val lab = newLabel()
			val indxR = getTmpReg() and tmpR = getTmpReg()
			in
			  loadImmed (startindx*4, indxR);
			  C.define lab;
			  emit_ld (srcR, REGrand indxR, tmpR);
			  compareImmed (indxR, (startindx-blksz)*4);
			  emit_st (dataptrR, REGrand indxR, tmpR);
			  emit_sub (indxR, IMrand 4, indxR);
			  emit_bcc (GTR, lab);
			  freeTmpReg indxR; freeTmpReg tmpR
			end
		      else let
			val lab = newLabel()
			val indxR1 = getTmpReg() and indxR2 = getTmpReg()
			val tmpR = getTmpReg()
			in
			  loadImmed ((startindx+offset)*4, indxR1);
			  loadImmed (startindx*4, indxR2);
			  C.define lab;
			  emit_ld (srcR, REGrand indxR1, tmpR);
			  emit_sub (indxR1, IMrand 4, indxR1);
			  emit_st (dataptrR, REGrand indxR2, tmpR);
			  emit_sub (indxR2, IMrand 4, indxR2);
			  compareImmed (indxR1, (startindx+offset-blksz)*4);
			  emit_bcc (GTR, lab);
			  freeTmpReg indxR1; freeTmpReg indxR2; freeTmpReg tmpR
			end;
		  freeReg srcR;
		  (startindx-blksz, rest)
		end (* blockMove *)
      (* For each field in the record generate the necessary moves to initialize
       * it in the new record.
       *)
	  fun fields (_, nil) = ()
	    | fields (i, (Direct r, CPS.SELp(j, CPS.OFFp 0)) :: rest) =
		fields (blockMove (r, i, rest, j-i))
	    | fields (i, (Direct r, CPS.SELp(j, p)) :: rest) = let
		val tmpR = getTmpReg()
		in
		  loadReg(r, j*4, tmpR);
		  freeReg r;
		  fields (i, (Direct tmpR, p) :: rest)
		end
	    | fields (i, (Direct r, CPS.OFFp 0) :: rest) = (
		store (r, dataptrR, i*4);
		freeReg r;
		fields (i-1, rest))
	    | fields (i, (Direct r, CPS.OFFp j) :: rest) = let
		val tmpR = getTmpReg()
		val offset = j*4
		in
		  case sizeImmed offset
		   of Immed13 => emit_add (r, IMrand offset, tmpR)
		    | Immed32 => (
			loadImmed32 (offset, tmpR);
			emit_add (r, REGrand tmpR, tmpR))
		  (* end case *);
		  store (tmpR, dataptrR, i*4);
		  freeTmpReg tmpR; freeReg r;
		  fields (i-1, rest)
		end
	    | fields (i, (x, p) :: rest) =  let
		val tmpR = getTmpReg()
		in
		  move (x, Direct tmpR);
		  fields (i, (Direct tmpR, p) :: rest)
		end
	  in
	    fields (len-2, rev vl);
	    emitMove (dataptrR, dst);
	    addImmed (dataptrR, len*4, dataptrR)
	end
      | record _ = ErrorMsg.impossible "[SparcCM.record]"

  (* select (i, x, y):  y <- mem[x + 4*i] *)
    fun select (i, Direct r, Direct dst) = loadReg(r, i*4, dst)
      | select (i, ImmedLab lab, Direct dst) = let val tmpR = getTmpReg()
	  in
	    load (lab, i*4, dst, tmpR);
	    freeTmpReg tmpR
	  end
      | select _ = ErrorMsg.impossible "[SparcCM.select]"

  (* offset (i, x, y):  y <- (x + 4*i) *)
    fun offset (i, Direct r, Direct dst) = addImmed (r, 4*i, dst)
      | offset (i, ImmedLab lab, Direct dst) = let val tmpR = getTmpReg()
	  in
	    loadAddr (lab, i, dst, tmpR);
	    freeTmpReg tmpR
	  end
      | offset _ = ErrorMsg.impossible "[SparcCM.offset]"

  (* fetchindexb (x, y) fetches an unsigned byte:  y <- mem[x+arithtemp] *)
    fun fetchindexb (Direct r, Direct dst) = emit_ldb (r, arithtempRand, dst)
      | fetchindexb _ = ErrorMsg.impossible "[SparcCM.fetchindexb]"

  (* storeindexb (x, y) stores a byte:  mem[y+arithtemp] <- x *)
    fun storeindexb (Direct src, Direct r) = emit_stb (r, arithtempRand, src)
      | storeindexb _ = ErrorMsg.impossible "[SparcCM.storeindexb]"

  (* jmpindexb (x):  pc <- (x+arithtemp) *)
    fun jmpindexb (ImmedLab lab) = let
	  val tmpR1 = getTmpReg() and tmpR2 = getTmpReg()
	  in
	    loadAddr (lab, 0, tmpR1, tmpR2);
	    emit_jmp (tmpR1, arithtempRand);
	    freeTmpReg tmpR1; freeTmpReg tmpR2
	  end
      | jmpindexb _ = ErrorMsg.impossible "[SparcCM.jmpindexb]"

  (* fetchindexl (x, y, z) fetches a word:  y <- mem[x+2*(z-1)] *)
    fun fetchindexl (Direct r1, Direct dst, Direct r2) = let
	  val tmpR = getTmpReg()
	  in
	    emit_sub (r2, IMrand 1, tmpR);
	    emit_add (tmpR, REGrand tmpR, tmpR);
	    emit_ld (r1, REGrand tmpR, dst);
	    freeTmpReg tmpR
	  end
      | fetchindexl (Direct r1, Direct dst, Immed i) = loadReg(r1, 2*(i-1), dst)
      | fetchindexl (ImmedLab lab, Direct dst, Direct r) =  let
	  val tmpR1 = getTmpReg() and tmpR2 = getTmpReg()
	  in
	    loadAddr (lab, ~2, tmpR1, tmpR2);
	    emit_add (r, REGrand tmpR1, tmpR1);
	    emit_ld (r, REGrand tmpR1, dst);
	    freeTmpReg tmpR1; freeTmpReg tmpR2
	  end
      | fetchindexl _ = ErrorMsg.impossible "[SparcCM.fetchindexl]"

  (*storeindexl (x, y, z) stores a word:  mem[y+2*(z-1)] <- x *)
    fun storeindexl (Direct src, Direct r1, Direct r2) = let val tmpR = getTmpReg()
	  in
	    emit_sub (r2, IMrand 1, tmpR);
	    emit_add (tmpR, REGrand tmpR, tmpR);
	    emit_st (r1, REGrand tmpR, src);
	    freeTmpReg tmpR
	  end
      | storeindexl (Direct src, Direct r, Immed i) = store (src, r, 2*(i-1))
      | storeindexl (Immed n, x, y) = let val tmpR = getTmpReg()
	  in
	    loadImmed (n, tmpR);
	    storeindexl (Direct tmpR, x, y);
	    freeTmpReg tmpR
	  end
      | storeindexl (ImmedLab lab, x, y) = let
	  val tmpR1 = getTmpReg() and tmpR2 = getTmpReg()
	  in
	    loadAddr (lab, 0, tmpR1, tmpR2);
	    storeindexl (Direct tmpR1, x, y);
	    freeTmpReg tmpR1; freeTmpReg tmpR2
	  end
(** NOTE: in a sane world the following case would be unecessary, but they
 ** are used in an ugly profiling hack.
 **)
      | storeindexl (Direct src, ImmedLab lab, Immed i) = let
	  val tmpR1 = getTmpReg() and tmpR2 = getTmpReg()
	  in
	    loadAddr (lab, 2*(i-1), tmpR1, tmpR2);
	    emit_st (tmpR1, zeroRand, src);
	    freeTmpReg tmpR1; freeTmpReg tmpR2
	  end
      | storeindexl _ = ErrorMsg.impossible "[SparcCM.storeindexl]"

  (* ashl (n, x, y) shift left: y <- (x << n), with  n >= 0 *)
    fun ashl (Direct cntR, Direct src, Direct dst) =
	  emit_sll(src, REGrand cntR, dst)
      | ashl (Immed cnt, Direct src, Direct dst) =
	  emit_sll (src, IMrand(Bits.andb(cnt, 31)), dst)
      | ashl (Direct cntR, Immed src, Direct dst) = let val tmpR = getTmpReg()
	  in
	    loadImmed (src, tmpR);
	    emit_sll (tmpR, REGrand cntR, dst);
	    freeTmpReg tmpR
	  end
      | ashl _ = ErrorMsg.impossible "[SparcCM.ashl]"

  (* ashr (n, x, y) shift right: y <- (x >> n), with  n >= 0 *)
    fun ashr (Direct cntR, Direct src, Direct dst) =
	  emit_sra (src, REGrand cntR, dst)
      | ashr (Immed cnt, Direct src, Direct dst) =
	  emit_sra (src, IMrand(Bits.andb(cnt, 31)), dst)
      | ashr (Direct cntR, Immed src, Direct dst) = let val tmpR = getTmpReg()
	  in
	    loadImmed (src, tmpR);
	    emit_sra (tmpR, REGrand cntR, dst);
	    freeTmpReg tmpR
	  end
      | ashr (Immed cnt, Immed src, Direct dst) = (
print "[missed constant fold ("; print src; print " >> "; print cnt; print ")]\n";
	  loadImmed (Bits.rshift(src, cnt), dst))
      | ashr _ = ErrorMsg.impossible "[SparcCM.ashr]"

    local
	fun adjArgs f (a as Immed _, b, c) = f (b, a, c)
	  | adjArgs f args = f args
	fun adjSubArgs f (a, Immed b, c) = let val tmpR = getTmpReg()
	      in
		loadImmed (b, tmpR);
		f (Direct tmpR, a, c);
		freeTmpReg tmpR
	      end
	  | adjSubArgs f (a, b, c) = f (b, a, c)
	fun arithOp f (Direct r1, Direct r2, Direct dst) = f (r1, REGrand r2, dst)
	  | arithOp f (Direct r, Immed n, Direct dst) = (
	      case (sizeImmed n)
	       of Immed13 => f (r, IMrand n, dst)
		| Immed32 => let val tmpR = getTmpReg()
		    in
		      loadImmed32 (n, tmpR);
		      f (r, REGrand tmpR, dst);
		      freeTmpReg tmpR
		    end)
	  | arithOp _ _ = ErrorMsg.impossible "[SparcCM.arithOp]"
	val addt = adjArgs (arithOp (fn args => (emit_addcc args; emit_tvs())))
    in

    val orb = adjArgs (arithOp emit_or)
    val andb = adjArgs (arithOp emit_and)
    val xorb = adjArgs (arithOp emit_xor)
    fun notb (Direct src, Direct dst) = emit_not (src, dst)
      | notb _ = ErrorMsg.impossible "[SparcCM.notb]"

    val addl3 = adjArgs (arithOp emit_add)
    fun addl3t (Immed a, b as Immed _, dst) = let val tmpR = getTmpReg ()
	(* This should only occur when we need to build a constant larger than
	 * 2^29.  Note, we assume that "b" is tagged (see "cps/generic.sml").
	 *)
	  in
	    loadImmed (a, tmpR);
	    addt (Direct tmpR, b, dst);
	    freeTmpReg tmpR
	  end
      | addl3t args = addt args

    val subl3 = adjSubArgs (arithOp emit_sub)
    val subl3t = adjSubArgs (arithOp (fn args => (emit_subcc args; emit_tvs())))

    end (* local *)

  (* mull2t/divl2t:
   * mull2t (a, b):  b <- (a * b) (with overflow checking done by ml_mul)
   * divl2t (a, b):  b <- (b div a)
   *)
    local
	fun intOp opAddrOffset (a, b as Direct _) = (
	      emit_ld (spR, opAddrOffset, opAddrR);
	      move (a, arg2EA);
	      move (b, arg1EA);
	      emit_jmpl (opAddrR, zeroRand, linkR);
	      move (arg1EA, b))
	  | intOp _ _ = ErrorMsg.impossible "[SparcCM.intOp]"
	val mulAddrOffset = IMrand 72
	val divAddrOffset = IMrand 76
    in
    val mull2t = intOp mulAddrOffset
    val divl2 = intOp divAddrOffset
    end (* local *)

  (* bbs (i, dst, lab): test the i'th bit of dst and jump to lab if it is zero *)
    fun bbs (Immed i, Direct r, ImmedLab lab) = (
	  emit_andcc (r, IMrand(Bits.lshift(1, i)), zeroR);
	  emit_bcc (NEQ, lab))
      | bbs _ = ErrorMsg.impossible "[SparcCM.bbs]"

    local
    (* reverse a condition (eg., (a <= b) <==> (b >= a) *)
      fun revCond NEQ = NEQ | revCond EQL = EQL
	| revCond LEQ = GEQ | revCond GEQ = LEQ
	| revCond LSS = GTR | revCond GTR = LSS
    in

  (* ibranch (cond, a, b, lab): if (a <cond> b) then pc <- lab *)
    fun ibranch (cond, a as Immed _, b as Direct _, l) = ibranch (revCond cond, b, a, l)
      | ibranch (cond, Direct r1, b, ImmedLab lab) = (
	  case b
	   of Direct r2 => emit_subcc (r1, REGrand r2, zeroR)
	    | Immed n => (
		case (sizeImmed n)
		 of Immed13 => emit_subcc (r1, IMrand n, zeroR)
		  | Immed32 => let val tmpR = getTmpReg()
		      in
			loadImmed32 (n, tmpR);
			emit_subcc (r1, REGrand tmpR, zeroR);
			freeTmpReg tmpR
		      end)
	    | _ => ErrorMsg.impossible "[SparcCM.ibranch.case]"
	  (* end case *);
	  emit_bcc (cond, lab))
      | ibranch _ = ErrorMsg.impossible "[SparcCM.ibranch]"

    end (* local *)


  (** Floating point instructions **
   * These instructions take ML real values as arguments (ie., addresses of
   * heap objects) and store their results in the heap.
   *)

    local
      val f0 = FREG 0
      val f1 = FREG 1
      val f2 = FREG 2
    (* the tag code for real values. *)
      val realTag = (8*System.Tags.power_tags + System.Tags.tag_string)
    (* finishReal(r): emit code to store the result of a real operation
     * (in %f0, %f1) in the heap, and put the result address in r.
     *)
      fun finishReal r = let val tmpR = getTmpReg()
	    in
	      loadImmed (realTag, tmpR);
	      emit_st (dataptrR, IMrand(~4), tmpR);
	      emit_stf (dataptrR, zeroRand, f0);
	      emit_stf (dataptrR, IMrand 4, f1);
	      emitMove (dataptrR, r);
	      emit_add (dataptrR, IMrand 12, dataptrR);
	      freeTmpReg tmpR
	    end
    (* Fetch a ML real value into a floating-point register pair *)
      fun fetchReal (Direct r, FREG i) = (
	    emit_ldf (r, zeroRand, FREG i);
	    emit_ldf (r, IMrand 4, FREG(i+1)))
	| fetchReal (ImmedLab lab, dst) = let val tmpR = getTmpReg()
	    in
	      loadF (lab, 0, dst, tmpR);
	      freeTmpReg tmpR
	    end
	| fetchReal _ = ErrorMsg.impossible "[SparcCM.fetchReal]"

      fun floatOp fOp (a, b, Direct dst) = (
	    fetchReal (a, f0);
	    fetchReal (b, f2);
	    fOp (f0, f2, f0);
	    finishReal dst)
	| floatOp _ _ = ErrorMsg.impossible "[SparcCM.floatOp]"
    in

  (* Negate the first arg and return a pointer to the result in the second *)
    fun mnegg (src, Direct dst) = (
	  fetchReal (src, f0);
	  emit_fneg (f0, f0);
	  finishReal dst)
      | mnegg _ = ErrorMsg.impossible "[SparcCM.mnegg]"

  (* Add the first two arguments and store the result in the third *)
    val addg3 = floatOp emit_fadd

  (* Subtract the second argument from the first and store the result in the third *)
    val subg3 = floatOp emit_fsub

  (* Multiply the first two arguments and store the result in the third *)
    val mulg3 = floatOp emit_fmul

  (* Divide the first argument by the second and store the result in the third *)
    val divg3 = floatOp emit_fdiv

  (* Conditionally branch on the float values of two arguments. *)
    fun gbranch (cond, a, b, ImmedLab lab) = (
	  fetchReal (a, f0);
	  fetchReal (b, f2);
	  emit_fcmp (f0, f2);
	  emit_fbcc (cond, lab))
      | gbranch _ = ErrorMsg.impossible "[SparcCM.gbranch]"

    end (* local *)

    fun profile _ = ()

    end (* local *)

end (* functor SparcCM *)

unix.superglobalmegacorp.com

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