module GHC.Core.Opt.ConstantFold
( primOpRules
, builtinRules
, caseRules
, EnableBignumRules (..)
)
where
#include "HsVersions.h"
import GHC.Prelude
import GHC.Types.Id.Make ( mkPrimOpId, magicDictId )
import GHC.Core
import GHC.Core.Make
import GHC.Types.Id
import GHC.Types.Literal
import GHC.Core.SimpleOpt ( exprIsLiteral_maybe )
import GHC.Builtin.PrimOps ( PrimOp(..), tagToEnumKey )
import GHC.Builtin.Types
import GHC.Builtin.Types.Prim
import GHC.Core.TyCon
( tyConDataCons_maybe, isAlgTyCon, isEnumerationTyCon
, isNewTyCon, unwrapNewTyCon_maybe, tyConDataCons
, tyConFamilySize )
import GHC.Core.DataCon ( dataConTagZ, dataConTyCon, dataConWrapId, dataConWorkId )
import GHC.Core.Utils ( eqExpr, cheapEqExpr, exprIsHNF, exprType
, stripTicksTop, stripTicksTopT, mkTicks )
import GHC.Core.Unfold ( exprIsConApp_maybe )
import GHC.Core.Multiplicity
import GHC.Core.FVs
import GHC.Core.Type
import GHC.Types.Var.Set
import GHC.Types.Var.Env
import GHC.Types.Name.Occurrence ( occNameFS )
import GHC.Builtin.Names
import GHC.Data.Maybe ( orElse )
import GHC.Types.Name ( Name, nameOccName )
import GHC.Utils.Outputable
import GHC.Data.FastString
import GHC.Types.Basic
import GHC.Platform
import GHC.Utils.Misc
import GHC.Core.Coercion (mkUnbranchedAxInstCo,mkSymCo,Role(..))
import Control.Applicative ( Alternative(..) )
import Control.Monad
import Data.Bits as Bits
import qualified Data.ByteString as BS
import Data.Int
import Data.Ratio
import Data.Word
import Data.Maybe (fromMaybe)
primOpRules :: Name -> PrimOp -> Maybe CoreRule
primOpRules nm = \case
TagToEnumOp -> mkPrimOpRule nm 2 [ tagToEnumRule ]
DataToTagOp -> mkPrimOpRule nm 2 [ dataToTagRule ]
IntAddOp -> mkPrimOpRule nm 2 [ binaryLit (intOp2 (+))
, identityPlatform zeroi
, numFoldingRules IntAddOp intPrimOps
]
IntSubOp -> mkPrimOpRule nm 2 [ binaryLit (intOp2 ())
, rightIdentityPlatform zeroi
, equalArgs >> retLit zeroi
, numFoldingRules IntSubOp intPrimOps
]
IntAddCOp -> mkPrimOpRule nm 2 [ binaryLit (intOpC2 (+))
, identityCPlatform zeroi ]
IntSubCOp -> mkPrimOpRule nm 2 [ binaryLit (intOpC2 ())
, rightIdentityCPlatform zeroi
, equalArgs >> retLitNoC zeroi ]
IntMulOp -> mkPrimOpRule nm 2 [ binaryLit (intOp2 (*))
, zeroElem zeroi
, identityPlatform onei
, numFoldingRules IntMulOp intPrimOps
]
IntQuotOp -> mkPrimOpRule nm 2 [ nonZeroLit 1 >> binaryLit (intOp2 quot)
, leftZero zeroi
, rightIdentityPlatform onei
, equalArgs >> retLit onei ]
IntRemOp -> mkPrimOpRule nm 2 [ nonZeroLit 1 >> binaryLit (intOp2 rem)
, leftZero zeroi
, do l <- getLiteral 1
platform <- getPlatform
guard (l == onei platform)
retLit zeroi
, equalArgs >> retLit zeroi
, equalArgs >> retLit zeroi ]
AndIOp -> mkPrimOpRule nm 2 [ binaryLit (intOp2 (.&.))
, idempotent
, zeroElem zeroi ]
OrIOp -> mkPrimOpRule nm 2 [ binaryLit (intOp2 (.|.))
, idempotent
, identityPlatform zeroi ]
XorIOp -> mkPrimOpRule nm 2 [ binaryLit (intOp2 xor)
, identityPlatform zeroi
, equalArgs >> retLit zeroi ]
NotIOp -> mkPrimOpRule nm 1 [ unaryLit complementOp
, inversePrimOp NotIOp ]
IntNegOp -> mkPrimOpRule nm 1 [ unaryLit negOp
, inversePrimOp IntNegOp ]
ISllOp -> mkPrimOpRule nm 2 [ shiftRule LitNumInt (const Bits.shiftL)
, rightIdentityPlatform zeroi ]
ISraOp -> mkPrimOpRule nm 2 [ shiftRule LitNumInt (const Bits.shiftR)
, rightIdentityPlatform zeroi ]
ISrlOp -> mkPrimOpRule nm 2 [ shiftRule LitNumInt shiftRightLogical
, rightIdentityPlatform zeroi ]
WordAddOp -> mkPrimOpRule nm 2 [ binaryLit (wordOp2 (+))
, identityPlatform zerow
, numFoldingRules WordAddOp wordPrimOps
]
WordSubOp -> mkPrimOpRule nm 2 [ binaryLit (wordOp2 ())
, rightIdentityPlatform zerow
, equalArgs >> retLit zerow
, numFoldingRules WordSubOp wordPrimOps
]
WordAddCOp -> mkPrimOpRule nm 2 [ binaryLit (wordOpC2 (+))
, identityCPlatform zerow ]
WordSubCOp -> mkPrimOpRule nm 2 [ binaryLit (wordOpC2 ())
, rightIdentityCPlatform zerow
, equalArgs >> retLitNoC zerow ]
WordMulOp -> mkPrimOpRule nm 2 [ binaryLit (wordOp2 (*))
, identityPlatform onew
, numFoldingRules WordMulOp wordPrimOps
]
WordQuotOp -> mkPrimOpRule nm 2 [ nonZeroLit 1 >> binaryLit (wordOp2 quot)
, rightIdentityPlatform onew ]
WordRemOp -> mkPrimOpRule nm 2 [ nonZeroLit 1 >> binaryLit (wordOp2 rem)
, leftZero zerow
, do l <- getLiteral 1
platform <- getPlatform
guard (l == onew platform)
retLit zerow
, equalArgs >> retLit zerow ]
AndOp -> mkPrimOpRule nm 2 [ binaryLit (wordOp2 (.&.))
, idempotent
, zeroElem zerow ]
OrOp -> mkPrimOpRule nm 2 [ binaryLit (wordOp2 (.|.))
, idempotent
, identityPlatform zerow ]
XorOp -> mkPrimOpRule nm 2 [ binaryLit (wordOp2 xor)
, identityPlatform zerow
, equalArgs >> retLit zerow ]
NotOp -> mkPrimOpRule nm 1 [ unaryLit complementOp
, inversePrimOp NotOp ]
SllOp -> mkPrimOpRule nm 2 [ shiftRule LitNumWord (const Bits.shiftL) ]
SrlOp -> mkPrimOpRule nm 2 [ shiftRule LitNumWord shiftRightLogical ]
Word2IntOp -> mkPrimOpRule nm 1 [ liftLitPlatform word2IntLit
, inversePrimOp Int2WordOp ]
Int2WordOp -> mkPrimOpRule nm 1 [ liftLitPlatform int2WordLit
, inversePrimOp Word2IntOp ]
Narrow8IntOp -> mkPrimOpRule nm 1 [ liftLit narrow8IntLit
, subsumedByPrimOp Narrow8IntOp
, Narrow8IntOp `subsumesPrimOp` Narrow16IntOp
, Narrow8IntOp `subsumesPrimOp` Narrow32IntOp
, narrowSubsumesAnd AndIOp Narrow8IntOp 8 ]
Narrow16IntOp -> mkPrimOpRule nm 1 [ liftLit narrow16IntLit
, subsumedByPrimOp Narrow8IntOp
, subsumedByPrimOp Narrow16IntOp
, Narrow16IntOp `subsumesPrimOp` Narrow32IntOp
, narrowSubsumesAnd AndIOp Narrow16IntOp 16 ]
Narrow32IntOp -> mkPrimOpRule nm 1 [ liftLit narrow32IntLit
, subsumedByPrimOp Narrow8IntOp
, subsumedByPrimOp Narrow16IntOp
, subsumedByPrimOp Narrow32IntOp
, removeOp32
, narrowSubsumesAnd AndIOp Narrow32IntOp 32 ]
Narrow8WordOp -> mkPrimOpRule nm 1 [ liftLit narrow8WordLit
, subsumedByPrimOp Narrow8WordOp
, Narrow8WordOp `subsumesPrimOp` Narrow16WordOp
, Narrow8WordOp `subsumesPrimOp` Narrow32WordOp
, narrowSubsumesAnd AndOp Narrow8WordOp 8 ]
Narrow16WordOp -> mkPrimOpRule nm 1 [ liftLit narrow16WordLit
, subsumedByPrimOp Narrow8WordOp
, subsumedByPrimOp Narrow16WordOp
, Narrow16WordOp `subsumesPrimOp` Narrow32WordOp
, narrowSubsumesAnd AndOp Narrow16WordOp 16 ]
Narrow32WordOp -> mkPrimOpRule nm 1 [ liftLit narrow32WordLit
, subsumedByPrimOp Narrow8WordOp
, subsumedByPrimOp Narrow16WordOp
, subsumedByPrimOp Narrow32WordOp
, removeOp32
, narrowSubsumesAnd AndOp Narrow32WordOp 32 ]
OrdOp -> mkPrimOpRule nm 1 [ liftLit char2IntLit
, inversePrimOp ChrOp ]
ChrOp -> mkPrimOpRule nm 1 [ do [Lit lit] <- getArgs
guard (litFitsInChar lit)
liftLit int2CharLit
, inversePrimOp OrdOp ]
Float2IntOp -> mkPrimOpRule nm 1 [ liftLit float2IntLit ]
Int2FloatOp -> mkPrimOpRule nm 1 [ liftLit int2FloatLit ]
Double2IntOp -> mkPrimOpRule nm 1 [ liftLit double2IntLit ]
Int2DoubleOp -> mkPrimOpRule nm 1 [ liftLit int2DoubleLit ]
Float2DoubleOp -> mkPrimOpRule nm 1 [ liftLit float2DoubleLit ]
Double2FloatOp -> mkPrimOpRule nm 1 [ liftLit double2FloatLit ]
FloatAddOp -> mkPrimOpRule nm 2 [ binaryLit (floatOp2 (+))
, identity zerof ]
FloatSubOp -> mkPrimOpRule nm 2 [ binaryLit (floatOp2 ())
, rightIdentity zerof ]
FloatMulOp -> mkPrimOpRule nm 2 [ binaryLit (floatOp2 (*))
, identity onef
, strengthReduction twof FloatAddOp ]
FloatDivOp -> mkPrimOpRule nm 2 [ guardFloatDiv >> binaryLit (floatOp2 (/))
, rightIdentity onef ]
FloatNegOp -> mkPrimOpRule nm 1 [ unaryLit negOp
, inversePrimOp FloatNegOp ]
DoubleAddOp -> mkPrimOpRule nm 2 [ binaryLit (doubleOp2 (+))
, identity zerod ]
DoubleSubOp -> mkPrimOpRule nm 2 [ binaryLit (doubleOp2 ())
, rightIdentity zerod ]
DoubleMulOp -> mkPrimOpRule nm 2 [ binaryLit (doubleOp2 (*))
, identity oned
, strengthReduction twod DoubleAddOp ]
DoubleDivOp -> mkPrimOpRule nm 2 [ guardDoubleDiv >> binaryLit (doubleOp2 (/))
, rightIdentity oned ]
DoubleNegOp -> mkPrimOpRule nm 1 [ unaryLit negOp
, inversePrimOp DoubleNegOp ]
IntEqOp -> mkRelOpRule nm (==) [ litEq True ]
IntNeOp -> mkRelOpRule nm (/=) [ litEq False ]
CharEqOp -> mkRelOpRule nm (==) [ litEq True ]
CharNeOp -> mkRelOpRule nm (/=) [ litEq False ]
IntGtOp -> mkRelOpRule nm (>) [ boundsCmp Gt ]
IntGeOp -> mkRelOpRule nm (>=) [ boundsCmp Ge ]
IntLeOp -> mkRelOpRule nm (<=) [ boundsCmp Le ]
IntLtOp -> mkRelOpRule nm (<) [ boundsCmp Lt ]
CharGtOp -> mkRelOpRule nm (>) [ boundsCmp Gt ]
CharGeOp -> mkRelOpRule nm (>=) [ boundsCmp Ge ]
CharLeOp -> mkRelOpRule nm (<=) [ boundsCmp Le ]
CharLtOp -> mkRelOpRule nm (<) [ boundsCmp Lt ]
FloatGtOp -> mkFloatingRelOpRule nm (>)
FloatGeOp -> mkFloatingRelOpRule nm (>=)
FloatLeOp -> mkFloatingRelOpRule nm (<=)
FloatLtOp -> mkFloatingRelOpRule nm (<)
FloatEqOp -> mkFloatingRelOpRule nm (==)
FloatNeOp -> mkFloatingRelOpRule nm (/=)
DoubleGtOp -> mkFloatingRelOpRule nm (>)
DoubleGeOp -> mkFloatingRelOpRule nm (>=)
DoubleLeOp -> mkFloatingRelOpRule nm (<=)
DoubleLtOp -> mkFloatingRelOpRule nm (<)
DoubleEqOp -> mkFloatingRelOpRule nm (==)
DoubleNeOp -> mkFloatingRelOpRule nm (/=)
WordGtOp -> mkRelOpRule nm (>) [ boundsCmp Gt ]
WordGeOp -> mkRelOpRule nm (>=) [ boundsCmp Ge ]
WordLeOp -> mkRelOpRule nm (<=) [ boundsCmp Le ]
WordLtOp -> mkRelOpRule nm (<) [ boundsCmp Lt ]
WordEqOp -> mkRelOpRule nm (==) [ litEq True ]
WordNeOp -> mkRelOpRule nm (/=) [ litEq False ]
AddrAddOp -> mkPrimOpRule nm 2 [ rightIdentityPlatform zeroi ]
SeqOp -> mkPrimOpRule nm 4 [ seqRule ]
SparkOp -> mkPrimOpRule nm 4 [ sparkRule ]
_ -> Nothing
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 $
binaryCmpLit cmp : equal_rule : extra
where
equal_rule = do { equalArgs
; platform <- getPlatform
; return (if cmp True True
then trueValInt platform
else falseValInt platform) }
mkFloatingRelOpRule :: Name -> (forall a . Ord a => a -> a -> Bool)
-> Maybe CoreRule
mkFloatingRelOpRule nm cmp
= mkPrimOpRule nm 2 [binaryCmpLit cmp]
zeroi, onei, zerow, onew :: Platform -> Literal
zeroi platform = mkLitInt platform 0
onei platform = mkLitInt platform 1
zerow platform = mkLitWord platform 0
onew platform = mkLitWord platform 1
zerof, onef, twof, zerod, oned, twod :: Literal
zerof = mkLitFloat 0.0
onef = mkLitFloat 1.0
twof = mkLitFloat 2.0
zerod = mkLitDouble 0.0
oned = mkLitDouble 1.0
twod = mkLitDouble 2.0
cmpOp :: Platform -> (forall a . Ord a => a -> a -> Bool)
-> Literal -> Literal -> Maybe CoreExpr
cmpOp platform cmp = go
where
done True = Just $ trueValInt platform
done False = Just $ falseValInt platform
go (LitChar i1) (LitChar i2) = done (i1 `cmp` i2)
go (LitFloat i1) (LitFloat i2) = done (i1 `cmp` i2)
go (LitDouble i1) (LitDouble i2) = done (i1 `cmp` i2)
go (LitNumber nt1 i1) (LitNumber nt2 i2)
| nt1 /= nt2 = Nothing
| otherwise = done (i1 `cmp` i2)
go _ _ = Nothing
negOp :: RuleOpts -> Literal -> Maybe CoreExpr
negOp env = \case
(LitFloat 0.0) -> Nothing
(LitFloat f) -> Just (mkFloatVal env (f))
(LitDouble 0.0) -> Nothing
(LitDouble d) -> Just (mkDoubleVal env (d))
(LitNumber nt i)
| litNumIsSigned nt -> Just (Lit (mkLitNumberWrap (roPlatform env) nt (i)))
_ -> Nothing
complementOp :: RuleOpts -> Literal -> Maybe CoreExpr
complementOp env (LitNumber nt i) =
Just (Lit (mkLitNumberWrap (roPlatform env) nt (complement i)))
complementOp _ _ = Nothing
intOp2 :: (Integral a, Integral b)
=> (a -> b -> Integer)
-> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
intOp2 = intOp2' . const
intOp2' :: (Integral a, Integral b)
=> (RuleOpts -> a -> b -> Integer)
-> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
intOp2' op env (LitNumber LitNumInt i1) (LitNumber LitNumInt i2) =
let o = op env
in intResult (roPlatform env) (fromInteger i1 `o` fromInteger i2)
intOp2' _ _ _ _ = Nothing
intOpC2 :: (Integral a, Integral b)
=> (a -> b -> Integer)
-> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
intOpC2 op env (LitNumber LitNumInt i1) (LitNumber LitNumInt i2) = do
intCResult (roPlatform env) (fromInteger i1 `op` fromInteger i2)
intOpC2 _ _ _ _ = Nothing
shiftRightLogical :: Platform -> Integer -> Int -> Integer
shiftRightLogical platform x n =
case platformWordSize platform of
PW4 -> fromIntegral (fromInteger x `shiftR` n :: Word32)
PW8 -> fromIntegral (fromInteger x `shiftR` n :: Word64)
retLit :: (Platform -> Literal) -> RuleM CoreExpr
retLit l = do platform <- getPlatform
return $ Lit $ l platform
retLitNoC :: (Platform -> Literal) -> RuleM CoreExpr
retLitNoC l = do platform <- getPlatform
let lit = l platform
let ty = literalType lit
return $ mkCoreUbxTup [ty, ty] [Lit lit, Lit (zeroi platform)]
wordOp2 :: (Integral a, Integral b)
=> (a -> b -> Integer)
-> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
wordOp2 op env (LitNumber LitNumWord w1) (LitNumber LitNumWord w2)
= wordResult (roPlatform env) (fromInteger w1 `op` fromInteger w2)
wordOp2 _ _ _ _ = Nothing
wordOpC2 :: (Integral a, Integral b)
=> (a -> b -> Integer)
-> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
wordOpC2 op env (LitNumber LitNumWord w1) (LitNumber LitNumWord w2) =
wordCResult (roPlatform env) (fromInteger w1 `op` fromInteger w2)
wordOpC2 _ _ _ _ = Nothing
shiftRule :: LitNumType
-> (Platform -> Integer -> Int -> Integer)
-> RuleM CoreExpr
shiftRule lit_num_ty shift_op
= do { platform <- getPlatform
; [e1, Lit (LitNumber LitNumInt shift_len)] <- getArgs
; case e1 of
_ | shift_len == 0
-> return e1
| shift_len < 0 || shift_len > toInteger (platformWordSizeInBits platform)
-> return $ Lit $ mkLitNumberWrap platform lit_num_ty 0
Lit (LitNumber nt x)
| 0 < shift_len
, shift_len <= toInteger (platformWordSizeInBits platform)
-> let op = shift_op platform
y = x `op` fromInteger shift_len
in liftMaybe $ Just (Lit (mkLitNumberWrap platform nt y))
_ -> mzero }
floatOp2 :: (Rational -> Rational -> Rational)
-> RuleOpts -> Literal -> Literal
-> Maybe (Expr CoreBndr)
floatOp2 op env (LitFloat f1) (LitFloat f2)
= Just (mkFloatVal env (f1 `op` f2))
floatOp2 _ _ _ _ = Nothing
doubleOp2 :: (Rational -> Rational -> Rational)
-> RuleOpts -> Literal -> Literal
-> Maybe (Expr CoreBndr)
doubleOp2 op env (LitDouble f1) (LitDouble f2)
= Just (mkDoubleVal env (f1 `op` f2))
doubleOp2 _ _ _ _ = Nothing
litEq :: Bool
-> RuleM CoreExpr
litEq is_eq = msum
[ do [Lit lit, expr] <- getArgs
platform <- getPlatform
do_lit_eq platform lit expr
, do [expr, Lit lit] <- getArgs
platform <- getPlatform
do_lit_eq platform lit expr ]
where
do_lit_eq platform lit expr = do
guard (not (litIsLifted lit))
return (mkWildCase expr (unrestricted $ literalType lit) intPrimTy
[(DEFAULT, [], val_if_neq),
(LitAlt lit, [], val_if_eq)])
where
val_if_eq | is_eq = trueValInt platform
| otherwise = falseValInt platform
val_if_neq | is_eq = falseValInt platform
| otherwise = trueValInt platform
boundsCmp :: Comparison -> RuleM CoreExpr
boundsCmp op = do
platform <- getPlatform
[a, b] <- getArgs
liftMaybe $ mkRuleFn platform op a b
data Comparison = Gt | Ge | Lt | Le
mkRuleFn :: Platform -> Comparison -> CoreExpr -> CoreExpr -> Maybe CoreExpr
mkRuleFn platform Gt (Lit lit) _ | isMinBound platform lit = Just $ falseValInt platform
mkRuleFn platform Le (Lit lit) _ | isMinBound platform lit = Just $ trueValInt platform
mkRuleFn platform Ge _ (Lit lit) | isMinBound platform lit = Just $ trueValInt platform
mkRuleFn platform Lt _ (Lit lit) | isMinBound platform lit = Just $ falseValInt platform
mkRuleFn platform Ge (Lit lit) _ | isMaxBound platform lit = Just $ trueValInt platform
mkRuleFn platform Lt (Lit lit) _ | isMaxBound platform lit = Just $ falseValInt platform
mkRuleFn platform Gt _ (Lit lit) | isMaxBound platform lit = Just $ falseValInt platform
mkRuleFn platform Le _ (Lit lit) | isMaxBound platform lit = Just $ trueValInt platform
mkRuleFn _ _ _ _ = Nothing
isMinBound :: Platform -> Literal -> Bool
isMinBound _ (LitChar c) = c == minBound
isMinBound platform (LitNumber nt i) = case nt of
LitNumInt -> i == platformMinInt platform
LitNumInt64 -> i == toInteger (minBound :: Int64)
LitNumWord -> i == 0
LitNumWord64 -> i == 0
LitNumNatural -> i == 0
LitNumInteger -> False
isMinBound _ _ = False
isMaxBound :: Platform -> Literal -> Bool
isMaxBound _ (LitChar c) = c == maxBound
isMaxBound platform (LitNumber nt i) = case nt of
LitNumInt -> i == platformMaxInt platform
LitNumInt64 -> i == toInteger (maxBound :: Int64)
LitNumWord -> i == platformMaxWord platform
LitNumWord64 -> i == toInteger (maxBound :: Word64)
LitNumNatural -> False
LitNumInteger -> False
isMaxBound _ _ = False
intResult :: Platform -> Integer -> Maybe CoreExpr
intResult platform result = Just (intResult' platform result)
intResult' :: Platform -> Integer -> CoreExpr
intResult' platform result = Lit (mkLitIntWrap platform result)
intCResult :: Platform -> Integer -> Maybe CoreExpr
intCResult platform result = Just (mkPair [Lit lit, Lit c])
where
mkPair = mkCoreUbxTup [intPrimTy, intPrimTy]
(lit, b) = mkLitIntWrapC platform result
c = if b then onei platform else zeroi platform
wordResult :: Platform -> Integer -> Maybe CoreExpr
wordResult platform result = Just (wordResult' platform result)
wordResult' :: Platform -> Integer -> CoreExpr
wordResult' platform result = Lit (mkLitWordWrap platform result)
wordCResult :: Platform -> Integer -> Maybe CoreExpr
wordCResult platform result = Just (mkPair [Lit lit, Lit c])
where
mkPair = mkCoreUbxTup [wordPrimTy, intPrimTy]
(lit, b) = mkLitWordWrapC platform result
c = if b then onei platform else zeroi platform
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
narrowSubsumesAnd :: PrimOp -> PrimOp -> Int -> RuleM CoreExpr
narrowSubsumesAnd and_primop narrw n = do
[Var primop_id `App` x `App` y] <- getArgs
matchPrimOpId and_primop primop_id
let mask = bit n 1
g v (Lit (LitNumber _ m)) = do
guard (m .&. mask == mask)
return (Var (mkPrimOpId narrw) `App` v)
g _ _ = mzero
g x y <|> g y x
idempotent :: RuleM CoreExpr
idempotent = do [e1, e2] <- getArgs
guard $ cheapEqExpr e1 e2
return e1
mkBasicRule :: Name -> Int -> RuleM CoreExpr -> CoreRule
mkBasicRule op_name n_args rm
= BuiltinRule { ru_name = occNameFS (nameOccName op_name),
ru_fn = op_name,
ru_nargs = n_args,
ru_try = runRuleM rm }
newtype RuleM r = RuleM
{ runRuleM :: RuleOpts -> InScopeEnv -> Id -> [CoreExpr] -> Maybe r }
deriving (Functor)
instance Applicative RuleM where
pure x = RuleM $ \_ _ _ _ -> Just x
(<*>) = ap
instance Monad RuleM where
RuleM f >>= g
= RuleM $ \env iu fn args ->
case f env iu fn args of
Nothing -> Nothing
Just r -> runRuleM (g r) env iu fn args
instance MonadFail RuleM where
fail _ = mzero
instance Alternative RuleM where
empty = RuleM $ \_ _ _ _ -> Nothing
RuleM f1 <|> RuleM f2 = RuleM $ \env iu fn args ->
f1 env iu fn args <|> f2 env iu fn args
instance MonadPlus RuleM
getPlatform :: RuleM Platform
getPlatform = roPlatform <$> getEnv
getEnv :: RuleM RuleOpts
getEnv = RuleM $ \env _ _ _ -> Just env
liftMaybe :: Maybe a -> RuleM a
liftMaybe Nothing = mzero
liftMaybe (Just x) = return x
liftLit :: (Literal -> Literal) -> RuleM CoreExpr
liftLit f = liftLitPlatform (const f)
liftLitPlatform :: (Platform -> Literal -> Literal) -> RuleM CoreExpr
liftLitPlatform f = do
platform <- getPlatform
[Lit lit] <- getArgs
return $ Lit (f platform lit)
removeOp32 :: RuleM CoreExpr
removeOp32 = do
platform <- getPlatform
case platformWordSize platform of
PW4 -> do
[e] <- getArgs
return e
PW8 ->
mzero
getArgs :: RuleM [CoreExpr]
getArgs = RuleM $ \_ _ _ args -> Just args
getInScopeEnv :: RuleM InScopeEnv
getInScopeEnv = RuleM $ \_ iu _ _ -> Just iu
getFunction :: RuleM Id
getFunction = RuleM $ \_ _ fn _ -> Just fn
getLiteral :: Int -> RuleM Literal
getLiteral n = RuleM $ \_ _ _ exprs -> case drop n exprs of
(Lit l:_) -> Just l
_ -> Nothing
unaryLit :: (RuleOpts -> Literal -> Maybe CoreExpr) -> RuleM CoreExpr
unaryLit op = do
env <- getEnv
[Lit l] <- getArgs
liftMaybe $ op env (convFloating env l)
binaryLit :: (RuleOpts -> Literal -> Literal -> Maybe CoreExpr) -> RuleM CoreExpr
binaryLit op = do
env <- getEnv
[Lit l1, Lit l2] <- getArgs
liftMaybe $ op env (convFloating env l1) (convFloating env l2)
binaryCmpLit :: (forall a . Ord a => a -> a -> Bool) -> RuleM CoreExpr
binaryCmpLit op = do
platform <- getPlatform
binaryLit (\_ -> cmpOp platform op)
leftIdentity :: Literal -> RuleM CoreExpr
leftIdentity id_lit = leftIdentityPlatform (const id_lit)
rightIdentity :: Literal -> RuleM CoreExpr
rightIdentity id_lit = rightIdentityPlatform (const id_lit)
identity :: Literal -> RuleM CoreExpr
identity lit = leftIdentity lit `mplus` rightIdentity lit
leftIdentityPlatform :: (Platform -> Literal) -> RuleM CoreExpr
leftIdentityPlatform id_lit = do
platform <- getPlatform
[Lit l1, e2] <- getArgs
guard $ l1 == id_lit platform
return e2
leftIdentityCPlatform :: (Platform -> Literal) -> RuleM CoreExpr
leftIdentityCPlatform id_lit = do
platform <- getPlatform
[Lit l1, e2] <- getArgs
guard $ l1 == id_lit platform
let no_c = Lit (zeroi platform)
return (mkCoreUbxTup [exprType e2, intPrimTy] [e2, no_c])
rightIdentityPlatform :: (Platform -> Literal) -> RuleM CoreExpr
rightIdentityPlatform id_lit = do
platform <- getPlatform
[e1, Lit l2] <- getArgs
guard $ l2 == id_lit platform
return e1
rightIdentityCPlatform :: (Platform -> Literal) -> RuleM CoreExpr
rightIdentityCPlatform id_lit = do
platform <- getPlatform
[e1, Lit l2] <- getArgs
guard $ l2 == id_lit platform
let no_c = Lit (zeroi platform)
return (mkCoreUbxTup [exprType e1, intPrimTy] [e1, no_c])
identityPlatform :: (Platform -> Literal) -> RuleM CoreExpr
identityPlatform lit =
leftIdentityPlatform lit `mplus` rightIdentityPlatform lit
identityCPlatform :: (Platform -> Literal) -> RuleM CoreExpr
identityCPlatform lit =
leftIdentityCPlatform lit `mplus` rightIdentityCPlatform lit
leftZero :: (Platform -> Literal) -> RuleM CoreExpr
leftZero zero = do
platform <- getPlatform
[Lit l1, _] <- getArgs
guard $ l1 == zero platform
return $ Lit l1
rightZero :: (Platform -> Literal) -> RuleM CoreExpr
rightZero zero = do
platform <- getPlatform
[_, Lit l2] <- getArgs
guard $ l2 == zero platform
return $ Lit l2
zeroElem :: (Platform -> 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
convFloating :: RuleOpts -> Literal -> Literal
convFloating env (LitFloat f) | not (roExcessRationalPrecision env) =
LitFloat (toRational (fromRational f :: Float ))
convFloating env (LitDouble d) | not (roExcessRationalPrecision env) =
LitDouble (toRational (fromRational d :: Double))
convFloating _ l = l
guardFloatDiv :: RuleM ()
guardFloatDiv = do
[Lit (LitFloat f1), Lit (LitFloat f2)] <- getArgs
guard $ (f1 /=0 || f2 > 0)
&& f2 /= 0
guardDoubleDiv :: RuleM ()
guardDoubleDiv = do
[Lit (LitDouble d1), Lit (LitDouble d2)] <- getArgs
guard $ (d1 /=0 || d2 > 0)
&& d2 /= 0
strengthReduction :: Literal -> PrimOp -> RuleM CoreExpr
strengthReduction two_lit add_op = do
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
trueValInt, falseValInt :: Platform -> Expr CoreBndr
trueValInt platform = Lit $ onei platform
falseValInt platform = Lit $ zeroi platform
trueValBool, falseValBool :: Expr CoreBndr
trueValBool = Var trueDataConId
falseValBool = Var falseDataConId
ltVal, eqVal, gtVal :: Expr CoreBndr
ltVal = Var ordLTDataConId
eqVal = Var ordEQDataConId
gtVal = Var ordGTDataConId
mkIntVal :: Platform -> Integer -> Expr CoreBndr
mkIntVal platform i = Lit (mkLitInt platform i)
mkFloatVal :: RuleOpts -> Rational -> Expr CoreBndr
mkFloatVal env f = Lit (convFloating env (LitFloat f))
mkDoubleVal :: RuleOpts -> Rational -> Expr CoreBndr
mkDoubleVal env d = Lit (convFloating env (LitDouble d))
matchPrimOpId :: PrimOp -> Id -> RuleM ()
matchPrimOpId op id = do
op' <- liftMaybe $ isPrimOpId_maybe id
guard $ op == op'
tagToEnumRule :: RuleM CoreExpr
tagToEnumRule = do
[Type ty, Lit (LitNumber LitNumInt i)] <- getArgs
case splitTyConApp_maybe ty of
Just (tycon, tc_args) | isEnumerationTyCon tycon -> do
let tag = fromInteger i
correct_tag dc = (dataConTagZ dc) == tag
(dc:rest) <- return $ filter correct_tag (tyConDataCons_maybe tycon `orElse` [])
ASSERT(null rest) return ()
return $ mkTyApps (Var (dataConWorkId dc)) tc_args
_ -> WARN( True, text "tagToEnum# on non-enumeration type" <+> ppr ty )
return $ mkRuntimeErrorApp rUNTIME_ERROR_ID ty "tagToEnum# on non-enumeration type"
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
b = do
dflags <- getPlatform
[_, val_arg] <- getArgs
in_scope <- getInScopeEnv
(_,floats, dc,_,_) <- liftMaybe $ exprIsConApp_maybe in_scope val_arg
ASSERT( not (isNewTyCon (dataConTyCon dc)) ) return ()
return $ wrapFloats floats (mkIntVal dflags (toInteger (dataConTagZ dc)))
unsafeEqualityProofRule :: RuleM CoreExpr
unsafeEqualityProofRule
= do { [Type rep, Type t1, Type t2] <- getArgs
; guard (t1 `eqType` t2)
; fn <- getFunction
; let (_, ue) = splitForAllTys (idType fn)
tc = tyConAppTyCon ue
(dc:_) = tyConDataCons tc
; return (mkTyApps (Var (dataConWrapId dc)) [rep, t1]) }
seqRule :: RuleM CoreExpr
seqRule = do
[Type ty_a, Type _ty_s, a, s] <- getArgs
guard $ exprIsHNF a
return $ mkCoreUbxTup [exprType s, ty_a] [s, a]
sparkRule :: RuleM CoreExpr
sparkRule = seqRule
newtype EnableBignumRules = EnableBignumRules Bool
builtinRules :: EnableBignumRules -> [CoreRule]
builtinRules enableBignumRules
= [BuiltinRule { ru_name = fsLit "AppendLitString",
ru_fn = unpackCStringFoldrName,
ru_nargs = 4, ru_try = match_append_lit_C },
BuiltinRule { ru_name = fsLit "AppendLitStringUtf8",
ru_fn = unpackCStringFoldrUtf8Name,
ru_nargs = 4, ru_try = match_append_lit_utf8 },
BuiltinRule { ru_name = fsLit "EqString", ru_fn = eqStringName,
ru_nargs = 2, ru_try = match_eq_string },
BuiltinRule { ru_name = fsLit "CStringLength", ru_fn = cstringLengthName,
ru_nargs = 1, ru_try = match_cstring_length },
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 },
mkBasicRule unsafeEqualityProofName 3 unsafeEqualityProofRule,
mkBasicRule divIntName 2 $ msum
[ nonZeroLit 1 >> binaryLit (intOp2 div)
, leftZero zeroi
, do
[arg, Lit (LitNumber LitNumInt d)] <- getArgs
Just n <- return $ exactLog2 d
platform <- getPlatform
return $ Var (mkPrimOpId ISraOp) `App` arg `App` mkIntVal platform n
],
mkBasicRule modIntName 2 $ msum
[ nonZeroLit 1 >> binaryLit (intOp2 mod)
, leftZero zeroi
, do
[arg, Lit (LitNumber LitNumInt d)] <- getArgs
Just _ <- return $ exactLog2 d
platform <- getPlatform
return $ Var (mkPrimOpId AndIOp)
`App` arg `App` mkIntVal platform (d 1)
]
]
++ builtinBignumRules enableBignumRules
builtinBignumRules :: EnableBignumRules -> [CoreRule]
builtinBignumRules (EnableBignumRules False) = []
builtinBignumRules _ =
[ rule_IntegerFromLitNum "Word# -> Integer" integerFromWordName
, rule_IntegerFromLitNum "Int64# -> Integer" integerFromInt64Name
, rule_IntegerFromLitNum "Word64# -> Integer" integerFromWord64Name
, rule_IntegerFromLitNum "Natural -> Integer" integerFromNaturalName
, rule_convert "Integer -> Word#" integerToWordName mkWordLitWord
, rule_convert "Integer -> Int#" integerToIntName mkIntLitInt
, rule_convert "Integer -> Word64#" integerToWord64Name (\_ -> mkWord64LitWord64)
, rule_convert "Integer -> Int64#" integerToInt64Name (\_ -> mkInt64LitInt64)
, rule_binopi "integerAdd" integerAddName (+)
, rule_binopi "integerSub" integerSubName ()
, rule_binopi "integerMul" integerMulName (*)
, rule_unop "integerNegate" integerNegateName negate
, rule_binop_Prim "integerEq#" integerEqPrimName (==)
, rule_binop_Prim "integerNe#" integerNePrimName (/=)
, rule_binop_Prim "integerLe#" integerLePrimName (<=)
, rule_binop_Prim "integerGt#" integerGtPrimName (>)
, rule_binop_Prim "integerLt#" integerLtPrimName (<)
, rule_binop_Prim "integerGe#" integerGePrimName (>=)
, rule_unop "integerAbs" integerAbsName abs
, rule_unop "integerSignum" integerSignumName signum
, rule_binop_Ordering "integerCompare" integerCompareName compare
, rule_encodeFloat "integerEncodeFloat" integerEncodeFloatName mkFloatLitFloat
, rule_convert "integerToFloat" integerToFloatName (\_ -> mkFloatLitFloat)
, rule_encodeFloat "integerEncodeDouble" integerEncodeDoubleName mkDoubleLitDouble
, rule_decodeDouble "integerDecodeDouble" integerDecodeDoubleName
, rule_convert "integerToDouble" integerToDoubleName (\_ -> mkDoubleLitDouble)
, rule_binopi "integerGcd" integerGcdName gcd
, rule_binopi "integerLcm" integerLcmName lcm
, rule_binopi "integerAnd" integerAndName (.&.)
, rule_binopi "integerOr" integerOrName (.|.)
, rule_binopi "integerXor" integerXorName xor
, rule_unop "integerComplement" integerComplementName complement
, rule_shift_op "integerShiftL" integerShiftLName shiftL
, rule_shift_op "integerShiftR" integerShiftRName shiftR
, rule_integerBit "integerBit" integerBitName
, rule_divop_one "integerQuot" integerQuotName quot
, rule_divop_one "integerRem" integerRemName rem
, rule_divop_one "integerDiv" integerDivName div
, rule_divop_one "integerMod" integerModName mod
, rule_divop_both "integerDivMod" integerDivModName divMod
, rule_divop_both "integerQuotRem" integerQuotRemName quotRem
, rule_passthrough "Int# -> Integer -> Int#" integerToIntName integerISDataConName
, rule_passthrough "Word# -> Integer -> Word#" integerToWordName integerFromWordName
, rule_passthrough "Int64# -> Integer -> Int64#" integerToInt64Name integerFromInt64Name
, rule_passthrough "Word64# -> Integer -> Word64#" integerToWord64Name integerFromWord64Name
, rule_smallIntegerTo "IS -> Word#" integerToWordName Int2WordOp
, rule_smallIntegerTo "IS -> Float" integerToFloatName Int2FloatOp
, rule_smallIntegerTo "IS -> Double" integerToDoubleName Int2DoubleOp
, rule_passthrough "Word# -> Natural -> Word#" naturalToWordName naturalNSDataConName
, rule_IntegerToNaturalClamp "Integer -> Natural (clamp)" integerToNaturalClampName
, rule_binopn "naturalAdd" naturalAddName (+)
, rule_partial_binopn "naturalSub" naturalSubName (\a b -> if a >= b then Just (a b) else Nothing)
, rule_binopn "naturalMul" naturalMulName (*)
, rule_rationalTo "rationalToFloat" rationalToFloatName mkFloatExpr
, rule_rationalTo "rationalToDouble" rationalToDoubleName mkDoubleExpr
]
where rule_convert str name convert
= BuiltinRule { ru_name = fsLit str, ru_fn = name, ru_nargs = 1,
ru_try = match_Integer_convert convert }
rule_IntegerFromLitNum str name
= BuiltinRule { ru_name = fsLit str, ru_fn = name, ru_nargs = 1,
ru_try = match_LitNumToInteger }
rule_unop str name op
= BuiltinRule { ru_name = fsLit str, ru_fn = name, ru_nargs = 1,
ru_try = match_Integer_unop op }
rule_integerBit str name
= BuiltinRule { ru_name = fsLit str, ru_fn = name, ru_nargs = 1,
ru_try = match_integerBit }
rule_binopi 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_shift_op str name op
= BuiltinRule { ru_name = fsLit str, ru_fn = name, ru_nargs = 2,
ru_try = match_Integer_shift_op 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_passthrough str name toIntegerName
= BuiltinRule { ru_name = fsLit str, ru_fn = name, ru_nargs = 1,
ru_try = match_passthrough 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 }
rule_IntegerToNaturalClamp str name
= BuiltinRule { ru_name = fsLit str, ru_fn = name, ru_nargs = 1,
ru_try = match_IntegerToNaturalClamp }
rule_binopn str name op
= BuiltinRule { ru_name = fsLit str, ru_fn = name, ru_nargs = 2,
ru_try = match_Natural_binop op }
rule_partial_binopn str name op
= BuiltinRule { ru_name = fsLit str, ru_fn = name, ru_nargs = 2,
ru_try = match_Natural_partial_binop op }
match_append_lit_C :: RuleFun
match_append_lit_C = match_append_lit unpackCStringFoldrIdKey
match_append_lit_utf8 :: RuleFun
match_append_lit_utf8 = match_append_lit unpackCStringFoldrUtf8IdKey
match_append_lit :: Unique -> RuleFun
match_append_lit foldVariant _ id_unf _
[ Type ty1
, lit1
, c1
, e2
]
| (strTicks, Var unpk `App` Type ty2
`App` lit2
`App` c2
`App` n) <- stripTicksTop tickishFloatable e2
, unpk `hasKey` foldVariant
, Just (LitString s1) <- exprIsLiteral_maybe id_unf lit1
, Just (LitString s2) <- exprIsLiteral_maybe id_unf lit2
, let freeVars = (mkInScopeSet (exprFreeVars c1 `unionVarSet` exprFreeVars c2))
in eqExpr freeVars c1 c2
, (c1Ticks, c1') <- stripTicksTop tickishFloatable c1
, c2Ticks <- stripTicksTopT tickishFloatable c2
= ASSERT( ty1 `eqType` ty2 )
Just $ mkTicks strTicks
$ Var unpk `App` Type ty1
`App` Lit (LitString (s1 `BS.append` s2))
`App` mkTicks (c1Ticks ++ c2Ticks) c1'
`App` n
match_append_lit _ _ _ _ _ = Nothing
match_eq_string :: RuleFun
match_eq_string _ id_unf _
[Var unpk1 `App` lit1, Var unpk2 `App` lit2]
| unpk_key1 <- getUnique unpk1
, unpk_key2 <- getUnique unpk2
, unpk_key1 == unpk_key2
, unpk_key1 `elem` [unpackCStringUtf8IdKey, unpackCStringIdKey]
, Just (LitString s1) <- exprIsLiteral_maybe id_unf lit1
, Just (LitString s2) <- exprIsLiteral_maybe id_unf lit2
= Just (if s1 == s2 then trueValBool else falseValBool)
match_eq_string _ _ _ _ = Nothing
match_cstring_length :: RuleFun
match_cstring_length env id_unf _ [lit1]
| Just (LitString str) <- exprIsLiteral_maybe id_unf lit1
= let len = fromMaybe (BS.length str) (BS.elemIndex 0 str)
in Just (Lit (mkLitInt (roPlatform env) (fromIntegral len)))
match_cstring_length _ _ _ _ = Nothing
match_inline :: [Expr CoreBndr] -> Maybe (Expr CoreBndr)
match_inline (Type _ : e : _)
| (Var f, args1) <- collectArgs e,
Just unf <- maybeUnfoldingTemplate (realIdUnfolding f)
= Just (mkApps unf args1)
match_inline _ = Nothing
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
match_LitNumToInteger :: RuleFun
match_LitNumToInteger _ id_unf _ [xl]
| Just (LitNumber _ x) <- exprIsLiteral_maybe id_unf xl
= Just (Lit (mkLitInteger x))
match_LitNumToInteger _ _ _ _ = Nothing
match_IntegerToNaturalClamp :: RuleFun
match_IntegerToNaturalClamp _ id_unf _ [xl]
| Just (LitNumber LitNumInteger x) <- exprIsLiteral_maybe id_unf xl
= if x >= 0
then Just (Lit (mkLitNatural x))
else Just (Lit (mkLitNatural 0))
match_IntegerToNaturalClamp _ _ _ _ = Nothing
match_integerBit :: RuleFun
match_integerBit env id_unf _fn [arg]
| Just (LitNumber _ x) <- exprIsLiteral_maybe id_unf arg
, x >= 0
, x <= fromIntegral (platformWordSizeInBits (roPlatform env))
, let x_int = fromIntegral x :: Int
= Just (Lit (mkLitInteger (bit x_int)))
match_integerBit _ _ _ _ = Nothing
match_Integer_convert :: Num a
=> (Platform -> a -> Expr CoreBndr)
-> RuleFun
match_Integer_convert convert env id_unf _ [xl]
| Just (LitNumber LitNumInteger x) <- exprIsLiteral_maybe id_unf xl
= Just (convert (roPlatform env) (fromInteger x))
match_Integer_convert _ _ _ _ _ = Nothing
match_Integer_unop :: (Integer -> Integer) -> RuleFun
match_Integer_unop unop _ id_unf _ [xl]
| Just (LitNumber LitNumInteger x) <- exprIsLiteral_maybe id_unf xl
= Just (Lit (LitNumber LitNumInteger (unop x)))
match_Integer_unop _ _ _ _ _ = Nothing
match_Integer_binop :: (Integer -> Integer -> Integer) -> RuleFun
match_Integer_binop binop _ id_unf _ [xl,yl]
| Just (LitNumber LitNumInteger x) <- exprIsLiteral_maybe id_unf xl
, Just (LitNumber LitNumInteger y) <- exprIsLiteral_maybe id_unf yl
= Just (Lit (mkLitInteger (x `binop` y)))
match_Integer_binop _ _ _ _ _ = Nothing
match_Natural_binop :: (Integer -> Integer -> Integer) -> RuleFun
match_Natural_binop binop _ id_unf _ [xl,yl]
| Just (LitNumber LitNumNatural x) <- exprIsLiteral_maybe id_unf xl
, Just (LitNumber LitNumNatural y) <- exprIsLiteral_maybe id_unf yl
= Just (Lit (mkLitNatural (x `binop` y)))
match_Natural_binop _ _ _ _ _ = Nothing
match_Natural_partial_binop :: (Integer -> Integer -> Maybe Integer) -> RuleFun
match_Natural_partial_binop binop _ id_unf _ [xl,yl]
| Just (LitNumber LitNumNatural x) <- exprIsLiteral_maybe id_unf xl
, Just (LitNumber LitNumNatural y) <- exprIsLiteral_maybe id_unf yl
, Just z <- x `binop` y
= Just (Lit (mkLitNatural z))
match_Natural_partial_binop _ _ _ _ _ = Nothing
match_Integer_divop_both
:: (Integer -> Integer -> (Integer, Integer)) -> RuleFun
match_Integer_divop_both divop _ id_unf _ [xl,yl]
| Just (LitNumber LitNumInteger x) <- exprIsLiteral_maybe id_unf xl
, Just (LitNumber LitNumInteger y) <- exprIsLiteral_maybe id_unf yl
, y /= 0
, (r,s) <- x `divop` y
= Just $ mkCoreUbxTup [integerTy,integerTy]
[Lit (mkLitInteger r), Lit (mkLitInteger s)]
match_Integer_divop_both _ _ _ _ _ = Nothing
match_Integer_divop_one :: (Integer -> Integer -> Integer) -> RuleFun
match_Integer_divop_one divop _ id_unf _ [xl,yl]
| Just (LitNumber LitNumInteger x) <- exprIsLiteral_maybe id_unf xl
, Just (LitNumber LitNumInteger y) <- exprIsLiteral_maybe id_unf yl
, y /= 0
= Just (Lit (mkLitInteger (x `divop` y)))
match_Integer_divop_one _ _ _ _ _ = Nothing
match_Integer_shift_op :: (Integer -> Int -> Integer) -> RuleFun
match_Integer_shift_op binop _ id_unf _ [xl,yl]
| Just (LitNumber LitNumInteger x) <- exprIsLiteral_maybe id_unf xl
, Just (LitNumber LitNumWord y) <- exprIsLiteral_maybe id_unf yl
, y >= 0
, y <= 4
= Just (Lit (mkLitInteger (x `binop` fromIntegral y)))
match_Integer_shift_op _ _ _ _ _ = Nothing
match_Integer_binop_Prim :: (Integer -> Integer -> Bool) -> RuleFun
match_Integer_binop_Prim binop env id_unf _ [xl, yl]
| Just (LitNumber LitNumInteger x) <- exprIsLiteral_maybe id_unf xl
, Just (LitNumber LitNumInteger y) <- exprIsLiteral_maybe id_unf yl
= Just (if x `binop` y then trueValInt (roPlatform env) else falseValInt (roPlatform env))
match_Integer_binop_Prim _ _ _ _ _ = Nothing
match_Integer_binop_Ordering :: (Integer -> Integer -> Ordering) -> RuleFun
match_Integer_binop_Ordering binop _ id_unf _ [xl, yl]
| Just (LitNumber LitNumInteger x) <- exprIsLiteral_maybe id_unf xl
, Just (LitNumber LitNumInteger 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 (LitNumber LitNumInteger x) <- exprIsLiteral_maybe id_unf xl
, Just (LitNumber LitNumInt y) <- exprIsLiteral_maybe id_unf yl
= Just (mkLit $ encodeFloat x (fromInteger y))
match_Integer_Int_encodeFloat _ _ _ _ _ = Nothing
match_rationalTo :: RealFloat a
=> (a -> Expr CoreBndr)
-> RuleFun
match_rationalTo mkLit _ id_unf _ [xl, yl]
| Just (LitNumber LitNumInteger x) <- exprIsLiteral_maybe id_unf xl
, Just (LitNumber LitNumInteger y) <- exprIsLiteral_maybe id_unf yl
, y /= 0
= Just (mkLit (fromRational (x % y)))
match_rationalTo _ _ _ _ _ = Nothing
match_decodeDouble :: RuleFun
match_decodeDouble env id_unf fn [xl]
| Just (LitDouble x) <- exprIsLiteral_maybe id_unf xl
= case splitFunTy_maybe (idType fn) of
Just (_, _, res)
| Just [_lev1, _lev2, _integerTy, intHashTy] <- tyConAppArgs_maybe res
-> case decodeFloat (fromRational x :: Double) of
(y, z) ->
Just $ mkCoreUbxTup [integerTy, intHashTy]
[Lit (mkLitInteger y),
Lit (mkLitInt (roPlatform env) (toInteger z))]
_ ->
pprPanic "match_decodeDouble: Id has the wrong type"
(ppr fn <+> dcolon <+> ppr (idType fn))
match_decodeDouble _ _ _ _ = Nothing
match_passthrough :: Name -> RuleFun
match_passthrough n _ _ _ [App (Var x) y]
| idName x == n
= Just y
match_passthrough _ _ _ _ _ = Nothing
match_smallIntegerTo :: PrimOp -> RuleFun
match_smallIntegerTo primOp _ _ _ [App (Var x) y]
| idName x == integerISDataConName
= Just $ App (Var (mkPrimOpId primOp)) y
match_smallIntegerTo _ _ _ _ _ = Nothing
numFoldingRules :: PrimOp -> (Platform -> PrimOps) -> RuleM CoreExpr
numFoldingRules op dict = do
env <- getEnv
if not (roNumConstantFolding env)
then mzero
else do
[e1,e2] <- getArgs
platform <- getPlatform
let PrimOps{..} = dict platform
case BinOpApp e1 op e2 of
x :++: (y :++: v) -> return $ mkL (x+y) `add` v
x :++: (L y :-: v) -> return $ mkL (x+y) `sub` v
x :++: (v :-: L y) -> return $ mkL (xy) `add` v
L x :-: (y :++: v) -> return $ mkL (xy) `sub` v
L x :-: (L y :-: v) -> return $ mkL (xy) `add` v
L x :-: (v :-: L y) -> return $ mkL (x+y) `sub` v
(y :++: v) :-: L x -> return $ mkL (yx) `add` v
(L y :-: v) :-: L x -> return $ mkL (yx) `sub` v
(v :-: L y) :-: L x -> return $ mkL (0yx) `add` v
(x :++: w) :+: (y :++: v) -> return $ mkL (x+y) `add` (w `add` v)
(w :-: L x) :+: (L y :-: v) -> return $ mkL (yx) `add` (w `sub` v)
(w :-: L x) :+: (v :-: L y) -> return $ mkL (0xy) `add` (w `add` v)
(L x :-: w) :+: (L y :-: v) -> return $ mkL (x+y) `sub` (w `add` v)
(L x :-: w) :+: (v :-: L y) -> return $ mkL (xy) `add` (v `sub` w)
(w :-: L x) :+: (y :++: v) -> return $ mkL (yx) `add` (w `add` v)
(L x :-: w) :+: (y :++: v) -> return $ mkL (x+y) `add` (v `sub` w)
(y :++: v) :+: (w :-: L x) -> return $ mkL (yx) `add` (w `add` v)
(y :++: v) :+: (L x :-: w) -> return $ mkL (x+y) `add` (v `sub` w)
(v :-: L y) :-: (w :-: L x) -> return $ mkL (xy) `add` (v `sub` w)
(v :-: L y) :-: (L x :-: w) -> return $ mkL (0xy) `add` (v `add` w)
(L y :-: v) :-: (w :-: L x) -> return $ mkL (x+y) `sub` (v `add` w)
(L y :-: v) :-: (L x :-: w) -> return $ mkL (yx) `add` (w `sub` v)
(x :++: w) :-: (y :++: v) -> return $ mkL (xy) `add` (w `sub` v)
(w :-: L x) :-: (y :++: v) -> return $ mkL (0yx) `add` (w `sub` v)
(L x :-: w) :-: (y :++: v) -> return $ mkL (xy) `sub` (v `add` w)
(y :++: v) :-: (w :-: L x) -> return $ mkL (y+x) `add` (v `sub` w)
(y :++: v) :-: (L x :-: w) -> return $ mkL (yx) `add` (v `add` w)
x :**: (y :**: v) -> return $ mkL (x*y) `mul` v
(x :**: w) :*: (y :**: v) -> return $ mkL (x*y) `mul` (w `mul` v)
x :**: (y :++: v) -> return $ mkL (x*y) `add` (mkL x `mul` v)
x :**: (L y :-: v) -> return $ mkL (x*y) `sub` (mkL x `mul` v)
x :**: (v :-: L y) -> return $ (mkL x `mul` v) `sub` mkL (x*y)
v :+: w
| w `cheapEqExpr` v -> return $ mkL 2 `mul` v
w :+: (y :**: v)
| w `cheapEqExpr` v -> return $ mkL (1+y) `mul` v
w :-: (y :**: v)
| w `cheapEqExpr` v -> return $ mkL (1y) `mul` v
(y :**: v) :+: w
| w `cheapEqExpr` v -> return $ mkL (y+1) `mul` v
(y :**: v) :-: w
| w `cheapEqExpr` v -> return $ mkL (y1) `mul` v
(x :**: w) :+: (y :**: v)
| w `cheapEqExpr` v -> return $ mkL (x+y) `mul` v
(x :**: w) :-: (y :**: v)
| w `cheapEqExpr` v -> return $ mkL (xy) `mul` v
w :+: (y :++: v) -> return $ mkL y `add` (w `add` v)
(y :++: v) :+: w -> return $ mkL y `add` (w `add` v)
w :-: (y :++: v) -> return $ (w `sub` v) `sub` mkL y
(y :++: v) :-: w -> return $ mkL y `add` (v `sub` w)
w :-: (L y :-: v) -> return $ (w `add` v) `sub` mkL y
(L y :-: v) :-: w -> return $ mkL y `sub` (w `add` v)
w :+: (L y :-: v) -> return $ mkL y `add` (w `sub` v)
w :+: (v :-: L y) -> return $ (w `add` v) `sub` mkL y
(L y :-: v) :+: w -> return $ mkL y `add` (w `sub` v)
(v :-: L y) :+: w -> return $ (w `add` v) `sub` mkL y
_ -> mzero
pattern BinOpApp :: Arg CoreBndr -> PrimOp -> Arg CoreBndr -> CoreExpr
pattern BinOpApp x op y = OpVal op `App` x `App` y
pattern OpVal :: PrimOp -> Arg CoreBndr
pattern OpVal op <- Var (isPrimOpId_maybe -> Just op) where
OpVal op = Var (mkPrimOpId op)
pattern L :: Integer -> Arg CoreBndr
pattern L l <- Lit (isLitValue_maybe -> Just l)
pattern (:+:) :: Arg CoreBndr -> Arg CoreBndr -> CoreExpr
pattern x :+: y <- BinOpApp x (isAddOp -> True) y
pattern (:++:) :: Integer -> Arg CoreBndr -> CoreExpr
pattern l :++: x <- (isAdd -> Just (l,x))
isAdd :: CoreExpr -> Maybe (Integer,CoreExpr)
isAdd e = case e of
L l :+: x -> Just (l,x)
x :+: L l -> Just (l,x)
_ -> Nothing
pattern (:*:) :: Arg CoreBndr -> Arg CoreBndr -> CoreExpr
pattern x :*: y <- BinOpApp x (isMulOp -> True) y
pattern (:**:) :: Integer -> Arg CoreBndr -> CoreExpr
pattern l :**: x <- (isMul -> Just (l,x))
isMul :: CoreExpr -> Maybe (Integer,CoreExpr)
isMul e = case e of
L l :*: x -> Just (l,x)
x :*: L l -> Just (l,x)
_ -> Nothing
pattern (:-:) :: Arg CoreBndr -> Arg CoreBndr -> CoreExpr
pattern x :-: y <- BinOpApp x (isSubOp -> True) y
isSubOp :: PrimOp -> Bool
isSubOp IntSubOp = True
isSubOp WordSubOp = True
isSubOp _ = False
isAddOp :: PrimOp -> Bool
isAddOp IntAddOp = True
isAddOp WordAddOp = True
isAddOp _ = False
isMulOp :: PrimOp -> Bool
isMulOp IntMulOp = True
isMulOp WordMulOp = True
isMulOp _ = False
data PrimOps = PrimOps
{ add :: CoreExpr -> CoreExpr -> CoreExpr
, sub :: CoreExpr -> CoreExpr -> CoreExpr
, mul :: CoreExpr -> CoreExpr -> CoreExpr
, mkL :: Integer -> CoreExpr
}
intPrimOps :: Platform -> PrimOps
intPrimOps platform = PrimOps
{ add = \x y -> BinOpApp x IntAddOp y
, sub = \x y -> BinOpApp x IntSubOp y
, mul = \x y -> BinOpApp x IntMulOp y
, mkL = intResult' platform
}
wordPrimOps :: Platform -> PrimOps
wordPrimOps platform = PrimOps
{ add = \x y -> BinOpApp x WordAddOp y
, sub = \x y -> BinOpApp x WordSubOp y
, mul = \x y -> BinOpApp x WordMulOp y
, mkL = wordResult' platform
}
caseRules :: Platform
-> CoreExpr
-> Maybe ( CoreExpr
, AltCon -> Maybe AltCon
, Id -> CoreExpr)
caseRules platform (App (App (Var f) v) (Lit l))
| Just op <- isPrimOpId_maybe f
, Just x <- isLitValue_maybe l
, Just adjust_lit <- adjustDyadicRight op x
= Just (v, tx_lit_con platform adjust_lit
, \v -> (App (App (Var f) (Var v)) (Lit l)))
caseRules platform (App (App (Var f) (Lit l)) v)
| Just op <- isPrimOpId_maybe f
, Just x <- isLitValue_maybe l
, Just adjust_lit <- adjustDyadicLeft x op
= Just (v, tx_lit_con platform adjust_lit
, \v -> (App (App (Var f) (Lit l)) (Var v)))
caseRules platform (App (Var f) v )
| Just op <- isPrimOpId_maybe f
, Just adjust_lit <- adjustUnary op
= Just (v, tx_lit_con platform adjust_lit
, \v -> App (Var f) (Var v))
caseRules platform (App (App (Var f) type_arg) v)
| Just TagToEnumOp <- isPrimOpId_maybe f
= Just (v, tx_con_tte platform
, \v -> (App (App (Var f) type_arg) (Var v)))
caseRules _ (App (App (Var f) (Type ty)) v)
| Just DataToTagOp <- isPrimOpId_maybe f
, Just (tc, _) <- tcSplitTyConApp_maybe ty
, isAlgTyCon tc
= Just (v, tx_con_dtt ty
, \v -> App (App (Var f) (Type ty)) (Var v))
caseRules _ _ = Nothing
tx_lit_con :: Platform -> (Integer -> Integer) -> AltCon -> Maybe AltCon
tx_lit_con _ _ DEFAULT = Just DEFAULT
tx_lit_con platform adjust (LitAlt l) = Just $ LitAlt (mapLitValue platform adjust l)
tx_lit_con _ _ alt = pprPanic "caseRules" (ppr alt)
adjustDyadicRight :: PrimOp -> Integer -> Maybe (Integer -> Integer)
adjustDyadicRight op lit
= case op of
WordAddOp -> Just (\y -> ylit )
IntAddOp -> Just (\y -> ylit )
WordSubOp -> Just (\y -> y+lit )
IntSubOp -> Just (\y -> y+lit )
XorOp -> Just (\y -> y `xor` lit)
XorIOp -> Just (\y -> y `xor` lit)
_ -> Nothing
adjustDyadicLeft :: Integer -> PrimOp -> Maybe (Integer -> Integer)
adjustDyadicLeft lit op
= case op of
WordAddOp -> Just (\y -> ylit )
IntAddOp -> Just (\y -> ylit )
WordSubOp -> Just (\y -> lity )
IntSubOp -> Just (\y -> lity )
XorOp -> Just (\y -> y `xor` lit)
XorIOp -> Just (\y -> y `xor` lit)
_ -> Nothing
adjustUnary :: PrimOp -> Maybe (Integer -> Integer)
adjustUnary op
= case op of
NotOp -> Just (\y -> complement y)
NotIOp -> Just (\y -> complement y)
IntNegOp -> Just (\y -> negate y )
_ -> Nothing
tx_con_tte :: Platform -> AltCon -> Maybe AltCon
tx_con_tte _ DEFAULT = Just DEFAULT
tx_con_tte _ alt@(LitAlt {}) = pprPanic "caseRules" (ppr alt)
tx_con_tte platform (DataAlt dc)
= Just $ LitAlt $ mkLitInt platform $ toInteger $ dataConTagZ dc
tx_con_dtt :: Type -> AltCon -> Maybe AltCon
tx_con_dtt _ DEFAULT = Just DEFAULT
tx_con_dtt ty (LitAlt (LitNumber LitNumInt i))
| tag >= 0
, tag < n_data_cons
= Just (DataAlt (data_cons !! tag))
| otherwise
= Nothing
where
tag = fromInteger i :: ConTagZ
tc = tyConAppTyCon ty
n_data_cons = tyConFamilySize tc
data_cons = tyConDataCons tc
tx_con_dtt _ alt = pprPanic "caseRules" (ppr alt)