summaryrefslogtreecommitdiff
path: root/testsuite/tests/perf/join_points/join004.hs
blob: 1962cc266e728d310fa2cdec90be37d10b4734a5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
{-
 - A rather contrived example demonstrating the virtues of not floating join
 - points outward.
 -}

module Main (main) where

-- Calculate n `div` d `div` d by looping.

{-# NOINLINE slowDivDiv #-}
slowDivDiv :: Int -> Int -> Int
slowDivDiv n d
  = let {-# NOINLINE divPos #-}
        divPos :: Int -> Int
        divPos n0
          = -- This function is a join point (all calls are tail calls), so it
            -- never causes a closure allocation, so it doesn't help to float it
            -- out. Thus -fno-join-points causes a ~25% jump in allocations.
            let go n' i
                  = case n' >= d of True  -> go (n' - d) (i + 1)
                                    False -> i
            in go n0 0
    in case n >= 0 of True  -> divPos (divPos n)
                      False -> divPos (-(divPos (-n)))
                                 -- It's important that divPos be called twice
                                 -- because otherwise it'd be a one-shot lambda
                                 -- and so the join point would be floated
                                 -- back in again.

main = print $ sum [slowDivDiv n d | n <- [1..1000], d <- [1..1000]]