module GHC.Core.Opt.ConstantFold
( primOpRules
, builtinRules
, caseRules
, EnableBignumRules (..)
)
where
#include "HsVersions.h"
import GHC.Prelude
import GHC.Types.Id.Make ( mkPrimOpId, magicDictId, voidPrimId )
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 ]
FloatDecode_IntOp -> mkPrimOpRule nm 1 [ unaryLit floatDecodeOp ]
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 ]
DoubleDecode_Int64Op -> mkPrimOpRule nm 1 [ unaryLit doubleDecodeOp ]
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
floatDecodeOp :: RuleOpts -> Literal -> Maybe CoreExpr
floatDecodeOp env (LitFloat ((decodeFloat . fromRational @Float) -> (m, e)))
= Just $ mkCoreUbxTup [intPrimTy, intPrimTy]
[ mkIntVal (roPlatform env) (toInteger m)
, mkIntVal (roPlatform env) (toInteger e) ]
floatDecodeOp _ _
= 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
doubleDecodeOp :: RuleOpts -> Literal -> Maybe CoreExpr
doubleDecodeOp env (LitDouble ((decodeFloat . fromRational @Double) -> (m, e)))
= Just $ mkCoreUbxTup [iNT64Ty, intPrimTy]
[ Lit (mkLitINT64 (roPlatform env) (toInteger m))
, mkIntVal platform (toInteger e) ]
where
platform = roPlatform env
(iNT64Ty, mkLitINT64)
| platformWordSizeInBits platform < 64
= (int64PrimTy, mkLitInt64Wrap)
| otherwise
= (intPrimTy , mkLitIntWrap)
doubleDecodeOp _ _
= 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
isLiteral :: CoreExpr -> RuleM Literal
isLiteral e = do
env <- getInScopeEnv
case exprIsLiteral_maybe env e of
Nothing -> mzero
Just l -> pure l
isNumberLiteral :: CoreExpr -> RuleM Integer
isNumberLiteral e = isLiteral e >>= \case
LitNumber _ x -> pure x
_ -> mzero
isIntegerLiteral :: CoreExpr -> RuleM Integer
isIntegerLiteral e = isLiteral e >>= \case
LitNumber LitNumInteger x -> pure x
_ -> mzero
isNaturalLiteral :: CoreExpr -> RuleM Integer
isNaturalLiteral e = isLiteral e >>= \case
LitNumber LitNumNatural x -> pure x
_ -> mzero
isWordLiteral :: CoreExpr -> RuleM Integer
isWordLiteral e = isLiteral e >>= \case
LitNumber LitNumWord x -> pure x
_ -> mzero
isIntLiteral :: CoreExpr -> RuleM Integer
isIntLiteral e = isLiteral e >>= \case
LitNumber LitNumInt x -> pure x
_ -> mzero
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 _ =
[
lit_to_integer "Word# -> Integer" integerFromWordName
, lit_to_integer "Int64# -> Integer" integerFromInt64Name
, lit_to_integer "Word64# -> Integer" integerFromWord64Name
, lit_to_integer "Natural -> Integer" integerFromNaturalName
, integer_to_lit "Integer -> Word# (wrap)" integerToWordName mkWordLitWrap
, integer_to_lit "Integer -> Int# (wrap)" integerToIntName mkIntLitWrap
, integer_to_lit "Integer -> Word64# (wrap)" integerToWord64Name (\_ -> mkWord64LitWord64 . fromInteger)
, integer_to_lit "Integer -> Int64# (wrap)" integerToInt64Name (\_ -> mkInt64LitInt64 . fromInteger)
, integer_to_lit "Integer -> Float#" integerToFloatName (\_ -> mkFloatLitFloat . fromInteger)
, integer_to_lit "Integer -> Double#" integerToDoubleName (\_ -> mkDoubleLitDouble . fromInteger)
, integer_to_natural "Integer -> Natural (clamp)" integerToNaturalClampName False True
, integer_to_natural "Integer -> Natural (wrap)" integerToNaturalName False False
, integer_to_natural "Integer -> Natural (throw)" integerToNaturalThrowName True False
, lit_to_natural "Word# -> Natural" naturalNSDataConName
, natural_to_word "Natural -> Word# (wrap)" naturalToWordName False
, natural_to_word "Natural -> Word# (clamp)" naturalToWordClampName True
, integer_cmp "integerEq#" integerEqName (==)
, integer_cmp "integerNe#" integerNeName (/=)
, integer_cmp "integerLe#" integerLeName (<=)
, integer_cmp "integerGt#" integerGtName (>)
, integer_cmp "integerLt#" integerLtName (<)
, integer_cmp "integerGe#" integerGeName (>=)
, natural_cmp "naturalEq#" naturalEqName (==)
, natural_cmp "naturalNe#" naturalNeName (/=)
, natural_cmp "naturalLe#" naturalLeName (<=)
, natural_cmp "naturalGt#" naturalGtName (>)
, natural_cmp "naturalLt#" naturalLtName (<)
, natural_cmp "naturalGe#" naturalGeName (>=)
, bignum_compare "integerCompare" integerCompareName
, bignum_compare "naturalCompare" naturalCompareName
, integer_binop "integerAdd" integerAddName (+)
, integer_binop "integerSub" integerSubName ()
, integer_binop "integerMul" integerMulName (*)
, integer_binop "integerGcd" integerGcdName gcd
, integer_binop "integerLcm" integerLcmName lcm
, integer_binop "integerAnd" integerAndName (.&.)
, integer_binop "integerOr" integerOrName (.|.)
, integer_binop "integerXor" integerXorName xor
, natural_binop "naturalAdd" naturalAddName (+)
, natural_binop "naturalMul" naturalMulName (*)
, natural_binop "naturalGcd" naturalGcdName gcd
, natural_binop "naturalLcm" naturalLcmName lcm
, natural_binop "naturalAnd" naturalAndName (.&.)
, natural_binop "naturalOr" naturalOrName (.|.)
, natural_binop "naturalXor" naturalXorName xor
, natural_sub "naturalSubUnsafe" naturalSubUnsafeName
, natural_sub "naturalSubThrow" naturalSubThrowName
, mkRule "naturalSub" naturalSubName 2 $ do
[a0,a1] <- getArgs
x <- isNaturalLiteral a0
y <- isNaturalLiteral a1
let ret n v = pure $ mkCoreUbxSum 2 n [voidPrimTy,naturalTy] v
if x < y
then ret 1 $ Var voidPrimId
else ret 2 $ Lit (mkLitNatural (x y))
, bignum_unop "integerNegate" integerNegateName mkLitInteger negate
, bignum_unop "integerAbs" integerAbsName mkLitInteger abs
, bignum_unop "integerSignum" integerSignumName mkLitInteger signum
, bignum_unop "integerComplement" integerComplementName mkLitInteger complement
, bignum_unop "naturalSignum" naturalSignumName mkLitNatural signum
, mkRule "naturalNegate" naturalNegateName 1 $ do
[a0] <- getArgs
x <- isNaturalLiteral a0
guard (x == 0)
pure a0
, bignum_popcount "integerPopCount" integerPopCountName mkLitIntWrap
, bignum_popcount "naturalPopCount" naturalPopCountName mkLitWordWrap
, id_passthrough "Int# -> Integer -> Int#" integerToIntName integerISDataConName
, id_passthrough "Word# -> Integer -> Word#" integerToWordName integerFromWordName
, id_passthrough "Int64# -> Integer -> Int64#" integerToInt64Name integerFromInt64Name
, id_passthrough "Word64# -> Integer -> Word64#" integerToWord64Name integerFromWord64Name
, id_passthrough "Word# -> Natural -> Word#" naturalToWordName naturalNSDataConName
, small_passthrough "Int# -> Integer -> Word#"
integerISDataConName integerToWordName (mkPrimOpId Int2WordOp)
, small_passthrough "Int# -> Integer -> Float#"
integerISDataConName integerToFloatName (mkPrimOpId Int2FloatOp)
, small_passthrough "Int# -> Integer -> Double#"
integerISDataConName integerToDoubleName (mkPrimOpId Int2DoubleOp)
, small_passthrough "Word# -> Natural -> Int#"
naturalNSDataConName naturalToWordName (mkPrimOpId Word2IntOp)
, bignum_bit "integerBit" integerBitName mkLitInteger
, bignum_bit "naturalBit" naturalBitName mkLitNatural
, bignum_testbit "integerTestBit" integerTestBitName
, bignum_testbit "naturalTestBit" naturalTestBitName
, bignum_shift "integerShiftL" integerShiftLName shiftL mkLitInteger
, bignum_shift "integerShiftR" integerShiftRName shiftR mkLitInteger
, bignum_shift "naturalShiftL" naturalShiftLName shiftL mkLitNatural
, bignum_shift "naturalShiftR" naturalShiftRName shiftR mkLitNatural
, divop_one "integerQuot" integerQuotName quot mkLitInteger
, divop_one "integerRem" integerRemName rem mkLitInteger
, divop_one "integerDiv" integerDivName div mkLitInteger
, divop_one "integerMod" integerModName mod mkLitInteger
, divop_both "integerDivMod" integerDivModName divMod mkLitInteger integerTy
, divop_both "integerQuotRem" integerQuotRemName quotRem mkLitInteger integerTy
, divop_one "naturalQuot" naturalQuotName quot mkLitNatural
, divop_one "naturalRem" naturalRemName rem mkLitNatural
, divop_both "naturalQuotRem" naturalQuotRemName quotRem mkLitNatural naturalTy
, rational_to "rationalToFloat" rationalToFloatName mkFloatExpr
, rational_to "rationalToDouble" rationalToDoubleName mkDoubleExpr
, integer_encode_float "integerEncodeFloat" integerEncodeFloatName mkFloatLitFloat
, integer_encode_float "integerEncodeDouble" integerEncodeDoubleName mkDoubleLitDouble
]
where
mkRule str name nargs f = BuiltinRule
{ ru_name = fsLit str
, ru_fn = name
, ru_nargs = nargs
, ru_try = runRuleM f
}
integer_to_lit str name convert = mkRule str name 1 $ do
[a0] <- getArgs
platform <- getPlatform
x <- isIntegerLiteral a0
pure (convert platform x)
natural_to_word str name clamp = mkRule str name 1 $ do
[a0] <- getArgs
n <- isNaturalLiteral a0
platform <- getPlatform
if clamp && not (platformInWordRange platform n)
then pure (Lit (mkLitWord platform (platformMaxWord platform)))
else pure (Lit (mkLitWordWrap platform n))
integer_to_natural str name thrw clamp = mkRule str name 1 $ do
[a0] <- getArgs
x <- isIntegerLiteral a0
if | x >= 0 -> pure $ Lit $ mkLitNatural x
| thrw -> mzero
| clamp -> pure $ Lit $ mkLitNatural 0
| otherwise -> pure $ Lit $ mkLitNatural (abs x)
lit_to_integer str name = mkRule str name 1 $ do
[a0] <- getArgs
isLiteral a0 >>= \case
LitNumber _ i -> pure (Lit (mkLitInteger i))
_ -> mzero
lit_to_natural str name = mkRule str name 1 $ do
[a0] <- getArgs
isLiteral a0 >>= \case
LitNumber _ i | i >= 0 -> pure (Lit (mkLitNatural i))
_ -> mzero
integer_binop str name op = mkRule str name 2 $ do
[a0,a1] <- getArgs
x <- isIntegerLiteral a0
y <- isIntegerLiteral a1
pure (Lit (mkLitInteger (x `op` y)))
natural_binop str name op = mkRule str name 2 $ do
[a0,a1] <- getArgs
x <- isNaturalLiteral a0
y <- isNaturalLiteral a1
pure (Lit (mkLitNatural (x `op` y)))
natural_sub str name = mkRule str name 2 $ do
[a0,a1] <- getArgs
x <- isNaturalLiteral a0
y <- isNaturalLiteral a1
guard (x >= y)
pure (Lit (mkLitNatural (x y)))
integer_cmp str name op = mkRule str name 2 $ do
platform <- getPlatform
[a0,a1] <- getArgs
x <- isIntegerLiteral a0
y <- isIntegerLiteral a1
pure $ if x `op` y
then trueValInt platform
else falseValInt platform
natural_cmp str name op = mkRule str name 2 $ do
platform <- getPlatform
[a0,a1] <- getArgs
x <- isNaturalLiteral a0
y <- isNaturalLiteral a1
pure $ if x `op` y
then trueValInt platform
else falseValInt platform
bignum_compare str name = mkRule str name 2 $ do
[a0,a1] <- getArgs
x <- isNumberLiteral a0
y <- isNumberLiteral a1
pure $ case x `compare` y of
LT -> ltVal
EQ -> eqVal
GT -> gtVal
bignum_unop str name mk_lit op = mkRule str name 1 $ do
[a0] <- getArgs
x <- isNumberLiteral a0
pure $ Lit (mk_lit (op x))
bignum_popcount str name mk_lit = mkRule str name 1 $ do
platform <- getPlatform
guard (platformWordSizeInBits platform == finiteBitSize (0 :: Word))
[a0] <- getArgs
x <- isNumberLiteral a0
pure $ Lit (mk_lit platform (fromIntegral (popCount x)))
id_passthrough str to_x from_x = mkRule str to_x 1 $ do
[App (Var f) x] <- getArgs
guard (idName f == from_x)
pure x
small_passthrough str from_x to_y x_to_y = mkRule str to_y 1 $ do
[App (Var f) x] <- getArgs
guard (idName f == from_x)
pure $ App (Var x_to_y) x
bignum_bit str name mk_lit = mkRule str name 1 $ do
[a0] <- getArgs
platform <- getPlatform
n <- isNumberLiteral a0
guard (n >= 0 && n <= fromIntegral (platformWordSizeInBits platform))
pure $ Lit (mk_lit (bit (fromIntegral n)))
bignum_testbit str name = mkRule str name 2 $ do
[a0,a1] <- getArgs
platform <- getPlatform
x <- isNumberLiteral a0
n <- isNumberLiteral a1
guard (n >= 0 && n <= fromIntegral (maxBound :: Int))
pure $ if testBit x (fromIntegral n)
then trueValInt platform
else falseValInt platform
bignum_shift str name shift_op mk_lit = mkRule str name 2 $ do
[a0,a1] <- getArgs
x <- isNumberLiteral a0
n <- isWordLiteral a1
guard (n <= 4)
pure $ Lit (mk_lit (x `shift_op` fromIntegral n))
divop_one str name divop mk_lit = mkRule str name 2 $ do
[a0,a1] <- getArgs
n <- isNumberLiteral a0
d <- isNumberLiteral a1
guard (d /= 0)
pure $ Lit (mk_lit (n `divop` d))
divop_both str name divop mk_lit ty = mkRule str name 2 $ do
[a0,a1] <- getArgs
n <- isNumberLiteral a0
d <- isNumberLiteral a1
guard (d /= 0)
let (r,s) = n `divop` d
pure $ mkCoreUbxTup [ty,ty] [Lit (mk_lit r), Lit (mk_lit s)]
integer_encode_float :: RealFloat a => String -> Name -> (a -> CoreExpr) -> CoreRule
integer_encode_float str name mk_lit = mkRule str name 2 $ do
[a0,a1] <- getArgs
x <- isIntegerLiteral a0
y <- isIntLiteral a1
guard (y <= fromIntegral (maxBound :: Int))
pure (mk_lit $ encodeFloat x (fromInteger y))
rational_to :: RealFloat a => String -> Name -> (a -> CoreExpr) -> CoreRule
rational_to str name mk_lit = mkRule str name 2 $ do
[a0,a1] <- getArgs
n <- isIntegerLiteral a0
d <- isIntegerLiteral a1
guard (d /= 0)
pure $ mk_lit (fromRational (n % d))
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
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)