Skip to content

inference: track reaching defs for slots#55601

Merged
vtjnash merged 4 commits intoJuliaLang:masterfrom
topolarity:ct/fix-55548
Dec 30, 2025
Merged

inference: track reaching defs for slots#55601
vtjnash merged 4 commits intoJuliaLang:masterfrom
topolarity:ct/fix-55548

Conversation

@topolarity
Copy link
Copy Markdown
Member

@topolarity topolarity commented Aug 27, 2024

This PR implements the "Path-Convergence Criterion" for SSA / ϕ-nodes as part of type-inference.

The VarState.ssadef field corresponds to the "reaching definition" of the slot in SSA form, which allows us to conveniently reason about the identity of a slot across multiple program points. If the reaching def is equal at two program points, then the slot contents are guaranteed to be egal (i.e. x₀ === x₁)

Tasks:

  • Split StateRefinement change to separate PR
  • Split VarTable plumbing to separate PR
  • Remove old Conditional invalidation logic
  • Add tests

Fixes #55548 (alternative to #55551), by having Conditional remember the reaching definition that it narrows.

@topolarity topolarity force-pushed the ct/fix-55548 branch 2 times, most recently from 4829608 to e60a5ee Compare August 28, 2024 16:44
Copy link
Copy Markdown
Member

@aviatesk aviatesk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, this looks much better than my PR in general.
Still I would like to add the test case from it, i.e.

# JuliaLang/julia#55548: invalidate stale slot wrapper types in `ssavaluetypes`
_issue55548_proj1(a, b) = a
function issue55548(a)
    a = Base.inferencebarrier(a)::Union{Int64,Float64}
    if _issue55548_proj1(isa(a, Int64), (a = Base.inferencebarrier(1.0)::Union{Int64,Float64}; true))
        return a
    end
    return 2
end
@test Float64 <: Base.infer_return_type(issue55548, (Int,))

@aviatesk
Copy link
Copy Markdown
Member

@nanosoldier runbenchmarks("inference", vs=":master")

@topolarity
Copy link
Copy Markdown
Member Author

topolarity commented Aug 29, 2024

Thanks for the test case and review @aviatesk

fwiw, there's also a precision regression that I encountered w/ this PR:

function foo()
    value = @noinline rand((true, false, 1))
    is_bool = value isa Bool
    if inferencebarrier(@noinline rand(Bool))
        value = 1.0
        is_bool = false
    end
    # at this merge point, only the "false half" of the Conditional should be invalidated
    return is_bool ? value : false
end
@assert only(Base.return_types(foo, ())) === Bool # fails w/ PR

but I think this can be mostly fixed by widening the Conditional at the merge point and giving it a new .ssadef to match

@nanosoldier
Copy link
Copy Markdown
Collaborator

Your benchmark job has completed - possible performance regressions were detected. A full report can be found here.

@vtjnash
Copy link
Copy Markdown
Member

vtjnash commented Nov 18, 2024

bump? are we able to land this and backport to v1.11/v1.10?

@vtjnash vtjnash added compiler:inference Type inference bugfix This change fixes an existing bug labels Nov 18, 2024
@serenity4 serenity4 force-pushed the ct/fix-55548 branch 3 times, most recently from e614050 to eca1168 Compare August 6, 2025 05:19
@serenity4
Copy link
Copy Markdown
Member

As discussed with @topolarity, I will take over this PR and finish it so we can have a fix for the underlying issue.

It seems like most of the core functionality works well at the moment, so I believe it's mostly a matter of finishing up the design and related refactors, and address performance regressions.

@serenity4
Copy link
Copy Markdown
Member

@nanosoldier runbenchmarks("inference", vs=":master")

@nanosoldier
Copy link
Copy Markdown
Collaborator

Your benchmark job has completed - possible performance regressions were detected. A full report can be found here.

@serenity4
Copy link
Copy Markdown
Member

@nanosoldier runbenchmarks("inference", vs=":master")

@nanosoldier
Copy link
Copy Markdown
Collaborator

Your benchmark job has completed - possible performance regressions were detected. A full report can be found here.

@serenity4
Copy link
Copy Markdown
Member

@nanosoldier runbenchmarks("inference", vs=":master")

@nanosoldier
Copy link
Copy Markdown
Collaborator

Your benchmark job has completed - possible performance regressions were detected. A full report can be found here.

@vtjnash
Copy link
Copy Markdown
Member

vtjnash commented Sep 17, 2025

@serenity4 are you still planning to mark this ready for review in time for v1.12 backports?

@vtjnash vtjnash added the backport 1.12 Change should be backported to release-1.12 label Sep 17, 2025
@serenity4
Copy link
Copy Markdown
Member

serenity4 commented Sep 17, 2025

Thanks for the ping. Yes, I plan to work again on it soon-ish, not sure it will be ready for a backport for 1.12.0 but at least 1.12.1 would be nice. That is, unless we have a strong motivation to get it in for 1.12.0, in which case I can divert more resources to it.

This was referenced Sep 24, 2025
@KristofferC KristofferC mentioned this pull request Oct 21, 2025
35 tasks
@KristofferC KristofferC mentioned this pull request Nov 24, 2025
22 tasks
topolarity and others added 4 commits December 8, 2025 18:48
Add a new `StateRefinement` struct that guarantees object identity is preserved
by the update (i.e. `x (before) === x (after)`), in contrast to `StateUpdate`
which represents a new assignment. This allows us to remove the `conditional`
flag from `StateUpdate` and the `ignore_conditional` parameter from
`invalidate_slotwrapper`.

