Skip to content

Drop redundant unsafeCaseList calls produced by AsData#7679

Merged
zliu41 merged 4 commits intomasterfrom
zliu41/wrapUnsafeCaseList
Mar 19, 2026
Merged

Drop redundant unsafeCaseList calls produced by AsData#7679
zliu41 merged 4 commits intomasterfrom
zliu41/wrapUnsafeCaseList

Conversation

@zliu41
Copy link
Member

@zliu41 zliu41 commented Mar 18, 2026

This makes AsData generate much more optimal code. See Note [Dropping redundant unsafeCaseList calls produced by AsData].

@zliu41 zliu41 requested review from a team, SeungheonOh, Unisay and ana-pantilie March 18, 2026 18:06
@zliu41 zliu41 added the No Changelog Required Add this to skip the Changelog Check label Mar 18, 2026
@github-actions
Copy link
Contributor

github-actions bot commented Mar 18, 2026

Execution Budget Golden Diff

2fad725 (master) vs 82933e7

output

plutus-benchmark/cardano-loans/test/9.6/main.golden.eval

Metric Old New Δ%
Flat Size 8_698 8_695 -0.03%

plutus-tx-plugin/test/AsData/Budget/9.12/richSumSingleField.golden.eval

Metric Old New Δ%
CPU 717_432 461_432 -35.68%
Memory 4_364 2_764 -36.66%
Flat Size 105 66 -37.14%

plutus-tx-plugin/test/AsData/Budget/9.6/richSumSingleField.golden.eval

Metric Old New Δ%
CPU 717_432 461_432 -35.68%
Memory 4_364 2_764 -36.66%
Flat Size 105 66 -37.14%

This comment will get updated when changes are made.

@zliu41
Copy link
Member Author

zliu41 commented Mar 18, 2026

Regarding the changes in the constitution scripts, see #7681

@zliu41 zliu41 force-pushed the zliu41/wrapUnsafeCaseList branch from 0abb6f4 to dc2cb59 Compare March 19, 2026 06:04
Copy link
Collaborator

@SeungheonOh SeungheonOh left a comment

Choose a reason for hiding this comment

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

The optimizations are very good; I don't particularly like having extra optimization pass and annotation for dropping cases since they introduces extra complexity on the annotation interface and they are very specific to Data matching in particular.

Being said, I don't think there's an easy way to do this on TH so this is probably best approach with minimal change. And all the changes looks good with some minor suggestions.

=> Term TyName name uni fun a
-> Term TyName name uni fun a
processTerm = \case
Case a _resTy _scrut [LamAbs _ x _ (LamAbs _ y _ body)]
Copy link
Collaborator

Choose a reason for hiding this comment

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

Is there any reason we only check two nested lambdas? I think it should work on arbitrarily nested lambdas. So

When we have
case scrut [\a b ... y z -> <handler>]

this case should be dropped if case is marked safe to drop and <handler> doesn't use a b ... y z.

Copy link
Member Author

Choose a reason for hiding this comment

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

I'm only thinking about casing on lists. But I agree we can make it more general.

Copy link
Member Author

Choose a reason for hiding this comment

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

It's actually not easy to generalize this. In general, it's incorrect to simply drop all binders. To determine how many binders to drop, you'd need to run the type checker. Which is doable, but will make this pass a lot more complicated. I'd prefer keeping things simple for now, and going that route when it becomes necessary.

Copy link
Collaborator

Choose a reason for hiding this comment

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

But don't we have same problem on the two nested-lambda case as well? For example, if we mark below Case safe to drop, it will break the types

[(case (constr 0) [\a b x y -> x + y]) 1 2 3 4]

as we will optimize this into

[(\x y -> x + y) 1 2 3 4]

which is incorrect.

But I think it's okay to keep as is since it's mainly just for optimizing casing on list. We can make this optimization more general once we have other places to run this optimization on.

Copy link
Member Author

Choose a reason for hiding this comment

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

But I think it's okay to keep as is since it's mainly just for optimizing casing on list. We can make this optimization more general once we have other places to run this optimization on.

Exactly.

Copy link
Contributor

@Unisay Unisay left a comment

Choose a reason for hiding this comment

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

richSumSingleField goldens look good (−36% CPU, −52% AST).

=> Term TyName name uni fun a
-> Term TyName name uni fun a
processTerm = \case
Case a _resTy _scrut [LamAbs _ x _ (LamAbs _ y _ body)]
Copy link
Contributor

@Unisay Unisay Mar 19, 2026

Choose a reason for hiding this comment

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

JFYI: I tried this to handle any number of LamAbs binders, not just two:

processTerm = \case
  Case a _resTy _scrut [branch]
    | annIsSafeToDrop a
    , let (binders, body) = peelLamAbs branch
    , not (null binders)
    , let usages = Usages.termUsages body
    , all (\b -> Usages.getUsageCount b usages == 0) binders ->
        body
  other -> other

peelLamAbs :: Term tyname name uni fun a -> ([name], Term tyname name uni fun a)
peelLamAbs (LamAbs _ n _ inner) = let (ns, body) = peelLamAbs inner in (n : ns, body)
peelLamAbs t = ([], t)

Copy link
Member Author

@zliu41 zliu41 Mar 19, 2026

Choose a reason for hiding this comment

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

This is incorrect, because the type of body may not match _resTy (e.g., consider case list [f]). They must match.

@zliu41 zliu41 merged commit faa3260 into master Mar 19, 2026
7 of 9 checks passed
@zliu41 zliu41 deleted the zliu41/wrapUnsafeCaseList branch March 19, 2026 19:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

No Changelog Required Add this to skip the Changelog Check

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants