summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Ericson <git@JohnEricson.me>2019-10-19 18:59:48 -0400
committerJohn Ericson <John.Ericson@Obsidian.Systems>2021-03-15 03:06:10 +0000
commit9c5db244d7607ab46266c3f6b437d2f1ce08f858 (patch)
tree38b8ec71d2082726f5be210c642f62bdf494b0ef
parent87ae062ab8a73430308f4ea5967e76bc384e5a76 (diff)
downloadhaskell-wip/defensive-rem-mod.tar.gz
Add more boundary checks for `rem` and `mod`wip/defensive-rem-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.hs62
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#)