{-
(c) The GRASP/AQUA Project, Glasgow University, 1992-1998

Conceptually, constant folding should be parameterized with the kind
of target machine to get identical behaviour during compilation time
and runtime. We cheat a little bit here...

ToDo:
   check boundaries before folding, e.g. we can fold the Float addition
   (i1 + i2) only if it results in a valid Float.
-}

{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE MultiWayIf #-}
{-# LANGUAGE PatternSynonyms #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE ViewPatterns #-}

{-# OPTIONS_GHC -optc-DNON_POSIX_SOURCE -Wno-incomplete-uni-patterns #-}

-- | Constant Folder
module GHC.Core.Opt.ConstantFold
   ( primOpRules
   , builtinRules
   , caseRules
   )
where

#include "HsVersions.h"
#include "MachDeps.h"

import GHC.Prelude

import GHC.Driver.Ppr

import {-# SOURCE #-} 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, stripTicksE )
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 qualified Data.ByteString as BS
import Data.Ratio
import Data.Word
import Data.Maybe (fromMaybe)

{-
Note [Constant folding]
~~~~~~~~~~~~~~~~~~~~~~~
primOpRules generates a rewrite rule for each primop
These rules do what is often called "constant folding"
E.g. the rules for +# might say
        4 +# 5 = 9
Well, of course you'd need a lot of rules if you did it
like that, so we use a BuiltinRule instead, so that we
can match in any two literal values.  So the rule is really
more like
        (Lit x) +# (Lit y) = Lit (x+#y)
where the (+#) on the rhs is done at compile time

That is why these rules are built in here.
-}

primOpRules ::  Name -> PrimOp -> Maybe CoreRule
primOpRules :: Name -> PrimOp -> Maybe CoreRule
primOpRules Name
nm = \case
   PrimOp
TagToEnumOp -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
2 [ RuleM CoreExpr
tagToEnumRule ]
   PrimOp
DataToTagOp -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
2 [ RuleM CoreExpr
dataToTagRule ]

   -- Int8 operations
   PrimOp
Int8AddOp   -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
2 [ (RuleOpts -> Literal -> Literal -> Maybe CoreExpr)
-> RuleM CoreExpr
binaryLit (forall a b.
(Integral a, Integral b) =>
(a -> b -> Integer)
-> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
int8Op2 forall a. Num a => a -> a -> a
(+))
                                    , Literal -> RuleM CoreExpr
identity Literal
zeroI8
                                    , PrimOp -> NumOps -> RuleM CoreExpr
addFoldingRules PrimOp
Int8AddOp NumOps
int8Ops
                                    ]
   PrimOp
Int8SubOp   -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
2 [ (RuleOpts -> Literal -> Literal -> Maybe CoreExpr)
-> RuleM CoreExpr
binaryLit (forall a b.
(Integral a, Integral b) =>
(a -> b -> Integer)
-> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
int8Op2 (-))
                                    , Literal -> RuleM CoreExpr
rightIdentity Literal
zeroI8
                                    , RuleM ()
equalArgs forall (f :: * -> *) a b. Functor f => f a -> b -> f b
$> forall b. Literal -> Expr b
Lit Literal
zeroI8
                                    , PrimOp -> NumOps -> RuleM CoreExpr
subFoldingRules PrimOp
Int8SubOp NumOps
int8Ops
                                    ]
   PrimOp
Int8MulOp   -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
2 [ (RuleOpts -> Literal -> Literal -> Maybe CoreExpr)
-> RuleM CoreExpr
binaryLit (forall a b.
(Integral a, Integral b) =>
(a -> b -> Integer)
-> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
int8Op2 forall a. Num a => a -> a -> a
(*))
                                    , RuleM CoreExpr
zeroElem
                                    , Literal -> RuleM CoreExpr
identity Literal
oneI8
                                    , PrimOp -> NumOps -> RuleM CoreExpr
mulFoldingRules PrimOp
Int8MulOp NumOps
int8Ops
                                    ]
   PrimOp
Int8QuotOp  -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
2 [ ConTagZ -> RuleM ()
nonZeroLit ConTagZ
1 forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> (RuleOpts -> Literal -> Literal -> Maybe CoreExpr)
-> RuleM CoreExpr
binaryLit (forall a b.
(Integral a, Integral b) =>
(a -> b -> Integer)
-> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
int8Op2 forall a. Integral a => a -> a -> a
quot)
                                    , RuleM CoreExpr
leftZero
                                    , Literal -> RuleM CoreExpr
rightIdentity Literal
oneI8
                                    , RuleM ()
equalArgs forall (f :: * -> *) a b. Functor f => f a -> b -> f b
$> forall b. Literal -> Expr b
Lit Literal
oneI8 ]
   PrimOp
Int8RemOp   -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
2 [ ConTagZ -> RuleM ()
nonZeroLit ConTagZ
1 forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> (RuleOpts -> Literal -> Literal -> Maybe CoreExpr)
-> RuleM CoreExpr
binaryLit (forall a b.
(Integral a, Integral b) =>
(a -> b -> Integer)
-> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
int8Op2 forall a. Integral a => a -> a -> a
rem)
                                    , RuleM CoreExpr
leftZero
                                    , ConTagZ -> RuleM ()
oneLit ConTagZ
1 forall (f :: * -> *) a b. Functor f => f a -> b -> f b
$> forall b. Literal -> Expr b
Lit Literal
zeroI8
                                    , RuleM ()
equalArgs forall (f :: * -> *) a b. Functor f => f a -> b -> f b
$> forall b. Literal -> Expr b
Lit Literal
zeroI8 ]
   PrimOp
Int8NegOp   -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
1 [ (RuleOpts -> Literal -> Maybe CoreExpr) -> RuleM CoreExpr
unaryLit RuleOpts -> Literal -> Maybe CoreExpr
negOp
                                    , PrimOp -> RuleM CoreExpr
semiInversePrimOp PrimOp
Int8NegOp ]
   PrimOp
Int8SllOp   -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
2 [ LitNumType
-> (Platform -> Integer -> ConTagZ -> Integer) -> RuleM CoreExpr
shiftRule LitNumType
LitNumInt8 (forall a b. a -> b -> a
const forall a. Bits a => a -> ConTagZ -> a
shiftL)
                                    , Literal -> RuleM CoreExpr
rightIdentity Literal
zeroI8 ]
   PrimOp
Int8SraOp   -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
2 [ LitNumType
-> (Platform -> Integer -> ConTagZ -> Integer) -> RuleM CoreExpr
shiftRule LitNumType
LitNumInt8 (forall a b. a -> b -> a
const forall a. Bits a => a -> ConTagZ -> a
shiftR)
                                    , Literal -> RuleM CoreExpr
rightIdentity Literal
zeroI8 ]
   PrimOp
Int8SrlOp   -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
2 [ LitNumType
-> (Platform -> Integer -> ConTagZ -> Integer) -> RuleM CoreExpr
shiftRule LitNumType
LitNumInt8 forall a b. (a -> b) -> a -> b
$ forall a b. a -> b -> a
const forall a b. (a -> b) -> a -> b
$ forall t. (Integral t, Bits t) => Integer -> ConTagZ -> Integer
shiftRightLogical @Word8
                                    , Literal -> RuleM CoreExpr
rightIdentity Literal
zeroI8 ]

   -- Word8 operations
   PrimOp
Word8AddOp  -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
2 [ (RuleOpts -> Literal -> Literal -> Maybe CoreExpr)
-> RuleM CoreExpr
binaryLit (forall a b.
(Integral a, Integral b) =>
(a -> b -> Integer)
-> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
word8Op2 forall a. Num a => a -> a -> a
(+))
                                    , Literal -> RuleM CoreExpr
identity Literal
zeroW8
                                    , PrimOp -> NumOps -> RuleM CoreExpr
addFoldingRules PrimOp
Word8AddOp NumOps
word8Ops
                                    ]
   PrimOp
Word8SubOp  -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
2 [ (RuleOpts -> Literal -> Literal -> Maybe CoreExpr)
-> RuleM CoreExpr
binaryLit (forall a b.
(Integral a, Integral b) =>
(a -> b -> Integer)
-> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
word8Op2 (-))
                                    , Literal -> RuleM CoreExpr
rightIdentity Literal
zeroW8
                                    , RuleM ()
equalArgs forall (f :: * -> *) a b. Functor f => f a -> b -> f b
$> forall b. Literal -> Expr b
Lit Literal
zeroW8
                                    , PrimOp -> NumOps -> RuleM CoreExpr
subFoldingRules PrimOp
Word8SubOp NumOps
word8Ops
                                    ]
   PrimOp
Word8MulOp  -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
2 [ (RuleOpts -> Literal -> Literal -> Maybe CoreExpr)
-> RuleM CoreExpr
binaryLit (forall a b.
(Integral a, Integral b) =>
(a -> b -> Integer)
-> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
word8Op2 forall a. Num a => a -> a -> a
(*))
                                    , Literal -> RuleM CoreExpr
identity Literal
oneW8
                                    , PrimOp -> NumOps -> RuleM CoreExpr
mulFoldingRules PrimOp
Word8MulOp NumOps
word8Ops
                                    ]
   PrimOp
Word8QuotOp -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
2 [ ConTagZ -> RuleM ()
nonZeroLit ConTagZ
1 forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> (RuleOpts -> Literal -> Literal -> Maybe CoreExpr)
-> RuleM CoreExpr
binaryLit (forall a b.
(Integral a, Integral b) =>
(a -> b -> Integer)
-> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
word8Op2 forall a. Integral a => a -> a -> a
quot)
                                    , Literal -> RuleM CoreExpr
rightIdentity Literal
oneW8 ]
   PrimOp
Word8RemOp  -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
2 [ ConTagZ -> RuleM ()
nonZeroLit ConTagZ
1 forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> (RuleOpts -> Literal -> Literal -> Maybe CoreExpr)
-> RuleM CoreExpr
binaryLit (forall a b.
(Integral a, Integral b) =>
(a -> b -> Integer)
-> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
word8Op2 forall a. Integral a => a -> a -> a
rem)
                                    , RuleM CoreExpr
leftZero
                                    , ConTagZ -> RuleM ()
oneLit ConTagZ
1 forall (f :: * -> *) a b. Functor f => f a -> b -> f b
$> forall b. Literal -> Expr b
Lit Literal
zeroW8
                                    , RuleM ()
equalArgs forall (f :: * -> *) a b. Functor f => f a -> b -> f b
$> forall b. Literal -> Expr b
Lit Literal
zeroW8 ]
   PrimOp
Word8AndOp  -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
2 [ (RuleOpts -> Literal -> Literal -> Maybe CoreExpr)
-> RuleM CoreExpr
binaryLit (forall a b.
(Integral a, Integral b) =>
(a -> b -> Integer)
-> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
word8Op2 forall a. Bits a => a -> a -> a
(.&.))
                                    , RuleM CoreExpr
idempotent
                                    , RuleM CoreExpr
zeroElem
                                    , PrimOp -> RuleM CoreExpr
sameArgIdempotentCommut PrimOp
Word8AndOp
                                    ]
   PrimOp
Word8OrOp   -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
2 [ (RuleOpts -> Literal -> Literal -> Maybe CoreExpr)
-> RuleM CoreExpr
binaryLit (forall a b.
(Integral a, Integral b) =>
(a -> b -> Integer)
-> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
word8Op2 forall a. Bits a => a -> a -> a
(.|.))
                                    , RuleM CoreExpr
idempotent
                                    , Literal -> RuleM CoreExpr
identity Literal
zeroW8
                                    , PrimOp -> RuleM CoreExpr
sameArgIdempotentCommut PrimOp
Word8OrOp
                                    ]
   PrimOp
Word8XorOp  -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
2 [ (RuleOpts -> Literal -> Literal -> Maybe CoreExpr)
-> RuleM CoreExpr
binaryLit (forall a b.
(Integral a, Integral b) =>
(a -> b -> Integer)
-> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
word8Op2 forall a. Bits a => a -> a -> a
xor)
                                    , Literal -> RuleM CoreExpr
identity Literal
zeroW8
                                    , RuleM ()
equalArgs forall (f :: * -> *) a b. Functor f => f a -> b -> f b
$> forall b. Literal -> Expr b
Lit Literal
zeroW8 ]
   PrimOp
Word8NotOp  -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
1 [ (RuleOpts -> Literal -> Maybe CoreExpr) -> RuleM CoreExpr
unaryLit RuleOpts -> Literal -> Maybe CoreExpr
complementOp
                                    , PrimOp -> RuleM CoreExpr
semiInversePrimOp PrimOp
Word8NotOp ]
   PrimOp
Word8SllOp  -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
2 [ LitNumType
-> (Platform -> Integer -> ConTagZ -> Integer) -> RuleM CoreExpr
shiftRule LitNumType
LitNumWord (forall a b. a -> b -> a
const forall a. Bits a => a -> ConTagZ -> a
shiftL) ]
   PrimOp
Word8SrlOp  -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
2 [ LitNumType
-> (Platform -> Integer -> ConTagZ -> Integer) -> RuleM CoreExpr
shiftRule LitNumType
LitNumWord forall a b. (a -> b) -> a -> b
$ forall a b. a -> b -> a
const forall a b. (a -> b) -> a -> b
$ forall t. (Integral t, Bits t) => Integer -> ConTagZ -> Integer
shiftRightLogical @Word8 ]


   -- Int16 operations
   PrimOp
Int16AddOp  -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
2 [ (RuleOpts -> Literal -> Literal -> Maybe CoreExpr)
-> RuleM CoreExpr
binaryLit (forall a b.
(Integral a, Integral b) =>
(a -> b -> Integer)
-> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
int16Op2 forall a. Num a => a -> a -> a
(+))
                                    , Literal -> RuleM CoreExpr
identity Literal
zeroI16
                                    , PrimOp -> NumOps -> RuleM CoreExpr
addFoldingRules PrimOp
Int16AddOp NumOps
int16Ops
                                    ]
   PrimOp
Int16SubOp  -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
2 [ (RuleOpts -> Literal -> Literal -> Maybe CoreExpr)
-> RuleM CoreExpr
binaryLit (forall a b.
(Integral a, Integral b) =>
(a -> b -> Integer)
-> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
int16Op2 (-))
                                    , Literal -> RuleM CoreExpr
rightIdentity Literal
zeroI16
                                    , RuleM ()
equalArgs forall (f :: * -> *) a b. Functor f => f a -> b -> f b
$> forall b. Literal -> Expr b
Lit Literal
zeroI16
                                    , PrimOp -> NumOps -> RuleM CoreExpr
subFoldingRules PrimOp
Int16SubOp NumOps
int16Ops
                                    ]
   PrimOp
Int16MulOp  -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
2 [ (RuleOpts -> Literal -> Literal -> Maybe CoreExpr)
-> RuleM CoreExpr
binaryLit (forall a b.
(Integral a, Integral b) =>
(a -> b -> Integer)
-> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
int16Op2 forall a. Num a => a -> a -> a
(*))
                                    , RuleM CoreExpr
zeroElem
                                    , Literal -> RuleM CoreExpr
identity Literal
oneI16
                                    , PrimOp -> NumOps -> RuleM CoreExpr
mulFoldingRules PrimOp
Int16MulOp NumOps
int16Ops
                                    ]
   PrimOp
Int16QuotOp -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
2 [ ConTagZ -> RuleM ()
nonZeroLit ConTagZ
1 forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> (RuleOpts -> Literal -> Literal -> Maybe CoreExpr)
-> RuleM CoreExpr
binaryLit (forall a b.
(Integral a, Integral b) =>
(a -> b -> Integer)
-> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
int16Op2 forall a. Integral a => a -> a -> a
quot)
                                    , RuleM CoreExpr
leftZero
                                    , Literal -> RuleM CoreExpr
rightIdentity Literal
oneI16
                                    , RuleM ()
equalArgs forall (f :: * -> *) a b. Functor f => f a -> b -> f b
$> forall b. Literal -> Expr b
Lit Literal
oneI16 ]
   PrimOp
Int16RemOp  -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
2 [ ConTagZ -> RuleM ()
nonZeroLit ConTagZ
1 forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> (RuleOpts -> Literal -> Literal -> Maybe CoreExpr)
-> RuleM CoreExpr
binaryLit (forall a b.
(Integral a, Integral b) =>
(a -> b -> Integer)
-> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
int16Op2 forall a. Integral a => a -> a -> a
rem)
                                    , RuleM CoreExpr
leftZero
                                    , ConTagZ -> RuleM ()
oneLit ConTagZ
1 forall (f :: * -> *) a b. Functor f => f a -> b -> f b
$> forall b. Literal -> Expr b
Lit Literal
zeroI16
                                    , RuleM ()
equalArgs forall (f :: * -> *) a b. Functor f => f a -> b -> f b
$> forall b. Literal -> Expr b
Lit Literal
zeroI16 ]
   PrimOp
Int16NegOp  -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
1 [ (RuleOpts -> Literal -> Maybe CoreExpr) -> RuleM CoreExpr
unaryLit RuleOpts -> Literal -> Maybe CoreExpr
negOp
                                    , PrimOp -> RuleM CoreExpr
semiInversePrimOp PrimOp
Int16NegOp ]
   PrimOp
Int16SllOp  -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
2 [ LitNumType
-> (Platform -> Integer -> ConTagZ -> Integer) -> RuleM CoreExpr
shiftRule LitNumType
LitNumInt16 (forall a b. a -> b -> a
const forall a. Bits a => a -> ConTagZ -> a
shiftL)
                                    , Literal -> RuleM CoreExpr
rightIdentity Literal
zeroI16 ]
   PrimOp
Int16SraOp  -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
2 [ LitNumType
-> (Platform -> Integer -> ConTagZ -> Integer) -> RuleM CoreExpr
shiftRule LitNumType
LitNumInt16 (forall a b. a -> b -> a
const forall a. Bits a => a -> ConTagZ -> a
shiftR)
                                    , Literal -> RuleM CoreExpr
rightIdentity Literal
zeroI16 ]
   PrimOp
Int16SrlOp  -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
2 [ LitNumType
-> (Platform -> Integer -> ConTagZ -> Integer) -> RuleM CoreExpr
shiftRule LitNumType
LitNumInt16 forall a b. (a -> b) -> a -> b
$ forall a b. a -> b -> a
const forall a b. (a -> b) -> a -> b
$ forall t. (Integral t, Bits t) => Integer -> ConTagZ -> Integer
shiftRightLogical @Word16
                                    , Literal -> RuleM CoreExpr
rightIdentity Literal
zeroI16 ]

   -- Word16 operations
   PrimOp
Word16AddOp -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
2 [ (RuleOpts -> Literal -> Literal -> Maybe CoreExpr)
-> RuleM CoreExpr
binaryLit (forall a b.
(Integral a, Integral b) =>
(a -> b -> Integer)
-> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
word16Op2 forall a. Num a => a -> a -> a
(+))
                                    , Literal -> RuleM CoreExpr
identity Literal
zeroW16
                                    , PrimOp -> NumOps -> RuleM CoreExpr
addFoldingRules PrimOp
Word16AddOp NumOps
word16Ops
                                    ]
   PrimOp
Word16SubOp -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
2 [ (RuleOpts -> Literal -> Literal -> Maybe CoreExpr)
-> RuleM CoreExpr
binaryLit (forall a b.
(Integral a, Integral b) =>
(a -> b -> Integer)
-> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
word16Op2 (-))
                                    , Literal -> RuleM CoreExpr
rightIdentity Literal
zeroW16
                                    , RuleM ()
equalArgs forall (f :: * -> *) a b. Functor f => f a -> b -> f b
$> forall b. Literal -> Expr b
Lit Literal
zeroW16
                                    , PrimOp -> NumOps -> RuleM CoreExpr
subFoldingRules PrimOp
Word16SubOp NumOps
word16Ops
                                    ]
   PrimOp
Word16MulOp -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
2 [ (RuleOpts -> Literal -> Literal -> Maybe CoreExpr)
-> RuleM CoreExpr
binaryLit (forall a b.
(Integral a, Integral b) =>
(a -> b -> Integer)
-> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
word16Op2 forall a. Num a => a -> a -> a
(*))
                                    , Literal -> RuleM CoreExpr
identity Literal
oneW16
                                    , PrimOp -> NumOps -> RuleM CoreExpr
mulFoldingRules PrimOp
Word16MulOp NumOps
word16Ops
                                    ]
   PrimOp
Word16QuotOp-> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
2 [ ConTagZ -> RuleM ()
nonZeroLit ConTagZ
1 forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> (RuleOpts -> Literal -> Literal -> Maybe CoreExpr)
-> RuleM CoreExpr
binaryLit (forall a b.
(Integral a, Integral b) =>
(a -> b -> Integer)
-> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
word16Op2 forall a. Integral a => a -> a -> a
quot)
                                    , Literal -> RuleM CoreExpr
rightIdentity Literal
oneW16 ]
   PrimOp
Word16RemOp -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
2 [ ConTagZ -> RuleM ()
nonZeroLit ConTagZ
1 forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> (RuleOpts -> Literal -> Literal -> Maybe CoreExpr)
-> RuleM CoreExpr
binaryLit (forall a b.
(Integral a, Integral b) =>
(a -> b -> Integer)
-> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
word16Op2 forall a. Integral a => a -> a -> a
rem)
                                    , RuleM CoreExpr
leftZero
                                    , ConTagZ -> RuleM ()
oneLit ConTagZ
1 forall (f :: * -> *) a b. Functor f => f a -> b -> f b
$> forall b. Literal -> Expr b
Lit Literal
zeroW16
                                    , RuleM ()
equalArgs forall (f :: * -> *) a b. Functor f => f a -> b -> f b
$> forall b. Literal -> Expr b
Lit Literal
zeroW16 ]
   PrimOp
Word16AndOp -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
2 [ (RuleOpts -> Literal -> Literal -> Maybe CoreExpr)
-> RuleM CoreExpr
binaryLit (forall a b.
(Integral a, Integral b) =>
(a -> b -> Integer)
-> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
word16Op2 forall a. Bits a => a -> a -> a
(.&.))
                                    , RuleM CoreExpr
idempotent
                                    , RuleM CoreExpr
zeroElem
                                    , PrimOp -> RuleM CoreExpr
sameArgIdempotentCommut PrimOp
Word16AndOp
                                    ]
   PrimOp
Word16OrOp  -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
2 [ (RuleOpts -> Literal -> Literal -> Maybe CoreExpr)
-> RuleM CoreExpr
binaryLit (forall a b.
(Integral a, Integral b) =>
(a -> b -> Integer)
-> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
word16Op2 forall a. Bits a => a -> a -> a
(.|.))
                                    , RuleM CoreExpr
idempotent
                                    , Literal -> RuleM CoreExpr
identity Literal
zeroW16
                                    , PrimOp -> RuleM CoreExpr
sameArgIdempotentCommut PrimOp
Word16OrOp
                                    ]
   PrimOp
Word16XorOp -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
2 [ (RuleOpts -> Literal -> Literal -> Maybe CoreExpr)
-> RuleM CoreExpr
binaryLit (forall a b.
(Integral a, Integral b) =>
(a -> b -> Integer)
-> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
word16Op2 forall a. Bits a => a -> a -> a
xor)
                                    , Literal -> RuleM CoreExpr
identity Literal
zeroW16
                                    , RuleM ()
equalArgs forall (f :: * -> *) a b. Functor f => f a -> b -> f b
$> forall b. Literal -> Expr b
Lit Literal
zeroW16 ]
   PrimOp
Word16NotOp -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
1 [ (RuleOpts -> Literal -> Maybe CoreExpr) -> RuleM CoreExpr
unaryLit RuleOpts -> Literal -> Maybe CoreExpr
complementOp
                                    , PrimOp -> RuleM CoreExpr
semiInversePrimOp PrimOp
Word16NotOp ]
   PrimOp
Word16SllOp -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
2 [ LitNumType
-> (Platform -> Integer -> ConTagZ -> Integer) -> RuleM CoreExpr
shiftRule LitNumType
LitNumWord (forall a b. a -> b -> a
const forall a. Bits a => a -> ConTagZ -> a
shiftL) ]
   PrimOp
Word16SrlOp -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
2 [ LitNumType
-> (Platform -> Integer -> ConTagZ -> Integer) -> RuleM CoreExpr
shiftRule LitNumType
LitNumWord forall a b. (a -> b) -> a -> b
$ forall a b. a -> b -> a
const forall a b. (a -> b) -> a -> b
$ forall t. (Integral t, Bits t) => Integer -> ConTagZ -> Integer
shiftRightLogical @Word16 ]


   -- Int32 operations
   PrimOp
Int32AddOp  -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
2 [ (RuleOpts -> Literal -> Literal -> Maybe CoreExpr)
-> RuleM CoreExpr
binaryLit (forall a b.
(Integral a, Integral b) =>
(a -> b -> Integer)
-> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
int32Op2 forall a. Num a => a -> a -> a
(+))
                                    , Literal -> RuleM CoreExpr
identity Literal
zeroI32
                                    , PrimOp -> NumOps -> RuleM CoreExpr
addFoldingRules PrimOp
Int32AddOp NumOps
int32Ops
                                    ]
   PrimOp
Int32SubOp  -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
2 [ (RuleOpts -> Literal -> Literal -> Maybe CoreExpr)
-> RuleM CoreExpr
binaryLit (forall a b.
(Integral a, Integral b) =>
(a -> b -> Integer)
-> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
int32Op2 (-))
                                    , Literal -> RuleM CoreExpr
rightIdentity Literal
zeroI32
                                    , RuleM ()
equalArgs forall (f :: * -> *) a b. Functor f => f a -> b -> f b
$> forall b. Literal -> Expr b
Lit Literal
zeroI32
                                    , PrimOp -> NumOps -> RuleM CoreExpr
subFoldingRules PrimOp
Int32SubOp NumOps
int32Ops
                                    ]
   PrimOp
Int32MulOp  -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
2 [ (RuleOpts -> Literal -> Literal -> Maybe CoreExpr)
-> RuleM CoreExpr
binaryLit (forall a b.
(Integral a, Integral b) =>
(a -> b -> Integer)
-> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
int32Op2 forall a. Num a => a -> a -> a
(*))
                                    , RuleM CoreExpr
zeroElem
                                    , Literal -> RuleM CoreExpr
identity Literal
oneI32
                                    , PrimOp -> NumOps -> RuleM CoreExpr
mulFoldingRules PrimOp
Int32MulOp NumOps
int32Ops
                                    ]
   PrimOp
Int32QuotOp -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
2 [ ConTagZ -> RuleM ()
nonZeroLit ConTagZ
1 forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> (RuleOpts -> Literal -> Literal -> Maybe CoreExpr)
-> RuleM CoreExpr
binaryLit (forall a b.
(Integral a, Integral b) =>
(a -> b -> Integer)
-> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
int32Op2 forall a. Integral a => a -> a -> a
quot)
                                    , RuleM CoreExpr
leftZero
                                    , Literal -> RuleM CoreExpr
rightIdentity Literal
oneI32
                                    , RuleM ()
equalArgs forall (f :: * -> *) a b. Functor f => f a -> b -> f b
$> forall b. Literal -> Expr b
Lit Literal
oneI32 ]
   PrimOp
Int32RemOp  -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
2 [ ConTagZ -> RuleM ()
nonZeroLit ConTagZ
1 forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> (RuleOpts -> Literal -> Literal -> Maybe CoreExpr)
-> RuleM CoreExpr
binaryLit (forall a b.
(Integral a, Integral b) =>
(a -> b -> Integer)
-> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
int32Op2 forall a. Integral a => a -> a -> a
rem)
                                    , RuleM CoreExpr
leftZero
                                    , ConTagZ -> RuleM ()
oneLit ConTagZ
1 forall (f :: * -> *) a b. Functor f => f a -> b -> f b
$> forall b. Literal -> Expr b
Lit Literal
zeroI32
                                    , RuleM ()
equalArgs forall (f :: * -> *) a b. Functor f => f a -> b -> f b
$> forall b. Literal -> Expr b
Lit Literal
zeroI32 ]
   PrimOp
Int32NegOp  -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
1 [ (RuleOpts -> Literal -> Maybe CoreExpr) -> RuleM CoreExpr
unaryLit RuleOpts -> Literal -> Maybe CoreExpr
negOp
                                    , PrimOp -> RuleM CoreExpr
semiInversePrimOp PrimOp
Int32NegOp ]
   PrimOp
Int32SllOp  -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
2 [ LitNumType
-> (Platform -> Integer -> ConTagZ -> Integer) -> RuleM CoreExpr
shiftRule LitNumType
LitNumInt32 (forall a b. a -> b -> a
const forall a. Bits a => a -> ConTagZ -> a
shiftL)
                                    , Literal -> RuleM CoreExpr
rightIdentity Literal
zeroI32 ]
   PrimOp
Int32SraOp  -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
2 [ LitNumType
-> (Platform -> Integer -> ConTagZ -> Integer) -> RuleM CoreExpr
shiftRule LitNumType
LitNumInt32 (forall a b. a -> b -> a
const forall a. Bits a => a -> ConTagZ -> a
shiftR)
                                    , Literal -> RuleM CoreExpr
rightIdentity Literal
zeroI32 ]
   PrimOp
Int32SrlOp  -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
2 [ LitNumType
-> (Platform -> Integer -> ConTagZ -> Integer) -> RuleM CoreExpr
shiftRule LitNumType
LitNumInt32 forall a b. (a -> b) -> a -> b
$ forall a b. a -> b -> a
const forall a b. (a -> b) -> a -> b
$ forall t. (Integral t, Bits t) => Integer -> ConTagZ -> Integer
shiftRightLogical @Word32
                                    , Literal -> RuleM CoreExpr
rightIdentity Literal
zeroI32 ]

   -- Word32 operations
   PrimOp
Word32AddOp -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
2 [ (RuleOpts -> Literal -> Literal -> Maybe CoreExpr)
-> RuleM CoreExpr
binaryLit (forall a b.
(Integral a, Integral b) =>
(a -> b -> Integer)
-> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
word32Op2 forall a. Num a => a -> a -> a
(+))
                                    , Literal -> RuleM CoreExpr
identity Literal
zeroW32
                                    , PrimOp -> NumOps -> RuleM CoreExpr
addFoldingRules PrimOp
Word32AddOp NumOps
word32Ops
                                    ]
   PrimOp
Word32SubOp -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
2 [ (RuleOpts -> Literal -> Literal -> Maybe CoreExpr)
-> RuleM CoreExpr
binaryLit (forall a b.
(Integral a, Integral b) =>
(a -> b -> Integer)
-> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
word32Op2 (-))
                                    , Literal -> RuleM CoreExpr
rightIdentity Literal
zeroW32
                                    , RuleM ()
equalArgs forall (f :: * -> *) a b. Functor f => f a -> b -> f b
$> forall b. Literal -> Expr b
Lit Literal
zeroW32
                                    , PrimOp -> NumOps -> RuleM CoreExpr
subFoldingRules PrimOp
Word32SubOp NumOps
word32Ops
                                    ]
   PrimOp
Word32MulOp -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
2 [ (RuleOpts -> Literal -> Literal -> Maybe CoreExpr)
-> RuleM CoreExpr
binaryLit (forall a b.
(Integral a, Integral b) =>
(a -> b -> Integer)
-> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
word32Op2 forall a. Num a => a -> a -> a
(*))
                                    , Literal -> RuleM CoreExpr
identity Literal
oneW32
                                    , PrimOp -> NumOps -> RuleM CoreExpr
mulFoldingRules PrimOp
Word32MulOp NumOps
word32Ops
                                    ]
   PrimOp
Word32QuotOp-> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
2 [ ConTagZ -> RuleM ()
nonZeroLit ConTagZ
1 forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> (RuleOpts -> Literal -> Literal -> Maybe CoreExpr)
-> RuleM CoreExpr
binaryLit (forall a b.
(Integral a, Integral b) =>
(a -> b -> Integer)
-> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
word32Op2 forall a. Integral a => a -> a -> a
quot)
                                    , Literal -> RuleM CoreExpr
rightIdentity Literal
oneW32 ]
   PrimOp
Word32RemOp -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
2 [ ConTagZ -> RuleM ()
nonZeroLit ConTagZ
1 forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> (RuleOpts -> Literal -> Literal -> Maybe CoreExpr)
-> RuleM CoreExpr
binaryLit (forall a b.
(Integral a, Integral b) =>
(a -> b -> Integer)
-> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
word32Op2 forall a. Integral a => a -> a -> a
rem)
                                    , RuleM CoreExpr
leftZero
                                    , ConTagZ -> RuleM ()
oneLit ConTagZ
1 forall (f :: * -> *) a b. Functor f => f a -> b -> f b
$> forall b. Literal -> Expr b
Lit Literal
zeroW32
                                    , RuleM ()
equalArgs forall (f :: * -> *) a b. Functor f => f a -> b -> f b
$> forall b. Literal -> Expr b
Lit Literal
zeroW32 ]
   PrimOp
Word32AndOp -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
2 [ (RuleOpts -> Literal -> Literal -> Maybe CoreExpr)
-> RuleM CoreExpr
binaryLit (forall a b.
(Integral a, Integral b) =>
(a -> b -> Integer)
-> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
word32Op2 forall a. Bits a => a -> a -> a
(.&.))
                                    , RuleM CoreExpr
idempotent
                                    , RuleM CoreExpr
zeroElem
                                    , PrimOp -> RuleM CoreExpr
sameArgIdempotentCommut PrimOp
Word32AndOp
                                    ]
   PrimOp
Word32OrOp  -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
2 [ (RuleOpts -> Literal -> Literal -> Maybe CoreExpr)
-> RuleM CoreExpr
binaryLit (forall a b.
(Integral a, Integral b) =>
(a -> b -> Integer)
-> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
word32Op2 forall a. Bits a => a -> a -> a
(.|.))
                                    , RuleM CoreExpr
idempotent
                                    , Literal -> RuleM CoreExpr
identity Literal
zeroW32
                                    , PrimOp -> RuleM CoreExpr
sameArgIdempotentCommut PrimOp
Word32OrOp
                                    ]
   PrimOp
Word32XorOp -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
2 [ (RuleOpts -> Literal -> Literal -> Maybe CoreExpr)
-> RuleM CoreExpr
binaryLit (forall a b.
(Integral a, Integral b) =>
(a -> b -> Integer)
-> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
word32Op2 forall a. Bits a => a -> a -> a
xor)
                                    , Literal -> RuleM CoreExpr
identity Literal
zeroW32
                                    , RuleM ()
equalArgs forall (f :: * -> *) a b. Functor f => f a -> b -> f b
$> forall b. Literal -> Expr b
Lit Literal
zeroW32 ]
   PrimOp
Word32NotOp -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
1 [ (RuleOpts -> Literal -> Maybe CoreExpr) -> RuleM CoreExpr
unaryLit RuleOpts -> Literal -> Maybe CoreExpr
complementOp
                                    , PrimOp -> RuleM CoreExpr
semiInversePrimOp PrimOp
Word32NotOp ]
   PrimOp
Word32SllOp -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
2 [ LitNumType
-> (Platform -> Integer -> ConTagZ -> Integer) -> RuleM CoreExpr
shiftRule LitNumType
LitNumWord (forall a b. a -> b -> a
const forall a. Bits a => a -> ConTagZ -> a
shiftL) ]
   PrimOp
Word32SrlOp -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
2 [ LitNumType
-> (Platform -> Integer -> ConTagZ -> Integer) -> RuleM CoreExpr
shiftRule LitNumType
LitNumWord forall a b. (a -> b) -> a -> b
$ forall a b. a -> b -> a
const forall a b. (a -> b) -> a -> b
$ forall t. (Integral t, Bits t) => Integer -> ConTagZ -> Integer
shiftRightLogical @Word32 ]

#if WORD_SIZE_IN_BITS < 64
   -- Int64 operations
   Int64AddOp  -> mkPrimOpRule nm 2 [ binaryLit (int64Op2 (+))
                                    , identity zeroI64
                                    , addFoldingRules Int64AddOp int64Ops
                                    ]
   Int64SubOp  -> mkPrimOpRule nm 2 [ binaryLit (int64Op2 (-))
                                    , rightIdentity zeroI64
                                    , equalArgs $> Lit zeroI64
                                    , subFoldingRules Int64SubOp int64Ops
                                    ]
   Int64MulOp  -> mkPrimOpRule nm 2 [ binaryLit (int64Op2 (*))
                                    , zeroElem
                                    , identity oneI64
                                    , mulFoldingRules Int64MulOp int64Ops
                                    ]
   Int64QuotOp -> mkPrimOpRule nm 2 [ nonZeroLit 1 >> binaryLit (int64Op2 quot)
                                    , leftZero
                                    , rightIdentity oneI64
                                    , equalArgs $> Lit oneI64 ]
   Int64RemOp  -> mkPrimOpRule nm 2 [ nonZeroLit 1 >> binaryLit (int64Op2 rem)
                                    , leftZero
                                    , oneLit 1 $> Lit zeroI64
                                    , equalArgs $> Lit zeroI64 ]
   Int64NegOp  -> mkPrimOpRule nm 1 [ unaryLit negOp
                                    , semiInversePrimOp Int64NegOp ]
   Int64SllOp  -> mkPrimOpRule nm 2 [ shiftRule LitNumInt64 (const shiftL)
                                    , rightIdentity zeroI64 ]
   Int64SraOp  -> mkPrimOpRule nm 2 [ shiftRule LitNumInt64 (const shiftR)
                                    , rightIdentity zeroI64 ]
   Int64SrlOp  -> mkPrimOpRule nm 2 [ shiftRule LitNumInt64 $ const $ shiftRightLogical @Word64
                                    , rightIdentity zeroI64 ]

   -- Word64 operations
   Word64AddOp -> mkPrimOpRule nm 2 [ binaryLit (word64Op2 (+))
                                    , identity zeroW64
                                    , addFoldingRules Word64AddOp word64Ops
                                    ]
   Word64SubOp -> mkPrimOpRule nm 2 [ binaryLit (word64Op2 (-))
                                    , rightIdentity zeroW64
                                    , equalArgs $> Lit zeroW64
                                    , subFoldingRules Word64SubOp word64Ops
                                    ]
   Word64MulOp -> mkPrimOpRule nm 2 [ binaryLit (word64Op2 (*))
                                    , identity oneW64
                                    , mulFoldingRules Word64MulOp word64Ops
                                    ]
   Word64QuotOp-> mkPrimOpRule nm 2 [ nonZeroLit 1 >> binaryLit (word64Op2 quot)
                                    , rightIdentity oneW64 ]
   Word64RemOp -> mkPrimOpRule nm 2 [ nonZeroLit 1 >> binaryLit (word64Op2 rem)
                                    , leftZero
                                    , oneLit 1 $> Lit zeroW64
                                    , equalArgs $> Lit zeroW64 ]
   Word64AndOp -> mkPrimOpRule nm 2 [ binaryLit (word64Op2 (.&.))
                                    , idempotent
                                    , zeroElem
                                    , sameArgIdempotentCommut Word64AndOp
                                    ]
   Word64OrOp  -> mkPrimOpRule nm 2 [ binaryLit (word64Op2 (.|.))
                                    , idempotent
                                    , identity zeroW64
                                    , sameArgIdempotentCommut Word64OrOp
                                    ]
   Word64XorOp -> mkPrimOpRule nm 2 [ binaryLit (word64Op2 xor)
                                    , identity zeroW64
                                    , equalArgs $> Lit zeroW64 ]
   Word64NotOp -> mkPrimOpRule nm 1 [ unaryLit complementOp
                                    , semiInversePrimOp Word64NotOp ]
   Word64SllOp -> mkPrimOpRule nm 2 [ shiftRule LitNumWord64 (const shiftL) ]
   Word64SrlOp -> mkPrimOpRule nm 2 [ shiftRule LitNumWord64 $ const $ shiftRightLogical @Word64 ]
#endif

   -- Int operations
   PrimOp
IntAddOp    -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
2 [ (RuleOpts -> Literal -> Literal -> Maybe CoreExpr)
-> RuleM CoreExpr
binaryLit (forall a b.
(Integral a, Integral b) =>
(a -> b -> Integer)
-> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
intOp2 forall a. Num a => a -> a -> a
(+))
                                    , (Platform -> Literal) -> RuleM CoreExpr
identityPlatform Platform -> Literal
zeroi
                                    , PrimOp -> NumOps -> RuleM CoreExpr
addFoldingRules PrimOp
IntAddOp NumOps
intOps
                                    ]
   PrimOp
IntSubOp    -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
2 [ (RuleOpts -> Literal -> Literal -> Maybe CoreExpr)
-> RuleM CoreExpr
binaryLit (forall a b.
(Integral a, Integral b) =>
(a -> b -> Integer)
-> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
intOp2 (-))
                                    , (Platform -> Literal) -> RuleM CoreExpr
rightIdentityPlatform Platform -> Literal
zeroi
                                    , RuleM ()
equalArgs forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> (Platform -> Literal) -> RuleM CoreExpr
retLit Platform -> Literal
zeroi
                                    , PrimOp -> NumOps -> RuleM CoreExpr
subFoldingRules PrimOp
IntSubOp NumOps
intOps
                                    ]
   PrimOp
IntAddCOp   -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
2 [ (RuleOpts -> Literal -> Literal -> Maybe CoreExpr)
-> RuleM CoreExpr
binaryLit (forall a b.
(Integral a, Integral b) =>
(a -> b -> Integer)
-> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
intOpC2 forall a. Num a => a -> a -> a
(+))
                                    , (Platform -> Literal) -> RuleM CoreExpr
identityCPlatform Platform -> Literal
zeroi ]
   PrimOp
IntSubCOp   -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
2 [ (RuleOpts -> Literal -> Literal -> Maybe CoreExpr)
-> RuleM CoreExpr
binaryLit (forall a b.
(Integral a, Integral b) =>
(a -> b -> Integer)
-> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
intOpC2 (-))
                                    , (Platform -> Literal) -> RuleM CoreExpr
rightIdentityCPlatform Platform -> Literal
zeroi
                                    , RuleM ()
equalArgs forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> (Platform -> Literal) -> RuleM CoreExpr
retLitNoC Platform -> Literal
zeroi ]
   PrimOp
IntMulOp    -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
2 [ (RuleOpts -> Literal -> Literal -> Maybe CoreExpr)
-> RuleM CoreExpr
binaryLit (forall a b.
(Integral a, Integral b) =>
(a -> b -> Integer)
-> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
intOp2 forall a. Num a => a -> a -> a
(*))
                                    , RuleM CoreExpr
zeroElem
                                    , (Platform -> Literal) -> RuleM CoreExpr
identityPlatform Platform -> Literal
onei
                                    , PrimOp -> NumOps -> RuleM CoreExpr
mulFoldingRules PrimOp
IntMulOp NumOps
intOps
                                    ]
   PrimOp
IntQuotOp   -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
2 [ ConTagZ -> RuleM ()
nonZeroLit ConTagZ
1 forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> (RuleOpts -> Literal -> Literal -> Maybe CoreExpr)
-> RuleM CoreExpr
binaryLit (forall a b.
(Integral a, Integral b) =>
(a -> b -> Integer)
-> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
intOp2 forall a. Integral a => a -> a -> a
quot)
                                    , RuleM CoreExpr
leftZero
                                    , (Platform -> Literal) -> RuleM CoreExpr
rightIdentityPlatform Platform -> Literal
onei
                                    , RuleM ()
equalArgs forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> (Platform -> Literal) -> RuleM CoreExpr
retLit Platform -> Literal
onei ]
   PrimOp
IntRemOp    -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
2 [ ConTagZ -> RuleM ()
nonZeroLit ConTagZ
1 forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> (RuleOpts -> Literal -> Literal -> Maybe CoreExpr)
-> RuleM CoreExpr
binaryLit (forall a b.
(Integral a, Integral b) =>
(a -> b -> Integer)
-> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
intOp2 forall a. Integral a => a -> a -> a
rem)
                                    , RuleM CoreExpr
leftZero
                                    , ConTagZ -> RuleM ()
oneLit ConTagZ
1 forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> (Platform -> Literal) -> RuleM CoreExpr
retLit Platform -> Literal
zeroi
                                    , RuleM ()
equalArgs forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> (Platform -> Literal) -> RuleM CoreExpr
retLit Platform -> Literal
zeroi ]
   PrimOp
IntAndOp    -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
2 [ (RuleOpts -> Literal -> Literal -> Maybe CoreExpr)
-> RuleM CoreExpr
binaryLit (forall a b.
(Integral a, Integral b) =>
(a -> b -> Integer)
-> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
intOp2 forall a. Bits a => a -> a -> a
(.&.))
                                    , RuleM CoreExpr
idempotent
                                    , RuleM CoreExpr
zeroElem
                                    , PrimOp -> RuleM CoreExpr
sameArgIdempotentCommut PrimOp
IntAndOp
                                    ]
   PrimOp
IntOrOp     -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
2 [ (RuleOpts -> Literal -> Literal -> Maybe CoreExpr)
-> RuleM CoreExpr
binaryLit (forall a b.
(Integral a, Integral b) =>
(a -> b -> Integer)
-> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
intOp2 forall a. Bits a => a -> a -> a
(.|.))
                                    , RuleM CoreExpr
idempotent
                                    , (Platform -> Literal) -> RuleM CoreExpr
identityPlatform Platform -> Literal
zeroi
                                    , PrimOp -> RuleM CoreExpr
sameArgIdempotentCommut PrimOp
IntOrOp
                                    ]
   PrimOp
IntXorOp    -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
2 [ (RuleOpts -> Literal -> Literal -> Maybe CoreExpr)
-> RuleM CoreExpr
binaryLit (forall a b.
(Integral a, Integral b) =>
(a -> b -> Integer)
-> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
intOp2 forall a. Bits a => a -> a -> a
xor)
                                    , (Platform -> Literal) -> RuleM CoreExpr
identityPlatform Platform -> Literal
zeroi
                                    , RuleM ()
equalArgs forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> (Platform -> Literal) -> RuleM CoreExpr
retLit Platform -> Literal
zeroi ]
   PrimOp
IntNotOp    -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
1 [ (RuleOpts -> Literal -> Maybe CoreExpr) -> RuleM CoreExpr
unaryLit RuleOpts -> Literal -> Maybe CoreExpr
complementOp
                                    , PrimOp -> RuleM CoreExpr
semiInversePrimOp PrimOp
IntNotOp ]
   PrimOp
IntNegOp    -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
1 [ (RuleOpts -> Literal -> Maybe CoreExpr) -> RuleM CoreExpr
unaryLit RuleOpts -> Literal -> Maybe CoreExpr
negOp
                                    , PrimOp -> RuleM CoreExpr
semiInversePrimOp PrimOp
IntNegOp ]
   PrimOp
IntSllOp    -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
2 [ LitNumType
-> (Platform -> Integer -> ConTagZ -> Integer) -> RuleM CoreExpr
shiftRule LitNumType
LitNumInt (forall a b. a -> b -> a
const forall a. Bits a => a -> ConTagZ -> a
shiftL)
                                    , (Platform -> Literal) -> RuleM CoreExpr
rightIdentityPlatform Platform -> Literal
zeroi ]
   PrimOp
IntSraOp    -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
2 [ LitNumType
-> (Platform -> Integer -> ConTagZ -> Integer) -> RuleM CoreExpr
shiftRule LitNumType
LitNumInt (forall a b. a -> b -> a
const forall a. Bits a => a -> ConTagZ -> a
shiftR)
                                    , (Platform -> Literal) -> RuleM CoreExpr
rightIdentityPlatform Platform -> Literal
zeroi ]
   PrimOp
IntSrlOp    -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
2 [ LitNumType
-> (Platform -> Integer -> ConTagZ -> Integer) -> RuleM CoreExpr
shiftRule LitNumType
LitNumInt Platform -> Integer -> ConTagZ -> Integer
shiftRightLogicalNative
                                    , (Platform -> Literal) -> RuleM CoreExpr
rightIdentityPlatform Platform -> Literal
zeroi ]

   -- Word operations
   PrimOp
WordAddOp   -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
2 [ (RuleOpts -> Literal -> Literal -> Maybe CoreExpr)
-> RuleM CoreExpr
binaryLit (forall a b.
(Integral a, Integral b) =>
(a -> b -> Integer)
-> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
wordOp2 forall a. Num a => a -> a -> a
(+))
                                    , (Platform -> Literal) -> RuleM CoreExpr
identityPlatform Platform -> Literal
zerow
                                    , PrimOp -> NumOps -> RuleM CoreExpr
addFoldingRules PrimOp
WordAddOp NumOps
wordOps
                                    ]
   PrimOp
WordSubOp   -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
2 [ (RuleOpts -> Literal -> Literal -> Maybe CoreExpr)
-> RuleM CoreExpr
binaryLit (forall a b.
(Integral a, Integral b) =>
(a -> b -> Integer)
-> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
wordOp2 (-))
                                    , (Platform -> Literal) -> RuleM CoreExpr
rightIdentityPlatform Platform -> Literal
zerow
                                    , RuleM ()
equalArgs forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> (Platform -> Literal) -> RuleM CoreExpr
retLit Platform -> Literal
zerow
                                    , PrimOp -> NumOps -> RuleM CoreExpr
subFoldingRules PrimOp
WordSubOp NumOps
wordOps
                                    ]
   PrimOp
WordAddCOp  -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
2 [ (RuleOpts -> Literal -> Literal -> Maybe CoreExpr)
-> RuleM CoreExpr
binaryLit (forall a b.
(Integral a, Integral b) =>
(a -> b -> Integer)
-> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
wordOpC2 forall a. Num a => a -> a -> a
(+))
                                    , (Platform -> Literal) -> RuleM CoreExpr
identityCPlatform Platform -> Literal
zerow ]
   PrimOp
WordSubCOp  -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
2 [ (RuleOpts -> Literal -> Literal -> Maybe CoreExpr)
-> RuleM CoreExpr
binaryLit (forall a b.
(Integral a, Integral b) =>
(a -> b -> Integer)
-> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
wordOpC2 (-))
                                    , (Platform -> Literal) -> RuleM CoreExpr
rightIdentityCPlatform Platform -> Literal
zerow
                                    , RuleM ()
equalArgs forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> (Platform -> Literal) -> RuleM CoreExpr
retLitNoC Platform -> Literal
zerow ]
   PrimOp
WordMulOp   -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
2 [ (RuleOpts -> Literal -> Literal -> Maybe CoreExpr)
-> RuleM CoreExpr
binaryLit (forall a b.
(Integral a, Integral b) =>
(a -> b -> Integer)
-> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
wordOp2 forall a. Num a => a -> a -> a
(*))
                                    , (Platform -> Literal) -> RuleM CoreExpr
identityPlatform Platform -> Literal
onew
                                    , PrimOp -> NumOps -> RuleM CoreExpr
mulFoldingRules PrimOp
WordMulOp NumOps
wordOps
                                    ]
   PrimOp
WordQuotOp  -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
2 [ ConTagZ -> RuleM ()
nonZeroLit ConTagZ
1 forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> (RuleOpts -> Literal -> Literal -> Maybe CoreExpr)
-> RuleM CoreExpr
binaryLit (forall a b.
(Integral a, Integral b) =>
(a -> b -> Integer)
-> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
wordOp2 forall a. Integral a => a -> a -> a
quot)
                                    , (Platform -> Literal) -> RuleM CoreExpr
rightIdentityPlatform Platform -> Literal
onew ]
   PrimOp
WordRemOp   -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
2 [ ConTagZ -> RuleM ()
nonZeroLit ConTagZ
1 forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> (RuleOpts -> Literal -> Literal -> Maybe CoreExpr)
-> RuleM CoreExpr
binaryLit (forall a b.
(Integral a, Integral b) =>
(a -> b -> Integer)
-> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
wordOp2 forall a. Integral a => a -> a -> a
rem)
                                    , RuleM CoreExpr
leftZero
                                    , ConTagZ -> RuleM ()
oneLit ConTagZ
1 forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> (Platform -> Literal) -> RuleM CoreExpr
retLit Platform -> Literal
zerow
                                    , RuleM ()
equalArgs forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> (Platform -> Literal) -> RuleM CoreExpr
retLit Platform -> Literal
zerow ]
   PrimOp
WordAndOp   -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
2 [ (RuleOpts -> Literal -> Literal -> Maybe CoreExpr)
-> RuleM CoreExpr
binaryLit (forall a b.
(Integral a, Integral b) =>
(a -> b -> Integer)
-> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
wordOp2 forall a. Bits a => a -> a -> a
(.&.))
                                    , RuleM CoreExpr
idempotent
                                    , RuleM CoreExpr
zeroElem
                                    , PrimOp -> RuleM CoreExpr
sameArgIdempotentCommut PrimOp
WordAndOp
                                    ]
   PrimOp
WordOrOp    -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
2 [ (RuleOpts -> Literal -> Literal -> Maybe CoreExpr)
-> RuleM CoreExpr
binaryLit (forall a b.
(Integral a, Integral b) =>
(a -> b -> Integer)
-> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
wordOp2 forall a. Bits a => a -> a -> a
(.|.))
                                    , RuleM CoreExpr
idempotent
                                    , (Platform -> Literal) -> RuleM CoreExpr
identityPlatform Platform -> Literal
zerow
                                    , PrimOp -> RuleM CoreExpr
sameArgIdempotentCommut PrimOp
WordOrOp
                                    ]
   PrimOp
WordXorOp   -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
2 [ (RuleOpts -> Literal -> Literal -> Maybe CoreExpr)
-> RuleM CoreExpr
binaryLit (forall a b.
(Integral a, Integral b) =>
(a -> b -> Integer)
-> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
wordOp2 forall a. Bits a => a -> a -> a
xor)
                                    , (Platform -> Literal) -> RuleM CoreExpr
identityPlatform Platform -> Literal
zerow
                                    , RuleM ()
equalArgs forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> (Platform -> Literal) -> RuleM CoreExpr
retLit Platform -> Literal
zerow ]
   PrimOp
WordNotOp   -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
1 [ (RuleOpts -> Literal -> Maybe CoreExpr) -> RuleM CoreExpr
unaryLit RuleOpts -> Literal -> Maybe CoreExpr
complementOp
                                    , PrimOp -> RuleM CoreExpr
semiInversePrimOp PrimOp
WordNotOp ]
   PrimOp
WordSllOp   -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
2 [ LitNumType
-> (Platform -> Integer -> ConTagZ -> Integer) -> RuleM CoreExpr
shiftRule LitNumType
LitNumWord (forall a b. a -> b -> a
const forall a. Bits a => a -> ConTagZ -> a
shiftL) ]
   PrimOp
WordSrlOp   -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
2 [ LitNumType
-> (Platform -> Integer -> ConTagZ -> Integer) -> RuleM CoreExpr
shiftRule LitNumType
LitNumWord Platform -> Integer -> ConTagZ -> Integer
shiftRightLogicalNative ]

   -- coercions

   PrimOp
Int8ToIntOp    -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
1 [ (Platform -> Literal -> Literal) -> RuleM CoreExpr
liftLitPlatform Platform -> Literal -> Literal
convertToIntLit ]
   PrimOp
Int16ToIntOp   -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
1 [ (Platform -> Literal -> Literal) -> RuleM CoreExpr
liftLitPlatform Platform -> Literal -> Literal
convertToIntLit ]
   PrimOp
Int32ToIntOp   -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
1 [ (Platform -> Literal -> Literal) -> RuleM CoreExpr
liftLitPlatform Platform -> Literal -> Literal
convertToIntLit ]
#if WORD_SIZE_IN_BITS < 64
   Int64ToIntOp   -> mkPrimOpRule nm 1 [ liftLitPlatform convertToIntLit ]
#endif
   PrimOp
IntToInt8Op    -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
1 [ (Literal -> Literal) -> RuleM CoreExpr
liftLit Literal -> Literal
narrowInt8Lit
                                       , PrimOp -> RuleM CoreExpr
semiInversePrimOp PrimOp
Int8ToIntOp
                                       , PrimOp -> PrimOp -> ConTagZ -> RuleM CoreExpr
narrowSubsumesAnd PrimOp
IntAndOp PrimOp
IntToInt8Op ConTagZ
8 ]
   PrimOp
IntToInt16Op   -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
1 [ (Literal -> Literal) -> RuleM CoreExpr
liftLit Literal -> Literal
narrowInt16Lit
                                       , PrimOp -> RuleM CoreExpr
semiInversePrimOp PrimOp
Int16ToIntOp
                                       , PrimOp -> PrimOp -> ConTagZ -> RuleM CoreExpr
narrowSubsumesAnd PrimOp
IntAndOp PrimOp
IntToInt16Op ConTagZ
16 ]
   PrimOp
IntToInt32Op   -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
1 [ (Literal -> Literal) -> RuleM CoreExpr
liftLit Literal -> Literal
narrowInt32Lit
                                       , PrimOp -> RuleM CoreExpr
semiInversePrimOp PrimOp
Int32ToIntOp
                                       , PrimOp -> PrimOp -> ConTagZ -> RuleM CoreExpr
narrowSubsumesAnd PrimOp
IntAndOp PrimOp
IntToInt32Op ConTagZ
32 ]
#if WORD_SIZE_IN_BITS < 64
   IntToInt64Op   -> mkPrimOpRule nm 1 [ liftLit narrowInt64Lit ]
#endif

   PrimOp
Word8ToWordOp  -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
1 [ (Platform -> Literal -> Literal) -> RuleM CoreExpr
liftLitPlatform Platform -> Literal -> Literal
convertToWordLit
                                       , PrimOp -> Integer -> RuleM CoreExpr
extendNarrowPassthrough PrimOp
WordToWord8Op Integer
0xFF
                                       ]
   PrimOp
Word16ToWordOp -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
1 [ (Platform -> Literal -> Literal) -> RuleM CoreExpr
liftLitPlatform Platform -> Literal -> Literal
convertToWordLit
                                       , PrimOp -> Integer -> RuleM CoreExpr
extendNarrowPassthrough PrimOp
WordToWord16Op Integer
0xFFFF
                                       ]
   PrimOp
Word32ToWordOp -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
1 [ (Platform -> Literal -> Literal) -> RuleM CoreExpr
liftLitPlatform Platform -> Literal -> Literal
convertToWordLit
                                       , PrimOp -> Integer -> RuleM CoreExpr
extendNarrowPassthrough PrimOp
WordToWord32Op Integer
0xFFFFFFFF
                                       ]
#if WORD_SIZE_IN_BITS < 64
   Word64ToWordOp -> mkPrimOpRule nm 1 [ liftLitPlatform convertToWordLit ]
#endif

   PrimOp
WordToWord8Op  -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
1 [ (Literal -> Literal) -> RuleM CoreExpr
liftLit Literal -> Literal
narrowWord8Lit
                                       , PrimOp -> RuleM CoreExpr
semiInversePrimOp PrimOp
Word8ToWordOp
                                       , PrimOp -> PrimOp -> ConTagZ -> RuleM CoreExpr
narrowSubsumesAnd PrimOp
WordAndOp PrimOp
WordToWord8Op ConTagZ
8 ]
   PrimOp
WordToWord16Op -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
1 [ (Literal -> Literal) -> RuleM CoreExpr
liftLit Literal -> Literal
narrowWord16Lit
                                       , PrimOp -> RuleM CoreExpr
semiInversePrimOp PrimOp
Word16ToWordOp
                                       , PrimOp -> PrimOp -> ConTagZ -> RuleM CoreExpr
narrowSubsumesAnd PrimOp
WordAndOp PrimOp
WordToWord16Op ConTagZ
16 ]
   PrimOp
WordToWord32Op -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
1 [ (Literal -> Literal) -> RuleM CoreExpr
liftLit Literal -> Literal
narrowWord32Lit
                                       , PrimOp -> RuleM CoreExpr
semiInversePrimOp PrimOp
Word32ToWordOp
                                       , PrimOp -> PrimOp -> ConTagZ -> RuleM CoreExpr
narrowSubsumesAnd PrimOp
WordAndOp PrimOp
WordToWord32Op ConTagZ
32 ]
#if WORD_SIZE_IN_BITS < 64
   WordToWord64Op -> mkPrimOpRule nm 1 [ liftLit narrowWord64Lit ]
#endif

   PrimOp
Word8ToInt8Op  -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
1 [ (Platform -> Literal -> Literal) -> RuleM CoreExpr
liftLitPlatform (LitNumType -> Platform -> Literal -> Literal
litNumCoerce LitNumType
LitNumInt8)
                                       , PrimOp -> RuleM CoreExpr
semiInversePrimOp PrimOp
Int8ToWord8Op ]
   PrimOp
Int8ToWord8Op  -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
1 [ (Platform -> Literal -> Literal) -> RuleM CoreExpr
liftLitPlatform (LitNumType -> Platform -> Literal -> Literal
litNumCoerce LitNumType
LitNumWord8)
                                       , PrimOp -> RuleM CoreExpr
semiInversePrimOp PrimOp
Word8ToInt8Op ]
   PrimOp
Word16ToInt16Op-> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
1 [ (Platform -> Literal -> Literal) -> RuleM CoreExpr
liftLitPlatform (LitNumType -> Platform -> Literal -> Literal
litNumCoerce LitNumType
LitNumInt16)
                                       , PrimOp -> RuleM CoreExpr
semiInversePrimOp PrimOp
Int16ToWord16Op ]
   PrimOp
Int16ToWord16Op-> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
1 [ (Platform -> Literal -> Literal) -> RuleM CoreExpr
liftLitPlatform (LitNumType -> Platform -> Literal -> Literal
litNumCoerce LitNumType
LitNumWord16)
                                       , PrimOp -> RuleM CoreExpr
semiInversePrimOp PrimOp
Word16ToInt16Op ]
   PrimOp
Word32ToInt32Op-> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
1 [ (Platform -> Literal -> Literal) -> RuleM CoreExpr
liftLitPlatform (LitNumType -> Platform -> Literal -> Literal
litNumCoerce LitNumType
LitNumInt32)
                                       , PrimOp -> RuleM CoreExpr
semiInversePrimOp PrimOp
Int32ToWord32Op ]
   PrimOp
Int32ToWord32Op-> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
1 [ (Platform -> Literal -> Literal) -> RuleM CoreExpr
liftLitPlatform (LitNumType -> Platform -> Literal -> Literal
litNumCoerce LitNumType
LitNumWord32)
                                       , PrimOp -> RuleM CoreExpr
semiInversePrimOp PrimOp
Word32ToInt32Op ]
#if WORD_SIZE_IN_BITS < 64
   Word64ToInt64Op-> mkPrimOpRule nm 1 [ liftLitPlatform (litNumCoerce LitNumInt64)
                                       , semiInversePrimOp Int64ToWord64Op ]
   Int64ToWord64Op-> mkPrimOpRule nm 1 [ liftLitPlatform (litNumCoerce LitNumWord64)
                                       , semiInversePrimOp Word64ToInt64Op ]
#endif

   PrimOp
WordToIntOp    -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
1 [ (Platform -> Literal -> Literal) -> RuleM CoreExpr
liftLitPlatform (LitNumType -> Platform -> Literal -> Literal
litNumCoerce LitNumType
LitNumInt)
                                       , PrimOp -> RuleM CoreExpr
semiInversePrimOp PrimOp
IntToWordOp ]
   PrimOp
IntToWordOp    -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
1 [ (Platform -> Literal -> Literal) -> RuleM CoreExpr
liftLitPlatform (LitNumType -> Platform -> Literal -> Literal
litNumCoerce LitNumType
LitNumWord)
                                       , PrimOp -> RuleM CoreExpr
semiInversePrimOp PrimOp
WordToIntOp ]

   PrimOp
Narrow8IntOp   -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
1 [ (Platform -> Literal -> Literal) -> RuleM CoreExpr
liftLitPlatform (LitNumType -> Platform -> Literal -> Literal
litNumNarrow LitNumType
LitNumInt8)
                                       , PrimOp -> RuleM CoreExpr
subsumedByPrimOp PrimOp
Narrow8IntOp
                                       , PrimOp
Narrow8IntOp PrimOp -> PrimOp -> RuleM CoreExpr
`subsumesPrimOp` PrimOp
Narrow16IntOp
                                       , PrimOp
Narrow8IntOp PrimOp -> PrimOp -> RuleM CoreExpr
`subsumesPrimOp` PrimOp
Narrow32IntOp
                                       , PrimOp -> PrimOp -> ConTagZ -> RuleM CoreExpr
narrowSubsumesAnd PrimOp
IntAndOp PrimOp
Narrow8IntOp ConTagZ
8 ]
   PrimOp
Narrow16IntOp  -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
1 [ (Platform -> Literal -> Literal) -> RuleM CoreExpr
liftLitPlatform (LitNumType -> Platform -> Literal -> Literal
litNumNarrow LitNumType
LitNumInt16)
                                       , PrimOp -> RuleM CoreExpr
subsumedByPrimOp PrimOp
Narrow8IntOp
                                       , PrimOp -> RuleM CoreExpr
subsumedByPrimOp PrimOp
Narrow16IntOp
                                       , PrimOp
Narrow16IntOp PrimOp -> PrimOp -> RuleM CoreExpr
`subsumesPrimOp` PrimOp
Narrow32IntOp
                                       , PrimOp -> PrimOp -> ConTagZ -> RuleM CoreExpr
narrowSubsumesAnd PrimOp
IntAndOp PrimOp
Narrow16IntOp ConTagZ
16 ]
   PrimOp
Narrow32IntOp  -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
1 [ (Platform -> Literal -> Literal) -> RuleM CoreExpr
liftLitPlatform (LitNumType -> Platform -> Literal -> Literal
litNumNarrow LitNumType
LitNumInt32)
                                       , PrimOp -> RuleM CoreExpr
subsumedByPrimOp PrimOp
Narrow8IntOp
                                       , PrimOp -> RuleM CoreExpr
subsumedByPrimOp PrimOp
Narrow16IntOp
                                       , PrimOp -> RuleM CoreExpr
subsumedByPrimOp PrimOp
Narrow32IntOp
                                       , RuleM CoreExpr
removeOp32
                                       , PrimOp -> PrimOp -> ConTagZ -> RuleM CoreExpr
narrowSubsumesAnd PrimOp
IntAndOp PrimOp
Narrow32IntOp ConTagZ
32 ]
   PrimOp
Narrow8WordOp  -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
1 [ (Platform -> Literal -> Literal) -> RuleM CoreExpr
liftLitPlatform (LitNumType -> Platform -> Literal -> Literal
litNumNarrow LitNumType
LitNumWord8)
                                       , PrimOp -> RuleM CoreExpr
subsumedByPrimOp PrimOp
Narrow8WordOp
                                       , PrimOp
Narrow8WordOp PrimOp -> PrimOp -> RuleM CoreExpr
`subsumesPrimOp` PrimOp
Narrow16WordOp
                                       , PrimOp
Narrow8WordOp PrimOp -> PrimOp -> RuleM CoreExpr
`subsumesPrimOp` PrimOp
Narrow32WordOp
                                       , PrimOp -> PrimOp -> ConTagZ -> RuleM CoreExpr
narrowSubsumesAnd PrimOp
WordAndOp PrimOp
Narrow8WordOp ConTagZ
8 ]
   PrimOp
Narrow16WordOp -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
1 [ (Platform -> Literal -> Literal) -> RuleM CoreExpr
liftLitPlatform (LitNumType -> Platform -> Literal -> Literal
litNumNarrow LitNumType
LitNumWord16)
                                       , PrimOp -> RuleM CoreExpr
subsumedByPrimOp PrimOp
Narrow8WordOp
                                       , PrimOp -> RuleM CoreExpr
subsumedByPrimOp PrimOp
Narrow16WordOp
                                       , PrimOp
Narrow16WordOp PrimOp -> PrimOp -> RuleM CoreExpr
`subsumesPrimOp` PrimOp
Narrow32WordOp
                                       , PrimOp -> PrimOp -> ConTagZ -> RuleM CoreExpr
narrowSubsumesAnd PrimOp
WordAndOp PrimOp
Narrow16WordOp ConTagZ
16 ]
   PrimOp
Narrow32WordOp -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
1 [ (Platform -> Literal -> Literal) -> RuleM CoreExpr
liftLitPlatform (LitNumType -> Platform -> Literal -> Literal
litNumNarrow LitNumType
LitNumWord32)
                                       , PrimOp -> RuleM CoreExpr
subsumedByPrimOp PrimOp
Narrow8WordOp
                                       , PrimOp -> RuleM CoreExpr
subsumedByPrimOp PrimOp
Narrow16WordOp
                                       , PrimOp -> RuleM CoreExpr
subsumedByPrimOp PrimOp
Narrow32WordOp
                                       , RuleM CoreExpr
removeOp32
                                       , PrimOp -> PrimOp -> ConTagZ -> RuleM CoreExpr
narrowSubsumesAnd PrimOp
WordAndOp PrimOp
Narrow32WordOp ConTagZ
32 ]

   PrimOp
OrdOp          -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
1 [ (Literal -> Literal) -> RuleM CoreExpr
liftLit Literal -> Literal
charToIntLit
                                       , PrimOp -> RuleM CoreExpr
semiInversePrimOp PrimOp
ChrOp ]
   PrimOp
ChrOp          -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
1 [ do [Lit Literal
lit] <- RuleM [CoreExpr]
getArgs
                                            forall (f :: * -> *). Alternative f => Bool -> f ()
guard (Literal -> Bool
litFitsInChar Literal
lit)
                                            (Literal -> Literal) -> RuleM CoreExpr
liftLit Literal -> Literal
intToCharLit
                                       , PrimOp -> RuleM CoreExpr
semiInversePrimOp PrimOp
OrdOp ]
   PrimOp
FloatToIntOp    -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
1 [ (Literal -> Literal) -> RuleM CoreExpr
liftLit Literal -> Literal
floatToIntLit ]
   PrimOp
IntToFloatOp    -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
1 [ (Literal -> Literal) -> RuleM CoreExpr
liftLit Literal -> Literal
intToFloatLit ]
   PrimOp
DoubleToIntOp   -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
1 [ (Literal -> Literal) -> RuleM CoreExpr
liftLit Literal -> Literal
doubleToIntLit ]
   PrimOp
IntToDoubleOp   -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
1 [ (Literal -> Literal) -> RuleM CoreExpr
liftLit Literal -> Literal
intToDoubleLit ]
   -- SUP: Not sure what the standard says about precision in the following 2 cases
   PrimOp
FloatToDoubleOp -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
1 [ (Literal -> Literal) -> RuleM CoreExpr
liftLit Literal -> Literal
floatToDoubleLit ]
   PrimOp
DoubleToFloatOp -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
1 [ (Literal -> Literal) -> RuleM CoreExpr
liftLit Literal -> Literal
doubleToFloatLit ]

   -- Float
   PrimOp
FloatAddOp        -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
2 [ (RuleOpts -> Literal -> Literal -> Maybe CoreExpr)
-> RuleM CoreExpr
binaryLit ((Rational -> Rational -> Rational)
-> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
floatOp2 forall a. Num a => a -> a -> a
(+))
                                          , Literal -> RuleM CoreExpr
identity Literal
zerof ]
   PrimOp
FloatSubOp        -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
2 [ (RuleOpts -> Literal -> Literal -> Maybe CoreExpr)
-> RuleM CoreExpr
binaryLit ((Rational -> Rational -> Rational)
-> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
floatOp2 (-))
                                          , Literal -> RuleM CoreExpr
rightIdentity Literal
zerof ]
   PrimOp
FloatMulOp        -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
2 [ (RuleOpts -> Literal -> Literal -> Maybe CoreExpr)
-> RuleM CoreExpr
binaryLit ((Rational -> Rational -> Rational)
-> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
floatOp2 forall a. Num a => a -> a -> a
(*))
                                          , Literal -> RuleM CoreExpr
identity Literal
onef
                                          , Literal -> PrimOp -> RuleM CoreExpr
strengthReduction Literal
twof PrimOp
FloatAddOp  ]
             -- zeroElem zerof doesn't hold because of NaN
   PrimOp
FloatDivOp        -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
2 [ RuleM ()
guardFloatDiv forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> (RuleOpts -> Literal -> Literal -> Maybe CoreExpr)
-> RuleM CoreExpr
binaryLit ((Rational -> Rational -> Rational)
-> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
floatOp2 forall a. Fractional a => a -> a -> a
(/))
                                          , Literal -> RuleM CoreExpr
rightIdentity Literal
onef ]
   PrimOp
FloatNegOp        -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
1 [ (RuleOpts -> Literal -> Maybe CoreExpr) -> RuleM CoreExpr
unaryLit RuleOpts -> Literal -> Maybe CoreExpr
negOp
                                          , PrimOp -> RuleM CoreExpr
semiInversePrimOp PrimOp
FloatNegOp ]
   PrimOp
FloatDecode_IntOp -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
1 [ (RuleOpts -> Literal -> Maybe CoreExpr) -> RuleM CoreExpr
unaryLit RuleOpts -> Literal -> Maybe CoreExpr
floatDecodeOp ]

   -- Double
   PrimOp
DoubleAddOp          -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
2 [ (RuleOpts -> Literal -> Literal -> Maybe CoreExpr)
-> RuleM CoreExpr
binaryLit ((Rational -> Rational -> Rational)
-> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
doubleOp2 forall a. Num a => a -> a -> a
(+))
                                             , Literal -> RuleM CoreExpr
identity Literal
zerod ]
   PrimOp
DoubleSubOp          -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
2 [ (RuleOpts -> Literal -> Literal -> Maybe CoreExpr)
-> RuleM CoreExpr
binaryLit ((Rational -> Rational -> Rational)
-> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
doubleOp2 (-))
                                             , Literal -> RuleM CoreExpr
rightIdentity Literal
zerod ]
   PrimOp
DoubleMulOp          -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
2 [ (RuleOpts -> Literal -> Literal -> Maybe CoreExpr)
-> RuleM CoreExpr
binaryLit ((Rational -> Rational -> Rational)
-> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
doubleOp2 forall a. Num a => a -> a -> a
(*))
                                             , Literal -> RuleM CoreExpr
identity Literal
oned
                                             , Literal -> PrimOp -> RuleM CoreExpr
strengthReduction Literal
twod PrimOp
DoubleAddOp  ]
              -- zeroElem zerod doesn't hold because of NaN
   PrimOp
DoubleDivOp          -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
2 [ RuleM ()
guardDoubleDiv forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> (RuleOpts -> Literal -> Literal -> Maybe CoreExpr)
-> RuleM CoreExpr
binaryLit ((Rational -> Rational -> Rational)
-> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
doubleOp2 forall a. Fractional a => a -> a -> a
(/))
                                             , Literal -> RuleM CoreExpr
rightIdentity Literal
oned ]
   PrimOp
DoubleNegOp          -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
1 [ (RuleOpts -> Literal -> Maybe CoreExpr) -> RuleM CoreExpr
unaryLit RuleOpts -> Literal -> Maybe CoreExpr
negOp
                                             , PrimOp -> RuleM CoreExpr
semiInversePrimOp PrimOp
DoubleNegOp ]
   PrimOp
DoubleDecode_Int64Op -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
1 [ (RuleOpts -> Literal -> Maybe CoreExpr) -> RuleM CoreExpr
unaryLit RuleOpts -> Literal -> Maybe CoreExpr
doubleDecodeOp ]

   -- Relational operators

   PrimOp
IntEqOp    -> Name
-> (forall a. Ord a => a -> a -> Bool)
-> [RuleM CoreExpr]
-> Maybe CoreRule
mkRelOpRule Name
nm forall a. Eq a => a -> a -> Bool
(==) [ Bool -> RuleM CoreExpr
litEq Bool
True ]
   PrimOp
IntNeOp    -> Name
-> (forall a. Ord a => a -> a -> Bool)
-> [RuleM CoreExpr]
-> Maybe CoreRule
mkRelOpRule Name
nm forall a. Eq a => a -> a -> Bool
(/=) [ Bool -> RuleM CoreExpr
litEq Bool
False ]
   PrimOp
CharEqOp   -> Name
-> (forall a. Ord a => a -> a -> Bool)
-> [RuleM CoreExpr]
-> Maybe CoreRule
mkRelOpRule Name
nm forall a. Eq a => a -> a -> Bool
(==) [ Bool -> RuleM CoreExpr
litEq Bool
True ]
   PrimOp
CharNeOp   -> Name
-> (forall a. Ord a => a -> a -> Bool)
-> [RuleM CoreExpr]
-> Maybe CoreRule
mkRelOpRule Name
nm forall a. Eq a => a -> a -> Bool
(/=) [ Bool -> RuleM CoreExpr
litEq Bool
False ]

   PrimOp
IntGtOp    -> Name
-> (forall a. Ord a => a -> a -> Bool)
-> [RuleM CoreExpr]
-> Maybe CoreRule
mkRelOpRule Name
nm forall a. Ord a => a -> a -> Bool
(>)  [ Comparison -> RuleM CoreExpr
boundsCmp Comparison
Gt ]
   PrimOp
IntGeOp    -> Name
-> (forall a. Ord a => a -> a -> Bool)
-> [RuleM CoreExpr]
-> Maybe CoreRule
mkRelOpRule Name
nm forall a. Ord a => a -> a -> Bool
(>=) [ Comparison -> RuleM CoreExpr
boundsCmp Comparison
Ge ]
   PrimOp
IntLeOp    -> Name
-> (forall a. Ord a => a -> a -> Bool)
-> [RuleM CoreExpr]
-> Maybe CoreRule
mkRelOpRule Name
nm forall a. Ord a => a -> a -> Bool
(<=) [ Comparison -> RuleM CoreExpr
boundsCmp Comparison
Le ]
   PrimOp
IntLtOp    -> Name
-> (forall a. Ord a => a -> a -> Bool)
-> [RuleM CoreExpr]
-> Maybe CoreRule
mkRelOpRule Name
nm forall a. Ord a => a -> a -> Bool
(<)  [ Comparison -> RuleM CoreExpr
boundsCmp Comparison
Lt ]

   PrimOp
CharGtOp   -> Name
-> (forall a. Ord a => a -> a -> Bool)
-> [RuleM CoreExpr]
-> Maybe CoreRule
mkRelOpRule Name
nm forall a. Ord a => a -> a -> Bool
(>)  [ Comparison -> RuleM CoreExpr
boundsCmp Comparison
Gt ]
   PrimOp
CharGeOp   -> Name
-> (forall a. Ord a => a -> a -> Bool)
-> [RuleM CoreExpr]
-> Maybe CoreRule
mkRelOpRule Name
nm forall a. Ord a => a -> a -> Bool
(>=) [ Comparison -> RuleM CoreExpr
boundsCmp Comparison
Ge ]
   PrimOp
CharLeOp   -> Name
-> (forall a. Ord a => a -> a -> Bool)
-> [RuleM CoreExpr]
-> Maybe CoreRule
mkRelOpRule Name
nm forall a. Ord a => a -> a -> Bool
(<=) [ Comparison -> RuleM CoreExpr
boundsCmp Comparison
Le ]
   PrimOp
CharLtOp   -> Name
-> (forall a. Ord a => a -> a -> Bool)
-> [RuleM CoreExpr]
-> Maybe CoreRule
mkRelOpRule Name
nm forall a. Ord a => a -> a -> Bool
(<)  [ Comparison -> RuleM CoreExpr
boundsCmp Comparison
Lt ]

   PrimOp
FloatGtOp  -> Name -> (forall a. Ord a => a -> a -> Bool) -> Maybe CoreRule
mkFloatingRelOpRule Name
nm forall a. Ord a => a -> a -> Bool
(>)
   PrimOp
FloatGeOp  -> Name -> (forall a. Ord a => a -> a -> Bool) -> Maybe CoreRule
mkFloatingRelOpRule Name
nm forall a. Ord a => a -> a -> Bool
(>=)
   PrimOp
FloatLeOp  -> Name -> (forall a. Ord a => a -> a -> Bool) -> Maybe CoreRule
mkFloatingRelOpRule Name
nm forall a. Ord a => a -> a -> Bool
(<=)
   PrimOp
FloatLtOp  -> Name -> (forall a. Ord a => a -> a -> Bool) -> Maybe CoreRule
mkFloatingRelOpRule Name
nm forall a. Ord a => a -> a -> Bool
(<)
   PrimOp
FloatEqOp  -> Name -> (forall a. Ord a => a -> a -> Bool) -> Maybe CoreRule
mkFloatingRelOpRule Name
nm forall a. Eq a => a -> a -> Bool
(==)
   PrimOp
FloatNeOp  -> Name -> (forall a. Ord a => a -> a -> Bool) -> Maybe CoreRule
mkFloatingRelOpRule Name
nm forall a. Eq a => a -> a -> Bool
(/=)

   PrimOp
DoubleGtOp -> Name -> (forall a. Ord a => a -> a -> Bool) -> Maybe CoreRule
mkFloatingRelOpRule Name
nm forall a. Ord a => a -> a -> Bool
(>)
   PrimOp
DoubleGeOp -> Name -> (forall a. Ord a => a -> a -> Bool) -> Maybe CoreRule
mkFloatingRelOpRule Name
nm forall a. Ord a => a -> a -> Bool
(>=)
   PrimOp
DoubleLeOp -> Name -> (forall a. Ord a => a -> a -> Bool) -> Maybe CoreRule
mkFloatingRelOpRule Name
nm forall a. Ord a => a -> a -> Bool
(<=)
   PrimOp
DoubleLtOp -> Name -> (forall a. Ord a => a -> a -> Bool) -> Maybe CoreRule
mkFloatingRelOpRule Name
nm forall a. Ord a => a -> a -> Bool
(<)
   PrimOp
DoubleEqOp -> Name -> (forall a. Ord a => a -> a -> Bool) -> Maybe CoreRule
mkFloatingRelOpRule Name
nm forall a. Eq a => a -> a -> Bool
(==)
   PrimOp
DoubleNeOp -> Name -> (forall a. Ord a => a -> a -> Bool) -> Maybe CoreRule
mkFloatingRelOpRule Name
nm forall a. Eq a => a -> a -> Bool
(/=)

   PrimOp
WordGtOp   -> Name
-> (forall a. Ord a => a -> a -> Bool)
-> [RuleM CoreExpr]
-> Maybe CoreRule
mkRelOpRule Name
nm forall a. Ord a => a -> a -> Bool
(>)  [ Comparison -> RuleM CoreExpr
boundsCmp Comparison
Gt ]
   PrimOp
WordGeOp   -> Name
-> (forall a. Ord a => a -> a -> Bool)
-> [RuleM CoreExpr]
-> Maybe CoreRule
mkRelOpRule Name
nm forall a. Ord a => a -> a -> Bool
(>=) [ Comparison -> RuleM CoreExpr
boundsCmp Comparison
Ge ]
   PrimOp
WordLeOp   -> Name
-> (forall a. Ord a => a -> a -> Bool)
-> [RuleM CoreExpr]
-> Maybe CoreRule
mkRelOpRule Name
nm forall a. Ord a => a -> a -> Bool
(<=) [ Comparison -> RuleM CoreExpr
boundsCmp Comparison
Le ]
   PrimOp
WordLtOp   -> Name
-> (forall a. Ord a => a -> a -> Bool)
-> [RuleM CoreExpr]
-> Maybe CoreRule
mkRelOpRule Name
nm forall a. Ord a => a -> a -> Bool
(<)  [ Comparison -> RuleM CoreExpr
boundsCmp Comparison
Lt ]
   PrimOp
WordEqOp   -> Name
-> (forall a. Ord a => a -> a -> Bool)
-> [RuleM CoreExpr]
-> Maybe CoreRule
mkRelOpRule Name
nm forall a. Eq a => a -> a -> Bool
(==) [ Bool -> RuleM CoreExpr
litEq Bool
True ]
   PrimOp
WordNeOp   -> Name
-> (forall a. Ord a => a -> a -> Bool)
-> [RuleM CoreExpr]
-> Maybe CoreRule
mkRelOpRule Name
nm forall a. Eq a => a -> a -> Bool
(/=) [ Bool -> RuleM CoreExpr
litEq Bool
False ]

   PrimOp
AddrAddOp  -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
2 [ (Platform -> Literal) -> RuleM CoreExpr
rightIdentityPlatform Platform -> Literal
zeroi ]

   PrimOp
SeqOp      -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
4 [ RuleM CoreExpr
seqRule ]
   PrimOp
SparkOp    -> Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
4 [ RuleM CoreExpr
sparkRule ]

   PrimOp
_          -> forall a. Maybe a
Nothing

{-
************************************************************************
*                                                                      *
\subsection{Doing the business}
*                                                                      *
************************************************************************
-}

-- useful shorthands
mkPrimOpRule :: Name -> Int -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule :: Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
arity [RuleM CoreExpr]
rules = forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ Name -> ConTagZ -> RuleM CoreExpr -> CoreRule
mkBasicRule Name
nm ConTagZ
arity (forall (t :: * -> *) (m :: * -> *) a.
(Foldable t, MonadPlus m) =>
t (m a) -> m a
msum [RuleM CoreExpr]
rules)

mkRelOpRule :: Name -> (forall a . Ord a => a -> a -> Bool)
            -> [RuleM CoreExpr] -> Maybe CoreRule
mkRelOpRule :: Name
-> (forall a. Ord a => a -> a -> Bool)
-> [RuleM CoreExpr]
-> Maybe CoreRule
mkRelOpRule Name
nm forall a. Ord a => a -> a -> Bool
cmp [RuleM CoreExpr]
extra
  = Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
2 forall a b. (a -> b) -> a -> b
$
    (forall a. Ord a => a -> a -> Bool) -> RuleM CoreExpr
binaryCmpLit forall a. Ord a => a -> a -> Bool
cmp forall a. a -> [a] -> [a]
: RuleM CoreExpr
equal_rule forall a. a -> [a] -> [a]
: [RuleM CoreExpr]
extra
  where
        -- x `cmp` x does not depend on x, so
        -- compute it for the arbitrary value 'True'
        -- and use that result
    equal_rule :: RuleM CoreExpr
equal_rule = do { RuleM ()
equalArgs
                    ; Platform
platform <- RuleM Platform
getPlatform
                    ; forall (m :: * -> *) a. Monad m => a -> m a
return (if forall a. Ord a => a -> a -> Bool
cmp Bool
True Bool
True
                              then Platform -> CoreExpr
trueValInt  Platform
platform
                              else Platform -> CoreExpr
falseValInt Platform
platform) }

{- Note [Rules for floating-point comparisons]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
We need different rules for floating-point values because for floats
it is not true that x = x (for NaNs); so we do not want the equal_rule
rule that mkRelOpRule uses.

Note also that, in the case of equality/inequality, we do /not/
want to switch to a case-expression.  For example, we do not want
to convert
   case (eqFloat# x 3.8#) of
     True -> this
     False -> that
to
  case x of
    3.8#::Float# -> this
    _            -> that
See #9238.  Reason: comparing floating-point values for equality
delicate, and we don't want to implement that delicacy in the code for
case expressions.  So we make it an invariant of Core that a case
expression never scrutinises a Float# or Double#.

This transformation is what the litEq rule does;
see Note [The litEq rule: converting equality to case].
So we /refrain/ from using litEq for mkFloatingRelOpRule.
-}

mkFloatingRelOpRule :: Name -> (forall a . Ord a => a -> a -> Bool)
                    -> Maybe CoreRule
-- See Note [Rules for floating-point comparisons]
mkFloatingRelOpRule :: Name -> (forall a. Ord a => a -> a -> Bool) -> Maybe CoreRule
mkFloatingRelOpRule Name
nm forall a. Ord a => a -> a -> Bool
cmp
  = Name -> ConTagZ -> [RuleM CoreExpr] -> Maybe CoreRule
mkPrimOpRule Name
nm ConTagZ
2 [(forall a. Ord a => a -> a -> Bool) -> RuleM CoreExpr
binaryCmpLit forall a. Ord a => a -> a -> Bool
cmp]

-- common constants
zeroi, onei, zerow, onew :: Platform -> Literal
zeroi :: Platform -> Literal
zeroi Platform
platform = Platform -> Integer -> Literal
mkLitInt  Platform
platform Integer
0
onei :: Platform -> Literal
onei  Platform
platform = Platform -> Integer -> Literal
mkLitInt  Platform
platform Integer
1
zerow :: Platform -> Literal
zerow Platform
platform = Platform -> Integer -> Literal
mkLitWord Platform
platform Integer
0
onew :: Platform -> Literal
onew  Platform
platform = Platform -> Integer -> Literal
mkLitWord Platform
platform Integer
1

zeroI8, oneI8, zeroW8, oneW8 :: Literal
zeroI8 :: Literal
zeroI8 = Integer -> Literal
mkLitInt8  Integer
0
oneI8 :: Literal
oneI8  = Integer -> Literal
mkLitInt8  Integer
1
zeroW8 :: Literal
zeroW8 = Integer -> Literal
mkLitWord8 Integer
0
oneW8 :: Literal
oneW8  = Integer -> Literal
mkLitWord8 Integer
1

zeroI16, oneI16, zeroW16, oneW16 :: Literal
zeroI16 :: Literal
zeroI16 = Integer -> Literal
mkLitInt16  Integer
0
oneI16 :: Literal
oneI16  = Integer -> Literal
mkLitInt16  Integer
1
zeroW16 :: Literal
zeroW16 = Integer -> Literal
mkLitWord16 Integer
0
oneW16 :: Literal
oneW16  = Integer -> Literal
mkLitWord16 Integer
1

zeroI32, oneI32, zeroW32, oneW32 :: Literal
zeroI32 :: Literal
zeroI32 = Integer -> Literal
mkLitInt32  Integer
0
oneI32 :: Literal
oneI32  = Integer -> Literal
mkLitInt32  Integer
1
zeroW32 :: Literal
zeroW32 = Integer -> Literal
mkLitWord32 Integer
0
oneW32 :: Literal
oneW32  = Integer -> Literal
mkLitWord32 Integer
1

#if WORD_SIZE_IN_BITS < 64
zeroI64, oneI64, zeroW64, oneW64 :: Literal
zeroI64 = mkLitInt64  0
oneI64  = mkLitInt64  1
zeroW64 = mkLitWord64 0
oneW64  = mkLitWord64 1
#endif

zerof, onef, twof, zerod, oned, twod :: Literal
zerof :: Literal
zerof = Rational -> Literal
mkLitFloat Rational
0.0
onef :: Literal
onef  = Rational -> Literal
mkLitFloat Rational
1.0
twof :: Literal
twof  = Rational -> Literal
mkLitFloat Rational
2.0
zerod :: Literal
zerod = Rational -> Literal
mkLitDouble Rational
0.0
oned :: Literal
oned  = Rational -> Literal
mkLitDouble Rational
1.0
twod :: Literal
twod  = Rational -> Literal
mkLitDouble Rational
2.0

cmpOp :: Platform -> (forall a . Ord a => a -> a -> Bool)
      -> Literal -> Literal -> Maybe CoreExpr
cmpOp :: Platform
-> (forall a. Ord a => a -> a -> Bool)
-> Literal
-> Literal
-> Maybe CoreExpr
cmpOp Platform
platform forall a. Ord a => a -> a -> Bool
cmp = Literal -> Literal -> Maybe CoreExpr
go
  where
    done :: Bool -> Maybe CoreExpr
done Bool
True  = forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ Platform -> CoreExpr
trueValInt  Platform
platform
    done Bool
False = forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ Platform -> CoreExpr
falseValInt Platform
platform

    -- These compares are at different types
    go :: Literal -> Literal -> Maybe CoreExpr
go (LitChar Char
i1)   (LitChar Char
i2)   = Bool -> Maybe CoreExpr
done (Char
i1 forall a. Ord a => a -> a -> Bool
`cmp` Char
i2)
    go (LitFloat Rational
i1)  (LitFloat Rational
i2)  = Bool -> Maybe CoreExpr
done (Rational
i1 forall a. Ord a => a -> a -> Bool
`cmp` Rational
i2)
    go (LitDouble Rational
i1) (LitDouble Rational
i2) = Bool -> Maybe CoreExpr
done (Rational
i1 forall a. Ord a => a -> a -> Bool
`cmp` Rational
i2)
    go (LitNumber LitNumType
nt1 Integer
i1) (LitNumber LitNumType
nt2 Integer
i2)
      | LitNumType
nt1 forall a. Eq a => a -> a -> Bool
/= LitNumType
nt2 = forall a. Maybe a
Nothing
      | Bool
otherwise  = Bool -> Maybe CoreExpr
done (Integer
i1 forall a. Ord a => a -> a -> Bool
`cmp` Integer
i2)
    go Literal
_               Literal
_               = forall a. Maybe a
Nothing

--------------------------

negOp :: RuleOpts -> Literal -> Maybe CoreExpr  -- Negate
negOp :: RuleOpts -> Literal -> Maybe CoreExpr
negOp RuleOpts
env = \case
   (LitFloat Rational
0.0)  -> forall a. Maybe a
Nothing  -- can't represent -0.0 as a Rational
   (LitFloat Rational
f)    -> forall a. a -> Maybe a
Just (RuleOpts -> Rational -> CoreExpr
mkFloatVal RuleOpts
env (-Rational
f))
   (LitDouble Rational
0.0) -> forall a. Maybe a
Nothing
   (LitDouble Rational
d)   -> forall a. a -> Maybe a
Just (RuleOpts -> Rational -> CoreExpr
mkDoubleVal RuleOpts
env (-Rational
d))
   (LitNumber LitNumType
nt Integer
i)
      | LitNumType -> Bool
litNumIsSigned LitNumType
nt -> forall a. a -> Maybe a
Just (forall b. Literal -> Expr b
Lit (Platform -> LitNumType -> Integer -> Literal
mkLitNumberWrap (RuleOpts -> Platform
roPlatform RuleOpts
env) LitNumType
nt (-Integer
i)))
   Literal
_ -> forall a. Maybe a
Nothing

complementOp :: RuleOpts -> Literal -> Maybe CoreExpr  -- Binary complement
complementOp :: RuleOpts -> Literal -> Maybe CoreExpr
complementOp RuleOpts
env (LitNumber LitNumType
nt Integer
i) =
   forall a. a -> Maybe a
Just (forall b. Literal -> Expr b
Lit (Platform -> LitNumType -> Integer -> Literal
mkLitNumberWrap (RuleOpts -> Platform
roPlatform RuleOpts
env) LitNumType
nt (forall a. Bits a => a -> a
complement Integer
i)))
complementOp RuleOpts
_      Literal
_            = forall a. Maybe a
Nothing

int8Op2
  :: (Integral a, Integral b)
  => (a -> b -> Integer)
  -> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
int8Op2 :: forall a b.
(Integral a, Integral b) =>
(a -> b -> Integer)
-> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
int8Op2 a -> b -> Integer
op RuleOpts
_ (LitNumber LitNumType
LitNumInt8 Integer
i1) (LitNumber LitNumType
LitNumInt8 Integer
i2) =
  Integer -> Maybe CoreExpr
int8Result (forall a. Num a => Integer -> a
fromInteger Integer
i1 a -> b -> Integer
`op` forall a. Num a => Integer -> a
fromInteger Integer
i2)
int8Op2 a -> b -> Integer
_ RuleOpts
_ Literal
_ Literal
_ = forall a. Maybe a
Nothing

int16Op2
  :: (Integral a, Integral b)
  => (a -> b -> Integer)
  -> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
int16Op2 :: forall a b.
(Integral a, Integral b) =>
(a -> b -> Integer)
-> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
int16Op2 a -> b -> Integer
op RuleOpts
_ (LitNumber LitNumType
LitNumInt16 Integer
i1) (LitNumber LitNumType
LitNumInt16 Integer
i2) =
  Integer -> Maybe CoreExpr
int16Result (forall a. Num a => Integer -> a
fromInteger Integer
i1 a -> b -> Integer
`op` forall a. Num a => Integer -> a
fromInteger Integer
i2)
int16Op2 a -> b -> Integer
_ RuleOpts
_ Literal
_ Literal
_ = forall a. Maybe a
Nothing

int32Op2
  :: (Integral a, Integral b)
  => (a -> b -> Integer)
  -> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
int32Op2 :: forall a b.
(Integral a, Integral b) =>
(a -> b -> Integer)
-> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
int32Op2 a -> b -> Integer
op RuleOpts
_ (LitNumber LitNumType
LitNumInt32 Integer
i1) (LitNumber LitNumType
LitNumInt32 Integer
i2) =
  Integer -> Maybe CoreExpr
int32Result (forall a. Num a => Integer -> a
fromInteger Integer
i1 a -> b -> Integer
`op` forall a. Num a => Integer -> a
fromInteger Integer
i2)
int32Op2 a -> b -> Integer
_ RuleOpts
_ Literal
_ Literal
_ = forall a. Maybe a
Nothing

#if WORD_SIZE_IN_BITS < 64
int64Op2
  :: (Integral a, Integral b)
  => (a -> b -> Integer)
  -> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
int64Op2 op _ (LitNumber LitNumInt64 i1) (LitNumber LitNumInt64 i2) =
  int64Result (fromInteger i1 `op` fromInteger i2)
int64Op2 _ _ _ _ = Nothing
#endif

intOp2 :: (Integral a, Integral b)
       => (a -> b -> Integer)
       -> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
intOp2 :: forall a b.
(Integral a, Integral b) =>
(a -> b -> Integer)
-> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
intOp2 = forall a b.
(Integral a, Integral b) =>
(RuleOpts -> a -> b -> Integer)
-> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
intOp2' forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. a -> b -> a
const

intOp2' :: (Integral a, Integral b)
        => (RuleOpts -> a -> b -> Integer)
        -> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
intOp2' :: forall a b.
(Integral a, Integral b) =>
(RuleOpts -> a -> b -> Integer)
-> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
intOp2' RuleOpts -> a -> b -> Integer
op RuleOpts
env (LitNumber LitNumType
LitNumInt Integer
i1) (LitNumber LitNumType
LitNumInt Integer
i2) =
  let o :: a -> b -> Integer
o = RuleOpts -> a -> b -> Integer
op RuleOpts
env
  in  Platform -> Integer -> Maybe CoreExpr
intResult (RuleOpts -> Platform
roPlatform RuleOpts
env) (forall a. Num a => Integer -> a
fromInteger Integer
i1 a -> b -> Integer
`o` forall a. Num a => Integer -> a
fromInteger Integer
i2)
intOp2' RuleOpts -> a -> b -> Integer
_ RuleOpts
_ Literal
_ Literal
_ = forall a. Maybe a
Nothing

intOpC2 :: (Integral a, Integral b)
        => (a -> b -> Integer)
        -> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
intOpC2 :: forall a b.
(Integral a, Integral b) =>
(a -> b -> Integer)
-> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
intOpC2 a -> b -> Integer
op RuleOpts
env (LitNumber LitNumType
LitNumInt Integer
i1) (LitNumber LitNumType
LitNumInt Integer
i2) =
  Platform -> Integer -> Maybe CoreExpr
intCResult (RuleOpts -> Platform
roPlatform RuleOpts
env) (forall a. Num a => Integer -> a
fromInteger Integer
i1 a -> b -> Integer
`op` forall a. Num a => Integer -> a
fromInteger Integer
i2)
intOpC2 a -> b -> Integer
_ RuleOpts
_ Literal
_ Literal
_ = forall a. Maybe a
Nothing

shiftRightLogical :: forall t. (Integral t, Bits t) => Integer -> Int -> Integer
shiftRightLogical :: forall t. (Integral t, Bits t) => Integer -> ConTagZ -> Integer
shiftRightLogical Integer
x ConTagZ
n = forall a b. (Integral a, Num b) => a -> b
fromIntegral (forall a. Num a => Integer -> a
fromInteger Integer
x forall a. Bits a => a -> ConTagZ -> a
`shiftR` ConTagZ
n :: t)

-- | Shift right, putting zeros in rather than sign-propagating as
-- 'Bits.shiftR' would do. Do this by converting to the appropriate Word
-- and back. Obviously this won't work for too-big values, but its ok as
-- we use it here.
shiftRightLogicalNative :: Platform -> Integer -> Int -> Integer
shiftRightLogicalNative :: Platform -> Integer -> ConTagZ -> Integer
shiftRightLogicalNative Platform
platform =
    case Platform -> PlatformWordSize
platformWordSize Platform
platform of
      PlatformWordSize
PW4 -> forall t. (Integral t, Bits t) => Integer -> ConTagZ -> Integer
shiftRightLogical @Word32
      PlatformWordSize
PW8 -> forall t. (Integral t, Bits t) => Integer -> ConTagZ -> Integer
shiftRightLogical @Word64

--------------------------
retLit :: (Platform -> Literal) -> RuleM CoreExpr
retLit :: (Platform -> Literal) -> RuleM CoreExpr
retLit Platform -> Literal
l = do Platform
platform <- RuleM Platform
getPlatform
              forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall b. Literal -> Expr b
Lit forall a b. (a -> b) -> a -> b
$ Platform -> Literal
l Platform
platform

retLitNoC :: (Platform -> Literal) -> RuleM CoreExpr
retLitNoC :: (Platform -> Literal) -> RuleM CoreExpr
retLitNoC Platform -> Literal
l = do Platform
platform <- RuleM Platform
getPlatform
                 let lit :: Literal
lit = Platform -> Literal
l Platform
platform
                 let ty :: Type
ty = Literal -> Type
literalType Literal
lit
                 forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ [Type] -> [CoreExpr] -> CoreExpr
mkCoreUbxTup [Type
ty, Type
ty] [forall b. Literal -> Expr b
Lit Literal
lit, forall b. Literal -> Expr b
Lit (Platform -> Literal
zeroi Platform
platform)]

word8Op2
  :: (Integral a, Integral b)
  => (a -> b -> Integer)
  -> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
word8Op2 :: forall a b.
(Integral a, Integral b) =>
(a -> b -> Integer)
-> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
word8Op2 a -> b -> Integer
op RuleOpts
_ (LitNumber LitNumType
LitNumWord8 Integer
i1) (LitNumber LitNumType
LitNumWord8 Integer
i2) =
  Integer -> Maybe CoreExpr
word8Result (forall a. Num a => Integer -> a
fromInteger Integer
i1 a -> b -> Integer
`op` forall a. Num a => Integer -> a
fromInteger Integer
i2)
word8Op2 a -> b -> Integer
_ RuleOpts
_ Literal
_ Literal
_ = forall a. Maybe a
Nothing

word16Op2
  :: (Integral a, Integral b)
  => (a -> b -> Integer)
  -> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
word16Op2 :: forall a b.
(Integral a, Integral b) =>
(a -> b -> Integer)
-> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
word16Op2 a -> b -> Integer
op RuleOpts
_ (LitNumber LitNumType
LitNumWord16 Integer
i1) (LitNumber LitNumType
LitNumWord16 Integer
i2) =
  Integer -> Maybe CoreExpr
word16Result (forall a. Num a => Integer -> a
fromInteger Integer
i1 a -> b -> Integer
`op` forall a. Num a => Integer -> a
fromInteger Integer
i2)
word16Op2 a -> b -> Integer
_ RuleOpts
_ Literal
_ Literal
_ = forall a. Maybe a
Nothing

word32Op2
  :: (Integral a, Integral b)
  => (a -> b -> Integer)
  -> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
word32Op2 :: forall a b.
(Integral a, Integral b) =>
(a -> b -> Integer)
-> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
word32Op2 a -> b -> Integer
op RuleOpts
_ (LitNumber LitNumType
LitNumWord32 Integer
i1) (LitNumber LitNumType
LitNumWord32 Integer
i2) =
  Integer -> Maybe CoreExpr
word32Result (forall a. Num a => Integer -> a
fromInteger Integer
i1 a -> b -> Integer
`op` forall a. Num a => Integer -> a
fromInteger Integer
i2)
word32Op2 a -> b -> Integer
_ RuleOpts
_ Literal
_ Literal
_ = forall a. Maybe a
Nothing

#if WORD_SIZE_IN_BITS < 64
word64Op2
  :: (Integral a, Integral b)
  => (a -> b -> Integer)
  -> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
word64Op2 op _ (LitNumber LitNumWord64 i1) (LitNumber LitNumWord64 i2) =
  word64Result (fromInteger i1 `op` fromInteger i2)
word64Op2 _ _ _ _ = Nothing
#endif

wordOp2 :: (Integral a, Integral b)
        => (a -> b -> Integer)
        -> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
wordOp2 :: forall a b.
(Integral a, Integral b) =>
(a -> b -> Integer)
-> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
wordOp2 a -> b -> Integer
op RuleOpts
env (LitNumber LitNumType
LitNumWord Integer
w1) (LitNumber LitNumType
LitNumWord Integer
w2)
    = Platform -> Integer -> Maybe CoreExpr
wordResult (RuleOpts -> Platform
roPlatform RuleOpts
env) (forall a. Num a => Integer -> a
fromInteger Integer
w1 a -> b -> Integer
`op` forall a. Num a => Integer -> a
fromInteger Integer
w2)
wordOp2 a -> b -> Integer
_ RuleOpts
_ Literal
_ Literal
_ = forall a. Maybe a
Nothing

wordOpC2 :: (Integral a, Integral b)
        => (a -> b -> Integer)
        -> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
wordOpC2 :: forall a b.
(Integral a, Integral b) =>
(a -> b -> Integer)
-> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
wordOpC2 a -> b -> Integer
op RuleOpts
env (LitNumber LitNumType
LitNumWord Integer
w1) (LitNumber LitNumType
LitNumWord Integer
w2) =
  Platform -> Integer -> Maybe CoreExpr
wordCResult (RuleOpts -> Platform
roPlatform RuleOpts
env) (forall a. Num a => Integer -> a
fromInteger Integer
w1 a -> b -> Integer
`op` forall a. Num a => Integer -> a
fromInteger Integer
w2)
wordOpC2 a -> b -> Integer
_ RuleOpts
_ Literal
_ Literal
_ = forall a. Maybe a
Nothing

shiftRule :: LitNumType
          -> (Platform -> Integer -> Int -> Integer)
          -> RuleM CoreExpr
-- Shifts take an Int; hence third arg of op is Int
-- Used for shift primops
--    IntSllOp, IntSraOp, IntSrlOp :: Int# -> Int# -> Int#
--    SllOp, SrlOp                 :: Word# -> Int# -> Word#
shiftRule :: LitNumType
-> (Platform -> Integer -> ConTagZ -> Integer) -> RuleM CoreExpr
shiftRule LitNumType
lit_num_ty Platform -> Integer -> ConTagZ -> Integer
shift_op = do
  Platform
platform <- RuleM Platform
getPlatform
  [CoreExpr
e1, Lit (LitNumber LitNumType
LitNumInt Integer
shift_len)] <- RuleM [CoreExpr]
getArgs

  Integer
bit_size <- case Platform -> LitNumType -> Maybe Word
litNumBitSize Platform
platform LitNumType
lit_num_ty of
   Maybe Word
Nothing -> forall (m :: * -> *) a. MonadPlus m => m a
mzero
   Just Word
bs -> forall (f :: * -> *) a. Applicative f => a -> f a
pure (forall a. Integral a => a -> Integer
toInteger Word
bs)

  case CoreExpr
e1 of
    CoreExpr
_ | Integer
shift_len forall a. Eq a => a -> a -> Bool
== Integer
0 -> forall (f :: * -> *) a. Applicative f => a -> f a
pure CoreExpr
e1

      -- See Note [Guarding against silly shifts]
    CoreExpr
_ | Integer
shift_len forall a. Ord a => a -> a -> Bool
< Integer
0 Bool -> Bool -> Bool
|| Integer
shift_len forall a. Ord a => a -> a -> Bool
> Integer
bit_size
      -> forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ forall b. Literal -> Expr b
Lit forall a b. (a -> b) -> a -> b
$ Platform -> LitNumType -> Integer -> Literal
mkLitNumberWrap Platform
platform LitNumType
lit_num_ty Integer
0
           -- Be sure to use lit_num_ty here, so we get a correctly typed zero.
           -- See #18589

    Lit (LitNumber LitNumType
nt Integer
x)
       | Integer
0 forall a. Ord a => a -> a -> Bool
< Integer
shift_len Bool -> Bool -> Bool
&& Integer
shift_len forall a. Ord a => a -> a -> Bool
<= Integer
bit_size
       -> ASSERT(nt == lit_num_ty)
          let op :: Integer -> ConTagZ -> Integer
op = Platform -> Integer -> ConTagZ -> Integer
shift_op Platform
platform
              -- Do the shift at type Integer, but shift length is Int.
              -- Using host's Int is ok even if target's Int has a different size
              -- because we test that shift_len <= bit_size (which is at most 64)
              y :: Integer
y  = Integer
x Integer -> ConTagZ -> Integer
`op` forall a. Num a => Integer -> a
fromInteger Integer
shift_len
          in forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ forall b. Literal -> Expr b
Lit forall a b. (a -> b) -> a -> b
$ Platform -> LitNumType -> Integer -> Literal
mkLitNumberWrap Platform
platform LitNumType
nt Integer
y

    CoreExpr
_ -> forall (m :: * -> *) a. MonadPlus m => m a
mzero

--------------------------
floatOp2 :: (Rational -> Rational -> Rational)
         -> RuleOpts -> Literal -> Literal
         -> Maybe (Expr CoreBndr)
floatOp2 :: (Rational -> Rational -> Rational)
-> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
floatOp2 Rational -> Rational -> Rational
op RuleOpts
env (LitFloat Rational
f1) (LitFloat Rational
f2)
  = forall a. a -> Maybe a
Just (RuleOpts -> Rational -> CoreExpr
mkFloatVal RuleOpts
env (Rational
f1 Rational -> Rational -> Rational
`op` Rational
f2))
floatOp2 Rational -> Rational -> Rational
_ RuleOpts
_ Literal
_ Literal
_ = forall a. Maybe a
Nothing

--------------------------
floatDecodeOp :: RuleOpts -> Literal -> Maybe CoreExpr
floatDecodeOp :: RuleOpts -> Literal -> Maybe CoreExpr
floatDecodeOp RuleOpts
env (LitFloat ((forall a. RealFloat a => a -> (Integer, ConTagZ)
decodeFloat forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Fractional a => Rational -> a
fromRational @Float) -> (Integer
m, ConTagZ
e)))
  = forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ [Type] -> [CoreExpr] -> CoreExpr
mkCoreUbxTup [Type
intPrimTy, Type
intPrimTy]
                        [ Platform -> Integer -> CoreExpr
mkIntVal (RuleOpts -> Platform
roPlatform RuleOpts
env) (forall a. Integral a => a -> Integer
toInteger Integer
m)
                        , Platform -> Integer -> CoreExpr
mkIntVal (RuleOpts -> Platform
roPlatform RuleOpts
env) (forall a. Integral a => a -> Integer
toInteger ConTagZ
e) ]
floatDecodeOp RuleOpts
_   Literal
_
  = forall a. Maybe a
Nothing

--------------------------
doubleOp2 :: (Rational -> Rational -> Rational)
          -> RuleOpts -> Literal -> Literal
          -> Maybe (Expr CoreBndr)
doubleOp2 :: (Rational -> Rational -> Rational)
-> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
doubleOp2 Rational -> Rational -> Rational
op RuleOpts
env (LitDouble Rational
f1) (LitDouble Rational
f2)
  = forall a. a -> Maybe a
Just (RuleOpts -> Rational -> CoreExpr
mkDoubleVal RuleOpts
env (Rational
f1 Rational -> Rational -> Rational
`op` Rational
f2))
doubleOp2 Rational -> Rational -> Rational
_ RuleOpts
_ Literal
_ Literal
_ = forall a. Maybe a
Nothing

--------------------------
doubleDecodeOp :: RuleOpts -> Literal -> Maybe CoreExpr
doubleDecodeOp :: RuleOpts -> Literal -> Maybe CoreExpr
doubleDecodeOp RuleOpts
env (LitDouble ((forall a. RealFloat a => a -> (Integer, ConTagZ)
decodeFloat forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Fractional a => Rational -> a
fromRational @Double) -> (Integer
m, ConTagZ
e)))
  = forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ [Type] -> [CoreExpr] -> CoreExpr
mkCoreUbxTup [Type
iNT64Ty, Type
intPrimTy]
                        [ forall b. Literal -> Expr b
Lit (Integer -> Literal
mkLitINT64 (forall a. Integral a => a -> Integer
toInteger Integer
m))
                        , Platform -> Integer -> CoreExpr
mkIntVal Platform
platform (forall a. Integral a => a -> Integer
toInteger ConTagZ
e) ]
  where
    platform :: Platform
platform = RuleOpts -> Platform
roPlatform RuleOpts
env
    (Type
iNT64Ty, Integer -> Literal
mkLitINT64)
      | Platform -> ConTagZ
platformWordSizeInBits Platform
platform forall a. Ord a => a -> a -> Bool
< ConTagZ
64
      = (Type
int64PrimTy, Integer -> Literal
mkLitInt64Wrap)
      | Bool
otherwise
      = (Type
intPrimTy  , Platform -> Integer -> Literal
mkLitIntWrap Platform
platform)
doubleDecodeOp RuleOpts
_   Literal
_
  = forall a. Maybe a
Nothing

--------------------------
{- Note [The litEq rule: converting equality to case]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This stuff turns
     n ==# 3#
into
     case n of
       3# -> True
       m  -> False

This is a Good Thing, because it allows case-of case things
to happen, and case-default absorption to happen.  For
example:

     if (n ==# 3#) || (n ==# 4#) then e1 else e2
will transform to
     case n of
       3# -> e1
       4# -> e1
       m  -> e2
(modulo the usual precautions to avoid duplicating e1)
-}

litEq :: Bool  -- True <=> equality, False <=> inequality
      -> RuleM CoreExpr
litEq :: Bool -> RuleM CoreExpr
litEq Bool
is_eq = forall (t :: * -> *) (m :: * -> *) a.
(Foldable t, MonadPlus m) =>
t (m a) -> m a
msum
  [ do [Lit Literal
lit, CoreExpr
expr] <- RuleM [CoreExpr]
getArgs
       Platform
platform <- RuleM Platform
getPlatform
       Platform -> Literal -> CoreExpr -> RuleM CoreExpr
do_lit_eq Platform
platform Literal
lit CoreExpr
expr
  , do [CoreExpr
expr, Lit Literal
lit] <- RuleM [CoreExpr]
getArgs
       Platform
platform <- RuleM Platform
getPlatform
       Platform -> Literal -> CoreExpr -> RuleM CoreExpr
do_lit_eq Platform
platform Literal
lit CoreExpr
expr ]
  where
    do_lit_eq :: Platform -> Literal -> CoreExpr -> RuleM CoreExpr
do_lit_eq Platform
platform Literal
lit CoreExpr
expr = do
      forall (f :: * -> *). Alternative f => Bool -> f ()
guard (Bool -> Bool
not (Literal -> Bool
litIsLifted Literal
lit))
      forall (m :: * -> *) a. Monad m => a -> m a
return (CoreExpr -> Scaled Type -> Type -> [CoreAlt] -> CoreExpr
mkWildCase CoreExpr
expr (forall a. a -> Scaled a
unrestricted forall a b. (a -> b) -> a -> b
$ Literal -> Type
literalType Literal
lit) Type
intPrimTy
                    [ forall b. AltCon -> [b] -> Expr b -> Alt b
Alt AltCon
DEFAULT      [] CoreExpr
val_if_neq
                    , forall b. AltCon -> [b] -> Expr b -> Alt b
Alt (Literal -> AltCon
LitAlt Literal
lit) [] CoreExpr
val_if_eq])
      where
        val_if_eq :: CoreExpr
val_if_eq  | Bool
is_eq     = Platform -> CoreExpr
trueValInt  Platform
platform
                   | Bool
otherwise = Platform -> CoreExpr
falseValInt Platform
platform
        val_if_neq :: CoreExpr
val_if_neq | Bool
is_eq     = Platform -> CoreExpr
falseValInt Platform
platform
                   | Bool
otherwise = Platform -> CoreExpr
trueValInt  Platform
platform


-- | Check if there is comparison with minBound or maxBound, that is
-- always true or false. For instance, an Int cannot be smaller than its
-- minBound, so we can replace such comparison with False.
boundsCmp :: Comparison -> RuleM CoreExpr
boundsCmp :: Comparison -> RuleM CoreExpr
boundsCmp Comparison
op = do
  Platform
platform <- RuleM Platform
getPlatform
  [CoreExpr
a, CoreExpr
b] <- RuleM [CoreExpr]
getArgs
  forall a. Maybe a -> RuleM a
liftMaybe forall a b. (a -> b) -> a -> b
$ Platform -> Comparison -> CoreExpr -> CoreExpr -> Maybe CoreExpr
mkRuleFn Platform
platform Comparison
op CoreExpr
a CoreExpr
b

data Comparison = Gt | Ge | Lt | Le

mkRuleFn :: Platform -> Comparison -> CoreExpr -> CoreExpr -> Maybe CoreExpr
mkRuleFn :: Platform -> Comparison -> CoreExpr -> CoreExpr -> Maybe CoreExpr
mkRuleFn Platform
platform Comparison
Gt (Lit Literal
lit) CoreExpr
_ | Platform -> Literal -> Bool
isMinBound Platform
platform Literal
lit = forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ Platform -> CoreExpr
falseValInt Platform
platform
mkRuleFn Platform
platform Comparison
Le (Lit Literal
lit) CoreExpr
_ | Platform -> Literal -> Bool
isMinBound Platform
platform Literal
lit = forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ Platform -> CoreExpr
trueValInt  Platform
platform
mkRuleFn Platform
platform Comparison
Ge CoreExpr
_ (Lit Literal
lit) | Platform -> Literal -> Bool
isMinBound Platform
platform Literal
lit = forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ Platform -> CoreExpr
trueValInt  Platform
platform
mkRuleFn Platform
platform Comparison
Lt CoreExpr
_ (Lit Literal
lit) | Platform -> Literal -> Bool
isMinBound Platform
platform Literal
lit = forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ Platform -> CoreExpr
falseValInt Platform
platform
mkRuleFn Platform
platform Comparison
Ge (Lit Literal
lit) CoreExpr
_ | Platform -> Literal -> Bool
isMaxBound Platform
platform Literal
lit = forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ Platform -> CoreExpr
trueValInt  Platform
platform
mkRuleFn Platform
platform Comparison
Lt (Lit Literal
lit) CoreExpr
_ | Platform -> Literal -> Bool
isMaxBound Platform
platform Literal
lit = forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ Platform -> CoreExpr
falseValInt Platform
platform
mkRuleFn Platform
platform Comparison
Gt CoreExpr
_ (Lit Literal
lit) | Platform -> Literal -> Bool
isMaxBound Platform
platform Literal
lit = forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ Platform -> CoreExpr
falseValInt Platform
platform
mkRuleFn Platform
platform Comparison
Le CoreExpr
_ (Lit Literal
lit) | Platform -> Literal -> Bool
isMaxBound Platform
platform Literal
lit = forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ Platform -> CoreExpr
trueValInt  Platform
platform
mkRuleFn Platform
_ Comparison
_ CoreExpr
_ CoreExpr
_                                           = forall a. Maybe a
Nothing

-- | Create an Int literal expression while ensuring the given Integer is in the
-- target Int range
int8Result :: Integer -> Maybe CoreExpr
int8Result :: Integer -> Maybe CoreExpr
int8Result Integer
result = forall a. a -> Maybe a
Just (Integer -> CoreExpr
int8Result' Integer
result)

int8Result' :: Integer -> CoreExpr
int8Result' :: Integer -> CoreExpr
int8Result' Integer
result = forall b. Literal -> Expr b
Lit (Integer -> Literal
mkLitInt8Wrap Integer
result)

-- | Create an Int literal expression while ensuring the given Integer is in the
-- target Int range
int16Result :: Integer -> Maybe CoreExpr
int16Result :: Integer -> Maybe CoreExpr
int16Result Integer
result = forall a. a -> Maybe a
Just (Integer -> CoreExpr
int16Result' Integer
result)

int16Result' :: Integer -> CoreExpr
int16Result' :: Integer -> CoreExpr
int16Result' Integer
result = forall b. Literal -> Expr b
Lit (Integer -> Literal
mkLitInt16Wrap Integer
result)

-- | Create an Int literal expression while ensuring the given Integer is in the
-- target Int range
int32Result :: Integer -> Maybe CoreExpr
int32Result :: Integer -> Maybe CoreExpr
int32Result Integer
result = forall a. a -> Maybe a
Just (Integer -> CoreExpr
int32Result' Integer
result)

int32Result' :: Integer -> CoreExpr
int32Result' :: Integer -> CoreExpr
int32Result' Integer
result = forall b. Literal -> Expr b
Lit (Integer -> Literal
mkLitInt32Wrap Integer
result)

intResult :: Platform -> Integer -> Maybe CoreExpr
intResult :: Platform -> Integer -> Maybe CoreExpr
intResult Platform
platform Integer
result = forall a. a -> Maybe a
Just (Platform -> Integer -> CoreExpr
intResult' Platform
platform Integer
result)

intResult' :: Platform -> Integer -> CoreExpr
intResult' :: Platform -> Integer -> CoreExpr
intResult' Platform
platform Integer
result = forall b. Literal -> Expr b
Lit (Platform -> Integer -> Literal
mkLitIntWrap Platform
platform Integer
result)

-- | Create an unboxed pair of an Int literal expression, ensuring the given
-- Integer is in the target Int range and the corresponding overflow flag
-- (@0#@/@1#@) if it wasn't.
intCResult :: Platform -> Integer -> Maybe CoreExpr
intCResult :: Platform -> Integer -> Maybe CoreExpr
intCResult Platform
platform Integer
result = forall a. a -> Maybe a
Just ([CoreExpr] -> CoreExpr
mkPair [forall b. Literal -> Expr b
Lit Literal
lit, forall b. Literal -> Expr b
Lit Literal
c])
  where
    mkPair :: [CoreExpr] -> CoreExpr
mkPair = [Type] -> [CoreExpr] -> CoreExpr
mkCoreUbxTup [Type
intPrimTy, Type
intPrimTy]
    (Literal
lit, Bool
b) = Platform -> Integer -> (Literal, Bool)
mkLitIntWrapC Platform
platform Integer
result
    c :: Literal
c = if Bool
b then Platform -> Literal
onei Platform
platform else Platform -> Literal
zeroi Platform
platform

-- | Create a Word literal expression while ensuring the given Integer is in the
-- target Word range
word8Result :: Integer -> Maybe CoreExpr
word8Result :: Integer -> Maybe CoreExpr
word8Result Integer
result = forall a. a -> Maybe a
Just (Integer -> CoreExpr
word8Result' Integer
result)

word8Result' :: Integer -> CoreExpr
word8Result' :: Integer -> CoreExpr
word8Result' Integer
result = forall b. Literal -> Expr b
Lit (Integer -> Literal
mkLitWord8Wrap Integer
result)

-- | Create a Word literal expression while ensuring the given Integer is in the
-- target Word range
word16Result :: Integer -> Maybe CoreExpr
word16Result :: Integer -> Maybe CoreExpr
word16Result Integer
result = forall a. a -> Maybe a
Just (Integer -> CoreExpr
word16Result' Integer
result)

word16Result' :: Integer -> CoreExpr
word16Result' :: Integer -> CoreExpr
word16Result' Integer
result = forall b. Literal -> Expr b
Lit (Integer -> Literal
mkLitWord16Wrap Integer
result)

-- | Create a Word literal expression while ensuring the given Integer is in the
-- target Word range
word32Result :: Integer -> Maybe CoreExpr
word32Result :: Integer -> Maybe CoreExpr
word32Result Integer
result = forall a. a -> Maybe a
Just (Integer -> CoreExpr
word32Result' Integer
result)

word32Result' :: Integer -> CoreExpr
word32Result' :: Integer -> CoreExpr
word32Result' Integer
result = forall b. Literal -> Expr b
Lit (Integer -> Literal
mkLitWord32Wrap Integer
result)

-- | Create a Word literal expression while ensuring the given Integer is in the
-- target Word range
wordResult :: Platform -> Integer -> Maybe CoreExpr
wordResult :: Platform -> Integer -> Maybe CoreExpr
wordResult Platform
platform Integer
result = forall a. a -> Maybe a
Just (Platform -> Integer -> CoreExpr
wordResult' Platform
platform Integer
result)

wordResult' :: Platform -> Integer -> CoreExpr
wordResult' :: Platform -> Integer -> CoreExpr
wordResult' Platform
platform Integer
result = forall b. Literal -> Expr b
Lit (Platform -> Integer -> Literal
mkLitWordWrap Platform
platform Integer
result)

-- | Create an unboxed pair of a Word literal expression, ensuring the given
-- Integer is in the target Word range and the corresponding carry flag
-- (@0#@/@1#@) if it wasn't.
wordCResult :: Platform -> Integer -> Maybe CoreExpr
wordCResult :: Platform -> Integer -> Maybe CoreExpr
wordCResult Platform
platform Integer
result = forall a. a -> Maybe a
Just ([CoreExpr] -> CoreExpr
mkPair [forall b. Literal -> Expr b
Lit Literal
lit, forall b. Literal -> Expr b
Lit Literal
c])
  where
    mkPair :: [CoreExpr] -> CoreExpr
mkPair = [Type] -> [CoreExpr] -> CoreExpr
mkCoreUbxTup [Type
wordPrimTy, Type
intPrimTy]
    (Literal
lit, Bool
b) = Platform -> Integer -> (Literal, Bool)
mkLitWordWrapC Platform
platform Integer
result
    c :: Literal
c = if Bool
b then Platform -> Literal
onei Platform
platform else Platform -> Literal
zeroi Platform
platform

#if WORD_SIZE_IN_BITS < 64
int64Result :: Integer -> Maybe CoreExpr
int64Result result = Just (int64Result' result)

int64Result' :: Integer -> CoreExpr
int64Result' result = Lit (mkLitInt64Wrap result)

word64Result :: Integer -> Maybe CoreExpr
word64Result result = Just (word64Result' result)

word64Result' :: Integer -> CoreExpr
word64Result' result = Lit (mkLitWord64Wrap result)
#endif


-- | 'ambiant (primop x) = x', but not nececesarily 'primop (ambient x) = x'.
semiInversePrimOp :: PrimOp -> RuleM CoreExpr
semiInversePrimOp :: PrimOp -> RuleM CoreExpr
semiInversePrimOp PrimOp
primop = do
  [Var Id
primop_id `App` CoreExpr
e] <- RuleM [CoreExpr]
getArgs
  PrimOp -> Id -> RuleM ()
matchPrimOpId PrimOp
primop Id
primop_id
  forall (m :: * -> *) a. Monad m => a -> m a
return CoreExpr
e

subsumesPrimOp :: PrimOp -> PrimOp -> RuleM CoreExpr
PrimOp
this subsumesPrimOp :: PrimOp -> PrimOp -> RuleM CoreExpr
`subsumesPrimOp` PrimOp
that = do
  [Var Id
primop_id `App` CoreExpr
e] <- RuleM [CoreExpr]
getArgs
  PrimOp -> Id -> RuleM ()
matchPrimOpId PrimOp
that Id
primop_id
  forall (m :: * -> *) a. Monad m => a -> m a
return (forall b. Id -> Expr b
Var (PrimOp -> Id
mkPrimOpId PrimOp
this) forall b. Expr b -> Expr b -> Expr b
`App` CoreExpr
e)

subsumedByPrimOp :: PrimOp -> RuleM CoreExpr
subsumedByPrimOp :: PrimOp -> RuleM CoreExpr
subsumedByPrimOp PrimOp
primop = do
  [e :: CoreExpr
e@(Var Id
primop_id `App` CoreExpr
_)] <- RuleM [CoreExpr]
getArgs
  PrimOp -> Id -> RuleM ()
matchPrimOpId PrimOp
primop Id
primop_id
  forall (m :: * -> *) a. Monad m => a -> m a
return CoreExpr
e

-- | Transform `extendWordN (narrowWordN x)` into `x .&. 0xFF..FF`
extendNarrowPassthrough :: PrimOp -> Integer -> RuleM CoreExpr
extendNarrowPassthrough :: PrimOp -> Integer -> RuleM CoreExpr
extendNarrowPassthrough PrimOp
narrow_primop Integer
n = do
  [Var Id
primop_id `App` CoreExpr
x] <- RuleM [CoreExpr]
getArgs
  PrimOp -> Id -> RuleM ()
matchPrimOpId PrimOp
narrow_primop Id
primop_id
  forall (m :: * -> *) a. Monad m => a -> m a
return (forall b. Id -> Expr b
Var (PrimOp -> Id
mkPrimOpId PrimOp
WordAndOp) forall b. Expr b -> Expr b -> Expr b
`App` CoreExpr
x forall b. Expr b -> Expr b -> Expr b
`App` forall b. Literal -> Expr b
Lit (LitNumType -> Integer -> Literal
LitNumber LitNumType
LitNumWord Integer
n))

-- | narrow subsumes bitwise `and` with full mask (cf #16402):
--
--       narrowN (x .&. m)
--       m .&. (2^N-1) = 2^N-1
--       ==> narrowN x
--
-- e.g.  narrow16 (x .&. 0xFFFF)
--       ==> narrow16 x
--
narrowSubsumesAnd :: PrimOp -> PrimOp -> Int -> RuleM CoreExpr
narrowSubsumesAnd :: PrimOp -> PrimOp -> ConTagZ -> RuleM CoreExpr
narrowSubsumesAnd PrimOp
and_primop PrimOp
narrw ConTagZ
n = do
  [Var Id
primop_id `App` CoreExpr
x `App` CoreExpr
y] <- RuleM [CoreExpr]
getArgs
  PrimOp -> Id -> RuleM ()
matchPrimOpId PrimOp
and_primop Id
primop_id
  let mask :: Integer
mask = forall a. Bits a => ConTagZ -> a
bit ConTagZ
n forall a. Num a => a -> a -> a
-Integer
1
      g :: CoreExpr -> CoreExpr -> RuleM CoreExpr
g CoreExpr
v (Lit (LitNumber LitNumType
_ Integer
m)) = do
         forall (f :: * -> *). Alternative f => Bool -> f ()
guard (Integer
m forall a. Bits a => a -> a -> a
.&. Integer
mask forall a. Eq a => a -> a -> Bool
== Integer
mask)
         forall (m :: * -> *) a. Monad m => a -> m a
return (forall b. Id -> Expr b
Var (PrimOp -> Id
mkPrimOpId PrimOp
narrw) forall b. Expr b -> Expr b -> Expr b
`App` CoreExpr
v)
      g CoreExpr
_ CoreExpr
_ = forall (m :: * -> *) a. MonadPlus m => m a
mzero
  CoreExpr -> CoreExpr -> RuleM CoreExpr
g CoreExpr
x CoreExpr
y forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> CoreExpr -> CoreExpr -> RuleM CoreExpr
g CoreExpr
y CoreExpr
x

idempotent :: RuleM CoreExpr
idempotent :: RuleM CoreExpr
idempotent = do [CoreExpr
e1, CoreExpr
e2] <- RuleM [CoreExpr]
getArgs
                forall (f :: * -> *). Alternative f => Bool -> f ()
guard forall a b. (a -> b) -> a -> b
$ forall b. Expr b -> Expr b -> Bool
cheapEqExpr CoreExpr
e1 CoreExpr
e2
                forall (m :: * -> *) a. Monad m => a -> m a
return CoreExpr
e1

-- | Match
--       (op (op v e) e)
--    or (op e (op v e))
--    or (op (op e v) e)
--    or (op e (op e v))
--  and return the innermost (op v e) or (op e v).
sameArgIdempotentCommut :: PrimOp -> RuleM CoreExpr
sameArgIdempotentCommut :: PrimOp -> RuleM CoreExpr
sameArgIdempotentCommut PrimOp
op = do
  let is_op :: CoreExpr -> Maybe (CoreExpr, CoreExpr)
is_op = \case
        BinOpApp CoreExpr
v PrimOp
op' CoreExpr
e | PrimOp
op forall a. Eq a => a -> a -> Bool
== PrimOp
op' -> forall a. a -> Maybe a
Just (CoreExpr
v,CoreExpr
e)
        CoreExpr
_                            -> forall a. Maybe a
Nothing
  [CoreExpr
a,CoreExpr
b] <- RuleM [CoreExpr]
getArgs
  case (CoreExpr
a,CoreExpr
b) of
    (CoreExpr -> Maybe (CoreExpr, CoreExpr)
is_op -> Just (CoreExpr
e1,CoreExpr
e2), CoreExpr
e3)
      | forall b. Expr b -> Expr b -> Bool
cheapEqExpr CoreExpr
e2 CoreExpr
e3 -> forall (m :: * -> *) a. Monad m => a -> m a
return CoreExpr
a
      | forall b. Expr b -> Expr b -> Bool
cheapEqExpr CoreExpr
e1 CoreExpr
e3 -> forall (m :: * -> *) a. Monad m => a -> m a
return CoreExpr
a
    (CoreExpr
e3, CoreExpr -> Maybe (CoreExpr, CoreExpr)
is_op -> Just (CoreExpr
e1,CoreExpr
e2))
      | forall b. Expr b -> Expr b -> Bool
cheapEqExpr CoreExpr
e2 CoreExpr
e3 -> forall (m :: * -> *) a. Monad m => a -> m a
return CoreExpr
b
      | forall b. Expr b -> Expr b -> Bool
cheapEqExpr CoreExpr
e1 CoreExpr
e3 -> forall (m :: * -> *) a. Monad m => a -> m a
return CoreExpr
b
    (CoreExpr, CoreExpr)
_ -> forall (m :: * -> *) a. MonadPlus m => m a
mzero

{-
Note [Guarding against silly shifts]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Consider this code:

  import Data.Bits( (.|.), shiftL )
  chunkToBitmap :: [Bool] -> Word32
  chunkToBitmap chunk = foldr (.|.) 0 [ 1 `shiftL` n | (True,n) <- zip chunk [0..] ]

This optimises to:
Shift.$wgo = \ (w_sCS :: GHC.Prim.Int#) (w1_sCT :: [GHC.Types.Bool]) ->
    case w1_sCT of _ {
      [] -> 0##;
      : x_aAW xs_aAX ->
        case x_aAW of _ {
          GHC.Types.False ->
            case w_sCS of wild2_Xh {
              __DEFAULT -> Shift.$wgo (GHC.Prim.+# wild2_Xh 1) xs_aAX;
              9223372036854775807 -> 0## };
          GHC.Types.True ->
            case GHC.Prim.>=# w_sCS 64 of _ {
              GHC.Types.False ->
                case w_sCS of wild3_Xh {
                  __DEFAULT ->
                    case Shift.$wgo (GHC.Prim.+# wild3_Xh 1) xs_aAX of ww_sCW { __DEFAULT ->
                      GHC.Prim.or# (GHC.Prim.narrow32Word#
                                      (GHC.Prim.uncheckedShiftL# 1## wild3_Xh))
                                   ww_sCW
                     };
                  9223372036854775807 ->
                    GHC.Prim.narrow32Word#
!!!!-->                  (GHC.Prim.uncheckedShiftL# 1## 9223372036854775807)
                };
              GHC.Types.True ->
                case w_sCS of wild3_Xh {
                  __DEFAULT -> Shift.$wgo (GHC.Prim.+# wild3_Xh 1) xs_aAX;
                  9223372036854775807 -> 0##
                } } } }

Note the massive shift on line "!!!!".  It can't happen, because we've checked
that w < 64, but the optimiser didn't spot that. We DO NOT want to constant-fold this!
Moreover, if the programmer writes (n `uncheckedShiftL` 9223372036854775807), we
can't constant fold it, but if it gets to the assembler we get
     Error: operand type mismatch for `shl'

So the best thing to do is to rewrite the shift with a call to error,
when the second arg is large. However, in general we cannot do this; consider
this case

    let x = I# (uncheckedIShiftL# n 80)
    in ...

Here x contains an invalid shift and consequently we would like to rewrite it
as follows:

    let x = I# (error "invalid shift)
    in ...

This was originally done in the fix to #16449 but this breaks the let/app
invariant (see Note [Core let/app invariant] in GHC.Core) as noted in #16742.
For the reasons discussed in Note [Checking versus non-checking primops] (in
the PrimOp module) there is no safe way rewrite the argument of I# such that
it bottoms.

Consequently we instead take advantage of the fact that large shifts are
undefined behavior (see associated documentation in primops.txt.pp) and
transform the invalid shift into an "obviously incorrect" value.

There are two cases:

- Shifting fixed-width things: the primops IntSll, Sll, etc
  These are handled by shiftRule.

  We are happy to shift by any amount up to wordSize but no more.

- Shifting Bignums (Integer, Natural): these are handled by bignum_shift.

  Here we could in principle shift by any amount, but we arbitrary
  limit the shift to 4 bits; in particular we do not want shift by a
  huge amount, which can happen in code like that above.

The two cases are more different in their code paths that is comfortable,
but that is only a historical accident.


************************************************************************
*                                                                      *
\subsection{Vaguely generic functions}
*                                                                      *
************************************************************************
-}

mkBasicRule :: Name -> Int -> RuleM CoreExpr -> CoreRule
-- Gives the Rule the same name as the primop itself
mkBasicRule :: Name -> ConTagZ -> RuleM CoreExpr -> CoreRule
mkBasicRule Name
op_name ConTagZ
n_args RuleM CoreExpr
rm
  = BuiltinRule { ru_name :: RuleName
ru_name  = OccName -> RuleName
occNameFS (Name -> OccName
nameOccName Name
op_name),
                  ru_fn :: Name
ru_fn    = Name
op_name,
                  ru_nargs :: ConTagZ
ru_nargs = ConTagZ
n_args,
                  ru_try :: RuleFun
ru_try   = forall r.
RuleM r -> RuleOpts -> InScopeEnv -> Id -> [CoreExpr] -> Maybe r
runRuleM RuleM CoreExpr
rm }

newtype RuleM r = RuleM
  { forall r.
RuleM r -> RuleOpts -> InScopeEnv -> Id -> [CoreExpr] -> Maybe r
runRuleM :: RuleOpts -> InScopeEnv -> Id -> [CoreExpr] -> Maybe r }
  deriving (forall a b. a -> RuleM b -> RuleM a
forall a b. (a -> b) -> RuleM a -> RuleM b
forall (f :: * -> *).
(forall a b. (a -> b) -> f a -> f b)
-> (forall a b. a -> f b -> f a) -> Functor f
<$ :: forall a b. a -> RuleM b -> RuleM a
$c<$ :: forall a b. a -> RuleM b -> RuleM a
fmap :: forall a b. (a -> b) -> RuleM a -> RuleM b
$cfmap :: forall a b. (a -> b) -> RuleM a -> RuleM b
Functor)

instance Applicative RuleM where
    pure :: forall a. a -> RuleM a
pure a
x = forall r.
(RuleOpts -> InScopeEnv -> Id -> [CoreExpr] -> Maybe r) -> RuleM r
RuleM forall a b. (a -> b) -> a -> b
$ \RuleOpts
_ InScopeEnv
_ Id
_ [CoreExpr]
_ -> forall a. a -> Maybe a
Just a
x
    <*> :: forall a b. RuleM (a -> b) -> RuleM a -> RuleM b
(<*>) = forall (m :: * -> *) a b. Monad m => m (a -> b) -> m a -> m b
ap

instance Monad RuleM where
  RuleM RuleOpts -> InScopeEnv -> Id -> [CoreExpr] -> Maybe a
f >>= :: forall a b. RuleM a -> (a -> RuleM b) -> RuleM b
>>= a -> RuleM b
g
    = forall r.
(RuleOpts -> InScopeEnv -> Id -> [CoreExpr] -> Maybe r) -> RuleM r
RuleM forall a b. (a -> b) -> a -> b
$ \RuleOpts
env InScopeEnv
iu Id
fn [CoreExpr]
args ->
              case RuleOpts -> InScopeEnv -> Id -> [CoreExpr] -> Maybe a
f RuleOpts
env InScopeEnv
iu Id
fn [CoreExpr]
args of
                Maybe a
Nothing -> forall a. Maybe a
Nothing
                Just a
r  -> forall r.
RuleM r -> RuleOpts -> InScopeEnv -> Id -> [CoreExpr] -> Maybe r
runRuleM (a -> RuleM b
g a
r) RuleOpts
env InScopeEnv
iu Id
fn [CoreExpr]
args

instance MonadFail RuleM where
    fail :: forall a. String -> RuleM a
fail String
_ = forall (m :: * -> *) a. MonadPlus m => m a
mzero

instance Alternative RuleM where
  empty :: forall a. RuleM a
empty = forall r.
(RuleOpts -> InScopeEnv -> Id -> [CoreExpr] -> Maybe r) -> RuleM r
RuleM forall a b. (a -> b) -> a -> b
$ \RuleOpts
_ InScopeEnv
_ Id
_ [CoreExpr]
_ -> forall a. Maybe a
Nothing
  RuleM RuleOpts -> InScopeEnv -> Id -> [CoreExpr] -> Maybe a
f1 <|> :: forall a. RuleM a -> RuleM a -> RuleM a
<|> RuleM RuleOpts -> InScopeEnv -> Id -> [CoreExpr] -> Maybe a
f2 = forall r.
(RuleOpts -> InScopeEnv -> Id -> [CoreExpr] -> Maybe r) -> RuleM r
RuleM forall a b. (a -> b) -> a -> b
$ \RuleOpts
env InScopeEnv
iu Id
fn [CoreExpr]
args ->
    RuleOpts -> InScopeEnv -> Id -> [CoreExpr] -> Maybe a
f1 RuleOpts
env InScopeEnv
iu Id
fn [CoreExpr]
args forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> RuleOpts -> InScopeEnv -> Id -> [CoreExpr] -> Maybe a
f2 RuleOpts
env InScopeEnv
iu Id
fn [CoreExpr]
args

instance MonadPlus RuleM

getPlatform :: RuleM Platform
getPlatform :: RuleM Platform
getPlatform = RuleOpts -> Platform
roPlatform forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> RuleM RuleOpts
getRuleOpts

getRuleOpts :: RuleM RuleOpts
getRuleOpts :: RuleM RuleOpts
getRuleOpts = forall r.
(RuleOpts -> InScopeEnv -> Id -> [CoreExpr] -> Maybe r) -> RuleM r
RuleM forall a b. (a -> b) -> a -> b
$ \RuleOpts
rule_opts InScopeEnv
_ Id
_ [CoreExpr]
_ -> forall a. a -> Maybe a
Just RuleOpts
rule_opts

getEnv :: RuleM InScopeEnv
getEnv :: RuleM InScopeEnv
getEnv = forall r.
(RuleOpts -> InScopeEnv -> Id -> [CoreExpr] -> Maybe r) -> RuleM r
RuleM forall a b. (a -> b) -> a -> b
$ \RuleOpts
_ InScopeEnv
env Id
_ [CoreExpr]
_ -> forall a. a -> Maybe a
Just InScopeEnv
env

liftMaybe :: Maybe a -> RuleM a
liftMaybe :: forall a. Maybe a -> RuleM a
liftMaybe Maybe a
Nothing = forall (m :: * -> *) a. MonadPlus m => m a
mzero
liftMaybe (Just a
x) = forall (m :: * -> *) a. Monad m => a -> m a
return a
x

liftLit :: (Literal -> Literal) -> RuleM CoreExpr
liftLit :: (Literal -> Literal) -> RuleM CoreExpr
liftLit Literal -> Literal
f = (Platform -> Literal -> Literal) -> RuleM CoreExpr
liftLitPlatform (forall a b. a -> b -> a
const Literal -> Literal
f)

liftLitPlatform :: (Platform -> Literal -> Literal) -> RuleM CoreExpr
liftLitPlatform :: (Platform -> Literal -> Literal) -> RuleM CoreExpr
liftLitPlatform Platform -> Literal -> Literal
f = do
  Platform
platform <- RuleM Platform
getPlatform
  [Lit Literal
lit] <- RuleM [CoreExpr]
getArgs
  forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall b. Literal -> Expr b
Lit (Platform -> Literal -> Literal
f Platform
platform Literal
lit)

removeOp32 :: RuleM CoreExpr
removeOp32 :: RuleM CoreExpr
removeOp32 = do
  Platform
platform <- RuleM Platform
getPlatform
  case Platform -> PlatformWordSize
platformWordSize Platform
platform of
    PlatformWordSize
PW4 -> do
      [CoreExpr
e] <- RuleM [CoreExpr]
getArgs
      forall (m :: * -> *) a. Monad m => a -> m a
return CoreExpr
e
    PlatformWordSize
PW8 ->
      forall (m :: * -> *) a. MonadPlus m => m a
mzero

getArgs :: RuleM [CoreExpr]
getArgs :: RuleM [CoreExpr]
getArgs = forall r.
(RuleOpts -> InScopeEnv -> Id -> [CoreExpr] -> Maybe r) -> RuleM r
RuleM forall a b. (a -> b) -> a -> b
$ \RuleOpts
_ InScopeEnv
_ Id
_ [CoreExpr]
args -> forall a. a -> Maybe a
Just [CoreExpr]
args

getInScopeEnv :: RuleM InScopeEnv
getInScopeEnv :: RuleM InScopeEnv
getInScopeEnv = forall r.
(RuleOpts -> InScopeEnv -> Id -> [CoreExpr] -> Maybe r) -> RuleM r
RuleM forall a b. (a -> b) -> a -> b
$ \RuleOpts
_ InScopeEnv
iu Id
_ [CoreExpr]
_ -> forall a. a -> Maybe a
Just InScopeEnv
iu

getFunction :: RuleM Id
getFunction :: RuleM Id
getFunction = forall r.
(RuleOpts -> InScopeEnv -> Id -> [CoreExpr] -> Maybe r) -> RuleM r
RuleM forall a b. (a -> b) -> a -> b
$ \RuleOpts
_ InScopeEnv
_ Id
fn [CoreExpr]
_ -> forall a. a -> Maybe a
Just Id
fn

exprIsVarApp_maybe :: InScopeEnv -> CoreExpr -> Maybe (Id,CoreArg)
exprIsVarApp_maybe :: InScopeEnv -> CoreExpr -> Maybe (Id, CoreExpr)
exprIsVarApp_maybe env :: InScopeEnv
env@(InScopeSet
_, IdUnfoldingFun
id_unf) CoreExpr
e = case CoreExpr
e of
  App (Var Id
f) CoreExpr
a -> forall a. a -> Maybe a
Just (Id
f, CoreExpr
a)
  Var Id
v
    | Just CoreExpr
rhs <- Unfolding -> Maybe CoreExpr
expandUnfolding_maybe (IdUnfoldingFun
id_unf Id
v)
    -> InScopeEnv -> CoreExpr -> Maybe (Id, CoreExpr)
exprIsVarApp_maybe InScopeEnv
env CoreExpr
rhs
  CoreExpr
_ -> forall a. Maybe a
Nothing

-- | Looks into the expression or its unfolding to find "App (Var f) x"
isVarApp :: InScopeEnv -> CoreExpr -> RuleM (Id,CoreArg)
isVarApp :: InScopeEnv -> CoreExpr -> RuleM (Id, CoreExpr)
isVarApp InScopeEnv
env CoreExpr
e = case InScopeEnv -> CoreExpr -> Maybe (Id, CoreExpr)
exprIsVarApp_maybe InScopeEnv
env CoreExpr
e of
  Maybe (Id, CoreExpr)
Nothing -> forall (m :: * -> *) a. MonadPlus m => m a
mzero
  Just (Id, CoreExpr)
r  -> forall (f :: * -> *) a. Applicative f => a -> f a
pure (Id, CoreExpr)
r

isLiteral :: CoreExpr -> RuleM Literal
isLiteral :: CoreExpr -> RuleM Literal
isLiteral CoreExpr
e = do
    InScopeEnv
env <- RuleM InScopeEnv
getInScopeEnv
    case InScopeEnv -> CoreExpr -> Maybe Literal
exprIsLiteral_maybe InScopeEnv
env CoreExpr
e of
        Maybe Literal
Nothing -> forall (m :: * -> *) a. MonadPlus m => m a
mzero
        Just Literal
l  -> forall (f :: * -> *) a. Applicative f => a -> f a
pure Literal
l

isNumberLiteral :: CoreExpr -> RuleM Integer
isNumberLiteral :: CoreExpr -> RuleM Integer
isNumberLiteral CoreExpr
e = CoreExpr -> RuleM Literal
isLiteral CoreExpr
e forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
  LitNumber LitNumType
_ Integer
x -> forall (f :: * -> *) a. Applicative f => a -> f a
pure Integer
x
  Literal
_             -> forall (m :: * -> *) a. MonadPlus m => m a
mzero

isIntegerLiteral :: CoreExpr -> RuleM Integer
isIntegerLiteral :: CoreExpr -> RuleM Integer
isIntegerLiteral CoreExpr
e = CoreExpr -> RuleM Literal
isLiteral CoreExpr
e forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
  LitNumber LitNumType
LitNumInteger Integer
x -> forall (f :: * -> *) a. Applicative f => a -> f a
pure Integer
x
  Literal
_                         -> forall (m :: * -> *) a. MonadPlus m => m a
mzero

isNaturalLiteral :: CoreExpr -> RuleM Integer
isNaturalLiteral :: CoreExpr -> RuleM Integer
isNaturalLiteral CoreExpr
e = CoreExpr -> RuleM Literal
isLiteral CoreExpr
e forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
  LitNumber LitNumType
LitNumNatural Integer
x -> forall (f :: * -> *) a. Applicative f => a -> f a
pure Integer
x
  Literal
_                         -> forall (m :: * -> *) a. MonadPlus m => m a
mzero

isWordLiteral :: CoreExpr -> RuleM Integer
isWordLiteral :: CoreExpr -> RuleM Integer
isWordLiteral CoreExpr
e = CoreExpr -> RuleM Literal
isLiteral CoreExpr
e forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
  LitNumber LitNumType
LitNumWord Integer
x -> forall (f :: * -> *) a. Applicative f => a -> f a
pure Integer
x
  Literal
_                      -> forall (m :: * -> *) a. MonadPlus m => m a
mzero

isIntLiteral :: CoreExpr -> RuleM Integer
isIntLiteral :: CoreExpr -> RuleM Integer
isIntLiteral CoreExpr
e = CoreExpr -> RuleM Literal
isLiteral CoreExpr
e forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
  LitNumber LitNumType
LitNumInt Integer
x -> forall (f :: * -> *) a. Applicative f => a -> f a
pure Integer
x
  Literal
_                     -> forall (m :: * -> *) a. MonadPlus m => m a
mzero

-- return the n-th argument of this rule, if it is a literal
-- argument indices start from 0
getLiteral :: Int -> RuleM Literal
getLiteral :: ConTagZ -> RuleM Literal
getLiteral ConTagZ
n = forall r.
(RuleOpts -> InScopeEnv -> Id -> [CoreExpr] -> Maybe r) -> RuleM r
RuleM forall a b. (a -> b) -> a -> b
$ \RuleOpts
_ InScopeEnv
_ Id
_ [CoreExpr]
exprs -> case forall a. ConTagZ -> [a] -> [a]
drop ConTagZ
n [CoreExpr]
exprs of
  (Lit Literal
l:[CoreExpr]
_) -> forall a. a -> Maybe a
Just Literal
l
  [CoreExpr]
_ -> forall a. Maybe a
Nothing

unaryLit :: (RuleOpts -> Literal -> Maybe CoreExpr) -> RuleM CoreExpr
unaryLit :: (RuleOpts -> Literal -> Maybe CoreExpr) -> RuleM CoreExpr
unaryLit RuleOpts -> Literal -> Maybe CoreExpr
op = do
  RuleOpts
env <- RuleM RuleOpts
getRuleOpts
  [Lit Literal
l] <- RuleM [CoreExpr]
getArgs
  forall a. Maybe a -> RuleM a
liftMaybe forall a b. (a -> b) -> a -> b
$ RuleOpts -> Literal -> Maybe CoreExpr
op RuleOpts
env (RuleOpts -> Literal -> Literal
convFloating RuleOpts
env Literal
l)

binaryLit :: (RuleOpts -> Literal -> Literal -> Maybe CoreExpr) -> RuleM CoreExpr
binaryLit :: (RuleOpts -> Literal -> Literal -> Maybe CoreExpr)
-> RuleM CoreExpr
binaryLit RuleOpts -> Literal -> Literal -> Maybe CoreExpr
op = do
  RuleOpts
env <- RuleM RuleOpts
getRuleOpts
  [Lit Literal
l1, Lit Literal
l2] <- RuleM [CoreExpr]
getArgs
  forall a. Maybe a -> RuleM a
liftMaybe forall a b. (a -> b) -> a -> b
$ RuleOpts -> Literal -> Literal -> Maybe CoreExpr
op RuleOpts
env (RuleOpts -> Literal -> Literal
convFloating RuleOpts
env Literal
l1) (RuleOpts -> Literal -> Literal
convFloating RuleOpts
env Literal
l2)

binaryCmpLit :: (forall a . Ord a => a -> a -> Bool) -> RuleM CoreExpr
binaryCmpLit :: (forall a. Ord a => a -> a -> Bool) -> RuleM CoreExpr
binaryCmpLit forall a. Ord a => a -> a -> Bool
op = do
  Platform
platform <- RuleM Platform
getPlatform
  (RuleOpts -> Literal -> Literal -> Maybe CoreExpr)
-> RuleM CoreExpr
binaryLit (\RuleOpts
_ -> Platform
-> (forall a. Ord a => a -> a -> Bool)
-> Literal
-> Literal
-> Maybe CoreExpr
cmpOp Platform
platform forall a. Ord a => a -> a -> Bool
op)

leftIdentity :: Literal -> RuleM CoreExpr
leftIdentity :: Literal -> RuleM CoreExpr
leftIdentity Literal
id_lit = (Platform -> Literal) -> RuleM CoreExpr
leftIdentityPlatform (forall a b. a -> b -> a
const Literal
id_lit)

rightIdentity :: Literal -> RuleM CoreExpr
rightIdentity :: Literal -> RuleM CoreExpr
rightIdentity Literal
id_lit = (Platform -> Literal) -> RuleM CoreExpr
rightIdentityPlatform (forall a b. a -> b -> a
const Literal
id_lit)

identity :: Literal -> RuleM CoreExpr
identity :: Literal -> RuleM CoreExpr
identity Literal
lit = Literal -> RuleM CoreExpr
leftIdentity Literal
lit forall (m :: * -> *) a. MonadPlus m => m a -> m a -> m a
`mplus` Literal -> RuleM CoreExpr
rightIdentity Literal
lit

leftIdentityPlatform :: (Platform -> Literal) -> RuleM CoreExpr
leftIdentityPlatform :: (Platform -> Literal) -> RuleM CoreExpr
leftIdentityPlatform Platform -> Literal
id_lit = do
  Platform
platform <- RuleM Platform
getPlatform
  [Lit Literal
l1, CoreExpr
e2] <- RuleM [CoreExpr]
getArgs
  forall (f :: * -> *). Alternative f => Bool -> f ()
guard forall a b. (a -> b) -> a -> b
$ Literal
l1 forall a. Eq a => a -> a -> Bool
== Platform -> Literal
id_lit Platform
platform
  forall (m :: * -> *) a. Monad m => a -> m a
return CoreExpr
e2

-- | Left identity rule for PrimOps like 'IntAddC' and 'WordAddC', where, in
-- addition to the result, we have to indicate that no carry/overflow occurred.
leftIdentityCPlatform :: (Platform -> Literal) -> RuleM CoreExpr
leftIdentityCPlatform :: (Platform -> Literal) -> RuleM CoreExpr
leftIdentityCPlatform Platform -> Literal
id_lit = do
  Platform
platform <- RuleM Platform
getPlatform
  [Lit Literal
l1, CoreExpr
e2] <- RuleM [CoreExpr]
getArgs
  forall (f :: * -> *). Alternative f => Bool -> f ()
guard forall a b. (a -> b) -> a -> b
$ Literal
l1 forall a. Eq a => a -> a -> Bool
== Platform -> Literal
id_lit Platform
platform
  let no_c :: CoreExpr
no_c = forall b. Literal -> Expr b
Lit (Platform -> Literal
zeroi Platform
platform)
  forall (m :: * -> *) a. Monad m => a -> m a
return ([Type] -> [CoreExpr] -> CoreExpr
mkCoreUbxTup [CoreExpr -> Type
exprType CoreExpr
e2, Type
intPrimTy] [CoreExpr
e2, CoreExpr
no_c])

rightIdentityPlatform :: (Platform -> Literal) -> RuleM CoreExpr
rightIdentityPlatform :: (Platform -> Literal) -> RuleM CoreExpr
rightIdentityPlatform Platform -> Literal
id_lit = do
  Platform
platform <- RuleM Platform
getPlatform
  [CoreExpr
e1, Lit Literal
l2] <- RuleM [CoreExpr]
getArgs
  forall (f :: * -> *). Alternative f => Bool -> f ()
guard forall a b. (a -> b) -> a -> b
$ Literal
l2 forall a. Eq a => a -> a -> Bool
== Platform -> Literal
id_lit Platform
platform
  forall (m :: * -> *) a. Monad m => a -> m a
return CoreExpr
e1

-- | Right identity rule for PrimOps like 'IntSubC' and 'WordSubC', where, in
-- addition to the result, we have to indicate that no carry/overflow occurred.
rightIdentityCPlatform :: (Platform -> Literal) -> RuleM CoreExpr
rightIdentityCPlatform :: (Platform -> Literal) -> RuleM CoreExpr
rightIdentityCPlatform Platform -> Literal
id_lit = do
  Platform
platform <- RuleM Platform
getPlatform
  [CoreExpr
e1, Lit Literal
l2] <- RuleM [CoreExpr]
getArgs
  forall (f :: * -> *). Alternative f => Bool -> f ()
guard forall a b. (a -> b) -> a -> b
$ Literal
l2 forall a. Eq a => a -> a -> Bool
== Platform -> Literal
id_lit Platform
platform
  let no_c :: CoreExpr
no_c = forall b. Literal -> Expr b
Lit (Platform -> Literal
zeroi Platform
platform)
  forall (m :: * -> *) a. Monad m => a -> m a
return ([Type] -> [CoreExpr] -> CoreExpr
mkCoreUbxTup [CoreExpr -> Type
exprType CoreExpr
e1, Type
intPrimTy] [CoreExpr
e1, CoreExpr
no_c])

identityPlatform :: (Platform -> Literal) -> RuleM CoreExpr
identityPlatform :: (Platform -> Literal) -> RuleM CoreExpr
identityPlatform Platform -> Literal
lit =
  (Platform -> Literal) -> RuleM CoreExpr
leftIdentityPlatform Platform -> Literal
lit forall (m :: * -> *) a. MonadPlus m => m a -> m a -> m a
`mplus` (Platform -> Literal) -> RuleM CoreExpr
rightIdentityPlatform Platform -> Literal
lit

-- | Identity rule for PrimOps like 'IntAddC' and 'WordAddC', where, in addition
-- to the result, we have to indicate that no carry/overflow occurred.
identityCPlatform :: (Platform -> Literal) -> RuleM CoreExpr
identityCPlatform :: (Platform -> Literal) -> RuleM CoreExpr
identityCPlatform Platform -> Literal
lit =
  (Platform -> Literal) -> RuleM CoreExpr
leftIdentityCPlatform Platform -> Literal
lit forall (m :: * -> *) a. MonadPlus m => m a -> m a -> m a
`mplus` (Platform -> Literal) -> RuleM CoreExpr
rightIdentityCPlatform Platform -> Literal
lit

leftZero :: RuleM CoreExpr
leftZero :: RuleM CoreExpr
leftZero = do
  [Lit Literal
l1, CoreExpr
_] <- RuleM [CoreExpr]
getArgs
  forall (f :: * -> *). Alternative f => Bool -> f ()
guard forall a b. (a -> b) -> a -> b
$ Literal -> Bool
isZeroLit Literal
l1
  forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall b. Literal -> Expr b
Lit Literal
l1

rightZero :: RuleM CoreExpr
rightZero :: RuleM CoreExpr
rightZero = do
  [CoreExpr
_, Lit Literal
l2] <- RuleM [CoreExpr]
getArgs
  forall (f :: * -> *). Alternative f => Bool -> f ()
guard forall a b. (a -> b) -> a -> b
$ Literal -> Bool
isZeroLit Literal
l2
  forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall b. Literal -> Expr b
Lit Literal
l2

zeroElem :: RuleM CoreExpr
zeroElem :: RuleM CoreExpr
zeroElem = RuleM CoreExpr
leftZero forall (m :: * -> *) a. MonadPlus m => m a -> m a -> m a
`mplus` RuleM CoreExpr
rightZero

equalArgs :: RuleM ()
equalArgs :: RuleM ()
equalArgs = do
  [CoreExpr
e1, CoreExpr
e2] <- RuleM [CoreExpr]
getArgs
  forall (f :: * -> *). Alternative f => Bool -> f ()
guard forall a b. (a -> b) -> a -> b
$ CoreExpr
e1 forall b. Expr b -> Expr b -> Bool
`cheapEqExpr` CoreExpr
e2

nonZeroLit :: Int -> RuleM ()
nonZeroLit :: ConTagZ -> RuleM ()
nonZeroLit ConTagZ
n = ConTagZ -> RuleM Literal
getLiteral ConTagZ
n forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= forall (f :: * -> *). Alternative f => Bool -> f ()
guard forall b c a. (b -> c) -> (a -> b) -> a -> c
. Bool -> Bool
not forall b c a. (b -> c) -> (a -> b) -> a -> c
. Literal -> Bool
isZeroLit

oneLit :: Int -> RuleM ()
oneLit :: ConTagZ -> RuleM ()
oneLit ConTagZ
n = ConTagZ -> RuleM Literal
getLiteral ConTagZ
n forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= forall (f :: * -> *). Alternative f => Bool -> f ()
guard forall b c a. (b -> c) -> (a -> b) -> a -> c
. Literal -> Bool
isOneLit

-- When excess precision is not requested, cut down the precision of the
-- Rational value to that of Float/Double. We confuse host architecture
-- and target architecture here, but it's convenient (and wrong :-).
convFloating :: RuleOpts -> Literal -> Literal
convFloating :: RuleOpts -> Literal -> Literal
convFloating RuleOpts
env (LitFloat  Rational
f) | Bool -> Bool
not (RuleOpts -> Bool
roExcessRationalPrecision RuleOpts
env) =
   Rational -> Literal
LitFloat  (forall a. Real a => a -> Rational
toRational (forall a. Fractional a => Rational -> a
fromRational Rational
f :: Float ))
convFloating RuleOpts
env (LitDouble Rational
d) | Bool -> Bool
not (RuleOpts -> Bool
roExcessRationalPrecision RuleOpts
env) =
   Rational -> Literal
LitDouble (forall a. Real a => a -> Rational
toRational (forall a. Fractional a => Rational -> a
fromRational Rational
d :: Double))
convFloating RuleOpts
_ Literal
l = Literal
l

guardFloatDiv :: RuleM ()
guardFloatDiv :: RuleM ()
guardFloatDiv = do
  [Lit (LitFloat Rational
f1), Lit (LitFloat Rational
f2)] <- RuleM [CoreExpr]
getArgs
  forall (f :: * -> *). Alternative f => Bool -> f ()
guard forall a b. (a -> b) -> a -> b
$ (Rational
f1 forall a. Eq a => a -> a -> Bool
/=Rational
0 Bool -> Bool -> Bool
|| Rational
f2 forall a. Ord a => a -> a -> Bool
> Rational
0) -- see Note [negative zero]
       Bool -> Bool -> Bool
&& Rational
f2 forall a. Eq a => a -> a -> Bool
/= Rational
0            -- avoid NaN and Infinity/-Infinity

guardDoubleDiv :: RuleM ()
guardDoubleDiv :: RuleM ()
guardDoubleDiv = do
  [Lit (LitDouble Rational
d1), Lit (LitDouble Rational
d2)] <- RuleM [CoreExpr]
getArgs
  forall (f :: * -> *). Alternative f => Bool -> f ()
guard forall a b. (a -> b) -> a -> b
$ (Rational
d1 forall a. Eq a => a -> a -> Bool
/=Rational
0 Bool -> Bool -> Bool
|| Rational
d2 forall a. Ord a => a -> a -> Bool
> Rational
0) -- see Note [negative zero]
       Bool -> Bool -> Bool
&& Rational
d2 forall a. Eq a => a -> a -> Bool
/= Rational
0            -- avoid NaN and Infinity/-Infinity
-- Note [negative zero] Avoid (0 / -d), otherwise 0/(-1) reduces to
-- zero, but we might want to preserve the negative zero here which
-- is representable in Float/Double but not in (normalised)
-- Rational. (#3676) Perhaps we should generate (0 :% (-1)) instead?

strengthReduction :: Literal -> PrimOp -> RuleM CoreExpr
strengthReduction :: Literal -> PrimOp -> RuleM CoreExpr
strengthReduction Literal
two_lit PrimOp
add_op = do -- Note [Strength reduction]
  CoreExpr
arg <- forall (t :: * -> *) (m :: * -> *) a.
(Foldable t, MonadPlus m) =>
t (m a) -> m a
msum [ do [CoreExpr
arg, Lit Literal
mult_lit] <- RuleM [CoreExpr]
getArgs
                   forall (f :: * -> *). Alternative f => Bool -> f ()
guard (Literal
mult_lit forall a. Eq a => a -> a -> Bool
== Literal
two_lit)
                   forall (m :: * -> *) a. Monad m => a -> m a
return CoreExpr
arg
              , do [Lit Literal
mult_lit, CoreExpr
arg] <- RuleM [CoreExpr]
getArgs
                   forall (f :: * -> *). Alternative f => Bool -> f ()
guard (Literal
mult_lit forall a. Eq a => a -> a -> Bool
== Literal
two_lit)
                   forall (m :: * -> *) a. Monad m => a -> m a
return CoreExpr
arg ]
  forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall b. Id -> Expr b
Var (PrimOp -> Id
mkPrimOpId PrimOp
add_op) forall b. Expr b -> Expr b -> Expr b
`App` CoreExpr
arg forall b. Expr b -> Expr b -> Expr b
`App` CoreExpr
arg

-- Note [Strength reduction]
-- ~~~~~~~~~~~~~~~~~~~~~~~~~
--
-- This rule turns floating point multiplications of the form 2.0 * x and
-- x * 2.0 into x + x addition, because addition costs less than multiplication.
-- See #7116

-- Note [What's true and false]
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
--
-- trueValInt and falseValInt represent true and false values returned by
-- comparison primops for Char, Int, Word, Integer, Double, Float and Addr.
-- True is represented as an unboxed 1# literal, while false is represented
-- as 0# literal.
-- We still need Bool data constructors (True and False) to use in a rule
-- for constant folding of equal Strings

trueValInt, falseValInt :: Platform -> Expr CoreBndr
trueValInt :: Platform -> CoreExpr
trueValInt  Platform
platform = forall b. Literal -> Expr b
Lit forall a b. (a -> b) -> a -> b
$ Platform -> Literal
onei  Platform
platform -- see Note [What's true and false]
falseValInt :: Platform -> CoreExpr
falseValInt Platform
platform = forall b. Literal -> Expr b
Lit forall a b. (a -> b) -> a -> b
$ Platform -> Literal
zeroi Platform
platform

trueValBool, falseValBool :: Expr CoreBndr
trueValBool :: CoreExpr
trueValBool   = forall b. Id -> Expr b
Var Id
trueDataConId -- see Note [What's true and false]
falseValBool :: CoreExpr
falseValBool  = forall b. Id -> Expr b
Var Id
falseDataConId

ltVal, eqVal, gtVal :: Expr CoreBndr
ltVal :: CoreExpr
ltVal = forall b. Id -> Expr b
Var Id
ordLTDataConId
eqVal :: CoreExpr
eqVal = forall b. Id -> Expr b
Var Id
ordEQDataConId
gtVal :: CoreExpr
gtVal = forall b. Id -> Expr b
Var Id
ordGTDataConId

mkIntVal :: Platform -> Integer -> Expr CoreBndr
mkIntVal :: Platform -> Integer -> CoreExpr
mkIntVal Platform
platform Integer
i = forall b. Literal -> Expr b
Lit (Platform -> Integer -> Literal
mkLitInt Platform
platform Integer
i)
mkFloatVal :: RuleOpts -> Rational -> Expr CoreBndr
mkFloatVal :: RuleOpts -> Rational -> CoreExpr
mkFloatVal RuleOpts
env Rational
f = forall b. Literal -> Expr b
Lit (RuleOpts -> Literal -> Literal
convFloating RuleOpts
env (Rational -> Literal
LitFloat  Rational
f))
mkDoubleVal :: RuleOpts -> Rational -> Expr CoreBndr
mkDoubleVal :: RuleOpts -> Rational -> CoreExpr
mkDoubleVal RuleOpts
env Rational
d = forall b. Literal -> Expr b
Lit (RuleOpts -> Literal -> Literal
convFloating RuleOpts
env (Rational -> Literal
LitDouble Rational
d))

matchPrimOpId :: PrimOp -> Id -> RuleM ()
matchPrimOpId :: PrimOp -> Id -> RuleM ()
matchPrimOpId PrimOp
op Id
id = do
  PrimOp
op' <- forall a. Maybe a -> RuleM a
liftMaybe forall a b. (a -> b) -> a -> b
$ Id -> Maybe PrimOp
isPrimOpId_maybe Id
id
  forall (f :: * -> *). Alternative f => Bool -> f ()
guard forall a b. (a -> b) -> a -> b
$ PrimOp
op forall a. Eq a => a -> a -> Bool
== PrimOp
op'

{-
************************************************************************
*                                                                      *
\subsection{Special rules for seq, tagToEnum, dataToTag}
*                                                                      *
************************************************************************

Note [tagToEnum#]
~~~~~~~~~~~~~~~~~
Nasty check to ensure that tagToEnum# is applied to a type that is an
enumeration TyCon.  Unification may refine the type later, but this
check won't see that, alas.  It's crude but it works.

Here's are two cases that should fail
        f :: forall a. a
        f = tagToEnum# 0        -- Can't do tagToEnum# at a type variable

        g :: Int
        g = tagToEnum# 0        -- Int is not an enumeration

We used to make this check in the type inference engine, but it's quite
ugly to do so, because the delayed constraint solving means that we don't
really know what's going on until the end. It's very much a corner case
because we don't expect the user to call tagToEnum# at all; we merely
generate calls in derived instances of Enum.  So we compromise: a
rewrite rule rewrites a bad instance of tagToEnum# to an error call,
and emits a warning.
-}

tagToEnumRule :: RuleM CoreExpr
-- If     data T a = A | B | C
-- then   tagToEnum# (T ty) 2# -->  B ty
tagToEnumRule :: RuleM CoreExpr
tagToEnumRule = do
  [Type Type
ty, Lit (LitNumber LitNumType
LitNumInt Integer
i)] <- RuleM [CoreExpr]
getArgs
  case HasDebugCallStack => Type -> Maybe (TyCon, [Type])
splitTyConApp_maybe Type
ty of
    Just (TyCon
tycon, [Type]
tc_args) | TyCon -> Bool
isEnumerationTyCon TyCon
tycon -> do
      let tag :: ConTagZ
tag = forall a. Num a => Integer -> a
fromInteger Integer
i
          correct_tag :: DataCon -> Bool
correct_tag DataCon
dc = (DataCon -> ConTagZ
dataConTagZ DataCon
dc) forall a. Eq a => a -> a -> Bool
== ConTagZ
tag
      (DataCon
dc:[DataCon]
rest) <- forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall a. (a -> Bool) -> [a] -> [a]
filter DataCon -> Bool
correct_tag (TyCon -> Maybe [DataCon]
tyConDataCons_maybe TyCon
tycon forall a. Maybe a -> a -> a
`orElse` [])
      ASSERT(null rest) return ()
      forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall b. Expr b -> [Type] -> Expr b
mkTyApps (forall b. Id -> Expr b
Var (DataCon -> Id
dataConWorkId DataCon
dc)) [Type]
tc_args

    -- See Note [tagToEnum#]
    Maybe (TyCon, [Type])
_ -> WARN( True, text "tagToEnum# on non-enumeration type" <+> ppr ty )
         forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ Id -> Type -> String -> CoreExpr
mkRuntimeErrorApp Id
rUNTIME_ERROR_ID Type
ty String
"tagToEnum# on non-enumeration type"

------------------------------
dataToTagRule :: RuleM CoreExpr
-- See Note [dataToTag#] in primops.txt.pp
dataToTagRule :: RuleM CoreExpr
dataToTagRule = RuleM CoreExpr
a forall (m :: * -> *) a. MonadPlus m => m a -> m a -> m a
`mplus` RuleM CoreExpr
b
  where
    -- dataToTag (tagToEnum x)   ==>   x
    a :: RuleM CoreExpr
a = do
      [Type Type
ty1, Var Id
tag_to_enum `App` Type Type
ty2 `App` CoreExpr
tag] <- RuleM [CoreExpr]
getArgs
      forall (f :: * -> *). Alternative f => Bool -> f ()
guard forall a b. (a -> b) -> a -> b
$ Id
tag_to_enum forall a. Uniquable a => a -> Unique -> Bool
`hasKey` Unique
tagToEnumKey
      forall (f :: * -> *). Alternative f => Bool -> f ()
guard forall a b. (a -> b) -> a -> b
$ Type
ty1 Type -> Type -> Bool
`eqType` Type
ty2
      forall (m :: * -> *) a. Monad m => a -> m a
return CoreExpr
tag

    -- dataToTag (K e1 e2)  ==>   tag-of K
    -- This also works (via exprIsConApp_maybe) for
    --   dataToTag x
    -- where x's unfolding is a constructor application
    b :: RuleM CoreExpr
b = do
      Platform
dflags <- RuleM Platform
getPlatform
      [CoreExpr
_, CoreExpr
val_arg] <- RuleM [CoreExpr]
getArgs
      InScopeEnv
in_scope <- RuleM InScopeEnv
getInScopeEnv
      (InScopeSet
_,[FloatBind]
floats, DataCon
dc,[Type]
_,[CoreExpr]
_) <- forall a. Maybe a -> RuleM a
liftMaybe forall a b. (a -> b) -> a -> b
$ HasDebugCallStack =>
InScopeEnv
-> CoreExpr
-> Maybe (InScopeSet, [FloatBind], DataCon, [Type], [CoreExpr])
exprIsConApp_maybe InScopeEnv
in_scope CoreExpr
val_arg
      ASSERT( not (isNewTyCon (dataConTyCon dc)) ) return ()
      forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ [FloatBind] -> CoreExpr -> CoreExpr
wrapFloats [FloatBind]
floats (Platform -> Integer -> CoreExpr
mkIntVal Platform
dflags (forall a. Integral a => a -> Integer
toInteger (DataCon -> ConTagZ
dataConTagZ DataCon
dc)))

{- Note [dataToTag# magic]
~~~~~~~~~~~~~~~~~~~~~~~~~~
The primop dataToTag# is unusual because it evaluates its argument.
Only `SeqOp` shares that property.  (Other primops do not do anything
as fancy as argument evaluation.)  The special handling for dataToTag#
is:

* GHC.Core.Utils.exprOkForSpeculation has a special case for DataToTagOp,
  (actually in app_ok).  Most primops with lifted arguments do not
  evaluate those arguments, but DataToTagOp and SeqOp are two
  exceptions.  We say that they are /never/ ok-for-speculation,
  regardless of the evaluated-ness of their argument.
  See GHC.Core.Utils Note [exprOkForSpeculation and SeqOp/DataToTagOp]

* There is a special case for DataToTagOp in GHC.StgToCmm.Expr.cgExpr,
  that evaluates its argument and then extracts the tag from
  the returned value.

* An application like (dataToTag# (Just x)) is optimised by
  dataToTagRule in GHC.Core.Opt.ConstantFold.

* A case expression like
     case (dataToTag# e) of <alts>
  gets transformed t
     case e of <transformed alts>
  by GHC.Core.Opt.ConstantFold.caseRules; see Note [caseRules for dataToTag]

See #15696 for a long saga.
-}

{- *********************************************************************
*                                                                      *
             unsafeEqualityProof
*                                                                      *
********************************************************************* -}

-- unsafeEqualityProof k t t  ==>  UnsafeRefl (Refl t)
-- That is, if the two types are equal, it's not unsafe!

unsafeEqualityProofRule :: RuleM CoreExpr
unsafeEqualityProofRule :: RuleM CoreExpr
unsafeEqualityProofRule
  = do { [Type Type
rep, Type Type
t1, Type Type
t2] <- RuleM [CoreExpr]
getArgs
       ; forall (f :: * -> *). Alternative f => Bool -> f ()
guard (Type
t1 Type -> Type -> Bool
`eqType` Type
t2)
       ; Id
fn <- RuleM Id
getFunction
       ; let ([Id]
_, Type
ue) = Type -> ([Id], Type)
splitForAllTyCoVars (Id -> Type
idType Id
fn)
             tc :: TyCon
tc      = Type -> TyCon
tyConAppTyCon Type
ue  -- tycon:    UnsafeEquality
             (DataCon
dc:[DataCon]
_)  = TyCon -> [DataCon]
tyConDataCons TyCon
tc  -- data con: UnsafeRefl
             -- UnsafeRefl :: forall (r :: RuntimeRep) (a :: TYPE r).
             --               UnsafeEquality r a a
       ; forall (m :: * -> *) a. Monad m => a -> m a
return (forall b. Expr b -> [Type] -> Expr b
mkTyApps (forall b. Id -> Expr b
Var (DataCon -> Id
dataConWrapId DataCon
dc)) [Type
rep, Type
t1]) }


{- *********************************************************************
*                                                                      *
             Rules for seq# and spark#
*                                                                      *
********************************************************************* -}

{- Note [seq# magic]
~~~~~~~~~~~~~~~~~~~~
The primop
   seq# :: forall a s . a -> State# s -> (# State# s, a #)

is /not/ the same as the Prelude function seq :: a -> b -> b
as you can see from its type.  In fact, seq# is the implementation
mechanism for 'evaluate'

   evaluate :: a -> IO a
   evaluate a = IO $ \s -> seq# a s

The semantics of seq# is
  * evaluate its first argument
  * and return it

Things to note

* Why do we need a primop at all?  That is, instead of
      case seq# x s of (# x, s #) -> blah
  why not instead say this?
      case x of { DEFAULT -> blah)

  Reason (see #5129): if we saw
    catch# (\s -> case x of { DEFAULT -> raiseIO# exn s }) handler

  then we'd drop the 'case x' because the body of the case is bottom
  anyway. But we don't want to do that; the whole /point/ of
  seq#/evaluate is to evaluate 'x' first in the IO monad.

  In short, we /always/ evaluate the first argument and never
  just discard it.

* Why return the value?  So that we can control sharing of seq'd
  values: in
     let x = e in x `seq` ... x ...
  We don't want to inline x, so better to represent it as
       let x = e in case seq# x RW of (# _, x' #) -> ... x' ...
  also it matches the type of rseq in the Eval monad.

Implementing seq#.  The compiler has magic for SeqOp in

- GHC.Core.Opt.ConstantFold.seqRule: eliminate (seq# <whnf> s)

- GHC.StgToCmm.Expr.cgExpr, and cgCase: special case for seq#

- GHC.Core.Utils.exprOkForSpeculation;
  see Note [exprOkForSpeculation and SeqOp/DataToTagOp] in GHC.Core.Utils

- Simplify.addEvals records evaluated-ness for the result; see
  Note [Adding evaluatedness info to pattern-bound variables]
  in GHC.Core.Opt.Simplify
-}

seqRule :: RuleM CoreExpr
seqRule :: RuleM CoreExpr
seqRule = do
  [Type Type
ty_a, Type Type
_ty_s, CoreExpr
a, CoreExpr
s] <- RuleM [CoreExpr]
getArgs
  forall (f :: * -> *). Alternative f => Bool -> f ()
guard forall a b. (a -> b) -> a -> b
$ CoreExpr -> Bool
exprIsHNF CoreExpr
a
  forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ [Type] -> [CoreExpr] -> CoreExpr
mkCoreUbxTup [CoreExpr -> Type
exprType CoreExpr
s, Type
ty_a] [CoreExpr
s, CoreExpr
a]

-- spark# :: forall a s . a -> State# s -> (# State# s, a #)
sparkRule :: RuleM CoreExpr
sparkRule :: RuleM CoreExpr
sparkRule = RuleM CoreExpr
seqRule -- reduce on HNF, just the same
  -- XXX perhaps we shouldn't do this, because a spark eliminated by
  -- this rule won't be counted as a dud at runtime?

{-
************************************************************************
*                                                                      *
\subsection{Built in rules}
*                                                                      *
************************************************************************

Note [Scoping for Builtin rules]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
When compiling a (base-package) module that defines one of the
functions mentioned in the RHS of a built-in rule, there's a danger
that we'll see

        f = ...(eq String x)....

        ....and lower down...

        eqString = ...

Then a rewrite would give

        f = ...(eqString x)...
        ....and lower down...
        eqString = ...

and lo, eqString is not in scope.  This only really matters when we
get to code generation.  But the occurrence analyser does a GlomBinds
step when necessary, that does a new SCC analysis on the whole set of
bindings (see occurAnalysePgm), which sorts out the dependency, so all
is fine.
-}

builtinRules :: [CoreRule]
-- Rules for non-primops that can't be expressed using a RULE pragma
builtinRules :: [CoreRule]
builtinRules
  = [BuiltinRule { ru_name :: RuleName
ru_name = String -> RuleName
fsLit String
"AppendLitString",
                   ru_fn :: Name
ru_fn = Name
unpackCStringFoldrName,
                   ru_nargs :: ConTagZ
ru_nargs = ConTagZ
4, ru_try :: RuleFun
ru_try = RuleFun
match_append_lit_C },
     BuiltinRule { ru_name :: RuleName
ru_name = String -> RuleName
fsLit String
"AppendLitStringUtf8",
                   ru_fn :: Name
ru_fn = Name
unpackCStringFoldrUtf8Name,
                   ru_nargs :: ConTagZ
ru_nargs = ConTagZ
4, ru_try :: RuleFun
ru_try = RuleFun
match_append_lit_utf8 },
     BuiltinRule { ru_name :: RuleName
ru_name = String -> RuleName
fsLit String
"EqString", ru_fn :: Name
ru_fn = Name
eqStringName,
                   ru_nargs :: ConTagZ
ru_nargs = ConTagZ
2, ru_try :: RuleFun
ru_try = RuleFun
match_eq_string },
     BuiltinRule { ru_name :: RuleName
ru_name = String -> RuleName
fsLit String
"CStringLength", ru_fn :: Name
ru_fn = Name
cstringLengthName,
                   ru_nargs :: ConTagZ
ru_nargs = ConTagZ
1, ru_try :: RuleFun
ru_try = RuleFun
match_cstring_length },
     BuiltinRule { ru_name :: RuleName
ru_name = String -> RuleName
fsLit String
"Inline", ru_fn :: Name
ru_fn = Name
inlineIdName,
                   ru_nargs :: ConTagZ
ru_nargs = ConTagZ
2, ru_try :: RuleFun
ru_try = \RuleOpts
_ InScopeEnv
_ Id
_ -> [CoreExpr] -> Maybe CoreExpr
match_inline },
     BuiltinRule { ru_name :: RuleName
ru_name = String -> RuleName
fsLit String
"MagicDict", ru_fn :: Name
ru_fn = Id -> Name
idName Id
magicDictId,
                   ru_nargs :: ConTagZ
ru_nargs = ConTagZ
4, ru_try :: RuleFun
ru_try = \RuleOpts
_ InScopeEnv
_ Id
_ -> [CoreExpr] -> Maybe CoreExpr
match_magicDict },

     Name -> ConTagZ -> RuleM CoreExpr -> CoreRule
mkBasicRule Name
unsafeEqualityProofName ConTagZ
3 RuleM CoreExpr
unsafeEqualityProofRule,

     Name -> ConTagZ -> RuleM CoreExpr -> CoreRule
mkBasicRule Name
divIntName ConTagZ
2 forall a b. (a -> b) -> a -> b
$ forall (t :: * -> *) (m :: * -> *) a.
(Foldable t, MonadPlus m) =>
t (m a) -> m a
msum
        [ ConTagZ -> RuleM ()
nonZeroLit ConTagZ
1 forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> (RuleOpts -> Literal -> Literal -> Maybe CoreExpr)
-> RuleM CoreExpr
binaryLit (forall a b.
(Integral a, Integral b) =>
(a -> b -> Integer)
-> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
intOp2 forall a. Integral a => a -> a -> a
div)
        , RuleM CoreExpr
leftZero
        , do
          [CoreExpr
arg, Lit (LitNumber LitNumType
LitNumInt Integer
d)] <- RuleM [CoreExpr]
getArgs
          Just Integer
n <- forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ Integer -> Maybe Integer
exactLog2 Integer
d
          Platform
platform <- RuleM Platform
getPlatform
          forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall b. Id -> Expr b
Var (PrimOp -> Id
mkPrimOpId PrimOp
IntSraOp) forall b. Expr b -> Expr b -> Expr b
`App` CoreExpr
arg forall b. Expr b -> Expr b -> Expr b
`App` Platform -> Integer -> CoreExpr
mkIntVal Platform
platform Integer
n
        ],

     Name -> ConTagZ -> RuleM CoreExpr -> CoreRule
mkBasicRule Name
modIntName ConTagZ
2 forall a b. (a -> b) -> a -> b
$ forall (t :: * -> *) (m :: * -> *) a.
(Foldable t, MonadPlus m) =>
t (m a) -> m a
msum
        [ ConTagZ -> RuleM ()
nonZeroLit ConTagZ
1 forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> (RuleOpts -> Literal -> Literal -> Maybe CoreExpr)
-> RuleM CoreExpr
binaryLit (forall a b.
(Integral a, Integral b) =>
(a -> b -> Integer)
-> RuleOpts -> Literal -> Literal -> Maybe CoreExpr
intOp2 forall a. Integral a => a -> a -> a
mod)
        , RuleM CoreExpr
leftZero
        , do
          [CoreExpr
arg, Lit (LitNumber LitNumType
LitNumInt Integer
d)] <- RuleM [CoreExpr]
getArgs
          Just Integer
_ <- forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ Integer -> Maybe Integer
exactLog2 Integer
d
          Platform
platform <- RuleM Platform
getPlatform
          forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall b. Id -> Expr b
Var (PrimOp -> Id
mkPrimOpId PrimOp
IntAndOp)
            forall b. Expr b -> Expr b -> Expr b
`App` CoreExpr
arg forall b. Expr b -> Expr b -> Expr b
`App` Platform -> Integer -> CoreExpr
mkIntVal Platform
platform (Integer
d forall a. Num a => a -> a -> a
- Integer
1)
        ]
     ]
 forall a. [a] -> [a] -> [a]
++ [CoreRule]
builtinBignumRules
{-# NOINLINE builtinRules #-}
-- there is no benefit to inlining these yet, despite this, GHC produces
-- unfoldings for this regardless since the floated list entries look small.

builtinBignumRules :: [CoreRule]
builtinBignumRules :: [CoreRule]
builtinBignumRules =
  [ -- conversions
    String -> Name -> CoreRule
lit_to_integer String
"Word# -> Integer"   Name
integerFromWordName
  , String -> Name -> CoreRule
lit_to_integer String
"Int64# -> Integer"  Name
integerFromInt64Name
  , String -> Name -> CoreRule
lit_to_integer String
"Word64# -> Integer" Name
integerFromWord64Name
  , String -> Name -> CoreRule
lit_to_integer String
"Natural -> Integer" Name
integerFromNaturalName

  , String -> Name -> (Platform -> Integer -> CoreExpr) -> CoreRule
integer_to_lit String
"Integer -> Word# (wrap)"   Name
integerToWordName   forall b. Platform -> Integer -> Expr b
mkWordLitWrap
  , String -> Name -> (Platform -> Integer -> CoreExpr) -> CoreRule
integer_to_lit String
"Integer -> Int# (wrap)"    Name
integerToIntName    forall b. Platform -> Integer -> Expr b
mkIntLitWrap
  , String -> Name -> (Platform -> Integer -> CoreExpr) -> CoreRule
integer_to_lit String
"Integer -> Word64# (wrap)" Name
integerToWord64Name (\Platform
_ -> forall b. Word64 -> Expr b
mkWord64LitWord64 forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Num a => Integer -> a
fromInteger)
  , String -> Name -> (Platform -> Integer -> CoreExpr) -> CoreRule
integer_to_lit String
"Integer -> Int64# (wrap)"  Name
integerToInt64Name  (\Platform
_ -> forall b. Int64 -> Expr b
mkInt64LitInt64 forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Num a => Integer -> a
fromInteger)
  , String -> Name -> (Platform -> Integer -> CoreExpr) -> CoreRule
integer_to_lit String
"Integer -> Float#"         Name
integerToFloatName  (\Platform
_ -> forall b. Float -> Expr b
mkFloatLitFloat forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Num a => Integer -> a
fromInteger)
  , String -> Name -> (Platform -> Integer -> CoreExpr) -> CoreRule
integer_to_lit String
"Integer -> Double#"        Name
integerToDoubleName (\Platform
_ -> forall b. Double -> Expr b
mkDoubleLitDouble forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Num a => Integer -> a
fromInteger)

  , String -> Name -> Bool -> Bool -> CoreRule
integer_to_natural String
"Integer -> Natural (clamp)" Name
integerToNaturalClampName Bool
False Bool
True
  , String -> Name -> Bool -> Bool -> CoreRule
integer_to_natural String
"Integer -> Natural (wrap)"  Name
integerToNaturalName      Bool
False Bool
False
  , String -> Name -> Bool -> Bool -> CoreRule
integer_to_natural String
"Integer -> Natural (throw)" Name
integerToNaturalThrowName Bool
True Bool
False

  , String -> Name -> CoreRule
lit_to_natural  String
"Word# -> Natural"         Name
naturalNSName
  , String -> Name -> Bool -> CoreRule
natural_to_word String
"Natural -> Word# (wrap)"  Name
naturalToWordName      Bool
False
  , String -> Name -> Bool -> CoreRule
natural_to_word String
"Natural -> Word# (clamp)" Name
naturalToWordClampName Bool
True

    -- comparisons (return an unlifted Int#)
  , String -> Name -> (Integer -> Integer -> Bool) -> CoreRule
integer_cmp String
"integerEq#" Name
integerEqName forall a. Eq a => a -> a -> Bool
(==)
  , String -> Name -> (Integer -> Integer -> Bool) -> CoreRule
integer_cmp String
"integerNe#" Name
integerNeName forall a. Eq a => a -> a -> Bool
(/=)
  , String -> Name -> (Integer -> Integer -> Bool) -> CoreRule
integer_cmp String
"integerLe#" Name
integerLeName forall a. Ord a => a -> a -> Bool
(<=)
  , String -> Name -> (Integer -> Integer -> Bool) -> CoreRule
integer_cmp String
"integerGt#" Name
integerGtName forall a. Ord a => a -> a -> Bool
(>)
  , String -> Name -> (Integer -> Integer -> Bool) -> CoreRule
integer_cmp String
"integerLt#" Name
integerLtName forall a. Ord a => a -> a -> Bool
(<)
  , String -> Name -> (Integer -> Integer -> Bool) -> CoreRule
integer_cmp String
"integerGe#" Name
integerGeName forall a. Ord a => a -> a -> Bool
(>=)

  , String -> Name -> (Integer -> Integer -> Bool) -> CoreRule
natural_cmp String
"naturalEq#" Name
naturalEqName forall a. Eq a => a -> a -> Bool
(==)
  , String -> Name -> (Integer -> Integer -> Bool) -> CoreRule
natural_cmp String
"naturalNe#" Name
naturalNeName forall a. Eq a => a -> a -> Bool
(/=)
  , String -> Name -> (Integer -> Integer -> Bool) -> CoreRule
natural_cmp String
"naturalLe#" Name
naturalLeName forall a. Ord a => a -> a -> Bool
(<=)
  , String -> Name -> (Integer -> Integer -> Bool) -> CoreRule
natural_cmp String
"naturalGt#" Name
naturalGtName forall a. Ord a => a -> a -> Bool
(>)
  , String -> Name -> (Integer -> Integer -> Bool) -> CoreRule
natural_cmp String
"naturalLt#" Name
naturalLtName forall a. Ord a => a -> a -> Bool
(<)
  , String -> Name -> (Integer -> Integer -> Bool) -> CoreRule
natural_cmp String
"naturalGe#" Name
naturalGeName forall a. Ord a => a -> a -> Bool
(>=)

    -- comparisons (return an Ordering)
  , String -> Name -> CoreRule
bignum_compare String
"integerCompare" Name
integerCompareName
  , String -> Name -> CoreRule
bignum_compare String
"naturalCompare" Name
naturalCompareName

    -- binary operations
  , String -> Name -> (Integer -> Integer -> Integer) -> CoreRule
integer_binop String
"integerAdd" Name
integerAddName forall a. Num a => a -> a -> a
(+)
  , String -> Name -> (Integer -> Integer -> Integer) -> CoreRule
integer_binop String
"integerSub" Name
integerSubName (-)
  , String -> Name -> (Integer -> Integer -> Integer) -> CoreRule
integer_binop String
"integerMul" Name
integerMulName forall a. Num a => a -> a -> a
(*)
  , String -> Name -> (Integer -> Integer -> Integer) -> CoreRule
integer_binop String
"integerGcd" Name
integerGcdName forall a. Integral a => a -> a -> a
gcd
  , String -> Name -> (Integer -> Integer -> Integer) -> CoreRule
integer_binop String
"integerLcm" Name
integerLcmName forall a. Integral a => a -> a -> a
lcm
  , String -> Name -> (Integer -> Integer -> Integer) -> CoreRule
integer_binop String
"integerAnd" Name
integerAndName forall a. Bits a => a -> a -> a
(.&.)
  , String -> Name -> (Integer -> Integer -> Integer) -> CoreRule
integer_binop String
"integerOr"  Name
integerOrName  forall a. Bits a => a -> a -> a
(.|.)
  , String -> Name -> (Integer -> Integer -> Integer) -> CoreRule
integer_binop String
"integerXor" Name
integerXorName forall a. Bits a => a -> a -> a
xor

  , String -> Name -> (Integer -> Integer -> Integer) -> CoreRule
natural_binop String
"naturalAdd" Name
naturalAddName forall a. Num a => a -> a -> a
(+)
  , String -> Name -> (Integer -> Integer -> Integer) -> CoreRule
natural_binop String
"naturalMul" Name
naturalMulName forall a. Num a => a -> a -> a
(*)
  , String -> Name -> (Integer -> Integer -> Integer) -> CoreRule
natural_binop String
"naturalGcd" Name
naturalGcdName forall a. Integral a => a -> a -> a
gcd
  , String -> Name -> (Integer -> Integer -> Integer) -> CoreRule
natural_binop String
"naturalLcm" Name
naturalLcmName forall a. Integral a => a -> a -> a
lcm
  , String -> Name -> (Integer -> Integer -> Integer) -> CoreRule
natural_binop String
"naturalAnd" Name
naturalAndName forall a. Bits a => a -> a -> a
(.&.)
  , String -> Name -> (Integer -> Integer -> Integer) -> CoreRule
natural_binop String
"naturalOr"  Name
naturalOrName  forall a. Bits a => a -> a -> a
(.|.)
  , String -> Name -> (Integer -> Integer -> Integer) -> CoreRule
natural_binop String
"naturalXor" Name
naturalXorName forall a. Bits a => a -> a -> a
xor

    -- Natural subtraction: it's a binop but it can fail because of underflow so
    -- we have several primitives to handle here.
  , String -> Name -> CoreRule
natural_sub String
"naturalSubUnsafe" Name
naturalSubUnsafeName
  , String -> Name -> CoreRule
natural_sub String
"naturalSubThrow"  Name
naturalSubThrowName
  , String -> Name -> ConTagZ -> RuleM CoreExpr -> CoreRule
mkRule String
"naturalSub" Name
naturalSubName ConTagZ
2 forall a b. (a -> b) -> a -> b
$ do
        [CoreExpr
a0,CoreExpr
a1] <- RuleM [CoreExpr]
getArgs
        Integer
x <- CoreExpr -> RuleM Integer
isNaturalLiteral CoreExpr
a0
        Integer
y <- CoreExpr -> RuleM Integer
isNaturalLiteral CoreExpr
a1
        -- return an unboxed sum: (# (# #) | Natural #)
        let ret :: ConTagZ -> CoreExpr -> f CoreExpr
ret ConTagZ
n CoreExpr
v = forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ ConTagZ -> ConTagZ -> [Type] -> CoreExpr -> CoreExpr
mkCoreUbxSum ConTagZ
2 ConTagZ
n [Type
unboxedUnitTy,Type
naturalTy] CoreExpr
v
        if Integer
x forall a. Ord a => a -> a -> Bool
< Integer
y
            then forall {f :: * -> *}.
Applicative f =>
ConTagZ -> CoreExpr -> f CoreExpr
ret ConTagZ
1 forall a b. (a -> b) -> a -> b
$ forall b. Id -> Expr b
Var Id
voidPrimId
            else forall {f :: * -> *}.
Applicative f =>
ConTagZ -> CoreExpr -> f CoreExpr
ret ConTagZ
2 forall a b. (a -> b) -> a -> b
$ forall b. Literal -> Expr b
Lit (Integer -> Literal
mkLitNatural (Integer
x forall a. Num a => a -> a -> a
- Integer
y))

    -- unary operations
  , forall {t}.
String -> Name -> (t -> Literal) -> (Integer -> t) -> CoreRule
bignum_unop String
"integerNegate"     Name
integerNegateName     Integer -> Literal
mkLitInteger forall a. Num a => a -> a
negate
  , forall {t}.
String -> Name -> (t -> Literal) -> (Integer -> t) -> CoreRule
bignum_unop String
"integerAbs"        Name
integerAbsName        Integer -> Literal
mkLitInteger forall a. Num a => a -> a
abs
  , forall {t}.
String -> Name -> (t -> Literal) -> (Integer -> t) -> CoreRule
bignum_unop String
"integerSignum"     Name
integerSignumName     Integer -> Literal
mkLitInteger forall a. Num a => a -> a
signum
  , forall {t}.
String -> Name -> (t -> Literal) -> (Integer -> t) -> CoreRule
bignum_unop String
"integerComplement" Name
integerComplementName Integer -> Literal
mkLitInteger forall a. Bits a => a -> a
complement

  , forall {t}.
String -> Name -> (t -> Literal) -> (Integer -> t) -> CoreRule
bignum_unop String
"naturalSignum"     Name
naturalSignumName     Integer -> Literal
mkLitNatural forall a. Num a => a -> a
signum

  , String -> Name -> ConTagZ -> RuleM CoreExpr -> CoreRule
mkRule String
"naturalNegate" Name
naturalNegateName ConTagZ
1 forall a b. (a -> b) -> a -> b
$ do
        [CoreExpr
a0] <- RuleM [CoreExpr]
getArgs
        Integer
x <- CoreExpr -> RuleM Integer
isNaturalLiteral CoreExpr
a0
        forall (f :: * -> *). Alternative f => Bool -> f ()
guard (Integer
x forall a. Eq a => a -> a -> Bool
== Integer
0) -- negate is only valid for (0 :: Natural)
        forall (f :: * -> *) a. Applicative f => a -> f a
pure CoreExpr
a0

  , forall {t}.
Num t =>
String -> Name -> (Platform -> t -> Literal) -> CoreRule
bignum_popcount String
"integerPopCount" Name
integerPopCountName Platform -> Integer -> Literal
mkLitIntWrap
  , forall {t}.
Num t =>
String -> Name -> (Platform -> t -> Literal) -> CoreRule
bignum_popcount String
"naturalPopCount" Name
naturalPopCountName Platform -> Integer -> Literal
mkLitWordWrap

  ------------------------------------------------------------
  -- The following `small_passthough_*` rules are used to optimise conversions
  -- between numeric types by avoiding passing through "small" constructors of
  -- Integer and Natural.
  --
  -- See Note [Optimising conversions between numeric types]
  --

  , String -> Name -> Name -> CoreRule
small_passthrough_id String
"Word# -> Natural -> Word#"
      Name
naturalNSName Name
naturalToWordName
  , String -> Name -> Name -> CoreRule
small_passthrough_id String
"Word# -> Natural -> Word# (clamp)"
      Name
naturalNSName Name
naturalToWordClampName

  , String -> Name -> Name -> CoreRule
small_passthrough_id String
"Int# -> Integer -> Int#"
      Name
integerISName Name
integerToIntName
  , String -> Name -> Name -> CoreRule
small_passthrough_id String
"Word# -> Integer -> Word#"
      Name
integerFromWordName Name
integerToWordName
  , String -> Name -> Name -> CoreRule
small_passthrough_id String
"Int64# -> Integer -> Int64#"
      Name
integerFromInt64Name Name
integerToInt64Name
  , String -> Name -> Name -> CoreRule
small_passthrough_id String
"Word64# -> Integer -> Word64#"
      Name
integerFromWord64Name Name
integerToWord64Name
  , String -> Name -> Name -> CoreRule
small_passthrough_id String
"Natural -> Integer -> Natural (wrap)"
      Name
integerFromNaturalName Name
integerToNaturalName
  , String -> Name -> Name -> CoreRule
small_passthrough_id String
"Natural -> Integer -> Natural (throw)"
      Name
integerFromNaturalName Name
integerToNaturalThrowName
  , String -> Name -> Name -> CoreRule
small_passthrough_id String
"Natural -> Integer -> Natural (clamp)"
      Name
integerFromNaturalName Name
integerToNaturalClampName

  , String -> Name -> Name -> Id -> CoreRule
small_passthrough_app String
"Int# -> Integer -> Word#"
        Name
integerISName Name
integerToWordName   (PrimOp -> Id
mkPrimOpId PrimOp
IntToWordOp)
  , String -> Name -> Name -> Id -> CoreRule
small_passthrough_app String
"Int# -> Integer -> Float#"
        Name
integerISName Name
integerToFloatName  (PrimOp -> Id
mkPrimOpId PrimOp
IntToFloatOp)
  , String -> Name -> Name -> Id -> CoreRule
small_passthrough_app String
"Int# -> Integer -> Double#"
        Name
integerISName Name
integerToDoubleName (PrimOp -> Id
mkPrimOpId PrimOp
IntToDoubleOp)

  , String -> Name -> Name -> Id -> CoreRule
small_passthrough_app String
"Word# -> Integer -> Int#"
        Name
integerFromWordName Name
integerToIntName (PrimOp -> Id
mkPrimOpId PrimOp
WordToIntOp)
  , String -> Name -> Name -> Id -> CoreRule
small_passthrough_app String
"Word# -> Integer -> Float#"
        Name
integerFromWordName Name
integerToFloatName (PrimOp -> Id
mkPrimOpId PrimOp
WordToFloatOp)
  , String -> Name -> Name -> Id -> CoreRule
small_passthrough_app String
"Word# -> Integer -> Double#"
        Name
integerFromWordName Name
integerToDoubleName (PrimOp -> Id
mkPrimOpId PrimOp
WordToDoubleOp)
  , String -> Name -> Name -> Id -> CoreRule
small_passthrough_app String
"Word# -> Integer -> Natural (wrap)"
        Name
integerFromWordName Name
integerToNaturalName Id
naturalNSId
  , String -> Name -> Name -> Id -> CoreRule
small_passthrough_app String
"Word# -> Integer -> Natural (throw)"
        Name
integerFromWordName Name
integerToNaturalThrowName Id
naturalNSId
  , String -> Name -> Name -> Id -> CoreRule
small_passthrough_app String
"Word# -> Integer -> Natural (clamp)"
        Name
integerFromWordName Name
integerToNaturalClampName Id
naturalNSId

  , String -> Name -> Name -> Id -> CoreRule
small_passthrough_app String
"Word# -> Natural -> Float#"
        Name
naturalNSName Name
naturalToFloatName  (PrimOp -> Id
mkPrimOpId PrimOp
WordToFloatOp)
  , String -> Name -> Name -> Id -> CoreRule
small_passthrough_app String
"Word# -> Natural -> Double#"
        Name
naturalNSName Name
naturalToDoubleName (PrimOp -> Id
mkPrimOpId PrimOp
WordToDoubleOp)

#if WORD_SIZE_IN_BITS < 64
  , small_passthrough_id "Int64# -> Integer -> Int64#"
      integerFromInt64Name integerToInt64Name
  , small_passthrough_id "Word64# -> Integer -> Word64#"
      integerFromWord64Name integerToWord64Name

  , small_passthrough_app "Int64# -> Integer -> Word64#"
        integerFromInt64Name integerToWord64Name   (mkPrimOpId Int64ToWord64Op)
  , small_passthrough_app "Word64# -> Integer -> Int64#"
        integerFromWord64Name integerToInt64Name   (mkPrimOpId Word64ToInt64Op)

  , small_passthrough_app "Word# -> Integer -> Word64#"
        integerFromWordName integerToWord64Name (mkPrimOpId WordToWord64Op)
  , small_passthrough_app "Word64# -> Integer -> Word#"
        integerFromWord64Name integerToWordName (mkPrimOpId Word64ToWordOp)
  , small_passthrough_app "Int# -> Integer -> Int64#"
        integerISName integerToInt64Name (mkPrimOpId IntToInt64Op)
  , small_passthrough_app "Int64# -> Integer -> Int#"
        integerFromInt64Name integerToIntName (mkPrimOpId Int64ToIntOp)

  , small_passthrough_custom "Int# -> Integer -> Word64#"
        integerISName integerToWord64Name
          (\x -> Var (mkPrimOpId Int64ToWord64Op) `App` (Var (mkPrimOpId IntToInt64Op) `App` x))
  , small_passthrough_custom "Word64# -> Integer -> Int#"
        integerFromWord64Name integerToIntName
          (\x -> Var (mkPrimOpId WordToIntOp) `App` (Var (mkPrimOpId Word64ToWordOp) `App` x))
  , small_passthrough_custom "Word# -> Integer -> Int64#"
        integerFromWordName integerToInt64Name
          (\x -> Var (mkPrimOpId Word64ToInt64Op) `App` (Var (mkPrimOpId WordToWord64Op) `App` x))
  , small_passthrough_custom "Int64# -> Integer -> Word#"
        integerFromInt64Name integerToWordName
          (\x -> Var (mkPrimOpId IntToWordOp) `App` (Var (mkPrimOpId Int64ToIntOp) `App` x))
#endif

    -- Bits.bit
  , forall {t}. Bits t => String -> Name -> (t -> Literal) -> CoreRule
bignum_bit String
"integerBit" Name
integerBitName Integer -> Literal
mkLitInteger
  , forall {t}. Bits t => String -> Name -> (t -> Literal) -> CoreRule
bignum_bit String
"naturalBit" Name
naturalBitName Integer -> Literal
mkLitNatural

    -- Bits.testBit
  , String -> Name -> CoreRule
bignum_testbit String
"integerTestBit" Name
integerTestBitName
  , String -> Name -> CoreRule
bignum_testbit String
"naturalTestBit" Name
naturalTestBitName

    -- Bits.shift
  , forall {t} {t}.
Num t =>
String -> Name -> (Integer -> t -> t) -> (t -> Literal) -> CoreRule
bignum_shift String
"integerShiftL" Name
integerShiftLName forall a. Bits a => a -> ConTagZ -> a
shiftL Integer -> Literal
mkLitInteger
  , forall {t} {t}.
Num t =>
String -> Name -> (Integer -> t -> t) -> (t -> Literal) -> CoreRule
bignum_shift String
"integerShiftR" Name
integerShiftRName forall a. Bits a => a -> ConTagZ -> a
shiftR Integer -> Literal
mkLitInteger
  , forall {t} {t}.
Num t =>
String -> Name -> (Integer -> t -> t) -> (t -> Literal) -> CoreRule
bignum_shift String
"naturalShiftL" Name
naturalShiftLName forall a. Bits a => a -> ConTagZ -> a
shiftL Integer -> Literal
mkLitNatural
  , forall {t} {t}.
Num t =>
String -> Name -> (Integer -> t -> t) -> (t -> Literal) -> CoreRule
bignum_shift String
"naturalShiftR" Name
naturalShiftRName forall a. Bits a => a -> ConTagZ -> a
shiftR Integer -> Literal
mkLitNatural

    -- division
  , forall {t}.
String
-> Name -> (Integer -> Integer -> t) -> (t -> Literal) -> CoreRule
divop_one  String
"integerQuot"    Name
integerQuotName    forall a. Integral a => a -> a -> a
quot    Integer -> Literal
mkLitInteger
  , forall {t}.
String
-> Name -> (Integer -> Integer -> t) -> (t -> Literal) -> CoreRule
divop_one  String
"integerRem"     Name
integerRemName     forall a. Integral a => a -> a -> a
rem     Integer -> Literal
mkLitInteger
  , forall {t}.
String
-> Name -> (Integer -> Integer -> t) -> (t -> Literal) -> CoreRule
divop_one  String
"integerDiv"     Name
integerDivName     forall a. Integral a => a -> a -> a
div     Integer -> Literal
mkLitInteger
  , forall {t}.
String
-> Name -> (Integer -> Integer -> t) -> (t -> Literal) -> CoreRule
divop_one  String
"integerMod"     Name
integerModName     forall a. Integral a => a -> a -> a
mod     Integer -> Literal
mkLitInteger
  , forall {t}.
String
-> Name
-> (Integer -> Integer -> (t, t))
-> (t -> Literal)
-> Type
-> CoreRule
divop_both String
"integerDivMod"  Name
integerDivModName  forall a. Integral a => a -> a -> (a, a)
divMod  Integer -> Literal
mkLitInteger Type
integerTy
  , forall {t}.
String
-> Name
-> (Integer -> Integer -> (t, t))
-> (t -> Literal)
-> Type
-> CoreRule
divop_both String
"integerQuotRem" Name
integerQuotRemName forall a. Integral a => a -> a -> (a, a)
quotRem Integer -> Literal
mkLitInteger Type
integerTy

  , forall {t}.
String
-> Name -> (Integer -> Integer -> t) -> (t -> Literal) -> CoreRule
divop_one  String
"naturalQuot"    Name
naturalQuotName    forall a. Integral a => a -> a -> a
quot    Integer -> Literal
mkLitNatural
  , forall {t}.
String
-> Name -> (Integer -> Integer -> t) -> (t -> Literal) -> CoreRule
divop_one  String
"naturalRem"     Name
naturalRemName     forall a. Integral a => a -> a -> a
rem     Integer -> Literal
mkLitNatural
  , forall {t}.
String
-> Name
-> (Integer -> Integer -> (t, t))
-> (t -> Literal)
-> Type
-> CoreRule
divop_both String
"naturalQuotRem" Name
naturalQuotRemName forall a. Integral a => a -> a -> (a, a)
quotRem Integer -> Literal
mkLitNatural Type
naturalTy

    -- conversions from Rational for Float/Double literals
  , forall a.
RealFloat a =>
String -> Name -> (a -> CoreExpr) -> CoreRule
rational_to String
"rationalToFloat"  Name
rationalToFloatName  Float -> CoreExpr
mkFloatExpr
  , forall a.
RealFloat a =>
String -> Name -> (a -> CoreExpr) -> CoreRule
rational_to String
"rationalToDouble" Name
rationalToDoubleName Double -> CoreExpr
mkDoubleExpr

    -- conversions from Integer for Float/Double literals
  , forall a.
RealFloat a =>
String -> Name -> (a -> CoreExpr) -> CoreRule
integer_encode_float String
"integerEncodeFloat"  Name
integerEncodeFloatName  forall b. Float -> Expr b
mkFloatLitFloat
  , forall a.
RealFloat a =>
String -> Name -> (a -> CoreExpr) -> CoreRule
integer_encode_float String
"integerEncodeDouble" Name
integerEncodeDoubleName forall b. Double -> Expr b
mkDoubleLitDouble
  ]
  where
    -- The rule is matching against an occurrence of a data constructor in a
    -- Core expression. It must match either its worker name or its wrapper
    -- name, /not/ the DataCon name itself, which is different.
    -- See Note [Data Constructor Naming] in GHC.Core.DataCon and #19892
    --
    -- But data constructor wrappers deliberately inline late; See Note
    -- [Activation for data constructor wrappers] in GHC.Types.Id.Make.
    -- Suppose there is a wrapper and the rule matches on the worker: the
    -- wrapper won't be inlined until rules have finished firing and the rule
    -- will never fire.
    --
    -- Hence the rule must match on the wrapper, if there is one, otherwise on
    -- the worker. That is exactly the dataConWrapId for the data constructor.
    -- The data constructor may or may not have a wrapper, but if not
    -- dataConWrapId will return the worker
    --
    integerISId :: Id
integerISId   = DataCon -> Id
dataConWrapId DataCon
integerISDataCon
    naturalNSId :: Id
naturalNSId   = DataCon -> Id
dataConWrapId DataCon
naturalNSDataCon
    integerISName :: Name
integerISName = Id -> Name
idName Id
integerISId
    naturalNSName :: Name
naturalNSName = Id -> Name
idName Id
naturalNSId

    mkRule :: String -> Name -> ConTagZ -> RuleM CoreExpr -> CoreRule
mkRule String
str Name
name ConTagZ
nargs RuleM CoreExpr
f = BuiltinRule
      { ru_name :: RuleName
ru_name = String -> RuleName
fsLit String
str
      , ru_fn :: Name
ru_fn = Name
name
      , ru_nargs :: ConTagZ
ru_nargs = ConTagZ
nargs
      , ru_try :: RuleFun
ru_try = forall r.
RuleM r -> RuleOpts -> InScopeEnv -> Id -> [CoreExpr] -> Maybe r
runRuleM forall a b. (a -> b) -> a -> b
$ do
          RuleOpts
env <- RuleM RuleOpts
getRuleOpts
          forall (f :: * -> *). Alternative f => Bool -> f ()
guard (RuleOpts -> Bool
roBignumRules RuleOpts
env)
          RuleM CoreExpr
f
      }

    integer_to_lit :: String -> Name -> (Platform -> Integer -> CoreExpr) -> CoreRule
integer_to_lit String
str Name
name Platform -> Integer -> CoreExpr
convert = String -> Name -> ConTagZ -> RuleM CoreExpr -> CoreRule
mkRule String
str Name
name ConTagZ
1 forall a b. (a -> b) -> a -> b
$ do
      [CoreExpr
a0] <- RuleM [CoreExpr]
getArgs
      Platform
platform <- RuleM Platform
getPlatform
      Integer
x <- CoreExpr -> RuleM Integer
isIntegerLiteral CoreExpr
a0
      forall (f :: * -> *) a. Applicative f => a -> f a
pure (Platform -> Integer -> CoreExpr
convert Platform
platform Integer
x)

    natural_to_word :: String -> Name -> Bool -> CoreRule
natural_to_word String
str Name
name Bool
clamp = String -> Name -> ConTagZ -> RuleM CoreExpr -> CoreRule
mkRule String
str Name
name ConTagZ
1 forall a b. (a -> b) -> a -> b
$ do
      [CoreExpr
a0] <- RuleM [CoreExpr]
getArgs
      Integer
n <- CoreExpr -> RuleM Integer
isNaturalLiteral CoreExpr
a0
      Platform
platform <- RuleM Platform
getPlatform
      if Bool
clamp Bool -> Bool -> Bool
&& Bool -> Bool
not (Platform -> Integer -> Bool
platformInWordRange Platform
platform Integer
n)
          then forall (f :: * -> *) a. Applicative f => a -> f a
pure (forall b. Literal -> Expr b
Lit (Platform -> Integer -> Literal
mkLitWord Platform
platform (Platform -> Integer
platformMaxWord Platform
platform)))
          else forall (f :: * -> *) a. Applicative f => a -> f a
pure (forall b. Literal -> Expr b
Lit (Platform -> Integer -> Literal
mkLitWordWrap Platform
platform Integer
n))

    integer_to_natural :: String -> Name -> Bool -> Bool -> CoreRule
integer_to_natural String
str Name
name Bool
thrw Bool
clamp = String -> Name -> ConTagZ -> RuleM CoreExpr -> CoreRule
mkRule String
str Name
name ConTagZ
1 forall a b. (a -> b) -> a -> b
$ do
      [CoreExpr
a0] <- RuleM [CoreExpr]
getArgs
      Integer
x <- CoreExpr -> RuleM Integer
isIntegerLiteral CoreExpr
a0
      if | Integer
x forall a. Ord a => a -> a -> Bool
>= Integer
0    -> forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ forall b. Literal -> Expr b
Lit forall a b. (a -> b) -> a -> b
$ Integer -> Literal
mkLitNatural Integer
x
         | Bool
thrw      -> forall (m :: * -> *) a. MonadPlus m => m a
mzero
         | Bool
clamp     -> forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ forall b. Literal -> Expr b
Lit forall a b. (a -> b) -> a -> b
$ Integer -> Literal
mkLitNatural Integer
0       -- clamp to 0
         | Bool
otherwise -> forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ forall b. Literal -> Expr b
Lit forall a b. (a -> b) -> a -> b
$ Integer -> Literal
mkLitNatural (forall a. Num a => a -> a
abs Integer
x) -- negate/wrap

    lit_to_integer :: String -> Name -> CoreRule
lit_to_integer String
str Name
name = String -> Name -> ConTagZ -> RuleM CoreExpr -> CoreRule
mkRule String
str Name
name ConTagZ
1 forall a b. (a -> b) -> a -> b
$ do
      [CoreExpr
a0] <- RuleM [CoreExpr]
getArgs
      CoreExpr -> RuleM Literal
isLiteral CoreExpr
a0 forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
        -- convert any numeric literal into an Integer literal
        LitNumber LitNumType
_ Integer
i -> forall (f :: * -> *) a. Applicative f => a -> f a
pure (forall b. Literal -> Expr b
Lit (Integer -> Literal
mkLitInteger Integer
i))
        Literal
_             -> forall (m :: * -> *) a. MonadPlus m => m a
mzero

    lit_to_natural :: String -> Name -> CoreRule
lit_to_natural String
str Name
name = String -> Name -> ConTagZ -> RuleM CoreExpr -> CoreRule
mkRule String
str Name
name ConTagZ
1 forall a b. (a -> b) -> a -> b
$ do
      [CoreExpr
a0] <- RuleM [CoreExpr]
getArgs
      CoreExpr -> RuleM Literal
isLiteral CoreExpr
a0 forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
        -- convert any *positive* numeric literal into a Natural literal
        LitNumber LitNumType
_ Integer
i | Integer
i forall a. Ord a => a -> a -> Bool
>= Integer
0 -> forall (f :: * -> *) a. Applicative f => a -> f a
pure (forall b. Literal -> Expr b
Lit (Integer -> Literal
mkLitNatural Integer
i))
        Literal
_                      -> forall (m :: * -> *) a. MonadPlus m => m a
mzero

    integer_binop :: String -> Name -> (Integer -> Integer -> Integer) -> CoreRule
integer_binop String
str Name
name Integer -> Integer -> Integer
op = String -> Name -> ConTagZ -> RuleM CoreExpr -> CoreRule
mkRule String
str Name
name ConTagZ
2 forall a b. (a -> b) -> a -> b
$ do
      [CoreExpr
a0,CoreExpr
a1] <- RuleM [CoreExpr]
getArgs
      Integer
x <- CoreExpr -> RuleM Integer
isIntegerLiteral CoreExpr
a0
      Integer
y <- CoreExpr -> RuleM Integer
isIntegerLiteral CoreExpr
a1
      forall (f :: * -> *) a. Applicative f => a -> f a
pure (forall b. Literal -> Expr b
Lit (Integer -> Literal
mkLitInteger (Integer
x Integer -> Integer -> Integer
`op` Integer
y)))

    natural_binop :: String -> Name -> (Integer -> Integer -> Integer) -> CoreRule
natural_binop String
str Name
name Integer -> Integer -> Integer
op = String -> Name -> ConTagZ -> RuleM CoreExpr -> CoreRule
mkRule String
str Name
name ConTagZ
2 forall a b. (a -> b) -> a -> b
$ do
      [CoreExpr
a0,CoreExpr
a1] <- RuleM [CoreExpr]
getArgs
      Integer
x <- CoreExpr -> RuleM Integer
isNaturalLiteral CoreExpr
a0
      Integer
y <- CoreExpr -> RuleM Integer
isNaturalLiteral CoreExpr
a1
      forall (f :: * -> *) a. Applicative f => a -> f a
pure (forall b. Literal -> Expr b
Lit (Integer -> Literal
mkLitNatural (Integer
x Integer -> Integer -> Integer
`op` Integer
y)))

    natural_sub :: String -> Name -> CoreRule
natural_sub String
str Name
name = String -> Name -> ConTagZ -> RuleM CoreExpr -> CoreRule
mkRule String
str Name
name ConTagZ
2 forall a b. (a -> b) -> a -> b
$ do
      [CoreExpr
a0,CoreExpr
a1] <- RuleM [CoreExpr]
getArgs
      Integer
x <- CoreExpr -> RuleM Integer
isNaturalLiteral CoreExpr
a0
      Integer
y <- CoreExpr -> RuleM Integer
isNaturalLiteral CoreExpr
a1
      forall (f :: * -> *). Alternative f => Bool -> f ()
guard (Integer
x forall a. Ord a => a -> a -> Bool
>= Integer
y)
      forall (f :: * -> *) a. Applicative f => a -> f a
pure (forall b. Literal -> Expr b
Lit (Integer -> Literal
mkLitNatural (Integer
x forall a. Num a => a -> a -> a
- Integer
y)))

    integer_cmp :: String -> Name -> (Integer -> Integer -> Bool) -> CoreRule
integer_cmp String
str Name
name Integer -> Integer -> Bool
op = String -> Name -> ConTagZ -> RuleM CoreExpr -> CoreRule
mkRule String
str Name
name ConTagZ
2 forall a b. (a -> b) -> a -> b
$ do
      Platform
platform <- RuleM Platform
getPlatform
      [CoreExpr
a0,CoreExpr
a1] <- RuleM [CoreExpr]
getArgs
      Integer
x <- CoreExpr -> RuleM Integer
isIntegerLiteral CoreExpr
a0
      Integer
y <- CoreExpr -> RuleM Integer
isIntegerLiteral CoreExpr
a1
      forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ if Integer
x Integer -> Integer -> Bool
`op` Integer
y
              then Platform -> CoreExpr
trueValInt Platform
platform
              else Platform -> CoreExpr
falseValInt Platform
platform

    natural_cmp :: String -> Name -> (Integer -> Integer -> Bool) -> CoreRule
natural_cmp String
str Name
name Integer -> Integer -> Bool
op = String -> Name -> ConTagZ -> RuleM CoreExpr -> CoreRule
mkRule String
str Name
name ConTagZ
2 forall a b. (a -> b) -> a -> b
$ do
      Platform
platform <- RuleM Platform
getPlatform
      [CoreExpr
a0,CoreExpr
a1] <- RuleM [CoreExpr]
getArgs
      Integer
x <- CoreExpr -> RuleM Integer
isNaturalLiteral CoreExpr
a0
      Integer
y <- CoreExpr -> RuleM Integer
isNaturalLiteral CoreExpr
a1
      forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ if Integer
x Integer -> Integer -> Bool
`op` Integer
y
              then Platform -> CoreExpr
trueValInt Platform
platform
              else Platform -> CoreExpr
falseValInt Platform
platform

    bignum_compare :: String -> Name -> CoreRule
bignum_compare String
str Name
name = String -> Name -> ConTagZ -> RuleM CoreExpr -> CoreRule
mkRule String
str Name
name ConTagZ
2 forall a b. (a -> b) -> a -> b
$ do
      [CoreExpr
a0,CoreExpr
a1] <- RuleM [CoreExpr]
getArgs
      Integer
x <- CoreExpr -> RuleM Integer
isNumberLiteral CoreExpr
a0
      Integer
y <- CoreExpr -> RuleM Integer
isNumberLiteral CoreExpr
a1
      forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ case Integer
x forall a. Ord a => a -> a -> Ordering
`compare` Integer
y of
              Ordering
LT -> CoreExpr
ltVal
              Ordering
EQ -> CoreExpr
eqVal
              Ordering
GT -> CoreExpr
gtVal

    bignum_unop :: String -> Name -> (t -> Literal) -> (Integer -> t) -> CoreRule
bignum_unop String
str Name
name t -> Literal
mk_lit Integer -> t
op = String -> Name -> ConTagZ -> RuleM CoreExpr -> CoreRule
mkRule String
str Name
name ConTagZ
1 forall a b. (a -> b) -> a -> b
$ do
      [CoreExpr
a0] <- RuleM [CoreExpr]
getArgs
      Integer
x <- CoreExpr -> RuleM Integer
isNumberLiteral CoreExpr
a0
      forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ forall b. Literal -> Expr b
Lit (t -> Literal
mk_lit (Integer -> t
op Integer
x))

    bignum_popcount :: String -> Name -> (Platform -> t -> Literal) -> CoreRule
bignum_popcount String
str Name
name Platform -> t -> Literal
mk_lit = String -> Name -> ConTagZ -> RuleM CoreExpr -> CoreRule
mkRule String
str Name
name ConTagZ
1 forall a b. (a -> b) -> a -> b
$ do
      Platform
platform <- RuleM Platform
getPlatform
      -- We use a host Int to compute the popCount. If we compile on a 32-bit
      -- host for a 64-bit target, the result may be different than if computed
      -- by the target. So we disable this rule if sizes don't match.
      forall (f :: * -> *). Alternative f => Bool -> f ()
guard (Platform -> ConTagZ
platformWordSizeInBits Platform
platform forall a. Eq a => a -> a -> Bool
== forall b. FiniteBits b => b -> ConTagZ
finiteBitSize (Word
0 :: Word))
      [CoreExpr
a0] <- RuleM [CoreExpr]
getArgs
      Integer
x <- CoreExpr -> RuleM Integer
isNumberLiteral CoreExpr
a0
      forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ forall b. Literal -> Expr b
Lit (Platform -> t -> Literal
mk_lit Platform
platform (forall a b. (Integral a, Num b) => a -> b
fromIntegral (forall a. Bits a => a -> ConTagZ
popCount Integer
x)))

    small_passthrough_id :: String -> Name -> Name -> CoreRule
small_passthrough_id String
str Name
from_x Name
to_x =
      String -> Name -> Name -> (CoreExpr -> CoreExpr) -> CoreRule
small_passthrough_custom String
str Name
from_x Name
to_x forall a. a -> a
id

    small_passthrough_app :: String -> Name -> Name -> Id -> CoreRule
small_passthrough_app String
str Name
from_x Name
to_y Id
x_to_y =
      String -> Name -> Name -> (CoreExpr -> CoreExpr) -> CoreRule
small_passthrough_custom String
str Name
from_x Name
to_y (forall b. Expr b -> Expr b -> Expr b
App (forall b. Id -> Expr b
Var Id
x_to_y))

    small_passthrough_custom :: String -> Name -> Name -> (CoreExpr -> CoreExpr) -> CoreRule
small_passthrough_custom String
str Name
from_x Name
to_y CoreExpr -> CoreExpr
x_to_y = String -> Name -> ConTagZ -> RuleM CoreExpr -> CoreRule
mkRule String
str Name
to_y ConTagZ
1 forall a b. (a -> b) -> a -> b
$ do
      [CoreExpr
a0] <- RuleM [CoreExpr]
getArgs
      InScopeEnv
env <- RuleM InScopeEnv
getEnv
      (Id
f,CoreExpr
x) <- InScopeEnv -> CoreExpr -> RuleM (Id, CoreExpr)
isVarApp InScopeEnv
env CoreExpr
a0
      forall (f :: * -> *). Alternative f => Bool -> f ()
guard (Id -> Name
idName Id
f forall a. Eq a => a -> a -> Bool
== Name
from_x)
      forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ CoreExpr -> CoreExpr
x_to_y CoreExpr
x

    bignum_bit :: String -> Name -> (t -> Literal) -> CoreRule
bignum_bit String
str Name
name t -> Literal
mk_lit = String -> Name -> ConTagZ -> RuleM CoreExpr -> CoreRule
mkRule String
str Name
name ConTagZ
1 forall a b. (a -> b) -> a -> b
$ do
      [CoreExpr
a0] <- RuleM [CoreExpr]
getArgs
      Platform
platform <- RuleM Platform
getPlatform
      Integer
n <- CoreExpr -> RuleM Integer
isNumberLiteral CoreExpr
a0
      -- Make sure n is positive and small enough to yield a decently
      -- small number. Attempting to construct the Integer for
      --    (integerBit 9223372036854775807#)
      -- would be a bad idea (#14959)
      forall (f :: * -> *). Alternative f => Bool -> f ()
guard (Integer
n forall a. Ord a => a -> a -> Bool
>= Integer
0 Bool -> Bool -> Bool
&& Integer
n forall a. Ord a => a -> a -> Bool
<= forall a b. (Integral a, Num b) => a -> b
fromIntegral (Platform -> ConTagZ
platformWordSizeInBits Platform
platform))
      -- it's safe to convert a target Int value into a host Int value
      -- to perform the "bit" operation because n is very small (<= 64).
      forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ forall b. Literal -> Expr b
Lit (t -> Literal
mk_lit (forall a. Bits a => ConTagZ -> a
bit (forall a b. (Integral a, Num b) => a -> b
fromIntegral Integer
n)))

    bignum_testbit :: String -> Name -> CoreRule
bignum_testbit String
str Name
name = String -> Name -> ConTagZ -> RuleM CoreExpr -> CoreRule
mkRule String
str Name
name ConTagZ
2 forall a b. (a -> b) -> a -> b
$ do
      [CoreExpr
a0,CoreExpr
a1] <- RuleM [CoreExpr]
getArgs
      Platform
platform <- RuleM Platform
getPlatform
      Integer
x <- CoreExpr -> RuleM Integer
isNumberLiteral CoreExpr
a0
      Integer
n <- CoreExpr -> RuleM Integer
isNumberLiteral CoreExpr
a1
      -- ensure that we can store 'n' in a host Int
      forall (f :: * -> *). Alternative f => Bool -> f ()
guard (Integer
n forall a. Ord a => a -> a -> Bool
>= Integer
0 Bool -> Bool -> Bool
&& Integer
n forall a. Ord a => a -> a -> Bool
<= forall a b. (Integral a, Num b) => a -> b
fromIntegral (forall a. Bounded a => a
maxBound :: Int))
      forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ if forall a. Bits a => a -> ConTagZ -> Bool
testBit Integer
x (forall a b. (Integral a, Num b) => a -> b
fromIntegral Integer
n)
              then Platform -> CoreExpr
trueValInt Platform
platform
              else Platform -> CoreExpr
falseValInt Platform
platform

    bignum_shift :: String -> Name -> (Integer -> t -> t) -> (t -> Literal) -> CoreRule
bignum_shift String
str Name
name Integer -> t -> t
shift_op t -> Literal
mk_lit = String -> Name -> ConTagZ -> RuleM CoreExpr -> CoreRule
mkRule String
str Name
name ConTagZ
2 forall a b. (a -> b) -> a -> b
$ do
      [CoreExpr
a0,CoreExpr
a1] <- RuleM [CoreExpr]
getArgs
      Integer
x <- CoreExpr -> RuleM Integer
isNumberLiteral CoreExpr
a0
      Integer
n <- CoreExpr -> RuleM Integer
isWordLiteral CoreExpr
a1
      -- See Note [Guarding against silly shifts]
      -- Restrict constant-folding of shifts on Integers, somewhat arbitrary.
      -- We can get huge shifts in inaccessible code (#15673)
      forall (f :: * -> *). Alternative f => Bool -> f ()
guard (Integer
n forall a. Ord a => a -> a -> Bool
<= Integer
4)
      forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ forall b. Literal -> Expr b
Lit (t -> Literal
mk_lit (Integer
x Integer -> t -> t
`shift_op` forall a b. (Integral a, Num b) => a -> b
fromIntegral Integer
n))

    divop_one :: String
-> Name -> (Integer -> Integer -> t) -> (t -> Literal) -> CoreRule
divop_one String
str Name
name Integer -> Integer -> t
divop t -> Literal
mk_lit = String -> Name -> ConTagZ -> RuleM CoreExpr -> CoreRule
mkRule String
str Name
name ConTagZ
2 forall a b. (a -> b) -> a -> b
$ do
      [CoreExpr
a0,CoreExpr
a1] <- RuleM [CoreExpr]
getArgs
      Integer
n <- CoreExpr -> RuleM Integer
isNumberLiteral CoreExpr
a0
      Integer
d <- CoreExpr -> RuleM Integer
isNumberLiteral CoreExpr
a1
      forall (f :: * -> *). Alternative f => Bool -> f ()
guard (Integer
d forall a. Eq a => a -> a -> Bool
/= Integer
0)
      forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ forall b. Literal -> Expr b
Lit (t -> Literal
mk_lit (Integer
n Integer -> Integer -> t
`divop` Integer
d))

    divop_both :: String
-> Name
-> (Integer -> Integer -> (t, t))
-> (t -> Literal)
-> Type
-> CoreRule
divop_both String
str Name
name Integer -> Integer -> (t, t)
divop t -> Literal
mk_lit Type
ty = String -> Name -> ConTagZ -> RuleM CoreExpr -> CoreRule
mkRule String
str Name
name ConTagZ
2 forall a b. (a -> b) -> a -> b
$ do
      [CoreExpr
a0,CoreExpr
a1] <- RuleM [CoreExpr]
getArgs
      Integer
n <- CoreExpr -> RuleM Integer
isNumberLiteral CoreExpr
a0
      Integer
d <- CoreExpr -> RuleM Integer
isNumberLiteral CoreExpr
a1
      forall (f :: * -> *). Alternative f => Bool -> f ()
guard (Integer
d forall a. Eq a => a -> a -> Bool
/= Integer
0)
      let (t
r,t
s) = Integer
n Integer -> Integer -> (t, t)
`divop` Integer
d
      forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ [Type] -> [CoreExpr] -> CoreExpr
mkCoreUbxTup [Type
ty,Type
ty] [forall b. Literal -> Expr b
Lit (t -> Literal
mk_lit t
r), forall b. Literal -> Expr b
Lit (t -> Literal
mk_lit t
s)]

    integer_encode_float :: RealFloat a => String -> Name -> (a -> CoreExpr) -> CoreRule
    integer_encode_float :: forall a.
RealFloat a =>
String -> Name -> (a -> CoreExpr) -> CoreRule
integer_encode_float String
str Name
name a -> CoreExpr
mk_lit = String -> Name -> ConTagZ -> RuleM CoreExpr -> CoreRule
mkRule String
str Name
name ConTagZ
2 forall a b. (a -> b) -> a -> b
$ do
      [CoreExpr
a0,CoreExpr
a1] <- RuleM [CoreExpr]
getArgs
      Integer
x <- CoreExpr -> RuleM Integer
isIntegerLiteral CoreExpr
a0
      Integer
y <- CoreExpr -> RuleM Integer
isIntLiteral CoreExpr
a1
      -- check that y (a target Int) is in the host Int range
      forall (f :: * -> *). Alternative f => Bool -> f ()
guard (Integer
y forall a. Ord a => a -> a -> Bool
<= forall a b. (Integral a, Num b) => a -> b
fromIntegral (forall a. Bounded a => a
maxBound :: Int))
      forall (f :: * -> *) a. Applicative f => a -> f a
pure (a -> CoreExpr
mk_lit forall a b. (a -> b) -> a -> b
$ forall a. RealFloat a => Integer -> ConTagZ -> a
encodeFloat Integer
x (forall a. Num a => Integer -> a
fromInteger Integer
y))

    rational_to :: RealFloat a => String -> Name -> (a -> CoreExpr) -> CoreRule
    rational_to :: forall a.
RealFloat a =>
String -> Name -> (a -> CoreExpr) -> CoreRule
rational_to String
str Name
name a -> CoreExpr
mk_lit = String -> Name -> ConTagZ -> RuleM CoreExpr -> CoreRule
mkRule String
str Name
name ConTagZ
2 forall a b. (a -> b) -> a -> b
$ do
      -- This turns `rationalToFloat n d` where `n` and `d` are literals into
      -- a literal Float (and similarly for Double).
      [CoreExpr
a0,CoreExpr
a1] <- RuleM [CoreExpr]
getArgs
      Integer
n <- CoreExpr -> RuleM Integer
isIntegerLiteral CoreExpr
a0
      Integer
d <- CoreExpr -> RuleM Integer
isIntegerLiteral CoreExpr
a1
      -- it's important to not match d == 0, because that may represent a
      -- literal "0/0" or similar, and we can't produce a literal value for
      -- NaN or +-Inf
      forall (f :: * -> *). Alternative f => Bool -> f ()
guard (Integer
d forall a. Eq a => a -> a -> Bool
/= Integer
0)
      forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ a -> CoreExpr
mk_lit (forall a. Fractional a => Rational -> a
fromRational (Integer
n forall a. Integral a => a -> a -> Ratio a
% Integer
d))



---------------------------------------------------
-- The rule is this:
--      unpackFoldrCString*# "foo"# c (unpackFoldrCString*# "baz"# c n)
--      =  unpackFoldrCString*# "foobaz"# c n
--
-- See also Note [String literals in GHC] in CString.hs

-- CString version
match_append_lit_C :: RuleFun
match_append_lit_C :: RuleFun
match_append_lit_C = Unique -> RuleFun
match_append_lit Unique
unpackCStringFoldrIdKey

-- CStringUTF8 version
match_append_lit_utf8 :: RuleFun
match_append_lit_utf8 :: RuleFun
match_append_lit_utf8 = Unique -> RuleFun
match_append_lit Unique
unpackCStringFoldrUtf8IdKey

{-# INLINE match_append_lit #-}
match_append_lit :: Unique -> RuleFun
match_append_lit :: Unique -> RuleFun
match_append_lit Unique
foldVariant RuleOpts
_ InScopeEnv
id_unf Id
_
        [ Type Type
ty1
        , CoreExpr
lit1
        , CoreExpr
c1
        , CoreExpr
e2
        ]
  -- N.B. Ensure that we strip off any ticks (e.g. source notes) from the
  -- `lit` and `c` arguments, lest this may fail to fire when building with
  -- -g3. See #16740.
  | ([CoreTickish]
strTicks, Var Id
unpk `App` Type Type
ty2
                        `App` CoreExpr
lit2
                        `App` CoreExpr
c2
                        `App` CoreExpr
n) <- forall b.
(CoreTickish -> Bool) -> Expr b -> ([CoreTickish], Expr b)
stripTicksTop forall (pass :: TickishPass). GenTickish pass -> Bool
tickishFloatable CoreExpr
e2
  , Id
unpk forall a. Uniquable a => a -> Unique -> Bool
`hasKey` Unique
foldVariant
  , Just (LitString ByteString
s1) <- InScopeEnv -> CoreExpr -> Maybe Literal
exprIsLiteral_maybe InScopeEnv
id_unf CoreExpr
lit1
  , Just (LitString ByteString
s2) <- InScopeEnv -> CoreExpr -> Maybe Literal
exprIsLiteral_maybe InScopeEnv
id_unf CoreExpr
lit2
  , let freeVars :: InScopeSet
freeVars = (VarSet -> InScopeSet
mkInScopeSet (CoreExpr -> VarSet
exprFreeVars CoreExpr
c1 VarSet -> VarSet -> VarSet
`unionVarSet` CoreExpr -> VarSet
exprFreeVars CoreExpr
c2))
    in InScopeSet -> CoreExpr -> CoreExpr -> Bool
eqExpr InScopeSet
freeVars CoreExpr
c1 CoreExpr
c2
  , ([CoreTickish]
c1Ticks, CoreExpr
c1') <- forall b.
(CoreTickish -> Bool) -> Expr b -> ([CoreTickish], Expr b)
stripTicksTop forall (pass :: TickishPass). GenTickish pass -> Bool
tickishFloatable CoreExpr
c1
  , [CoreTickish]
c2Ticks <- forall b. (CoreTickish -> Bool) -> Expr b -> [CoreTickish]
stripTicksTopT forall (pass :: TickishPass). GenTickish pass -> Bool
tickishFloatable CoreExpr
c2
  = ASSERT( ty1 `eqType` ty2 )
    forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ [CoreTickish] -> CoreExpr -> CoreExpr
mkTicks [CoreTickish]
strTicks
         forall a b. (a -> b) -> a -> b
$ forall b. Id -> Expr b
Var Id
unpk forall b. Expr b -> Expr b -> Expr b
`App` forall b. Type -> Expr b
Type Type
ty1
                    forall b. Expr b -> Expr b -> Expr b
`App` forall b. Literal -> Expr b
Lit (ByteString -> Literal
LitString (ByteString
s1 ByteString -> ByteString -> ByteString
`BS.append` ByteString
s2))
                    forall b. Expr b -> Expr b -> Expr b
`App` [CoreTickish] -> CoreExpr -> CoreExpr
mkTicks ([CoreTickish]
c1Ticks forall a. [a] -> [a] -> [a]
++ [CoreTickish]
c2Ticks) CoreExpr
c1'
                    forall b. Expr b -> Expr b -> Expr b
`App` CoreExpr
n

match_append_lit Unique
_ RuleOpts
_ InScopeEnv
_ Id
_ [CoreExpr]
_ = forall a. Maybe a
Nothing

---------------------------------------------------
-- The rule is this:
--      eqString (unpackCString# (Lit s1)) (unpackCString# (Lit s2)) = s1==s2
-- Also  matches unpackCStringUtf8#

match_eq_string :: RuleFun
match_eq_string :: RuleFun
match_eq_string RuleOpts
_ InScopeEnv
id_unf Id
_
        [Var Id
unpk1 `App` CoreExpr
lit1, Var Id
unpk2 `App` CoreExpr
lit2]
  | Unique
unpk_key1 <- forall a. Uniquable a => a -> Unique
getUnique Id
unpk1
  , Unique
unpk_key2 <- forall a. Uniquable a => a -> Unique
getUnique Id
unpk2
  , Unique
unpk_key1 forall a. Eq a => a -> a -> Bool
== Unique
unpk_key2
  -- For now we insist the literals have to agree in their encoding
  -- to keep the rule simple. But we could check if the decoded strings
  -- compare equal in here as well.
  , Unique
unpk_key1 forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Unique
unpackCStringUtf8IdKey, Unique
unpackCStringIdKey]
  , Just (LitString ByteString
s1) <- InScopeEnv -> CoreExpr -> Maybe Literal
exprIsLiteral_maybe InScopeEnv
id_unf CoreExpr
lit1
  , Just (LitString ByteString
s2) <- InScopeEnv -> CoreExpr -> Maybe Literal
exprIsLiteral_maybe InScopeEnv
id_unf CoreExpr
lit2
  = forall a. a -> Maybe a
Just (if ByteString
s1 forall a. Eq a => a -> a -> Bool
== ByteString
s2 then CoreExpr
trueValBool else CoreExpr
falseValBool)

match_eq_string RuleOpts
_ InScopeEnv
_ Id
_ [CoreExpr]
_ = forall a. Maybe a
Nothing

-----------------------------------------------------------------------
-- Illustration of this rule:
--
-- cstringLength# "foobar"# --> 6
-- cstringLength# "fizz\NULzz"# --> 4
--
-- Nota bene: Addr# literals are suffixed by a NUL byte when they are
-- compiled to read-only data sections. That's why cstringLength# is
-- well defined on Addr# literals that do not explicitly have an embedded
-- NUL byte.
--
-- See GHC issue #5218, MR 2165, and bytestring PR 191. This is particularly
-- helpful when using OverloadedStrings to create a ByteString since the
-- function computing the length of such ByteStrings can often be constant
-- folded.
match_cstring_length :: RuleFun
match_cstring_length :: RuleFun
match_cstring_length RuleOpts
env InScopeEnv
id_unf Id
_ [CoreExpr
lit1]
  | Just (LitString ByteString
str) <- InScopeEnv -> CoreExpr -> Maybe Literal
exprIsLiteral_maybe InScopeEnv
id_unf CoreExpr
lit1
    -- If elemIndex returns Just, it has the index of the first embedded NUL
    -- in the string. If no NUL bytes are present (the common case) then use
    -- full length of the byte string.
  = let len :: ConTagZ
len = forall a. a -> Maybe a -> a
fromMaybe (ByteString -> ConTagZ
BS.length ByteString
str) (Word8 -> ByteString -> Maybe ConTagZ
BS.elemIndex Word8
0 ByteString
str)
     in forall a. a -> Maybe a
Just (forall b. Literal -> Expr b
Lit (Platform -> Integer -> Literal
mkLitInt (RuleOpts -> Platform
roPlatform RuleOpts
env) (forall a b. (Integral a, Num b) => a -> b
fromIntegral ConTagZ
len)))
match_cstring_length RuleOpts
_ InScopeEnv
_ Id
_ [CoreExpr]
_ = forall a. Maybe a
Nothing

---------------------------------------------------
{- Note [inlineId magic]
~~~~~~~~~~~~~~~~~~~~~~~~
The call 'inline f' arranges that 'f' is inlined, regardless of
its size. More precisely, the call 'inline f' rewrites to the
right-hand side of 'f's definition. This allows the programmer to
control inlining from a particular call site rather than the
definition site of the function.

The moving parts are simple:

* A very simple definition in the library base:GHC.Magic
     {-# NOINLINE[0] inline #-}
     inline :: a -> a
     inline x = x
  So in phase 0, 'inline' will be inlined, so its use imposes
  no overhead.

* A rewrite rule, in GHC.Core.Opt.ConstantFold, which makes
  (inline f) inline, implemented by match_inline.
  The rule for the 'inline' function is this:
     inline f_ty (f a b c) = <f's unfolding> a b c
  (if f has an unfolding, EVEN if it's a loop breaker)

  It's important to allow the argument to 'inline' to have args itself
  (a) because its more forgiving to allow the programmer to write
      either  inline f a b c
      or      inline (f a b c)
  (b) because a polymorphic f wll get a type argument that the
      programmer can't avoid, so the call may look like
        inline (map @Int @Bool) g xs

  Also, don't forget about 'inline's type argument!
-}

match_inline :: [Expr CoreBndr] -> Maybe (Expr CoreBndr)
match_inline :: [CoreExpr] -> Maybe CoreExpr
match_inline (Type Type
_ : CoreExpr
e : [CoreExpr]
_)
  | (Var Id
f, [CoreExpr]
args1) <- forall b. Expr b -> (Expr b, [Expr b])
collectArgs CoreExpr
e,
    Just CoreExpr
unf <- Unfolding -> Maybe CoreExpr
maybeUnfoldingTemplate (IdUnfoldingFun
realIdUnfolding Id
f)
             -- Ignore the IdUnfoldingFun here!
  = forall a. a -> Maybe a
Just (forall b. Expr b -> [Expr b] -> Expr b
mkApps CoreExpr
unf [CoreExpr]
args1)

match_inline [CoreExpr]
_ = forall a. Maybe a
Nothing

---------------------------------------------------
-- See Note [magicDictId magic] in "GHC.Types.Id.Make"
-- for a description of what is going on here.
match_magicDict :: [Expr CoreBndr] -> Maybe (Expr CoreBndr)
match_magicDict :: [CoreExpr] -> Maybe CoreExpr
match_magicDict [Type Type
_, (forall b. (CoreTickish -> Bool) -> Expr b -> Expr b
stripTicksE (forall a b. a -> b -> a
const Bool
True) -> (Var Id
wrap `App` Type Type
a `App` Type Type
_ `App` CoreExpr
f)), CoreExpr
x, CoreExpr
y ]
  | Just (Type
_, Type
fieldTy, Type
_)  <- Type -> Maybe (Type, Type, Type)
splitFunTy_maybe forall a b. (a -> b) -> a -> b
$ Type -> Type
dropForAlls forall a b. (a -> b) -> a -> b
$ Id -> Type
idType Id
wrap
  , Just (Type
_, Type
dictTy, Type
_)   <- Type -> Maybe (Type, Type, Type)
splitFunTy_maybe Type
fieldTy
  , Just TyCon
dictTc           <- Type -> Maybe TyCon
tyConAppTyCon_maybe Type
dictTy
  , Just ([Id]
_,Type
_,CoAxiom Unbranched
co)         <- TyCon -> Maybe ([Id], Type, CoAxiom Unbranched)
unwrapNewTyCon_maybe TyCon
dictTc
  = forall a. a -> Maybe a
Just
  forall a b. (a -> b) -> a -> b
$ CoreExpr
f forall b. Expr b -> Expr b -> Expr b
`App` forall b. Expr b -> CoercionR -> Expr b
Cast CoreExpr
x (CoercionR -> CoercionR
mkSymCo (Role -> CoAxiom Unbranched -> [Type] -> [CoercionR] -> CoercionR
mkUnbranchedAxInstCo Role
Representational CoAxiom Unbranched
co [Type
a] []))
      forall b. Expr b -> Expr b -> Expr b
`App` CoreExpr
y

match_magicDict [CoreExpr]
_ = forall a. Maybe a
Nothing

--------------------------------------------------------
-- Note [Constant folding through nested expressions]
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
--
-- We use rewrites rules to perform constant folding. It means that we don't
-- have a global view of the expression we are trying to optimise. As a
-- consequence we only perform local (small-step) transformations that either:
--    1) reduce the number of operations
--    2) rearrange the expression to increase the odds that other rules will
--    match
--
-- We don't try to handle more complex expression optimisation cases that would
-- require a global view. For example, rewriting expressions to increase
-- sharing (e.g., Horner's method); optimisations that require local
-- transformations increasing the number of operations; rearrangements to
-- cancel/factorize terms (e.g., (a+b-a-b) isn't rearranged to reduce to 0).
--
-- We already have rules to perform constant folding on expressions with the
-- following shape (where a and/or b are literals):
--
--          D)    op
--                /\
--               /  \
--              /    \
--             a      b
--
-- To support nested expressions, we match three other shapes of expression
-- trees:
--
-- A)   op1          B)       op1       C)       op1
--      /\                    /\                 /\
--     /  \                  /  \               /  \
--    /    \                /    \             /    \
--   a     op2            op2     c          op2    op3
--          /\            /\                 /\      /\
--         /  \          /  \               /  \    /  \
--        b    c        a    b             a    b  c    d
--
--
-- R1) +/- simplification:
--    ops = + or -, two literals (not siblings)
--
--    Examples:
--       A: 5 + (10-x)  ==> 15-x
--       B: (10+x) + 5  ==> 15+x
--       C: (5+a)-(5-b) ==> 0+(a+b)
--
-- R2) * simplification
--    ops = *, two literals (not siblings)
--
--    Examples:
--       A: 5 * (10*x)  ==> 50*x
--       B: (10*x) * 5  ==> 50*x
--       C: (5*a)*(5*b) ==> 25*(a*b)
--
-- R3) * distribution over +/-
--    op1 = *, op2 = + or -, two literals (not siblings)
--
--    This transformation doesn't reduce the number of operations but switches
--    the outer and the inner operations so that the outer is (+) or (-) instead
--    of (*). It increases the odds that other rules will match after this one.
--
--    Examples:
--       A: 5 * (10-x)  ==> 50 - (5*x)
--       B: (10+x) * 5  ==> 50 + (5*x)
--       C: Not supported as it would increase the number of operations:
--          (5+a)*(5-b) ==> 25 - 5*b + 5*a - a*b
--
-- R4) Simple factorization
--
--    op1 = + or -, op2/op3 = *,
--    one literal for each innermost * operation (except in the D case),
--    the two other terms are equals
--
--    Examples:
--       A: x - (10*x)  ==> (-9)*x
--       B: (10*x) + x  ==> 11*x
--       C: (5*x)-(x*3) ==> 2*x
--       D: x+x         ==> 2*x
--
-- R5) +/- propagation
--
--    ops = + or -, one literal
--
--    This transformation doesn't reduce the number of operations but propagates
--    the constant to the outer level. It increases the odds that other rules
--    will match after this one.
--
--    Examples:
--       A: x - (10-y)  ==> (x+y) - 10
--       B: (10+x) - y  ==> 10 + (x-y)
--       C: N/A (caught by the A and B cases)
--
--------------------------------------------------------

-- Rules to perform constant folding into nested expressions
--
--See Note [Constant folding through nested expressions]

addFoldingRules :: PrimOp -> NumOps -> RuleM CoreExpr
addFoldingRules :: PrimOp -> NumOps -> RuleM CoreExpr
addFoldingRules PrimOp
op NumOps
num_ops = do
   ASSERT(op == numAdd num_ops) return ()
   RuleOpts
env <- RuleM RuleOpts
getRuleOpts
   forall (f :: * -> *). Alternative f => Bool -> f ()
guard (RuleOpts -> Bool
roNumConstantFolding RuleOpts
env)
   [CoreExpr
arg1,CoreExpr
arg2] <- RuleM [CoreExpr]
getArgs
   Platform
platform <- RuleM Platform
getPlatform
   forall a. Maybe a -> RuleM a
liftMaybe
      -- commutativity for + is handled here
      (Platform -> CoreExpr -> CoreExpr -> NumOps -> Maybe CoreExpr
addFoldingRules' Platform
platform CoreExpr
arg1 CoreExpr
arg2 NumOps
num_ops
       forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> Platform -> CoreExpr -> CoreExpr -> NumOps -> Maybe CoreExpr
addFoldingRules' Platform
platform CoreExpr
arg2 CoreExpr
arg1 NumOps
num_ops)

subFoldingRules :: PrimOp -> NumOps -> RuleM CoreExpr
subFoldingRules :: PrimOp -> NumOps -> RuleM CoreExpr
subFoldingRules PrimOp
op NumOps
num_ops = do
   ASSERT(op == numSub num_ops) return ()
   RuleOpts
env <- RuleM RuleOpts
getRuleOpts
   forall (f :: * -> *). Alternative f => Bool -> f ()
guard (RuleOpts -> Bool
roNumConstantFolding RuleOpts
env)
   [CoreExpr
arg1,CoreExpr
arg2] <- RuleM [CoreExpr]
getArgs
   Platform
platform <- RuleM Platform
getPlatform
   forall a. Maybe a -> RuleM a
liftMaybe (Platform -> CoreExpr -> CoreExpr -> NumOps -> Maybe CoreExpr
subFoldingRules' Platform
platform CoreExpr
arg1 CoreExpr
arg2 NumOps
num_ops)

mulFoldingRules :: PrimOp -> NumOps -> RuleM CoreExpr
mulFoldingRules :: PrimOp -> NumOps -> RuleM CoreExpr
mulFoldingRules PrimOp
op NumOps
num_ops = do
   ASSERT(op == numMul num_ops) return ()
   RuleOpts
env <- RuleM RuleOpts
getRuleOpts
   forall (f :: * -> *). Alternative f => Bool -> f ()
guard (RuleOpts -> Bool
roNumConstantFolding RuleOpts
env)
   [CoreExpr
arg1,CoreExpr
arg2] <- RuleM [CoreExpr]
getArgs
   Platform
platform <- RuleM Platform
getPlatform
   forall a. Maybe a -> RuleM a
liftMaybe
      -- commutativity for * is handled here
      (Platform -> CoreExpr -> CoreExpr -> NumOps -> Maybe CoreExpr
mulFoldingRules' Platform
platform CoreExpr
arg1 CoreExpr
arg2 NumOps
num_ops
       forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> Platform -> CoreExpr -> CoreExpr -> NumOps -> Maybe CoreExpr
mulFoldingRules' Platform
platform CoreExpr
arg2 CoreExpr
arg1 NumOps
num_ops)


addFoldingRules' :: Platform -> CoreExpr -> CoreExpr -> NumOps -> Maybe CoreExpr
addFoldingRules' :: Platform -> CoreExpr -> CoreExpr -> NumOps -> Maybe CoreExpr
addFoldingRules' Platform
platform CoreExpr
arg1 CoreExpr
arg2 NumOps
num_ops = case (CoreExpr
arg1, CoreExpr
arg2) of
      -- R1) +/- simplification

      -- l1 + (l2 + x) ==> (l1+l2) + x
      (L Integer
l1, NumOps -> CoreExpr -> Maybe (Integer, CoreExpr)
is_lit_add NumOps
num_ops -> Just (Integer
l2,CoreExpr
x))
         -> forall a. a -> Maybe a
Just (Integer -> CoreExpr
mkL (Integer
l1forall a. Num a => a -> a -> a
+Integer
l2) CoreExpr -> CoreExpr -> CoreExpr
`add` CoreExpr
x)

      -- l1 + (l2 - x) ==> (l1+l2) - x
      (L Integer
l1, NumOps -> CoreExpr -> Maybe (CoreExpr, CoreExpr)
is_sub NumOps
num_ops -> Just (L Integer
l2,CoreExpr
x))
         -> forall a. a -> Maybe a
Just (Integer -> CoreExpr
mkL (Integer
l1forall a. Num a => a -> a -> a
+Integer
l2) CoreExpr -> CoreExpr -> CoreExpr
`sub` CoreExpr
x)

      -- l1 + (x - l2) ==> (l1-l2) + x
      (L Integer
l1, NumOps -> CoreExpr -> Maybe (CoreExpr, CoreExpr)
is_sub NumOps
num_ops -> Just (CoreExpr
x,L Integer
l2))
         -> forall a. a -> Maybe a
Just (Integer -> CoreExpr
mkL (Integer
l1forall a. Num a => a -> a -> a
-Integer
l2) CoreExpr -> CoreExpr -> CoreExpr
`add` CoreExpr
x)

      -- (l1 + x) + (l2 + y) ==> (l1+l2) + (x+y)
      (NumOps -> CoreExpr -> Maybe (Integer, CoreExpr)
is_lit_add NumOps
num_ops -> Just (Integer
l1,CoreExpr
x), NumOps -> CoreExpr -> Maybe (Integer, CoreExpr)
is_lit_add NumOps
num_ops -> Just (Integer
l2,CoreExpr
y))
         -> forall a. a -> Maybe a
Just (Integer -> CoreExpr
mkL (Integer
l1forall a. Num a => a -> a -> a
+Integer
l2) CoreExpr -> CoreExpr -> CoreExpr
`add` (CoreExpr
x CoreExpr -> CoreExpr -> CoreExpr
`add` CoreExpr
y))

      -- (l1 + x) + (l2 - y) ==> (l1+l2) + (x-y)
      (NumOps -> CoreExpr -> Maybe (Integer, CoreExpr)
is_lit_add NumOps
num_ops -> Just (Integer
l1,CoreExpr
x), NumOps -> CoreExpr -> Maybe (CoreExpr, CoreExpr)
is_sub NumOps
num_ops -> Just (L Integer
l2,CoreExpr
y))
         -> forall a. a -> Maybe a
Just (Integer -> CoreExpr
mkL (Integer
l1forall a. Num a => a -> a -> a
+Integer
l2) CoreExpr -> CoreExpr -> CoreExpr
`add` (CoreExpr
x CoreExpr -> CoreExpr -> CoreExpr
`sub` CoreExpr
y))

      -- (l1 + x) + (y - l2) ==> (l1-l2) + (x+y)
      (NumOps -> CoreExpr -> Maybe (Integer, CoreExpr)
is_lit_add NumOps
num_ops -> Just (Integer
l1,CoreExpr
x), NumOps -> CoreExpr -> Maybe (CoreExpr, CoreExpr)
is_sub NumOps
num_ops -> Just (CoreExpr
y,L Integer
l2))
         -> forall a. a -> Maybe a
Just (Integer -> CoreExpr
mkL (Integer
l1forall a. Num a => a -> a -> a
-Integer
l2) CoreExpr -> CoreExpr -> CoreExpr
`add` (CoreExpr
x CoreExpr -> CoreExpr -> CoreExpr
`add` CoreExpr
y))

      -- (l1 - x) + (l2 - y) ==> (l1+l2) - (x+y)
      (NumOps -> CoreExpr -> Maybe (CoreExpr, CoreExpr)
is_sub NumOps
num_ops -> Just (L Integer
l1,CoreExpr
x), NumOps -> CoreExpr -> Maybe (CoreExpr, CoreExpr)
is_sub NumOps
num_ops -> Just (L Integer
l2,CoreExpr
y))
         -> forall a. a -> Maybe a
Just (Integer -> CoreExpr
mkL (Integer
l1forall a. Num a => a -> a -> a
+Integer
l2) CoreExpr -> CoreExpr -> CoreExpr
`sub` (CoreExpr
x CoreExpr -> CoreExpr -> CoreExpr
`add` CoreExpr
y))

      -- (l1 - x) + (y - l2) ==> (l1-l2) + (y-x)
      (NumOps -> CoreExpr -> Maybe (CoreExpr, CoreExpr)
is_sub NumOps
num_ops -> Just (L Integer
l1,CoreExpr
x), NumOps -> CoreExpr -> Maybe (CoreExpr, CoreExpr)
is_sub NumOps
num_ops -> Just (CoreExpr
y,L Integer
l2))
         -> forall a. a -> Maybe a
Just (Integer -> CoreExpr
mkL (Integer
l1forall a. Num a => a -> a -> a
-Integer
l2) CoreExpr -> CoreExpr -> CoreExpr
`add` (CoreExpr
y CoreExpr -> CoreExpr -> CoreExpr
`sub` CoreExpr
x))

      -- (x - l1) + (y - l2) ==> (0-l1-l2) + (x+y)
      (NumOps -> CoreExpr -> Maybe (CoreExpr, CoreExpr)
is_sub NumOps
num_ops -> Just (CoreExpr
x,L Integer
l1), NumOps -> CoreExpr -> Maybe (CoreExpr, CoreExpr)
is_sub NumOps
num_ops -> Just (CoreExpr
y,L Integer
l2))
         -> forall a. a -> Maybe a
Just (Integer -> CoreExpr
mkL (Integer
0forall a. Num a => a -> a -> a
-Integer
l1forall a. Num a => a -> a -> a
-Integer
l2) CoreExpr -> CoreExpr -> CoreExpr
`add` (CoreExpr
x CoreExpr -> CoreExpr -> CoreExpr
`add` CoreExpr
y))

      -- R4) Simple factorization

      -- x + x ==> 2 * x
      (CoreExpr, CoreExpr)
_ | Just Integer
l1 <- NumOps -> CoreExpr -> CoreExpr -> Maybe Integer
is_expr_mul NumOps
num_ops CoreExpr
arg1 CoreExpr
arg2
        -> forall a. a -> Maybe a
Just (Integer -> CoreExpr
mkL (Integer
l1forall a. Num a => a -> a -> a
+Integer
1) CoreExpr -> CoreExpr -> CoreExpr
`mul` CoreExpr
arg1)

      -- (l1 * x) + x ==> (l1+1) * x
      (CoreExpr, CoreExpr)
_ | Just Integer
l1 <- NumOps -> CoreExpr -> CoreExpr -> Maybe Integer
is_expr_mul NumOps
num_ops CoreExpr
arg2 CoreExpr
arg1
        -> forall a. a -> Maybe a
Just (Integer -> CoreExpr
mkL (Integer
l1forall a. Num a => a -> a -> a
+Integer
1) CoreExpr -> CoreExpr -> CoreExpr
`mul` CoreExpr
arg2)

      -- (l1 * x) + (l2 * x) ==> (l1+l2) * x
      (NumOps -> CoreExpr -> Maybe (Integer, CoreExpr)
is_lit_mul NumOps
num_ops -> Just (Integer
l1,CoreExpr
x), NumOps -> CoreExpr -> CoreExpr -> Maybe Integer
is_expr_mul NumOps
num_ops CoreExpr
x -> Just Integer
l2)
         -> forall a. a -> Maybe a
Just (Integer -> CoreExpr
mkL (Integer
l1forall a. Num a => a -> a -> a
+Integer
l2) CoreExpr -> CoreExpr -> CoreExpr
`mul` CoreExpr
x)

      -- R5) +/- propagation: these transformations push literals outwards
      -- with the hope that other rules can then be applied.

      -- In the following rules, x can't be a literal otherwise another
      -- rule would have combined it with the other literal in arg2. So we
      -- don't have to check this to avoid loops here.

      -- x + (l1 + y) ==> l1 + (x + y)
      (CoreExpr
_, NumOps -> CoreExpr -> Maybe (Integer, CoreExpr)
is_lit_add NumOps
num_ops -> Just (Integer
l1,CoreExpr
y))
         -> forall a. a -> Maybe a
Just (Integer -> CoreExpr
mkL Integer
l1 CoreExpr -> CoreExpr -> CoreExpr
`add` (CoreExpr
arg1 CoreExpr -> CoreExpr -> CoreExpr
`add` CoreExpr
y))

      -- x + (l1 - y) ==> l1 + (x - y)
      (CoreExpr
_, NumOps -> CoreExpr -> Maybe (CoreExpr, CoreExpr)
is_sub NumOps
num_ops -> Just (L Integer
l1,CoreExpr
y))
         -> forall a. a -> Maybe a
Just (Integer -> CoreExpr
mkL Integer
l1 CoreExpr -> CoreExpr -> CoreExpr
`add` (CoreExpr
arg1 CoreExpr -> CoreExpr -> CoreExpr
`sub` CoreExpr
y))

      -- x + (y - l1) ==> (x + y) - l1
      (CoreExpr
_, NumOps -> CoreExpr -> Maybe (CoreExpr, CoreExpr)
is_sub NumOps
num_ops -> Just (CoreExpr
y,L Integer
l1))
         -> forall a. a -> Maybe a
Just ((CoreExpr
arg1 CoreExpr -> CoreExpr -> CoreExpr
`add` CoreExpr
y) CoreExpr -> CoreExpr -> CoreExpr
`sub` Integer -> CoreExpr
mkL Integer
l1)

      (CoreExpr, CoreExpr)
_ -> forall a. Maybe a
Nothing

   where
      mkL :: Integer -> CoreExpr
mkL = forall b. Literal -> Expr b
Lit forall b c a. (b -> c) -> (a -> b) -> a -> c
. Platform -> NumOps -> Integer -> Literal
mkNumLiteral Platform
platform NumOps
num_ops
      add :: CoreExpr -> CoreExpr -> CoreExpr
add CoreExpr
x CoreExpr
y = CoreExpr -> PrimOp -> CoreExpr -> CoreExpr
BinOpApp CoreExpr
x (NumOps -> PrimOp
numAdd NumOps
num_ops) CoreExpr
y
      sub :: CoreExpr -> CoreExpr -> CoreExpr
sub CoreExpr
x CoreExpr
y = CoreExpr -> PrimOp -> CoreExpr -> CoreExpr
BinOpApp CoreExpr
x (NumOps -> PrimOp
numSub NumOps
num_ops) CoreExpr
y
      mul :: CoreExpr -> CoreExpr -> CoreExpr
mul CoreExpr
x CoreExpr
y = CoreExpr -> PrimOp -> CoreExpr -> CoreExpr
BinOpApp CoreExpr
x (NumOps -> PrimOp
numMul NumOps
num_ops) CoreExpr
y

subFoldingRules' :: Platform -> CoreExpr -> CoreExpr -> NumOps -> Maybe CoreExpr
subFoldingRules' :: Platform -> CoreExpr -> CoreExpr -> NumOps -> Maybe CoreExpr
subFoldingRules' Platform
platform CoreExpr
arg1 CoreExpr
arg2 NumOps
num_ops = case (CoreExpr
arg1,CoreExpr
arg2) of
      -- R1) +/- simplification

      -- l1 - (l2 + x) ==> (l1-l2) - x
      (L Integer
l1, NumOps -> CoreExpr -> Maybe (Integer, CoreExpr)
is_lit_add NumOps
num_ops -> Just (Integer
l2,CoreExpr
x))
         -> forall a. a -> Maybe a
Just (Integer -> CoreExpr
mkL (Integer
l1forall a. Num a => a -> a -> a
-Integer
l2) CoreExpr -> CoreExpr -> CoreExpr
`sub` CoreExpr
x)

      -- l1 - (l2 - x) ==> (l1-l2) + x
      (L Integer
l1, NumOps -> CoreExpr -> Maybe (CoreExpr, CoreExpr)
is_sub NumOps
num_ops -> Just (L Integer
l2,CoreExpr
x))
         -> forall a. a -> Maybe a
Just (Integer -> CoreExpr
mkL (Integer
l1forall a. Num a => a -> a -> a
-Integer
l2) CoreExpr -> CoreExpr -> CoreExpr
`add` CoreExpr
x)

      -- l1 - (x - l2) ==> (l1+l2) - x
      (L Integer
l1, NumOps -> CoreExpr -> Maybe (CoreExpr, CoreExpr)
is_sub NumOps
num_ops -> Just (CoreExpr
x, L Integer
l2))
         -> forall a. a -> Maybe a
Just (Integer -> CoreExpr
mkL (Integer
l1forall a. Num a => a -> a -> a
+Integer
l2) CoreExpr -> CoreExpr -> CoreExpr
`sub` CoreExpr
x)

      -- (l1 + x) - l2 ==> (l1-l2) + x
      (NumOps -> CoreExpr -> Maybe (Integer, CoreExpr)
is_lit_add NumOps
num_ops -> Just (Integer
l1,CoreExpr
x), L Integer
l2)
         -> forall a. a -> Maybe a
Just (Integer -> CoreExpr
mkL (Integer
l1forall a. Num a => a -> a -> a
-Integer
l2) CoreExpr -> CoreExpr -> CoreExpr
`add` CoreExpr
x)

      -- (l1 - x) - l2 ==> (l1-l2) - x
      (NumOps -> CoreExpr -> Maybe (CoreExpr, CoreExpr)
is_sub NumOps
num_ops -> Just (L Integer
l1,CoreExpr
x), L Integer
l2)
         -> forall a. a -> Maybe a
Just (Integer -> CoreExpr
mkL (Integer
l1forall a. Num a => a -> a -> a
-Integer
l2) CoreExpr -> CoreExpr -> CoreExpr
`sub` CoreExpr
x)

      -- (x - l1) - l2 ==> x - (l1+l2)
      (NumOps -> CoreExpr -> Maybe (CoreExpr, CoreExpr)
is_sub NumOps
num_ops -> Just (CoreExpr
x,L Integer
l1), L Integer
l2)
         -> forall a. a -> Maybe a
Just (CoreExpr
x CoreExpr -> CoreExpr -> CoreExpr
`sub` Integer -> CoreExpr
mkL (Integer
l1forall a. Num a => a -> a -> a
+Integer
l2))


      -- (l1 + x) - (l2 + y) ==> (l1-l2) + (x-y)
      (NumOps -> CoreExpr -> Maybe (Integer, CoreExpr)
is_lit_add NumOps
num_ops -> Just (Integer
l1,CoreExpr
x), NumOps -> CoreExpr -> Maybe (Integer, CoreExpr)
is_lit_add NumOps
num_ops -> Just (Integer
l2,CoreExpr
y))
         -> forall a. a -> Maybe a
Just (Integer -> CoreExpr
mkL (Integer
l1forall a. Num a => a -> a -> a
-Integer
l2) CoreExpr -> CoreExpr -> CoreExpr
`add` (CoreExpr
x CoreExpr -> CoreExpr -> CoreExpr
`sub` CoreExpr
y))

      -- (l1 + x) - (l2 - y) ==> (l1-l2) + (x+y)
      (NumOps -> CoreExpr -> Maybe (Integer, CoreExpr)
is_lit_add NumOps
num_ops -> Just (Integer
l1,CoreExpr
x), NumOps -> CoreExpr -> Maybe (CoreExpr, CoreExpr)
is_sub NumOps
num_ops -> Just (L Integer
l2,CoreExpr
y))
         -> forall a. a -> Maybe a
Just (Integer -> CoreExpr
mkL (Integer
l1forall a. Num a => a -> a -> a
-Integer
l2) CoreExpr -> CoreExpr -> CoreExpr
`add` (CoreExpr
x CoreExpr -> CoreExpr -> CoreExpr
`add` CoreExpr
y))

      -- (l1 + x) - (y - l2) ==> (l1+l2) + (x-y)
      (NumOps -> CoreExpr -> Maybe (Integer, CoreExpr)
is_lit_add NumOps
num_ops -> Just (Integer
l1,CoreExpr
x), NumOps -> CoreExpr -> Maybe (CoreExpr, CoreExpr)
is_sub NumOps
num_ops -> Just (CoreExpr
y,L Integer
l2))
         -> forall a. a -> Maybe a
Just (Integer -> CoreExpr
mkL (Integer
l1forall a. Num a => a -> a -> a
+Integer
l2) CoreExpr -> CoreExpr -> CoreExpr
`add` (CoreExpr
x CoreExpr -> CoreExpr -> CoreExpr
`sub` CoreExpr
y))

      -- (l1 - x) - (l2 + y) ==> (l1-l2) - (x+y)
      (NumOps -> CoreExpr -> Maybe (CoreExpr, CoreExpr)
is_sub NumOps
num_ops -> Just (L Integer
l1,CoreExpr
x), NumOps -> CoreExpr -> Maybe (Integer, CoreExpr)
is_lit_add NumOps
num_ops -> Just (Integer
l2,CoreExpr
y))
         -> forall a. a -> Maybe a
Just (Integer -> CoreExpr
mkL (Integer
l1forall a. Num a => a -> a -> a
-Integer
l2) CoreExpr -> CoreExpr -> CoreExpr
`sub` (CoreExpr
x CoreExpr -> CoreExpr -> CoreExpr
`add` CoreExpr
y))

      -- (x - l1) - (l2 + y) ==> (0-l1-l2) + (x-y)
      (NumOps -> CoreExpr -> Maybe (CoreExpr, CoreExpr)
is_sub NumOps
num_ops -> Just (CoreExpr
x,L Integer
l1), NumOps -> CoreExpr -> Maybe (Integer, CoreExpr)
is_lit_add NumOps
num_ops -> Just (Integer
l2,CoreExpr
y))
         -> forall a. a -> Maybe a
Just (Integer -> CoreExpr
mkL (Integer
0forall a. Num a => a -> a -> a
-Integer
l1forall a. Num a => a -> a -> a
-Integer
l2) CoreExpr -> CoreExpr -> CoreExpr
`add` (CoreExpr
x CoreExpr -> CoreExpr -> CoreExpr
`sub` CoreExpr
y))

      -- (l1 - x) - (l2 - y) ==> (l1-l2) + (y-x)
      (NumOps -> CoreExpr -> Maybe (CoreExpr, CoreExpr)
is_sub NumOps
num_ops -> Just (L Integer
l1,CoreExpr
x), NumOps -> CoreExpr -> Maybe (CoreExpr, CoreExpr)
is_sub NumOps
num_ops -> Just (L Integer
l2,CoreExpr
y))
         -> forall a. a -> Maybe a
Just (Integer -> CoreExpr
mkL (Integer
l1forall a. Num a => a -> a -> a
-Integer
l2) CoreExpr -> CoreExpr -> CoreExpr
`add` (CoreExpr
y CoreExpr -> CoreExpr -> CoreExpr
`sub` CoreExpr
x))

      -- (l1 - x) - (y - l2) ==> (l1+l2) - (x+y)
      (NumOps -> CoreExpr -> Maybe (CoreExpr, CoreExpr)
is_sub NumOps
num_ops -> Just (L Integer
l1,CoreExpr
x), NumOps -> CoreExpr -> Maybe (CoreExpr, CoreExpr)
is_sub NumOps
num_ops -> Just (CoreExpr
y,L Integer
l2))
         -> forall a. a -> Maybe a
Just (Integer -> CoreExpr
mkL (Integer
l1forall a. Num a => a -> a -> a
+Integer
l2) CoreExpr -> CoreExpr -> CoreExpr
`sub` (CoreExpr
x CoreExpr -> CoreExpr -> CoreExpr
`add` CoreExpr
y))

      -- (x - l1) - (l2 - y) ==> (0-l1-l2) + (x+y)
      (NumOps -> CoreExpr -> Maybe (CoreExpr, CoreExpr)
is_sub NumOps
num_ops -> Just (CoreExpr
x,L Integer
l1), NumOps -> CoreExpr -> Maybe (CoreExpr, CoreExpr)
is_sub NumOps
num_ops -> Just (L Integer
l2,CoreExpr
y))
         -> forall a. a -> Maybe a
Just (Integer -> CoreExpr
mkL (Integer
0forall a. Num a => a -> a -> a
-Integer
l1forall a. Num a => a -> a -> a
-Integer
l2) CoreExpr -> CoreExpr -> CoreExpr
`add` (CoreExpr
x CoreExpr -> CoreExpr -> CoreExpr
`add` CoreExpr
y))

      -- (x - l1) - (y - l2) ==> (l2-l1) + (x-y)
      (NumOps -> CoreExpr -> Maybe (CoreExpr, CoreExpr)
is_sub NumOps
num_ops -> Just (CoreExpr
x,L Integer
l1), NumOps -> CoreExpr -> Maybe (CoreExpr, CoreExpr)
is_sub NumOps
num_ops -> Just (CoreExpr
y,L Integer
l2))
         -> forall a. a -> Maybe a
Just (Integer -> CoreExpr
mkL (Integer
l2forall a. Num a => a -> a -> a
-Integer
l1) CoreExpr -> CoreExpr -> CoreExpr
`add` (CoreExpr
x CoreExpr -> CoreExpr -> CoreExpr
`sub` CoreExpr
y))

       -- R4) Simple factorization

      -- x - (l1 * x) ==> (1-l1) * x
      (CoreExpr, CoreExpr)
_ | Just Integer
l1 <- NumOps -> CoreExpr -> CoreExpr -> Maybe Integer
is_expr_mul NumOps
num_ops CoreExpr
arg1 CoreExpr
arg2
        -> forall a. a -> Maybe a
Just (Integer -> CoreExpr
mkL (Integer
1forall a. Num a => a -> a -> a
-Integer
l1) CoreExpr -> CoreExpr -> CoreExpr
`mul` CoreExpr
arg1)

      -- (l1 * x) - x ==> (l1-1) * x
      (CoreExpr, CoreExpr)
_ | Just Integer
l1 <- NumOps -> CoreExpr -> CoreExpr -> Maybe Integer
is_expr_mul NumOps
num_ops CoreExpr
arg2 CoreExpr
arg1
        -> forall a. a -> Maybe a
Just (Integer -> CoreExpr
mkL (Integer
l1forall a. Num a => a -> a -> a
-Integer
1) CoreExpr -> CoreExpr -> CoreExpr
`mul` CoreExpr
arg2)

      -- (l1 * x) - (l2 * x) ==> (l1-l2) * x
      (NumOps -> CoreExpr -> Maybe (Integer, CoreExpr)
is_lit_mul NumOps
num_ops -> Just (Integer
l1,CoreExpr
x), NumOps -> CoreExpr -> CoreExpr -> Maybe Integer
is_expr_mul NumOps
num_ops CoreExpr
x -> Just Integer
l2)
         -> forall a. a -> Maybe a
Just (Integer -> CoreExpr
mkL (Integer
l1forall a. Num a => a -> a -> a
-Integer
l2) CoreExpr -> CoreExpr -> CoreExpr
`mul` CoreExpr
x)

      -- R5) +/- propagation: these transformations push literals outwards
      -- with the hope that other rules can then be applied.

      -- In the following rules, x can't be a literal otherwise another
      -- rule would have combined it with the other literal in arg2. So we
      -- don't have to check this to avoid loops here.

      -- x - (l1 + y) ==> (x - y) - l1
      (CoreExpr
_, NumOps -> CoreExpr -> Maybe (Integer, CoreExpr)
is_lit_add NumOps
num_ops -> Just (Integer
l1,CoreExpr
y))
         -> forall a. a -> Maybe a
Just ((CoreExpr
arg1 CoreExpr -> CoreExpr -> CoreExpr
`sub` CoreExpr
y) CoreExpr -> CoreExpr -> CoreExpr
`sub` Integer -> CoreExpr
mkL Integer
l1)

      -- (l1 + x) - y ==> l1 + (x - y)
      (NumOps -> CoreExpr -> Maybe (Integer, CoreExpr)
is_lit_add NumOps
num_ops -> Just (Integer
l1,CoreExpr
x), CoreExpr
_)
         -> forall a. a -> Maybe a
Just (Integer -> CoreExpr
mkL Integer
l1 CoreExpr -> CoreExpr -> CoreExpr
`add` (CoreExpr
x CoreExpr -> CoreExpr -> CoreExpr
`sub` CoreExpr
arg2))

      -- x - (l1 - y) ==> (x + y) - l1
      (CoreExpr
_, NumOps -> CoreExpr -> Maybe (CoreExpr, CoreExpr)
is_sub NumOps
num_ops -> Just (L Integer
l1,CoreExpr
y))
         -> forall a. a -> Maybe a
Just ((CoreExpr
arg1 CoreExpr -> CoreExpr -> CoreExpr
`add` CoreExpr
y) CoreExpr -> CoreExpr -> CoreExpr
`sub` Integer -> CoreExpr
mkL Integer
l1)

      -- x - (y - l1) ==> l1 + (x - y)
      (CoreExpr
_, NumOps -> CoreExpr -> Maybe (CoreExpr, CoreExpr)
is_sub NumOps
num_ops -> Just (CoreExpr
y,L Integer
l1))
         -> forall a. a -> Maybe a
Just (Integer -> CoreExpr
mkL Integer
l1 CoreExpr -> CoreExpr -> CoreExpr
`add` (CoreExpr
arg1 CoreExpr -> CoreExpr -> CoreExpr
`sub` CoreExpr
y))

      -- (l1 - x) - y ==> l1 - (x + y)
      (NumOps -> CoreExpr -> Maybe (CoreExpr, CoreExpr)
is_sub NumOps
num_ops -> Just (L Integer
l1,CoreExpr
x), CoreExpr
_)
         -> forall a. a -> Maybe a
Just (Integer -> CoreExpr
mkL Integer
l1 CoreExpr -> CoreExpr -> CoreExpr
`sub` (CoreExpr
x CoreExpr -> CoreExpr -> CoreExpr
`add` CoreExpr
arg2))

      -- (x - l1) - y ==> (x - y) - l1
      (NumOps -> CoreExpr -> Maybe (CoreExpr, CoreExpr)
is_sub NumOps
num_ops -> Just (CoreExpr
x,L Integer
l1), CoreExpr
_)
         -> forall a. a -> Maybe a
Just ((CoreExpr
x CoreExpr -> CoreExpr -> CoreExpr
`sub` CoreExpr
arg2) CoreExpr -> CoreExpr -> CoreExpr
`sub` Integer -> CoreExpr
mkL Integer
l1)

      (CoreExpr, CoreExpr)
_ -> forall a. Maybe a
Nothing
   where
      mkL :: Integer -> CoreExpr
mkL = forall b. Literal -> Expr b
Lit forall b c a. (b -> c) -> (a -> b) -> a -> c
. Platform -> NumOps -> Integer -> Literal
mkNumLiteral Platform
platform NumOps
num_ops
      add :: CoreExpr -> CoreExpr -> CoreExpr
add CoreExpr
x CoreExpr
y = CoreExpr -> PrimOp -> CoreExpr -> CoreExpr
BinOpApp CoreExpr
x (NumOps -> PrimOp
numAdd NumOps
num_ops) CoreExpr
y
      sub :: CoreExpr -> CoreExpr -> CoreExpr
sub CoreExpr
x CoreExpr
y = CoreExpr -> PrimOp -> CoreExpr -> CoreExpr
BinOpApp CoreExpr
x (NumOps -> PrimOp
numSub NumOps
num_ops) CoreExpr
y
      mul :: CoreExpr -> CoreExpr -> CoreExpr
mul CoreExpr
x CoreExpr
y = CoreExpr -> PrimOp -> CoreExpr -> CoreExpr
BinOpApp CoreExpr
x (NumOps -> PrimOp
numMul NumOps
num_ops) CoreExpr
y

mulFoldingRules' :: Platform -> CoreExpr -> CoreExpr -> NumOps -> Maybe CoreExpr
mulFoldingRules' :: Platform -> CoreExpr -> CoreExpr -> NumOps -> Maybe CoreExpr
mulFoldingRules' Platform
platform CoreExpr
arg1 CoreExpr
arg2 NumOps
num_ops = case (CoreExpr
arg1,CoreExpr
arg2) of
   -- l1 * (l2 * x) ==> (l1*l2) * x
   (L Integer
l1, NumOps -> CoreExpr -> Maybe (Integer, CoreExpr)
is_lit_mul NumOps
num_ops -> Just (Integer
l2,CoreExpr
x))
      -> forall a. a -> Maybe a
Just (Integer -> CoreExpr
mkL (Integer
l1forall a. Num a => a -> a -> a
*Integer
l2) CoreExpr -> CoreExpr -> CoreExpr
`mul` CoreExpr
x)

   -- l1 * (l2 + x) ==> (l1*l2) + (l1 * x)
   (L Integer
l1, NumOps -> CoreExpr -> Maybe (Integer, CoreExpr)
is_lit_add NumOps
num_ops -> Just (Integer
l2,CoreExpr
x))
      -> forall a. a -> Maybe a
Just (Integer -> CoreExpr
mkL (Integer
l1forall a. Num a => a -> a -> a
*Integer
l2) CoreExpr -> CoreExpr -> CoreExpr
`add` (CoreExpr
arg1 CoreExpr -> CoreExpr -> CoreExpr
`mul` CoreExpr
x))

   -- l1 * (l2 - x) ==> (l1*l2) - (l1 * x)
   (L Integer
l1, NumOps -> CoreExpr -> Maybe (CoreExpr, CoreExpr)
is_sub NumOps
num_ops -> Just (L Integer
l2,CoreExpr
x))
      -> forall a. a -> Maybe a
Just (Integer -> CoreExpr
mkL (Integer
l1forall a. Num a => a -> a -> a
*Integer
l2) CoreExpr -> CoreExpr -> CoreExpr
`sub` (CoreExpr
arg1 CoreExpr -> CoreExpr -> CoreExpr
`mul` CoreExpr
x))

   -- l1 * (x - l2) ==> (l1 * x) - (l1*l2)
   (L Integer
l1, NumOps -> CoreExpr -> Maybe (CoreExpr, CoreExpr)
is_sub NumOps
num_ops -> Just (CoreExpr
x, L Integer
l2))
      -> forall a. a -> Maybe a
Just ((CoreExpr
arg1 CoreExpr -> CoreExpr -> CoreExpr
`mul` CoreExpr
x) CoreExpr -> CoreExpr -> CoreExpr
`sub` Integer -> CoreExpr
mkL (Integer
l1forall a. Num a => a -> a -> a
*Integer
l2))

   -- (l1 * x) * (l2 * y) ==> (l1*l2) * (x * y)
   (NumOps -> CoreExpr -> Maybe (Integer, CoreExpr)
is_lit_mul NumOps
num_ops -> Just (Integer
l1,CoreExpr
x), NumOps -> CoreExpr -> Maybe (Integer, CoreExpr)
is_lit_mul NumOps
num_ops -> Just (Integer
l2,CoreExpr
y))
      -> forall a. a -> Maybe a
Just (Integer -> CoreExpr
mkL (Integer
l1forall a. Num a => a -> a -> a
*Integer
l2) CoreExpr -> CoreExpr -> CoreExpr
`mul` (CoreExpr
x CoreExpr -> CoreExpr -> CoreExpr
`mul` CoreExpr
y))

   (CoreExpr, CoreExpr)
_ -> forall a. Maybe a
Nothing
   where
      mkL :: Integer -> CoreExpr
mkL = forall b. Literal -> Expr b
Lit forall b c a. (b -> c) -> (a -> b) -> a -> c
. Platform -> NumOps -> Integer -> Literal
mkNumLiteral Platform
platform NumOps
num_ops
      add :: CoreExpr -> CoreExpr -> CoreExpr
add CoreExpr
x CoreExpr
y = CoreExpr -> PrimOp -> CoreExpr -> CoreExpr
BinOpApp CoreExpr
x (NumOps -> PrimOp
numAdd NumOps
num_ops) CoreExpr
y
      sub :: CoreExpr -> CoreExpr -> CoreExpr
sub CoreExpr
x CoreExpr
y = CoreExpr -> PrimOp -> CoreExpr -> CoreExpr
BinOpApp CoreExpr
x (NumOps -> PrimOp
numSub NumOps
num_ops) CoreExpr
y
      mul :: CoreExpr -> CoreExpr -> CoreExpr
mul CoreExpr
x CoreExpr
y = CoreExpr -> PrimOp -> CoreExpr -> CoreExpr
BinOpApp CoreExpr
x (NumOps -> PrimOp
numMul NumOps
num_ops) CoreExpr
y

is_op :: PrimOp -> CoreExpr -> Maybe (Arg CoreBndr, Arg CoreBndr)
is_op :: PrimOp -> CoreExpr -> Maybe (CoreExpr, CoreExpr)
is_op PrimOp
op CoreExpr
e = case CoreExpr
e of
 BinOpApp CoreExpr
x PrimOp
op' CoreExpr
y | PrimOp
op forall a. Eq a => a -> a -> Bool
== PrimOp
op' -> forall a. a -> Maybe a
Just (CoreExpr
x,CoreExpr
y)
 CoreExpr
_                            -> forall a. Maybe a
Nothing

is_add, is_sub, is_mul :: NumOps -> CoreExpr -> Maybe (Arg CoreBndr, Arg CoreBndr)
is_add :: NumOps -> CoreExpr -> Maybe (CoreExpr, CoreExpr)
is_add NumOps
num_ops = PrimOp -> CoreExpr -> Maybe (CoreExpr, CoreExpr)
is_op (NumOps -> PrimOp
numAdd NumOps
num_ops)
is_sub :: NumOps -> CoreExpr -> Maybe (CoreExpr, CoreExpr)
is_sub NumOps
num_ops = PrimOp -> CoreExpr -> Maybe (CoreExpr, CoreExpr)
is_op (NumOps -> PrimOp
numSub NumOps
num_ops)
is_mul :: NumOps -> CoreExpr -> Maybe (CoreExpr, CoreExpr)
is_mul NumOps
num_ops = PrimOp -> CoreExpr -> Maybe (CoreExpr, CoreExpr)
is_op (NumOps -> PrimOp
numMul NumOps
num_ops)

-- match addition with a literal (handles commutativity)
is_lit_add :: NumOps -> CoreExpr -> Maybe (Integer, Arg CoreBndr)
is_lit_add :: NumOps -> CoreExpr -> Maybe (Integer, CoreExpr)
is_lit_add NumOps
num_ops CoreExpr
e = case NumOps -> CoreExpr -> Maybe (CoreExpr, CoreExpr)
is_add NumOps
num_ops CoreExpr
e of
   Just (L Integer
l, CoreExpr
x  ) -> forall a. a -> Maybe a
Just (Integer
l,CoreExpr
x)
   Just (CoreExpr
x  , L Integer
l) -> forall a. a -> Maybe a
Just (Integer
l,CoreExpr
x)
   Maybe (CoreExpr, CoreExpr)
_               -> forall a. Maybe a
Nothing

-- match multiplication with a literal (handles commutativity)
is_lit_mul :: NumOps -> CoreExpr -> Maybe (Integer, Arg CoreBndr)
is_lit_mul :: NumOps -> CoreExpr -> Maybe (Integer, CoreExpr)
is_lit_mul NumOps
num_ops CoreExpr
e = case NumOps -> CoreExpr -> Maybe (CoreExpr, CoreExpr)
is_mul NumOps
num_ops CoreExpr
e of
   Just (L Integer
l, CoreExpr
x  ) -> forall a. a -> Maybe a
Just (Integer
l,CoreExpr
x)
   Just (CoreExpr
x  , L Integer
l) -> forall a. a -> Maybe a
Just (Integer
l,CoreExpr
x)
   Maybe (CoreExpr, CoreExpr)
_               -> forall a. Maybe a
Nothing

-- match given "x": return 1
-- match "lit * x": return lit value (handles commutativity)
is_expr_mul :: NumOps -> Expr CoreBndr -> Expr CoreBndr -> Maybe Integer
is_expr_mul :: NumOps -> CoreExpr -> CoreExpr -> Maybe Integer
is_expr_mul NumOps
num_ops CoreExpr
x CoreExpr
e = if
   | CoreExpr
x forall b. Expr b -> Expr b -> Bool
`cheapEqExpr` CoreExpr
e
   -> forall a. a -> Maybe a
Just Integer
1
   | Just (Integer
k,CoreExpr
x') <- NumOps -> CoreExpr -> Maybe (Integer, CoreExpr)
is_lit_mul NumOps
num_ops CoreExpr
e
   , CoreExpr
x forall b. Expr b -> Expr b -> Bool
`cheapEqExpr` CoreExpr
x'
   -> forall (m :: * -> *) a. Monad m => a -> m a
return Integer
k
   | Bool
otherwise
   -> forall a. Maybe a
Nothing


-- | Match the application of a binary primop
pattern BinOpApp :: Arg CoreBndr -> PrimOp -> Arg CoreBndr -> CoreExpr
pattern $mBinOpApp :: forall {r}.
CoreExpr
-> (CoreExpr -> PrimOp -> CoreExpr -> r) -> ((# #) -> r) -> r
$bBinOpApp :: CoreExpr -> PrimOp -> CoreExpr -> CoreExpr
BinOpApp x op y = OpVal op `App` x `App` y

-- | Match a primop
pattern OpVal:: PrimOp  -> Arg CoreBndr
pattern $mOpVal :: forall {r}. CoreExpr -> (PrimOp -> r) -> ((# #) -> r) -> r
$bOpVal :: PrimOp -> CoreExpr
OpVal op <- Var (isPrimOpId_maybe -> Just op) where
   OpVal PrimOp
op = forall b. Id -> Expr b
Var (PrimOp -> Id
mkPrimOpId PrimOp
op)

-- | Match a literal
pattern L :: Integer -> Arg CoreBndr
pattern $mL :: forall {r}. CoreExpr -> (Integer -> r) -> ((# #) -> r) -> r
L i <- Lit (LitNumber _ i)

-- | Explicit "type-class"-like dictionary for numeric primops
data NumOps = NumOps
   { NumOps -> PrimOp
numAdd     :: !PrimOp     -- ^ Add two numbers
   , NumOps -> PrimOp
numSub     :: !PrimOp     -- ^ Sub two numbers
   , NumOps -> PrimOp
numMul     :: !PrimOp     -- ^ Multiply two numbers
   , NumOps -> LitNumType
numLitType :: !LitNumType -- ^ Literal type
   }

-- | Create a numeric literal
mkNumLiteral :: Platform -> NumOps -> Integer -> Literal
mkNumLiteral :: Platform -> NumOps -> Integer -> Literal
mkNumLiteral Platform
platform NumOps
ops Integer
i = Platform -> LitNumType -> Integer -> Literal
mkLitNumberWrap Platform
platform (NumOps -> LitNumType
numLitType NumOps
ops) Integer
i

int8Ops :: NumOps
int8Ops :: NumOps
int8Ops = NumOps
   { numAdd :: PrimOp
numAdd     = PrimOp
Int8AddOp
   , numSub :: PrimOp
numSub     = PrimOp
Int8SubOp
   , numMul :: PrimOp
numMul     = PrimOp
Int8MulOp
   , numLitType :: LitNumType
numLitType = LitNumType
LitNumInt8
   }

word8Ops :: NumOps
word8Ops :: NumOps
word8Ops = NumOps
   { numAdd :: PrimOp
numAdd     = PrimOp
Word8AddOp
   , numSub :: PrimOp
numSub     = PrimOp
Word8SubOp
   , numMul :: PrimOp
numMul     = PrimOp
Word8MulOp
   , numLitType :: LitNumType
numLitType = LitNumType
LitNumWord8
   }

int16Ops :: NumOps
int16Ops :: NumOps
int16Ops = NumOps
   { numAdd :: PrimOp
numAdd     = PrimOp
Int16AddOp
   , numSub :: PrimOp
numSub     = PrimOp
Int16SubOp
   , numMul :: PrimOp
numMul     = PrimOp
Int16MulOp
   , numLitType :: LitNumType
numLitType = LitNumType
LitNumInt16
   }

word16Ops :: NumOps
word16Ops :: NumOps
word16Ops = NumOps
   { numAdd :: PrimOp
numAdd     = PrimOp
Word16AddOp
   , numSub :: PrimOp
numSub     = PrimOp
Word16SubOp
   , numMul :: PrimOp
numMul     = PrimOp
Word16MulOp
   , numLitType :: LitNumType
numLitType = LitNumType
LitNumWord16
   }

int32Ops :: NumOps
int32Ops :: NumOps
int32Ops = NumOps
   { numAdd :: PrimOp
numAdd     = PrimOp
Int32AddOp
   , numSub :: PrimOp
numSub     = PrimOp
Int32SubOp
   , numMul :: PrimOp
numMul     = PrimOp
Int32MulOp
   , numLitType :: LitNumType
numLitType = LitNumType
LitNumInt32
   }

word32Ops :: NumOps
word32Ops :: NumOps
word32Ops = NumOps
   { numAdd :: PrimOp
numAdd     = PrimOp
Word32AddOp
   , numSub :: PrimOp
numSub     = PrimOp
Word32SubOp
   , numMul :: PrimOp
numMul     = PrimOp
Word32MulOp
   , numLitType :: LitNumType
numLitType = LitNumType
LitNumWord32
   }

#if WORD_SIZE_IN_BITS < 64
int64Ops :: NumOps
int64Ops = NumOps
   { numAdd     = Int64AddOp
   , numSub     = Int64SubOp
   , numMul     = Int64MulOp
   , numLitType = LitNumInt64
   }

word64Ops :: NumOps
word64Ops = NumOps
   { numAdd     = Word64AddOp
   , numSub     = Word64SubOp
   , numMul     = Word64MulOp
   , numLitType = LitNumWord64
   }
#endif

intOps :: NumOps
intOps :: NumOps
intOps = NumOps
   { numAdd :: PrimOp
numAdd     = PrimOp
IntAddOp
   , numSub :: PrimOp
numSub     = PrimOp
IntSubOp
   , numMul :: PrimOp
numMul     = PrimOp
IntMulOp
   , numLitType :: LitNumType
numLitType = LitNumType
LitNumInt
   }

wordOps :: NumOps
wordOps :: NumOps
wordOps = NumOps
   { numAdd :: PrimOp
numAdd     = PrimOp
WordAddOp
   , numSub :: PrimOp
numSub     = PrimOp
WordSubOp
   , numMul :: PrimOp
numMul     = PrimOp
WordMulOp
   , numLitType :: LitNumType
numLitType = LitNumType
LitNumWord
   }

--------------------------------------------------------
-- Constant folding through case-expressions
--
-- cf Scrutinee Constant Folding in simplCore/GHC.Core.Opt.Simplify.Utils
--------------------------------------------------------

-- | Match the scrutinee of a case and potentially return a new scrutinee and a
-- function to apply to each literal alternative.
caseRules :: Platform
          -> CoreExpr                       -- Scrutinee
          -> Maybe ( CoreExpr               -- New scrutinee
                   , AltCon -> Maybe AltCon -- How to fix up the alt pattern
                                            --   Nothing <=> Unreachable
                                            -- See Note [Unreachable caseRules alternatives]
                   , Id -> CoreExpr)        -- How to reconstruct the original scrutinee
                                            -- from the new case-binder
-- e.g  case e of b {
--         ...;
--         con bs -> rhs;
--         ... }
--  ==>
--      case e' of b' {
--         ...;
--         fixup_altcon[con] bs -> let b = mk_orig[b] in rhs;
--         ... }

caseRules :: Platform
-> CoreExpr
-> Maybe (CoreExpr, AltCon -> Maybe AltCon, Id -> CoreExpr)
caseRules Platform
platform (App (App (Var Id
f) CoreExpr
v) (Lit Literal
l))   -- v `op` x#
  | Just PrimOp
op <- Id -> Maybe PrimOp
isPrimOpId_maybe Id
f
  , LitNumber LitNumType
_ Integer
x <- Literal
l
  , Just Integer -> Integer
adjust_lit <- PrimOp -> Integer -> Maybe (Integer -> Integer)
adjustDyadicRight PrimOp
op Integer
x
  = forall a. a -> Maybe a
Just (CoreExpr
v, Platform -> (Integer -> Integer) -> AltCon -> Maybe AltCon
tx_lit_con Platform
platform Integer -> Integer
adjust_lit
           , \Id
v -> (forall b. Expr b -> Expr b -> Expr b
App (forall b. Expr b -> Expr b -> Expr b
App (forall b. Id -> Expr b
Var Id
f) (forall b. Id -> Expr b
Var Id
v)) (forall b. Literal -> Expr b
Lit Literal
l)))

caseRules Platform
platform (App (App (Var Id
f) (Lit Literal
l)) CoreExpr
v)   -- x# `op` v
  | Just PrimOp
op <- Id -> Maybe PrimOp
isPrimOpId_maybe Id
f
  , LitNumber LitNumType
_ Integer
x <- Literal
l
  , Just Integer -> Integer
adjust_lit <- Integer -> PrimOp -> Maybe (Integer -> Integer)
adjustDyadicLeft Integer
x PrimOp
op
  = forall a. a -> Maybe a
Just (CoreExpr
v, Platform -> (Integer -> Integer) -> AltCon -> Maybe AltCon
tx_lit_con Platform
platform Integer -> Integer
adjust_lit
           , \Id
v -> (forall b. Expr b -> Expr b -> Expr b
App (forall b. Expr b -> Expr b -> Expr b
App (forall b. Id -> Expr b
Var Id
f) (forall b. Literal -> Expr b
Lit Literal
l)) (forall b. Id -> Expr b
Var Id
v)))


caseRules Platform
platform (App (Var Id
f) CoreExpr
v              )   -- op v
  | Just PrimOp
op <- Id -> Maybe PrimOp
isPrimOpId_maybe Id
f
  , Just Integer -> Integer
adjust_lit <- PrimOp -> Maybe (Integer -> Integer)
adjustUnary PrimOp
op
  = forall a. a -> Maybe a
Just (CoreExpr
v, Platform -> (Integer -> Integer) -> AltCon -> Maybe AltCon
tx_lit_con Platform
platform Integer -> Integer
adjust_lit
           , \Id
v -> forall b. Expr b -> Expr b -> Expr b
App (forall b. Id -> Expr b
Var Id
f) (forall b. Id -> Expr b
Var Id
v))

-- See Note [caseRules for tagToEnum]
caseRules Platform
platform (App (App (Var Id
f) CoreExpr
type_arg) CoreExpr
v)
  | Just PrimOp
TagToEnumOp <- Id -> Maybe PrimOp
isPrimOpId_maybe Id
f
  = forall a. a -> Maybe a
Just (CoreExpr
v, Platform -> AltCon -> Maybe AltCon
tx_con_tte Platform
platform
           , \Id
v -> (forall b. Expr b -> Expr b -> Expr b
App (forall b. Expr b -> Expr b -> Expr b
App (forall b. Id -> Expr b
Var Id
f) CoreExpr
type_arg) (forall b. Id -> Expr b
Var Id
v)))

-- See Note [caseRules for dataToTag]
caseRules Platform
_ (App (App (Var Id
f) (Type Type
ty)) CoreExpr
v)       -- dataToTag x
  | Just PrimOp
DataToTagOp <- Id -> Maybe PrimOp
isPrimOpId_maybe Id
f
  , Just (TyCon
tc, [Type]
_) <- HasCallStack => Type -> Maybe (TyCon, [Type])
tcSplitTyConApp_maybe Type
ty
  , TyCon -> Bool
isAlgTyCon TyCon
tc
  = forall a. a -> Maybe a
Just (CoreExpr
v, Type -> AltCon -> Maybe AltCon
tx_con_dtt Type
ty
           , \Id
v -> forall b. Expr b -> Expr b -> Expr b
App (forall b. Expr b -> Expr b -> Expr b
App (forall b. Id -> Expr b
Var Id
f) (forall b. Type -> Expr b
Type Type
ty)) (forall b. Id -> Expr b
Var Id
v))

caseRules Platform
_ CoreExpr
_ = forall a. Maybe a
Nothing


tx_lit_con :: Platform -> (Integer -> Integer) -> AltCon -> Maybe AltCon
tx_lit_con :: Platform -> (Integer -> Integer) -> AltCon -> Maybe AltCon
tx_lit_con Platform
_        Integer -> Integer
_      AltCon
DEFAULT    = forall a. a -> Maybe a
Just AltCon
DEFAULT
tx_lit_con Platform
platform Integer -> Integer
adjust (LitAlt Literal
l) = forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ Literal -> AltCon
LitAlt (Platform -> (Integer -> Integer) -> Literal -> Literal
mapLitValue Platform
platform Integer -> Integer
adjust Literal
l)
tx_lit_con Platform
_        Integer -> Integer
_      AltCon
alt        = forall a. HasCallStack => String -> SDoc -> a
pprPanic String
"caseRules" (forall a. Outputable a => a -> SDoc
ppr AltCon
alt)
   -- NB: mapLitValue uses mkLitIntWrap etc, to ensure that the
   -- literal alternatives remain in Word/Int target ranges
   -- (See Note [Word/Int underflow/overflow] in GHC.Types.Literal and #13172).

adjustDyadicRight :: PrimOp -> Integer -> Maybe (Integer -> Integer)
-- Given (x `op` lit) return a function 'f' s.t.  f (x `op` lit) = x
adjustDyadicRight :: PrimOp -> Integer -> Maybe (Integer -> Integer)
adjustDyadicRight PrimOp
op Integer
lit
  = case PrimOp
op of
         PrimOp
WordAddOp -> forall a. a -> Maybe a
Just (\Integer
y -> Integer
yforall a. Num a => a -> a -> a
-Integer
lit      )
         PrimOp
IntAddOp  -> forall a. a -> Maybe a
Just (\Integer
y -> Integer
yforall a. Num a => a -> a -> a
-Integer
lit      )
         PrimOp
WordSubOp -> forall a. a -> Maybe a
Just (\Integer
y -> Integer
yforall a. Num a => a -> a -> a
+Integer
lit      )
         PrimOp
IntSubOp  -> forall a. a -> Maybe a
Just (\Integer
y -> Integer
yforall a. Num a => a -> a -> a
+Integer
lit      )
         PrimOp
WordXorOp -> forall a. a -> Maybe a
Just (\Integer
y -> Integer
y forall a. Bits a => a -> a -> a
`xor` Integer
lit)
         PrimOp
IntXorOp  -> forall a. a -> Maybe a
Just (\Integer
y -> Integer
y forall a. Bits a => a -> a -> a
`xor` Integer
lit)
         PrimOp
_         -> forall a. Maybe a
Nothing

adjustDyadicLeft :: Integer -> PrimOp -> Maybe (Integer -> Integer)
-- Given (lit `op` x) return a function 'f' s.t.  f (lit `op` x) = x
adjustDyadicLeft :: Integer -> PrimOp -> Maybe (Integer -> Integer)
adjustDyadicLeft Integer
lit PrimOp
op
  = case PrimOp
op of
         PrimOp
WordAddOp -> forall a. a -> Maybe a
Just (\Integer
y -> Integer
yforall a. Num a => a -> a -> a
-Integer
lit      )
         PrimOp
IntAddOp  -> forall a. a -> Maybe a
Just (\Integer
y -> Integer
yforall a. Num a => a -> a -> a
-Integer
lit      )
         PrimOp
WordSubOp -> forall a. a -> Maybe a
Just (\Integer
y -> Integer
litforall a. Num a => a -> a -> a
-Integer
y      )
         PrimOp
IntSubOp  -> forall a. a -> Maybe a
Just (\Integer
y -> Integer
litforall a. Num a => a -> a -> a
-Integer
y      )
         PrimOp
WordXorOp -> forall a. a -> Maybe a
Just (\Integer
y -> Integer
y forall a. Bits a => a -> a -> a
`xor` Integer
lit)
         PrimOp
IntXorOp  -> forall a. a -> Maybe a
Just (\Integer
y -> Integer
y forall a. Bits a => a -> a -> a
`xor` Integer
lit)
         PrimOp
_         -> forall a. Maybe a
Nothing


adjustUnary :: PrimOp -> Maybe (Integer -> Integer)
-- Given (op x) return a function 'f' s.t.  f (op x) = x
adjustUnary :: PrimOp -> Maybe (Integer -> Integer)
adjustUnary PrimOp
op
  = case PrimOp
op of
         PrimOp
WordNotOp -> forall a. a -> Maybe a
Just (\Integer
y -> forall a. Bits a => a -> a
complement Integer
y)
         PrimOp
IntNotOp  -> forall a. a -> Maybe a
Just (\Integer
y -> forall a. Bits a => a -> a
complement Integer
y)
         PrimOp
IntNegOp  -> forall a. a -> Maybe a
Just (\Integer
y -> forall a. Num a => a -> a
negate Integer
y    )
         PrimOp
_         -> forall a. Maybe a
Nothing

tx_con_tte :: Platform -> AltCon -> Maybe AltCon
tx_con_tte :: Platform -> AltCon -> Maybe AltCon
tx_con_tte Platform
_        AltCon
DEFAULT         = forall a. a -> Maybe a
Just AltCon
DEFAULT
tx_con_tte Platform
_        alt :: AltCon
alt@(LitAlt {}) = forall a. HasCallStack => String -> SDoc -> a
pprPanic String
"caseRules" (forall a. Outputable a => a -> SDoc
ppr AltCon
alt)
tx_con_tte Platform
platform (DataAlt DataCon
dc)  -- See Note [caseRules for tagToEnum]
  = forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ Literal -> AltCon
LitAlt forall a b. (a -> b) -> a -> b
$ Platform -> Integer -> Literal
mkLitInt Platform
platform forall a b. (a -> b) -> a -> b
$ forall a. Integral a => a -> Integer
toInteger forall a b. (a -> b) -> a -> b
$ DataCon -> ConTagZ
dataConTagZ DataCon
dc

tx_con_dtt :: Type -> AltCon -> Maybe AltCon
tx_con_dtt :: Type -> AltCon -> Maybe AltCon
tx_con_dtt Type
_  AltCon
DEFAULT = forall a. a -> Maybe a
Just AltCon
DEFAULT
tx_con_dtt Type
ty (LitAlt (LitNumber LitNumType
LitNumInt Integer
i))
   | ConTagZ
tag forall a. Ord a => a -> a -> Bool
>= ConTagZ
0
   , ConTagZ
tag forall a. Ord a => a -> a -> Bool
< ConTagZ
n_data_cons
   = forall a. a -> Maybe a
Just (DataCon -> AltCon
DataAlt ([DataCon]
data_cons forall a. [a] -> ConTagZ -> a
!! ConTagZ
tag))   -- tag is zero-indexed, as is (!!)
   | Bool
otherwise
   = forall a. Maybe a
Nothing
   where
     tag :: ConTagZ
tag         = forall a. Num a => Integer -> a
fromInteger Integer
i :: ConTagZ
     tc :: TyCon
tc          = Type -> TyCon
tyConAppTyCon Type
ty
     n_data_cons :: ConTagZ
n_data_cons = TyCon -> ConTagZ
tyConFamilySize TyCon
tc
     data_cons :: [DataCon]
data_cons   = TyCon -> [DataCon]
tyConDataCons TyCon
tc

tx_con_dtt Type
_ AltCon
alt = forall a. HasCallStack => String -> SDoc -> a
pprPanic String
"caseRules" (forall a. Outputable a => a -> SDoc
ppr AltCon
alt)


{- Note [caseRules for tagToEnum]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
We want to transform
   case tagToEnum x of
     False -> e1
     True  -> e2
into
   case x of
     0# -> e1
     1# -> e2

This rule eliminates a lot of boilerplate. For
  if (x>y) then e2 else e1
we generate
  case tagToEnum (x ># y) of
    False -> e1
    True  -> e2
and it is nice to then get rid of the tagToEnum.

Beware (#14768): avoid the temptation to map constructor 0 to
DEFAULT, in the hope of getting this
  case (x ># y) of
    DEFAULT -> e1
    1#      -> e2
That fails utterly in the case of
   data Colour = Red | Green | Blue
   case tagToEnum x of
      DEFAULT -> e1
      Red     -> e2

We don't want to get this!
   case x of
      DEFAULT -> e1
      DEFAULT -> e2

Instead, we deal with turning one branch into DEFAULT in GHC.Core.Opt.Simplify.Utils
(add_default in mkCase3).

Note [caseRules for dataToTag]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
See also Note [dataToTag#] in primpops.txt.pp

We want to transform
  case dataToTag x of
    DEFAULT -> e1
    1# -> e2
into
  case x of
    DEFAULT -> e1
    (:) _ _ -> e2

Note the need for some wildcard binders in
the 'cons' case.

For the time, we only apply this transformation when the type of `x` is a type
headed by a normal tycon. In particular, we do not apply this in the case of a
data family tycon, since that would require carefully applying coercion(s)
between the data family and the data family instance's representation type,
which caseRules isn't currently engineered to handle (#14680).

Note [Unreachable caseRules alternatives]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Take care if we see something like
  case dataToTag x of
    DEFAULT -> e1
    -1# -> e2
    100 -> e3
because there isn't a data constructor with tag -1 or 100. In this case the
out-of-range alternative is dead code -- we know the range of tags for x.

Hence caseRules returns (AltCon -> Maybe AltCon), with Nothing indicating
an alternative that is unreachable.

You may wonder how this can happen: check out #15436.


Note [Optimising conversions between numeric types]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Converting between numeric types is very common in Haskell codes.  Suppose that
we have N inter-convertible numeric types (Word, Word8, Int, Integer, etc.).

- We don't want to have to use one conversion function per pair of types as that
would require N^2 functions: wordToWord8, wordToInt, wordToInteger...

- The following kind of class would allow us to have a single conversion
function at the price of N^2 instances and of the use of MultiParamTypeClasses
extension.

    class Convert a b where
      convert :: a -> b

What we do instead is that we use the Integer type (signed, unbounded) as a
passthrough type to perform every conversion. Hence we only need to define two
functions per numeric type:

  class Integral a where
    toInteger :: a -> Integer

  class Num a where
    fromInteger :: Integer -> a

These classes have a single parameter and can be derived automatically (e.g. for
newtypes). So we don't even have to define 2*N instances.

fromIntegral
------------

We can now define a generic conversion function:

  -- in the Prelude
  fromIntegral :: (Integral a, Num b) => a -> b
  fromIntegral = fromInteger . toInteger

The trouble with this approach is that performance might be terrible. E.g.
converting an Int into a Word, which is a no-op at the machine level, becomes
costly when performed via `fromIntegral` because an Integer has to be allocated.

To alleviate this:

- first `fromIntegral` was specialized (SPECIALIZE pragma). However it would
need N^2 pragmas to cover every case and it wouldn't cover user defined numeric
types which don't belong to base.

- while writing this note I discovered that we have a `-fwarn-identities` warning
to detect useless conversions (since 0656c72a8f):

  > fromIntegral (1 :: Int) :: Int

  <interactive>:3:21: warning: [-Widentities]
      Call of fromIntegral :: Int -> Int
        can probably be omitted

- but more importantly, many rules were added (e.g. in e0c787c10f):

    "fromIntegral/Int8->Int8" fromIntegral = id :: Int8 -> Int8
    "fromIntegral/a->Int8"    fromIntegral = \x -> case fromIntegral x of I# x# -> I8# (intToInt8# x#)
    "fromIntegral/Int8->a"    fromIntegral = \(I8# x#) -> fromIntegral (I# x#)

  The idea was to ensure that only cheap conversions ended up being used. E.g.:

      foo :: Int8 --> {- Integer -> -} -> Word8
      foo = fromIntegral

    ====> {Some fromIntegral rule for Int8}

      foo :: Int8 -> {- Int -> Integer -} -> Word8
      foo = fromIntegral . int8ToInt

    ====> {Some fromIntegral rule for Word8}

      foo :: Int8 -> {- Int -> Integer -> Word -} -> Word8
      foo = wordToWord8 . fromIntegral . int8ToInt

    ====> {Some fromIntegral rule for Int/Word}

      foo :: Int8 -> {- Int -> Word -} -> Word8
      foo = wordToWord8 . intToWord . int8ToInt
      -- not passing through Integer anymore!


It worked but there were still some issues with this approach:

1. These rules only work for `fromIntegral`. If we wanted to define our own
   similar function (e.g. using other type-classes), we would also have to redefine
   all the rules to get similar performance.

2. `fromIntegral` had to be marked `NOINLINE [1]`:
    - NOINLINE to allow rules to match
    - [1] to allow inlining in later phases to avoid incurring a function call
      overhead for such a trivial operation

   Users of the function had to be careful because a simple helper without an
   INLINE pragma like:

      toInt :: Integral a => a -> Int
      toInt = fromIntegral

   has the following unfolding:

      toInt = integerToInt . toInteger

   which doesn't mention `fromIntegral` anymore. Hence `fromIntegral` rules
   wouldn't be triggered for any user of `toInt`. For this reason, we also have
   a bunch of rules for bignum primitives such as `integerToInt`.

3. These rewrite rules are tedious to write and error-prone (cf #19345).


For these reasons, it is simpler to only rely on built-in rewrite rules for
bignum primitives. There aren't so many conversion primitives:
  - Natural <-> Word
  - Integer <-> Int/Word/Natural (+ Int64/Word64 on 32-bit arch)

All the built-in "small_passthrough_*" rules are used to avoid passing through
Integer/Natural. We now always inline `fromIntegral`.

-}