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

SCM Repository

[diderot] View of /branches/vis15/src/compiler/cfg-ir/promote-fn.sml
ViewVC logotype

View of /branches/vis15/src/compiler/cfg-ir/promote-fn.sml

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3754 - (download) (annotate)
Thu Apr 14 22:45:39 2016 UTC (3 years, 8 months ago) by jhr
File size: 8358 byte(s)
working on merge
(* promote-fn.sml
 *
 * This code is part of the Diderot Project (http://diderot-language.cs.uchicago.edu)
 *
 * COPYRIGHT (c) 2016 The University of Chicago
 * All rights reserved.
 *
 * Transformations, such as normalization, can create references to variables defined
 * in the global initialization section from nested scopes (e.g., inside strands).
 * This functor implements a pass that promotes such variables to be globals.
 *
 * FIXME: what about constants?
 *)

functor PromoteFn (IR : SSA) : sig

    val transform : IR.program -> IR.program

  end = struct

    structure V = IR.Var
    structure VTbl = V.Tbl
    structure VMap = V.Map

  (* adjust a variable's use count *)
    fun incUse (IR.V{useCnt, ...}) = (useCnt := !useCnt + 1)
    fun decUse (IR.V{useCnt, ...}) = (useCnt := !useCnt - 1)
    fun incGlobal (IR.GV{useCnt, ...}) = (useCnt := !useCnt + 1)

  (* local variables in the global initialization section are either just used locally
   * or used to define a global (via GASSIGN).
   *)
    datatype info = LOCAL | GLOBAL of IR.global_var

    fun initTbl globalInit = let
          val tbl = VTbl.mkTable (64, Fail "promote")
          val insert = VTbl.insert tbl
          fun doNode nd = (case IR.Node.kind nd
                 of IR.GASSIGN{lhs, rhs, ...} => insert (rhs, GLOBAL lhs)
                  | _ => List.app (fn x => insert (x, LOCAL)) (IR.Node.defs nd)
                (* end case *))
          in
            IR.CFG.apply doNode globalInit;
            tbl
          end

    fun transform (prog as IR.Program{globals=[], ...}) = prog
      | transform prog = let
	  val IR.Program{
		  props, consts, inputs, constInit, globals, globalInit, strand, create, update
		} = prog
        (* table mapping locals in the globalInit to info *)
          val promoteTbl = initTbl globalInit
        (* newly defined globals paired with their globalInit local definition *)
          val newGlobs : (IR.global_var * IR.var) list ref = ref []
        (* update a CFG as necessary to references to globalInit locals with references to new
         * globals.
         *)
          fun doCFG cfg = let
              (* assignment statements to load local copies of the new globals; these get put
               * at the beginning of the block.
               *)
                val initStms = ref []
                fun doNode (nd as IR.ND{id, props, kind}, env) = let
                      fun doUse (false, [], _, env, _) = env
                        | doUse (true, [], ys, env, mkNode) = (
                            IR.CFG.replaceNode (nd, mkNode(List.rev ys));
                            env)
                        | doUse (changed, x::xs, ys, env, mkNode) = (case VTbl.find promoteTbl x
                             of SOME LOCAL => let
                                  val x' = V.copy x
                                  val gx = IR.GlobalVar.new(IR.GlobalVar, false, V.name x, V.ty x)
                                  in
                                    decUse x; incUse x'; incGlobal gx;
                                    initStms := IR.ASSGN(x', IR.GLOBAL gx) :: !initStms;
                                    newGlobs := (gx, x) :: !newGlobs;
                                    VTbl.insert promoteTbl (x, GLOBAL gx);
                                    doUse (true, xs, x'::ys, VMap.insert(env, x, x'), mkNode)
                                  end
                              | SOME(GLOBAL gx) => (case VMap.find(env, x)
                                   of SOME x' => (
                                        decUse x; incUse x';
                                        doUse (true, xs, x'::ys, env, mkNode))
                                    | NONE => let (* no previous use of g in this CFG *)
                                        val x' = V.copy x
                                        in
                                          decUse x; incUse x'; incGlobal gx;
                                          initStms := IR.ASSGN(x', IR.GLOBAL gx) :: !initStms;
                                          doUse (true, xs, x'::ys, VMap.insert(env, x, x'), mkNode)
                                        end
                                  (* end case *))
                              | NONE => doUse (changed, xs, x::ys, env, mkNode)
                            (* end case *))
                      fun doArgs (args, mkNode) = doUse (false, args, [], env, mkNode)
                      in
                        case kind
                         of IR.NULL => env
                          | IR.ENTRY _ => env
                          | IR.JOIN _ => env
                          | IR.COND _ => env
			  | IR.FOREACH _ => env
			  | IR.NEXT _ => env
                          | IR.COM _ => env
                          | IR.ASSIGN{stm=(lhs, rhs), ...} => (case rhs
                               of IR.GLOBAL _ => env
                                | IR.STATE _ => env
                                | IR.VAR x => doArgs ([x], fn [x] => IR.Node.mkASSIGN(lhs, IR.VAR x))
                                | IR.LIT _ => env
                                | IR.OP(rator, args) =>
                                    doArgs (args, fn args => IR.Node.mkASSIGN(lhs, IR.OP(rator, args)))
                                | IR.CONS(args, ty) =>
                                    doArgs (args, fn args => IR.Node.mkASSIGN(lhs, IR.CONS(args, ty)))
                                | IR.SEQ(args, ty) =>
                                    doArgs (args, fn args => IR.Node.mkASSIGN(lhs, IR.SEQ(args, ty)))
				| IR.EINAPP(ein, args) =>
				    doArgs (args, fn args => IR.Node.mkASSIGN(lhs, IR.EINAPP(ein, args)))
                              (* end case *))
                          | IR.MASSIGN{stm=(lhs, rator, rhs), ...} =>
                              doArgs (rhs, fn rhs => IR.Node.mkMASSIGN(lhs, rator, rhs))
                          | IR.GASSIGN _ => raise Fail "unexpected GASSIGN"
                          | IR.NEW{strand, args, ...} =>
                              doArgs (args, fn args => IR.Node.mkNEW{strand=strand, args=args})
                          | IR.SAVE{lhs, rhs, ...} =>
                              doArgs ([rhs], fn [rhs] => IR.Node.mkSAVE(lhs, rhs))
                          | IR.EXIT _ => env
                        (* end case *)
                      end
                in
                  List.foldl doNode VMap.empty (IR.CFG.sort cfg);
                  case !initStms
                   of [] => cfg
                    | stms => IR.CFG.prependBlock(List.rev stms, cfg)
                  (* end case *)
                end
        (* process the strand *)
          val strand' = let
		val IR.Strand{name, params, state, stateInit, initM, updateM, stabilizeM} = strand
		in
		  IR.Strand{
		      name = name, params = params, state = state,
		      stateInit = doCFG stateInit,
		      initM = Option.map doCFG initM,
		      updateM = doCFG updateM,
		      stabilizeM = Option.map doCFG stabilizeM
		    }
		end
	(* process the initial strand creation code *)
	  val create' = (case create of IR.Create{dim, code} => IR.Create{dim = dim, code = doCFG code})
	(* process the global update *)
	  val update' = Option.map doCFG update
        (* check to see if we have created new globals and thus need to update the globalInit block *)
          val (globals', globalInit') = (case !newGlobs
                 of [] => (globals, globalInit)
                  | globs => let
                      fun f ([], globals, stms) = (globals, stms)
                        | f ((gx, x)::globs, globals, stms) = (
                              incUse x;
                              IR.GlobalVar.setBinding(gx, x);
                              f (globs, gx::globals, IR.GASSGN(gx, x)::stms))
                      val (globals', stms) = f (globs, [], [])
                      in
                        (globals @ globals', IR.CFG.appendBlock (globalInit, stms))
                      end
                (* end case *))
          in
            IR.Program{
                props = props,
		consts = consts,
		inputs = inputs,
		constInit = constInit,
                globals = globals',
                globalInit = globalInit',
                strand = strand',
		create = create',
		update = update'
              }
          end
          
  end

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