Home My Page Projects Code Snippets Project Openings diderot
Summary Activity Tracker Tasks SCM

SCM Repository

[diderot] View of /branches/vis15/src/compiler/target-cpu/gen-strand.sml
ViewVC logotype

View of /branches/vis15/src/compiler/target-cpu/gen-strand.sml

Parent Directory Parent Directory | Revision Log Revision Log


Revision 4547 - (download) (annotate)
Fri Sep 9 01:42:59 2016 UTC (3 years, 5 months ago) by jhr
File size: 8800 byte(s)
  Working on merge: cleaning up some remaining issues with the indirect dual-state rep.
(* gen-strand.sml
 *
 * Code generation for strands.  If the program does not have strand communication,
 * then we represent a strand S's state using a single struct type (S_strand).
 * If there is communication, then define three struct types:
 *
 *    S_shared, which contains those state variables that are both varying and shared
 *
 *    S_local, which contains the state variables not in S_shared, and
 *
 *    S_strand, which is a wrapper that contains one instance of S_local and two
 *    of S_shared.
 *
 * This code is part of the Diderot Project (http://diderot-language.cs.uchicago.edu)
 *
 * COPYRIGHT (c) 2016 The University of Chicago
 * All rights reserved.
 *)

structure GenStrand : sig

    val gen : CodeGenEnv.t * TreeIR.strand -> {
            structDefs : CLang.decl list,       (* representation of a strand's state *)
            methods : CLang.decl list           (* implementation of a strand's methods *)
          }

  end = struct

    structure IR = TreeIR
    structure SV = TreeStateVar
    structure CL = CLang
    structure RN = CxxNames
    structure Env = CodeGenEnv

    val strandStatusTy = CL.T_Named "diderot::strand_status"

  (* generate the `pos` method for the strand state *)
    fun genPosMethod (env, substruct, posV) = let
	  val realTy = RawTypes.toString(Env.rawRealTy env)
	  fun mkDcl s = CL.D_Verbatim[concat s]
	  val (addrof, select) = (case SV.ty posV
		 of TreeTypes.VecTy(1, 1) => ("&", "sv_pos")
		  | TreeTypes.TensorTy[d] => ("", "sv_pos.base()")
		(* end case *))
	  in
(* FIXME: once CLang supports "const" functions, we should switch to building AST *)
	    mkDcl [
		"const ", realTy, " *pos (uint32_t inIdx) const { return ",
		addrof, "this->", substruct, select, "; }"
	      ]
	  end

  (* is a state variable the special "pos" variable? *)
    fun isPosVar x = SV.name x = "pos"

  (* generate the strand-state struct declaration *)
    fun genStrandStructs (env, strandName, state) = let
          fun mkField sv = CL.D_Var([], TreeToCxx.trType(env, SV.ty sv), [], SV.qname sv, NONE)
	  fun mkStruct (name, svs, meths) = CL.D_ClassDef{
		  name = name,
		  args = NONE, from = NONE,
		  public = List.foldr (fn (sv, membs) => mkField sv :: membs) meths svs,
		  protected = [],
		  private = []
		}
	  val structName = RN.strandTyName strandName
	  val dualState = TargetSpec.dualState(Env.target env)
	  fun mkPosMeth () = if #hasCom(Env.target env)
		then (case List.find isPosVar state
		   of SOME sv => if not dualState
			  then [genPosMethod (env, "", sv)]
			else if SV.inSharedStruct sv
			  then [genPosMethod (env, "_shared[inIdx].", sv)]
			  else [genPosMethod (env, "_local.", sv)]
		    | NONE => raise Fail "impossible: missing \"pos\" state variable"
		  (* end case *))
		else []
	  in
	    if dualState
	      then let
(* QUESTION: should we special-case the situations where either sharedSVs or localSVs is empty? *)
		val (sharedSVs, localSVs) = List.partition SV.inSharedStruct state
		val localName = RN.localTyName strandName
		val localStruct = mkStruct (localName, localSVs, [])
		val sharedName = RN.sharedTyName strandName
		val sharedStruct = mkStruct (sharedName, sharedSVs, [])
		val strandStruct = CL.D_ClassDef{
		    name = structName,
		    args = NONE, from = NONE,
		    public =
			CL.D_Var([], CL.T_Named localName, [], "_local", NONE) ::
			CL.D_Var([], CL.T_Array(CL.T_Named sharedName, SOME 2), [], "_shared", NONE) ::
			mkPosMeth(),
		    protected = [],
		    private = []
		  }

		in
		  [localStruct, sharedStruct, strandStruct]
		end
	      else [mkStruct (structName, state, mkPosMeth())]
          end

  (* generate the strand-state initialization code.  The variables are the strand
   * parameters.
   * NOTE: the calling convention generated here must match that used in GenWorld.genCreateFun
   * and genNew below.
   *)
    fun genStateInit (env, strandName, stateParams, params, def) = let
          val IR.Method{needsW, hasG, body} = def
          val fName = strandName ^ "_init"
          val (env, params) = List.foldr
                (fn (x, (env, ps)) => let
                    val (env, p) = TreeToCxx.trParam(env, x)
                    in
                      (env, p::ps)
                    end)
                  (env, []) params
	  val params = stateParams @ params
          val params = if hasG
                then RN.globalsParam :: params
                else params
          val params = if needsW
                then RN.worldParam :: params
                else params
          val body = TreeToCxx.trBlock (env, body)
          in
            CL.D_Func(["static"], CL.voidTy, [], fName, params, body)
          end

  (* generate the function for dynamically creating new strands (if needed) *)
    fun genNew (env, strandName, strandPtrTy, params, initDef) = if #hasNew(Env.target env)
	  then let
	    val IR.Method{needsW, hasG, ...} = initDef
	    val fName = strandName ^ "_new"
	    val params' = RN.worldParam :: List.map
		  (fn x => CL.PARAM([], TreeToCxx.trType(env, TreeVar.ty x), TreeVar.name x))
		    params
	  (* allocate new strand *)
	    val allocStm = CL.mkDeclInit(CL.autoTy, "ix",
		  CL.mkDispatch(RN.strandArray env, "new_strand", []))
	  (* arguments to init function *)
	    val args = List.map (fn x => CL.mkVar(TreeVar.name x)) params
	  (* extend args with strand *)
	    val args = if TargetSpec.dualState(Env.target env)
		  then CL.mkDispatch(RN.strandArray env, "local_state", [CL.mkVar "ix"])
		    :: CL.mkDispatch(RN.strandArray env, "out_state", [CL.mkVar "ix"])
		    :: args
		  else CL.mkDispatch(RN.strandArray env, "strand", [CL.mkVar "ix"]) :: args
	  (* extend args globals (if necessary) *)
	    val args = if hasG
                then CL.mkIndirect(CL.mkVar RN.worldVar, "_globals") :: args
                else args
	  (* extend args and params with the world (if necessary) *)
	    val args = if needsW
		  then CL.mkVar RN.worldVar :: args
		  else args
	  (* initialize new strand *)
	    val initStm = CL.mkCall(strandName ^ "_init", args)
	    in [
	      CL.D_Func(["static"], CL.voidTy, [], fName, params', CL.mkBlock [allocStm, initStm])
	    ] end
	  else []

  (* generate a function definition for a strand method *)
    fun genMethodDef (env, strandName, stateParams, methTy, methName, needsWorld, usesGlobals, body) =
          let
          val fName = concat[strandName, "_", methName]
          val params = if usesGlobals
                then RN.globalsParam :: stateParams
                else stateParams
          val params = if needsWorld
                then RN.worldParam :: params
                else params
          in
            CL.D_Func(["static"], methTy, [], fName, params, body)
          end

  (* generate a function definition for a strand method *)
    fun genMethod (env, strandName, stateParams, methTy, methName, IR.Method{needsW, hasG, body}) =
          genMethodDef (
            env, strandName, stateParams, methTy, methName,
            needsW, hasG, TreeToCxx.trBlock (env, body))

    fun genStartMethod (_, _, _, NONE) = []
      | genStartMethod (env, strandName, stateParams, SOME meth) =
          [genMethod (env, strandName, stateParams, strandStatusTy, "start", meth)]

    fun genUpdateMethod (env, strandName, stateParams, meth) =
          genMethod (env, strandName, stateParams, strandStatusTy, "update", meth)

    fun genStabilizeMethod (_, _, _, NONE) = []
      | genStabilizeMethod (env, strandName, stateParams, SOME meth) =
          [genMethod (env, strandName, stateParams, CL.voidTy, "stabilize", meth)]

    fun gen (env, strand) = let
          val IR.Strand{name, params, state, stateInit, startM, updateM, stabilizeM, ...} = strand
          val name = Atom.toString name
          val strandPtrTy = CL.T_Ptr(RN.strandTy name)
	  val (initParams, updateParams) = if TargetSpec.dualState(Env.target env)
		then let
		  fun mkParam (ty, x) = CL.PARAM([], CL.T_Ptr(CL.T_Named ty), x)
		  val localParam = mkParam(RN.localTyName name, RN.selfLocalVar)
		  val inParam = mkParam(RN.sharedTyName name, RN.selfInVar)
		  val outParam = mkParam(RN.sharedTyName name, RN.selfOutVar)
		  in
		    ([localParam, outParam], [localParam, inParam, outParam])
		  end
		else let
		  val params = [CL.PARAM([], CL.T_Ptr(RN.strandTy name), RN.selfVar)]
		  in
		    (params, params)
		  end
          in {
            structDefs = genStrandStructs (env, name, state),
            methods = genStateInit (env, name, initParams, params, stateInit) ::
	      genNew (env, name, strandPtrTy, params, stateInit) @
              genStartMethod (env, name, updateParams, startM) @
              genUpdateMethod (env, name, updateParams, updateM) ::
              genStabilizeMethod (env, name, updateParams, stabilizeM)
          } end

  end

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