X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=ghc%2Fcompiler%2Fprelude%2FPrelRules.lhs;h=8f5df8c60e6f0ed556986d07e7db0a9e41d04812;hb=6e6b6f2c929ee59c0ab961f108406a332bda1dee;hp=081c4f108df567db41120e5d5cc4613ba75a57b8;hpb=5ca77490a603e0175bb717343884533ad8de017d;p=ghc-hetmet.git diff --git a/ghc/compiler/prelude/PrelRules.lhs b/ghc/compiler/prelude/PrelRules.lhs index 081c4f1..8f5df8c 100644 --- a/ghc/compiler/prelude/PrelRules.lhs +++ b/ghc/compiler/prelude/PrelRules.lhs @@ -3,127 +3,172 @@ % \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 ( getIdUnfolding ) -import Const ( mkMachInt, mkMachWord, Literal(..), Con(..) ) +import Id ( mkWildId ) +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 ( trueDataCon, falseDataCon ) -import TyCon ( tyConDataCons, isEnumerationTyCon, isNewTyCon ) -import DataCon ( dataConTag, dataConTyCon, fIRST_TAG ) -import CoreUnfold ( maybeUnfoldingTemplate ) -import CoreUtils ( exprIsValue, cheapEqExpr ) -import Type ( splitTyConApp_maybe ) +import TysWiredIn ( trueDataConId, falseDataConId ) +import TyCon ( tyConDataCons_maybe, isEnumerationTyCon, isNewTyCon ) +import DataCon ( dataConTag, dataConTyCon, dataConWorkId, fIRST_TAG ) +import CoreUtils ( cheapEqExpr, exprIsConApp_maybe ) +import Type ( tyConAppTyCon, eqType ) import OccName ( occNameUserString) -import ThinAir ( unpackCStringFoldrId ) -import Maybes ( maybeToBool ) -import Char ( ord, chr ) +import PrelNames ( unpackCStringFoldrName, unpackCStringFoldrIdKey, hasKey, + eqStringName, unpackCStringIdKey ) +import Maybes ( orElse ) +import Name ( Name ) import Outputable - -#if __GLASGOW_HASKELL__ >= 404 -import GlaExts ( fromInt ) +import FastString +import CmdLineOpts ( 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 -> [CoreRule] +primOpRules op = primop_rule op where - op_name = _PK_ (occNameUserString (primOpOcc op)) - op_name_case = op_name _APPEND_ SLIT("case") + op_name = mkFastString (occNameUserString (primOpOcc op)) + op_name_case = op_name `appendFS` FSLIT("->case") + + -- A useful shorthand + one_rule rule_fn = [BuiltinRule op_name 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 - - -- Addr operations - primop_rule Addr2IntOp = oneLit (addr2IntOp op_name) - - -- Char operations - primop_rule OrdOp = oneLit (chrOp 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 (intCoerce (mkCharVal . chr) op_name) - primop_rule Int2FloatOp = oneLit (intCoerce mkFloatVal op_name) - primop_rule Int2DoubleOp = oneLit (intCoerce mkDoubleVal op_name) - primop_rule Word2IntOp = oneLit (intCoerce mkIntVal op_name) - primop_rule Int2WordOp = oneLit (intCoerce mkWordVal 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 (==) op_name `or_rule` litVar True op_name_case - primop_rule IntNeOp = relop (/=) op_name `or_rule` litVar False op_name_case - primop_rule CharEqOp = relop (==) op_name `or_rule` litVar True op_name_case - primop_rule CharNeOp = relop (/=) op_name `or_rule` litVar False op_name_case - - primop_rule IntGtOp = relop (>) op_name - primop_rule IntGeOp = relop (>=) op_name - primop_rule IntLeOp = relop (<=) op_name - primop_rule IntLtOp = relop (<) op_name - - primop_rule CharGtOp = relop (>) op_name - primop_rule CharGeOp = relop (>=) op_name - primop_rule CharLeOp = relop (<=) op_name - primop_rule CharLtOp = relop (<) op_name - - primop_rule FloatGtOp = relop (>) op_name - primop_rule FloatGeOp = relop (>=) op_name - primop_rule FloatLeOp = relop (<=) op_name - primop_rule FloatLtOp = relop (<) op_name - primop_rule FloatEqOp = relop (==) op_name - primop_rule FloatNeOp = relop (/=) op_name - - primop_rule DoubleGtOp = relop (>) op_name - primop_rule DoubleGeOp = relop (>=) op_name - primop_rule DoubleLeOp = relop (<=) op_name - primop_rule DoubleLtOp = relop (<) op_name - primop_rule DoubleEqOp = relop (==) op_name - primop_rule DoubleNeOp = relop (/=) op_name - - primop_rule WordGtOp = relop (>) op_name - primop_rule WordGeOp = relop (>=) op_name - primop_rule WordLeOp = relop (<=) op_name - primop_rule WordLtOp = relop (<) op_name - primop_rule WordEqOp = relop (==) op_name - primop_rule WordNeOp = relop (/=) op_name - - primop_rule other = \args -> Nothing + primop_rule IntEqOp = [BuiltinRule op_name (relop (==)), BuiltinRule op_name_case (litEq True)] + primop_rule IntNeOp = [BuiltinRule op_name (relop (/=)), BuiltinRule op_name_case (litEq False)] + primop_rule CharEqOp = [BuiltinRule op_name (relop (==)), BuiltinRule op_name_case (litEq True)] + primop_rule CharNeOp = [BuiltinRule op_name (relop (/=)), BuiltinRule op_name_case (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. \end{code} %************************************************************************ @@ -132,59 +177,88 @@ primOpRule op %* * %************************************************************************ +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} -------------------------- -intCoerce :: Num a => (a -> CoreExpr) -> RuleName -> Literal -> Maybe (RuleName, CoreExpr) -intCoerce fn name (MachInt i _) = Just (name, fn (fromInteger i)) +litCoerce :: (Literal -> Literal) -> Literal -> Maybe CoreExpr +litCoerce fn lit = Just (Lit (fn lit)) -------------------------- -relop cmp name = twoLits (\l1 l2 -> Just (name, if l1 `cmp` l2 then trueVal else falseVal)) +cmpOp :: (Ordering -> Bool) -> Literal -> Literal -> Maybe CoreExpr +cmpOp cmp l1 l2 + = go l1 l2 + where + done res | cmp res = Just trueVal + | otherwise = Just falseVal + + -- These compares are at different types + go (MachChar i1) (MachChar i2) = done (i1 `compare` i2) + go (MachInt i1) (MachInt i2) = done (i1 `compare` i2) + go (MachInt64 i1) (MachInt64 i2) = done (i1 `compare` i2) + go (MachWord i1) (MachWord i2) = done (i1 `compare` i2) + go (MachWord64 i1) (MachWord64 i2) = done (i1 `compare` i2) + go (MachFloat i1) (MachFloat i2) = done (i1 `compare` i2) + go (MachDouble i1) (MachDouble i2) = done (i1 `compare` i2) + go l1 l2 = Nothing -------------------------- -negOp name (MachFloat f) = Just (name, mkFloatVal (-f)) -negOp name (MachDouble d) = Just (name, mkDoubleVal (-d)) -negOp name (MachInt i _) = Just (name, mkIntVal (-i)) - -chrOp name (MachChar c) = Just (name, mkIntVal (fromInt (ord c))) -addr2IntOp name (MachAddr i) = Just (name, mkIntVal i) +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 s1) l2@(MachInt i2 s2) - | (result > fromInt maxInt) || (result < fromInt minInt) - -- Better tell the user that we've overflowed... - -- ..not that it stops us from actually folding! - = pprTrace "Warning:" (text "Integer overflow in expression: " <> - ppr name <+> ppr l1 <+> ppr l2) $ - Just (name, mkIntVal result) - - | otherwise - = ASSERT( s1 && s2 ) -- Both should be signed - Just (name, mkIntVal result) - where - result = i1 `op` i2 - -intOp2Z op name (MachInt i1 s1) (MachInt i2 s2) - | i2 == 0 = Nothing -- Don't do it if the dividend < 0 - | otherwise = Just (name, mkIntVal (i1 `op` i2)) +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)) +#if __GLASGOW_HASKELL__ >= 500 +wordOp2 op (MachWord w1) (MachWord w2) + = wordResult (w1 `op` w2) +wordOp2 op l1 l2 = Nothing -- Could find LitLit +#endif -floatOp2Z op name (MachFloat f1) (MachFloat f2) - | f1 /= 0 = Just (name, mkFloatVal (f1 `op` f2)) - | otherwise = Nothing +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 (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)) - | otherwise = Nothing +doubleOp2Z op (MachDouble f1) (MachDouble f2) + | f2 /= 0 = Just (mkDoubleVal (f1 `op` f2)) +doubleOp2Z op l1 l2 = Nothing -------------------------- @@ -207,21 +281,36 @@ doubleOp2Z op name (MachDouble f1) (MachDouble f2) -- m -> e2 -- (modulo the usual precautions to avoid duplicating e1) -litVar :: Bool -- True <=> equality, False <=> inequality - -> RuleName - -> RuleFun -litVar is_eq name [Con (Literal lit) _, Var var] = do_lit_var is_eq name lit var -litVar is_eq name [Var var, Con (Literal lit) _] = do_lit_var is_eq name lit var -litVar is_eq name other = Nothing +litEq :: Bool -- True <=> equality, False <=> inequality + -> 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_var is_eq name lit var - = Just (name, Case (Var var) var [(Literal lit, [], val_if_eq), - (DEFAULT, [], val_if_neq)]) +do_lit_eq is_eq lit expr + = Just (Case expr (mkWildId (literalType lit)) + [(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 + +-- 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} @@ -232,29 +321,33 @@ do_lit_var is_eq name lit var %************************************************************************ \begin{code} -type RuleFun = [CoreExpr] -> Maybe (RuleName, 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 (RuleName, CoreExpr)) -> RuleFun -twoLits rule [Con (Literal l1) _, Con (Literal l2) _] = rule l1 l2 -twoLits rule other = Nothing - -oneLit :: (Literal -> Maybe (RuleName, CoreExpr)) -> RuleFun -oneLit rule [Con (Literal l1) _] = rule l1 -oneLit rule other = Nothing - - -trueVal = Con (DataCon trueDataCon) [] -falseVal = Con (DataCon falseDataCon) [] -mkIntVal i = Con (Literal (mkMachInt i)) [] -mkCharVal c = Con (Literal (MachChar c)) [] -mkWordVal w = Con (Literal (mkMachWord w)) [] -mkFloatVal f = Con (Literal (MachFloat f)) [] -mkDoubleVal d = Con (Literal (MachDouble d)) [] +type RuleFun = [CoreExpr] -> Maybe CoreExpr + +twoLits :: (Literal -> Literal -> Maybe CoreExpr) -> RuleFun +twoLits rule [Lit l1, Lit l2] = rule (convFloating l1) (convFloating l2) +twoLits rule _ = Nothing + +oneLit :: (Literal -> Maybe CoreExpr) -> RuleFun +oneLit rule [Lit l1] = rule (convFloating l1) +oneLit rule _ = 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) +mkWordVal w = Lit (mkMachWord w) +mkFloatVal f = Lit (convFloating (MachFloat f)) +mkDoubleVal d = Lit (convFloating (MachDouble d)) \end{code} @@ -264,75 +357,19 @@ mkDoubleVal d = Con (Literal (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} +tagToEnumRule [Type ty, Lit (MachInt i)] + = ASSERT( isEnumerationTyCon tycon ) + case filter correct_tag (tyConDataCons_maybe tycon `orElse` []) of -\begin{code} -tagToEnumRule [Type ty, Con (Literal (MachInt i _)) _] - = ASSERT( isEnumerationTyCon tycon ) - Just (SLIT("TagToEnum"), Con (DataCon dc) []) + [] -> 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} @@ -344,16 +381,11 @@ For dataToTag#, we can reduce if either \begin{code} dataToTagRule [_, val_arg] - = case val_arg of - Con (DataCon dc) _ -> yes dc - Var x -> case maybeUnfoldingTemplate (getIdUnfolding x) of - Just (Con (DataCon dc) _) -> yes dc - other -> Nothing - other -> Nothing - where - yes dc = ASSERT( not (isNewTyCon (dataConTyCon dc)) ) - Just (SLIT("DataToTag"), - mkIntVal (toInteger (dataConTag dc - fIRST_TAG))) + = case exprIsConApp_maybe val_arg of + Just (dc,_) -> ASSERT( not (isNewTyCon (dataConTyCon dc)) ) + Just (mkIntVal (toInteger (dataConTag dc - fIRST_TAG))) + + other -> Nothing dataToTagRule other = Nothing \end{code} @@ -365,31 +397,43 @@ dataToTagRule other = Nothing %************************************************************************ \begin{code} -builtinRules :: [ProtoCoreRule] +builtinRules :: [(Name, CoreRule)] +-- Rules for non-primops that can't be expressed using a RULE pragma builtinRules - = [ ProtoCoreRule False unpackCStringFoldrId - (BuiltinRule match_append_lit_str) + = [ (unpackCStringFoldrName, BuiltinRule FSLIT("AppendLitString") match_append_lit), + (eqStringName, BuiltinRule FSLIT("EqString") 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, - Con (Literal (MachStr s1)) [], - c1, - Var unpk `App` Type ty2 - `App` Con (Literal (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` Con (Literal (MachStr (s1 _APPEND_ s2))) [] + = ASSERT( ty1 `eqType` 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}