unifyTypes: pointer-eq fast-path (-7.5% full build)#17
Open
kozak wants to merge 2 commits into
Open
Conversation
- Unify.hs: when (not ...) -> unless - Types.hs: rename ctorSalt_X -> ctorSaltX (camelCase) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
When t1 and t2 refer to the same heap object, unifyTypes is a no-op (structurally equal => no unknowns to solve, no errors). One machine compare via reallyUnsafePtrEquality# bypasses substituteType (which walks closed types unnecessarily), the hint-stack push, and the cache lookup. Sound regardless of result: ptr-eq False just falls through to the existing path. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Collaborator
Doesn't make sense - the added operation is so cheap it shouldn't ever cause a regression. So this is probably just measurement noise. And this makes me wonder: is the improvement also just noise? Maybe we need a more rigorous measurement protocol? |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
One-line change in
unifyTypes: when both arguments refer to the same heap object, return immediately — bypassingsubstituteType, the hint-stack push, and the cache lookup. Sound regardless of the result; the fall-through path is unchanged.Why
The
unify-callsite-surveyexperiment found 75% of unification-cache hits at 3 sites inTypes.hsare on the trivial pair(tyFunction, tyFunction). Even on a cache hit, every call pays the wrapper overhead:gets checkSubstitution,substituteTypewalking closed types,withErrorMessageHintpushing/popping the hint stack, and the HashSet lookup. FortyFunctionpropagated fromEnvironment(a single shared constant), the two arguments are usually the same heap object — onereallyUnsafePtrEquality#short-circuits all of that.Results vs
5713e832baseline (type-hash + lint fix)Tests pass (1340/1340). Binary +4 KB (no inlining shift).
The trade-off
This is a partial win. The full build wins clearly. Cascade rebuild scenarios (prelude touches Prelude → 1342 deps, leaf touches a single module) regress modestly. We tried adding a phase 2 that kept the substituteType/hint-stack short-circuit but still inserted into the cache; the prelude regression was unchanged (+4.7%), so the cause isn't missed cache writes.
A cost-centre profile of the prelude scenario shows
unifyTypes/substituteType/withErrorMessageHintall at 0.0% inherited time despite ~188k entries — the regression is below cost-centre granularity, likely a code-gen / branch-prediction / icache effect of the kind LESSONS warns about for anyUnify.hsmodification.The full-build win is significantly larger than the rebuild-scenario regressions, so net across realistic workload mixes is positive. Full experiment writeup:
experiments/ptr-eq-unify/.Soundness
reallyUnsafePtrEquality#returning True implies the two arguments share a heap object → structurally equal →unifyTypesis a no-op (no fresh TUnknowns to solve, no errors). Returning False is allowed even on structurally equal inputs; the existing path handles that case unchanged.Stacked on
This builds on
type-hash(which addsTypeFlags+ HashSet-keyed unification cache; PR pending). The base for this PR istype-hash. The change is a few lines that should rebase cleanly onto master once type-hash lands.Test plan
stack build— clean compilestack test --fast— 1340/1340 pass🤖 Generated with Claude Code