Skip to content

Add variable support with load, store, and lea instructions#65

Open
RealA10N wants to merge 8 commits intomainfrom
claude/stack-variables-design-TyEc5
Open

Add variable support with load, store, and lea instructions#65
RealA10N wants to merge 8 commits intomainfrom
claude/stack-variables-design-TyEc5

Conversation

@RealA10N
Copy link
Copy Markdown
Owner

This PR introduces support for local variables in the USM instruction set, enabling functions to read from and write to named memory locations in the local frame.

Summary

Variables are distinct from registers—they are mutable memory locations that can be accessed by multiple instructions. This change adds three new instructions (load, store, lea) and the infrastructure to manage variables throughout the compilation pipeline.

Key Changes

New Instructions:

  • load: Reads a variable's value into a register ($type %reg = load &var)
  • store: Writes a register's value into a variable (store &var %reg)
  • lea: Computes the address of a variable and stores it in a pointer register ($type * %ptr = lea &var)

Variable Management:

  • Added VariableInfo to represent named, typed slots in the function's local frame
  • Implemented VariableManager interface with VariableList as the default implementation
  • Variables are lazily created on first use and their types are inferred from instruction context
  • Variables are collected and stored in FunctionInfo.Variables

Parser Updates:

  • Added VariableNode and VariableParser to parse variable references (prefixed with &)
  • Extended ArgumentParser to recognize variables as valid instruction arguments
  • Updated FunctionParser to properly format function blocks with indentation

Type System:

  • Added Equal() method to TypeDescriptorInfo for type comparison
  • lea validates that the target is a pointer type and infers variable type by stripping the pointer descriptor
  • load and store validate type consistency across multiple uses of the same variable

Code Generation:

  • Added VariableArgumentGenerator to generate VariableArgumentInfo during instruction context generation
  • Added ArgumentToVariable() helper for type-safe argument conversion
  • Updated FunctionGenerator to initialize the variables manager for each function

Notable Implementation Details

  • Variables support type inference: the first instruction using a variable determines its type
  • Type mismatches across instructions using the same variable produce detailed error messages with hints
  • store is marked as a critical instruction (not eliminated by dead code elimination) due to its side effects
  • load and lea are non-critical and can be eliminated if their results are unused
  • The lea instruction bridges variables to the general pointer model, allowing pointers to be passed to functions or stored in memory

https://claude.ai/code/session_01JxzeScSGcF7w9ADKnEL27q

claude added 3 commits March 17, 2026 18:18
…tions

Introduces first-class stack variable support to the USM IR, enabling
register allocation passes to spill virtual registers to named stack slots
that remain explicitly distinguishable from registers in the IR.

Key changes:
- lex: add VariableToken for the & sigil prefix
- parse: add VariableNode (argument), VariableDeclarationNode (preamble),
  update FunctionNode with Variables []VariableDeclarationNode field,
  update ArgumentParser to handle variable arguments
- gen: add VariableInfo, VariableManager interface, VariableArgumentInfo,
  VariableDeclarationGenerator; extend FunctionGenerationContext and
  ManagerCreators with VariableManager; extend FunctionInfo with Variables
  field and String() output; fix ReferencedTypeInfo.Equal() big.Int pointer
  comparison bug; add IsAutoGenerated to LabelInfo to suppress auto-labels
  in String() round-trips
- usm/managers: add VariableList (slice+map) implementation of VariableManager
- usm/isa: add load (&var → %reg), store (%reg → &var, critical),
  lea (&var → pointer %reg) instructions
- aarch64/managers: wire in VariableManagerCreator (reuses usm implementation)
- tests: parse-level and gen-level tests for variable declarations,
  round-trip String(), undefined/duplicate variable errors, load/store/lea

https://claude.ai/code/session_01JxzeScSGcF7w9ADKnEL27q
Variables no longer require explicit declarations — they are created
lazily on first use (via &name in any instruction argument) and their
type is inferred during instruction validation by load, store, and lea.

- parse: remove VariableDeclarationNode and preamble parsing; FunctionNode
  no longer has a Variables field
