Code Generation
Types
ComputableDAGs.FunctionCall
— TypeFunctionCall{VAL_T<:Tuple,FUNC_T<:Union{Function,Expr}}
Representation of a function call. Contains the function to call (or an expression of a value to assign), value arguments of type VAL_T
, argument symbols, the return symbol(s) and type(s) and the device to execute on.
To support vectorization, i.e., calling the same function on multiple inputs (SIMD), the value arguments, arguments, and return symbols are each vectors of the actual inputs. In the non-vectorized case, these Vector
s simply always have length 1. For this common case, a special constructor exists which automatically wraps each of these arguments in a Vector
.
Type Arguments
VAL_T<:Tuple
: A tuple of all the value arguments that are passed to the function when it's called.FUNC_T<:Union{Function, Expr}
: The type of the function.Function
is the default, but in some cases, anExpr
of a value can be necessary to assign to the return symbol. In this case, no arguments are allowed.
Fields
func::FUNC_T
: The function to be called, or an expression containing a value to assign to the return_symbol.value_arguments::Vector{VAL_T}
: The value arguments for the function call. These are passed first to the function, in the order given here. TheVector
contains the tuple of value arguments for each vectorization member.arguments::Vector{Vector{Symbol}}
: The first vector represents the vectorization, the second layer represents the symbols that will be passed as arguments to the function call.return_symbols::Vector{Vector{Symbol}}
: As with the arguments, the first vector level represents the vectorization, the second represents the symbols that the results of the function call are assigned to. For most function calls, there is only one return symbol. When using closures when generating a function body for aTape
, the option to have multiple return symbols is necessary.return_types::Vector{<:Type}
: The types of the function call with the arguments provided. This field only contains one level of Vector, because it is required that aFunctionCall
is type stable, and therefore, the types of the return symbols have to be equal for all members of a vectorization. The return type is initially set toNothing
and later inferred and assigned byinfer_types!
.device::AbstractDevice
: The device that this function call is scheduled on.
ComputableDAGs.Tape
— TypeTape{INPUT}
Lowered representation of a computation, generated from a DAG
through gen_tape
.
INPUT
the input type of the problem instance, see also the interface functioninput_type
Fields
input_assign_code::Vector{FunctionCall}
: TheFunctionCall
s representing the input assignments, mapping part of the input of the computation to each DAG entry node. These functions are generated using the interface functioninput_expr
.schedule::Vector{FunctionCall}
: TheFunctionCall
s representing the function body of the computation. There is one function call for each node in theDAG
.output_symbol::Symbol
: The symbol of the final calculated value, which is returned.instance::Any
: The instance that this tape is generated for.machine::Machine
: TheMachine
that this tape is generated for.
Function Generation
Implementations for generation of a callable function. A function generated this way cannot immediately be called. One Julia World Age has to pass before this is possible, which happens when the global Julia scope advances. If the DAG and therefore the generated function becomes too large, use the tape machine instead, since compiling large functions becomes infeasible.
ComputableDAGs.get_compute_function
— Methodget_compute_function(
graph::DAG,
instance,
machine::Machine,
context_module::Module
)
Return a function of signature compute_<id>(input::input_type(instance))
, which will return the result of the DAG computation on the given input. The final argument context_module
should always be @__MODULE__
to be able to use functions defined in the caller's environment. For this to work, you need
using RuntimeGeneratedFunctions
RuntimeGeneratedFunctions.init(@__MODULE__)
in your top level.
Keyword Arguments
closures_size
(default=0 (off)): The size of closures to use in the main generated code. This specifies the size of code blocks across which the compiler cannot optimize. For sufficiently large functions, a larger value means longer compile times but potentially faster execution time. Note that the actually used closure size might be different than the one passed here, since the function automatically chooses a size that is close to a n-th root of the total number of loc, based off the given size. concrete_input_type
(default=input_type(instance)
): A type that will be used as the expected input type of the generated function. If omitted, the input_type
of the problem instance is used. Note that the input_type
of the instance will still be used as the annotated type in the generated function header.
Tape Machine
ComputableDAGs._closure_fc
— Method_closure_fc(
code_block::AbstractVector{FunctionCall},
types::Dict{Symbol,Type},
machine::Machine,
undefined_argument_symbols::Set{Symbol},
context_module::Module,
)
From the given function calls, make and return 2 function calls representing all of them together. 2 function calls are necessary, one for setting up the anonymous function and the second for calling it. The undefinedargumentsymbols is the set of all Symbols that need to be returned if available inside the code_block. They get updated inside this function.
ComputableDAGs.gen_function_body
— Methodgen_function_body(tape::Tape, context_module::Module; closures_size)
Generate the function body from the given Tape
.
Keyword Arguments
closures_size
: The size of closures to generate (in lines of code). Closures introduce function barriers in the function body, preventing some optimizations by the compiler and therefore greatly reducing compile time. A value of 0 will disable the use of closures entirely. concrete_input_type
: A type that will be used as the expected input type of the generated function. If omitted, the input_type
of the problem instance is used.
ComputableDAGs.gen_input_assignment_code
— Methodgen_input_assignment_code(
input_symbols::Dict{String, Vector{Symbol}},
instance::Any,
machine::Machine,
input_type::Type,
context_module::Module
)
Return a Vector{Expr}
doing the input assignments from the given problem_input
onto the input_symbols
.
ComputableDAGs.gen_tape
— Functiongen_tape(
graph::DAG,
instance::Any,
machine::Machine,
context_module::Module,
scheduler::AbstractScheduler = GreedyScheduler()
)
Generate the code for a given graph. The return value is a Tape
.