X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=ghc%2Fcompiler%2Fprelude%2FPrelRules.lhs;h=9cdddc9065738ba1b188eea3852412431346a84a;hb=9d7da331989abcd1844e9d03b8d1e4163796fa85;hp=c22f57264a640601b2c3c80229b60f1da5f14480;hpb=111cee3f1ad93816cb828e38b38521d85c3bcebb;p=ghc-hetmet.git diff --git a/ghc/compiler/prelude/PrelRules.lhs b/ghc/compiler/prelude/PrelRules.lhs index c22f572..9cdddc9 100644 --- a/ghc/compiler/prelude/PrelRules.lhs +++ b/ghc/compiler/prelude/PrelRules.lhs @@ -3,125 +3,174 @@ % \section[ConFold]{Constant Folder} +Conceptually, constant folding should be parameterized with the kind +of target machine to get identical behaviour during compilation time +and runtime. We cheat a little bit here... + ToDo: check boundaries before folding, e.g. we can fold the Float addition (i1 + i2) only if it results in a valid Float. \begin{code} -module PrelRules ( primOpRule, builtinRules ) where + +{-# OPTIONS -optc-DNON_POSIX_SOURCE #-} + +module PrelRules ( primOpRules, builtinRules ) where #include "HsVersions.h" import CoreSyn -import Rules ( ProtoCoreRule(..) ) -import Id ( idUnfolding, mkWildId, isDataConId_maybe ) -import Literal ( Literal(..), mkMachInt, mkMachWord, inIntRange, literalType, - word2IntLit, int2WordLit, int2CharLit, char2IntLit, int2FloatLit, int2DoubleLit +import Id ( mkWildId, isPrimOpId_maybe ) +import Literal ( Literal(..), mkMachInt, mkMachWord + , literalType + , word2IntLit, int2WordLit + , narrow8IntLit, narrow16IntLit, narrow32IntLit + , narrow8WordLit, narrow16WordLit, narrow32WordLit + , char2IntLit, int2CharLit + , float2IntLit, int2FloatLit, double2IntLit, int2DoubleLit + , float2DoubleLit, double2FloatLit ) import PrimOp ( PrimOp(..), primOpOcc ) -import TysWiredIn ( trueDataConId, falseDataConId ) -import TyCon ( tyConDataCons, isEnumerationTyCon, isNewTyCon ) -import DataCon ( DataCon, dataConTag, dataConRepArity, dataConTyCon, dataConId, fIRST_TAG ) -import CoreUnfold ( maybeUnfoldingTemplate ) -import CoreUtils ( exprIsValue, cheapEqExpr ) -import Type ( splitTyConApp_maybe ) -import OccName ( occNameUserString) -import ThinAir ( unpackCStringFoldrId ) -import Maybes ( maybeToBool ) -import Char ( ord, chr ) +import TysWiredIn ( boolTy, trueDataConId, falseDataConId ) +import TyCon ( tyConDataCons_maybe, isEnumerationTyCon, isNewTyCon ) +import DataCon ( dataConTag, dataConTyCon, dataConWorkId, fIRST_TAG ) +import CoreUtils ( cheapEqExpr, exprIsConApp_maybe ) +import Type ( tyConAppTyCon, coreEqType ) +import OccName ( occNameFS ) +import PrelNames ( unpackCStringFoldrName, unpackCStringFoldrIdKey, hasKey, + eqStringName, unpackCStringIdKey ) +import Maybes ( orElse ) +import Name ( Name ) import Outputable +import FastString +import StaticFlags ( opt_SimplExcessPrecision ) + +import DATA_BITS ( Bits(..) ) +#if __GLASGOW_HASKELL__ >= 500 +import DATA_WORD ( Word ) +#else +import DATA_WORD ( Word64 ) +#endif \end{code} - \begin{code} -primOpRule :: PrimOp -> CoreRule -primOpRule op - = BuiltinRule (primop_rule op) +primOpRules :: PrimOp -> Name -> [CoreRule] +primOpRules op op_name = primop_rule op where - op_name = _PK_ (occNameUserString (primOpOcc op)) - op_name_case = op_name _APPEND_ SLIT("case") + rule_name = occNameFS (primOpOcc op) + rule_name_case = rule_name `appendFS` FSLIT("->case") + + -- A useful shorthand + one_rule rule_fn = [BuiltinRule { ru_name = rule_name, + ru_fn = op_name, + ru_try = rule_fn }] + case_rule rule_fn = [BuiltinRule { ru_name = rule_name_case, + ru_fn = op_name, + ru_try = rule_fn }] -- ToDo: something for integer-shift ops? -- NotOp - -- Int2WordOp -- SIGH: these two cause trouble in unfoldery - -- Int2AddrOp -- as we can't distinguish unsigned literals in interfaces (ToDo?) - - primop_rule SeqOp = seqRule - primop_rule TagToEnumOp = tagToEnumRule - primop_rule DataToTagOp = dataToTagRule - - -- Char operations - primop_rule OrdOp = oneLit (litCoerce char2IntLit op_name) - - -- Int/Word operations - primop_rule IntAddOp = twoLits (intOp2 (+) op_name) - primop_rule IntSubOp = twoLits (intOp2 (-) op_name) - primop_rule IntMulOp = twoLits (intOp2 (*) op_name) - primop_rule IntQuotOp = twoLits (intOp2Z quot op_name) - primop_rule IntRemOp = twoLits (intOp2Z rem op_name) - primop_rule IntNegOp = oneLit (negOp op_name) - - primop_rule ChrOp = oneLit (litCoerce int2CharLit op_name) - primop_rule Int2FloatOp = oneLit (litCoerce int2FloatLit op_name) - primop_rule Int2DoubleOp = oneLit (litCoerce int2DoubleLit op_name) - primop_rule Word2IntOp = oneLit (litCoerce word2IntLit op_name) - primop_rule Int2WordOp = oneLit (litCoerce int2WordLit op_name) + + primop_rule TagToEnumOp = one_rule tagToEnumRule + primop_rule DataToTagOp = one_rule dataToTagRule + + -- Int operations + primop_rule IntAddOp = one_rule (twoLits (intOp2 (+))) + primop_rule IntSubOp = one_rule (twoLits (intOp2 (-))) + primop_rule IntMulOp = one_rule (twoLits (intOp2 (*))) + primop_rule IntQuotOp = one_rule (twoLits (intOp2Z quot)) + primop_rule IntRemOp = one_rule (twoLits (intOp2Z rem)) + primop_rule IntNegOp = one_rule (oneLit negOp) + + -- Word operations +#if __GLASGOW_HASKELL__ >= 500 + primop_rule WordAddOp = one_rule (twoLits (wordOp2 (+))) + primop_rule WordSubOp = one_rule (twoLits (wordOp2 (-))) + primop_rule WordMulOp = one_rule (twoLits (wordOp2 (*))) +#endif + primop_rule WordQuotOp = one_rule (twoLits (wordOp2Z quot)) + primop_rule WordRemOp = one_rule (twoLits (wordOp2Z rem)) +#if __GLASGOW_HASKELL__ >= 407 + primop_rule AndOp = one_rule (twoLits (wordBitOp2 (.&.))) + primop_rule OrOp = one_rule (twoLits (wordBitOp2 (.|.))) + primop_rule XorOp = one_rule (twoLits (wordBitOp2 xor)) +#endif + + -- coercions + primop_rule Word2IntOp = one_rule (oneLit (litCoerce word2IntLit)) + primop_rule Int2WordOp = one_rule (oneLit (litCoerce int2WordLit)) + primop_rule Narrow8IntOp = one_rule (oneLit (litCoerce narrow8IntLit)) + primop_rule Narrow16IntOp = one_rule (oneLit (litCoerce narrow16IntLit)) + primop_rule Narrow32IntOp = one_rule (oneLit (litCoerce narrow32IntLit)) + primop_rule Narrow8WordOp = one_rule (oneLit (litCoerce narrow8WordLit)) + primop_rule Narrow16WordOp = one_rule (oneLit (litCoerce narrow16WordLit)) + primop_rule Narrow32WordOp = one_rule (oneLit (litCoerce narrow32WordLit)) + primop_rule OrdOp = one_rule (oneLit (litCoerce char2IntLit)) + primop_rule ChrOp = one_rule (oneLit (litCoerce int2CharLit)) + primop_rule Float2IntOp = one_rule (oneLit (litCoerce float2IntLit)) + primop_rule Int2FloatOp = one_rule (oneLit (litCoerce int2FloatLit)) + primop_rule Double2IntOp = one_rule (oneLit (litCoerce double2IntLit)) + primop_rule Int2DoubleOp = one_rule (oneLit (litCoerce int2DoubleLit)) + -- SUP: Not sure what the standard says about precision in the following 2 cases + primop_rule Float2DoubleOp = one_rule (oneLit (litCoerce float2DoubleLit)) + primop_rule Double2FloatOp = one_rule (oneLit (litCoerce double2FloatLit)) -- Float - primop_rule FloatAddOp = twoLits (floatOp2 (+) op_name) - primop_rule FloatSubOp = twoLits (floatOp2 (-) op_name) - primop_rule FloatMulOp = twoLits (floatOp2 (*) op_name) - primop_rule FloatDivOp = twoLits (floatOp2Z (/) op_name) - primop_rule FloatNegOp = oneLit (negOp op_name) + primop_rule FloatAddOp = one_rule (twoLits (floatOp2 (+))) + primop_rule FloatSubOp = one_rule (twoLits (floatOp2 (-))) + primop_rule FloatMulOp = one_rule (twoLits (floatOp2 (*))) + primop_rule FloatDivOp = one_rule (twoLits (floatOp2Z (/))) + primop_rule FloatNegOp = one_rule (oneLit negOp) -- Double - primop_rule DoubleAddOp = twoLits (doubleOp2 (+) op_name) - primop_rule DoubleSubOp = twoLits (doubleOp2 (-) op_name) - primop_rule DoubleMulOp = twoLits (doubleOp2 (*) op_name) - primop_rule DoubleDivOp = twoLits (doubleOp2Z (/) op_name) + primop_rule DoubleAddOp = one_rule (twoLits (doubleOp2 (+))) + primop_rule DoubleSubOp = one_rule (twoLits (doubleOp2 (-))) + primop_rule DoubleMulOp = one_rule (twoLits (doubleOp2 (*))) + primop_rule DoubleDivOp = one_rule (twoLits (doubleOp2Z (/))) + primop_rule DoubleNegOp = one_rule (oneLit negOp) -- Relational operators - primop_rule IntEqOp = relop (==) `or_rule` litEq True op_name_case - primop_rule IntNeOp = relop (/=) `or_rule` litEq False op_name_case - primop_rule CharEqOp = relop (==) `or_rule` litEq True op_name_case - primop_rule CharNeOp = relop (/=) `or_rule` litEq False op_name_case - - primop_rule IntGtOp = relop (>) - primop_rule IntGeOp = relop (>=) - primop_rule IntLeOp = relop (<=) - primop_rule IntLtOp = relop (<) - - primop_rule CharGtOp = relop (>) - primop_rule CharGeOp = relop (>=) - primop_rule CharLeOp = relop (<=) - primop_rule CharLtOp = relop (<) - - primop_rule FloatGtOp = relop (>) - primop_rule FloatGeOp = relop (>=) - primop_rule FloatLeOp = relop (<=) - primop_rule FloatLtOp = relop (<) - primop_rule FloatEqOp = relop (==) - primop_rule FloatNeOp = relop (/=) - - primop_rule DoubleGtOp = relop (>) - primop_rule DoubleGeOp = relop (>=) - primop_rule DoubleLeOp = relop (<=) - primop_rule DoubleLtOp = relop (<) - primop_rule DoubleEqOp = relop (==) - primop_rule DoubleNeOp = relop (/=) - - primop_rule WordGtOp = relop (>) - primop_rule WordGeOp = relop (>=) - primop_rule WordLeOp = relop (<=) - primop_rule WordLtOp = relop (<) - primop_rule WordEqOp = relop (==) - primop_rule WordNeOp = relop (/=) - - primop_rule other = \args -> Nothing - - - relop cmp = twoLits (cmpOp (\ord -> ord `cmp` EQ) op_name) + primop_rule IntEqOp = one_rule (relop (==)) ++ case_rule (litEq True) + primop_rule IntNeOp = one_rule (relop (/=)) ++ case_rule (litEq False) + primop_rule CharEqOp = one_rule (relop (==)) ++ case_rule (litEq True) + primop_rule CharNeOp = one_rule (relop (/=)) ++ case_rule (litEq False) + + primop_rule IntGtOp = one_rule (relop (>)) + primop_rule IntGeOp = one_rule (relop (>=)) + primop_rule IntLeOp = one_rule (relop (<=)) + primop_rule IntLtOp = one_rule (relop (<)) + + primop_rule CharGtOp = one_rule (relop (>)) + primop_rule CharGeOp = one_rule (relop (>=)) + primop_rule CharLeOp = one_rule (relop (<=)) + primop_rule CharLtOp = one_rule (relop (<)) + + primop_rule FloatGtOp = one_rule (relop (>)) + primop_rule FloatGeOp = one_rule (relop (>=)) + primop_rule FloatLeOp = one_rule (relop (<=)) + primop_rule FloatLtOp = one_rule (relop (<)) + primop_rule FloatEqOp = one_rule (relop (==)) + primop_rule FloatNeOp = one_rule (relop (/=)) + + primop_rule DoubleGtOp = one_rule (relop (>)) + primop_rule DoubleGeOp = one_rule (relop (>=)) + primop_rule DoubleLeOp = one_rule (relop (<=)) + primop_rule DoubleLtOp = one_rule (relop (<)) + primop_rule DoubleEqOp = one_rule (relop (==)) + primop_rule DoubleNeOp = one_rule (relop (/=)) + + primop_rule WordGtOp = one_rule (relop (>)) + primop_rule WordGeOp = one_rule (relop (>=)) + primop_rule WordLeOp = one_rule (relop (<=)) + primop_rule WordLtOp = one_rule (relop (<)) + primop_rule WordEqOp = one_rule (relop (==)) + primop_rule WordNeOp = one_rule (relop (/=)) + + primop_rule other = [] + + + relop cmp = twoLits (cmpOp (\ord -> ord `cmp` EQ)) -- Cunning. cmpOp compares the values to give an Ordering. -- It applies its argument to that ordering value to turn -- the ordering into a boolean value. (`cmp` EQ) is just the job. @@ -133,23 +182,22 @@ primOpRule op %* * %************************************************************************ - IMPORTANT NOTE - -In all these operations we might find a LitLit as an operand; that's -why we have the catch-all Nothing case. +ToDo: the reason these all return Nothing is because there used to be +the possibility of an argument being a litlit. Litlits are now gone, +so this could be cleaned up. \begin{code} -------------------------- -litCoerce :: (Literal -> Literal) -> RuleName -> Literal -> Maybe (RuleName, CoreExpr) -litCoerce fn name lit = Just (name, Lit (fn lit)) +litCoerce :: (Literal -> Literal) -> Literal -> Maybe CoreExpr +litCoerce fn lit = Just (Lit (fn lit)) -------------------------- -cmpOp :: (Ordering -> Bool) -> FAST_STRING -> Literal -> Literal -> Maybe (RuleName, CoreExpr) -cmpOp cmp name l1 l2 +cmpOp :: (Ordering -> Bool) -> Literal -> Literal -> Maybe CoreExpr +cmpOp cmp l1 l2 = go l1 l2 where - done res | cmp res = Just (name, trueVal) - | otherwise = Just (name, falseVal) + done res | cmp res = Just trueVal + | otherwise = Just falseVal -- These compares are at different types go (MachChar i1) (MachChar i2) = done (i1 `compare` i2) @@ -163,40 +211,59 @@ cmpOp cmp name l1 l2 -------------------------- -negOp name (MachFloat f) = Just (name, mkFloatVal (-f)) -negOp name (MachDouble d) = Just (name, mkDoubleVal (-d)) -negOp name l@(MachInt i) = intResult name (ppr l) (-i) -negOp name l = Nothing +negOp (MachFloat 0.0) = Nothing -- can't represent -0.0 as a Rational +negOp (MachFloat f) = Just (mkFloatVal (-f)) +negOp (MachDouble 0.0) = Nothing +negOp (MachDouble d) = Just (mkDoubleVal (-d)) +negOp (MachInt i) = intResult (-i) +negOp l = Nothing -------------------------- -intOp2 op name l1@(MachInt i1) l2@(MachInt i2) - = intResult name (ppr l1 <+> ppr l2) (i1 `op` i2) -intOp2 op name l1 l2 = Nothing -- Could find LitLit - -intOp2Z op name (MachInt i1) (MachInt i2) - | i2 /= 0 = Just (name, mkIntVal (i1 `op` i2)) -intOp2Z op name l1 l2 = Nothing -- LitLit or zero dividend +intOp2 op (MachInt i1) (MachInt i2) = intResult (i1 `op` i2) +intOp2 op l1 l2 = Nothing -- Could find LitLit +intOp2Z op (MachInt i1) (MachInt i2) + | i2 /= 0 = Just (mkIntVal (i1 `op` i2)) +intOp2Z op l1 l2 = Nothing -- LitLit or zero dividend -------------------------- -floatOp2 op name (MachFloat f1) (MachFloat f2) - = Just (name, mkFloatVal (f1 `op` f2)) -floatOp2 op name l1 l2 = Nothing - -floatOp2Z op name (MachFloat f1) (MachFloat f2) - | f1 /= 0 = Just (name, mkFloatVal (f1 `op` f2)) -floatOp2Z op name l1 l2 = Nothing +#if __GLASGOW_HASKELL__ >= 500 +wordOp2 op (MachWord w1) (MachWord w2) + = wordResult (w1 `op` w2) +wordOp2 op l1 l2 = Nothing -- Could find LitLit +#endif + +wordOp2Z op (MachWord w1) (MachWord w2) + | w2 /= 0 = Just (mkWordVal (w1 `op` w2)) +wordOp2Z op l1 l2 = Nothing -- LitLit or zero dividend + +#if __GLASGOW_HASKELL__ >= 500 +wordBitOp2 op l1@(MachWord w1) l2@(MachWord w2) + = Just (mkWordVal (w1 `op` w2)) +#else +-- Integer is not an instance of Bits, so we operate on Word64 +wordBitOp2 op l1@(MachWord w1) l2@(MachWord w2) + = Just (mkWordVal ((fromIntegral::Word64->Integer) (fromIntegral w1 `op` fromIntegral w2))) +#endif +wordBitOp2 op l1 l2 = Nothing -- Could find LitLit +-------------------------- +floatOp2 op (MachFloat f1) (MachFloat f2) + = Just (mkFloatVal (f1 `op` f2)) +floatOp2 op l1 l2 = Nothing +floatOp2Z op (MachFloat f1) (MachFloat f2) + | f2 /= 0 = Just (mkFloatVal (f1 `op` f2)) +floatOp2Z op l1 l2 = Nothing -------------------------- -doubleOp2 op name (MachDouble f1) (MachDouble f2) - = Just (name, mkDoubleVal (f1 `op` f2)) -doubleOp2 op name l1 l2 = Nothing +doubleOp2 op (MachDouble f1) (MachDouble f2) + = Just (mkDoubleVal (f1 `op` f2)) +doubleOp2 op l1 l2 = Nothing -doubleOp2Z op name (MachDouble f1) (MachDouble f2) - | f1 /= 0 = Just (name, mkDoubleVal (f1 `op` f2)) -doubleOp2Z op name l1 l2 = Nothing +doubleOp2Z op (MachDouble f1) (MachDouble f2) + | f2 /= 0 = Just (mkDoubleVal (f1 `op` f2)) +doubleOp2Z op l1 l2 = Nothing -------------------------- @@ -220,35 +287,35 @@ doubleOp2Z op name l1 l2 = Nothing -- (modulo the usual precautions to avoid duplicating e1) litEq :: Bool -- True <=> equality, False <=> inequality - -> RuleName - -> RuleFun -litEq is_eq name [Lit lit, expr] = do_lit_eq is_eq name lit expr -litEq is_eq name [expr, Lit lit] = do_lit_eq is_eq name lit expr -litEq is_eq name other = Nothing - -do_lit_eq is_eq name lit expr - = Just (name, Case expr (mkWildId (literalType lit)) - [(LitAlt lit, [], val_if_eq), - (DEFAULT, [], val_if_neq)]) + -> RuleFun +litEq is_eq [Lit lit, expr] = do_lit_eq is_eq lit expr +litEq is_eq [expr, Lit lit] = do_lit_eq is_eq lit expr +litEq is_eq other = Nothing + +do_lit_eq is_eq lit expr + = Just (Case expr (mkWildId (literalType lit)) boolTy + [(DEFAULT, [], val_if_neq), + (LitAlt lit, [], val_if_eq)]) where val_if_eq | is_eq = trueVal | otherwise = falseVal val_if_neq | is_eq = falseVal | otherwise = trueVal -intResult name pp_args result - | not (inIntRange result) - -- Better tell the user that we've overflowed... - -- ..not that it stops us from actually folding! - - = pprTrace "Warning:" (text "Integer overflow in:" <+> ppr name <+> pp_args) - Just (name, mkIntVal (squash result)) - - | otherwise - = Just (name, mkIntVal result) - -squash :: Integer -> Integer -- Squash into Int range -squash i = toInteger ((fromInteger i)::Int) +-- Note that we *don't* warn the user about overflow. It's not done at +-- runtime either, and compilation of completely harmless things like +-- ((124076834 :: Word32) + (2147483647 :: Word32)) +-- would yield a warning. Instead we simply squash the value into the +-- Int range, but not in a way suitable for cross-compiling... :-( +intResult :: Integer -> Maybe CoreExpr +intResult result + = Just (mkIntVal (toInteger (fromInteger result :: Int))) + +#if __GLASGOW_HASKELL__ >= 500 +wordResult :: Integer -> Maybe CoreExpr +wordResult result + = Just (mkWordVal (toInteger (fromInteger result :: Word))) +#endif \end{code} @@ -259,28 +326,33 @@ squash i = toInteger ((fromInteger i)::Int) %************************************************************************ \begin{code} -type RuleFun = [CoreExpr] -> Maybe (RuleName, CoreExpr) +type RuleFun = [CoreExpr] -> Maybe CoreExpr -or_rule :: RuleFun -> RuleFun -> RuleFun -or_rule r1 r2 args = case r1 args of - Just stuff -> Just stuff - Nothing -> r2 args +twoLits :: (Literal -> Literal -> Maybe CoreExpr) -> RuleFun +twoLits rule [Lit l1, Lit l2] = rule (convFloating l1) (convFloating l2) +twoLits rule _ = Nothing -twoLits :: (Literal -> Literal -> Maybe (RuleName, CoreExpr)) -> RuleFun -twoLits rule [Lit l1, Lit l2] = rule l1 l2 -twoLits rule other = Nothing +oneLit :: (Literal -> Maybe CoreExpr) -> RuleFun +oneLit rule [Lit l1] = rule (convFloating l1) +oneLit rule _ = Nothing -oneLit :: (Literal -> Maybe (RuleName, CoreExpr)) -> RuleFun -oneLit rule [Lit l1] = rule l1 -oneLit rule other = Nothing +-- When excess precision is not requested, cut down the precision of the +-- Rational value to that of Float/Double. We confuse host architecture +-- and target architecture here, but it's convenient (and wrong :-). +convFloating :: Literal -> Literal +convFloating (MachFloat f) | not opt_SimplExcessPrecision = + MachFloat (toRational ((fromRational f) :: Float )) +convFloating (MachDouble d) | not opt_SimplExcessPrecision = + MachDouble (toRational ((fromRational d) :: Double)) +convFloating l = l trueVal = Var trueDataConId falseVal = Var falseDataConId -mkIntVal i = Lit (mkMachInt i) -mkCharVal c = Lit (MachChar c) -mkFloatVal f = Lit (MachFloat f) -mkDoubleVal d = Lit (MachDouble d) +mkIntVal i = Lit (mkMachInt i) +mkWordVal w = Lit (mkMachWord w) +mkFloatVal f = Lit (convFloating (MachFloat f)) +mkDoubleVal d = Lit (convFloating (MachDouble d)) \end{code} @@ -290,75 +362,19 @@ mkDoubleVal d = Lit (MachDouble d) %* * %************************************************************************ -In the parallel world, we use _seq_ to control the order in which -certain expressions will be evaluated. Operationally, the expression -``_seq_ a b'' evaluates a and then evaluates b. We have an inlining -for _seq_ which translates _seq_ to: - - _seq_ = /\ a b -> \ x::a y::b -> case seq# x of { 0# -> parError#; _ -> y } - -Now, we know that the seq# primitive will never return 0#, but we -don't let the simplifier know that. We also use a special error -value, parError#, which is *not* a bottoming Id, so as far as the -simplifier is concerned, we have to evaluate seq# a before we know -whether or not y will be evaluated. - -If we didn't have the extra case, then after inlining the compiler might -see: - f p q = case seq# p of { _ -> p+q } - -If it sees that, it can see that f is strict in q, and hence it might -evaluate q before p! The "0# ->" case prevents this happening. -By having the parError# branch we make sure that anything in the -other branch stays there! - -This is fine, but we'd like to get rid of the extraneous code. Hence, -we *do* let the simplifier know that seq# is strict in its argument. -As a result, we hope that `a' will be evaluated before seq# is called. -At this point, we have a very special and magical simpification which -says that ``seq# a'' can be immediately simplified to `1#' if we -know that `a' is already evaluated. - -NB: If we ever do case-floating, we have an extra worry: - - case a of - a' -> let b' = case seq# a of { True -> b; False -> parError# } - in case b' of ... - - => - - case a of - a' -> let b' = case True of { True -> b; False -> parError# } - in case b' of ... - - => - - case a of - a' -> let b' = b - in case b' of ... - - => - - case a of - a' -> case b of ... - -The second case must never be floated outside of the first! - -\begin{code} -seqRule [Type ty, arg] | exprIsValue arg = Just (SLIT("Seq"), mkIntVal 1) -seqRule other = Nothing -\end{code} - - \begin{code} tagToEnumRule [Type ty, Lit (MachInt i)] = ASSERT( isEnumerationTyCon tycon ) - Just (SLIT("TagToEnum"), Var (dataConId dc)) + case filter correct_tag (tyConDataCons_maybe tycon `orElse` []) of + + + [] -> Nothing -- Abstract type + (dc:rest) -> ASSERT( null rest ) + Just (Var (dataConWorkId dc)) where - tag = fromInteger i - constrs = tyConDataCons tycon - (dc:_) = [ dc | dc <- constrs, tag == dataConTag dc - fIRST_TAG ] - (Just (tycon,_)) = splitTyConApp_maybe ty + correct_tag dc = (dataConTag dc - fIRST_TAG) == tag + tag = fromInteger i + tycon = tyConAppTyCon ty tagToEnumRule other = Nothing \end{code} @@ -369,32 +385,17 @@ For dataToTag#, we can reduce if either (b) the argument is a variable whose unfolding is a known constructor \begin{code} -dataToTagRule [_, val_arg] - = case maybeConApp val_arg of - Just dc -> ASSERT( not (isNewTyCon (dataConTyCon dc)) ) - Just (SLIT("DataToTag"), - mkIntVal (toInteger (dataConTag dc - fIRST_TAG))) +dataToTagRule [Type ty1, Var tag_to_enum `App` Type ty2 `App` tag] + | Just TagToEnumOp <- isPrimOpId_maybe tag_to_enum + , ty1 `coreEqType` ty2 + = Just tag -- dataToTag (tagToEnum x) ==> x - other -> Nothing +dataToTagRule [_, val_arg] + | Just (dc,_) <- exprIsConApp_maybe val_arg + = ASSERT( not (isNewTyCon (dataConTyCon dc)) ) + Just (mkIntVal (toInteger (dataConTag dc - fIRST_TAG))) dataToTagRule other = Nothing - -maybeConApp :: CoreExpr -> Maybe DataCon -maybeConApp (Var v) - = case maybeUnfoldingTemplate (idUnfolding v) of - Just unf -> maybeConApp unf - Nothing -> Nothing - -maybeConApp expr - = go expr 0 - where - go (App f a) n | isTypeArg a = go f n - | otherwise = go f (n+1) - go (Var f) n = case isDataConId_maybe f of - Just dc -> ASSERT( n == dataConRepArity dc ) - Just dc -- Check it's saturated - other -> Nothing - go other n = Nothing \end{code} %************************************************************************ @@ -404,32 +405,43 @@ maybeConApp expr %************************************************************************ \begin{code} -builtinRules :: [ProtoCoreRule] +builtinRules :: [CoreRule] -- Rules for non-primops that can't be expressed using a RULE pragma builtinRules - = [ ProtoCoreRule False unpackCStringFoldrId - (BuiltinRule match_append_lit_str) + = [ BuiltinRule FSLIT("AppendLitString") unpackCStringFoldrName match_append_lit, + BuiltinRule FSLIT("EqString") eqStringName match_eq_string ] --- unpack "foo" c (unpack "baz" c n) = unpack "foobaz" c n +-- The rule is this: +-- unpackFoldrCString# "foo" c (unpackFoldrCString# "baz" c n) = unpackFoldrCString# "foobaz" c n -match_append_lit_str [Type ty1, - Lit (MachStr s1), - c1, - Var unpk `App` Type ty2 - `App` Lit (MachStr s2) - `App` c2 - `App` n - ] - | unpk == unpackCStringFoldrId && +match_append_lit [Type ty1, + Lit (MachStr s1), + c1, + Var unpk `App` Type ty2 + `App` Lit (MachStr s2) + `App` c2 + `App` n + ] + | unpk `hasKey` unpackCStringFoldrIdKey && c1 `cheapEqExpr` c2 - = ASSERT( ty1 == ty2 ) - Just (SLIT("AppendLitString"), - Var unpk `App` Type ty1 - `App` Lit (MachStr (s1 _APPEND_ s2)) + = ASSERT( ty1 `coreEqType` ty2 ) + Just (Var unpk `App` Type ty1 + `App` Lit (MachStr (s1 `appendFS` s2)) `App` c1 `App` n) -match_append_lit_str other = Nothing +match_append_lit other = Nothing + +-- The rule is this: +-- eqString (unpackCString# (Lit s1)) (unpackCString# (Lit s2) = s1==s2 + +match_eq_string [Var unpk1 `App` Lit (MachStr s1), + Var unpk2 `App` Lit (MachStr s2)] + | unpk1 `hasKey` unpackCStringIdKey, + unpk2 `hasKey` unpackCStringIdKey + = Just (if s1 == s2 then trueVal else falseVal) + +match_eq_string other = Nothing \end{code}