fix(Compiler/Expr): replace caseInteger list-indexing fallback with equalsInteger chain#7693
Open
fix(Compiler/Expr): replace caseInteger list-indexing fallback with equalsInteger chain#7693
Conversation
Adds a minimal test that compiles unsafeFromBuiltinData on a 3-constructor type in the default SumsOfProducts mode (no BuiltinCasing pragma). This captures the caseInteger fallback regression for comparison.
…disabled Temporarily set `if False` in unsafeFromDataClause to bypass caseInteger and generate golden files from the old equalsInteger/ifThenElse code path. These serve as the equivalence target for the Expr.hs fix.
Contributor
43759bb to f2f4424 Compare f2f4424 to 8a53491 Compare zliu41 approved these changes Mar 26, 2026
Member
zliu41 left a comment
There was a problem hiding this comment.
This needs to be backported to the version the Hydra team is using.
a298e64 to 759d2f5 Compare …qualsInteger chain When compiling caseInteger in non-BuiltinCasing mode (SumsOfProducts), the fallback used PlutusTx.List.!! which built a linked list of branches at runtime and indexed into it with a Y-combinator. This caused a 3-5x execution cost regression for unsafeFromBuiltinData on multi-constructor types (reported by the Hydra team, see #7691). Replace the fallback with mkEqualsIntegerChain, which generates a flat chain of equalsInteger/ifThenElse comparisons in PIR. This produces UPLC equivalent to the pre-caseInteger code path with no runtime allocation. See Note [caseInteger non-BuiltinCasing fallback] in Expr.hs.
759d2f5 to 3f451f2 Compare 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
Fixes the execution cost regression documented in #7691.
When compiling
caseIntegerin the default SumsOfProducts mode, the fallback usedPlutusTx.List.!!, which built a linked list at runtime and indexed into it with a Z-combinator. This caused a 3-5x cost increase forunsafeFromBuiltinDataon multi-constructor types.This PR replaces the fallback with a lazy
equalsInteger/ifThenElsechain in PIR.Uses the
(all dead. resTy)/(/\dead -> branch)encoding to avoid evaluating non-matching branches. No runtime allocation, no Y-combinator, no linked list.How it works
The non-BuiltinCasing branch in
Compiler/Expr.hsnow generates PIR equivalent to:Which erases to
delay/forcein UPLC, matching the pre-regression pattern.The BuiltinCasing branch is unchanged (native
caseon the integer).Budget comparison
data ABC = A Integer | B Integer | C Integer, same source compiled in both modes:SumsOfProducts (default, the regressed mode)
if False)Baseline is generated by bypassing
caseInteger(if FalseinunsafeFromDataClause),which falls back to the old tuple-pattern-matching TH code. The small remaining difference
(~4% for index 0) is from
casePaircontinuation vsfst/sndlet-bindings in thepair extraction, which is inherent to the
caseIntegerTH code path.BuiltinCasing (unaffected by this change)