base: Mark `findIndices` as INLINABLE instead of INLINE (fixes #15426)
authorKevin Buhr <buhr@asaurus.net>
Tue, 21 Aug 2018 20:04:59 +0000 (16:04 -0400)
committerBen Gamari <ben@smart-cactus.org>
Tue, 21 Aug 2018 22:56:11 +0000 (18:56 -0400)
If `findIndices` is marked INLINE in `Data.OldList`, then the unfolded
versions of `elemIndex` and `findIndex` included in the interface file
are unfusible (even though `findIndices` itself remains fusible).  By
marking it INLINABLE instead, elemIndex` and `findIndex` will fuse
properly.

Test Plan: make TEST=T15426

Reviewers: hvr, bgamari

Reviewed By: bgamari

Subscribers: rwbarton, carter

GHC Trac Issues: #15426

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

libraries/base/Data/OldList.hs
testsuite/tests/perf/should_run/T15426.hs [new file with mode: 0644]
testsuite/tests/perf/should_run/all.T

index c4c38d4..ee2dfac 100644 (file)
@@ -310,7 +310,9 @@ findIndices      :: (a -> Bool) -> [a] -> [Int]
 findIndices p xs = [ i | (x,i) <- zip xs [0..], p x]
 #else
 -- Efficient definition, adapted from Data.Sequence
-{-# INLINE findIndices #-}
+-- (Note that making this INLINABLE instead of INLINE allows
+-- 'findIndex' to fuse, fixing #15426.)
+{-# INLINABLE findIndices #-}
 findIndices p ls = build $ \c n ->
   let go x r k | p x       = I# k `c` r (k +# 1#)
                | otherwise = r (k +# 1#)
diff --git a/testsuite/tests/perf/should_run/T15426.hs b/testsuite/tests/perf/should_run/T15426.hs
new file mode 100644 (file)
index 0000000..de88c28
--- /dev/null
@@ -0,0 +1,13 @@
+import Control.Exception (evaluate)
+import Data.List
+
+-- The following will fuse with minimal heap usage provided
+-- `findIndices` is marked `INLINABLE` instead of `INLINE`.
+
+unsafeFindIndex p = head . findIndices p
+
+main = do evaluate $ elemIndex 999999 [(1::Int)..1000000]
+          evaluate $ elemIndices 999999 [(1::Int)..1000000]
+          evaluate $ findIndex (>=999999) [(1::Int)..1000000]
+          evaluate $ findIndices (>=999999) [(1::Int)..1000000]
+          evaluate $ unsafeFindIndex (>=999999) [(1::Int)..1000000]
index 9705a08..6a7bcf0 100644 (file)
@@ -595,3 +595,12 @@ test('T15226a',
      only_ways(['normal'])],
     compile_and_run,
     ['-O'])
+
+test('T15426',
+    [stats_num_field('bytes allocated',
+                    [ (wordsize(64), 41272, 20) ]),
+                   # 2018-08-10   41272  Change findIndices from INLINE to INLINABLE
+                   # initial  160041176
+     only_ways(['normal'])],
+    compile_and_run,
+    ['-O2'])