- gen: remove VariableDeclarationGenerator and collectVariableDeclarations;
  VariableArgumentGenerator creates the variable lazily with a nil type
- usm/isa: load/store infer variable type from target/value on first use
  and validate on subsequent uses; lea infers by stripping the pointer
  descriptor from the target type, and adds stripPointer() helper
- gen: add TypeDescriptorInfo.Equal() and use it in
  ReferencedTypeInfo.Equal() and isPointerTo() to replace ad-hoc struct
  field comparisons

https://claude.ai/code/session_01JxzeScSGcF7w9ADKnEL27q
…, parse/function minimal diff

- gen/label_info.go: replace IsAutoGenerated bool with Declaration
  *core.UnmanagedSourceView (nil = auto-generated), which is the
  idiomatic Go way to express optional source locations
- gen/label_map.go: GenerateLabel() returns LabelInfo with nil Declaration
- gen/basic_block_info.go: check Declaration != nil instead of IsAutoGenerated
- gen/label_definition_generator.go: store &declaration as pointer
- gen/variable_info.go: fix comment — registers are not required to be SSA
  values (they can have multiple definitions before SSA construction)
- parse/function.go: restore if n.Instructions != nil guard in stringBlock
  to minimise the diff from the original

https://claude.ai/code/session_01JxzeScSGcF7w9ADKnEL27q
@codecov
Copy link
Copy Markdown

codecov bot commented Mar 17, 2026

Codecov Report

❌ Patch coverage is 35.49618% with 169 lines in your changes missing coverage. Please review.
✅ Project coverage is 41.89%. Comparing base (661e744) to head (63d32ca).

Files with missing lines Patch % Lines
usm/isa/lea.go 0.00% 49 Missing ⚠️
usm/isa/store.go 0.00% 40 Missing ⚠️
usm/isa/load.go 0.00% 37 Missing ⚠️
usm/managers/variables.go 13.33% 13 Missing ⚠️
gen/type_referenced_info.go 75.00% 5 Missing and 3 partials ⚠️
gen/variable_argument.go 70.00% 5 Missing and 1 partial ⚠️
gen/translate.go 37.50% 5 Missing ⚠️
parse/function.go 90.62% 2 Missing and 1 partial ⚠️
usm/managers/instructions.go 0.00% 3 Missing ⚠️
gen/variable_info.go 0.00% 2 Missing ⚠️
... and 3 more
Additional details and impacted files
@@            Coverage Diff             @@
##             main      #65      +/-   ##
==========================================
+ Coverage   41.00%   41.89%   +0.88%     
==========================================
  Files         123      130       +7     
  Lines        3790     4039     +249     
==========================================
+ Hits         1554     1692     +138     
- Misses       2134     2238     +104     
- Partials      102      109       +7     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

The descriptor *N packs N consecutive pointer levels into a single entry,
so adding one level of indirection to a type ending with *N must yield
*(N+1), not a separate *1 appended.

- isPointerTo: split into two cases — if varType ends with *N, target
  must be identical with *(N+1) as last descriptor; otherwise target
  must append a new *1 descriptor
- stripPointer: if last descriptor has Amount > 1, decrement it; if
  Amount == 1, remove the descriptor entirely
- lea Validate: remove incorrect Amount == 1 guard in the inference path
  (any pointer descriptor, including *2, is a valid lea target)
- Add TestLeaNestedPointer (variable of type $32 *1 → target $32 *2) and
  TestLeaMismatchedPointer to cover the new cases

https://claude.ai/code/session_01JxzeScSGcF7w9ADKnEL27q
Add PointerTo() and Deref() methods to ReferencedTypeInfo in gen/ so
pointer-level arithmetic is reusable across ISAs rather than buried in
the lea instruction. Both methods correctly handle the *N packed-pointer
semantics (adding a level increments N; removing decrements it, dropping
the descriptor when N reaches 1).

lea.go loses isPointerTo and stripPointer entirely — validation and
inference are now single expressions using the new methods.
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.

2 participants