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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3931 - (download) (annotate)
Sun Jun 5 14:13:21 2016 UTC (3 years ago) by jhr
File size: 13328 byte(s)
  working on merge: code generation
(* gen-inputs.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.
 *
 * Generate code to handle input variables for the C target.
 *)

structure GenInputs : sig

  (* input variable descriptor: type, name, description, and default *)
    type input_desc = GenInputsUtil.input_desc

  (*** Support for standalone executables ***)

  (* generate the input initialization structure that we use to initialize input
   * globals from command-line arguments in stand-alone executables.
   *)
    val genInputsStruct : CodeGenEnv.t * input_desc list -> CLang.decl list

  (* generate the functions that handle inputs for standalone executables.  These are:
   *    init_defaults    -- called to initialize the default input values
   *    register_inputs  -- called to register the command-line options for the input globals
   *    init_inputs      -- called to initialize the input globals from the values specified
   *                        on the command line.
   *)
    val genExecInputFuns : CodeGenEnv.t * TreeIR.program -> CLang.decl list

  (*** Support for libraries ***)

  (* generate the typedef for the defined-input flag struct. *)
    val genDefinedInpStruct : input_desc list -> CLang.decl list

  (* generated the functions to initialize inputs for the library API.  This function also
   * generates the function to initialize the defined input flags struct.
   *)
    val genInputFuns : CodeGenEnv.t * input_desc list -> CLang.decl list

  end = struct

    structure IR = TreeIR
    structure Ty = APITypes
    structure GVar = TreeGlobalVar
    structure CL = CLang
    structure RN = CxxNames
    structure ToC = TreeToCxx
    structure U = GenInputsUtil
    structure Env = CodeGenEnv
    structure GenAPI = GenLibraryInterface
    structure Inp = Inputs

    type input_desc = U.input_desc

    val genInputsStruct = U.genInputsStruct
    val genDefinedInpStruct = U.genDefinedInpStruct

  (* translate an API type to the C types used to represent it in the external API *)
    val trType = CodeGenUtil.trAPIType

    val nrrdPtrTy = CL.T_Ptr(CL.T_Named "Nrrd")

  (* world pointer *)
    val wrldV = CL.mkVar "wrld"

  (* an l-value expression for accessing a global variable *)
    fun global gv = CL.mkIndirect(CL.mkIndirect(CL.mkVar "wrld", "_globals"), GVar.qname gv)

  (* define a function that is exported to C *)
    fun cFunc (ty, name, params, body) = CL.D_Func(["extern \"C\""], ty, name, params, body)

  (* generate code to initialize the global input variables from the command-line inputs *)
    fun genInitInputs (env, inputs) = let
        (* the world pointer type *)
          val worldPtrTy = RN.worldPtrTy
        (* the global state pointer type *)
          val globPtrTy = RN.globalPtrTy
        (* some common variables *)
          val inpV = CL.mkVar "inp"
          val optsV = CL.mkVar "opts"
        (* initialize a given input global; for sequences and images, this requires
         * loading the value from the specified nrrd file, while for other types
         * we just copy the values.
         *)
          fun initInput (Inp.INP{var, name, ty, desc, init}, stms) = (case ty
                 of Ty.SeqTy(elemTy, NONE) => let
                      val (loadFn, nDims, dims) = (case elemTy
                             of Ty.BoolTy => ("diderot::load_dynseq<bool>", CL.mkInt 0, CL.mkInt 0)
                              | Ty.IntTy => ("Diderot_DynSeqLoadIntFromFile", CL.mkInt 0, CL.mkInt 0)
                              | Ty.TensorTy[] => ("Diderot_DynSeqLoadRealFromFile", CL.mkInt 0, CL.mkInt 0)
                              | Ty.TensorTy _ => raise Fail "TODO: sequences of tensors"
                              | Ty.SeqTy elemTy => raise Fail "TODO: sequences of sequences"
                              | _ => raise Fail "unsupported dynamic sequence type"
                            (* end case *))
                      in
                        CL.mkAssign(global var,
                          CL.mkApply(loadFn, [wrldV, CL.mkIndirect(inpV, GVar.name var), nDims, dims])) ::
                        CL.mkIfThen(CL.mkBinOp(global var, CL.#==, CL.mkInt 0),
                          CL.mkReturn(SOME(CL.mkVar "true"))) :: stms
                      end
                  | Ty.ImageTy(dim, _) => let
                      val loadFn = (case dim
                             of 1 => "Diderot_LoadImage1D"
                              | 2 => "Diderot_LoadImage2D"
                              | 3 => "Diderot_LoadImage3D"
                              | _ => raise Fail "image with dimension > 3"
                            (* end case *))
                      in
                        CL.mkIfThen(
                          CL.mkApply(loadFn, [
			      wrldV, CL.mkIndirect(inpV, GVar.name var), CL.mkAddrOf(global var)
			    ]),
                          CL.mkReturn(SOME(CL.mkVar "true"))) :: stms
                      end
                  | ty => U.copy{
			env=env, ty=ty, dst=global var, src=CL.mkIndirect(inpV, GVar.qname var)
		      } :: stms
                (* end case *))
          in
            CL.D_Func(
              ["static"], CL.boolTy, "init_inputs",
              [CL.PARAM([], worldPtrTy, "wrld"), CL.PARAM([], RN.inputsPtrTy, "inp")],
              CL.mkBlock(
                CL.mkDeclInit(globPtrTy, RN.globalsVar, CL.mkIndirect(CL.mkVar "wrld", "_globals")) ::
                List.foldr initInput [CL.mkReturn(SOME(CL.mkVar "false"))] inputs))
          end

  (* generate the functions that handle inputs for standalone executables.  These are:
   *    init_defaults    -- called to initialize the default input values
   *    register_inputs  -- called to register the command-line options for the input globals
   *    init_inputs      -- called to initialize the input globals from the values specified
   *                        on the command line.
   *)
    fun genExecInputFuns (env, prog as IR.Program{inputs, ...}) =
	  if List.null inputs
	    then []
	    else U.genExecInputFuns (env, prog) @ [genInitInputs (env, inputs)]

    fun genCheckInputs (env, inputs) = let
        (* the world pointer type *)
          val worldPtrTy = RN.worldPtrTy
          val wrldParam = CL.PARAM([], worldPtrTy, "wrld")
        (* check that the specified input has been defined and, if not, define it to its default *)
          fun check (Inp.INP{var, name, ty, init, ...}) = let
		fun undef () = CL.mkBlock[
			ToC.errorMsgAdd(env, CL.mkStr(concat["undefined input \"", name, "\"\n"])),
			CL.mkReturn(SOME(CL.mkBool true))
		      ]
                val dfltStm = (case init
		       of Inp.NoDefault => undef ()
			| Inp.ConstExpr => CL.mkBlock[] (* initialization was handled in constInit *)
			| Inp.LoadSeq file =>
			    GenLoadNrrd.loadSeqFromFile (global var, ty, CL.mkStr file)
			| Inp.Proxy(file, _) => GenLoadNrrd.loadImage (global var, CL.mkStr file)
			| Inp.Image _ => undef ()
		      (* end case *))
                in
                  CL.mkIfThen(CL.mkUnOp(CL.%!, U.defined var), dfltStm)
                end
          in
            CL.D_Func(
              ["static"], CL.boolTy, "check_defined",
              [wrldParam],
              CL.mkBlock(List.map check inputs @ [CL.mkReturn(SOME(CL.mkBool false))]))
          end

  (* for each input variable we generate two or three top-level declarations in the
   * exported API.
   *)
    fun genInputFuns (_, []) = []
      | genInputFuns (env, inputs) = let
	  val spec = Env.target env
        (* the world pointer type *)
          val worldPtrTy = RN.worldPtrTy
          val wrldParam = CL.PARAM([], worldPtrTy, "wrld")
        (* create decls for an input variable *)
          fun mkInputDecls (Inp.INP{var, name, ty, desc, init}) = let
              (* create a description declaration for the input variable *)
                val descDcl = (case desc
                       of SOME desc => [
                              CL.D_Var([], CL.T_Ptr(CL.T_Named "const char"),
                                GenAPI.inputDesc(spec, name),
                                SOME(CL.I_Exp(CL.mkStr desc)))
                            ]
                        | NONE => []
                      (* end case *))
                val getDcl = if (Inp.isDefault init)
                        then let
                          val getName = GenAPI.inputGet(spec, name)
                        (* generate code for a function that returns the current value of
                         * an input global.
                         *)
                          fun mkFunc outTy = cFunc(
				CL.voidTy, getName,
                                [wrldParam, CL.PARAM([], outTy, "v")],
                                U.copy {
				    env = env,
                                    ty = ty,
                                    dst = (case outTy
                                         of CL.T_Ptr _ => CL.mkUnOp(CL.%*, CL.mkVar "v")
                                          | CL.T_Array _ => CL.mkVar "v"
                                          | _ => raise Fail "not l-value type"
                                        (* end cade *)),
                                    src = global var
                                  })
(* FIXME: for images and sequences, it is not clear what the get function should return.
 * For now, we just return 0
 *)
                        (* for images and sequences, we currently return 0 *)
                          fun nrrdFunc () = cFunc(
				CL.voidTy, getName,
                                [wrldParam, CL.PARAM([], CL.T_Ptr CL.voidPtr, "v")],
                                CL.mkAssign(CL.mkUnOp(CL.%*, CL.mkVar "v"), CL.mkInt 0))
                          val func = (case ty
                                 of Ty.BoolTy => mkFunc(CL.T_Ptr(trType(env, ty)))
                                  | Ty.StringTy => mkFunc(CL.T_Ptr(trType(env, ty)))
                                  | Ty.IntTy => mkFunc(CL.T_Ptr(trType(env, ty)))
                                  | Ty.TensorTy[] => mkFunc(CL.T_Ptr(trType(env, ty)))
                                  | Ty.TensorTy _ => mkFunc(trType(env, ty))
                                  | Ty.SeqTy(_, SOME _) => mkFunc(trType(env, ty))
                                  | Ty.SeqTy(_, NONE) => nrrdFunc ()
                                  | Ty.ImageTy _ => nrrdFunc ()
                                (* end case *))
                          in
                            [func]
                          end
                        else []
                val setDcl = (case ty
                       of Ty.ImageTy _ => [
                              cFunc(
                                CL.boolTy, GenAPI.inputSetByName(spec, name),
                                [wrldParam, CL.PARAM(["const"], CL.charPtr, "s")],
                                CL.appendStm(
                                  GenLoadNrrd.loadImage (global var, CL.mkVar "s"),
                                  CL.mkReturn(SOME(CL.mkBool false)))),
                              cFunc(
                                CL.boolTy, GenAPI.inputSet(spec, name),
                                [wrldParam, CL.PARAM([], nrrdPtrTy, "nin")],
                                CL.appendStm(
                                  GenLoadNrrd.loadImage (global var, CL.mkVar "nin"),
                                  CL.mkReturn(SOME(CL.mkBool false))))
                            ]
                        | Ty.SeqTy(elemTy, NONE) => [
                              cFunc(
                                CL.boolTy, GenAPI.inputSetByName(spec, name),
                                [wrldParam, CL.PARAM(["const"], CL.charPtr, "s")],
                                CL.appendStm(
                                  GenLoadNrrd.loadSeqFromFile (global var, elemTy, CL.mkVar "s"),
                                  CL.mkReturn(SOME(CL.mkBool false)))),
                              cFunc(
                                CL.boolTy, GenAPI.inputSet(spec, name),
                                [wrldParam, CL.PARAM([], nrrdPtrTy, "nin")],
                                CL.appendStm(
                                  GenLoadNrrd.loadSeq (global var, elemTy, CL.mkVar "nin"),
                                  CL.mkReturn(SOME(CL.mkBool false))))
                            ]
                        | _ => [
                              cFunc(
                                CL.boolTy, GenAPI.inputSet(spec, name),
                                [wrldParam, CL.PARAM([], trType(env, ty), "v")],
                                CL.mkBlock(
                                  CL.mkAssign(U.defined var, CL.mkBool true) ::
                                  U.copy {env=env, ty=ty, dst=global var, src=CL.mkVar "v"} ::
                                    [CL.mkReturn(SOME(CL.mkVar "false"))]))
                            ]
                      (* end case *))
                in
                  (descDcl @ getDcl @ setDcl)
                end
          val extras = [
                  genCheckInputs (env, inputs),
                  U.genDefineInp inputs
                ]
          in
            List.foldr (fn (input, dcls) => mkInputDecls input @ dcls) extras inputs
          end

  end

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