lvmlib-1.0: Lvm/Core/Normalize.hs
--------------------------------------------------------------------------------
-- Copyright 2001-2012, Daan Leijen, Bastiaan Heeren, Jurriaan Hage. This file
-- is distributed under the terms of the BSD3 License. For more information,
-- see the file "LICENSE.txt", which is included in the distribution.
--------------------------------------------------------------------------------
-- $Id: Normalize.hs 291 2012-11-08 11:27:33Z heere112 $
----------------------------------------------------------------
-- Normalises Core:
-- * no lambda's, except directly at let-bindings
-- * each Ap argument is atomic & not a call to an instruction or external function
-- * each Ap target is atomic
--
-- an atomic expression is
-- * a Var
-- * a Lit
-- * a Con
-- * a normalised Ap
-- * a normalised Let(Rec) expression
--
-- pre: [coreNoShadow, coreSaturate]
----------------------------------------------------------------
module Lvm.Core.Normalize (coreNormalize) where
import Lvm.Common.Id
import Lvm.Common.IdSet
import Lvm.Core.Expr
import Lvm.Core.Utils
----------------------------------------------------------------
-- Environment: the name supply
----------------------------------------------------------------
data Env = Env NameSupply !IdSet {- instructions + externs -}
uniqueId :: Env -> Id
uniqueId (Env supply _) = fst (freshId supply)
splitEnv :: Env -> (Env, Env)
splitEnv (Env s d)
= let (s0,s1) = splitNameSupply s in (Env s0 d, Env s1 d)
splitEnvs :: Env -> [Env]
splitEnvs (Env s d) = map (`Env` d) (splitNameSupplies s)
isDirect :: Env -> Id -> Bool
isDirect (Env _ d) x = elemSet x d
----------------------------------------------------------------
-- coreNormalise
----------------------------------------------------------------
coreNormalize :: NameSupply -> CoreModule -> CoreModule
coreNormalize supply m
= mapExprWithSupply (normDeclExpr primitives) supply m
where
primitives = externNames m
normDeclExpr :: IdSet -> NameSupply -> Expr -> Expr
normDeclExpr directs supply = normBind (Env supply directs)
----------------------------------------------------------------
-- Expression & bindings
----------------------------------------------------------------
normExpr :: Env -> Expr -> Expr
normExpr env expr
= let (env1,env2) = splitEnv env
expr' = normBind env1 expr
in case expr' of
Lam _ _ -> let x = uniqueId env2
in (Let (NonRec (Bind x expr')) (Var x))
_ -> expr'
-- can return lambda's on top
normBind :: Env -> Expr -> Expr
normBind env expr
= case expr of
Let binds e -> let (env1,env2) = splitEnv env
in Let (normBinds env1 binds) (normExpr env2 e)
Match x alts -> Match x (normAlts env alts)
Lam x e -> Lam x (normBind env e)
Ap _ _ -> normAtomExpr env expr
_ -> expr
normBinds :: Env -> Binds -> Binds
normBinds
= zipBindsWith (\env x expr -> Bind x (normBind env expr)) . splitEnvs
normAlts :: Env -> Alts -> Alts
normAlts
= zipAltsWith (\env pat expr -> Alt pat (normExpr env expr)) . splitEnvs
normAtomExpr :: Env -> Expr -> Expr
normAtomExpr env expr
= let (atom,f) = normAtom env expr
in (f atom)
-- returns an atomic expression + a function that adds the right bindings
normAtom :: Env -> Expr -> (Expr, Expr -> Expr)
normAtom env expr
= case expr of
Match _ _ -> freshBinding
Lam _ _ -> freshBinding
Let (Strict _) _ -> freshBinding
-- we could leave let bindings in place when they are fully
-- atomic but otherwise the bindings get messed up (shadow7.core).
-- we lift all bindings out and rely on asmInline to put them
-- back again if possible.
Let binds e -> let (env1,env2) = splitEnv env
(atom,f) = normAtom env1 e
-- (abinds,g) = normAtomBinds env2 binds
in (atom, Let (normBinds env2 binds) . f)
-- (abinds atom, f . g)
Ap e1 e2 -> let (env1,env2) = splitEnv env
(atom,f) = normAtom env1 e1
(arg,g) = normArg env2 e2
in (Ap atom arg, f . g)
_ -> (expr,id)
where
freshBinding = let (env1,env2) = splitEnv env
expr' = normBind env1 expr
x = uniqueId env2
in (Var x, Let (NonRec (Bind x expr')))
-- normAtomBinds returns two functions: one that adds atomic
-- let bindings and one that adds non-atomic bindings
{- normAtomBinds :: Env -> Binds -> (Expr -> Expr, Expr -> Expr)
normAtomBinds env binds
= let (binds',(env',f)) = mapAccumBinds norm (env,id) binds
in (Let binds', f)
where
norm (env,f) id expr = let (env1,env2) = splitEnv env
(atom,g) = normAtom env1 expr
in (Bind id atom, (env2, f . g))
-}
-- just as an atomic expression but binds 'direct' applications (ie. externs & instructions)
normArg :: Env -> Expr -> (Expr, Expr -> Expr)
normArg env expr
= let (env1,env2) = splitEnv env
(atom,f) = normAtom env1 expr
in if isDirectAp env atom
then let x = uniqueId env2
in (Var x, f . Let (NonRec (Bind x atom)))
else (atom,f)
isDirectAp :: Env -> Expr -> Bool
isDirectAp env expr
= case expr of
Ap e1 _ -> isDirectAp env e1
Var x -> isDirect env x
_ -> False