Skip to content

DmdAnal: unlifted but ok-for-spec is still used

Consider

{-# LANGUAGE MagicHash #-}

module Lib where

import GHC.Exts

f :: Int# -> Int
f x = 0
{-# OPAQUE f #-}

g1 :: Int# -> Int
g1 x = f (42# `quotInt#` x)

g2 :: Int# -> Int
g2 x = f (uncheckedIShiftL# 1# x)

f is absent in its parameter, but the arguments at its call sites still need to be computed. Yet today we get

Lib.f: <A>
Lib.g1: <L>
Lib.g2: <A>

g1 says it uses its argument. And good thing at that, because if we weren't, then we could replace a call site g1 1# by g1 RUBBISH and the latter may well lead to a division-by-zero exception, depending on what value we pick for RUBBISH (remember that we may pick any).

But g2 says it is absent in its argument. Ergo we would rewrite a call site g2 3# by g2 RUBBISH, and when we pick 240598# as the value for RUBBISH (which we well could), then we'd trigger undefined behavior in the shift instruction. Which is not too bad either way, given that the Int# is absent.

g1 and g2 would no longer differ if we fixed #24698, but DmdAnal sort of assumes that the transformation in #24698 happens today, in that uncheckedIShiftL# 1# x will be replaced by a RUBBISH lit and thus the value of x will never be needed.

If we wanted to change the outcome, we would need to touch anticipateANF in DmdAnal, specifically remove exprOkForSpeculation from https://gitlab.haskell.org/ghc/ghc/-/blob/master/compiler/GHC/Core/Opt/DmdAnal.hs#L409 to have <L> unconditionally.

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