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.sml
ViewVC logotype

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 4407 - (download) (annotate)
Fri Aug 12 13:33:46 2016 UTC (3 years ago) by jhr
File size: 13374 byte(s)
  working on merge: support for initially method (sequential target)
(* gen.sml
 *
 * Code generation for the sequential and parallel targets.
 *
 * COPYRIGHT (c) 2016 The Diderot Project (http://diderot-language.cs.uchicago.edu)
 * All rights reserved.
 *)

structure Gen : sig

    val exec : TargetSpec.t * TreeIR.program -> unit

    val library : TargetSpec.t * TreeIR.program -> unit

  end = struct

    structure IR = TreeIR
    structure GV = TreeGlobalVar
    structure CL = CLang
    structure Env = CodeGenEnv
    structure Out = CodeOutput
    structure RN = CxxNames
    structure Frags = CPUFragments

    val openCxxOut = Out.openOut {ext = "cxx", ppDecl = PrintAsCxx.output}

    fun mkEnv spec = if TargetSpec.dualState spec
          then Env.new {
              world = RN.worldVar,
              global = RN.globalsVar,
              selfIn = RN.selfInVar,
              selfOut = RN.selfOutVar,
              spec = spec
            }
          else Env.new {
              world = RN.worldVar,
              global = RN.globalsVar,
              selfIn = RN.selfVar,
              selfOut = RN.selfVar,
              spec = spec
            }

  (* create the target-specific substitution list *)
    fun mkSubs (spec, strand, create) = let
          val IR.Strand{name, stateInit, initM, updateM, stabilizeM, ...} = strand
          fun mkMethodArgs (name, NONE) = (name, "")
            | mkMethodArgs (name, SOME(IR.Method{needsW, hasG, ...})) = let
                val value = if needsW
                      then if TargetSpec.isParallel spec then "wrld, " else "this, "
                      else ""
                val value = if hasG then value ^ "glob, " else value
                in
                  (name, value)
                end
          in [
            ("CFILE",                   OS.Path.joinBaseExt{base= #outBase spec, ext= SOME "c"}),
            ("CXXFILE",                 OS.Path.joinBaseExt{base= #outBase spec, ext= SOME "cxx"}),
            ("H_FILE",                  OS.Path.joinBaseExt{base= #outBase spec, ext= SOME "h"}),
            ("PREFIX",                  #namespace spec),
            ("SRCFILE",                 #srcFile spec),
            ("PROG_NAME",               #outBase spec),
            ("STRAND",                  Atom.toString name),
            ("STRANDTY",                Atom.toString name ^ "_strand"),
            ("IS_GRID",                 Bool.toString(#isGrid spec)),
            ("NUM_AXES",                Int.toString(Option.getOpt(Create.gridDim create, 1))),
            ("SPATIAL_DIM",             Int.toString(Option.getOpt(#spatialDim spec, 0))),
            ("DIDEROTC_CMD",            #diderotc spec),
            ("DIDEROTC_ARGV",           String.concatWith " " (#argv spec)),
            ("DIDEROTC_VERSION",        #version spec),
            ("DIDEROT_FLOAT_PRECISION", TargetSpec.floatPrecisionDef spec),
            ("DIDEROT_INT_PRECISION",   TargetSpec.intPrecisionDef spec),
            ("DIDEROT_TARGET",          TargetSpec.targetDef spec),
            ("REALTY",                  if #double spec then "double" else "float"),
            ("INTTY",                   if #longint spec then "int64_t" else "int32_t"),
            ("BOOLTY",                  SizeOf.c_bool),
            mkMethodArgs ("STATE_INIT_ARGS", SOME stateInit),
            mkMethodArgs ("INITIALLY_ARGS", initM),
            mkMethodArgs ("UPDATE_ARGS", SOME updateM),
            mkMethodArgs ("STABILIZE_ARGS", stabilizeM)
          ] end

    fun condCons (true, x, xs) = x::xs
      | condCons (false, _, xs) = xs

    fun verbFrag (spec, parFrag, seqFrag, subs) =
          CL.verbatimDcl [if (TargetSpec.isParallel spec) then parFrag else seqFrag] subs

  (* generate the struct declaration for the global variables *)
(* FIXME: what about constants? *)
    fun genGlobalStruct (env, consts, inputs, globals) =
          if #hasGlobals(Env.target env)
            then let
              fun mkField gv = (TreeToCxx.trType(env, GV.ty gv), GV.qname gv)
              val fields = List.map (mkField o Inputs.varOf) inputs
              val fields = fields @ List.map mkField globals
              in
                [CL.D_StructDef(SOME "globals", fields, NONE)]
              end
            else []

  (* generate code for a user-defined function *)
    fun genFunc spec (IR.Func{name, params, body}) = let
          val (resTy, _) = TreeFunc.ty name
          val (env, params) = List.foldr
                (fn (x, (env, ps)) => let
                    val (env, p) = TreeToCxx.trParam(env, x)
                    in
                      (env, p::ps)
                    end)
                  (Env.empty spec, []) params
          val (env, params) = if TreeFunc.hasGlobals name
                then (
                    Env.insert(env, PseudoVars.global, RN.globalsVar),
                    CL.PARAM([], RN.globalPtrTy, RN.globalsVar) :: params
                  )
                else (env, params)
          val (env, params) = if TreeFunc.needsWorld name
                then (
                    Env.insert(env, PseudoVars.world, RN.worldVar),
                    CL.PARAM([], RN.worldPtrTy, RN.worldVar) :: params
                  )
                else (env, params)
          in
            CL.D_Func([], TreeToCxx.trType(env, resTy), [], TreeFunc.qname name, params,
              TreeToCxx.trBlock (env, body))
          end

(* QUESTION: should init_globals be a member of the world struct? *)
    fun genInitGlobals (env, IR.Block{locals, body}) = let
        (* the init_globals function should return false on success *)
          val body = IR.Block{
                  locals=locals,
                  body=body@[IR.S_Return(IR.E_Lit(Literal.Bool false))]
                }
          in
            CL.D_Func(["static"], CL.boolTy, [], "init_globals",
              [RN.worldParam],
              GenUtil.genBodyWithGlobPtr (env, body))
          end

  (* specialize the fragments that implement the run and run_initially world methods *)
    fun runFrag (spec, subs) = let
	  val code = if TargetSpec.noBSP spec
              then [verbFrag (spec, Frags.parRunNoBSP, Frags.seqRunNoBSP, subs)]
              else [verbFrag (spec, Frags.parRun, Frags.seqRun, subs)]
	  in
	    if #hasInitiallyMeth spec
	      then verbFrag (spec, Frags.parRunInit, Frags.seqRunInit, subs) :: code
	      else code
	  end

    fun compile (spec : TargetSpec.t, basename) = let
        (* generate the C compiler flags *)
          val cflags = ["-I" ^ Paths.diderotInclude(), "-I" ^ Paths.teemInclude()]
          val cflags = condCons (TargetSpec.isParallel spec, #pthread Paths.cxxflags, cflags)
          val cflags = if #debug spec
                then #debug Paths.cxxflags :: cflags
                else #ndebug Paths.cxxflags :: cflags
          val cflags = #base Paths.cxxflags :: cflags
          in
            RunCC.compile (basename, cflags)
          end

    fun ldFlags (spec : TargetSpec.t) = if #exec spec
          then let
            val extraLibs = condCons (TargetSpec.isParallel spec, #pthread Paths.extraLibs, [])
            val extraLibs = Paths.teemLinkFlags() @ #base Paths.extraLibs :: extraLibs
            val rtLib = TargetSpec.runtimeLibName spec
            in
              condCons (TargetSpec.isParallel spec, #pthread Paths.cxxflags, rtLib :: extraLibs)
            end
          else [TargetSpec.runtimeLibName spec]

  (* generate defines that control specialization of the code for various features (e.g.,
   * parallelism, global updates, ...
   *)
    fun outputDefines (outS, spec, substitutions) = let
          val ppDecl = Out.decl outS
          fun pp (true, dcl) = ppDecl (CL.D_Verbatim ["#define " ^ dcl])
            | pp _ = ()
          in
            pp (#hasStabilizeMeth spec, "DIDEROT_HAS_STABILIZE");
            pp (TargetSpec.dualState spec, "DIDEROT_DUAL_STATE");
            pp (not(#hasGlobals spec), "DIDEROT_NO_GLOBALS");
            pp (not(#hasInputs spec), "DIDEROT_NO_INPUTS");
            pp (#hasCom spec, "DIDEROT_HAS_STRAND_COMMUNICATION");
            pp (#hasGlobalInitially spec, "DIDEROT_HAS_GLOBAL_INITIALLY");
            pp (#hasGlobalUpdate spec, "DIDEROT_HAS_GLOBAL_UPDATE");
            pp (#hasReduce spec, "DIDEROT_HAS_MAPREDUCE")
          end

  (* generate source code that is common to both libraries and standalone executables *)
    fun outputSrc (outS, env, spec, prog, strand, substitutions, genInputCode) = let
          val IR.Program{consts, inputs, globals, funcs, globInit, create, init, update, ...} = prog
          val IR.Strand{name=strandName, ...} = strand
          val dim = Create.gridDim create
          val ppDecl = Out.decl outS
          val {structDef, methods} = GenStrand.gen (env, strand)
          val outputs = OutputUtil.gatherOutputs prog
          in
            List.app ppDecl (genGlobalStruct (env, consts, inputs, globals));
            ppDecl structDef;
            ppDecl (GenWorld.genStruct(env, strandName, Option.getOpt(dim, 1)));
            if (TargetSpec.isParallel spec)
              then ppDecl (CL.verbatimDcl [Frags.parExtras] substitutions)
              else ();
            List.app ppDecl (genInputCode());
            List.app (ppDecl o genFunc spec) funcs;
            if #hasGlobalInit spec
              then ppDecl (genInitGlobals (env, globInit))
              else ();
            List.app ppDecl methods;
            List.app ppDecl (GenOutputs.gen (env, dim, outputs));
            ppDecl (CL.verbatimDcl [Frags.worldMethods] substitutions);
            ppDecl (GenWorld.genCreateFun (env, globInit, strand, create));
            List.app ppDecl (runFrag (spec, substitutions));
            Option.app (fn blk => ppDecl (GenGlobalUpdate.gen (env, "initially", blk))) init;
            Option.app (fn blk => ppDecl (GenGlobalUpdate.gen (env, "update", blk))) update
          end

    fun exec (spec : TargetSpec.t, prog) = let
          val IR.Program{inputs, strand, create, ...} = prog
          val env = mkEnv spec
          val baseName = OS.Path.joinDirFile{dir = #outDir spec, file = #outBase spec}
          val substitutions = mkSubs (spec, strand, create)
        (* output to C++ file *)
          val outS = openCxxOut baseName
          val ppDecl = Out.decl outS
          val fragment = Out.fragment substitutions outS
          val {preWorld, postWorld} = GenTysAndOps.gen (env, CollectInfo.collect prog)
          in
            ppDecl (CL.verbatimDcl [CxxFragments.execHead] substitutions);
            outputDefines (outS, spec, substitutions);
            ppDecl (CL.verbatimDcl [CxxFragments.execIncl] substitutions);
            List.app ppDecl preWorld;
            ppDecl (CL.verbatimDcl [CxxFragments.namespaceOpen] substitutions);
            ppDecl (CL.verbatimDcl [CxxFragments.nrrdSaveHelper] substitutions);
            outputSrc (outS, env, spec, prog, strand, substitutions,
              fn () => (
                postWorld @
                GenInputs.genInputsStruct (env, inputs) @
                GenInputs.genExecInputFuns (env, prog) @
                GenOutputsUtil.genRegisterOutputOpts (env, OutputUtil.gatherOutputs prog)));
            ppDecl (CL.verbatimDcl [CxxFragments.namespaceClose] substitutions);
          (* generate main function after closing off the namespace *)
            ppDecl (verbFrag (spec, Frags.parMain, Frags.seqMain, substitutions));
            Out.closeOut outS;
            compile (spec, baseName);
            RunCC.linkExec (baseName, ldFlags spec)
          end

    fun library (spec : TargetSpec.t, prog) = let
          val IR.Program{inputs, strand, create, ...} = prog
          val env = mkEnv spec
          val baseName = OS.Path.joinDirFile{dir = #outDir spec, file = #outBase spec}
          val substitutions = mkSubs (spec, strand, create)
        (* output to C++ file *)
          val outS = openCxxOut baseName
          val ppDecl = Out.decl outS
          val fragment = Out.fragment substitutions outS
        (* gather the outputs *)
          val outputs = OutputUtil.gatherOutputs prog
          val {preWorld, postWorld} = GenTysAndOps.gen (env, CollectInfo.collect prog)
          in
          (* generate the library .h file *)
            GenLibraryInterface.gen {
                subs = substitutions,
                env = env,
                rt = NONE, (* ?? *)
                inputs = inputs,
                outputs = outputs
              };
            ppDecl (CL.verbatimDcl [CxxFragments.libCXXHead] substitutions);
            outputDefines (outS, spec, substitutions);
            ppDecl (CL.verbatimDcl [CxxFragments.libCXXIncl] substitutions);
            List.app ppDecl preWorld;
            ppDecl (CL.verbatimDcl [CxxFragments.namespaceOpen] substitutions);
            ppDecl (CL.verbatimDcl [CxxFragments.nrrdSaveHelper] substitutions);
            List.app ppDecl (GenInputs.genDefinedInpStruct inputs);
            outputSrc (outS, env, spec, prog, strand, substitutions,
              fn () => (postWorld @ GenInputs.genLibraryInputFuns (env, prog)));
            ppDecl (CL.verbatimDcl [CxxFragments.namespaceClose] substitutions);
            ppDecl (CL.verbatimDcl [Frags.cWrappers] substitutions);
            Out.closeOut outS;
          (* compile and link *)
            compile (spec, baseName);
            RunCC.linkLib (baseName, ldFlags spec)
          end

  end

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