This document is relevant for: Trn2, Trn3
Aliasing Output Rewrite Pass#
This pass runs as part of the FX passes stage of the compilation pipeline, between FX tracing and HLO lowering. It detects in-place buffer mutations and produces aliasing metadata for the XLA/HLO backend.
Problem Statement#
The XLA/HLO backend used by Neuron allocates separate memory buffers for every input and output of a compiled graph. When a model mutates an input buffer in-place (e.g. updating KV-cache state), the runtime must know that a particular output is the same buffer as a particular input so it can reuse the allocation instead of copying.
HLO expresses this through input_output_alias entries. The aliasing pass is responsible for analyzing the FX graph, detecting every case where an output derives from a mutated input, and producing the io_map metadata that downstream HLO conversion uses to emit those alias entries.
Sources of Aliasing#
The pass handles four categories:
In-place torch operations β
x.add_(y),operator.setitem, etc.NKI kernel mutations β
wrap_nkiHOP nodes whoseoperand_output_aliasesdict declares which kernel inputs are written back to kernel outputs.Custom ops with mutable arguments β ops whose schema contains
Tensor(a!)annotations (alias_info.is_write=True).Pass-through / view aliases β an output that is a direct reference to an input, or reaches one through a chain of view ops (
view,reshape,transpose, β¦).
Pipeline Position#
DeviceRewriterPass
β
βΌ
AliasingOutputRewritePass βββ this pass
β
βΌ
InPlaceToOutOfPlacePass
β
βΌ
NkiKernelWriteBackendConfigPass
β
βΌ
CollectiveReplicaGroupsPass
The aliasing pass runs before the in-place-to-out-of-place pass. It analyzes the graph while in-place operations are still present, records which inputs are mutated, and stashes root_input metadata on mutating nodes so the subsequent InPlaceToOutOfPlacePass can name replacement nodes correctly.
Algorithm Design#
Overview#
The pass performs a single linear scan of the graph followed by an output rewrite step. It produces an io_map dict ({output_idx: input_idx}) and an original_output_count integer that are returned as metadata alongside the transformed GraphModule.
Phase 1: Collect Input Placeholders#
All placeholder nodes are collected in order. Their positional index is significant because io_map uses it to pair outputs with inputs. Dynamoβs mangled names (e.g. L_self_modules_layer_parameters_weight_) are cleaned up for debug logging.
Phase 2: Build the Alias Chain#
A single forward pass over every node classifies it into one of:
Mutating op β the mutated tensor is traced back through the alias chain to its root input placeholder. The node is recorded in
mutated_inputsand added toalias_chainso downstream nodes can be traced back too.node.meta["root_input"]is set for theInPlaceToOutOfPlacePass.Aliasing op β view/reshape/transpose/etc. The node is added to
alias_chainpointing at its source tensor (first argument).Custom op with mutations β schema arguments with
alias_info.is_write=Trueare resolved to their root input placeholders.NKI kernel with mutations β
operand_output_aliasesentries are resolved. For tuple-returning kernels,getitemnodes are found or created and registered inalias_chain.
Phase 3: Extend Outputs and Build io_map#
Mutated inputs that are not already represented in the output tuple are appended as new output entries. For NKI kernels, the getitem node carrying the post-mutation value is preferred over the raw input placeholder.
A second scan over the (now extended) output tuple detects pass-through and view-alias relationships that allow buffer reuse even without mutations. Slice views are excluded because they change shape and cannot alias the full input buffer in HLO.
Data Structures#
alias_chain : dict[Node, Node]
Maps each node to the node it aliases. Following the chain
eventually reaches a graph-level input placeholder.
mutated_inputs : dict[int, Node]
Maps input placeholder index β placeholder node for every
input that is mutated in-place.
io_map : dict[int, int]
Maps output index β input index. Forwarded to HLO conversion
which writes input_output_alias entries.
Algorithm Flow#
ββββββββββββββββββββββββ
β Collect placeholdersβ
ββββββββββββ¬ββββββββββββ
βΌ
ββββββββββββββββββββββββ
β For each node: β
β β’ Mutating op? ββββΆ Record in mutated_inputs + alias_chain
β β’ Aliasing op? ββββΆ Record in alias_chain
β β’ Custom op w/mut? ββββΆ Resolve schema args β mutated_inputs
β β’ NKI kernel w/mut? ββββΆ Resolve aliases β mutated_inputs + alias_chain
ββββββββββββ¬ββββββββββββ
βΌ
ββββββββββββββββββββββββ
β Extend output tuple β
β with mutated inputs β
β not already present β
ββββββββββββ¬ββββββββββββ
βΌ
ββββββββββββββββββββββββ
β Scan outputs for β
β pass-through/view β
β aliases β io_map β
ββββββββββββ¬ββββββββββββ
βΌ
ββββββββββββββββββββββββ
β Return (gm, { β
β io_map, β
β original_output_ β
β count β
β }) β
ββββββββββββββββββββββββ
Example#
Before the pass, a graph that mutates kv_cache in-place:
placeholder x
placeholder kv_cache
call_method add_ (kv_cache, x)
output (result,)
After the pass, kv_cache is appended to the output tuple and io_map records the relationship:
placeholder x
placeholder kv_cache
call_method add_ (kv_cache, x)
output (result, kv_cache)
io_map = {1: 1} # output[1] aliases input[1]
The InPlaceToOutOfPlacePass then rewrites add_ β add and updates references, but the io_map remains valid because the output position is stable.
Module-Level Constants#
Three sets classify operations for the analysis:
ALIASING_METHODSβ method-call names that produce views (view,reshape,transpose,permute, β¦).ALIASING_ATEN_OPSβ ATen-level equivalents seen aftertorch.exportlowering (includes_unsafe_view,view_as,reshape_as, β¦).INPLACE_METHODSβ in-place method names used for mutation detection (add_,copy_,scatter_, β¦).
Source Location#
vllm_neuron/fx_passes/aliasing_pass.py
This document is relevant for: Trn2, Trn3