Skip to content

Introduce a Var entity to give an identity to region inputs and node outputs.#34

Draft
eddyb wants to merge 4 commits intoeddyb/insts-are-nodesfrom
eddyb/var-io
Draft

Introduce a Var entity to give an identity to region inputs and node outputs.#34
eddyb wants to merge 4 commits intoeddyb/insts-are-nodesfrom
eddyb/var-io

Conversation

@eddyb
Copy link
Copy Markdown
Member

@eddyb eddyb commented Apr 22, 2026

Note: this PR is a draft to avoid accidental merging onto its "base" branch (used as a form of ad-hoc PR stacking), and will remain as such, until its "base" branch can be set to main, i.e. all prerequisite PRs will have landed, up to and including this PR (whose branch is the "base" of this one):


Before this PR, Value had these two variants (besides Value::Const(Const)):

  • Value::RegionInput { region: Region, input_idx: u32 }
  • Value::NodeOutput { node: Node, output_idx: u32 }

These "positional" references felt simple, but were fragile/inefficient in a few ways:

  • any insertion/replacement/reordering of their declarations (other than adding new ones at the end) would require traversing all possible use locations, and correctly being able to remap indices
  • significant complexity for any single pass updating definitions and uses as it goes (needing e.g. perfect knowledge of whether a use has been replaced already, or not, breaking on-demand access patterns, etc.)
  • the exposed indices means that no possible API could be crafted to allow some mutation of the IR, but disallow accidental misuse of indices, detect misapplied substitutions, etc.

After this PR, those Value variants become a single Value::Var(Var), where:

  • Var is a new entity, mapping to a VarDecl
    (the name is more in the sense of lambda calculus and SSA, than anything like "memory-backed mutable variable")
  • RegionDef's inputs field and NodeDef's output fields holds Vars now
  • each VarDecl tracks the parent Region/Node and the Var's own index in that parent

While Vars can themselves be misused, and require extra indirection and redundancy, now:

  • only the VarDecls have to be updated, not any Var uses, when making any additions/reorderings/removals/etc. to region inputs/node outputs, and Vars' "ownership" can even be moved from e.g. a region input to a node output (without having to update any of its uses)
  • a pass willing to allocate new Vars can easily tell them apart from the old Vars it hasn't replaced yet, even if they might end up in the same positional slots of e.g. a node's outputs
  • the redundancy allows VarDecls to be checked against its parent region/node's list of Vars (and there is logic in the pretty-printer to do some of that, mostly to avoid a misleading view of the IR if some Vars have been orphaned/misplaced/etc.)

TODO: using the name "var(iable)" for this, while having some precedent in math/CS, does mean that GlobalVar and mem::MemOp::FuncLocalVar need to be updated to avoid overlapping with it - perhaps by describing those as "(memory) bindings" instead of "variables".

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant