module GHC.Core.Opt.ConstantFold
( primOpRules
, builtinRules
, caseRules
)
where
#include "HsVersions.h"
import GHC.Prelude
import GHC.Driver.Ppr
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 ( exprIsConApp_maybe, 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.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.Types.Tickish
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.Utils.Panic
import GHC.Core.Coercion (mkUnbranchedAxInstCo,mkSymCo,Role(..))
import Control.Applicative ( Alternative(..) )
import Control.Monad
import Data.Functor (($>))
import Data.Bits as Bits
import qualified Data.ByteString as BS
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 ]
Int8AddOp -> mkPrimOpRule nm 2 [ binaryLit (int8Op2 (+))
, identity zeroI8
, addFoldingRules Int8AddOp int8Ops
]
Int8SubOp -> mkPrimOpRule nm 2 [ binaryLit (int8Op2 ())
, rightIdentity zeroI8
, equalArgs $> Lit zeroI8
, subFoldingRules Int8SubOp int8Ops
]
Int8MulOp -> mkPrimOpRule nm 2 [ binaryLit (int8Op2 (*))
, zeroElem
, identity oneI8
, mulFoldingRules Int8MulOp int8Ops
]
Int8QuotOp -> mkPrimOpRule nm 2 [ nonZeroLit 1 >> binaryLit (int8Op2 quot)
, leftZero
, rightIdentity oneI8
, equalArgs $> Lit oneI8 ]
Int8RemOp -> mkPrimOpRule nm 2 [ nonZeroLit 1 >> binaryLit (int8Op2 rem)
, leftZero
, oneLit 1 $> Lit zeroI8
, equalArgs $> Lit zeroI8 ]
Int8NegOp -> mkPrimOpRule nm 1 [ unaryLit negOp
, semiInversePrimOp Int8NegOp ]
Int8SllOp -> mkPrimOpRule nm 2 [ shiftRule LitNumInt8 (const Bits.shiftL)
, rightIdentity zeroI8 ]
Int8SraOp -> mkPrimOpRule nm 2 [ shiftRule LitNumInt8 (const Bits.shiftR)
, rightIdentity zeroI8 ]
Int8SrlOp -> mkPrimOpRule nm 2 [ shiftRule LitNumInt8 $ const $ shiftRightLogical @Word8
, rightIdentity zeroI8 ]
Word8AddOp -> mkPrimOpRule nm 2 [ binaryLit (word8Op2 (+))
, identity zeroW8
, addFoldingRules Word8AddOp word8Ops
]
Word8SubOp -> mkPrimOpRule nm 2 [ binaryLit (word8Op2 ())
, rightIdentity zeroW8
, equalArgs $> Lit zeroW8
, subFoldingRules Word8SubOp word8Ops
]
Word8MulOp -> mkPrimOpRule nm 2 [ binaryLit (word8Op2 (*))
, identity oneW8
, mulFoldingRules Word8MulOp word8Ops
]
Word8QuotOp -> mkPrimOpRule nm 2 [ nonZeroLit 1 >> binaryLit (word8Op2 quot)
, rightIdentity oneW8 ]
Word8RemOp -> mkPrimOpRule nm 2 [ nonZeroLit 1 >> binaryLit (word8Op2 rem)
, leftZero
, oneLit 1 $> Lit zeroW8
, equalArgs $> Lit zeroW8 ]
Word8AndOp -> mkPrimOpRule nm 2 [ binaryLit (word8Op2 (.&.))
, idempotent
, zeroElem ]
Word8OrOp -> mkPrimOpRule nm 2 [ binaryLit (word8Op2 (.|.))
, idempotent
, identity zeroW8 ]
Word8XorOp -> mkPrimOpRule nm 2 [ binaryLit (word8Op2 xor)
, identity zeroW8
, equalArgs $> Lit zeroW8 ]
Word8NotOp -> mkPrimOpRule nm 1 [ unaryLit complementOp
, semiInversePrimOp Word8NotOp ]
Word8SllOp -> mkPrimOpRule nm 2 [ shiftRule LitNumWord (const Bits.shiftL) ]
Word8SrlOp -> mkPrimOpRule nm 2 [ shiftRule LitNumWord $ const $ shiftRightLogical @Word8 ]
Int16AddOp -> mkPrimOpRule nm 2 [ binaryLit (int16Op2 (+))
, identity zeroI16
, addFoldingRules Int16AddOp int16Ops
]
Int16SubOp -> mkPrimOpRule nm 2 [ binaryLit (int16Op2 ())
, rightIdentity zeroI16
, equalArgs $> Lit zeroI16
, subFoldingRules Int16SubOp int16Ops
]
Int16MulOp -> mkPrimOpRule nm 2 [ binaryLit (int16Op2 (*))
, zeroElem
, identity oneI16
, mulFoldingRules Int16MulOp int16Ops
]
Int16QuotOp -> mkPrimOpRule nm 2 [ nonZeroLit 1 >> binaryLit (int16Op2 quot)
, leftZero
, rightIdentity oneI16
, equalArgs $> Lit oneI16 ]
Int16RemOp -> mkPrimOpRule nm 2 [ nonZeroLit 1 >> binaryLit (int16Op2 rem)
, leftZero
, oneLit 1 $> Lit zeroI16
, equalArgs $> Lit zeroI16 ]
Int16NegOp -> mkPrimOpRule nm 1 [ unaryLit negOp
, semiInversePrimOp Int16NegOp ]
Int16SllOp -> mkPrimOpRule nm 2 [ shiftRule LitNumInt16 (const Bits.shiftL)
, rightIdentity zeroI16 ]
Int16SraOp -> mkPrimOpRule nm 2 [ shiftRule LitNumInt16 (const Bits.shiftR)
, rightIdentity zeroI16 ]
Int16SrlOp -> mkPrimOpRule nm 2 [ shiftRule LitNumInt16 $ const $ shiftRightLogical @Word16
, rightIdentity zeroI16 ]
Word16AddOp -> mkPrimOpRule nm 2 [ binaryLit (word16Op2 (+))
, identity zeroW16
, addFoldingRules Word16AddOp word16Ops
]
Word16SubOp -> mkPrimOpRule nm 2 [ binaryLit (word16Op2 ())
, rightIdentity zeroW16
, equalArgs $> Lit zeroW16
, subFoldingRules Word16SubOp word16Ops
]
Word16MulOp -> mkPrimOpRule nm 2 [ binaryLit (word16Op2 (*))
, identity oneW16
, mulFoldingRules Word16MulOp word16Ops
]
Word16QuotOp-> mkPrimOpRule nm 2 [ nonZeroLit 1 >> binaryLit (word16Op2 quot)
, rightIdentity oneW16 ]
Word16RemOp -> mkPrimOpRule nm 2 [ nonZeroLit 1 >> binaryLit (word16Op2 rem)
, leftZero
, oneLit 1 $> Lit zeroW16
, equalArgs $> Lit zeroW16 ]
Word16AndOp -> mkPrimOpRule nm 2 [ binaryLit (word16Op2 (.&.))
, idempotent
, zeroElem ]
Word16OrOp -> mkPrimOpRule nm 2 [ binaryLit (word16Op2 (.|.))
, idempotent
, identity zeroW16 ]
Word16XorOp -> mkPrimOpRule nm 2 [ binaryLit (word16Op2 xor)
, identity zeroW16
, equalArgs $> Lit zeroW16 ]
Word16NotOp -> mkPrimOpRule nm 1 [ unaryLit complementOp
, semiInversePrimOp Word16NotOp ]
Word16SllOp -> mkPrimOpRule nm 2 [ shiftRule LitNumWord (const Bits.shiftL) ]
Word16SrlOp -> mkPrimOpRule nm 2 [ shiftRule LitNumWord $ const $ shiftRightLogical @Word16 ]
Int32AddOp -> mkPrimOpRule nm 2 [ binaryLit (int32Op2 (+))
, identity zeroI32
, addFoldingRules Int32AddOp int32Ops
]
Int32SubOp -> mkPrimOpRule nm 2 [ binaryLit (int32Op2 ())
, rightIdentity zeroI32
, equalArgs $> Lit zeroI32
, subFoldingRules Int32SubOp int32Ops
]
Int32MulOp -> mkPrimOpRule nm 2 [ binaryLit (int32Op2 (*))
, zeroElem
, identity oneI32
, mulFoldingRules Int32MulOp int32Ops
]
Int32QuotOp -> mkPrimOpRule nm 2 [ nonZeroLit 1 >> binaryLit (int32Op2 quot)
, leftZero
, rightIdentity oneI32
, equalArgs $> Lit oneI32 ]
Int32RemOp -> mkPrimOpRule nm 2 [ nonZeroLit 1 >> binaryLit (int32Op2 rem)
, leftZero
, oneLit 1 $> Lit zeroI32
, equalArgs $> Lit zeroI32 ]
Int32NegOp -> mkPrimOpRule nm 1 [ unaryLit negOp
, semiInversePrimOp Int32NegOp ]
Int32SllOp -> mkPrimOpRule nm 2 [ shiftRule LitNumInt32 (const Bits.shiftL)
, rightIdentity zeroI32 ]
Int32SraOp -> mkPrimOpRule nm 2 [ shiftRule LitNumInt32 (const Bits.shiftR)
, rightIdentity zeroI32 ]
Int32SrlOp -> mkPrimOpRule nm 2 [ shiftRule LitNumInt32 $ const $ shiftRightLogical @Word32
, rightIdentity zeroI32 ]
Word32AddOp -> mkPrimOpRule nm 2 [ binaryLit (word32Op2 (+))
, identity zeroW32
, addFoldingRules Word32AddOp word32Ops
]
Word32SubOp -> mkPrimOpRule nm 2 [ binaryLit (word32Op2 ())
, rightIdentity zeroW32
, equalArgs $> Lit zeroW32
, subFoldingRules Word32SubOp word32Ops
]
Word32MulOp -> mkPrimOpRule nm 2 [ binaryLit (word32Op2 (*))
, identity oneW32
, mulFoldingRules Word32MulOp word32Ops
]
Word32QuotOp-> mkPrimOpRule nm 2 [ nonZeroLit 1 >> binaryLit (word32Op2 quot)
, rightIdentity oneW32 ]
Word32RemOp -> mkPrimOpRule nm 2 [ nonZeroLit 1 >> binaryLit (word32Op2 rem)
, leftZero
, oneLit 1 $> Lit zeroW32
, equalArgs $> Lit zeroW32 ]
Word32AndOp -> mkPrimOpRule nm 2 [ binaryLit (word32Op2 (.&.))
, idempotent
, zeroElem ]
Word32OrOp -> mkPrimOpRule nm 2 [ binaryLit (word32Op2 (.|.))
, idempotent
, identity zeroW32 ]
Word32XorOp -> mkPrimOpRule nm 2 [ binaryLit (word32Op2 xor)
, identity zeroW32
, equalArgs $> Lit zeroW32 ]
Word32NotOp -> mkPrimOpRule nm 1 [ unaryLit complementOp
, semiInversePrimOp Word32NotOp ]
Word32SllOp -> mkPrimOpRule nm 2 [ shiftRule LitNumWord (const Bits.shiftL) ]
Word32SrlOp -> mkPrimOpRule nm 2 [ shiftRule LitNumWord $ const $ shiftRightLogical @Word32 ]
IntAddOp -> mkPrimOpRule nm 2 [ binaryLit (intOp2 (+))
, identityPlatform zeroi
, addFoldingRules IntAddOp intOps
]
IntSubOp -> mkPrimOpRule nm 2 [ binaryLit (intOp2 ())
, rightIdentityPlatform zeroi
, equalArgs >> retLit zeroi
, subFoldingRules IntSubOp intOps
]
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
, identityPlatform onei
, mulFoldingRules IntMulOp intOps
]
IntQuotOp -> mkPrimOpRule nm 2 [ nonZeroLit 1 >> binaryLit (intOp2 quot)
, leftZero
, rightIdentityPlatform onei
, equalArgs >> retLit onei ]
IntRemOp -> mkPrimOpRule nm 2 [ nonZeroLit 1 >> binaryLit (intOp2 rem)
, leftZero
, oneLit 1 >> retLit zeroi
, equalArgs >> retLit zeroi ]
IntAndOp -> mkPrimOpRule nm 2 [ binaryLit (intOp2 (.&.))
, idempotent
, zeroElem ]
IntOrOp -> mkPrimOpRule nm 2 [ binaryLit (intOp2 (.|.))
, idempotent
, identityPlatform zeroi ]
IntXorOp -> mkPrimOpRule nm 2 [ binaryLit (intOp2 xor)
, identityPlatform zeroi
, equalArgs >> retLit zeroi ]
IntNotOp -> mkPrimOpRule nm 1 [ unaryLit complementOp
, semiInversePrimOp IntNotOp ]
IntNegOp -> mkPrimOpRule nm 1 [ unaryLit negOp
, semiInversePrimOp IntNegOp ]
IntSllOp -> mkPrimOpRule nm 2 [ shiftRule LitNumInt (const Bits.shiftL)
, rightIdentityPlatform zeroi ]
IntSraOp -> mkPrimOpRule nm 2 [ shiftRule LitNumInt (const Bits.shiftR)
, rightIdentityPlatform zeroi ]
IntSrlOp -> mkPrimOpRule nm 2 [ shiftRule LitNumInt shiftRightLogicalNative
, rightIdentityPlatform zeroi ]
WordAddOp -> mkPrimOpRule nm 2 [ binaryLit (wordOp2 (+))
, identityPlatform zerow
, addFoldingRules WordAddOp wordOps
]
WordSubOp -> mkPrimOpRule nm 2 [ binaryLit (wordOp2 ())
, rightIdentityPlatform zerow
, equalArgs >> retLit zerow
, subFoldingRules WordSubOp wordOps
]
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
, mulFoldingRules WordMulOp wordOps
]
WordQuotOp -> mkPrimOpRule nm 2 [ nonZeroLit 1 >> binaryLit (wordOp2 quot)
, rightIdentityPlatform onew ]
WordRemOp -> mkPrimOpRule nm 2 [ nonZeroLit 1 >> binaryLit (wordOp2 rem)
, leftZero
, oneLit 1 >> retLit zerow
, equalArgs >> retLit zerow ]
WordAndOp -> mkPrimOpRule nm 2 [ binaryLit (wordOp2 (.&.))
, idempotent
, zeroElem ]
WordOrOp -> mkPrimOpRule nm 2 [ binaryLit (wordOp2 (.|.))
, idempotent
, identityPlatform zerow ]
WordXorOp -> mkPrimOpRule nm 2 [ binaryLit (wordOp2 xor)
, identityPlatform zerow
, equalArgs >> retLit zerow ]
WordNotOp -> mkPrimOpRule nm 1 [ unaryLit complementOp
, semiInversePrimOp WordNotOp ]
WordSllOp -> mkPrimOpRule nm 2 [ shiftRule LitNumWord (const Bits.shiftL) ]
WordSrlOp -> mkPrimOpRule nm 2 [ shiftRule LitNumWord shiftRightLogicalNative ]
Int8ToIntOp -> mkPrimOpRule nm 1 [ liftLitPlatform extendIntLit ]
Int16ToIntOp -> mkPrimOpRule nm 1 [ liftLitPlatform extendIntLit ]
Int32ToIntOp -> mkPrimOpRule nm 1 [ liftLitPlatform extendIntLit ]
IntToInt8Op -> mkPrimOpRule nm 1 [ liftLit narrowInt8Lit
, semiInversePrimOp Int8ToIntOp
, narrowSubsumesAnd IntAndOp IntToInt8Op 8 ]
IntToInt16Op -> mkPrimOpRule nm 1 [ liftLit narrowInt16Lit
, semiInversePrimOp Int16ToIntOp
, narrowSubsumesAnd IntAndOp IntToInt16Op 16 ]
IntToInt32Op -> mkPrimOpRule nm 1 [ liftLit narrowInt32Lit
, semiInversePrimOp Int32ToIntOp
, narrowSubsumesAnd IntAndOp IntToInt32Op 32 ]
Word8ToWordOp -> mkPrimOpRule nm 1 [ liftLitPlatform extendWordLit
, extendNarrowPassthrough WordToWord8Op 0xFF
]
Word16ToWordOp -> mkPrimOpRule nm 1 [ liftLitPlatform extendWordLit
, extendNarrowPassthrough WordToWord16Op 0xFFFF
]
Word32ToWordOp -> mkPrimOpRule nm 1 [ liftLitPlatform extendWordLit
, extendNarrowPassthrough WordToWord32Op 0xFFFFFFFF
]
WordToWord8Op -> mkPrimOpRule nm 1 [ liftLit narrowWord8Lit
, semiInversePrimOp Word8ToWordOp
, narrowSubsumesAnd WordAndOp WordToWord8Op 8 ]
WordToWord16Op -> mkPrimOpRule nm 1 [ liftLit narrowWord16Lit
, semiInversePrimOp Word16ToWordOp
, narrowSubsumesAnd WordAndOp WordToWord16Op 16 ]
WordToWord32Op -> mkPrimOpRule nm 1 [ liftLit narrowWord32Lit
, semiInversePrimOp Word32ToWordOp
, narrowSubsumesAnd WordAndOp WordToWord32Op 32 ]
Word8ToInt8Op -> mkPrimOpRule nm 1 [ liftLitPlatform (litNumCoerce LitNumInt8)
, semiInversePrimOp Int8ToWord8Op ]
Int8ToWord8Op -> mkPrimOpRule nm 1 [ liftLitPlatform (litNumCoerce LitNumWord8)
, semiInversePrimOp Word8ToInt8Op ]
Word16ToInt16Op-> mkPrimOpRule nm 1 [ liftLitPlatform (litNumCoerce LitNumInt16)
, semiInversePrimOp Int16ToWord16Op ]
Int16ToWord16Op-> mkPrimOpRule nm 1 [ liftLitPlatform (litNumCoerce LitNumWord16)
, semiInversePrimOp Word16ToInt16Op ]
Word32ToInt32Op-> mkPrimOpRule nm 1 [ liftLitPlatform (litNumCoerce LitNumInt32)
, semiInversePrimOp Int32ToWord32Op ]
Int32ToWord32Op-> mkPrimOpRule nm 1 [ liftLitPlatform (litNumCoerce LitNumWord32)
, semiInversePrimOp Word32ToInt32Op ]
WordToIntOp -> mkPrimOpRule nm 1 [ liftLitPlatform (litNumCoerce LitNumInt)
, semiInversePrimOp IntToWordOp ]
IntToWordOp -> mkPrimOpRule nm 1 [ liftLitPlatform (litNumCoerce LitNumWord)
, semiInversePrimOp WordToIntOp ]
Narrow8IntOp -> mkPrimOpRule nm 1 [ liftLitPlatform (litNumNarrow LitNumInt8)
, subsumedByPrimOp Narrow8IntOp
, Narrow8IntOp `subsumesPrimOp` Narrow16IntOp
, Narrow8IntOp `subsumesPrimOp` Narrow32IntOp
, narrowSubsumesAnd IntAndOp Narrow8IntOp 8 ]
Narrow16IntOp -> mkPrimOpRule nm 1 [ liftLitPlatform (litNumNarrow LitNumInt16)
, subsumedByPrimOp Narrow8IntOp
, subsumedByPrimOp Narrow16IntOp
, Narrow16IntOp `subsumesPrimOp` Narrow32IntOp
, narrowSubsumesAnd IntAndOp Narrow16IntOp 16 ]
Narrow32IntOp -> mkPrimOpRule nm 1 [ liftLitPlatform (litNumNarrow LitNumInt32)
, subsumedByPrimOp Narrow8IntOp
, subsumedByPrimOp Narrow16IntOp
, subsumedByPrimOp Narrow32IntOp
, removeOp32
, narrowSubsumesAnd IntAndOp Narrow32IntOp 32 ]
Narrow8WordOp -> mkPrimOpRule nm 1 [ liftLitPlatform (litNumNarrow LitNumWord8)
, subsumedByPrimOp Narrow8WordOp
, Narrow8WordOp `subsumesPrimOp` Narrow16WordOp
, Narrow8WordOp `subsumesPrimOp` Narrow32WordOp
, narrowSubsumesAnd WordAndOp Narrow8WordOp 8 ]
Narrow16WordOp -> mkPrimOpRule nm 1 [ liftLitPlatform (litNumNarrow LitNumWord16)
, subsumedByPrimOp Narrow8WordOp
, subsumedByPrimOp Narrow16WordOp
, Narrow16WordOp `subsumesPrimOp` Narrow32WordOp
, narrowSubsumesAnd WordAndOp Narrow16WordOp 16 ]
Narrow32WordOp -> mkPrimOpRule nm 1 [ liftLitPlatform (litNumNarrow LitNumWord32)
, subsumedByPrimOp Narrow8WordOp
, subsumedByPrimOp Narrow16WordOp
, subsumedByPrimOp Narrow32WordOp
, removeOp32
, narrowSubsumesAnd WordAndOp Narrow32WordOp 32 ]
OrdOp -> mkPrimOpRule nm 1 [ liftLit charToIntLit
, semiInversePrimOp ChrOp ]
ChrOp -> mkPrimOpRule nm 1 [ do [Lit lit] <- getArgs
guard (litFitsInChar lit)
liftLit intToCharLit
, semiInversePrimOp OrdOp ]
FloatToIntOp -> mkPrimOpRule nm 1 [ liftLit floatToIntLit ]
IntToFloatOp -> mkPrimOpRule nm 1 [ liftLit intToFloatLit ]
DoubleToIntOp -> mkPrimOpRule nm 1 [ liftLit doubleToIntLit ]
IntToDoubleOp -> mkPrimOpRule nm 1 [ liftLit intToDoubleLit ]
FloatToDoubleOp -> mkPrimOpRule nm 1 [ liftLit floatToDoubleLit ]
DoubleToFloatOp -> mkPrimOpRule nm 1 [ liftLit doubleToFloatLit ]
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
, semiInversePrimOp 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
, semiInversePrimOp 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
zeroI8, oneI8, zeroW8, oneW8 :: Literal
zeroI8 = mkLitInt8 0
oneI8 = mkLitInt8 1
zeroW8 = mkLitWord8 0
oneW8 = mkLitWord8 1
zeroI16, oneI16, zeroW16, oneW16 :: Literal
zeroI16 = mkLitInt16 0
oneI16 = mkLitInt16 1
zeroW16 = mkLitWord16 0
oneW16 = mkLitWord16 1
zeroI32, oneI32, zeroW32, oneW32 :: Literal
zeroI32 = mkLitInt32 0
oneI32 = mkLitInt32 1
zeroW32 = mkLitWord32 0
oneW32 = mkLitWord32 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
int8Op2
:: (Integral a, Integral b)
=> (a -> b -> Integer)
-> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
int8Op2 op _ (LitNumber LitNumInt8 i1) (LitNumber LitNumInt8 i2) =
int8Result (fromInteger i1 `op` fromInteger i2)
int8Op2 _ _ _ _ = Nothing
int16Op2
:: (Integral a, Integral b)
=> (a -> b -> Integer)
-> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
int16Op2 op _ (LitNumber LitNumInt16 i1) (LitNumber LitNumInt16 i2) =
int16Result (fromInteger i1 `op` fromInteger i2)
int16Op2 _ _ _ _ = Nothing
int32Op2
:: (Integral a, Integral b)
=> (a -> b -> Integer)
-> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
int32Op2 op _ (LitNumber LitNumInt32 i1) (LitNumber LitNumInt32 i2) =
int32Result (fromInteger i1 `op` fromInteger i2)
int32Op2 _ _ _ _ = 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) =
intCResult (roPlatform env) (fromInteger i1 `op` fromInteger i2)
intOpC2 _ _ _ _ = Nothing
shiftRightLogical :: forall t. (Integral t, Bits t) => Integer -> Int -> Integer
shiftRightLogical x n = fromIntegral (fromInteger x `shiftR` n :: t)
shiftRightLogicalNative :: Platform -> Integer -> Int -> Integer
shiftRightLogicalNative platform =
case platformWordSize platform of
PW4 -> shiftRightLogical @Word32
PW8 -> shiftRightLogical @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)]
word8Op2
:: (Integral a, Integral b)
=> (a -> b -> Integer)
-> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
word8Op2 op _ (LitNumber LitNumWord8 i1) (LitNumber LitNumWord8 i2) =
word8Result (fromInteger i1 `op` fromInteger i2)
word8Op2 _ _ _ _ = Nothing
word16Op2
:: (Integral a, Integral b)
=> (a -> b -> Integer)
-> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
word16Op2 op _ (LitNumber LitNumWord16 i1) (LitNumber LitNumWord16 i2) =
word16Result (fromInteger i1 `op` fromInteger i2)
word16Op2 _ _ _ _ = Nothing
word32Op2
:: (Integral a, Integral b)
=> (a -> b -> Integer)
-> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
word32Op2 op _ (LitNumber LitNumWord32 i1) (LitNumber LitNumWord32 i2) =
word32Result (fromInteger i1 `op` fromInteger i2)
word32Op2 _ _ _ _ = Nothing
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 (toInteger m))
, mkIntVal platform (toInteger e) ]
where
platform = roPlatform env
(iNT64Ty, mkLitINT64)
| platformWordSizeInBits platform < 64
= (int64PrimTy, mkLitInt64Wrap)
| otherwise
= (intPrimTy , mkLitIntWrap platform)
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
[ Alt DEFAULT [] val_if_neq
, Alt (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
int8Result :: Integer -> Maybe CoreExpr
int8Result result = Just (int8Result' result)
int8Result' :: Integer -> CoreExpr
int8Result' result = Lit (mkLitInt8Wrap result)
int16Result :: Integer -> Maybe CoreExpr
int16Result result = Just (int16Result' result)
int16Result' :: Integer -> CoreExpr
int16Result' result = Lit (mkLitInt16Wrap result)
int32Result :: Integer -> Maybe CoreExpr
int32Result result = Just (int32Result' result)
int32Result' :: Integer -> CoreExpr
int32Result' result = Lit (mkLitInt32Wrap result)
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
word8Result :: Integer -> Maybe CoreExpr
word8Result result = Just (word8Result' result)
word8Result' :: Integer -> CoreExpr
word8Result' result = Lit (mkLitWord8Wrap result)
word16Result :: Integer -> Maybe CoreExpr
word16Result result = Just (word16Result' result)
word16Result' :: Integer -> CoreExpr
word16Result' result = Lit (mkLitWord16Wrap result)
word32Result :: Integer -> Maybe CoreExpr
word32Result result = Just (word32Result' result)
word32Result' :: Integer -> CoreExpr
word32Result' result = Lit (mkLitWord32Wrap result)
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
semiInversePrimOp :: PrimOp -> RuleM CoreExpr
semiInversePrimOp 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
extendNarrowPassthrough :: PrimOp -> Integer -> RuleM CoreExpr
extendNarrowPassthrough narrow_primop n = do
[Var primop_id `App` x] <- getArgs
matchPrimOpId narrow_primop primop_id
return (Var (mkPrimOpId WordAndOp) `App` x `App` Lit (LitNumber LitNumWord n))
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 :: RuleM CoreExpr
leftZero = do
[Lit l1, _] <- getArgs
guard $ isZeroLit l1
return $ Lit l1
rightZero :: RuleM CoreExpr
rightZero = do
[_, Lit l2] <- getArgs
guard $ isZeroLit l2
return $ Lit l2
zeroElem :: RuleM CoreExpr
zeroElem = leftZero `mplus` rightZero
equalArgs :: RuleM ()
equalArgs = do
[e1, e2] <- getArgs
guard $ e1 `cheapEqExpr` e2
nonZeroLit :: Int -> RuleM ()
nonZeroLit n = getLiteral n >>= guard . not . isZeroLit
oneLit :: Int -> RuleM ()
oneLit n = getLiteral n >>= guard . isOneLit
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) = splitForAllTyCoVars (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
builtinRules :: [CoreRule]
builtinRules
= [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
, do
[arg, Lit (LitNumber LitNumInt d)] <- getArgs
Just n <- return $ exactLog2 d
platform <- getPlatform
return $ Var (mkPrimOpId IntSraOp) `App` arg `App` mkIntVal platform n
],
mkBasicRule modIntName 2 $ msum
[ nonZeroLit 1 >> binaryLit (intOp2 mod)
, leftZero
, do
[arg, Lit (LitNumber LitNumInt d)] <- getArgs
Just _ <- return $ exactLog2 d
platform <- getPlatform
return $ Var (mkPrimOpId IntAndOp)
`App` arg `App` mkIntVal platform (d 1)
]
]
++ builtinBignumRules
builtinBignumRules :: [CoreRule]
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 [unboxedUnitTy,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 IntToWordOp)
, small_passthrough "Int# -> Integer -> Float#"
integerISDataConName integerToFloatName (mkPrimOpId IntToFloatOp)
, small_passthrough "Int# -> Integer -> Double#"
integerISDataConName integerToDoubleName (mkPrimOpId IntToDoubleOp)
, small_passthrough "Word# -> Natural -> Int#"
naturalNSDataConName naturalToWordName (mkPrimOpId WordToIntOp)
, 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 $ do
env <- getEnv
guard (roBignumRules env)
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
addFoldingRules :: PrimOp -> NumOps -> RuleM CoreExpr
addFoldingRules op num_ops = do
ASSERT(op == numAdd num_ops) return ()
env <- getEnv
guard (roNumConstantFolding env)
[arg1,arg2] <- getArgs
platform <- getPlatform
liftMaybe
(addFoldingRules' platform arg1 arg2 num_ops
<|> addFoldingRules' platform arg2 arg1 num_ops)
subFoldingRules :: PrimOp -> NumOps -> RuleM CoreExpr
subFoldingRules op num_ops = do
ASSERT(op == numSub num_ops) return ()
env <- getEnv
guard (roNumConstantFolding env)
[arg1,arg2] <- getArgs
platform <- getPlatform
liftMaybe (subFoldingRules' platform arg1 arg2 num_ops)
mulFoldingRules :: PrimOp -> NumOps -> RuleM CoreExpr
mulFoldingRules op num_ops = do
ASSERT(op == numMul num_ops) return ()
env <- getEnv
guard (roNumConstantFolding env)
[arg1,arg2] <- getArgs
platform <- getPlatform
liftMaybe
(mulFoldingRules' platform arg1 arg2 num_ops
<|> mulFoldingRules' platform arg2 arg1 num_ops)
addFoldingRules' :: Platform -> CoreExpr -> CoreExpr -> NumOps -> Maybe CoreExpr
addFoldingRules' platform arg1 arg2 num_ops = case (arg1, arg2) of
(L l1, is_lit_add num_ops -> Just (l2,x))
-> Just (mkL (l1+l2) `add` x)
(L l1, is_sub num_ops -> Just (L l2,x))
-> Just (mkL (l1+l2) `sub` x)
(L l1, is_sub num_ops -> Just (x,L l2))
-> Just (mkL (l1l2) `add` x)
(is_lit_add num_ops -> Just (l1,x), is_lit_add num_ops -> Just (l2,y))
-> Just (mkL (l1+l2) `add` (x `add` y))
(is_lit_add num_ops -> Just (l1,x), is_sub num_ops -> Just (L l2,y))
-> Just (mkL (l1+l2) `add` (x `sub` y))
(is_lit_add num_ops -> Just (l1,x), is_sub num_ops -> Just (y,L l2))
-> Just (mkL (l1l2) `add` (x `add` y))
(is_sub num_ops -> Just (L l1,x), is_sub num_ops -> Just (L l2,y))
-> Just (mkL (l1+l2) `sub` (x `add` y))
(is_sub num_ops -> Just (L l1,x), is_sub num_ops -> Just (y,L l2))
-> Just (mkL (l1l2) `add` (y `sub` x))
(is_sub num_ops -> Just (x,L l1), is_sub num_ops -> Just (y,L l2))
-> Just (mkL (0l1l2) `add` (x `add` y))
_ | Just l1 <- is_expr_mul num_ops arg1 arg2
-> Just (mkL (l1+1) `mul` arg1)
_ | Just l1 <- is_expr_mul num_ops arg2 arg1
-> Just (mkL (l1+1) `mul` arg2)
(is_lit_mul num_ops -> Just (l1,x), is_expr_mul num_ops x -> Just l2)
-> Just (mkL (l1+l2) `mul` x)
(_, is_lit_add num_ops -> Just (l1,y))
-> Just (mkL l1 `add` (arg1 `add` y))
(_, is_sub num_ops -> Just (L l1,y))
-> Just (mkL l1 `add` (arg1 `sub` y))
(_, is_sub num_ops -> Just (y,L l1))
-> Just ((arg1 `add` y) `sub` mkL l1)
_ -> Nothing
where
mkL = Lit . mkNumLiteral platform num_ops
add x y = BinOpApp x (numAdd num_ops) y
sub x y = BinOpApp x (numSub num_ops) y
mul x y = BinOpApp x (numMul num_ops) y
subFoldingRules' :: Platform -> CoreExpr -> CoreExpr -> NumOps -> Maybe CoreExpr
subFoldingRules' platform arg1 arg2 num_ops = case (arg1,arg2) of
(L l1, is_lit_add num_ops -> Just (l2,x))
-> Just (mkL (l1l2) `sub` x)
(L l1, is_sub num_ops -> Just (L l2,x))
-> Just (mkL (l1l2) `add` x)
(L l1, is_sub num_ops -> Just (x, L l2))
-> Just (mkL (l1+l2) `sub` x)
(is_lit_add num_ops -> Just (l1,x), L l2)
-> Just (mkL (l1l2) `add` x)
(is_sub num_ops -> Just (L l1,x), L l2)
-> Just (mkL (l1l2) `sub` x)
(is_sub num_ops -> Just (x,L l1), L l2)
-> Just (x `sub` mkL (l1+l2))
(is_lit_add num_ops -> Just (l1,x), is_lit_add num_ops -> Just (l2,y))
-> Just (mkL (l1l2) `add` (x `sub` y))
(is_lit_add num_ops -> Just (l1,x), is_sub num_ops -> Just (L l2,y))
-> Just (mkL (l1l2) `add` (x `add` y))
(is_lit_add num_ops -> Just (l1,x), is_sub num_ops -> Just (y,L l2))
-> Just (mkL (l1+l2) `add` (x `sub` y))
(is_sub num_ops -> Just (L l1,x), is_lit_add num_ops -> Just (l2,y))
-> Just (mkL (l1l2) `sub` (x `add` y))
(is_sub num_ops -> Just (x,L l1), is_lit_add num_ops -> Just (l2,y))
-> Just (mkL (0l1l2) `add` (x `sub` y))
(is_sub num_ops -> Just (L l1,x), is_sub num_ops -> Just (L l2,y))
-> Just (mkL (l1l2) `add` (y `sub` x))
(is_sub num_ops -> Just (L l1,x), is_sub num_ops -> Just (y,L l2))
-> Just (mkL (l1+l2) `sub` (x `add` y))
(is_sub num_ops -> Just (x,L l1), is_sub num_ops -> Just (L l2,y))
-> Just (mkL (0l1l2) `add` (x `add` y))
(is_sub num_ops -> Just (x,L l1), is_sub num_ops -> Just (y,L l2))
-> Just (mkL (l2l1) `add` (x `sub` y))
_ | Just l1 <- is_expr_mul num_ops arg1 arg2
-> Just (mkL (1l1) `mul` arg1)
_ | Just l1 <- is_expr_mul num_ops arg2 arg1
-> Just (mkL (l11) `mul` arg2)
(is_lit_mul num_ops -> Just (l1,x), is_expr_mul num_ops x -> Just l2)
-> Just (mkL (l1l2) `mul` x)
(_, is_lit_add num_ops -> Just (l1,y))
-> Just ((arg1 `sub` y) `sub` mkL l1)
(is_lit_add num_ops -> Just (l1,x), _)
-> Just (mkL l1 `add` (x `sub` arg2))
(_, is_sub num_ops -> Just (L l1,y))
-> Just ((arg1 `add` y) `sub` mkL l1)
(_, is_sub num_ops -> Just (y,L l1))
-> Just (mkL l1 `add` (arg1 `sub` y))
(is_sub num_ops -> Just (L l1,x), _)
-> Just (mkL l1 `sub` (x `add` arg2))
(is_sub num_ops -> Just (x,L l1), _)
-> Just ((x `sub` arg2) `sub` mkL l1)
_ -> Nothing
where
mkL = Lit . mkNumLiteral platform num_ops
add x y = BinOpApp x (numAdd num_ops) y
sub x y = BinOpApp x (numSub num_ops) y
mul x y = BinOpApp x (numMul num_ops) y
mulFoldingRules' :: Platform -> CoreExpr -> CoreExpr -> NumOps -> Maybe CoreExpr
mulFoldingRules' platform arg1 arg2 num_ops = case (arg1,arg2) of
(L l1, is_lit_mul num_ops -> Just (l2,x))
-> Just (mkL (l1*l2) `mul` x)
(L l1, is_lit_add num_ops -> Just (l2,x))
-> Just (mkL (l1*l2) `add` (arg1 `mul` x))
(L l1, is_sub num_ops -> Just (L l2,x))
-> Just (mkL (l1*l2) `sub` (arg1 `mul` x))
(L l1, is_sub num_ops -> Just (x, L l2))
-> Just ((arg1 `mul` x) `sub` mkL (l1*l2))
(is_lit_mul num_ops -> Just (l1,x), is_lit_mul num_ops -> Just (l2,y))
-> Just (mkL (l1*l2) `mul` (x `mul` y))
_ -> Nothing
where
mkL = Lit . mkNumLiteral platform num_ops
add x y = BinOpApp x (numAdd num_ops) y
sub x y = BinOpApp x (numSub num_ops) y
mul x y = BinOpApp x (numMul num_ops) y
is_op :: PrimOp -> CoreExpr -> Maybe (Arg CoreBndr, Arg CoreBndr)
is_op op e = case e of
BinOpApp x op' y | op == op' -> Just (x,y)
_ -> Nothing
is_add, is_sub, is_mul :: NumOps -> CoreExpr -> Maybe (Arg CoreBndr, Arg CoreBndr)
is_add num_ops = is_op (numAdd num_ops)
is_sub num_ops = is_op (numSub num_ops)
is_mul num_ops = is_op (numMul num_ops)
is_lit_add :: NumOps -> CoreExpr -> Maybe (Integer, Arg CoreBndr)
is_lit_add num_ops e = case is_add num_ops e of
Just (L l, x ) -> Just (l,x)
Just (x , L l) -> Just (l,x)
_ -> Nothing
is_lit_mul :: NumOps -> CoreExpr -> Maybe (Integer, Arg CoreBndr)
is_lit_mul num_ops e = case is_mul num_ops e of
Just (L l, x ) -> Just (l,x)
Just (x , L l) -> Just (l,x)
_ -> Nothing
is_expr_mul :: NumOps -> Expr CoreBndr -> Expr CoreBndr -> Maybe Integer
is_expr_mul num_ops x e = if
| x `cheapEqExpr` e
-> Just 1
| Just (k,x') <- is_lit_mul num_ops e
, x `cheapEqExpr` x'
-> return k
| otherwise
-> Nothing
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 i <- Lit (LitNumber _ i)
data NumOps = NumOps
{ numAdd :: !PrimOp
, numSub :: !PrimOp
, numMul :: !PrimOp
, numLitType :: !LitNumType
}
mkNumLiteral :: Platform -> NumOps -> Integer -> Literal
mkNumLiteral platform ops i = mkLitNumberWrap platform (numLitType ops) i
int8Ops :: NumOps
int8Ops = NumOps
{ numAdd = Int8AddOp
, numSub = Int8SubOp
, numMul = Int8MulOp
, numLitType = LitNumInt8
}
word8Ops :: NumOps
word8Ops = NumOps
{ numAdd = Word8AddOp
, numSub = Word8SubOp
, numMul = Word8MulOp
, numLitType = LitNumWord8
}
int16Ops :: NumOps
int16Ops = NumOps
{ numAdd = Int16AddOp
, numSub = Int16SubOp
, numMul = Int16MulOp
, numLitType = LitNumInt16
}
word16Ops :: NumOps
word16Ops = NumOps
{ numAdd = Word16AddOp
, numSub = Word16SubOp
, numMul = Word16MulOp
, numLitType = LitNumWord16
}
int32Ops :: NumOps
int32Ops = NumOps
{ numAdd = Int32AddOp
, numSub = Int32SubOp
, numMul = Int32MulOp
, numLitType = LitNumInt32
}
word32Ops :: NumOps
word32Ops = NumOps
{ numAdd = Word32AddOp
, numSub = Word32SubOp
, numMul = Word32MulOp
, numLitType = LitNumWord32
}
intOps :: NumOps
intOps = NumOps
{ numAdd = IntAddOp
, numSub = IntSubOp
, numMul = IntMulOp
, numLitType = LitNumInt
}
wordOps :: NumOps
wordOps = NumOps
{ numAdd = WordAddOp
, numSub = WordSubOp
, numMul = WordMulOp
, numLitType = LitNumWord
}
caseRules :: Platform
-> CoreExpr
-> Maybe ( CoreExpr
, AltCon -> Maybe AltCon
, Id -> CoreExpr)
caseRules platform (App (App (Var f) v) (Lit l))
| Just op <- isPrimOpId_maybe f
, LitNumber _ x <- 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
, LitNumber _ x <- 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 )
WordXorOp -> Just (\y -> y `xor` lit)
IntXorOp -> 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 )
WordXorOp -> Just (\y -> y `xor` lit)
IntXorOp -> Just (\y -> y `xor` lit)
_ -> Nothing
adjustUnary :: PrimOp -> Maybe (Integer -> Integer)
adjustUnary op
= case op of
WordNotOp -> Just (\y -> complement y)
IntNotOp -> 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)