| ... |
... |
@@ -36,6 +36,7 @@ import GHC.Core.Ppr ( pprCoreExpr ) |
|
36
|
36
|
import GHC.Core.Unfold
|
|
37
|
37
|
import GHC.Core.Unfold.Make
|
|
38
|
38
|
import GHC.Core.Utils
|
|
|
39
|
+import GHC.Core.Stats ( exprSize )
|
|
39
|
40
|
import GHC.Core.Opt.Arity ( ArityType, exprArity, arityTypeBotSigs_maybe
|
|
40
|
41
|
, pushCoTyArg, pushCoValArg, exprIsDeadEnd
|
|
41
|
42
|
, typeArity, arityTypeArity, etaExpandAT )
|
| ... |
... |
@@ -600,6 +601,7 @@ tryCastWorkerWrapper :: SimplEnv -> BindContext |
|
600
|
601
|
-> InId -> OutId -> OutExpr
|
|
601
|
602
|
-> SimplM (SimplFloats, SimplEnv)
|
|
602
|
603
|
-- See Note [Cast worker/wrapper]
|
|
|
604
|
+-- Binder /can/ be a JoinId
|
|
603
|
605
|
tryCastWorkerWrapper env bind_cxt old_bndr bndr (Cast rhs co)
|
|
604
|
606
|
| BC_Let top_lvl is_rec <- bind_cxt -- Not join points
|
|
605
|
607
|
, not (isDFunId bndr) -- nor DFuns; cast w/w is no help, and we can't transform
|
| ... |
... |
@@ -636,7 +638,7 @@ tryCastWorkerWrapper env bind_cxt old_bndr bndr (Cast rhs co) |
|
636
|
638
|
else do { wrap_unf <- mkLetUnfolding env top_lvl VanillaSrc bndr False triv_rhs
|
|
637
|
639
|
; let bndr' = bndr `setInlinePragma` mkCastWrapperInlinePrag (idInlinePragma bndr)
|
|
638
|
640
|
`setIdUnfolding` wrap_unf
|
|
639
|
|
- floats' = floats `extendFloats` NonRec bndr' triv_rhs
|
|
|
641
|
+ floats' = floats `addLetFloat` NonRec bndr' triv_rhs
|
|
640
|
642
|
; return ( floats', setInScopeFromF env floats' ) } }
|
|
641
|
643
|
where
|
|
642
|
644
|
-- Force the occ_fs so that the old Id is not retained in the new Id.
|
| ... |
... |
@@ -1655,6 +1657,10 @@ rebuildWithFloats :: SimplEnv -> SimplFloats -> OutExpr -> SimplCont |
|
1655
|
1657
|
-> SimplM (SimplFloats, OutExpr)
|
|
1656
|
1658
|
-- (rebuildWithFloats env floats expr cont) rebuilds (let floats in expr)
|
|
1657
|
1659
|
-- with continuation `cont`. Used only when seCaseCase is off.
|
|
|
1660
|
+-- The only reason it differs from wrapFloats-then-rebuild is when
|
|
|
1661
|
+-- we can do case-of-known-constructor:
|
|
|
1662
|
+-- case (let <binds> in Just e) of Just x -> rhs
|
|
|
1663
|
+-- --> let <binds> in let x=e in rhs
|
|
1658
|
1664
|
-- See (COC3) in Note [sm_case_case: switching off case continuations]
|
|
1659
|
1665
|
rebuildWithFloats env floats expr cont
|
|
1660
|
1666
|
| Select { sc_bndr = bndr, sc_alts = alts, sc_env = se, sc_cont = cont' } <- cont
|
| ... |
... |
@@ -2409,11 +2415,53 @@ simplOutExpr :: HasDebugCallStack |
|
2409
|
2415
|
--
|
|
2410
|
2416
|
-- What if expr = (K x y) and cont is `Select`? That is handled by rebuild.
|
|
2411
|
2417
|
-- (Why? That's a bit inconsistent with beta.)
|
|
2412
|
|
-simplOutExpr env expr cont
|
|
|
2418
|
+simplOutExpr env _expr _cont
|
|
2413
|
2419
|
| assertPpr (checkSimplEnvIS env) (pprBadSimplEnvIS env) $
|
|
2414
|
2420
|
False -- Just checks the assertion!
|
|
2415
|
2421
|
= panic "simplOutExpr"
|
|
2416
|
2422
|
|
|
|
2423
|
+simplOutExpr env expr cont
|
|
|
2424
|
+ | contIsStop cont
|
|
|
2425
|
+ = rebuild_go env expr cont
|
|
|
2426
|
+
|
|
|
2427
|
+simplOutExpr env expr@(Var v) cont
|
|
|
2428
|
+ | isDataConWorkId v = rebuild_go env expr cont
|
|
|
2429
|
+ | otherwise = simplOutId env v cont
|
|
|
2430
|
+simplOutExpr env (App fun (Type ty)) cont
|
|
|
2431
|
+ = simplOutExpr env fun (ApplyToTy { sc_arg_ty = ty, sc_hole_ty = exprType fun, sc_cont = cont })
|
|
|
2432
|
+simplOutExpr env (App fun arg) cont
|
|
|
2433
|
+ = simplOutExpr env fun (ApplyToVal { sc_arg = arg, sc_env = Simplified NoDup, sc_cast = MRefl
|
|
|
2434
|
+ , sc_hole_ty = exprType fun, sc_cont = cont })
|
|
|
2435
|
+simplOutExpr env (Cast e co) cont
|
|
|
2436
|
+ = do { cont' <- pushCast env co cont; simplOutExpr env e cont' }
|
|
|
2437
|
+simplOutExpr env expr@(Lam {}) cont
|
|
|
2438
|
+ | hasArgs cont = reSimplifyOutExpr env expr cont -- Beta-reduce
|
|
|
2439
|
+ | otherwise = rebuild_go env expr cont
|
|
|
2440
|
+
|
|
|
2441
|
+simplOutExpr env expr@(Case {}) cont
|
|
|
2442
|
+ -- `cont` is not a Stop (first equation), so pushing it into the
|
|
|
2443
|
+ -- alternatives now saves leaving a case-of-case, or a (case ...) arg
|
|
|
2444
|
+ -- redex, for the next iteration. But only for small expressions:
|
|
|
2445
|
+ -- see (RSO2) in Note [Re-simplifying an OutExpr]
|
|
|
2446
|
+ | exprSize expr <= reSimplifyThreshold = reSimplifyOutExpr env expr cont
|
|
|
2447
|
+ | otherwise = rebuild_go env expr cont
|
|
|
2448
|
+
|
|
|
2449
|
+simplOutExpr env expr@(Let {}) cont
|
|
|
2450
|
+ = -- For now just give up, but we could probably do better
|
|
|
2451
|
+ rebuild_go env expr cont
|
|
|
2452
|
+
|
|
|
2453
|
+simplOutExpr env expr@(Tick {}) cont
|
|
|
2454
|
+ = rebuild_go env expr cont
|
|
|
2455
|
+simplOutExpr env expr@(Coercion {}) cont
|
|
|
2456
|
+ = rebuild_go env expr cont
|
|
|
2457
|
+simplOutExpr env expr@(Lit {}) cont
|
|
|
2458
|
+ = rebuild_go env expr cont
|
|
|
2459
|
+
|
|
|
2460
|
+simplOutExpr _env expr@(Type {}) cont
|
|
|
2461
|
+ = pprPanic "simplOutExpr:Type" (ppr expr $$ ppr cont)
|
|
|
2462
|
+
|
|
|
2463
|
+
|
|
|
2464
|
+{-
|
|
2417
|
2465
|
| Lam {} <- expr
|
|
2418
|
2466
|
, cont_has_args
|
|
2419
|
2467
|
= simplLam env (occurAnalyseExpr expr) cont
|
| ... |
... |
@@ -2440,6 +2488,80 @@ simplOutExpr env expr cont |
|
2440
|
2488
|
= rebuild_go env expr cont
|
|
2441
|
2489
|
where
|
|
2442
|
2490
|
cont_has_args = hasArgs cont
|
|
|
2491
|
+-}
|
|
|
2492
|
+
|
|
|
2493
|
+reSimplifyOutExpr :: SimplEnvIS -> OutExpr -> SimplCont -> SimplM (SimplFloats, OutExpr)
|
|
|
2494
|
+-- See Note [Re-simplifying an OutExpr]
|
|
|
2495
|
+reSimplifyOutExpr env expr cont
|
|
|
2496
|
+ = simplExprF env (occurAnalyseExpr expr) cont
|
|
|
2497
|
+
|
|
|
2498
|
+reSimplifyThreshold :: Int
|
|
|
2499
|
+-- See (RSO2) in Note [Re-simplifying an OutExpr]
|
|
|
2500
|
+reSimplifyThreshold = 100
|
|
|
2501
|
+
|
|
|
2502
|
+{- Note [Re-simplifying an OutExpr]
|
|
|
2503
|
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
2504
|
+simplOutExpr is given an already-simplified expression `expr` (an OutExpr,
|
|
|
2505
|
+typically from a `DoneEx` in the substitution) and a continuation `cont`.
|
|
|
2506
|
+If `expr` is a lambda and `cont` has arguments, or if `expr` is a `case` and
|
|
|
2507
|
+`cont` is not a Stop, we want to push `cont` into `expr`: beta-reduce, do
|
|
|
2508
|
+case-of-case, apply the arguments in each alternative, and so on. Otherwise
|
|
|
2509
|
+the next Simplifier iteration would have to do it, and extra iterations are
|
|
|
2510
|
+expensive (T13056).
|
|
|
2511
|
+
|
|
|
2512
|
+We do this by simply running the Simplifier over `expr` again, with the
|
|
|
2513
|
+substitution-free environment `env` (a SimplEnvIS). That re-simplification
|
|
|
2514
|
+is mostly a renaming pass, but it is essential: we must NOT treat the binders
|
|
|
2515
|
+inside `expr` as if they were already simplified (e.g. by building a `Select`
|
|
|
2516
|
+with `sc_env = Simplified`, so that the alternatives go through the SAF_Out
|
|
|
2517
|
+route and `simplAltBinders` neither clones nor records the alternative binders).
|
|
|
2518
|
+Here is why:
|
|
|
2519
|
+
|
|
|
2520
|
+* The binders inside an OutExpr are not in the in-scope set at the point where
|
|
|
2521
|
+ `expr` is used. (The in-scope set records only binders that scope over the
|
|
|
2522
|
+ current point, not binders nested inside expressions in the substitution.)
|
|
|
2523
|
+
|
|
|
2524
|
+* Fresh uniques come from `uniqAway`, which deterministically picks the next
|
|
|
2525
|
+ unique above the largest in the in-scope set. So a binder created while
|
|
|
2526
|
+ simplifying `expr` (at its original binding site) and a binder created later
|
|
|
2527
|
+ elsewhere, from an in-scope set that does not contain the former, can share
|
|
|
2528
|
+ a unique.
|
|
|
2529
|
+
|
|
|
2530
|
+* So if we pushed `cont` into the alternatives without cloning the alternative
|
|
|
2531
|
+ binders against the current in-scope set, free variables of `cont` could be
|
|
|
2532
|
+ captured; and any Core operation that relies on the in-scope set, such as
|
|
|
2533
|
+ `exprIsConApp_maybe`, may crash (T9630: lookupIdSubst panic).
|
|
|
2534
|
+
|
|
|
2535
|
+Re-simplifying with an empty substitution cures all this: `simplBinders`
|
|
|
2536
|
+clones every binder whose unique is in scope and extends the in-scope set
|
|
|
2537
|
+with every binder. (This is also what happens when an unfolding is inlined.)
|
|
|
2538
|
+
|
|
|
2539
|
+Two further points:
|
|
|
2540
|
+
|
|
|
2541
|
+(RSO1) We occurrence-analyse `expr` first because its occurrence info may be
|
|
|
2542
|
+ stale: the Simplifier may have duplicated occurrences of binders inside
|
|
|
2543
|
+ `expr` (by case-of-case, say) without updating the binders' OccInfo.
|
|
|
2544
|
+ Compare Note [Occurrence-analyse after rule firing].
|
|
|
2545
|
+
|
|
|
2546
|
+(RSO2) The cost of re-simplifying is proportional to the size of `expr`, and
|
|
|
2547
|
+ that can go quadratic. In T15630 we get a chain
|
|
|
2548
|
+ f1 = case f0 of {...}; f2 = case f1 of {...}; f3 = case f2 of {...}; ...
|
|
|
2549
|
+ where each `fi` is bound by knownCon (so its RHS is already an OutExpr and
|
|
|
2550
|
+ preInlineUnconditionally never sees it), occurs once, and so becomes a
|
|
|
2551
|
+ `DoneEx` via postInlineUnconditionally. Its one occurrence is scrutinised
|
|
|
2552
|
+ by a case, so we arrive here with a `Select` continuation, and the
|
|
|
2553
|
+ re-simplified result of level i is contained in `expr` at level i+1.
|
|
|
2554
|
+ Re-simplifying at every level costs O(n^2) in the length of the chain,
|
|
|
2555
|
+ whereas simply rebuilding leaves case-of-case redexes that the next
|
|
|
2556
|
+ iteration deals with in one linear pass.
|
|
|
2557
|
+
|
|
|
2558
|
+ So we re-simplify only if `expr` is smaller than `reSimplifyThreshold`.
|
|
|
2559
|
+ That keeps the win on T13056 (whose re-simplified expressions all have
|
|
|
2560
|
+ size < 60, and where it saves a Simplifier iteration) and avoids the
|
|
|
2561
|
+ quadratic cost on T15630 and T15630a (chain members of size 100-320).
|
|
|
2562
|
+ A lambda applied to arguments is always re-simplified: beta-reduction is
|
|
|
2563
|
+ too good to miss.
|
|
|
2564
|
+-}
|
|
2443
|
2565
|
|
|
2444
|
2566
|
---------------------------------------------------------
|
|
2445
|
2567
|
simplOutId :: SimplEnvIS -> OutId -> SimplCont -> SimplM (SimplFloats, OutExpr)
|
| ... |
... |
@@ -4369,11 +4491,36 @@ mkDupableContWithDmds env dmds |
|
4369
|
4491
|
; (floats1, cont') <- mkDupableContWithDmds env cont_dmds cont
|
|
4370
|
4492
|
; let env' = env `setInScopeFromF` floats1
|
|
4371
|
4493
|
; arg' <- simplArg env' Nothing hole_ty se arg arg_mco
|
|
4372
|
|
- ; (let_floats2, triv_arg) <- makeTrivial env' NotTopLevel dmd (fsLit "karg") arg'
|
|
|
4494
|
+ ; (let_floats2, dup_arg)
|
|
|
4495
|
+ <- if small_enough_to_dup dmd arg'
|
|
|
4496
|
+ then return (nilOL, arg') -- See Note [Duplicating small arguments]
|
|
|
4497
|
+ else makeTrivial env' NotTopLevel dmd (fsLit "karg") arg'
|
|
4373
|
4498
|
; let all_floats = floats1 `addLetFloats` let_floats2
|
|
4374
|
4499
|
; return ( all_floats
|
|
4375
|
|
- , ApplyToVal { sc_arg = triv_arg, sc_env = Simplified OkDup
|
|
|
4500
|
+ , ApplyToVal { sc_arg = dup_arg, sc_env = Simplified OkDup
|
|
4376
|
4501
|
, sc_cast = MRefl, sc_cont = cont', sc_hole_ty = hole_ty }) }
|
|
|
4502
|
+ where
|
|
|
4503
|
+ -- See Note [Duplicating small arguments]
|
|
|
4504
|
+ small_enough_to_dup dmd arg
|
|
|
4505
|
+ = not (isStrUsedDmd dmd) && exprIsDupable (sePlatform env) arg
|
|
|
4506
|
+
|
|
|
4507
|
+{- Note [Duplicating small arguments]
|
|
|
4508
|
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
4509
|
+When mkDupableCont makes an (ApplyToVal arg) continuation duplicable, it
|
|
|
4510
|
+let-binds the argument, karg = arg, and duplicates (ApplyToVal karg). So
|
|
|
4511
|
+ (case x of { A -> f; B -> g }) arg
|
|
|
4512
|
+ ==> let karg = arg in case x of { A -> f karg; B -> g karg }
|
|
|
4513
|
+But if `arg` is small, the very next Simplifier iteration will inline karg into
|
|
|
4514
|
+both branches (postInlineUnconditionally: lazy, one occurrence per branch, and
|
|
|
4515
|
+smallEnoughToInline), costing an entire extra iteration for nothing (T13056).
|
|
|
4516
|
+So we duplicate such an argument straight away if it is not strictly demanded
|
|
|
4517
|
+(a strict one costs no allocation, so there is nothing to gain by duplicating
|
|
|
4518
|
+it) and it is `exprIsDupable`. That is not quite postInlineUnconditionally's
|
|
|
4519
|
+criterion (`smallEnoughToInline`), but it is much cheaper than building an
|
|
|
4520
|
+unfolding just to measure it, and getting it slightly wrong is harmless:
|
|
|
4521
|
+if we fail to duplicate, karg is inlined in the next iteration as before.
|
|
|
4522
|
+Duplication is work-safe because only one alternative is executed.
|
|
|
4523
|
+-}
|
|
4377
|
4524
|
|
|
4378
|
4525
|
mkDupableContWithDmds env _
|
|
4379
|
4526
|
(Select { sc_bndr = case_bndr, sc_alts = alts, sc_env = se, sc_cont = cont })
|