[GHC] #16111: Inconsistent behavior of Data.Bits.shiftL with different optimization levels and -fllvm
GHC
ghc-devs at haskell.org
Wed Jan 9 22:52:42 UTC 2019
#16111: Inconsistent behavior of Data.Bits.shiftL with different optimization
levels and -fllvm
-------------------------------------+-------------------------------------
Reporter: RyanGlScott | Owner: (none)
Type: bug | Status: new
Priority: normal | Milestone:
Component: Compiler | Version: 8.6.3
Resolution: | Keywords:
Operating System: Unknown/Multiple | Architecture:
Type of failure: Incorrect result | Unknown/Multiple
at runtime | Test Case:
Blocked By: | Blocking:
Related Tickets: | Differential Rev(s):
Wiki Page: |
-------------------------------------+-------------------------------------
Changes (by harpocrates):
* cc: harpocrates (added)
Comment:
`shiftL` is ''not'' supposed to be called with a negative number of bits
(that's what `shift` is for). It's documented in the Haddock for `shiftL`:
> Shift the argument left by the specified number of bits (which must be
non-negative).
Without any heavy optimizations, `shiftL 1 hm` turns into `shiftL#` turns
into the `uncheckedShiftL#` primop, which explicitly says that a negative
number of bits produces undefined output. I suspect it is nonetheless
usually deterministic, hence the `True` outputs.
On `-O2`, we'll trigger the `uncheckedShiftL#` builtin rule. That rule
takes one look at the negative shift bits and decides to "optimize" this
into a runtime error that prints out `"Bad shift length"` and the shift
length.
The only case that isn't yet covered is the `-O1 -fllvm` case. It's likely
that the LLVM call we produce for `uncheckedShiftL#` also has undefined
behaviour for negative shift values, and LLVM applies some more
optimizations ultimately resulting in the `False` output.
----
This looks like a bad API: we really should have `shiftL :: a -> Word ->
a` instead of `shiftL :: a -> Int -> a` (and same for `shiftR`). Instead
of stomaching that breakage, we could also just add an extra check to the
`Word`, `Int`, etc. instances of `shiftL` to guard against negative
inputs:
{{{
instance Bits Word where
{- snipped -}
(W# x#) `shift` (I# i#)
| isTrue# (i# >=# 0#) = W# (x# `shiftL#` i#)
| otherwise = W# (x# `shiftRL#` negateInt# i#)
(W# x#) `shiftL` (I# i#)
| isTrue# (i# >=# 0#) = W# (x# `shiftL#` i#)
| otherwise = error "shiftL: expected non-negative
number of bits"
}}}
Or even: deprecate `shiftL`/`shiftR` entirely in favour of `shift` (and
let the default definitions, which fall back to the safer `shift`, take
effect).
Thoughts?
--
Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/16111#comment:3>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler
More information about the ghc-tickets
mailing list