diff options
author | David Feuer <David.Feuer@gmail.com> | 2014-10-29 15:47:57 +0100 |
---|---|---|
committer | Joachim Breitner <mail@joachim-breitner.de> | 2014-10-29 15:48:04 +0100 |
commit | 64d0a198be05c7baff36e43ab96928a402f00a19 (patch) | |
tree | 5a9488cef1f4ce7d25200cf7f90d920b21bfc510 /libraries/base | |
parent | f1090855d9b8d33b3194364dcca0683d89049f03 (diff) | |
download | haskell-64d0a198be05c7baff36e43ab96928a402f00a19.tar.gz |
Really fix fft2 regression. #9740
Rewrite `take` more aggressively for fusion. Add some more explicit
strictness to `unsafeTake` and `unsafeDrop` that seems to help code size and
allocation just a drop in some nofib tests. They were not previously
strict in their numerical arguments, but always called in contexts where
those had been forced; it didn't make a difference in simple test cases,
but made a small difference for nofib. See #9740.
Differential Revision: https://phabricator.haskell.org/D394
Diffstat (limited to 'libraries/base')
-rw-r--r-- | libraries/base/GHC/List.lhs | 34 |
1 files changed, 20 insertions, 14 deletions
diff --git a/libraries/base/GHC/List.lhs b/libraries/base/GHC/List.lhs index 89c33d66f2..6a930333e0 100644 --- a/libraries/base/GHC/List.lhs +++ b/libraries/base/GHC/List.lhs @@ -533,23 +533,29 @@ take n _ | n <= 0 = [] take _ [] = [] take n (x:xs) = x : take (n-1) xs #else --- We always want to inline this to take advantage of a known --- length argument sign. -{-# INLINE take #-} + +{- We always want to inline this to take advantage of a known length argument +sign. Note, however, that it's important for the RULES to grab take, rather +than trying to INLINE take immediately and then letting the RULES grab +unsafeTake. Presumably the latter approach doesn't grab it early enough; it led +to an allocation regression in nofib/fft2. -} +{-# INLINE [1] take #-} take n xs | 0 < n = unsafeTake n xs | otherwise = [] -- A version of take that takes the whole list if it's given an argument less --- than 1. This does the same thing as the fold version. +-- than 1. {-# NOINLINE [1] unsafeTake #-} unsafeTake :: Int -> [a] -> [a] -unsafeTake _ [] = [] -unsafeTake 1 (x: _) = [x] -unsafeTake m (x:xs) = x : unsafeTake (m - 1) xs +unsafeTake !_ [] = [] +unsafeTake 1 (x: _) = [x] +unsafeTake m (x:xs) = x : unsafeTake (m - 1) xs {-# RULES -"unsafeTake" [~1] forall n xs . unsafeTake n xs = - build (\c nil -> foldr (takeFB c nil) (flipSeqTake nil) xs n) +"take" [~1] forall n xs . take n xs = + build (\c nil -> if 0 < n + then foldr (takeFB c nil) (flipSeqTake nil) xs n + else nil) "unsafeTakeList" [1] forall n xs . foldr (takeFB (:) []) (flipSeqTake []) xs n = unsafeTake n xs #-} @@ -558,8 +564,8 @@ unsafeTake m (x:xs) = x : unsafeTake (m - 1) xs -- Just flip seq, specialized to Int, but not inlined too early. -- It's important to force the numeric argument here, even though -- it's not used. Otherwise, take n [] doesn't force n. This is --- bad for strictness analysis and unboxing, and leads to test suite --- performance regressions. +-- bad for strictness analysis and unboxing, and leads to increased +-- allocation in T7257. flipSeqTake :: a -> Int -> a flipSeqTake x !_n = x @@ -602,9 +608,9 @@ drop n ls -- A version of drop that drops the whole list if given an argument -- less than 1 unsafeDrop :: Int -> [a] -> [a] - unsafeDrop _ [] = [] - unsafeDrop 1 (_:xs) = xs - unsafeDrop m (_:xs) = unsafeDrop (m - 1) xs + unsafeDrop !_ [] = [] + unsafeDrop 1 (_:xs) = xs + unsafeDrop m (_:xs) = unsafeDrop (m - 1) xs #endif -- | 'splitAt' @n xs@ returns a tuple where first element is @xs@ prefix of |