2 % (c) The GRASP/AQUA Project, Glasgow University, 1992-1998
4 \section[ConFold]{Constant Folder}
6 Conceptually, constant folding should be parameterized with the kind
7 of target machine to get identical behaviour during compilation time
8 and runtime. We cheat a little bit here...
11 check boundaries before folding, e.g. we can fold the Float addition
12 (i1 + i2) only if it results in a valid Float.
16 {-# OPTIONS -optc-DNON_POSIX_SOURCE #-}
18 module PrelRules ( primOpRules, builtinRules ) where
20 #include "HsVersions.h"
23 import Id ( mkWildId, idUnfolding )
24 import Literal ( Literal(..), mkMachInt, mkMachWord
26 , word2IntLit, int2WordLit
27 , narrow8IntLit, narrow16IntLit, narrow32IntLit
28 , narrow8WordLit, narrow16WordLit, narrow32WordLit
29 , char2IntLit, int2CharLit
30 , float2IntLit, int2FloatLit, double2IntLit, int2DoubleLit
31 , float2DoubleLit, double2FloatLit
33 import PrimOp ( PrimOp(..), tagToEnumKey )
34 import TysWiredIn ( boolTy, trueDataConId, falseDataConId )
35 import TyCon ( tyConDataCons_maybe, isEnumerationTyCon, isNewTyCon )
36 import DataCon ( dataConTag, dataConTyCon, dataConWorkId, fIRST_TAG )
37 import CoreUtils ( cheapEqExpr, exprIsConApp_maybe )
38 import Type ( tyConAppTyCon, coreEqType )
39 import OccName ( occNameFS )
40 import PrelNames ( unpackCStringFoldrName, unpackCStringFoldrIdKey, hasKey,
41 eqStringName, unpackCStringIdKey, inlineIdName )
42 import Maybes ( orElse )
43 import Name ( Name, nameOccName )
46 import StaticFlags ( opt_SimplExcessPrecision )
48 import Data.Bits as Bits ( Bits(..) )
49 #if __GLASGOW_HASKELL__ >= 500
50 import Data.Word ( Word )
52 import Data.Word ( Word64 )
57 Note [Constant folding]
58 ~~~~~~~~~~~~~~~~~~~~~~~
59 primOpRules generates the rewrite rules for each primop
60 These rules do what is often called "constant folding"
61 E.g. the rules for +# might say
63 Well, of course you'd need a lot of rules if you did it
64 like that, so we use a BuiltinRule instead, so that we
65 can match in any two literal values. So the rule is really
67 (Lit 4) +# (Lit y) = Lit (x+#y)
68 where the (+#) on the rhs is done at compile time
70 That is why these rules are built in here. Other rules
71 which don't need to be built in are in GHC.Base. For
77 primOpRules :: PrimOp -> Name -> [CoreRule]
78 primOpRules op op_name = primop_rule op
81 one_lit = oneLit op_name
82 two_lits = twoLits op_name
83 relop cmp = two_lits (cmpOp (\ord -> ord `cmp` EQ))
84 -- Cunning. cmpOp compares the values to give an Ordering.
85 -- It applies its argument to that ordering value to turn
86 -- the ordering into a boolean value. (`cmp` EQ) is just the job.
88 -- ToDo: something for integer-shift ops?
91 primop_rule TagToEnumOp = mkBasicRule op_name 2 tagToEnumRule
92 primop_rule DataToTagOp = mkBasicRule op_name 2 dataToTagRule
95 primop_rule IntAddOp = two_lits (intOp2 (+))
96 primop_rule IntSubOp = two_lits (intOp2 (-))
97 primop_rule IntMulOp = two_lits (intOp2 (*))
98 primop_rule IntQuotOp = two_lits (intOp2Z quot)
99 primop_rule IntRemOp = two_lits (intOp2Z rem)
100 primop_rule IntNegOp = one_lit negOp
101 primop_rule ISllOp = two_lits (intShiftOp2 Bits.shiftL)
102 primop_rule ISraOp = two_lits (intShiftOp2 Bits.shiftR)
103 primop_rule ISrlOp = two_lits (intShiftOp2 shiftRightLogical)
106 #if __GLASGOW_HASKELL__ >= 500
107 primop_rule WordAddOp = two_lits (wordOp2 (+))
108 primop_rule WordSubOp = two_lits (wordOp2 (-))
109 primop_rule WordMulOp = two_lits (wordOp2 (*))
111 primop_rule WordQuotOp = two_lits (wordOp2Z quot)
112 primop_rule WordRemOp = two_lits (wordOp2Z rem)
113 #if __GLASGOW_HASKELL__ >= 407
114 primop_rule AndOp = two_lits (wordBitOp2 (.&.))
115 primop_rule OrOp = two_lits (wordBitOp2 (.|.))
116 primop_rule XorOp = two_lits (wordBitOp2 xor)
118 primop_rule SllOp = two_lits (wordShiftOp2 Bits.shiftL)
119 primop_rule SrlOp = two_lits (wordShiftOp2 shiftRightLogical)
122 primop_rule Word2IntOp = one_lit (litCoerce word2IntLit)
123 primop_rule Int2WordOp = one_lit (litCoerce int2WordLit)
124 primop_rule Narrow8IntOp = one_lit (litCoerce narrow8IntLit)
125 primop_rule Narrow16IntOp = one_lit (litCoerce narrow16IntLit)
126 primop_rule Narrow32IntOp = one_lit (litCoerce narrow32IntLit)
127 primop_rule Narrow8WordOp = one_lit (litCoerce narrow8WordLit)
128 primop_rule Narrow16WordOp = one_lit (litCoerce narrow16WordLit)
129 primop_rule Narrow32WordOp = one_lit (litCoerce narrow32WordLit)
130 primop_rule OrdOp = one_lit (litCoerce char2IntLit)
131 primop_rule ChrOp = one_lit (litCoerce int2CharLit)
132 primop_rule Float2IntOp = one_lit (litCoerce float2IntLit)
133 primop_rule Int2FloatOp = one_lit (litCoerce int2FloatLit)
134 primop_rule Double2IntOp = one_lit (litCoerce double2IntLit)
135 primop_rule Int2DoubleOp = one_lit (litCoerce int2DoubleLit)
136 -- SUP: Not sure what the standard says about precision in the following 2 cases
137 primop_rule Float2DoubleOp = one_lit (litCoerce float2DoubleLit)
138 primop_rule Double2FloatOp = one_lit (litCoerce double2FloatLit)
141 primop_rule FloatAddOp = two_lits (floatOp2 (+))
142 primop_rule FloatSubOp = two_lits (floatOp2 (-))
143 primop_rule FloatMulOp = two_lits (floatOp2 (*))
144 primop_rule FloatDivOp = two_lits (floatOp2Z (/))
145 primop_rule FloatNegOp = one_lit negOp
148 primop_rule DoubleAddOp = two_lits (doubleOp2 (+))
149 primop_rule DoubleSubOp = two_lits (doubleOp2 (-))
150 primop_rule DoubleMulOp = two_lits (doubleOp2 (*))
151 primop_rule DoubleDivOp = two_lits (doubleOp2Z (/))
152 primop_rule DoubleNegOp = one_lit negOp
154 -- Relational operators
155 primop_rule IntEqOp = relop (==) ++ litEq op_name True
156 primop_rule IntNeOp = relop (/=) ++ litEq op_name False
157 primop_rule CharEqOp = relop (==) ++ litEq op_name True
158 primop_rule CharNeOp = relop (/=) ++ litEq op_name False
160 primop_rule IntGtOp = relop (>)
161 primop_rule IntGeOp = relop (>=)
162 primop_rule IntLeOp = relop (<=)
163 primop_rule IntLtOp = relop (<)
165 primop_rule CharGtOp = relop (>)
166 primop_rule CharGeOp = relop (>=)
167 primop_rule CharLeOp = relop (<=)
168 primop_rule CharLtOp = relop (<)
170 primop_rule FloatGtOp = relop (>)
171 primop_rule FloatGeOp = relop (>=)
172 primop_rule FloatLeOp = relop (<=)
173 primop_rule FloatLtOp = relop (<)
174 primop_rule FloatEqOp = relop (==)
175 primop_rule FloatNeOp = relop (/=)
177 primop_rule DoubleGtOp = relop (>)
178 primop_rule DoubleGeOp = relop (>=)
179 primop_rule DoubleLeOp = relop (<=)
180 primop_rule DoubleLtOp = relop (<)
181 primop_rule DoubleEqOp = relop (==)
182 primop_rule DoubleNeOp = relop (/=)
184 primop_rule WordGtOp = relop (>)
185 primop_rule WordGeOp = relop (>=)
186 primop_rule WordLeOp = relop (<=)
187 primop_rule WordLtOp = relop (<)
188 primop_rule WordEqOp = relop (==)
189 primop_rule WordNeOp = relop (/=)
191 primop_rule other = []
196 %************************************************************************
198 \subsection{Doing the business}
200 %************************************************************************
202 ToDo: the reason these all return Nothing is because there used to be
203 the possibility of an argument being a litlit. Litlits are now gone,
204 so this could be cleaned up.
207 --------------------------
208 litCoerce :: (Literal -> Literal) -> Literal -> Maybe CoreExpr
209 litCoerce fn lit = Just (Lit (fn lit))
211 --------------------------
212 cmpOp :: (Ordering -> Bool) -> Literal -> Literal -> Maybe CoreExpr
216 done res | cmp res = Just trueVal
217 | otherwise = Just falseVal
219 -- These compares are at different types
220 go (MachChar i1) (MachChar i2) = done (i1 `compare` i2)
221 go (MachInt i1) (MachInt i2) = done (i1 `compare` i2)
222 go (MachInt64 i1) (MachInt64 i2) = done (i1 `compare` i2)
223 go (MachWord i1) (MachWord i2) = done (i1 `compare` i2)
224 go (MachWord64 i1) (MachWord64 i2) = done (i1 `compare` i2)
225 go (MachFloat i1) (MachFloat i2) = done (i1 `compare` i2)
226 go (MachDouble i1) (MachDouble i2) = done (i1 `compare` i2)
229 --------------------------
231 negOp :: Literal -> Maybe CoreExpr -- Negate
232 negOp (MachFloat 0.0) = Nothing -- can't represent -0.0 as a Rational
233 negOp (MachFloat f) = Just (mkFloatVal (-f))
234 negOp (MachDouble 0.0) = Nothing
235 negOp (MachDouble d) = Just (mkDoubleVal (-d))
236 negOp (MachInt i) = intResult (-i)
239 --------------------------
240 intOp2 :: (Integer->Integer->Integer) -> Literal -> Literal -> Maybe CoreExpr
241 intOp2 op (MachInt i1) (MachInt i2) = intResult (i1 `op` i2)
242 intOp2 op l1 l2 = Nothing -- Could find LitLit
244 intOp2Z :: (Integer->Integer->Integer) -> Literal -> Literal -> Maybe CoreExpr
245 -- Like intOp2, but Nothing if i2=0
246 intOp2Z op (MachInt i1) (MachInt i2)
247 | i2 /= 0 = intResult (i1 `op` i2)
248 intOp2Z op l1 l2 = Nothing -- LitLit or zero dividend
250 intShiftOp2 :: (Integer->Int->Integer) -> Literal -> Literal -> Maybe CoreExpr
251 -- Shifts take an Int; hence second arg of op is Int
252 intShiftOp2 op (MachInt i1) (MachInt i2) = intResult (i1 `op` fromInteger i2)
253 intShiftOp2 op l1 l2 = Nothing
255 shiftRightLogical :: Integer -> Int -> Integer
256 -- Shift right, putting zeros in rather than sign-propagating as Bits.shiftR would do
257 -- Do this by converting to Word and back. Obviously this won't work for big
258 -- values, but its ok as we use it here
259 shiftRightLogical x n = fromIntegral (fromInteger x `shiftR` n :: Word)
262 --------------------------
263 #if __GLASGOW_HASKELL__ >= 500
264 wordOp2 :: (Integer->Integer->Integer) -> Literal -> Literal -> Maybe CoreExpr
265 wordOp2 op (MachWord w1) (MachWord w2)
266 = wordResult (w1 `op` w2)
267 wordOp2 op l1 l2 = Nothing -- Could find LitLit
270 wordOp2Z :: (Integer->Integer->Integer) -> Literal -> Literal -> Maybe CoreExpr
271 wordOp2Z op (MachWord w1) (MachWord w2)
272 | w2 /= 0 = wordResult (w1 `op` w2)
273 wordOp2Z op l1 l2 = Nothing -- LitLit or zero dividend
275 #if __GLASGOW_HASKELL__ >= 500
276 wordBitOp2 op l1@(MachWord w1) l2@(MachWord w2)
277 = wordResult (w1 `op` w2)
279 -- Integer is not an instance of Bits, so we operate on Word64
280 wordBitOp2 op l1@(MachWord w1) l2@(MachWord w2)
281 = wordResult ((fromIntegral::Word64->Integer) (fromIntegral w1 `op` fromIntegral w2))
283 wordBitOp2 op l1 l2 = Nothing -- Could find LitLit
285 wordShiftOp2 :: (Integer->Int->Integer) -> Literal -> Literal -> Maybe CoreExpr
286 -- Shifts take an Int; hence second arg of op is Int
287 wordShiftOp2 op (MachWord x) (MachInt n)
288 = wordResult (x `op` fromInteger n)
289 -- Do the shift at type Integer
290 wordShiftOp2 op l1 l2 = Nothing
292 --------------------------
293 floatOp2 op (MachFloat f1) (MachFloat f2)
294 = Just (mkFloatVal (f1 `op` f2))
295 floatOp2 op l1 l2 = Nothing
297 floatOp2Z op (MachFloat f1) (MachFloat f2)
298 | f2 /= 0 = Just (mkFloatVal (f1 `op` f2))
299 floatOp2Z op l1 l2 = Nothing
301 --------------------------
302 doubleOp2 op (MachDouble f1) (MachDouble f2)
303 = Just (mkDoubleVal (f1 `op` f2))
304 doubleOp2 op l1 l2 = Nothing
306 doubleOp2Z op (MachDouble f1) (MachDouble f2)
307 | f2 /= 0 = Just (mkDoubleVal (f1 `op` f2))
308 doubleOp2Z op l1 l2 = Nothing
311 --------------------------
319 -- This is a Good Thing, because it allows case-of case things
320 -- to happen, and case-default absorption to happen. For
323 -- if (n ==# 3#) || (n ==# 4#) then e1 else e2
329 -- (modulo the usual precautions to avoid duplicating e1)
332 -> Bool -- True <=> equality, False <=> inequality
335 = [BuiltinRule { ru_name = occNameFS (nameOccName op_name)
336 `appendFS` FSLIT("->case"),
338 ru_nargs = 2, ru_try = rule_fn }]
340 rule_fn [Lit lit, expr] = do_lit_eq lit expr
341 rule_fn [expr, Lit lit] = do_lit_eq lit expr
342 rule_fn other = Nothing
345 = Just (Case expr (mkWildId (literalType lit)) boolTy
346 [(DEFAULT, [], val_if_neq),
347 (LitAlt lit, [], val_if_eq)])
348 val_if_eq | is_eq = trueVal
349 | otherwise = falseVal
350 val_if_neq | is_eq = falseVal
351 | otherwise = trueVal
353 -- Note that we *don't* warn the user about overflow. It's not done at
354 -- runtime either, and compilation of completely harmless things like
355 -- ((124076834 :: Word32) + (2147483647 :: Word32))
356 -- would yield a warning. Instead we simply squash the value into the
357 -- Int range, but not in a way suitable for cross-compiling... :-(
358 intResult :: Integer -> Maybe CoreExpr
360 = Just (mkIntVal (toInteger (fromInteger result :: Int)))
362 #if __GLASGOW_HASKELL__ >= 500
363 wordResult :: Integer -> Maybe CoreExpr
365 = Just (mkWordVal (toInteger (fromInteger result :: Word)))
370 %************************************************************************
372 \subsection{Vaguely generic functions
374 %************************************************************************
377 mkBasicRule :: Name -> Int -> ([CoreExpr] -> Maybe CoreExpr) -> [CoreRule]
378 -- Gives the Rule the same name as the primop itself
379 mkBasicRule op_name n_args rule_fn
380 = [BuiltinRule { ru_name = occNameFS (nameOccName op_name),
382 ru_nargs = n_args, ru_try = rule_fn }]
384 oneLit :: Name -> (Literal -> Maybe CoreExpr)
387 = mkBasicRule op_name 1 rule_fn
389 rule_fn [Lit l1] = test (convFloating l1)
392 twoLits :: Name -> (Literal -> Literal -> Maybe CoreExpr)
395 = mkBasicRule op_name 2 rule_fn
397 rule_fn [Lit l1, Lit l2] = test (convFloating l1) (convFloating l2)
400 -- When excess precision is not requested, cut down the precision of the
401 -- Rational value to that of Float/Double. We confuse host architecture
402 -- and target architecture here, but it's convenient (and wrong :-).
403 convFloating :: Literal -> Literal
404 convFloating (MachFloat f) | not opt_SimplExcessPrecision =
405 MachFloat (toRational ((fromRational f) :: Float ))
406 convFloating (MachDouble d) | not opt_SimplExcessPrecision =
407 MachDouble (toRational ((fromRational d) :: Double))
410 trueVal = Var trueDataConId
411 falseVal = Var falseDataConId
412 mkIntVal i = Lit (mkMachInt i)
413 mkWordVal w = Lit (mkMachWord w)
414 mkFloatVal f = Lit (convFloating (MachFloat f))
415 mkDoubleVal d = Lit (convFloating (MachDouble d))
419 %************************************************************************
421 \subsection{Special rules for seq, tagToEnum, dataToTag}
423 %************************************************************************
426 tagToEnumRule [Type ty, Lit (MachInt i)]
427 = ASSERT( isEnumerationTyCon tycon )
428 case filter correct_tag (tyConDataCons_maybe tycon `orElse` []) of
431 [] -> Nothing -- Abstract type
432 (dc:rest) -> ASSERT( null rest )
433 Just (Var (dataConWorkId dc))
435 correct_tag dc = (dataConTag dc - fIRST_TAG) == tag
437 tycon = tyConAppTyCon ty
439 tagToEnumRule other = Nothing
442 For dataToTag#, we can reduce if either
444 (a) the argument is a constructor
445 (b) the argument is a variable whose unfolding is a known constructor
448 dataToTagRule [Type ty1, Var tag_to_enum `App` Type ty2 `App` tag]
449 | tag_to_enum `hasKey` tagToEnumKey
450 , ty1 `coreEqType` ty2
451 = Just tag -- dataToTag (tagToEnum x) ==> x
453 dataToTagRule [_, val_arg]
454 | Just (dc,_) <- exprIsConApp_maybe val_arg
455 = ASSERT( not (isNewTyCon (dataConTyCon dc)) )
456 Just (mkIntVal (toInteger (dataConTag dc - fIRST_TAG)))
458 dataToTagRule other = Nothing
461 %************************************************************************
463 \subsection{Built in rules}
465 %************************************************************************
468 builtinRules :: [CoreRule]
469 -- Rules for non-primops that can't be expressed using a RULE pragma
471 = [ BuiltinRule FSLIT("AppendLitString") unpackCStringFoldrName 4 match_append_lit,
472 BuiltinRule FSLIT("EqString") eqStringName 2 match_eq_string,
473 BuiltinRule FSLIT("Inline") inlineIdName 1 match_inline
477 ---------------------------------------------------
479 -- unpackFoldrCString# "foo" c (unpackFoldrCString# "baz" c n) = unpackFoldrCString# "foobaz" c n
481 match_append_lit [Type ty1,
484 Var unpk `App` Type ty2
485 `App` Lit (MachStr s2)
489 | unpk `hasKey` unpackCStringFoldrIdKey &&
491 = ASSERT( ty1 `coreEqType` ty2 )
492 Just (Var unpk `App` Type ty1
493 `App` Lit (MachStr (s1 `appendFS` s2))
497 match_append_lit other = Nothing
499 ---------------------------------------------------
501 -- eqString (unpackCString# (Lit s1)) (unpackCString# (Lit s2) = s1==s2
503 match_eq_string [Var unpk1 `App` Lit (MachStr s1),
504 Var unpk2 `App` Lit (MachStr s2)]
505 | unpk1 `hasKey` unpackCStringIdKey,
506 unpk2 `hasKey` unpackCStringIdKey
507 = Just (if s1 == s2 then trueVal else falseVal)
509 match_eq_string other = Nothing
512 ---------------------------------------------------
514 -- inline (f a b c) = <f's unfolding> a b c
515 -- (if f has an unfolding)
517 | (Var f, args1) <- collectArgs e,
518 Just unf <- maybeUnfoldingTemplate (idUnfolding f)
519 = Just (mkApps unf args1)
521 match_inline other = Nothing