Development Optimization Passes List
This is an automatically generated list of all internal xls developtment
optimization passes available with the default opt_main. Normal optimization
passes may be found
here.
This is generated automatically based on comments in the header files.
Warning
These passes are mostly intended for debugging and development use cases by the XLS development team and allow for the manipulation of ir files in ways that may not be desirable for general optimization use.
If the opt level is set below 'Min opt level' the pass will act as a no-op.
If the opt level is set above 'Cap opt level' the pass (or passes within the compound pass) will be executed with the opt level capped to the specified value.
Warning
Many of these passes have descriptions generated by the Gemini LLM and may not accurately reflect the behavior of the passes. As time goes on manual verification or editing of the pass descriptions may be done to improve accuracy.
assert_and_cover_removal - Assert and cover removal
Note
What follows was generated by the Gemini LLM. Not human verified.
AssertAndCoverRemovalPass (assert_and_cover_removal) is a development
pass that strips all assert and cover operations from a FunctionBase.
During IR debugging, optimization investigation, or area/delay experiments,
verification operations (assert and cover) can keep condition cones and
token chains alive. Removing them allows developers to inspect or synthesize
the pure datapath and control logic in isolation.
How It Works
The pass iterates over all nodes in the FunctionBase:
* Assert nodes (Op::kAssert): Because an assert takes an input
token as operand(0) and produces a token, the pass bypasses the
assertion in the token graph by replacing all uses of the assert node
with n->operand(0) and then removing the assert node.
* Cover nodes (Op::kCover): Because a cover returns an empty tuple
() and must have no users (XLS_RET_CHECK(n->users().empty())), the pass
removes the cover node directly.
Any condition logic feeding only the removed assert or cover nodes
becomes dead and can be cleaned up by a subsequent DeadCodeEliminationPass.
Example
// Before
fn checked_add(tkn: token, x: bits[8], y: bits[8]) -> (token, bits[8]) {
sum: bits[8] = add(x, y)
no_ovf: bits[1] = uge(sum, x)
assert_tkn: token = assert(tkn, no_ovf, message="overflow", label="ovf")
cover_max: () = cover( eq(sum, literal(value=255)), label="max_sum")
ret result: (token, bits[8]) = tuple(assert_tkn, sum)
}
After AssertAndCoverRemovalPass:
// After
fn checked_add(tkn: token, x: bits[8], y: bits[8]) -> (token, bits[8]) {
sum: bits[8] = add(x, y)
no_ovf: bits[1] = uge(sum, x)
ret result: (token, bits[8]) = tuple(tkn, sum)
}
decompose_dataflow - Decompose dataflow
Decompose and flatten all compound data type dataflow. This replaces all array and tuple operations with operations on base values except directly around externally visible values.
This pass is meant for testing and measurement.
literalize_zero_bits - Literalize zero bits
Note
What follows was generated by the Gemini LLM. Not human verified.
LiteralizeZeroBits (literalize_zero_bits) replaces all non-literal,
non-parameter operations that produce a zero-width bit vector (bits[0])
with a constant bits[0] literal (value=0).
Because a bits[0] type carries zero bits of runtime information, any pure
computation producing bits[0] always evaluates to the unique zero-bit
value. Replacing such nodes with a Literal of UBits(0, 0) severs data
dependencies on their operands, simplifying the IR graph and allowing dead
code elimination to remove upstream logic that only feeds zero-width values.
How It Works
The pass iterates over all nodes in the FunctionBase and checks whether
each node n satisfies:
* n->GetType()->IsBits() with bit_count() == 0,
* !n->Is<Literal>() (already a literal), and
* !n->Is<Param>() (parameters are preserved so the function signature and
parameter list remain valid).
Every matching node has its uses replaced with a new Literal node holding
Value(UBits(0, 0)).
Example
// Before
fn f(x: bits[8]) -> bits[8] {
empty_slice: bits[0] = bit_slice(x, start=0, width=0)
ret result: bits[8] = concat(empty_slice, x)
}
After LiteralizeZeroBits:
// After
fn f(x: bits[8]) -> bits[8] {
lit_zero_bits: bits[0] = literal(value=0)
ret result: bits[8] = concat(lit_zero_bits, x)
}
proc_state_legalization_shim - Proc State Legalization Pass
Compatibility shim to use the scheduling pass 'ProcStateLegalizationPass' in the optimization pass pipeline for modernizing procs.
Note
What follows was generated by the Gemini LLM. Not human verified.
ProcStateLegalizationPassShim (proc_state_legalization_shim) is an
OptimizationPass wrapper around the scheduling pass
ProcStateLegalizationPass. Because ProcStateLegalizationPass inherits
from SchedulingFunctionBasePass and normally executes inside the scheduling
pipeline, this shim constructs a package-wide SchedulingContext
(SchedulingContext::CreateForWholePackage) and default
SchedulingPassOptions so proc state legalization can be invoked directly
from opt_main and optimization pass pipelines when modernizing or testing
procs.
What the Wrapped ProcStateLegalizationPass Does
For each Proc in the package (non-proc FunctionBases are skipped),
ProcStateLegalizationPass legalizes every StateElement in three steps:
-
Mutual Exclusion Assertions (
AddMutualExclusionAsserts):- Write Mutual Exclusion (
AddNextValueMutualExclusionAssert): If a state element has two or morenext_value(Next) nodes, concatenates all of their predicates (__<state>__next_value_predicates), appliesone_hot(..., lsb_prio=true)and slices off the MSB, compares equality with the concatenated predicates (__<state>__at_most_one_next_value), and emits anassertlabeled__<state>__at_most_one_next_value_assertverifying that at most onenext_valuefires in any activation. - Read Mutual Exclusion (
AddStateReadMutualExclusionAssert): If a state element has two or morestate_readnodes, similarly concatenates their predicates (substitutingliteral(1)for any unpredicated read) and emits anassertlabeled__<state>__at_most_one_read_assertverifying that at most onestate_readis active at a time.
- Write Mutual Exclusion (
-
Write-Without-Read Assertions (
AddWriteWithoutReadAsserts): If a state element has one or morenext_valuenodes and all of itsstate_readnodes are predicated, computes the disjunction of all read predicates (__<state>__state_read_predicates_nary_or). For eachnext_valuenode, emits anassertlabeled__<state>__next_<id>_without_read_assertcheckingany_read_active | !next_predicate, ensuring a state update never fires when the state read is disabled. -
Default
next_valueGeneration (AddDefaultNextValues): Ensures every state element has an explicit state update under all conditions:- If any
next_valueis unconditional, or if an existing no-opnext_value(IsNoOpNext) already guardsnor(other_predicates)(so the pass is idempotent), no default is added. (When run in the scheduling pipeline withdefault_next_value_z3_rlimitset, a solver can also prove the predicates exhaustive; the shim uses defaultSchedulingPassOptionswhere this limit is unset.) - If no
next_valuenodes exist for the state element, emits a defaultnext_value(param=state, value=state_read, predicate=read_pred)for eachstate_read. - Otherwise, computes
__<state>__no_explicit_next_active = nor(predicates...)and, for eachstate_read, adds a defaultnext_valueholding the state unchanged (value=state_read) whenno_explicit_next_active(ANDed withstate_read->predicate(), if present) is true.
- If any
Example
// Before
proc counter(st: bits[32], init={0}) {
en: bits[1] = ...
inc: bits[32] = add(st, literal(value=1))
next_inc: () = next_value(param=st, value=inc, predicate=en)
}
After ProcStateLegalizationPassShim, an explicit default next_value is
added to retain st when en is false:
// After
proc counter(st: bits[32], init={0}) {
en: bits[1] = ...
inc: bits[32] = add(st, literal(value=1))
next_inc: () = next_value(param=st, value=inc, predicate=en)
__st__no_explicit_next_active: bits[1] = not(en)
st_default_st: () = next_value(
param=st, value=st, predicate=__st__no_explicit_next_active)
}
remove_identifiers_unsafe - UNSAFE: Remove all identifiers
A pass version of 'remove_identifers_main'. Running this pass will rewrite the package to remove the names of all functions, procs, nodes, channels, etc.
This should only be used while investigating optimizer behavior using the ir-visualizer or other tools.
Warning
This pass does not preserve externally visible names. Once run on a design the various io-constraint and other configs which rely on naming pieces of the design will not work. This pass is only for dev/ investigatory purposes.
Note
This pass does not preserve the id number of nodes.
remove_one_hot_sel - One Hot Select Removal Pass
Pass which replaces OneHotSelects with equivalent Selects without regard to profitability concerns. This pass is meant for investigation and analysis use only and should not be used for normal optimization pipelines.
To avoid extreme proliferation of nodes, we only translate OneHotSelects with a selector bitwidth <= 16.
to_zero_ext - DebugPass: To ZeroExt Pass
Converts any canonicalized zero-exts back from concat(zero, ...) to zero_ext since it generally makes for easier to read/visualize graphs. This pass is not meant to be used as an optimization pass at all.
Note
What follows was generated by the Gemini LLM. Not human verified.
ToZeroExtPass (to_zero_ext) is a debugging and visualization pass that
converts concat operations with leading zero operands back into explicit
zero_ext operations.
During standard XLS optimization pipelines, passes such as narrowing or bit
slicing often canonicalize or decompose a zero_ext into a concat of a
zero literal and the narrower value. While convenient for bit-level
transformations, these extra zero literals and concat nodes can clutter IR
graphs in visualizers and debugging dumps. ToZeroExtPass restores them to
single-operand zero_ext nodes.
How It Works
-
Query Engine Setup: Acquires a shared
PartialInfoQueryEnginefor theFunctionBaseand iterates over nodes in topological order (context.TopoSort(f)). -
Matching Zero-Extension-Like Concats (
ZeroExtLike::Make): For eachConcatnoden, the pass checksZeroExtLike::Make(n, *qe). AConcatmatches if:- Its total bit width is greater than zero, and
- Every operand except the last (least-significant) operand is proven to
be all zeros (
qe.IsAllZeros(op)).
-
Replacement: Replaces the matching
Concatnode with azero_ext(ExtendOpwithOp::kZeroExt) that extends the last operand (ext_like->to_extend()) to the full bit width of theConcat(n->BitCountOrDie()).
Example
// Before
fn extend_val(x: bits[8]) -> bits[16] {
zeros: bits[8] = literal(value=0)
ret ext: bits[16] = concat(zeros, x)
}
After ToZeroExtPass:
// After
fn extend_val(x: bits[8]) -> bits[16] {
ret ext: bits[16] = zero_ext(x, new_bit_count=16)
}