Also change `conditional_change` and `condition_object_change` to use a
`Symbol` parameter (`:then` or `:else`) instead of a `Bool` for clarity.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Cédric Belmant <cedric.belmant@juliahub.com>
Co-Authored-By: Jameson Nash <vtjnash+github@gmail.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add `vtypes::Union{VarTable,Nothing}` parameter to abstract call functions
to make the current VarTable available during call analysis. This enables
future improvements to track SSA definition sites for slot values.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Cédric Belmant <cedric.belmant@juliahub.com>
Co-Authored-By: Jameson Nash <vtjnash+github@gmail.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add `ssadef` field to `VarState`, `Conditional`, and `MustAlias` to track
the "reaching definition" for slot variables. This enables tracking object
identity across control flow, which is useful for later refinements.

The ssadef represents:
- 0: value comes from an argument
- negative: refers to a "virtual ϕ-block" preceding the given index

When a slot has the same ssadef at two different points of execution,
the slot contents are guaranteed to share identity (x₀ === x₁).

This commit updates:
- VarState to include ssadef field
- Conditional and MustAlias to include ssadef field
- smerge/schanged/stupdate! to compute reaching definitions using
  the path-convergence criterion for SSA construction
- All callsites to construct these types with the new field
- widenreturn to only convert to Inter* types when ssadef == 0

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Cédric Belmant <cedric.belmant@juliahub.com>
Co-Authored-By: Jameson Nash <vtjnash+github@gmail.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
With ssadef tracking, we no longer need to explicitly invalidate
Conditional/MustAlias lattice elements when a slot is reassigned.
The ssadef field in these types records which "version" of the slot
they refer to, and conditional_valid() detects when a Conditional
is stale (i.e., when the slot has been reassigned since the
Conditional was created).

This removes:
- invalidate_slotwrapper(): no longer needed
- widenwrappedslotwrapper(): was only used by invalidate_slotwrapper
- The invalidation loop in stoverwrite1!()

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@vtjnash vtjnash marked this pull request as ready for review December 8, 2025 19:55
@vtjnash
Copy link
Copy Markdown
Member

vtjnash commented Dec 8, 2025

@nanosoldier runbenchmarks("inference", vs=":master")

@nanosoldier
Copy link
Copy Markdown
Collaborator

Your benchmark job has completed - possible performance regressions were detected. A full report can be found here.

@vtjnash vtjnash added the don't squash Don't squash merge label Dec 8, 2025
@vtjnash
Copy link
Copy Markdown
Member

vtjnash commented Dec 8, 2025

I just had Claude finish the TODO items, since they sounded like very mechanical things. Seems to have done fine, so this seems ready to merge now, pending review and author approval.

@topolarity
Copy link
Copy Markdown
Member Author

Has the regression in #55601 (comment) been fixed?

We should also run a quick evaluation to make sure this doesn't make inference too slow (it turns inference into an semi-inefficient re-implementation of ϕ-node insertion, so it could slow down some cases)

@vtjnash
Copy link
Copy Markdown
Member

vtjnash commented Dec 9, 2025

Has the regression in #55601 (comment) been fixed?

No, I had a commit for it, but it was tricky enough that I wanted to make it a separate PR

We should also run a quick evaluation to make sure this doesn't make inference too slow (it turns inference into an semi-inefficient re-implementation of ϕ-node insertion, so it could slow down some cases)

It performed better in nanosoldier than our current implementation

@topolarity
Copy link
Copy Markdown
Member Author

@nanosoldier runtests()

@nanosoldier
Copy link
Copy Markdown
Collaborator

The package evaluation job you requested has completed - possible new issues were detected.
The full report is available.

Report summary

❗ Packages that crashed

2 packages crashed only on the current version.

  • An unreachable instruction was executed: 2 packages

25 packages crashed on the previous version too.

✖ Packages that failed

11 packages failed only on the current version.

  • Package fails to precompile: 3 packages
  • Package has test failures: 6 packages
  • Package tests unexpectedly errored: 1 packages
  • Test duration exceeded the time limit: 1 packages

2802 packages failed on the previous version too.

✔ Packages that passed tests

3 packages passed tests only on the current version.

  • Other: 3 packages

3924 packages passed tests on the previous version too.

~ Packages that at least loaded

3537 packages successfully loaded on the previous version too.

➖ Packages that were skipped altogether

1 packages were skipped only on the current version.

  • Package could not be installed: 1 packages

916 packages were skipped on the previous version too.

@KristofferC KristofferC mentioned this pull request Dec 16, 2025
21 tasks
@vtjnash vtjnash merged commit 94ae0ac into JuliaLang:master Dec 30, 2025
12 checks passed
vtjnash added a commit that referenced this pull request Dec 31, 2025
DRAFT of how this should be implemented
@KristofferC KristofferC mentioned this pull request Jan 9, 2026
40 tasks
@DilumAluthge
Copy link
Copy Markdown
Member

I see the backport 1.12 label here, but this does not backport cleanly to 1.12.

@topolarity Would you be able to push a manual backport to backports-release-1.12?

@KristofferC KristofferC mentioned this pull request Feb 25, 2026
37 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backport 1.12 Change should be backported to release-1.12 bugfix This change fixes an existing bug compiler:inference Type inference don't squash Don't squash merge

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Conditional lattice element is semantically broken in the presence of SSAValues

6 participants