feldspar-language-0.5.0.1: Feldspar/Core/Constructs/Binding.hs
--
-- Copyright (c) 2009-2011, ERICSSON AB
-- All rights reserved.
--
-- Redistribution and use in source and binary forms, with or without
-- modification, are permitted provided that the following conditions are met:
--
-- * Redistributions of source code must retain the above copyright notice,
-- this list of conditions and the following disclaimer.
-- * Redistributions in binary form must reproduce the above copyright
-- notice, this list of conditions and the following disclaimer in the
-- documentation and/or other materials provided with the distribution.
-- * Neither the name of the ERICSSON AB nor the names of its contributors
-- may be used to endorse or promote products derived from this software
-- without specific prior written permission.
--
-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-- DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
-- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
-- SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
-- CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-- OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--
{-# LANGUAGE UndecidableInstances #-}
-- | Interpretation of binding constructs
module Feldspar.Core.Constructs.Binding
( module Language.Syntactic.Constructs.Binding
, optimizeLambda
, optimizeFunction
, optimizeFunctionFix
) where
import Control.Monad.Reader
import Data.Maybe
import Data.Map
import Data.Typeable (Typeable, gcast)
import Data.Lens.Common
import Data.Proxy
import Language.Syntactic
import Language.Syntactic.Constructs.Binding
import Feldspar.Lattice
import Feldspar.Core.Types
import Feldspar.Core.Interpretation
instance Sharable (Variable TypeCtx)
-- Will not be shared anyway, because it's a terminal
instance Sharable (Lambda TypeCtx)
where
sharable _ = False
instance Sharable (Let TypeCtx TypeCtx)
optimizeLambda :: (Lambda TypeCtx :<: dom, Optimize dom dom)
=> (ASTF dom b -> Opt (ASTF (Decor Info dom) b)) -- ^ Optimization of the body
-> Info a
-> Lambda TypeCtx (b :-> Full (a -> b))
-> Args (AST dom) (b :-> Full (a -> b))
-> Opt (ASTF (Decor Info dom) (a -> b))
optimizeLambda opt info lam@(Lambda v) (body :* Nil) = do
body' <- localVar v info $ opt body
constructFeatUnOpt lam (body' :* Nil)
-- | Assumes that the expression is a 'Lambda'
optimizeFunction :: (Lambda TypeCtx :<: dom, Optimize dom dom)
=> (ASTF dom b -> Opt (ASTF (Decor Info dom) b)) -- ^ Optimization of the body
-> Info a
-> (ASTF dom (a -> b) -> Opt (ASTF (Decor Info dom) (a -> b)))
optimizeFunction opt info (lam :$ body)
| Just (Lambda v) <- prjCtx typeCtx lam
= optimizeLambda opt info (Lambda v) (body :* Nil)
optimizeFunBody :: (Lambda TypeCtx :<: dom, Optimize dom dom, Typeable a)
=> (ASTF dom a -> Opt (ASTF (Decor Info dom) a)) -- ^ Optimization of the body
-> Env -- ^ Environment (instead of using 'Opt')
-> VarId -- ^ Bound variable
-> ASTF dom a -- ^ Body
-> Info a -- ^ 'Info' of bound variable
-> ASTF (Decor Info dom) a
optimizeFunBody opt env v body info =
flip runReader env $ localVar v info $ opt body
-- | Assumes that the expression is a 'Lambda'
optimizeFunctionFix
:: forall dom a
. (Lambda TypeCtx :<: dom, Optimize dom dom, Type a)
=> (ASTF dom a -> Opt (ASTF (Decor Info dom) a)) -- ^ Optimization of the body
-> Info a
-> (ASTF dom (a -> a) -> Opt (ASTF (Decor Info dom) (a -> a)))
optimizeFunctionFix opt info (lam :$ body)
| Just (Lambda v) <- prjCtx typeCtx lam
= do
env <- ask
let aLens :: Lens (Info a) (Size a)
aLens = lens infoSize (\sz info -> info {infoSize = sz})
let bLens :: Lens (ASTF (Decor Info dom) a) (Size a)
bLens = lens (infoSize . getInfo)
(\sz a -> updateDecor (\info -> info {infoSize = sz}) a)
let body' = fst $ boundedLensedFixedPoint 1 aLens bLens
(optimizeFunBody opt env v body)
info
-- Using 1 as bound is motivated by the fact that a higher number
-- leads to exponential blowup when there are many nested
-- iterations. Since it is probably uncommon to have very deeply
-- nested loops, it might be fine to increase the bound. However
-- it is not clear that we gain anything by doing so, other than
-- in very special cases.
constructFeatUnOpt (Lambda v `withContext` typeCtx) (body' :* Nil)
instance (Variable TypeCtx :<: dom, Optimize dom dom) =>
Optimize (Variable TypeCtx) dom
where
constructFeatUnOpt var@(Variable v) Nil
| TypeWit <- fromSatWit $ witnessSat var
= reader $ \env -> case Prelude.lookup v (varEnv env) of
Nothing -> error $
"optimizeFeat: can't get size of free variable: v" ++ show v
Just (SomeInfo info) ->
let info' = (fromJust $ gcast info) {infoVars = singleton v 1}
in injDecorCtx typeCtx info' (Variable v)
instance (Lambda TypeCtx :<: dom, Optimize dom dom) =>
Optimize (Lambda TypeCtx) dom
where
-- | Assigns a 'universal' size to the bound variable. This only makes sense
-- for top-level lambdas. For other uses, use 'optimizeLambda' instead.
optimizeFeat lam@(Lambda v)
| TypeWit <- witnessByProxy typeCtx (argProxy lam)
= optimizeLambda optimizeM (mkInfo universal) (Lambda v)
constructFeatUnOpt lam@(Lambda v) (body :* Nil)
| TypeWit <- witnessByProxy typeCtx (argProxy lam)
, Info t sz vars _ <- getInfo body
= do
src <- asks sourceEnv
let info = Info (FunType typeRep t) sz (delete v vars) src
return $ injDecorCtx typeCtx info (Lambda v) :$ body
argProxy :: Lambda TypeCtx (b :-> Full (a -> b)) -> Proxy a
argProxy (Lambda _) = Proxy
instance SizeProp (Let TypeCtx TypeCtx)
where
sizeProp Let (_ :* WrapFull f :* Nil) = infoSize f
instance
( Let TypeCtx TypeCtx :<: dom
, Lambda TypeCtx :<: dom
, Variable TypeCtx :<: dom
, Optimize dom dom
) =>
Optimize (Let TypeCtx TypeCtx) dom
where
optimizeFeat lt@Let (a :* f :* Nil) = do
a' <- optimizeM a
f' <- optimizeFunction optimizeM (getInfo a') f
case getInfo f' of
Info{} -> constructFeat lt (a' :* f' :* Nil)
-- TODO Why is this pattern match needed?
constructFeatOpt Let (a :* (lam :$ var) :* Nil)
| Just (_,Lambda v1) <- prjDecorCtx typeCtx lam
, Just (_,Variable v2) <- prjDecorCtx typeCtx var
, v1 == v2
= return $ fromJust $ gcast a
constructFeatOpt a args = constructFeatUnOpt a args
constructFeatUnOpt = constructFeatUnOptDefault