diff options
author | John Ericson <git@JohnEricson.me> | 2019-10-19 18:59:48 -0400 |
---|---|---|
committer | Marge Bot <ben+marge-bot@smart-cactus.org> | 2021-03-20 07:52:12 -0400 |
commit | 3fa3fb79e02858c29797a904655985628513cc01 (patch) | |
tree | 07d8d1213c7a17c7a5eda0c582945103a5721ede | |
parent | d4605e7ce4f5f8252a1e932e239cab79219875a5 (diff) | |
download | haskell-3fa3fb79e02858c29797a904655985628513cc01.tar.gz |
Add more boundary checks for `rem` and `mod`
It's quite backend-dependent whether we will actually handle that case
right, so let's just always do this as a precaution.
In particular, once we replace the native primops used here with the new
sized primops, the 16-bit ones on x86 will begin to use 16-bit sized
instructions where they didn't before.
Though I'm not sure of any arch which has 8-bit scalar instructions, I
also did those for consistency. Plus, there are *vector* 8-bit ops in
the wild, so if we ever got into autovectorization or something maybe
it's prudent to put this here as a reminder not to forget about
catching overflows.
Progress towards #19026
-rw-r--r-- | libraries/base/GHC/Int.hs | 62 |
1 files changed, 44 insertions, 18 deletions
diff --git a/libraries/base/GHC/Int.hs b/libraries/base/GHC/Int.hs index 2fe7d6ce8c..6713130c14 100644 --- a/libraries/base/GHC/Int.hs +++ b/libraries/base/GHC/Int.hs @@ -136,6 +136,11 @@ instance Integral Int8 where | otherwise = I8# (intToInt8# ((int8ToInt# x#) `quotInt#` (int8ToInt# y#))) rem (I8# x#) y@(I8# y#) | y == 0 = divZeroError + -- The quotRem CPU instruction might fail for 'minBound + -- `quotRem` -1' if it is an instruction for exactly this + -- width of signed integer. But, 'minBound `rem` -1' is + -- well-defined (0). We therefore special-case it. + | y == (-1) = 0 | otherwise = I8# (intToInt8# ((int8ToInt# x#) `remInt#` (int8ToInt# y#))) div x@(I8# x#) y@(I8# y#) | y == 0 = divZeroError @@ -143,6 +148,11 @@ instance Integral Int8 where | otherwise = I8# (intToInt8# ((int8ToInt# x#) `divInt#` (int8ToInt# y#))) mod (I8# x#) y@(I8# y#) | y == 0 = divZeroError + -- The divMod CPU instruction might fail for 'minBound + -- `divMod` -1' if it is an instruction for exactly this + -- width of signed integer. But, 'minBound `mod` -1' is + -- well-defined (0). We therefore special-case it. + | y == (-1) = 0 | otherwise = I8# (intToInt8# ((int8ToInt# x#) `modInt#` (int8ToInt# y#))) quotRem x@(I8# x#) y@(I8# y#) | y == 0 = divZeroError @@ -343,6 +353,11 @@ instance Integral Int16 where | otherwise = I16# (intToInt16# ((int16ToInt# x#) `quotInt#` (int16ToInt# y#))) rem (I16# x#) y@(I16# y#) | y == 0 = divZeroError + -- The quotRem CPU instruction might fail for 'minBound + -- `quotRem` -1' if it is an instruction for exactly this + -- width of signed integer. But, 'minBound `rem` -1' is + -- well-defined (0). We therefore special-case it. + | y == (-1) = 0 | otherwise = I16# (intToInt16# ((int16ToInt# x#) `remInt#` (int16ToInt# y#))) div x@(I16# x#) y@(I16# y#) | y == 0 = divZeroError @@ -350,6 +365,11 @@ instance Integral Int16 where | otherwise = I16# (intToInt16# ((int16ToInt# x#) `divInt#` (int16ToInt# y#))) mod (I16# x#) y@(I16# y#) | y == 0 = divZeroError + -- The divMod CPU instruction might fail for 'minBound + -- `divMod` -1' if it is an instruction for exactly this + -- width of signed integer. But, 'minBound `mod` -1' is + -- well-defined (0). We therefore special-case it. + | y == (-1) = 0 | otherwise = I16# (intToInt16# ((int16ToInt# x#) `modInt#` (int16ToInt# y#))) quotRem x@(I16# x#) y@(I16# y#) | y == 0 = divZeroError @@ -555,9 +575,10 @@ instance Integral Int32 where | otherwise = I32# (intToInt32# ((int32ToInt# x#) `quotInt#` (int32ToInt# y#))) rem (I32# x#) y@(I32# y#) | y == 0 = divZeroError - -- The quotRem CPU instruction fails for minBound `quotRem` -1, - -- but minBound `rem` -1 is well-defined (0). We therefore - -- special-case it. + -- The quotRem CPU instruction might fail for 'minBound + -- `quotRem` -1' if it is an instruction for exactly this + -- width of signed integer. But, 'minBound `rem` -1' is + -- well-defined (0). We therefore special-case it. | y == (-1) = 0 | otherwise = I32# (intToInt32# ((int32ToInt# x#) `remInt#` (int32ToInt# y#))) div x@(I32# x#) y@(I32# y#) @@ -566,9 +587,10 @@ instance Integral Int32 where | otherwise = I32# (intToInt32# ((int32ToInt# x#) `divInt#` (int32ToInt# y#))) mod (I32# x#) y@(I32# y#) | y == 0 = divZeroError - -- The divMod CPU instruction fails for minBound `divMod` -1, - -- but minBound `mod` -1 is well-defined (0). We therefore - -- special-case it. + -- The divMod CPU instruction might fail for 'minBound + -- `divMod` -1' if it is an instruction for exactly this + -- width of signed integer. But, 'minBound `mod` -1' is + -- well-defined (0). We therefore special-case it. | y == (-1) = 0 | otherwise = I32# (intToInt32# ((int32ToInt# x#) `modInt#` (int32ToInt# y#))) quotRem x@(I32# x#) y@(I32# y#) @@ -776,9 +798,10 @@ instance Integral Int64 where | otherwise = I64# (x# `quotInt64#` y#) rem (I64# x#) y@(I64# y#) | y == 0 = divZeroError - -- The quotRem CPU instruction fails for minBound `quotRem` -1, - -- but minBound `rem` -1 is well-defined (0). We therefore - -- special-case it. + -- The quotRem CPU instruction might fail for 'minBound + -- `quotRem` -1' if it is an instruction for exactly this + -- width of signed integer. But, 'minBound `rem` -1' is + -- well-defined (0). We therefore special-case it. | y == (-1) = 0 | otherwise = I64# (x# `remInt64#` y#) div x@(I64# x#) y@(I64# y#) @@ -787,9 +810,10 @@ instance Integral Int64 where | otherwise = I64# (x# `divInt64#` y#) mod (I64# x#) y@(I64# y#) | y == 0 = divZeroError - -- The divMod CPU instruction fails for minBound `divMod` -1, - -- but minBound `mod` -1 is well-defined (0). We therefore - -- special-case it. + -- The divMod CPU instruction might fail for 'minBound + -- `divMod` -1' if it is an instruction for exactly this + -- width of signed integer. But, 'minBound `mod` -1' is + -- well-defined (0). We therefore special-case it. | y == (-1) = 0 | otherwise = I64# (x# `modInt64#` y#) quotRem x@(I64# x#) y@(I64# y#) @@ -976,9 +1000,10 @@ instance Integral Int64 where | otherwise = I64# (x# `quotInt#` y#) rem (I64# x#) y@(I64# y#) | y == 0 = divZeroError - -- The quotRem CPU instruction fails for minBound `quotRem` -1, - -- but minBound `rem` -1 is well-defined (0). We therefore - -- special-case it. + -- The quotRem CPU instruction might fail for 'minBound + -- `quotRem` -1' if it is an instruction for exactly this + -- width of signed integer. But, 'minBound `rem` -1' is + -- well-defined (0). We therefore special-case it. | y == (-1) = 0 | otherwise = I64# (x# `remInt#` y#) div x@(I64# x#) y@(I64# y#) @@ -987,9 +1012,10 @@ instance Integral Int64 where | otherwise = I64# (x# `divInt#` y#) mod (I64# x#) y@(I64# y#) | y == 0 = divZeroError - -- The divMod CPU instruction fails for minBound `divMod` -1, - -- but minBound `mod` -1 is well-defined (0). We therefore - -- special-case it. + -- The divMod CPU instruction might fail for 'minBound + -- `divMod` -1' if it is an instruction for exactly this + -- width of signed integer. But, 'minBound `mod` -1' is + -- well-defined (0). We therefore special-case it. | y == (-1) = 0 | otherwise = I64# (x# `modInt#` y#) quotRem x@(I64# x#) y@(I64# y#) |