| ... |
... |
@@ -474,14 +474,14 @@ leaving a simpler job for demand-analysis worker/wrapper. See #19874. |
|
474
|
474
|
|
|
475
|
475
|
Wrinkles
|
|
476
|
476
|
|
|
477
|
|
-1. We must /not/ do cast w/w on
|
|
|
477
|
+(CWW1) We must /not/ do cast w/w on
|
|
478
|
478
|
f = g |> co
|
|
479
|
479
|
otherwise it'll just keep repeating forever! You might think this
|
|
480
|
480
|
is avoided because the call to tryCastWorkerWrapper is guarded by
|
|
481
|
|
- preInlineUnconditinally, but I'm worried that a loop-breaker or an
|
|
482
|
|
- exported Id might say False to preInlineUnonditionally.
|
|
|
481
|
+ preInlineUnconditionally, but I'm worried that a loop-breaker or an
|
|
|
482
|
+ exported Id might say False to preInlineUnconditionally.
|
|
483
|
483
|
|
|
484
|
|
-2. We need to be careful with inline/noinline pragmas:
|
|
|
484
|
+(CWW2) We need to be careful with inline/noinline pragmas:
|
|
485
|
485
|
rec { {-# NOINLINE f #-}
|
|
486
|
486
|
f = (...g...) |> co
|
|
487
|
487
|
; g = ...f... }
|
| ... |
... |
@@ -496,15 +496,15 @@ Wrinkles |
|
496
|
496
|
f = $wf |> co
|
|
497
|
497
|
; g = ...f... }
|
|
498
|
498
|
and that is bad: the whole point is that we want to inline that
|
|
499
|
|
- cast! We want to transfer the pagma to $wf:
|
|
|
499
|
+ cast! We want to transfer the pragma to $wf:
|
|
500
|
500
|
rec { {-# NOINLINE $wf #-}
|
|
501
|
501
|
$wf = ...g...
|
|
502
|
502
|
; f = $wf |> co
|
|
503
|
503
|
; g = ...f... }
|
|
504
|
504
|
c.f. Note [Worker/wrapper for NOINLINE functions] in GHC.Core.Opt.WorkWrap.
|
|
505
|
505
|
|
|
506
|
|
-3. We should still do cast w/w even if `f` is INLINEABLE. E.g.
|
|
507
|
|
- {- f: Stable unfolding = <stable-big> -}
|
|
|
506
|
+(CWW3) We should still do cast w/w even if `f` is INLINEABLE. E.g.
|
|
|
507
|
+ {- f: Stable unfolding (arity 2) = <stable-big> -}
|
|
508
|
508
|
f = (\xy. <big-body>) |> co
|
|
509
|
509
|
Then we want to w/w to
|
|
510
|
510
|
{- $wf: Stable unfolding = <stable-big> |> sym co -}
|
| ... |
... |
@@ -513,15 +513,43 @@ Wrinkles |
|
513
|
513
|
Notice that the stable unfolding moves to the worker! Now demand analysis
|
|
514
|
514
|
will work fine on $wf, whereas it has trouble with the original f.
|
|
515
|
515
|
c.f. Note [Worker/wrapper for INLINABLE functions] in GHC.Core.Opt.WorkWrap.
|
|
516
|
|
- This point also applies to strong loopbreakers with INLINE pragmas, see
|
|
517
|
|
- wrinkle (4).
|
|
518
|
516
|
|
|
519
|
|
-4. We should /not/ do cast w/w for non-loop-breaker INLINE functions (hence
|
|
520
|
|
- hasInlineUnfolding in tryCastWorkerWrapper, which responds False to
|
|
521
|
|
- loop-breakers) because they'll definitely be inlined anyway, cast and
|
|
522
|
|
- all. And if we do cast w/w for an INLINE function with arity zero, we get
|
|
|
517
|
+(CWW4) We should /not/ do cast w/w for INLINE functions (hence `hasInlineUnfolding`
|
|
|
518
|
+ in `tryCastWorkerWrapper`) because they'll definitely be inlined anyway, cast
|
|
|
519
|
+ and all.
|
|
|
520
|
+
|
|
|
521
|
+ Moreover, if we do cast w/w for an INLINE function with arity zero, we get
|
|
523
|
522
|
something really silly: we inline that "worker" right back into the wrapper!
|
|
524
|
|
- Worse than a no-op, because we have then lost the stable unfolding.
|
|
|
523
|
+ In fact it is Much Worse than a no-op, because we have then lost the stable
|
|
|
524
|
+ unfolding --- aargh (see #26903). E.g. similar example to (CWW3)
|
|
|
525
|
+ {- g: Stable unfolding (arity 0) = <stable-big> -} NB arity 0!
|
|
|
526
|
+ g = (\xy. <big-body>) |> co
|
|
|
527
|
+ If we w/w to this:
|
|
|
528
|
+ {- $wg: Stable unfolding (arity 0) = <stable-big> |> sym co -}
|
|
|
529
|
+ $wg = \xy. <big-body>
|
|
|
530
|
+ g = $wg |> co
|
|
|
531
|
+ then we'll inline $wg at the call site in `g` giving
|
|
|
532
|
+ {- $wg: Stable unfolding (arity 0) = <stable-big> |> sym co -}
|
|
|
533
|
+ $wg = \xy. <big-body>
|
|
|
534
|
+ g = (<stable-big> |> sym co) |> co
|
|
|
535
|
+ and now we'll drop `$wg` as dead and we have lost the unfolding on `g`.
|
|
|
536
|
+ (We could /also/ give the binding `g = $wf |> co` a stable unfolding. Then
|
|
|
537
|
+ things would work right; but there is also no point in doing the cast
|
|
|
538
|
+ worker/wrapper in the first place.)
|
|
|
539
|
+
|
|
|
540
|
+ NB: you might wonder about a loop-breaker with an INLINE pragma; after all, a
|
|
|
541
|
+ loop breaker won't "definitely be inlined anyway", so arguably we should not
|
|
|
542
|
+ disable cast w/w/ for it. But a Rec group can /look/ recursive at an early
|
|
|
543
|
+ stage, and subsequently /become/ non-recursive after some simplification.
|
|
|
544
|
+ (This is common in instance decls; see Note [Checking for INLINE loop breakers]
|
|
|
545
|
+ in GHC.Core.Lint.) So the danger is that we'll permanently lose that stable
|
|
|
546
|
+ unfolding that we specifically wanted (#26903). Simple solution: disable cast
|
|
|
547
|
+ w/w for /any/ INLINE function. See the defn
|
|
|
548
|
+ of `GHC.Types.Id.Info.hasInlineUnfolding`.
|
|
|
549
|
+
|
|
|
550
|
+ The danger is that an INLINE pragma on a genuninely-recursive function
|
|
|
551
|
+ will kill worker-wrapper. Well, so be it. They are pretty suspicious anyway;
|
|
|
552
|
+ see Note [Checking for INLINE loop breakers].
|
|
525
|
553
|
|
|
526
|
554
|
All these wrinkles are exactly like worker/wrapper for strictness analysis:
|
|
527
|
555
|
f is the wrapper and must inline like crazy
|
| ... |
... |
@@ -586,11 +614,11 @@ tryCastWorkerWrapper env bind_cxt old_bndr bndr (Cast rhs co) |
|
586
|
614
|
| BC_Let top_lvl is_rec <- bind_cxt -- Not join points
|
|
587
|
615
|
, not (isDFunId bndr) -- nor DFuns; cast w/w is no help, and we can't transform
|
|
588
|
616
|
-- a DFunUnfolding in mk_worker_unfolding
|
|
589
|
|
- , not (exprIsTrivial rhs) -- Not x = y |> co; Wrinkle 1
|
|
590
|
|
- , not (hasInlineUnfolding info) -- Not INLINE things: Wrinkle 4
|
|
591
|
|
- , typeHasFixedRuntimeRep work_ty -- Don't peel off a cast if doing so would
|
|
592
|
|
- -- lose the underlying runtime representation.
|
|
593
|
|
- -- See Note [Preserve RuntimeRep info in cast w/w]
|
|
|
617
|
+ , not (exprIsTrivial rhs) -- Not x = y |> co; see (CWW1)
|
|
|
618
|
+ , not (hasInlineUnfolding info) -- Not INLINE things: see (CWW4)
|
|
|
619
|
+ , typeHasFixedRuntimeRep work_ty -- Don't peel off a cast if doing so would
|
|
|
620
|
+ -- lose the underlying runtime representation.
|
|
|
621
|
+ -- See Note [Preserve RuntimeRep info in cast w/w]
|
|
594
|
622
|
, not (isOpaquePragma (idInlinePragma old_bndr)) -- Not for OPAQUE bindings
|
|
595
|
623
|
-- See Note [OPAQUE pragma]
|
|
596
|
624
|
= do { uniq <- getUniqueM
|
| ... |
... |
@@ -637,13 +665,13 @@ tryCastWorkerWrapper env bind_cxt old_bndr bndr (Cast rhs co) |
|
637
|
665
|
`setArityInfo` work_arity
|
|
638
|
666
|
-- We do /not/ want to transfer OccInfo, Rules
|
|
639
|
667
|
-- Note [Preserve strictness in cast w/w]
|
|
640
|
|
- -- and Wrinkle 2 of Note [Cast worker/wrapper]
|
|
|
668
|
+ -- and (CWW2) of Note [Cast worker/wrapper]
|
|
641
|
669
|
|
|
642
|
670
|
----------- Worker unfolding -----------
|
|
643
|
671
|
-- Stable case: if there is a stable unfolding we have to compose with (Sym co);
|
|
644
|
672
|
-- the next round of simplification will do the job
|
|
645
|
673
|
-- Non-stable case: use work_rhs
|
|
646
|
|
- -- Wrinkle 3 of Note [Cast worker/wrapper]
|
|
|
674
|
+ -- See (CWW4) of Note [Cast worker/wrapper]
|
|
647
|
675
|
mk_worker_unfolding top_lvl work_id work_rhs
|
|
648
|
676
|
= case realUnfoldingInfo info of -- NB: the real one, even for loop-breakers
|
|
649
|
677
|
unf@(CoreUnfolding { uf_tmpl = unf_rhs, uf_src = src })
|