diff options
author | Austin Seipp <austin@well-typed.com> | 2014-12-03 12:42:24 -0600 |
---|---|---|
committer | Austin Seipp <austin@well-typed.com> | 2014-12-03 12:42:24 -0600 |
commit | dc00fb1b5e75fda17384af612a98a8c99f874cff (patch) | |
tree | 131d54bd8f43dfd151a08c4609654b615c684e5a /compiler/prelude/PrelRules.lhs | |
parent | 1389ff565d9a41d21eb7e4fc6e2b23d0df08de24 (diff) | |
download | haskell-dc00fb1b5e75fda17384af612a98a8c99f874cff.tar.gz |
compiler: de-lhs prelude/
Signed-off-by: Austin Seipp <austin@well-typed.com>
Diffstat (limited to 'compiler/prelude/PrelRules.lhs')
-rw-r--r-- | compiler/prelude/PrelRules.lhs | 1330 |
1 files changed, 0 insertions, 1330 deletions
diff --git a/compiler/prelude/PrelRules.lhs b/compiler/prelude/PrelRules.lhs deleted file mode 100644 index 054137178b..0000000000 --- a/compiler/prelude/PrelRules.lhs +++ /dev/null @@ -1,1330 +0,0 @@ -% -% (c) The GRASP/AQUA Project, Glasgow University, 1992-1998 -% -\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} -{-# LANGUAGE CPP, RankNTypes #-} -{-# OPTIONS_GHC -optc-DNON_POSIX_SOURCE #-} - -module PrelRules ( primOpRules, builtinRules ) where - -#include "HsVersions.h" -#include "../includes/MachDeps.h" - -import {-# SOURCE #-} MkId ( mkPrimOpId, magicDictId ) - -import CoreSyn -import MkCore -import Id -import Literal -import CoreSubst ( exprIsLiteral_maybe ) -import PrimOp ( PrimOp(..), tagToEnumKey ) -import TysWiredIn -import TysPrim -import TyCon ( tyConDataCons_maybe, isEnumerationTyCon, isNewTyCon, unwrapNewTyCon_maybe ) -import DataCon ( dataConTag, dataConTyCon, dataConWorkId ) -import CoreUtils ( cheapEqExpr, exprIsHNF ) -import CoreUnfold ( exprIsConApp_maybe ) -import Type -import TypeRep -import OccName ( occNameFS ) -import PrelNames -import Maybes ( orElse ) -import Name ( Name, nameOccName ) -import Outputable -import FastString -import BasicTypes -import DynFlags -import Platform -import Util -import Coercion (mkUnbranchedAxInstCo,mkSymCo,Role(..)) - -#if __GLASGOW_HASKELL__ >= 709 -import Control.Applicative ( Alternative(..) ) -#else -import Control.Applicative ( Applicative(..), Alternative(..) ) -#endif - -import Control.Monad -import Data.Bits as Bits -import qualified Data.ByteString as BS -import Data.Int -import Data.Ratio -import Data.Word -\end{code} - - -Note [Constant folding] -~~~~~~~~~~~~~~~~~~~~~~~ -primOpRules generates a rewrite rule for each primop -These rules do what is often called "constant folding" -E.g. the rules for +# might say - 4 +# 5 = 9 -Well, of course you'd need a lot of rules if you did it -like that, so we use a BuiltinRule instead, so that we -can match in any two literal values. So the rule is really -more like - (Lit x) +# (Lit y) = Lit (x+#y) -where the (+#) on the rhs is done at compile time - -That is why these rules are built in here. - - -\begin{code} -primOpRules :: Name -> PrimOp -> Maybe CoreRule - -- ToDo: something for integer-shift ops? - -- NotOp -primOpRules nm TagToEnumOp = mkPrimOpRule nm 2 [ tagToEnumRule ] -primOpRules nm DataToTagOp = mkPrimOpRule nm 2 [ dataToTagRule ] - --- Int operations -primOpRules nm IntAddOp = mkPrimOpRule nm 2 [ binaryLit (intOp2 (+)) - , identityDynFlags zeroi ] -primOpRules nm IntSubOp = mkPrimOpRule nm 2 [ binaryLit (intOp2 (-)) - , rightIdentityDynFlags zeroi - , equalArgs >> retLit zeroi ] -primOpRules nm IntMulOp = mkPrimOpRule nm 2 [ binaryLit (intOp2 (*)) - , zeroElem zeroi - , identityDynFlags onei ] -primOpRules nm IntQuotOp = mkPrimOpRule nm 2 [ nonZeroLit 1 >> binaryLit (intOp2 quot) - , leftZero zeroi - , rightIdentityDynFlags onei - , equalArgs >> retLit onei ] -primOpRules nm IntRemOp = mkPrimOpRule nm 2 [ nonZeroLit 1 >> binaryLit (intOp2 rem) - , leftZero zeroi - , do l <- getLiteral 1 - dflags <- getDynFlags - guard (l == onei dflags) - retLit zeroi - , equalArgs >> retLit zeroi - , equalArgs >> retLit zeroi ] -primOpRules nm AndIOp = mkPrimOpRule nm 2 [ binaryLit (intOp2 (.&.)) - , idempotent - , zeroElem zeroi ] -primOpRules nm OrIOp = mkPrimOpRule nm 2 [ binaryLit (intOp2 (.|.)) - , idempotent - , identityDynFlags zeroi ] -primOpRules nm XorIOp = mkPrimOpRule nm 2 [ binaryLit (intOp2 xor) - , identityDynFlags zeroi - , equalArgs >> retLit zeroi ] -primOpRules nm NotIOp = mkPrimOpRule nm 1 [ unaryLit complementOp - , inversePrimOp NotIOp ] -primOpRules nm IntNegOp = mkPrimOpRule nm 1 [ unaryLit negOp - , inversePrimOp IntNegOp ] -primOpRules nm ISllOp = mkPrimOpRule nm 2 [ binaryLit (intOp2 Bits.shiftL) - , rightIdentityDynFlags zeroi ] -primOpRules nm ISraOp = mkPrimOpRule nm 2 [ binaryLit (intOp2 Bits.shiftR) - , rightIdentityDynFlags zeroi ] -primOpRules nm ISrlOp = mkPrimOpRule nm 2 [ binaryLit (intOp2' shiftRightLogical) - , rightIdentityDynFlags zeroi ] - --- Word operations -primOpRules nm WordAddOp = mkPrimOpRule nm 2 [ binaryLit (wordOp2 (+)) - , identityDynFlags zerow ] -primOpRules nm WordSubOp = mkPrimOpRule nm 2 [ binaryLit (wordOp2 (-)) - , rightIdentityDynFlags zerow - , equalArgs >> retLit zerow ] -primOpRules nm WordMulOp = mkPrimOpRule nm 2 [ binaryLit (wordOp2 (*)) - , identityDynFlags onew ] -primOpRules nm WordQuotOp = mkPrimOpRule nm 2 [ nonZeroLit 1 >> binaryLit (wordOp2 quot) - , rightIdentityDynFlags onew ] -primOpRules nm WordRemOp = mkPrimOpRule nm 2 [ nonZeroLit 1 >> binaryLit (wordOp2 rem) - , rightIdentityDynFlags onew ] -primOpRules nm AndOp = mkPrimOpRule nm 2 [ binaryLit (wordOp2 (.&.)) - , idempotent - , zeroElem zerow ] -primOpRules nm OrOp = mkPrimOpRule nm 2 [ binaryLit (wordOp2 (.|.)) - , idempotent - , identityDynFlags zerow ] -primOpRules nm XorOp = mkPrimOpRule nm 2 [ binaryLit (wordOp2 xor) - , identityDynFlags zerow - , equalArgs >> retLit zerow ] -primOpRules nm NotOp = mkPrimOpRule nm 1 [ unaryLit complementOp - , inversePrimOp NotOp ] -primOpRules nm SllOp = mkPrimOpRule nm 2 [ wordShiftRule (const Bits.shiftL) ] -primOpRules nm SrlOp = mkPrimOpRule nm 2 [ wordShiftRule shiftRightLogical ] - --- coercions -primOpRules nm Word2IntOp = mkPrimOpRule nm 1 [ liftLitDynFlags word2IntLit - , inversePrimOp Int2WordOp ] -primOpRules nm Int2WordOp = mkPrimOpRule nm 1 [ liftLitDynFlags int2WordLit - , inversePrimOp Word2IntOp ] -primOpRules nm Narrow8IntOp = mkPrimOpRule nm 1 [ liftLit narrow8IntLit - , subsumedByPrimOp Narrow8IntOp - , Narrow8IntOp `subsumesPrimOp` Narrow16IntOp - , Narrow8IntOp `subsumesPrimOp` Narrow32IntOp ] -primOpRules nm Narrow16IntOp = mkPrimOpRule nm 1 [ liftLit narrow16IntLit - , subsumedByPrimOp Narrow8IntOp - , subsumedByPrimOp Narrow16IntOp - , Narrow16IntOp `subsumesPrimOp` Narrow32IntOp ] -primOpRules nm Narrow32IntOp = mkPrimOpRule nm 1 [ liftLit narrow32IntLit - , subsumedByPrimOp Narrow8IntOp - , subsumedByPrimOp Narrow16IntOp - , subsumedByPrimOp Narrow32IntOp - , removeOp32 ] -primOpRules nm Narrow8WordOp = mkPrimOpRule nm 1 [ liftLit narrow8WordLit - , subsumedByPrimOp Narrow8WordOp - , Narrow8WordOp `subsumesPrimOp` Narrow16WordOp - , Narrow8WordOp `subsumesPrimOp` Narrow32WordOp ] -primOpRules nm Narrow16WordOp = mkPrimOpRule nm 1 [ liftLit narrow16WordLit - , subsumedByPrimOp Narrow8WordOp - , subsumedByPrimOp Narrow16WordOp - , Narrow16WordOp `subsumesPrimOp` Narrow32WordOp ] -primOpRules nm Narrow32WordOp = mkPrimOpRule nm 1 [ liftLit narrow32WordLit - , subsumedByPrimOp Narrow8WordOp - , subsumedByPrimOp Narrow16WordOp - , subsumedByPrimOp Narrow32WordOp - , removeOp32 ] -primOpRules nm OrdOp = mkPrimOpRule nm 1 [ liftLit char2IntLit - , inversePrimOp ChrOp ] -primOpRules nm ChrOp = mkPrimOpRule nm 1 [ do [Lit lit] <- getArgs - guard (litFitsInChar lit) - liftLit int2CharLit - , inversePrimOp OrdOp ] -primOpRules nm Float2IntOp = mkPrimOpRule nm 1 [ liftLit float2IntLit ] -primOpRules nm Int2FloatOp = mkPrimOpRule nm 1 [ liftLit int2FloatLit ] -primOpRules nm Double2IntOp = mkPrimOpRule nm 1 [ liftLit double2IntLit ] -primOpRules nm Int2DoubleOp = mkPrimOpRule nm 1 [ liftLit int2DoubleLit ] --- SUP: Not sure what the standard says about precision in the following 2 cases -primOpRules nm Float2DoubleOp = mkPrimOpRule nm 1 [ liftLit float2DoubleLit ] -primOpRules nm Double2FloatOp = mkPrimOpRule nm 1 [ liftLit double2FloatLit ] - --- Float -primOpRules nm FloatAddOp = mkPrimOpRule nm 2 [ binaryLit (floatOp2 (+)) - , identity zerof ] -primOpRules nm FloatSubOp = mkPrimOpRule nm 2 [ binaryLit (floatOp2 (-)) - , rightIdentity zerof ] -primOpRules nm FloatMulOp = mkPrimOpRule nm 2 [ binaryLit (floatOp2 (*)) - , identity onef - , strengthReduction twof FloatAddOp ] - -- zeroElem zerof doesn't hold because of NaN -primOpRules nm FloatDivOp = mkPrimOpRule nm 2 [ guardFloatDiv >> binaryLit (floatOp2 (/)) - , rightIdentity onef ] -primOpRules nm FloatNegOp = mkPrimOpRule nm 1 [ unaryLit negOp - , inversePrimOp FloatNegOp ] - --- Double -primOpRules nm DoubleAddOp = mkPrimOpRule nm 2 [ binaryLit (doubleOp2 (+)) - , identity zerod ] -primOpRules nm DoubleSubOp = mkPrimOpRule nm 2 [ binaryLit (doubleOp2 (-)) - , rightIdentity zerod ] -primOpRules nm DoubleMulOp = mkPrimOpRule nm 2 [ binaryLit (doubleOp2 (*)) - , identity oned - , strengthReduction twod DoubleAddOp ] - -- zeroElem zerod doesn't hold because of NaN -primOpRules nm DoubleDivOp = mkPrimOpRule nm 2 [ guardDoubleDiv >> binaryLit (doubleOp2 (/)) - , rightIdentity oned ] -primOpRules nm DoubleNegOp = mkPrimOpRule nm 1 [ unaryLit negOp - , inversePrimOp DoubleNegOp ] - --- Relational operators - -primOpRules nm IntEqOp = mkRelOpRule nm (==) [ litEq True ] -primOpRules nm IntNeOp = mkRelOpRule nm (/=) [ litEq False ] -primOpRules nm CharEqOp = mkRelOpRule nm (==) [ litEq True ] -primOpRules nm CharNeOp = mkRelOpRule nm (/=) [ litEq False ] - -primOpRules nm IntGtOp = mkRelOpRule nm (>) [ boundsCmp Gt ] -primOpRules nm IntGeOp = mkRelOpRule nm (>=) [ boundsCmp Ge ] -primOpRules nm IntLeOp = mkRelOpRule nm (<=) [ boundsCmp Le ] -primOpRules nm IntLtOp = mkRelOpRule nm (<) [ boundsCmp Lt ] - -primOpRules nm CharGtOp = mkRelOpRule nm (>) [ boundsCmp Gt ] -primOpRules nm CharGeOp = mkRelOpRule nm (>=) [ boundsCmp Ge ] -primOpRules nm CharLeOp = mkRelOpRule nm (<=) [ boundsCmp Le ] -primOpRules nm CharLtOp = mkRelOpRule nm (<) [ boundsCmp Lt ] - -primOpRules nm FloatGtOp = mkFloatingRelOpRule nm (>) [] -primOpRules nm FloatGeOp = mkFloatingRelOpRule nm (>=) [] -primOpRules nm FloatLeOp = mkFloatingRelOpRule nm (<=) [] -primOpRules nm FloatLtOp = mkFloatingRelOpRule nm (<) [] -primOpRules nm FloatEqOp = mkFloatingRelOpRule nm (==) [ litEq True ] -primOpRules nm FloatNeOp = mkFloatingRelOpRule nm (/=) [ litEq False ] - -primOpRules nm DoubleGtOp = mkFloatingRelOpRule nm (>) [] -primOpRules nm DoubleGeOp = mkFloatingRelOpRule nm (>=) [] -primOpRules nm DoubleLeOp = mkFloatingRelOpRule nm (<=) [] -primOpRules nm DoubleLtOp = mkFloatingRelOpRule nm (<) [] -primOpRules nm DoubleEqOp = mkFloatingRelOpRule nm (==) [ litEq True ] -primOpRules nm DoubleNeOp = mkFloatingRelOpRule nm (/=) [ litEq False ] - -primOpRules nm WordGtOp = mkRelOpRule nm (>) [ boundsCmp Gt ] -primOpRules nm WordGeOp = mkRelOpRule nm (>=) [ boundsCmp Ge ] -primOpRules nm WordLeOp = mkRelOpRule nm (<=) [ boundsCmp Le ] -primOpRules nm WordLtOp = mkRelOpRule nm (<) [ boundsCmp Lt ] -primOpRules nm WordEqOp = mkRelOpRule nm (==) [ litEq True ] -primOpRules nm WordNeOp = mkRelOpRule nm (/=) [ litEq False ] - -primOpRules nm AddrAddOp = mkPrimOpRule nm 2 [ rightIdentityDynFlags zeroi ] - -primOpRules nm SeqOp = mkPrimOpRule nm 4 [ seqRule ] -primOpRules nm SparkOp = mkPrimOpRule nm 4 [ sparkRule ] - -primOpRules _ _ = Nothing - -\end{code} - -%************************************************************************ -%* * -\subsection{Doing the business} -%* * -%************************************************************************ - -\begin{code} - --- useful shorthands -mkPrimOpRule :: Name -> Int -> [RuleM CoreExpr] -> Maybe CoreRule -mkPrimOpRule nm arity rules = Just $ mkBasicRule nm arity (msum rules) - -mkRelOpRule :: Name -> (forall a . Ord a => a -> a -> Bool) - -> [RuleM CoreExpr] -> Maybe CoreRule -mkRelOpRule nm cmp extra - = mkPrimOpRule nm 2 $ rules ++ extra - where - rules = [ binaryCmpLit cmp - , do equalArgs - -- x `cmp` x does not depend on x, so - -- compute it for the arbitrary value 'True' - -- and use that result - dflags <- getDynFlags - return (if cmp True True - then trueValInt dflags - else falseValInt dflags) ] - --- Note [Rules for floating-point comparisons] --- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --- --- We need different rules for floating-point values because for floats --- it is not true that x = x. The special case when this does not occur --- are NaNs. - -mkFloatingRelOpRule :: Name -> (forall a . Ord a => a -> a -> Bool) - -> [RuleM CoreExpr] -> Maybe CoreRule -mkFloatingRelOpRule nm cmp extra -- See Note [Rules for floating-point comparisons] - = mkPrimOpRule nm 2 $ binaryCmpLit cmp : extra - --- common constants -zeroi, onei, zerow, onew :: DynFlags -> Literal -zeroi dflags = mkMachInt dflags 0 -onei dflags = mkMachInt dflags 1 -zerow dflags = mkMachWord dflags 0 -onew dflags = mkMachWord dflags 1 - -zerof, onef, twof, zerod, oned, twod :: Literal -zerof = mkMachFloat 0.0 -onef = mkMachFloat 1.0 -twof = mkMachFloat 2.0 -zerod = mkMachDouble 0.0 -oned = mkMachDouble 1.0 -twod = mkMachDouble 2.0 - -cmpOp :: DynFlags -> (forall a . Ord a => a -> a -> Bool) - -> Literal -> Literal -> Maybe CoreExpr -cmpOp dflags cmp = go - where - done True = Just $ trueValInt dflags - done False = Just $ falseValInt dflags - - -- These compares are at different types - go (MachChar i1) (MachChar i2) = done (i1 `cmp` i2) - go (MachInt i1) (MachInt i2) = done (i1 `cmp` i2) - go (MachInt64 i1) (MachInt64 i2) = done (i1 `cmp` i2) - go (MachWord i1) (MachWord i2) = done (i1 `cmp` i2) - go (MachWord64 i1) (MachWord64 i2) = done (i1 `cmp` i2) - go (MachFloat i1) (MachFloat i2) = done (i1 `cmp` i2) - go (MachDouble i1) (MachDouble i2) = done (i1 `cmp` i2) - go _ _ = Nothing - --------------------------- - -negOp :: DynFlags -> Literal -> Maybe CoreExpr -- Negate -negOp _ (MachFloat 0.0) = Nothing -- can't represent -0.0 as a Rational -negOp dflags (MachFloat f) = Just (mkFloatVal dflags (-f)) -negOp _ (MachDouble 0.0) = Nothing -negOp dflags (MachDouble d) = Just (mkDoubleVal dflags (-d)) -negOp dflags (MachInt i) = intResult dflags (-i) -negOp _ _ = Nothing - -complementOp :: DynFlags -> Literal -> Maybe CoreExpr -- Binary complement -complementOp dflags (MachWord i) = wordResult dflags (complement i) -complementOp dflags (MachInt i) = intResult dflags (complement i) -complementOp _ _ = Nothing - --------------------------- -intOp2 :: (Integral a, Integral b) - => (a -> b -> Integer) - -> DynFlags -> Literal -> Literal -> Maybe CoreExpr -intOp2 = intOp2' . const - -intOp2' :: (Integral a, Integral b) - => (DynFlags -> a -> b -> Integer) - -> DynFlags -> Literal -> Literal -> Maybe CoreExpr -intOp2' op dflags (MachInt i1) (MachInt i2) = - let o = op dflags - in intResult dflags (fromInteger i1 `o` fromInteger i2) -intOp2' _ _ _ _ = Nothing -- Could find LitLit - -shiftRightLogical :: DynFlags -> Integer -> Int -> Integer --- Shift right, putting zeros in rather than sign-propagating as Bits.shiftR would do --- Do this by converting to Word and back. Obviously this won't work for big --- values, but its ok as we use it here -shiftRightLogical dflags x n - | wordSizeInBits dflags == 32 = fromIntegral (fromInteger x `shiftR` n :: Word32) - | wordSizeInBits dflags == 64 = fromIntegral (fromInteger x `shiftR` n :: Word64) - | otherwise = panic "shiftRightLogical: unsupported word size" - --------------------------- -retLit :: (DynFlags -> Literal) -> RuleM CoreExpr -retLit l = do dflags <- getDynFlags - return $ Lit $ l dflags - -wordOp2 :: (Integral a, Integral b) - => (a -> b -> Integer) - -> DynFlags -> Literal -> Literal -> Maybe CoreExpr -wordOp2 op dflags (MachWord w1) (MachWord w2) - = wordResult dflags (fromInteger w1 `op` fromInteger w2) -wordOp2 _ _ _ _ = Nothing -- Could find LitLit - -wordShiftRule :: (DynFlags -> Integer -> Int -> Integer) -> RuleM CoreExpr - -- Shifts take an Int; hence third arg of op is Int --- See Note [Guarding against silly shifts] -wordShiftRule shift_op - = do { dflags <- getDynFlags - ; [e1, Lit (MachInt shift_len)] <- getArgs - ; case e1 of - _ | shift_len == 0 - -> return e1 - | shift_len < 0 || wordSizeInBits dflags < shift_len - -> return (mkRuntimeErrorApp rUNTIME_ERROR_ID wordPrimTy - ("Bad shift length" ++ show shift_len)) - Lit (MachWord x) - -> let op = shift_op dflags - in liftMaybe $ wordResult dflags (x `op` fromInteger shift_len) - -- Do the shift at type Integer, but shift length is Int - _ -> mzero } - -wordSizeInBits :: DynFlags -> Integer -wordSizeInBits dflags = toInteger (platformWordSize (targetPlatform dflags) `shiftL` 3) - --------------------------- -floatOp2 :: (Rational -> Rational -> Rational) - -> DynFlags -> Literal -> Literal - -> Maybe (Expr CoreBndr) -floatOp2 op dflags (MachFloat f1) (MachFloat f2) - = Just (mkFloatVal dflags (f1 `op` f2)) -floatOp2 _ _ _ _ = Nothing - --------------------------- -doubleOp2 :: (Rational -> Rational -> Rational) - -> DynFlags -> Literal -> Literal - -> Maybe (Expr CoreBndr) -doubleOp2 op dflags (MachDouble f1) (MachDouble f2) - = Just (mkDoubleVal dflags (f1 `op` f2)) -doubleOp2 _ _ _ _ = Nothing - --------------------------- --- This stuff turns --- n ==# 3# --- into --- case n of --- 3# -> True --- m -> False --- --- This is a Good Thing, because it allows case-of case things --- to happen, and case-default absorption to happen. For --- example: --- --- if (n ==# 3#) || (n ==# 4#) then e1 else e2 --- will transform to --- case n of --- 3# -> e1 --- 4# -> e1 --- m -> e2 --- (modulo the usual precautions to avoid duplicating e1) - -litEq :: Bool -- True <=> equality, False <=> inequality - -> RuleM CoreExpr -litEq is_eq = msum - [ do [Lit lit, expr] <- getArgs - dflags <- getDynFlags - do_lit_eq dflags lit expr - , do [expr, Lit lit] <- getArgs - dflags <- getDynFlags - do_lit_eq dflags lit expr ] - where - do_lit_eq dflags lit expr = do - guard (not (litIsLifted lit)) - return (mkWildCase expr (literalType lit) intPrimTy - [(DEFAULT, [], val_if_neq), - (LitAlt lit, [], val_if_eq)]) - where - val_if_eq | is_eq = trueValInt dflags - | otherwise = falseValInt dflags - val_if_neq | is_eq = falseValInt dflags - | otherwise = trueValInt dflags - - --- | Check if there is comparison with minBound or maxBound, that is --- always true or false. For instance, an Int cannot be smaller than its --- minBound, so we can replace such comparison with False. -boundsCmp :: Comparison -> RuleM CoreExpr -boundsCmp op = do - dflags <- getDynFlags - [a, b] <- getArgs - liftMaybe $ mkRuleFn dflags op a b - -data Comparison = Gt | Ge | Lt | Le - -mkRuleFn :: DynFlags -> Comparison -> CoreExpr -> CoreExpr -> Maybe CoreExpr -mkRuleFn dflags Gt (Lit lit) _ | isMinBound dflags lit = Just $ falseValInt dflags -mkRuleFn dflags Le (Lit lit) _ | isMinBound dflags lit = Just $ trueValInt dflags -mkRuleFn dflags Ge _ (Lit lit) | isMinBound dflags lit = Just $ trueValInt dflags -mkRuleFn dflags Lt _ (Lit lit) | isMinBound dflags lit = Just $ falseValInt dflags -mkRuleFn dflags Ge (Lit lit) _ | isMaxBound dflags lit = Just $ trueValInt dflags -mkRuleFn dflags Lt (Lit lit) _ | isMaxBound dflags lit = Just $ falseValInt dflags -mkRuleFn dflags Gt _ (Lit lit) | isMaxBound dflags lit = Just $ falseValInt dflags -mkRuleFn dflags Le _ (Lit lit) | isMaxBound dflags lit = Just $ trueValInt dflags -mkRuleFn _ _ _ _ = Nothing - -isMinBound :: DynFlags -> Literal -> Bool -isMinBound _ (MachChar c) = c == minBound -isMinBound dflags (MachInt i) = i == tARGET_MIN_INT dflags -isMinBound _ (MachInt64 i) = i == toInteger (minBound :: Int64) -isMinBound _ (MachWord i) = i == 0 -isMinBound _ (MachWord64 i) = i == 0 -isMinBound _ _ = False - -isMaxBound :: DynFlags -> Literal -> Bool -isMaxBound _ (MachChar c) = c == maxBound -isMaxBound dflags (MachInt i) = i == tARGET_MAX_INT dflags -isMaxBound _ (MachInt64 i) = i == toInteger (maxBound :: Int64) -isMaxBound dflags (MachWord i) = i == tARGET_MAX_WORD dflags -isMaxBound _ (MachWord64 i) = i == toInteger (maxBound :: Word64) -isMaxBound _ _ = False - - --- 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 --- *target* Int/Word range. -intResult :: DynFlags -> Integer -> Maybe CoreExpr -intResult dflags result = Just (mkIntVal dflags result') - where result' = case platformWordSize (targetPlatform dflags) of - 4 -> toInteger (fromInteger result :: Int32) - 8 -> toInteger (fromInteger result :: Int64) - w -> panic ("intResult: Unknown platformWordSize: " ++ show w) - -wordResult :: DynFlags -> Integer -> Maybe CoreExpr -wordResult dflags result = Just (mkWordVal dflags result') - where result' = case platformWordSize (targetPlatform dflags) of - 4 -> toInteger (fromInteger result :: Word32) - 8 -> toInteger (fromInteger result :: Word64) - w -> panic ("wordResult: Unknown platformWordSize: " ++ show w) - -inversePrimOp :: PrimOp -> RuleM CoreExpr -inversePrimOp primop = do - [Var primop_id `App` e] <- getArgs - matchPrimOpId primop primop_id - return e - -subsumesPrimOp :: PrimOp -> PrimOp -> RuleM CoreExpr -this `subsumesPrimOp` that = do - [Var primop_id `App` e] <- getArgs - matchPrimOpId that primop_id - return (Var (mkPrimOpId this) `App` e) - -subsumedByPrimOp :: PrimOp -> RuleM CoreExpr -subsumedByPrimOp primop = do - [e@(Var primop_id `App` _)] <- getArgs - matchPrimOpId primop primop_id - return e - -idempotent :: RuleM CoreExpr -idempotent = do [e1, e2] <- getArgs - guard $ cheapEqExpr e1 e2 - return e1 -\end{code} - -Note [Guarding against silly shifts] -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Consider this code: - - import Data.Bits( (.|.), shiftL ) - chunkToBitmap :: [Bool] -> Word32 - chunkToBitmap chunk = foldr (.|.) 0 [ 1 `shiftL` n | (True,n) <- zip chunk [0..] ] - -This optimises to: -Shift.$wgo = \ (w_sCS :: GHC.Prim.Int#) (w1_sCT :: [GHC.Types.Bool]) -> - case w1_sCT of _ { - [] -> __word 0; - : x_aAW xs_aAX -> - case x_aAW of _ { - GHC.Types.False -> - case w_sCS of wild2_Xh { - __DEFAULT -> Shift.$wgo (GHC.Prim.+# wild2_Xh 1) xs_aAX; - 9223372036854775807 -> __word 0 }; - GHC.Types.True -> - case GHC.Prim.>=# w_sCS 64 of _ { - GHC.Types.False -> - case w_sCS of wild3_Xh { - __DEFAULT -> - case Shift.$wgo (GHC.Prim.+# wild3_Xh 1) xs_aAX of ww_sCW { __DEFAULT -> - GHC.Prim.or# (GHC.Prim.narrow32Word# - (GHC.Prim.uncheckedShiftL# (__word 1) wild3_Xh)) - ww_sCW - }; - 9223372036854775807 -> - GHC.Prim.narrow32Word# -!!!!--> (GHC.Prim.uncheckedShiftL# (__word 1) 9223372036854775807) - }; - GHC.Types.True -> - case w_sCS of wild3_Xh { - __DEFAULT -> Shift.$wgo (GHC.Prim.+# wild3_Xh 1) xs_aAX; - 9223372036854775807 -> __word 0 - } } } } - -Note the massive shift on line "!!!!". It can't happen, because we've checked -that w < 64, but the optimiser didn't spot that. We DO NO want to constant-fold this! -Moreover, if the programmer writes (n `uncheckedShiftL` 9223372036854775807), we -can't constant fold it, but if it gets to the assember we get - Error: operand type mismatch for `shl' - -So the best thing to do is to rewrite the shift with a call to error, -when the second arg is stupid. - -%************************************************************************ -%* * -\subsection{Vaguely generic functions} -%* * -%************************************************************************ - -\begin{code} -mkBasicRule :: Name -> Int -> RuleM CoreExpr -> CoreRule --- Gives the Rule the same name as the primop itself -mkBasicRule op_name n_args rm - = BuiltinRule { ru_name = occNameFS (nameOccName op_name), - ru_fn = op_name, - ru_nargs = n_args, - ru_try = \ dflags in_scope _ -> runRuleM rm dflags in_scope } - -newtype RuleM r = RuleM - { runRuleM :: DynFlags -> InScopeEnv -> [CoreExpr] -> Maybe r } - -instance Functor RuleM where - fmap = liftM - -instance Applicative RuleM where - pure = return - (<*>) = ap - -instance Monad RuleM where - return x = RuleM $ \_ _ _ -> Just x - RuleM f >>= g = RuleM $ \dflags iu e -> case f dflags iu e of - Nothing -> Nothing - Just r -> runRuleM (g r) dflags iu e - fail _ = mzero - -instance Alternative RuleM where - empty = mzero - (<|>) = mplus - -instance MonadPlus RuleM where - mzero = RuleM $ \_ _ _ -> Nothing - mplus (RuleM f1) (RuleM f2) = RuleM $ \dflags iu args -> - f1 dflags iu args `mplus` f2 dflags iu args - -instance HasDynFlags RuleM where - getDynFlags = RuleM $ \dflags _ _ -> Just dflags - -liftMaybe :: Maybe a -> RuleM a -liftMaybe Nothing = mzero -liftMaybe (Just x) = return x - -liftLit :: (Literal -> Literal) -> RuleM CoreExpr -liftLit f = liftLitDynFlags (const f) - -liftLitDynFlags :: (DynFlags -> Literal -> Literal) -> RuleM CoreExpr -liftLitDynFlags f = do - dflags <- getDynFlags - [Lit lit] <- getArgs - return $ Lit (f dflags lit) - -removeOp32 :: RuleM CoreExpr -removeOp32 = do - dflags <- getDynFlags - if wordSizeInBits dflags == 32 - then do - [e] <- getArgs - return e - else mzero - -getArgs :: RuleM [CoreExpr] -getArgs = RuleM $ \_ _ args -> Just args - -getInScopeEnv :: RuleM InScopeEnv -getInScopeEnv = RuleM $ \_ iu _ -> Just iu - --- return the n-th argument of this rule, if it is a literal --- argument indices start from 0 -getLiteral :: Int -> RuleM Literal -getLiteral n = RuleM $ \_ _ exprs -> case drop n exprs of - (Lit l:_) -> Just l - _ -> Nothing - -unaryLit :: (DynFlags -> Literal -> Maybe CoreExpr) -> RuleM CoreExpr -unaryLit op = do - dflags <- getDynFlags - [Lit l] <- getArgs - liftMaybe $ op dflags (convFloating dflags l) - -binaryLit :: (DynFlags -> Literal -> Literal -> Maybe CoreExpr) -> RuleM CoreExpr -binaryLit op = do - dflags <- getDynFlags - [Lit l1, Lit l2] <- getArgs - liftMaybe $ op dflags (convFloating dflags l1) (convFloating dflags l2) - -binaryCmpLit :: (forall a . Ord a => a -> a -> Bool) -> RuleM CoreExpr -binaryCmpLit op = do - dflags <- getDynFlags - binaryLit (\_ -> cmpOp dflags op) - -leftIdentity :: Literal -> RuleM CoreExpr -leftIdentity id_lit = leftIdentityDynFlags (const id_lit) - -rightIdentity :: Literal -> RuleM CoreExpr -rightIdentity id_lit = rightIdentityDynFlags (const id_lit) - -identity :: Literal -> RuleM CoreExpr -identity lit = leftIdentity lit `mplus` rightIdentity lit - -leftIdentityDynFlags :: (DynFlags -> Literal) -> RuleM CoreExpr -leftIdentityDynFlags id_lit = do - dflags <- getDynFlags - [Lit l1, e2] <- getArgs - guard $ l1 == id_lit dflags - return e2 - -rightIdentityDynFlags :: (DynFlags -> Literal) -> RuleM CoreExpr -rightIdentityDynFlags id_lit = do - dflags <- getDynFlags - [e1, Lit l2] <- getArgs - guard $ l2 == id_lit dflags - return e1 - -identityDynFlags :: (DynFlags -> Literal) -> RuleM CoreExpr -identityDynFlags lit = leftIdentityDynFlags lit `mplus` rightIdentityDynFlags lit - -leftZero :: (DynFlags -> Literal) -> RuleM CoreExpr -leftZero zero = do - dflags <- getDynFlags - [Lit l1, _] <- getArgs - guard $ l1 == zero dflags - return $ Lit l1 - -rightZero :: (DynFlags -> Literal) -> RuleM CoreExpr -rightZero zero = do - dflags <- getDynFlags - [_, Lit l2] <- getArgs - guard $ l2 == zero dflags - return $ Lit l2 - -zeroElem :: (DynFlags -> Literal) -> RuleM CoreExpr -zeroElem lit = leftZero lit `mplus` rightZero lit - -equalArgs :: RuleM () -equalArgs = do - [e1, e2] <- getArgs - guard $ e1 `cheapEqExpr` e2 - -nonZeroLit :: Int -> RuleM () -nonZeroLit n = getLiteral n >>= guard . not . isZeroLit - --- 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 :: DynFlags -> Literal -> Literal -convFloating dflags (MachFloat f) | not (gopt Opt_ExcessPrecision dflags) = - MachFloat (toRational (fromRational f :: Float )) -convFloating dflags (MachDouble d) | not (gopt Opt_ExcessPrecision dflags) = - MachDouble (toRational (fromRational d :: Double)) -convFloating _ l = l - -guardFloatDiv :: RuleM () -guardFloatDiv = do - [Lit (MachFloat f1), Lit (MachFloat f2)] <- getArgs - guard $ (f1 /=0 || f2 > 0) -- see Note [negative zero] - && f2 /= 0 -- avoid NaN and Infinity/-Infinity - -guardDoubleDiv :: RuleM () -guardDoubleDiv = do - [Lit (MachDouble d1), Lit (MachDouble d2)] <- getArgs - guard $ (d1 /=0 || d2 > 0) -- see Note [negative zero] - && d2 /= 0 -- avoid NaN and Infinity/-Infinity --- Note [negative zero] Avoid (0 / -d), otherwise 0/(-1) reduces to --- zero, but we might want to preserve the negative zero here which --- is representable in Float/Double but not in (normalised) --- Rational. (#3676) Perhaps we should generate (0 :% (-1)) instead? - -strengthReduction :: Literal -> PrimOp -> RuleM CoreExpr -strengthReduction two_lit add_op = do -- Note [Strength reduction] - arg <- msum [ do [arg, Lit mult_lit] <- getArgs - guard (mult_lit == two_lit) - return arg - , do [Lit mult_lit, arg] <- getArgs - guard (mult_lit == two_lit) - return arg ] - return $ Var (mkPrimOpId add_op) `App` arg `App` arg - --- Note [Strength reduction] --- ~~~~~~~~~~~~~~~~~~~~~~~~~ --- --- This rule turns floating point multiplications of the form 2.0 * x and --- x * 2.0 into x + x addition, because addition costs less than multiplication. --- See #7116 - --- Note [What's true and false] --- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --- --- trueValInt and falseValInt represent true and false values returned by --- comparison primops for Char, Int, Word, Integer, Double, Float and Addr. --- True is represented as an unboxed 1# literal, while false is represented --- as 0# literal. --- We still need Bool data constructors (True and False) to use in a rule --- for constant folding of equal Strings - -trueValInt, falseValInt :: DynFlags -> Expr CoreBndr -trueValInt dflags = Lit $ onei dflags -- see Note [What's true and false] -falseValInt dflags = Lit $ zeroi dflags - -trueValBool, falseValBool :: Expr CoreBndr -trueValBool = Var trueDataConId -- see Note [What's true and false] -falseValBool = Var falseDataConId - -ltVal, eqVal, gtVal :: Expr CoreBndr -ltVal = Var ltDataConId -eqVal = Var eqDataConId -gtVal = Var gtDataConId - -mkIntVal :: DynFlags -> Integer -> Expr CoreBndr -mkIntVal dflags i = Lit (mkMachInt dflags i) -mkWordVal :: DynFlags -> Integer -> Expr CoreBndr -mkWordVal dflags w = Lit (mkMachWord dflags w) -mkFloatVal :: DynFlags -> Rational -> Expr CoreBndr -mkFloatVal dflags f = Lit (convFloating dflags (MachFloat f)) -mkDoubleVal :: DynFlags -> Rational -> Expr CoreBndr -mkDoubleVal dflags d = Lit (convFloating dflags (MachDouble d)) - -matchPrimOpId :: PrimOp -> Id -> RuleM () -matchPrimOpId op id = do - op' <- liftMaybe $ isPrimOpId_maybe id - guard $ op == op' - -\end{code} - -%************************************************************************ -%* * -\subsection{Special rules for seq, tagToEnum, dataToTag} -%* * -%************************************************************************ - -Note [tagToEnum#] -~~~~~~~~~~~~~~~~~ -Nasty check to ensure that tagToEnum# is applied to a type that is an -enumeration TyCon. Unification may refine the type later, but this -check won't see that, alas. It's crude but it works. - -Here's are two cases that should fail - f :: forall a. a - f = tagToEnum# 0 -- Can't do tagToEnum# at a type variable - - g :: Int - g = tagToEnum# 0 -- Int is not an enumeration - -We used to make this check in the type inference engine, but it's quite -ugly to do so, because the delayed constraint solving means that we don't -really know what's going on until the end. It's very much a corner case -because we don't expect the user to call tagToEnum# at all; we merely -generate calls in derived instances of Enum. So we compromise: a -rewrite rule rewrites a bad instance of tagToEnum# to an error call, -and emits a warning. - -\begin{code} -tagToEnumRule :: RuleM CoreExpr --- If data T a = A | B | C --- then tag2Enum# (T ty) 2# --> B ty -tagToEnumRule = do - [Type ty, Lit (MachInt i)] <- getArgs - case splitTyConApp_maybe ty of - Just (tycon, tc_args) | isEnumerationTyCon tycon -> do - let tag = fromInteger i - correct_tag dc = (dataConTag dc - fIRST_TAG) == tag - (dc:rest) <- return $ filter correct_tag (tyConDataCons_maybe tycon `orElse` []) - ASSERT(null rest) return () - return $ mkTyApps (Var (dataConWorkId dc)) tc_args - - -- See Note [tagToEnum#] - _ -> WARN( True, ptext (sLit "tagToEnum# on non-enumeration type") <+> ppr ty ) - return $ mkRuntimeErrorApp rUNTIME_ERROR_ID ty "tagToEnum# on non-enumeration type" -\end{code} - - -For dataToTag#, we can reduce if either - - (a) the argument is a constructor - (b) the argument is a variable whose unfolding is a known constructor - -\begin{code} -dataToTagRule :: RuleM CoreExpr -dataToTagRule = a `mplus` b - where - a = do - [Type ty1, Var tag_to_enum `App` Type ty2 `App` tag] <- getArgs - guard $ tag_to_enum `hasKey` tagToEnumKey - guard $ ty1 `eqType` ty2 - return tag -- dataToTag (tagToEnum x) ==> x - b = do - dflags <- getDynFlags - [_, val_arg] <- getArgs - in_scope <- getInScopeEnv - (dc,_,_) <- liftMaybe $ exprIsConApp_maybe in_scope val_arg - ASSERT( not (isNewTyCon (dataConTyCon dc)) ) return () - return $ mkIntVal dflags (toInteger (dataConTag dc - fIRST_TAG)) -\end{code} - -%************************************************************************ -%* * -\subsection{Rules for seq# and spark#} -%* * -%************************************************************************ - -\begin{code} --- seq# :: forall a s . a -> State# s -> (# State# s, a #) -seqRule :: RuleM CoreExpr -seqRule = do - [ty_a, Type ty_s, a, s] <- getArgs - guard $ exprIsHNF a - return $ mkConApp (tupleCon UnboxedTuple 2) - [Type (mkStatePrimTy ty_s), ty_a, s, a] - --- spark# :: forall a s . a -> State# s -> (# State# s, a #) -sparkRule :: RuleM CoreExpr -sparkRule = seqRule -- reduce on HNF, just the same - -- XXX perhaps we shouldn't do this, because a spark eliminated by - -- this rule won't be counted as a dud at runtime? -\end{code} - -%************************************************************************ -%* * -\subsection{Built in rules} -%* * -%************************************************************************ - -Note [Scoping for Builtin rules] -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -When compiling a (base-package) module that defines one of the -functions mentioned in the RHS of a built-in rule, there's a danger -that we'll see - - f = ...(eq String x).... - - ....and lower down... - - eqString = ... - -Then a rewrite would give - - f = ...(eqString x)... - ....and lower down... - eqString = ... - -and lo, eqString is not in scope. This only really matters when we get to code -generation. With -O we do a GlomBinds step that does a new SCC analysis on the whole -set of bindings, which sorts out the dependency. Without -O we don't do any rule -rewriting so again we are fine. - -(This whole thing doesn't show up for non-built-in rules because their dependencies -are explicit.) - - -\begin{code} -builtinRules :: [CoreRule] --- Rules for non-primops that can't be expressed using a RULE pragma -builtinRules - = [BuiltinRule { ru_name = fsLit "AppendLitString", - ru_fn = unpackCStringFoldrName, - ru_nargs = 4, ru_try = \_ _ _ -> match_append_lit }, - BuiltinRule { ru_name = fsLit "EqString", ru_fn = eqStringName, - ru_nargs = 2, ru_try = \dflags _ _ -> match_eq_string dflags }, - BuiltinRule { ru_name = fsLit "Inline", ru_fn = inlineIdName, - ru_nargs = 2, ru_try = \_ _ _ -> match_inline }, - BuiltinRule { ru_name = fsLit "MagicDict", ru_fn = idName magicDictId, - ru_nargs = 4, ru_try = \_ _ _ -> match_magicDict } - ] - ++ builtinIntegerRules - -builtinIntegerRules :: [CoreRule] -builtinIntegerRules = - [rule_IntToInteger "smallInteger" smallIntegerName, - rule_WordToInteger "wordToInteger" wordToIntegerName, - rule_Int64ToInteger "int64ToInteger" int64ToIntegerName, - rule_Word64ToInteger "word64ToInteger" word64ToIntegerName, - rule_convert "integerToWord" integerToWordName mkWordLitWord, - rule_convert "integerToInt" integerToIntName mkIntLitInt, - rule_convert "integerToWord64" integerToWord64Name (\_ -> mkWord64LitWord64), - rule_convert "integerToInt64" integerToInt64Name (\_ -> mkInt64LitInt64), - rule_binop "plusInteger" plusIntegerName (+), - rule_binop "minusInteger" minusIntegerName (-), - rule_binop "timesInteger" timesIntegerName (*), - rule_unop "negateInteger" negateIntegerName negate, - rule_binop_Prim "eqInteger#" eqIntegerPrimName (==), - rule_binop_Prim "neqInteger#" neqIntegerPrimName (/=), - rule_unop "absInteger" absIntegerName abs, - rule_unop "signumInteger" signumIntegerName signum, - rule_binop_Prim "leInteger#" leIntegerPrimName (<=), - rule_binop_Prim "gtInteger#" gtIntegerPrimName (>), - rule_binop_Prim "ltInteger#" ltIntegerPrimName (<), - rule_binop_Prim "geInteger#" geIntegerPrimName (>=), - rule_binop_Ordering "compareInteger" compareIntegerName compare, - rule_encodeFloat "encodeFloatInteger" encodeFloatIntegerName mkFloatLitFloat, - rule_convert "floatFromInteger" floatFromIntegerName (\_ -> mkFloatLitFloat), - rule_encodeFloat "encodeDoubleInteger" encodeDoubleIntegerName mkDoubleLitDouble, - rule_decodeDouble "decodeDoubleInteger" decodeDoubleIntegerName, - rule_convert "doubleFromInteger" doubleFromIntegerName (\_ -> mkDoubleLitDouble), - rule_rationalTo "rationalToFloat" rationalToFloatName mkFloatExpr, - rule_rationalTo "rationalToDouble" rationalToDoubleName mkDoubleExpr, - rule_binop "gcdInteger" gcdIntegerName gcd, - rule_binop "lcmInteger" lcmIntegerName lcm, - rule_binop "andInteger" andIntegerName (.&.), - rule_binop "orInteger" orIntegerName (.|.), - rule_binop "xorInteger" xorIntegerName xor, - rule_unop "complementInteger" complementIntegerName complement, - rule_Int_binop "shiftLInteger" shiftLIntegerName shiftL, - rule_Int_binop "shiftRInteger" shiftRIntegerName shiftR, - -- See Note [Integer division constant folding] in libraries/base/GHC/Real.lhs - rule_divop_one "quotInteger" quotIntegerName quot, - rule_divop_one "remInteger" remIntegerName rem, - rule_divop_one "divInteger" divIntegerName div, - rule_divop_one "modInteger" modIntegerName mod, - rule_divop_both "divModInteger" divModIntegerName divMod, - rule_divop_both "quotRemInteger" quotRemIntegerName quotRem, - -- These rules below don't actually have to be built in, but if we - -- put them in the Haskell source then we'd have to duplicate them - -- between all Integer implementations - rule_XToIntegerToX "smallIntegerToInt" integerToIntName smallIntegerName, - rule_XToIntegerToX "wordToIntegerToWord" integerToWordName wordToIntegerName, - rule_XToIntegerToX "int64ToIntegerToInt64" integerToInt64Name int64ToIntegerName, - rule_XToIntegerToX "word64ToIntegerToWord64" integerToWord64Name word64ToIntegerName, - rule_smallIntegerTo "smallIntegerToWord" integerToWordName Int2WordOp, - rule_smallIntegerTo "smallIntegerToFloat" floatFromIntegerName Int2FloatOp, - rule_smallIntegerTo "smallIntegerToDouble" doubleFromIntegerName Int2DoubleOp - ] - where rule_convert str name convert - = BuiltinRule { ru_name = fsLit str, ru_fn = name, ru_nargs = 1, - ru_try = match_Integer_convert convert } - rule_IntToInteger str name - = BuiltinRule { ru_name = fsLit str, ru_fn = name, ru_nargs = 1, - ru_try = match_IntToInteger } - rule_WordToInteger str name - = BuiltinRule { ru_name = fsLit str, ru_fn = name, ru_nargs = 1, - ru_try = match_WordToInteger } - rule_Int64ToInteger str name - = BuiltinRule { ru_name = fsLit str, ru_fn = name, ru_nargs = 1, - ru_try = match_Int64ToInteger } - rule_Word64ToInteger str name - = BuiltinRule { ru_name = fsLit str, ru_fn = name, ru_nargs = 1, - ru_try = match_Word64ToInteger } - rule_unop str name op - = BuiltinRule { ru_name = fsLit str, ru_fn = name, ru_nargs = 1, - ru_try = match_Integer_unop op } - rule_binop str name op - = BuiltinRule { ru_name = fsLit str, ru_fn = name, ru_nargs = 2, - ru_try = match_Integer_binop op } - rule_divop_both str name op - = BuiltinRule { ru_name = fsLit str, ru_fn = name, ru_nargs = 2, - ru_try = match_Integer_divop_both op } - rule_divop_one str name op - = BuiltinRule { ru_name = fsLit str, ru_fn = name, ru_nargs = 2, - ru_try = match_Integer_divop_one op } - rule_Int_binop str name op - = BuiltinRule { ru_name = fsLit str, ru_fn = name, ru_nargs = 2, - ru_try = match_Integer_Int_binop op } - rule_binop_Prim str name op - = BuiltinRule { ru_name = fsLit str, ru_fn = name, ru_nargs = 2, - ru_try = match_Integer_binop_Prim op } - rule_binop_Ordering str name op - = BuiltinRule { ru_name = fsLit str, ru_fn = name, ru_nargs = 2, - ru_try = match_Integer_binop_Ordering op } - rule_encodeFloat str name op - = BuiltinRule { ru_name = fsLit str, ru_fn = name, ru_nargs = 2, - ru_try = match_Integer_Int_encodeFloat op } - rule_decodeDouble str name - = BuiltinRule { ru_name = fsLit str, ru_fn = name, ru_nargs = 1, - ru_try = match_decodeDouble } - rule_XToIntegerToX str name toIntegerName - = BuiltinRule { ru_name = fsLit str, ru_fn = name, ru_nargs = 1, - ru_try = match_XToIntegerToX toIntegerName } - rule_smallIntegerTo str name primOp - = BuiltinRule { ru_name = fsLit str, ru_fn = name, ru_nargs = 1, - ru_try = match_smallIntegerTo primOp } - rule_rationalTo str name mkLit - = BuiltinRule { ru_name = fsLit str, ru_fn = name, ru_nargs = 2, - ru_try = match_rationalTo mkLit } - ---------------------------------------------------- --- The rule is this: --- unpackFoldrCString# "foo" c (unpackFoldrCString# "baz" c n) --- = unpackFoldrCString# "foobaz" c n - -match_append_lit :: [Expr CoreBndr] -> Maybe (Expr CoreBndr) -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 `eqType` ty2 ) - Just (Var unpk `App` Type ty1 - `App` Lit (MachStr (s1 `BS.append` s2)) - `App` c1 - `App` n) - -match_append_lit _ = Nothing - ---------------------------------------------------- --- The rule is this: --- eqString (unpackCString# (Lit s1)) (unpackCString# (Lit s2) = s1==s2 - -match_eq_string :: DynFlags -> [Expr CoreBndr] -> Maybe (Expr CoreBndr) -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 trueValBool else falseValBool) - -match_eq_string _ _ = Nothing - - ---------------------------------------------------- --- The rule is this: --- inline f_ty (f a b c) = <f's unfolding> a b c --- (if f has an unfolding, EVEN if it's a loop breaker) --- --- It's important to allow the argument to 'inline' to have args itself --- (a) because its more forgiving to allow the programmer to write --- inline f a b c --- or inline (f a b c) --- (b) because a polymorphic f wll get a type argument that the --- programmer can't avoid --- --- Also, don't forget about 'inline's type argument! -match_inline :: [Expr CoreBndr] -> Maybe (Expr CoreBndr) -match_inline (Type _ : e : _) - | (Var f, args1) <- collectArgs e, - Just unf <- maybeUnfoldingTemplate (realIdUnfolding f) - -- Ignore the IdUnfoldingFun here! - = Just (mkApps unf args1) - -match_inline _ = Nothing - - --- See Note [magicDictId magic] in `basicTypes/MkId.lhs` --- for a description of what is going on here. -match_magicDict :: [Expr CoreBndr] -> Maybe (Expr CoreBndr) -match_magicDict [Type _, Var wrap `App` Type a `App` Type _ `App` f, x, y ] - | Just (fieldTy, _) <- splitFunTy_maybe $ dropForAlls $ idType wrap - , Just (dictTy, _) <- splitFunTy_maybe fieldTy - , Just dictTc <- tyConAppTyCon_maybe dictTy - , Just (_,_,co) <- unwrapNewTyCon_maybe dictTc - = Just - $ f `App` Cast x (mkSymCo (mkUnbranchedAxInstCo Representational co [a])) - `App` y - -match_magicDict _ = Nothing - -------------------------------------------------- --- Integer rules --- smallInteger (79::Int#) = 79::Integer --- wordToInteger (79::Word#) = 79::Integer --- Similarly Int64, Word64 - -match_IntToInteger :: RuleFun -match_IntToInteger _ id_unf fn [xl] - | Just (MachInt x) <- exprIsLiteral_maybe id_unf xl - = case idType fn of - FunTy _ integerTy -> - Just (Lit (LitInteger x integerTy)) - _ -> - panic "match_IntToInteger: Id has the wrong type" -match_IntToInteger _ _ _ _ = Nothing - -match_WordToInteger :: RuleFun -match_WordToInteger _ id_unf id [xl] - | Just (MachWord x) <- exprIsLiteral_maybe id_unf xl - = case idType id of - FunTy _ integerTy -> - Just (Lit (LitInteger x integerTy)) - _ -> - panic "match_WordToInteger: Id has the wrong type" -match_WordToInteger _ _ _ _ = Nothing - -match_Int64ToInteger :: RuleFun -match_Int64ToInteger _ id_unf id [xl] - | Just (MachInt64 x) <- exprIsLiteral_maybe id_unf xl - = case idType id of - FunTy _ integerTy -> - Just (Lit (LitInteger x integerTy)) - _ -> - panic "match_Int64ToInteger: Id has the wrong type" -match_Int64ToInteger _ _ _ _ = Nothing - -match_Word64ToInteger :: RuleFun -match_Word64ToInteger _ id_unf id [xl] - | Just (MachWord64 x) <- exprIsLiteral_maybe id_unf xl - = case idType id of - FunTy _ integerTy -> - Just (Lit (LitInteger x integerTy)) - _ -> - panic "match_Word64ToInteger: Id has the wrong type" -match_Word64ToInteger _ _ _ _ = Nothing - -------------------------------------------------- -match_Integer_convert :: Num a - => (DynFlags -> a -> Expr CoreBndr) - -> RuleFun -match_Integer_convert convert dflags id_unf _ [xl] - | Just (LitInteger x _) <- exprIsLiteral_maybe id_unf xl - = Just (convert dflags (fromInteger x)) -match_Integer_convert _ _ _ _ _ = Nothing - -match_Integer_unop :: (Integer -> Integer) -> RuleFun -match_Integer_unop unop _ id_unf _ [xl] - | Just (LitInteger x i) <- exprIsLiteral_maybe id_unf xl - = Just (Lit (LitInteger (unop x) i)) -match_Integer_unop _ _ _ _ _ = Nothing - -match_Integer_binop :: (Integer -> Integer -> Integer) -> RuleFun -match_Integer_binop binop _ id_unf _ [xl,yl] - | Just (LitInteger x i) <- exprIsLiteral_maybe id_unf xl - , Just (LitInteger y _) <- exprIsLiteral_maybe id_unf yl - = Just (Lit (LitInteger (x `binop` y) i)) -match_Integer_binop _ _ _ _ _ = Nothing - --- This helper is used for the quotRem and divMod functions -match_Integer_divop_both - :: (Integer -> Integer -> (Integer, Integer)) -> RuleFun -match_Integer_divop_both divop _ id_unf _ [xl,yl] - | Just (LitInteger x t) <- exprIsLiteral_maybe id_unf xl - , Just (LitInteger y _) <- exprIsLiteral_maybe id_unf yl - , y /= 0 - , (r,s) <- x `divop` y - = Just $ mkConApp (tupleCon UnboxedTuple 2) - [Type t, - Type t, - Lit (LitInteger r t), - Lit (LitInteger s t)] -match_Integer_divop_both _ _ _ _ _ = Nothing - --- This helper is used for the quot and rem functions -match_Integer_divop_one :: (Integer -> Integer -> Integer) -> RuleFun -match_Integer_divop_one divop _ id_unf _ [xl,yl] - | Just (LitInteger x i) <- exprIsLiteral_maybe id_unf xl - , Just (LitInteger y _) <- exprIsLiteral_maybe id_unf yl - , y /= 0 - = Just (Lit (LitInteger (x `divop` y) i)) -match_Integer_divop_one _ _ _ _ _ = Nothing - -match_Integer_Int_binop :: (Integer -> Int -> Integer) -> RuleFun -match_Integer_Int_binop binop _ id_unf _ [xl,yl] - | Just (LitInteger x i) <- exprIsLiteral_maybe id_unf xl - , Just (MachInt y) <- exprIsLiteral_maybe id_unf yl - = Just (Lit (LitInteger (x `binop` fromIntegral y) i)) -match_Integer_Int_binop _ _ _ _ _ = Nothing - -match_Integer_binop_Prim :: (Integer -> Integer -> Bool) -> RuleFun -match_Integer_binop_Prim binop dflags id_unf _ [xl, yl] - | Just (LitInteger x _) <- exprIsLiteral_maybe id_unf xl - , Just (LitInteger y _) <- exprIsLiteral_maybe id_unf yl - = Just (if x `binop` y then trueValInt dflags else falseValInt dflags) -match_Integer_binop_Prim _ _ _ _ _ = Nothing - -match_Integer_binop_Ordering :: (Integer -> Integer -> Ordering) -> RuleFun -match_Integer_binop_Ordering binop _ id_unf _ [xl, yl] - | Just (LitInteger x _) <- exprIsLiteral_maybe id_unf xl - , Just (LitInteger y _) <- exprIsLiteral_maybe id_unf yl - = Just $ case x `binop` y of - LT -> ltVal - EQ -> eqVal - GT -> gtVal -match_Integer_binop_Ordering _ _ _ _ _ = Nothing - -match_Integer_Int_encodeFloat :: RealFloat a - => (a -> Expr CoreBndr) - -> RuleFun -match_Integer_Int_encodeFloat mkLit _ id_unf _ [xl,yl] - | Just (LitInteger x _) <- exprIsLiteral_maybe id_unf xl - , Just (MachInt y) <- exprIsLiteral_maybe id_unf yl - = Just (mkLit $ encodeFloat x (fromInteger y)) -match_Integer_Int_encodeFloat _ _ _ _ _ = Nothing - ---------------------------------------------------- --- constant folding for Float/Double --- --- This turns --- rationalToFloat n d --- into a literal Float, and similarly for Doubles. --- --- it's important to not match d == 0, because that may represent a --- literal "0/0" or similar, and we can't produce a literal value for --- NaN or +-Inf -match_rationalTo :: RealFloat a - => (a -> Expr CoreBndr) - -> RuleFun -match_rationalTo mkLit _ id_unf _ [xl, yl] - | Just (LitInteger x _) <- exprIsLiteral_maybe id_unf xl - , Just (LitInteger y _) <- exprIsLiteral_maybe id_unf yl - , y /= 0 - = Just (mkLit (fromRational (x % y))) -match_rationalTo _ _ _ _ _ = Nothing - -match_decodeDouble :: RuleFun -match_decodeDouble _ id_unf fn [xl] - | Just (MachDouble x) <- exprIsLiteral_maybe id_unf xl - = case idType fn of - FunTy _ (TyConApp _ [integerTy, intHashTy]) -> - case decodeFloat (fromRational x :: Double) of - (y, z) -> - Just $ mkConApp (tupleCon UnboxedTuple 2) - [Type integerTy, - Type intHashTy, - Lit (LitInteger y integerTy), - Lit (MachInt (toInteger z))] - _ -> - panic "match_decodeDouble: Id has the wrong type" -match_decodeDouble _ _ _ _ = Nothing - -match_XToIntegerToX :: Name -> RuleFun -match_XToIntegerToX n _ _ _ [App (Var x) y] - | idName x == n - = Just y -match_XToIntegerToX _ _ _ _ _ = Nothing - -match_smallIntegerTo :: PrimOp -> RuleFun -match_smallIntegerTo primOp _ _ _ [App (Var x) y] - | idName x == smallIntegerName - = Just $ App (Var (mkPrimOpId primOp)) y -match_smallIntegerTo _ _ _ _ _ = Nothing -\end{code} |