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 4349 - (download) (annotate)
Tue Aug 2 18:14:48 2016 UTC (3 years, 5 months ago) by jhr
File size: 13767 byte(s)
  Working on merge: spatial query support
(* 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

    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))),
            ("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

  (* generate code for a block, where we optionally add a local variable that points
   * to the globals struct.
   *)
    fun genBodyWithGlobPtr (env, IR.Block{locals, body}) = let
          fun mkBody env = let
                val stms = #2(TreeToCxx.trStms(env, body))
                val stms = if #hasGlobals(Env.target env)
                      then CL.mkDeclInit(
                          RN.globalPtrTy, RN.globalsVar,
                          CL.mkIndirect(CL.mkVar(Env.world env), "_globals")
                        ) :: stms
                      else stms
                in
                  stms
                end
          in
            TreeToCxx.trWithLocals (env, !locals, mkBody)
          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],
              genBodyWithGlobPtr (env, body))
          end

  (* generate the global initially code, which runs after the initial strands have been
   * created, but before the first super-step.
   *)
    fun genGlobalInitially (env, body) = let
          val env = Env.insert(env, PseudoVars.world, "this")
          in
            CL.D_Func([], CL.voidTy, [], "world::global_initially",
              [],
              genBodyWithGlobPtr (env, body))
          end

  (* generate the global-update code *)
    fun genGlobalUpdate (env, body) =let
          val env = Env.insert(env, PseudoVars.world, "this")
          in
            CL.D_Func([], CL.voidTy, [], "world::global_update",
              [],
              genBodyWithGlobPtr (env, body))
          end

    fun runFrag (spec, subs) = if TargetSpec.noBSP spec
            then verbFrag (spec, CPUFragments.parallelRunNoBSP, CPUFragments.sequentialRunNoBSP, subs)
            else verbFrag (spec, CPUFragments.parallelRun, CPUFragments.sequentialRun, subs)

    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 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
            if (TargetSpec.isParallel spec)
              then ppDecl (CL.verbatimDcl [CPUFragments.parallelExtras] substitutions)
              else ();
            if TargetSpec.dualState spec
              then ppDecl (CL.D_Verbatim ["#define DIDEROT_DUAL_STATE\n"])
              else ();
            if not(#hasGlobals spec)
              then ppDecl (CL.D_Verbatim ["#define DIDEROT_NO_GLOBALS\n"])
              else ();
            if not(#hasInputs spec)
              then ppDecl (CL.D_Verbatim ["#define DIDEROT_NO_INPUTS\n"])
              else ();
            if #hasGlobalUpdate spec
              then ppDecl (CL.D_Verbatim ["#define DIDEROT_HAS_GLOBAL_UPDATE\n"])
              else ();
            List.app ppDecl (genGlobalStruct (env, consts, inputs, globals));
            ppDecl structDef;
            ppDecl (GenWorld.genStruct(env, strandName, Option.getOpt(dim, 1)));
            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 [CPUFragments.worldMethods] substitutions);
            ppDecl (GenWorld.genInitiallyFun (env, globInit, strand, create));
            ppDecl (runFrag (spec, substitutions));
            Option.app (fn blk => ppDecl (genGlobalInitially (env, blk))) init;
            Option.app (fn blk => ppDecl (genGlobalUpdate (env, 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
          in
            ppDecl (CL.verbatimDcl [CxxFragments.execHead] substitutions);
            List.app ppDecl (GenTysAndOps.gen (env, CollectInfo.collect prog));
            ppDecl (CL.verbatimDcl [CxxFragments.namespaceOpen] substitutions);
            ppDecl (CL.verbatimDcl [CxxFragments.nrrdSaveHelper] substitutions);
            outputSrc (outS, env, spec, prog, strand, substitutions,
              fn () => (
                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, CPUFragments.parallelMain, CPUFragments.sequentialMain, 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
          in
          (* generate the library .h file *)
            GenLibraryInterface.gen {
                subs = substitutions,
                env = env,
                rt = NONE, (* ?? *)
                inputs = inputs,
                outputs = outputs
              };
            ppDecl (CL.verbatimDcl [CxxFragments.libCXXHead] substitutions);
            List.app ppDecl (GenTysAndOps.gen (env, CollectInfo.collect prog));
            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 () => (GenInputs.genLibraryInputFuns (env, prog)));
            ppDecl (CL.verbatimDcl [CxxFragments.namespaceClose] substitutions);
            ppDecl (CL.verbatimDcl [CPUFragments.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