Commit 02f893eb authored by Alan Mock's avatar Alan Mock Committed by Ben Gamari

integer-gmp: Make minusInteger more efficient

Give `minusInteger` its own implementation.
Previously `minusInteger` used `plusInteger` and `negateInteger`, which
meant it always allocated.  Now it works more like `plusInteger`.

Reviewers: goldfire, hvr, bgamari, austin

Reviewed By: hvr, bgamari, austin

Subscribers: thomie

Differential Revision: https://phabricator.haskell.org/D2278

GHC Trac Issues: #12129
parent 079c1b8c
# Changelog for [`integer-gmp` package](http://hackage.haskell.org/package/integer-gmp)
## 1.0.0.2 *TBA*
* Optimize `minusInteger`
## 1.0.0.1 *Feb 2016*
* Bundled with GHC 8.0.1
......
......@@ -418,10 +418,44 @@ plusInteger (Jp# x) (Jn# y)
GT -> bigNatToInteger (minusBigNat x y)
{-# CONSTANT_FOLDED plusInteger #-}
-- TODO
-- | Subtract two 'Integer's from each other.
-- | Subtract one 'Integer' from another.
minusInteger :: Integer -> Integer -> Integer
minusInteger x y = inline plusInteger x (inline negateInteger y)
minusInteger x (S# 0#) = x
minusInteger (S# 0#) (S# INT_MINBOUND#) = Jp# (wordToBigNat ABS_INT_MINBOUND##)
minusInteger (S# 0#) (S# y#) = S# (negateInt# y#)
minusInteger (S# x#) (S# y#)
= case subIntC# x# y# of
(# z#, 0# #) -> S# z#
(# 0#, _ #) -> Jn# (wordToBigNat2 1## 0##)
(# z#, _ #)
| isTrue# (z# ># 0#) -> Jn# (wordToBigNat ( (int2Word# (negateInt# z#))))
| True -> Jp# (wordToBigNat ( (int2Word# z#)))
minusInteger (S# x#) (Jp# y)
| isTrue# (x# >=# 0#) = bigNatToNegInteger (minusBigNatWord y (int2Word# x#))
| True = Jn# (plusBigNatWord y (int2Word# (negateInt# x#)))
minusInteger (S# x#) (Jn# y)
| isTrue# (x# >=# 0#) = Jp# (plusBigNatWord y (int2Word# x#))
| True = bigNatToInteger (minusBigNatWord y (int2Word#
(negateInt# x#)))
minusInteger (Jp# x) (Jp# y)
= case compareBigNat x y of
LT -> bigNatToNegInteger (minusBigNat y x)
EQ -> S# 0#
GT -> bigNatToInteger (minusBigNat x y)
minusInteger (Jp# x) (Jn# y) = Jp# (plusBigNat x y)
minusInteger (Jn# x) (Jp# y) = Jn# (plusBigNat x y)
minusInteger (Jn# x) (Jn# y)
= case compareBigNat x y of
LT -> bigNatToInteger (minusBigNat y x)
EQ -> S# 0#
GT -> bigNatToNegInteger (minusBigNat x y)
minusInteger (Jp# x) (S# y#)
| isTrue# (y# >=# 0#) = bigNatToInteger (minusBigNatWord x (int2Word# y#))
| True = Jp# (plusBigNatWord x (int2Word# (negateInt# y#)))
minusInteger (Jn# x) (S# y#)
| isTrue# (y# >=# 0#) = Jn# (plusBigNatWord x (int2Word# y#))
| True = bigNatToNegInteger (minusBigNatWord x
(int2Word# (negateInt# y#)))
{-# CONSTANT_FOLDED minusInteger #-}
-- | Multiply two 'Integer's
......
......@@ -2,6 +2,7 @@ test('integerBits', normal, compile_and_run, [''])
test('integerConversions', normal, compile_and_run, [''])
# skip ghci as it doesn't support unboxed tuples
test('integerGmpInternals', [reqlib('integer-gmp'), omit_ways('ghci')], compile_and_run, [''])
test('plusMinusInteger', [reqlib('integer-gmp'), omit_ways('ghci')], compile_and_run, [''])
test('integerConstantFolding',
[extra_clean(['integerConstantFolding.simpl']),
when(compiler_debugged(), expect_broken(11006))],
......@@ -16,4 +17,3 @@ test('IntegerConversionRules',
run_command,
['$MAKE -s --no-print-directory IntegerConversionRules'])
test('gcdInteger', normal, compile_and_run, [''])
module Main (main) where
main :: IO ()
main = do
print $ length vals
where
boundaries :: [Integer]
boundaries = [fromIntegral (maxBound :: Int) - 3,
fromIntegral (maxBound :: Int) - 2,
fromIntegral (maxBound :: Int) - 1,
fromIntegral (maxBound :: Int),
fromIntegral (maxBound :: Int) + 1,
fromIntegral (maxBound :: Int) + 2,
fromIntegral (maxBound :: Int) + 3,
fromIntegral (minBound :: Int) - 3,
fromIntegral (minBound :: Int) - 2,
fromIntegral (minBound :: Int) - 1,
fromIntegral (minBound :: Int),
fromIntegral (minBound :: Int) + 1,
fromIntegral (minBound :: Int) + 2,
fromIntegral (minBound :: Int) + 3,
fromIntegral (maxBound :: Word) - 3,
fromIntegral (maxBound :: Word) - 2,
fromIntegral (maxBound :: Word) - 1,
fromIntegral (maxBound :: Word),
fromIntegral (maxBound :: Word) + 1,
fromIntegral (maxBound :: Word) + 2,
fromIntegral (maxBound :: Word) + 3,
-3, -2, -1, 0, 1, 2, 3]
vals = filter (\(x, y) -> x /= y) [(x - y, x + negate y) |
x <- boundaries, y <- boundaries]
......@@ -204,9 +204,10 @@ test('T5549',
# expected value: 3362958676 (Windows)
# 2014-12-01: 4096606332 (Windows) integer-gmp2
(wordsize(64), 8193140752, 5)]),
(wordsize(64), 5793140200, 5)]),
# expected value: 6725846120 (amd64/Linux)
# 8193140752 (amd64/Linux) integer-gmp2
# 5793140200 (amd64/Linux) integer-gmp2
only_ways(['normal'])
],
compile_and_run,
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment