Zubin pushed to branch wip/26416 at Glasgow Haskell Compiler / GHC
Commits:
-
7b4eb1a1
by Zubin Duggal at 2026-03-10T17:18:49+05:30
3 changed files:
- compiler/GHC/Core/Opt/DmdAnal.hs
- compiler/GHC/Types/Demand.hs
- + testsuite/tests/dmdanal/should_run/T26416.stdout
Changes:
| ... | ... | @@ -1141,7 +1141,7 @@ dmdAnalRhsSig top_lvl rec_flag env let_sd id rhs |
| 1141 | 1141 | -- See Note [Absence analysis for stable unfoldings and RULES]
|
| 1142 | 1142 | -- The unfolding FVs are already included in full_rhs_env via addUnfoldingDemands.
|
| 1143 | 1143 | -- Here we only need demandRoots for RULES.
|
| 1144 | - rhs_env2 = rhs_env1 `plusDmdEnv` demandRootSet env (idRuleVars id)
|
|
| 1144 | + rhs_env2 = rhs_env1 `plusDmdEnv` demandRootSet env (filterVarSet isId (idRuleVars id))
|
|
| 1145 | 1145 | |
| 1146 | 1146 | -- See Note [Lazy and unleashable free variables]
|
| 1147 | 1147 | !(!sig_env, !weak_fvs) = splitWeakDmds rhs_env2
|
| ... | ... | @@ -1160,7 +1160,7 @@ addUnfoldingDemands env rhs_sd id rhs_dmd_ty |
| 1160 | 1160 | , Just unf_body <- maybeUnfoldingTemplate unf
|
| 1161 | 1161 | , let WithDmdType unf_dmd_ty _ = dmdAnal env rhs_sd unf_body
|
| 1162 | 1162 | = -- pprTrace "addUnfoldingDemands" (ppr id $$ ppr rhs_dmd_ty $$ ppr unf_dmd_ty) $
|
| 1163 | - lubUBglbLBDmdType rhs_dmd_ty unf_dmd_ty
|
|
| 1163 | + maxDmdType rhs_dmd_ty unf_dmd_ty
|
|
| 1164 | 1164 | |
| 1165 | 1165 | | otherwise
|
| 1166 | 1166 | = rhs_dmd_ty -- No stable unfolding, nothing to do
|
| ... | ... | @@ -1504,10 +1504,21 @@ and transform to |
| 1504 | 1504 | |
| 1505 | 1505 | Now if f is subsequently inlined, we'll use 'g' and ... disaster.
|
| 1506 | 1506 | |
| 1507 | -SOLUTION: if f has a stable unfolding, treat every free variable as a
|
|
| 1508 | -/demand root/, that is: Analyse it as if it was a variable occurring in a
|
|
| 1507 | +SOLUTION for stable unfoldings: in `dmdAnalRhsSig`, if the function has a
|
|
| 1508 | +stable unfolding, analyse it with `dmdAnal` and combine the resulting `DmdType`
|
|
| 1509 | +with the RHS's `DmdType`. This is done by `addUnfoldingDemands`, which uses
|
|
| 1510 | +`maxDmdType` to combine both argument demands and free variable demands.
|
|
| 1511 | +See Note [Combining demands for stable unfoldings] in GHC.Types.Demand for
|
|
| 1512 | +details of the combining operation.
|
|
| 1513 | + |
|
| 1514 | +This handles both the free variables and arguments of stable unfoldings in one
|
|
| 1515 | +go. For example, in the scenario above, the unfolding's `DmdType` will mention
|
|
| 1516 | +`g` as a free variable, so `maxDmdType` will keep it alive.
|
|
| 1517 | + |
|
| 1518 | +SOLUTION for RULES: treat every Id free in the RHS of a RULE as a
|
|
| 1519 | +/demand root/, that is: analyse it as if it was a variable occurring in a
|
|
| 1509 | 1520 | 'topDmd' context. This is done in `demandRoot` (which we also use for exported
|
| 1510 | -top-level ids). Do the same for Ids free in the RHS of any RULES for f.
|
|
| 1521 | +top-level ids).
|
|
| 1511 | 1522 | |
| 1512 | 1523 | Wrinkles:
|
| 1513 | 1524 | |
| ... | ... | @@ -1524,7 +1535,7 @@ Wrinkles: |
| 1524 | 1535 | this, that actually happened in practice.
|
| 1525 | 1536 | |
| 1526 | 1537 | (W2) You might wonder why we don't simply take the free vars of the
|
| 1527 | - unfolding/RULE and map them to topDmd. The reason is that any of the free vars
|
|
| 1538 | + RULE and map them to topDmd. The reason is that any of the free vars
|
|
| 1528 | 1539 | might have demand signatures themselves that in turn demand transitive free
|
| 1529 | 1540 | variables and that we hence need to unleash! This came up in #23208.
|
| 1530 | 1541 | Consider
|
| ... | ... | @@ -1546,7 +1557,7 @@ Wrinkles: |
| 1546 | 1557 | for `sg`, failing to unleash the signature and hence observed an absent
|
| 1547 | 1558 | error instead of the `really important message`.
|
| 1548 | 1559 | |
| 1549 | - (W3) The SOLUTION above handles /free variables/ of stable unfoldings, but
|
|
| 1560 | + (W3) The stable unfolding solution above handles /free variables/, but
|
|
| 1550 | 1561 | what about /arguments/? Consider (#26416)
|
| 1551 | 1562 | |
| 1552 | 1563 | fromVector :: (Storable a, KnownNat n) => Vector a -> Vector a
|
| ... | ... | @@ -1560,15 +1571,9 @@ Wrinkles: |
| 1560 | 1571 | worker's unfolding is inlined, it will use that rubbish value as a real
|
| 1561 | 1572 | dictionary, leading to a segfault!
|
| 1562 | 1573 | |
| 1563 | - SOLUTION: in `dmdAnalRhsSig`, if the function has a stable unfolding,
|
|
| 1564 | - analyse it with `dmdAnal` and combine the resulting `DmdType` with the
|
|
| 1565 | - RHS's `DmdType`. This is done by `addUnfoldingDemands`, which uses
|
|
| 1566 | - `lubUBglbLBDmdType` to combine both argument demands and free variable
|
|
| 1567 | - demands. See Note [Combining demands for stable unfoldings] in
|
|
| 1568 | - GHC.Types.Demand for details of the combining operation.
|
|
| 1569 | - |
|
| 1570 | - This replaces the `demandRoots` approach for stable unfoldings (though
|
|
| 1571 | - we still use `demandRoots` for RULES via `idRuleVars`).
|
|
| 1574 | + `addUnfoldingDemands` handles this too: since `maxDmdType` combines both
|
|
| 1575 | + the argument demands and free variable demands from the unfolding's
|
|
| 1576 | + `DmdType` with the RHS's, argument absence is correctly prevented.
|
|
| 1572 | 1577 | |
| 1573 | 1578 | Note [DmdAnal for DataCon wrappers]
|
| 1574 | 1579 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| ... | ... | @@ -2052,8 +2057,15 @@ finaliseArgBoxities :: AnalEnv -> Id -> Arity |
| 2052 | 2057 | -- If: (dmds', rhs') = finaliseArgBoxitities ... dmds .. rhs
|
| 2053 | 2058 | -- Then:
|
| 2054 | 2059 | -- dmds' is the same as dmds (including length), except for boxity info
|
| 2055 | --- rhs' is the same as rhs, except for dmd info on lambda binders
|
|
| 2060 | +-- rhs' is the same as rhs, except that the idDemandInfo on the outer
|
|
| 2061 | +-- lambda binders now includes the same finalised boxity info as dmds'
|
|
| 2056 | 2062 | -- NB: For join points, length dmds might be greater than ww_arity
|
| 2063 | +--
|
|
| 2064 | +-- IMPORTANT: The lambda binders of rhs' must carry the final demand info,
|
|
| 2065 | +-- because worker/wrapper drives decisions from the idDemandInfo on the lambdas
|
|
| 2066 | +-- (see mkWwstr_one), NOT from the strictness signature of the function.
|
|
| 2067 | +-- So the demands must reflect both the unfolding combination (from
|
|
| 2068 | +-- addUnfoldingDemands) and the boxity finalisation done here.
|
|
| 2057 | 2069 | finaliseArgBoxities env fn ww_arity arg_dmds div rhs
|
| 2058 | 2070 | |
| 2059 | 2071 | -- Check for an OPAQUE function: see Note [OPAQUE pragma]
|
| ... | ... | @@ -2097,7 +2109,7 @@ finaliseArgBoxities env fn ww_arity arg_dmds div rhs |
| 2097 | 2109 | [ bndr | bndr <- bndrs, isRuntimeVar bndr ]
|
| 2098 | 2110 | arg_dmds
|
| 2099 | 2111 | where
|
| 2100 | - mk_triple bndr dmd = (idType bndr, NotMarkedStrict, get_dmd dmd)
|
|
| 2112 | + mk_triple bndr arg_dmd = (idType bndr, NotMarkedStrict, get_dmd arg_dmd)
|
|
| 2101 | 2113 | |
| 2102 | 2114 | arg_dmds' = ww_arg_dmds ++ map trimBoxity (drop ww_arity arg_dmds)
|
| 2103 | 2115 | -- If ww_arity < length arg_dmds, the leftover ones
|
| ... | ... | @@ -23,8 +23,8 @@ module GHC.Types.Demand ( |
| 23 | 23 | lubCard, lubDmd, lubSubDmd,
|
| 24 | 24 | -- *** Greatest lower bound
|
| 25 | 25 | glbCard,
|
| 26 | - -- *** Unfolding combination (glb on strictness, lub on usage)
|
|
| 27 | - lubUBglbLBDmd,
|
|
| 26 | + -- *** Maximum (glb on strictness, lub on usage)
|
|
| 27 | + maxCard, maxDmd,
|
|
| 28 | 28 | -- *** Plus
|
| 29 | 29 | plusCard, plusDmd, plusSubDmd,
|
| 30 | 30 | -- *** Multiply
|
| ... | ... | @@ -57,7 +57,7 @@ module GHC.Types.Demand ( |
| 57 | 57 | DmdType(..), dmdTypeDepth,
|
| 58 | 58 | -- ** Algebra
|
| 59 | 59 | nopDmdType, botDmdType,
|
| 60 | - lubDmdType, lubUBglbLBDmdType, plusDmdType, multDmdType, discardArgDmds,
|
|
| 60 | + lubDmdType, maxDmdType, plusDmdType, multDmdType, discardArgDmds,
|
|
| 61 | 61 | -- ** Other operations
|
| 62 | 62 | peelFV, findIdDemand, addDemand, splitDmdTy, deferAfterPreciseException,
|
| 63 | 63 | |
| ... | ... | @@ -899,43 +899,46 @@ See Note [Absence analysis for stable unfoldings and RULES] in GHC.Core.Opt.DmdA |
| 899 | 899 | for the broader context.
|
| 900 | 900 | -}
|
| 901 | 901 | |
| 902 | --- | Combine demands for stable unfolding analysis.
|
|
| 902 | +-- | Takes the maximum of both the lower and upper bound of two 'Card's.
|
|
| 903 | +-- Semantically, this is glb on lower (strictness) and lub on upper (usage).
|
|
| 903 | 904 | -- See Note [Combining demands for stable unfoldings].
|
| 904 | -lubUBglbLBCard :: Card -> Card -> Card
|
|
| 905 | +maxCard :: Card -> Card -> Card
|
|
| 905 | 906 | -- Given Note [Bit vector representation for Card]:
|
| 906 | 907 | -- * bit 0 (strictness): take AND (glb) - 0 means strict, so 0 wins
|
| 907 | 908 | -- * bits 1,2 (usage): take OR (lub) - if either uses, result uses
|
| 908 | -lubUBglbLBCard (Card a) (Card b) = Card ((a .&. b .&. 0b001) .|. ((a .|. b) .&. 0b110))
|
|
| 909 | +maxCard (Card a) (Card b) = Card ((a .&. b .&. 0b001) .|. ((a .|. b) .&. 0b110))
|
|
| 909 | 910 | |
| 910 | --- | See Note [Combining demands for stable unfoldings].
|
|
| 911 | -lubUBglbLBDmd :: Demand -> Demand -> Demand
|
|
| 912 | -lubUBglbLBDmd BotDmd dmd2 = dmd2
|
|
| 913 | -lubUBglbLBDmd dmd1 BotDmd = dmd1
|
|
| 914 | -lubUBglbLBDmd (n1 :* sd1) (n2 :* sd2) =
|
|
| 915 | - lubUBglbLBCard n1 n2 :* lubUBglbLBSubDmd sd1 sd2
|
|
| 911 | +-- | Takes the maximum of both the lower and upper bounds of two 'Demand's.
|
|
| 912 | +-- Semantically, glb on lower (strictness) and lub on upper (usage).
|
|
| 913 | +-- See Note [Combining demands for stable unfoldings].
|
|
| 914 | +maxDmd :: Demand -> Demand -> Demand
|
|
| 915 | +maxDmd BotDmd dmd2 = dmd2
|
|
| 916 | +maxDmd dmd1 BotDmd = dmd1
|
|
| 917 | +maxDmd (n1 :* sd1) (n2 :* sd2) =
|
|
| 918 | + maxCard n1 n2 :* maxSubDmd sd1 sd2
|
|
| 916 | 919 | |
| 917 | -lubUBglbLBSubDmd :: SubDemand -> SubDemand -> SubDemand
|
|
| 920 | +maxSubDmd :: SubDemand -> SubDemand -> SubDemand
|
|
| 918 | 921 | -- Shortcuts for neutral and absorbing elements.
|
| 919 | -lubUBglbLBSubDmd (Poly Unboxed C_10) sd = sd
|
|
| 920 | -lubUBglbLBSubDmd sd (Poly Unboxed C_10) = sd
|
|
| 921 | -lubUBglbLBSubDmd sd@(Poly Boxed C_0N) _ = sd
|
|
| 922 | -lubUBglbLBSubDmd _ sd@(Poly Boxed C_0N) = sd
|
|
| 922 | +maxSubDmd (Poly Unboxed C_00) sd = sd
|
|
| 923 | +maxSubDmd sd (Poly Unboxed C_00) = sd
|
|
| 924 | +maxSubDmd sd@(Poly Boxed C_1N) _ = sd
|
|
| 925 | +maxSubDmd _ sd@(Poly Boxed C_1N) = sd
|
|
| 923 | 926 | -- Prod
|
| 924 | -lubUBglbLBSubDmd (Prod b1 ds1) (Poly b2 n2)
|
|
| 927 | +maxSubDmd (Prod b1 ds1) (Poly b2 n2)
|
|
| 925 | 928 | | let !d = polyFieldDmd b2 n2
|
| 926 | - = mkProd (lubBoxity b1 b2) (strictMap (lubUBglbLBDmd d) ds1)
|
|
| 927 | -lubUBglbLBSubDmd (Prod b1 ds1) (Prod b2 ds2)
|
|
| 929 | + = mkProd (lubBoxity b1 b2) (strictMap (maxDmd d) ds1)
|
|
| 930 | +maxSubDmd (Prod b1 ds1) (Prod b2 ds2)
|
|
| 928 | 931 | | equalLength ds1 ds2
|
| 929 | - = mkProd (lubBoxity b1 b2) (strictZipWith lubUBglbLBDmd ds1 ds2)
|
|
| 932 | + = mkProd (lubBoxity b1 b2) (strictZipWith maxDmd ds1 ds2)
|
|
| 930 | 933 | -- Handle Call
|
| 931 | -lubUBglbLBSubDmd (Call n1 sd1) (viewCall -> Just (n2, sd2)) =
|
|
| 932 | - mkCall (lubUBglbLBCard n1 n2) (lubUBglbLBSubDmd sd1 sd2)
|
|
| 934 | +maxSubDmd (Call n1 sd1) (viewCall -> Just (n2, sd2)) =
|
|
| 935 | + mkCall (maxCard n1 n2) (maxSubDmd sd1 sd2)
|
|
| 933 | 936 | -- Handle Poly
|
| 934 | -lubUBglbLBSubDmd (Poly b1 n1) (Poly b2 n2) = Poly (lubBoxity b1 b2) (lubUBglbLBCard n1 n2)
|
|
| 937 | +maxSubDmd (Poly b1 n1) (Poly b2 n2) = Poly (lubBoxity b1 b2) (maxCard n1 n2)
|
|
| 935 | 938 | -- Other Poly case by commutativity
|
| 936 | -lubUBglbLBSubDmd sd1@Poly{} sd2 = lubUBglbLBSubDmd sd2 sd1
|
|
| 937 | --- Otherwise (Call `lubUBglbLB` Prod) return Top
|
|
| 938 | -lubUBglbLBSubDmd _ _ = topSubDmd
|
|
| 939 | +maxSubDmd sd1@Poly{} sd2 = maxSubDmd sd2 sd1
|
|
| 940 | +-- Otherwise (Call `max` Prod) return Top
|
|
| 941 | +maxSubDmd _ _ = topSubDmd
|
|
| 939 | 942 | |
| 940 | 943 | -- | Denotes '+' on 'Demand'.
|
| 941 | 944 | plusDmd :: Demand -> Demand -> Demand
|
| ... | ... | @@ -1909,22 +1912,22 @@ lubDmdType d1 d2 = DmdType lub_fv lub_ds |
| 1909 | 1912 | |
| 1910 | 1913 | -- | Combine two 'DmdType's for stable unfolding analysis.
|
| 1911 | 1914 | -- See Note [Combining demands for stable unfoldings].
|
| 1912 | -lubUBglbLBDmdType :: DmdType -> DmdType -> DmdType
|
|
| 1913 | -lubUBglbLBDmdType (DmdType fv1 ds1) (DmdType fv2 ds2)
|
|
| 1915 | +maxDmdType :: DmdType -> DmdType -> DmdType
|
|
| 1916 | +maxDmdType (DmdType fv1 ds1) (DmdType fv2 ds2)
|
|
| 1914 | 1917 | = DmdType combined_fv combined_ds
|
| 1915 | 1918 | where
|
| 1916 | - combined_fv = lubUBglbLBDmdEnv fv1 fv2
|
|
| 1919 | + combined_fv = maxDmdEnv fv1 fv2
|
|
| 1917 | 1920 | combined_ds = go ds1 ds2
|
| 1918 | 1921 | -- If lists have different lengths, keep remaining ds1 (from RHS)
|
| 1919 | 1922 | go rhs [] = rhs
|
| 1920 | 1923 | go [] _ = []
|
| 1921 | - go (r:rhs) (u:unfs) = lubUBglbLBDmd r u : go rhs unfs
|
|
| 1924 | + go (r:rhs) (u:unfs) = maxDmd r u : go rhs unfs
|
|
| 1922 | 1925 | |
| 1923 | 1926 | -- | See Note [Combining demands for stable unfoldings].
|
| 1924 | -lubUBglbLBDmdEnv :: DmdEnv -> DmdEnv -> DmdEnv
|
|
| 1925 | -lubUBglbLBDmdEnv (DE fv1 d1) (DE fv2 d2) = DE combined_fv combined_div
|
|
| 1927 | +maxDmdEnv :: DmdEnv -> DmdEnv -> DmdEnv
|
|
| 1928 | +maxDmdEnv (DE fv1 d1) (DE fv2 d2) = DE combined_fv combined_div
|
|
| 1926 | 1929 | where
|
| 1927 | - combined_fv = plusVarEnv_CD lubUBglbLBDmd fv1 (defaultFvDmd d1) fv2 (defaultFvDmd d2)
|
|
| 1930 | + combined_fv = plusVarEnv_CD maxDmd fv1 (defaultFvDmd d1) fv2 (defaultFvDmd d2)
|
|
| 1928 | 1931 | combined_div = lubDivergence d1 d2
|
| 1929 | 1932 | |
| 1930 | 1933 | discardArgDmds :: DmdType -> DmdEnv
|
| 1 | +4.0 |