Converts a traced AnvlGraph into the StableHLO intermediate representation (IR),
building a stablehlo::Func with the stablehlo package.
Each statement of the graph is translated to its corresponding StableHLO op. The result can
be serialized to MLIR text via stablehlo::repr() and subsequently compiled to an
XLA executable with pjrt::pjrt_compile().
The rule for translating a primitive to stablehlo is prim_<name>[["stablehlo"]].
The arguments of the resulting function are, in this order: the graph's
constants (when constants_as_inputs = TRUE), the graph's inputs, and the
phantom donated inputs (when donate_unaliased_outputs = TRUE), one per
output that is not already aliased to a donated input, in the order of the
outputs.
This is a low-level function; most users should use jit() instead.
Arguments
- graph
(
AnvlGraph)
The graph to lower (e.g. produced bytrace_fn()).- id
(
character(1))
The id of the resulting StableHLO function. Use"main"(the default) for a top-level lowering (returning from themainfunction finalizes the module) and""for a closure/region lowering (e.g. a while body or a scatter update computation) that builds an anonymous nested function inside an enclosing build.- captured
(
list(FuncValue))
Values of the enclosing function to bind the graph's lastlength(captured)inputs to. The lowered function reads them the way an MLIR region captures a value from above, instead of declaring them as inputs. Used for the sub-graphs of higher-order primitives (e.g.nv_while), whose trailing inputs are the values they close over. The graph's constants always become inputs, andGraphLiterals are always inlined.- donate
(
character())
Names of the arguments whose buffers should be donated. Donated buffers can be aliased with outputs of the same type, enabling in-place operations.- donate_unaliased_outputs
(
logical(1))
IfTRUEand the current target platform is"cpu", append a phantom donated input for every output that isn't already aliased to a user-donated input. They come after all other arguments. This is needed internally so R keeps track of the CPU buffers memory in order to know when to garbage collect.- platform
(
NULL|character(1))
Target platform name (e.g."cpu","cuda"). Stored on a process-wide global during the call so that platform-aware lowering rules (queried viacurrent_platform()) can branch on it.NULL(the default) leaves the current value untouched — recursive calls from higher-order primitives inherit the platform of the enclosing call.
Value
(list)
Of length 3:
the
stablehlo::FuncThe graph's constants: the
GraphValues holdingConcreteArrays, whose data must be passed as the leading inputs at execution time whenconstants_as_inputs = TRUE.A list of phantom-output specs, one per phantom donated input appended when
donate_unaliased_outputs = TRUE. Each entry is alist(dtype, shape)describing the buffer the executor must allocate. Empty when no phantoms were added.
Examples
# the closed-over array `x` becomes the constant input %0, before the
# graph's own input `y` (%1)
x <- nv_array(c(1, 2))
graph <- trace_fn(function(y) y + x, list(y = nv_aval("f32", shape = 2)))
out <- stablehlo(graph)
out[[1L]]
#> func.func @main (%0: tensor<2xf32>, %1: tensor<2xf32>) -> tensor<2xf32> {
#> %2 = stablehlo.add %1, %0 : tensor<2xf32>
#> return %2 : tensor<2xf32>
#> }
out[[2L]]
#> [[1]]
#> GraphValue(ConcreteArray(f32, (2)))
#>
# a donated input is aliased with an output of the same type
graph <- trace_fn(
function(a, b) list(a + b, a * b),
list(a = nv_aval("f32", 3), b = nv_aval("f32", 3))
)
stablehlo(graph, donate = "a")[[1L]]
#> func.func @main (%0: tensor<3xf32> {tf.aliasing_output = 0 : i32}, %1: tensor<3xf32>) -> (tensor<3xf32>, tensor<3xf32>) {
#> %2 = stablehlo.add %0, %1 : tensor<3xf32>
#> %3 = stablehlo.multiply %0, %1 : tensor<3xf32>
#> return %2, %3 : tensor<3xf32>, tensor<3xf32>
#> }
# on CPU, a phantom input is appended for every output not aliased yet, and
# the third element describes the buffers to allocate for them
out <- stablehlo(graph, donate_unaliased_outputs = TRUE, platform = "cpu")
out[[1L]]
#> func.func @main (%0: tensor<3xf32>, %1: tensor<3xf32>, %2: tensor<3xf32> {tf.aliasing_output = 0 : i32}, %3: tensor<3xf32> {tf.aliasing_output = 1 : i32}) -> (tensor<3xf32>, tensor<3xf32>) {
#> %4 = stablehlo.add %0, %1 : tensor<3xf32>
#> %5 = stablehlo.multiply %0, %1 : tensor<3xf32>
#> return %4, %5 : tensor<3xf32>, tensor<3xf32>
#> }
out[[3L]]
#> [[1]]
#> [[1]]$dtype
#> <f32>
#>
#> [[1]]$shape
#> [1] 3
#>
#>
#> [[2]]
#> [[2]]$dtype
#> <f32>
#>
#> [[2]]$shape
#> [1] 3
#>
#>