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

SCM Repository

[diderot] View of /branches/vis12-cl/src/compiler/cl-target/gen-output.sml
ViewVC logotype

View of /branches/vis12-cl/src/compiler/cl-target/gen-output.sml

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2743 - (download) (annotate)
Sun Sep 28 02:54:54 2014 UTC (6 years, 2 months ago) by jhr
File size: 6379 byte(s)
  Working on OpenCL support
(* gen-output.sml
 *
 * COPYRIGHT (c) 2014 The Diderot Project (http://diderot-language.cs.uchicago.edu)
 * All rights reserved.
 *
 * Generate strand output functions for the OpenCL target.  The output formats always have
 * a single axis for the data elements followed by one, or more, axes for the output structure.
 * There are two cases that we handle:
 *
 *	grid, fixed-size elements:
 *		nrrd has object axis followed by grid axes
 *
 *	collection, fixed-size elements
 *		nrrd has object axis followed by a single axis
 *
 * NOTE: the C target also supports dynamic-sized elements (i.e., dynamic sequences), but the
 * OpenCL target does not support these yet.
 *
 * The object axis kind depends on the output type, but it will either be one of the tensor types
 * that Teem knows about or else nrrdKindList.  In any case, the data elements are written as a
 * flat vector following the in-memory layout.  The other axes in the file will have nrrdKindSpace
 * as their kind.
 *
 * TODO: some of this code is common with c-target/gen-output.sml (e.g., writing outputs to
 * files), so we should refactor it.
 *
 * TODO: for sequences of tensors (e.g., tensor[3]{2}), we should use a separate axis for the
 * sequence dimension with kind nrrdKindList.
 *)

structure GenOutput : sig

  (* gen (props, nAxes) outputs
   *	returns code for getting the output/snapshot nrrds from the program state.
   *    The arguments are:
   *	    props	- the target information
   *	    nAxes	- the number of axes in the grid of strands (NONE for a collection)
   *	    outputs	- the list of output state variables paired with their TreeIL types
   *    The return value is a record {kernels, getFns}, where
   *	    kernels	- list of OpenCL kernels used to get output variables
   *	    getFns	- list of function declarations that implement the public
   *			  output and snapshot queries.
   *)
    val gen : Properties.props * int option -> (TreeIL.Ty.ty * string) list -> CLang.decl list

    val genKernels : Properties.props * int option -> (TreeIL.Ty.ty * string) list -> CLang.decl list

  end = struct

    structure IL = TreeIL
    structure V = IL.Var
    structure Ty = IL.Ty
    structure CL = CLang
    structure RN = RuntimeNames
    structure Nrrd = NrrdEnums
    structure U = CLUtil

    fun mapi f l = let
	  fun mapf (i, [], l) = List.rev l
	    | mapf (i, x::xs, l) = mapf (i+1, xs, f(i, x)::l)
	  in
	    mapf (0, l, [])
	  end

    val nrrdPtrTy = CL.T_Ptr(CL.T_Named "Nrrd")
    val sizeTy = CL.T_Named "size_t"
    fun wrldPtr tgt = CL.T_Ptr(CL.T_Named(RN.worldTy tgt))
    fun globPtr tgt = CL.T_Ptr(CL.T_Named(CLNames.globalsTy tgt))
    fun mkInt i = CL.mkInt(IntInf.fromInt i)
	      
  (* variables in the generated code *)
    val wrldV = CL.mkVar "wrld"
    val sizesV = CL.mkVar "sizes"
    val nDataV = CL.mkVar "nData"

  (* utility functions for initializing the sizes array *)
    fun sizes i = CL.mkSubscript(sizesV, mkInt i)
    fun setSizes (i, v) = CL.mkAssign(sizes i, v)

  (* create a kernel for copying the given output state variable to the output
   * buffer.
   *)
(* NOTES: if the output is a grid, then we want to use the grid indices as a guide for processing
 * the output.  Otherwise, the order does not matter, but we do need to worry about synchronizing
 * writes to the output buffer.
 *)
    fun mkCopyKernel tgt (ty : TreeIL.Ty.ty, name) = let
	  val ty' = CLTyTranslate.toGPUType ty
	  val body = CL.mkBlock[]  (* FIXME *)
	  in
	    U.mkKernel(
	      name ^ "Kern",
	      [U.globalParam(globPtr tgt, "glob"), U.globalParam(CL.T_Ptr ty', "outBuf")],
	      body)
	  end

  (* create the body of an output function for fixed-size outputs.  The structure of the
   * function body is:
   *
   *	declare and compute sizes array
   *	allocate GPU data object
   *	invoke kernel to copy data from strand state into data buffer
   *	allocate nrrd nData
   *	copy data from GPU to nrrd
   *)
    fun genFixedOutput (tgt, snapshot, nAxes, ty, name) = let
	  val (elemCTy, nrrdType, axisKind, nElems) = OutputUtil.infoOf (tgt, ty)
	  val (isArray, nAxes, domAxisKind) = (case nAxes
		 of NONE => (false, 1, Nrrd.KindList)
		  | SOME n => (true, n, Nrrd.KindSpace)
		(* end case *))
          val nDataAxes = if (axisKind = Nrrd.KindScalar) then 0 else 1
	(* generate the sizes initialization code *)
	  val initSizes = let
		val dimSizes = let
                      val dcl = CL.mkDecl(CL.T_Array(sizeTy, SOME(nAxes+nDataAxes)), "sizes", NONE)
                      in
                        if (axisKind = Nrrd.KindScalar)
                          then [dcl]
                          else [dcl, setSizes(0, mkInt nElems)]
                      end
		in
		  if isArray
		    then dimSizes @
		      List.tabulate (nAxes, fn i =>
			setSizes(i+nDataAxes, CL.mkSubscript(CL.mkIndirect(wrldV, "size"), mkInt(nAxes-i-1))))
		    else raise Fail "output for collection is unimplemented"
		end
	(* code to copy the data from the GPU *)
	  val copyCode = [] (* FIXME *)
	(* the function body *)
	  val stms =
		CL.mkComment["Compute sizes of nrrd file"] ::
		initSizes @
		CL.mkComment["Allocate GPU buffer"] ::
		CL.mkComment["Run copy kernel"] ::
		CL.mkComment["Allocate nData nrrd"] ::
		OutputUtil.maybeAlloc (nDataV, Nrrd.tyToEnum  nrrdType, nAxes+nDataAxes) ::
		CL.mkComment["copy data to output nrrd"] ::
		copyCode @
		[CL.mkReturn(SOME(CL.mkVar "false"))]
	  in
	    ([CL.PARAM([], nrrdPtrTy, "nData")], CL.mkBlock stms)
	  end

    fun gen (tgt : Properties.props, nAxes) = let
	  fun getFn snapshot (ty, name) = let
		val funcName = if snapshot
		      then RN.snapshotGet(tgt, name)
		      else RN.outputGet(tgt, name)
		fun mkFunc (params, body) =
		      CL.D_Func([], CL.boolTy, funcName, CL.PARAM([], wrldPtr tgt, "wrld")::params, body)
		in
		  case ty
		   of Ty.DynSeqTy ty' => raise Fail "dynamic sequences not supported for OpenCL"
		    | _ => mkFunc (genFixedOutput(tgt, snapshot, nAxes, ty, name))
		  (* end case *)
		end
	  fun gen' outputs = let
		val getFns = List.map (getFn false) outputs
		val allFns = if (#exec tgt)
			then getFns @ OutputUtil.genOutput(tgt, outputs)
		      else if (#snapshot tgt)
			then List.map (getFn true) outputs @ getFns
			else getFns
		in
		  allFns
		end
	  in
	    gen'
	  end

    fun genKernels (tgt : Properties.props, nAxes) = List.map (mkCopyKernel tgt)
		      
  end

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