Zubin pushed to branch wip/26416 at Glasgow Haskell Compiler / GHC

Commits:

3 changed files:

Changes:

  • compiler/GHC/Core/Opt/DmdAnal.hs
    ... ... @@ -1106,8 +1106,17 @@ dmdAnalRhsSig top_lvl rec_flag env let_sd id rhs
    1106 1106
     
    
    1107 1107
         WithDmdType rhs_dmd_ty rhs' = dmdAnal env rhs_sd rhs
    
    1108 1108
         DmdType rhs_env rhs_dmds = rhs_dmd_ty
    
    1109
    +
    
    1110
    +    -- See Note [Absence analysis for stable unfoldings and RULES]
    
    1111
    +    -- If there's a stable unfolding, we need to combine argument demands
    
    1112
    +    -- from the unfolding with those from the RHS, because the unfolding
    
    1113
    +    -- might use arguments that the (optimised) RHS doesn't.
    
    1114
    +    -- Any argument with a demand absent in one but not the other can
    
    1115
    +    -- be problematic, see #26416
    
    1116
    +    combined_rhs_dmds = combineUnfoldingDmds env rhs_sd id rhs_dmds
    
    1117
    +
    
    1109 1118
         (final_rhs_dmds, final_rhs) = finaliseArgBoxities env id ww_arity
    
    1110
    -                                                      rhs_dmds (de_div rhs_env) rhs'
    
    1119
    +                                                      combined_rhs_dmds (de_div rhs_env) rhs'
    
    1111 1120
     
    
    1112 1121
         dmd_sig_arity = ww_arity + strictCallArity body_sd
    
    1113 1122
         sig = mkDmdSigForArity dmd_sig_arity (DmdType sig_env final_rhs_dmds)
    
    ... ... @@ -1144,6 +1153,27 @@ splitWeakDmds :: DmdEnv -> (DmdEnv, WeakDmds)
    1144 1153
     splitWeakDmds (DE fvs div) = (DE sig_fvs div, weak_fvs)
    
    1145 1154
       where (!weak_fvs, !sig_fvs) = partitionVarEnv isWeakDmd fvs
    
    1146 1155
     
    
    1156
    +-- | If there is a stable unfolding, don't let any demand be absent that
    
    1157
    +-- is also not absent in the unfolding
    
    1158
    +-- See Note [Absence analysis for stable unfoldings and RULES], Wrinkle (W3).
    
    1159
    +combineUnfoldingDmds :: AnalEnv -> SubDemand -> Id -> [Demand] -> [Demand]
    
    1160
    +combineUnfoldingDmds env rhs_sd id rhs_dmds
    
    1161
    +  | not (isStableUnfolding unf)
    
    1162
    +  = rhs_dmds  -- No stable unfolding, nothing to do
    
    1163
    +
    
    1164
    +  | Just unf_body <- maybeUnfoldingTemplate unf
    
    1165
    +  , let WithDmdType (DmdType _ unf_dmds) _ = dmdAnal env rhs_sd unf_body
    
    1166
    +  , let result = go rhs_dmds unf_dmds
    
    1167
    +  = -- pprTrace "lubUnfoldingDmds" (ppr id $$ ppr rhs_dmds $$ ppr unf_dmds $$ ppr result) $
    
    1168
    +   result
    
    1169
    +  | otherwise = rhs_dmds
    
    1170
    +  where
    
    1171
    +    unf = realIdUnfolding id
    
    1172
    +    go rhs          []            = rhs
    
    1173
    +    go []           _             = []
    
    1174
    +    go (AbsDmd:rhs) (u:unfs)      = u : go rhs unfs
    
    1175
    +    go (r:rhs)      (AbsDmd:unfs) = r : go rhs unfs
    
    1176
    +
    
    1147 1177
     -- | The result type after applying 'idArity' many arguments. Returns 'Nothing'
    
    1148 1178
     -- when the type doesn't have exactly 'idArity' many arrows.
    
    1149 1179
     resultType_maybe :: Id -> Maybe Type
    
    ... ... @@ -1523,6 +1553,25 @@ Wrinkles:
    1523 1553
         for `sg`, failing to unleash the signature and hence observed an absent
    
    1524 1554
         error instead of the `really important message`.
    
    1525 1555
     
    
    1556
    +  (W3) The SOLUTION above handles /free variables/ of stable unfoldings, but
    
    1557
    +    what about /arguments/?  Consider (#25965)
    
    1558
    +
    
    1559
    +       fromVector :: (Storable a, KnownNat n) => Vector a -> Vector a
    
    1560
    +       fromVector v = ... (uses Storable dictionary) ...
    
    1561
    +       {-# INLINABLE fromVector #-}
    
    1562
    +
    
    1563
    +    Suppose that the optimised RHS of `fromVector` somehow discards the use of
    
    1564
    +    the Storable dictionary, but the stable unfolding still uses it. Then the
    
    1565
    +    demand signature will say that the Storable dictionary argument is absent,
    
    1566
    +    and worker/wrapper will replace it with `LitRubbish`.  But when the
    
    1567
    +    worker's unfolding is inlined, it will use that rubbish value as a real
    
    1568
    +    dictionary, leading to a segfault!
    
    1569
    +
    
    1570
    +    SOLUTION: in `dmdAnalRhsSig`, if the function has a stable unfolding,
    
    1571
    +    analyse it and drop any AbsDmds which are not absent in the unfolding.
    
    1572
    +    This is done by `combineUnfoldingDmds`.  This ensures that if the unfolding
    
    1573
    +    uses an argument, it won't be marked as absent.
    
    1574
    +
    
    1526 1575
     Note [DmdAnal for DataCon wrappers]
    
    1527 1576
     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    1528 1577
     We give DataCon wrappers a (necessarily flat) demand signature in
    
    ... ... @@ -2046,8 +2095,11 @@ finaliseArgBoxities env fn ww_arity arg_dmds div rhs
    2046 2095
     
    
    2047 2096
         arg_triples :: [(Type, StrictnessMark, Demand)]
    
    2048 2097
         arg_triples = take ww_arity $
    
    2049
    -                  [ (idType bndr, NotMarkedStrict, get_dmd bndr)
    
    2050
    -                  | bndr <- bndrs, isRuntimeVar bndr ]
    
    2098
    +                  zipWith mk_triple
    
    2099
    +                          [ bndr | bndr <- bndrs, isRuntimeVar bndr ]
    
    2100
    +                          arg_dmds
    
    2101
    +      where
    
    2102
    +        mk_triple bndr dmd = (idType bndr, NotMarkedStrict, get_dmd dmd)
    
    2051 2103
     
    
    2052 2104
         arg_dmds' = ww_arg_dmds ++ map trimBoxity (drop ww_arity arg_dmds)
    
    2053 2105
                     -- If ww_arity < length arg_dmds, the leftover ones
    
    ... ... @@ -2063,12 +2115,10 @@ finaliseArgBoxities env fn ww_arity arg_dmds div rhs
    2063 2115
                         -- This is the budget initialisation step of
    
    2064 2116
                         -- Note [Worker argument budget]
    
    2065 2117
     
    
    2066
    -    get_dmd :: Id -> Demand
    
    2067
    -    get_dmd bndr
    
    2118
    +    get_dmd :: Demand -> Demand
    
    2119
    +    get_dmd dmd
    
    2068 2120
           | is_bot_fn = unboxDeeplyDmd dmd -- See Note [Boxity for bottoming functions],
    
    2069 2121
           | otherwise = dmd                --     case (B)
    
    2070
    -      where
    
    2071
    -        dmd = idDemandInfo bndr
    
    2072 2122
     
    
    2073 2123
         -- is_bot_fn:  see Note [Boxity for bottoming functions]
    
    2074 2124
         is_bot_fn = div == botDiv
    

  • testsuite/tests/dmdanal/should_run/M1.hs
    1
    +-- Short module name is essential, or else f doesn't inline
    
    2
    +module M1 where
    
    3
    +{-# INLINABLE [2] f #-}
    
    4
    +f :: Int -> Int -> Float
    
    5
    +f !dummy x = if   times dummy 0 x == 1
    
    6
    +             then 3.0 else 4.0
    
    7
    +
    
    8
    +{-# INLINE [0] times #-}
    
    9
    +times :: Int -> Int -> Int -> Int
    
    10
    +times dummy 0 x = x `seq` ( 0 + big dummy )
    
    11
    +times _     a b = a * b
    
    12
    +
    
    13
    +{-# RULES "times" [1] forall dummy x. times dummy 0 x = 0 + big dummy #-}
    
    14
    +
    
    15
    +big :: Int -> Int
    
    16
    +big x = succ . succ . succ . succ . succ . succ . succ . succ . succ $ x
    
    17
    +{-# INLINE big #-}

  • testsuite/tests/dmdanal/should_run/T26416.hs
    1
    +module Main where
    
    2
    +import M1 ( f )
    
    3
    +main = print (f 19 12)