- | SizeIs Int# -- Size found
- (Bag Id) -- Arguments cased herein
- Int# -- Size to subtract if result is scrutinised
- -- by a case expression
-
-sizeZero = SizeIs 0# emptyBag 0#
-sizeOne = SizeIs 1# emptyBag 0#
-sizeTwo = SizeIs 2# emptyBag 0#
-sizeN (I# n) = SizeIs n emptyBag 0#
-conSizeN (I# n) = SizeIs 1# emptyBag (n +# 1#)
- -- Treat constructors as size 1, that unfoldAlways responsds 'False'
- -- when asked about 'x' when x is bound to (C 3#).
- -- This avoids gratuitous 'ticks' when x itself appears as an
- -- atomic constructor argument.
+ | SizeIs FastInt -- Size found
+ (Bag (Id,Int)) -- Arguments cased herein, and discount for each such
+ FastInt -- Size to subtract if result is scrutinised
+ -- by a case expression
+
+-- subtract the discount before deciding whether to bale out. eg. we
+-- want to inline a large constructor application into a selector:
+-- tup = (a_1, ..., a_99)
+-- x = case tup of ...
+--
+mkSizeIs max n xs d | (n -# d) ># max = TooBig
+ | otherwise = SizeIs n xs d
+
+maxSize TooBig _ = TooBig
+maxSize _ TooBig = TooBig
+maxSize s1@(SizeIs n1 _ _) s2@(SizeIs n2 _ _) | n1 ># n2 = s1
+ | otherwise = s2
+
+sizeZero = SizeIs (_ILIT 0) emptyBag (_ILIT 0)
+sizeOne = SizeIs (_ILIT 1) emptyBag (_ILIT 0)
+sizeN n = SizeIs (iUnbox n) emptyBag (_ILIT 0)
+conSizeN dc n
+ | isUnboxedTupleCon dc = SizeIs (_ILIT 0) emptyBag (iUnbox n +# _ILIT 1)
+ | otherwise = SizeIs (_ILIT 1) emptyBag (iUnbox n +# _ILIT 1)
+ -- Treat constructors as size 1; we are keen to expose them
+ -- (and we charge separately for their args). We can't treat
+ -- them as size zero, else we find that (iBox x) has size 1,
+ -- which is the same as a lone variable; and hence 'v' will
+ -- always be replaced by (iBox x), where v is bound to iBox x.
+ --
+ -- However, unboxed tuples count as size zero
+ -- I found occasions where we had
+ -- f x y z = case op# x y z of { s -> (# s, () #) }
+ -- and f wasn't getting inlined
+
+primOpSize op n_args
+ | not (primOpIsDupable op) = sizeN opt_UF_DearOp
+ | not (primOpOutOfLine op) = sizeN (2 - n_args)
+ -- Be very keen to inline simple primops.
+ -- We give a discount of 1 for each arg so that (op# x y z) costs 2.
+ -- We can't make it cost 1, else we'll inline let v = (op# x y z)
+ -- at every use of v, which is excessive.
+ --
+ -- A good example is:
+ -- let x = +# p q in C {x}
+ -- Even though x get's an occurrence of 'many', its RHS looks cheap,
+ -- and there's a good chance it'll get inlined back into C's RHS. Urgh!
+ | otherwise = sizeOne
+
+buildSize = SizeIs (-2#) emptyBag 4#
+ -- We really want to inline applications of build
+ -- build t (\cn -> e) should cost only the cost of e (because build will be inlined later)
+ -- Indeed, we should add a result_discount becuause build is
+ -- very like a constructor. We don't bother to check that the
+ -- build is saturated (it usually is). The "-2" discounts for the \c n,
+ -- The "4" is rather arbitrary.
+
+augmentSize = SizeIs (-2#) emptyBag 4#
+ -- Ditto (augment t (\cn -> e) ys) should cost only the cost of
+ -- e plus ys. The -2 accounts for the \cn