RSSA

Stephen Weeks MLton@sourcelight.com
Fri, 21 Dec 2001 12:18:17 -0800


Here's my first attempt at RSSA, an IL that sits between SSA and
MACHINE.  It is like SSA in that it has variables and functions.  It
is like MACHINE in that representations are explicit.

The idea is to split what is currently the backend into two pieces,
one to translate from SSA to RSSA, and the other from RSSA to MACHINE.

SSA -> RSSA involves
	* implementing handlers
	* deciding representations (of tuples, datatypes)
	* making allocation explicit
	* inserting limit checks

RSSA -> MACHINE involves
	* deciding stack layout
	* computing liveness info
	* pseudoregister allocation

I don't claim that RSSA is type checkable.  But I do hope to be able
to do limit check insertion and verification on it.

The main things to notice are the new Exps for allocting and offsets,
the new Transfer for limit checks, and the fact that RSSA only uses
simple machine types.

Comments solicited.  :-)

--------------------------------------------------------------------------------

type int = Int.t
type word = Word.t
   
signature RSSA_STRUCTS = 
   sig
      include ATOMS
   end

signature RSSA = 
   sig
      include RSSA_STRUCTS

      structure Func: HASH_ID
      structure Label: HASH_ID
      structure Type: MTYPE

      structure Exp:
	 sig
	    datatype t =
	       Allocate of {numPointers: int,
			    numWordsNonPointers: int,
			    stores: {offset: int,
				     value: Var.t} Vector}
	     | AllocateArray of {numBytesNonPointers: int,
				 numElts: Var.t,
				 numPointers: int}
	     | ArrayOffset of {base: Var.t,
			       offset: Var.t,
			       ty: Type.t}
	     | Const of Const.t
	     | Offset of {base: Var.t,
			  offset: int} (* offset in bytes *)
	     | PrimApp of {prim: Prim.t,
			   args: Var.t vector}
	     | SetExnStackLocal
	     | SetExnStackSlot
	     | SetHandler of Label.t
	     | SetSlotExnStack
	 end

      structure Statement:
	 sig
	    datatype t = T of {var: Var.t option,
			       ty: Type.t,
			       exp: Exp.t}
	 end
      
      structure Cases: MACHINE_CASES sharing Label = Cases.Label

      structure Handler:
	 sig
	    datatype t =
	       CallerHandler
	     | None
	     | Handle of Label.t
	 end

      structure Return:
	 sig
	    datatype t =
	       Dead
	     | HandleOnly
	     | NonTail of {cont: Label.t, handler: Handler.t}
	     | Tail
	 end

      structure LimitCheck:
	 sig
	    datatype t =
	       Array of {numElts: Var.t,
			 bytesPerElt: int,
			 extraBytes: int} (* for subsequent allocation *)
	     | Heap of {bytes: int,
			stackToo: bool}
	     | Signal
	     | Stack
	 end
      
      structure Transfer:
	 sig
	    datatype t =
	       Arith of {prim: Prim.t,
			 args: Var.t vector,
			 overflow: Label.t, (* Must be nullary. *)
			 success: Label.t (* Must be unary. *)
			}
	     | Bug  (* MLton thought control couldn't reach here. *)
	     | Call of {func: Func.t,
			args: Var.t vector,
			return: Return.t}
	     | Case of {test: Var.t,
			cases: Label.t Cases.t,
			default: Label.t option (* Must be nullary. *)
		       }
	     | Goto of {dst: Label.t,
			args: Var.t vector
			}
	     | LimitCheck of {kind: LimitCheck.t,
			      return: Label.t}
	     (* Raise implicitly raises to the caller.  
	      * I.E. the local handler stack must be empty.
	      *)
	     | Raise of Var.t vector
	     | Return of Var.t vector
	     | Runtime of {prim: Prim.t,
			   args: Var.t vector,
			   return: Label.t (* Must be nullary. *)
			  }
	 end

      structure Block:
	 sig
	    datatype t =
	       T of {
		     label: Label.t,
		     args: (Var.t * Type.t) vector,
		     statements: Statement.t vector,
		     transfer: Transfer.t
		     }
	 end

      structure Function:
	 sig
	    datatype t = T of {args: (Var.t * Type.t) vector,
			       blocks: Block.t vector,
			       name: Func.t,
			       raises: Type.t vector option,
			       returns: Type.t vector option,
			       start: Label.t}
	 end
     
      structure Program:
	 sig
	    datatype t =
	       T of {
		     globals: Statement.t vector,
		     functions: Function.t list,
		     main: Func.t (* Must be nullary. *)
		    } 
	 end
   end