Skip to content

DmdAnal: Handling of RULES and unfolding free variables might be broken

While working on !7044, I realised that our current keepAlive* logic might be broken.

In particular, we have code of this form:

    -- See Note [Absence analysis for stable unfoldings and RULES]
    rule_fvs           = bndrRuleAndUnfoldingIds id
    final_ty           = body_ty' `plusDmdType` rhs_ty `keepAliveDmdType` rule_fvs


....


    -- See Note [Absence analysis for stable unfoldings and RULES]
    rhs_fv2 = rhs_fv1 `keepAliveDmdEnv` bndrRuleAndUnfoldingIds id

In dmdAnalBindLetUp and dmdAnalRhsSig (called from dmdAnalBindLEtDown), respectively.

This code fails to unleash demands on free variables in the demand signature of those FVs! E.g., if we could write

foo :: Integer -> Integer
foo a = f a
  where
    z :: Integer
    z = 0
    {-# NOINLINE z #-}

    g :: Integer -> Integer -> Integer
    g x y = x+z
    {-# NOINLINE g #-}
    
    f :: Integer -> Integer
    f x = x+a
    {-# NOINLINE[0] f #-}
    {-# RULES "f to g" f 0 = g 0 #-}

(which we can't because RULES on local bindings don't work), then we'd do the following:

  1. Compute a signature for g, <1L>{z->1L>}. Note that it is strict in its FV x.
  2. Analyse f's RHS. Get DmdType <1L>. Note that it doesn't mention g!
  3. Now we do the keepAliveDmdEnv on {g}, the only FV of f's RULE. This entails simply adding g to the DmdEnv of f. We get the final signature <1L>{g->L}.
  4. Analyse and unleash fs signature at the call f a.
  5. ... Leave scopes of f and g, properly annotating them ... 6.Realise that z is absent. Wrong wrong wrong!! This might lead to a crash whenever we rewrite f to g.

This won't work if lambda-lift f and g, because then we'll automatically record many-uses that end up in the lazy_fvs. In particular, we'd automatically record a usage of z->L when we add the lazy_fv's of g; z->1L would never be part of g's signature.

It also doesn't work as written, because we can't declare RULES on nested functions.

So I haven't been able to actually reproduce the issue in production. Nevertheless, the danger is there! And !7044 trips over it, because it considers no variable as weak. So it will actually give g the sig <1L>{z->1L>}, which we fail to unleash as part of keepAliveDmdEnv.

!7044 now has the fix. !5349 fixes it in similar manner.

Edited by Sebastian Graf
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information