Copyright (c) 2012 Toivo Henningsson ([email protected]), see LICENSE.md
This is a small suite of tools aimed at being able to write kernels in Julia,
which could be executed on the CPU, or as GPU kernels.
The idea is to implement a subset of Julia that can be easily converted into a kernel.
(Though the syntax dest[...] is only supported in @kernel blocks.)
The pipeline structure of the code should also allow to plug other front/back ends onto
the internal transformations.
The current version has a simple Julia backend;
speed seems to be somewhat slower than a handcoded kernel.
v0.1: Changed syntax from @kernel begin to @kernel let and eliminated nd parameter.
Pulled apart flatten to form tangle, DAG, transforms and untangle.
Added pretty-printing of DAGs and ASTs.
The currently supported syntax is
@kernel let
A = B.*C + D
dest1[...] = A
dest2[...] = A + C
end
which would be roughly equivalent to
let
A = B.*C + D
dest1[:,:] = A
dest2[:,:] = A + C
end
if A, B, C, D are 2d Arrays of the same size.
The [...] syntax expands within the @kernel block to denote an apropriate number of :.
One difference is that the value of the @kernel let block is nothing.
(Planned: allow to specify a value/value tuple) as the last expression in a @kernel block)
Example usage: see test/test_kernels.jl
The internal structure of julia-kernels is currently
DAG
^
+-------------+------------+
Front end Mid section Back end
^ ^ ^
+-------------+------------+
Main
The DAG subpackage encompasses directed acyclic graph (DAG)
representation of computations, and graph manipulation.
This DAG format is the common language of the other parts.
Main connects everything together and implements the @kernel macro.
Files: dag/dag.jl The Node and Expression types
dag/transforms.jl Tools for transforming DAGs
dag/pshow_dag.jl Pretty-printing of DAGs.
Relies on prettyshow/prettyshow.jl
The basic DAG structure is heavily inspired of julia ASTs. A DAG can represent linear julia code, but also other things. A DAG is easier to manipulate than an AST, e g since one can use dispatch on node types, and add metadata to nodes.
DAG nodes are represented by the type Node{T<:Expression} defined in dag/dag.jl.
Each node has a value val::T particular to its type,
and a vector of arguments args::Vector{Node}
that contains all the node's dependencies on other nodes.
Node types are distinguished by the type T<:Expression of val.
There is a hierarchy of Expression types in dag/dag.jl,
and a corresponding hierarchy of Node types.
A DAG is represented by its sink node, which depends directly or indirectly
on all other nodes in the DAG. The code uses a TupleNode as a supersink to gather multiple sinks.
dag/transforms.jl contains tools to transform DAGs into new DAGs (or other things). The convention is that a DAG is immutable once it is created; all transformations create new DAGs.
dag/pshow_dag.jl implements pretty-printing of DAG:s by
pshow(sink)/pprint(sink). See test/test_pshow_dag.jl for an example.
The underlying prettyshow/prettyshow.jl can also
be used to pretty print julia ASTs, see test/test_pshow_expr.jl.
tangle.jl transforms julia ASTs into DAGs.
midsection.jl implements transformations input DAG -> kernel DAG.
julia_backend.jl implements untangle(sink::Node) to create a
julia AST from a DAG.
It also contains wrap_kernel_body() to add the necessary for loops around
the raw julia kernel code.
kernels.jl implements the @kernel macro.
It ties the parts together to form the processing chain
AST --> raw DAG --> general DAG --> argument type specific DAG --> kernel
Front end | Front midsection | Back midsection | Back end
Front half | Back half
utils/ contains various utils used by different files.
I want to thank Jeff Bezanson for creating the @staged macro,
(in utils/staged.jl) which I'm using for argument type specialization. Great work!