module Grin.Devolve(twiddleGrin,devolveTransform,devolveGrin) where import Control.Monad.Identity import Control.Monad.RWS import Data.IORef import qualified Data.Map as Map import qualified Data.Set as Set import Util.Gen import Support.Transform import Grin.Grin import Grin.Noodle import Support.FreeVars devolveTransform = transformParms { transformDumpProgress = True, transformCategory = "Devolve", transformPass = "Grin", transformOperation = devolveGrin } -- devolve grin into a form in which it can be readily converted into C code -- This lifts any local functions which are ever called in a non-tail-calllike form -- to the top level. devolveGrin :: Grin -> IO Grin devolveGrin grin = do col <- newIORef [] let g (n,l :-> r) = f r >>= \r -> return (n,l :-> r) f lt@Let { expDefs = defs, expBody = body } = do let nonTail = expNonNormal lt (nmaps,rmaps) = splitEither (map z defs) z fd@FuncDef { funcDefName = name, funcDefBody = as :-> r } | name `Set.member` nonTail = Left ((name,(as ++ xs) :-> proc r),xs) | otherwise = Right fd { funcDefBody = as :-> proc r } where xs = [ Var v t | (v,t) <- Set.toList $ freeVars (as :-> r), v > v0] pmap = Map.fromList [ (n,xs) | ((n,_),xs) <- nmaps] proc b = runIdentity (proc' b) proc' (App a as t) | Just xs <- Map.lookup a pmap = return (App a (as ++ xs) t) proc' e = mapExpExp proc' e mapM_ print (Map.toList pmap) nmaps <- mapM (g . fst) nmaps modifyIORef col (++ nmaps) mapExpExp f $ updateLetProps lt { expDefs = rmaps, expBody = proc body } f e = mapExpExp f e nf <- mapM g (grinFuncs grin) lf <- readIORef col let ntenv = extendTyEnv [ createFuncDef False x y | (x,y) <- lf ] (grinTypeEnv grin) return $ setGrinFunctions (lf ++ nf) grin { grinPhase = PostDevolve, grinTypeEnv = ntenv } data Env = Env { envMap :: Map.Map Var Var, envVar :: Var } newtype R a = R (RWS Env (Set.Set Var) () a) deriving(Monad,Functor,MonadReader Env,MonadWriter (Set.Set Var)) runR (R x) = fst $ evalRWS x Env { envMap = mempty, envVar = v1 } () class Twiddle a where twiddle :: a -> R a twiddle a = return a instance Twiddle Exp where twiddle = twiddleExp instance Twiddle Val where twiddle = twiddleVal instance Twiddle a => Twiddle [a] where twiddle xs = mapM twiddle xs twiddleExp e = f e where f (x :>>= lam) = return (:>>=) `ap` twiddle x `ap` twiddle lam f l@Let {} = do ds <- twiddle (expDefs l) b <- twiddle (expBody l) return . updateLetProps $ l { expDefs = ds, expBody = b } f (Case v as) = return Case `ap` twiddle v `ap` twiddle as f n = do e <- mapExpVal twiddleVal n ; mapExpExp twiddle e instance Twiddle Lam where twiddle (vs :-> y) = do let fvs = freeVars vs (y,uv) <- censor (Set.filter (`notElem` fvs)) $ listen (twiddle y) let fvp' = Map.fromList $ concatMap (\v -> if v `Set.member` uv then [] else [(v,v0)]) fvs vs <- censor (const mempty) . local (\e -> e { envMap = fvp' }) $ twiddle vs return (vs :-> y) -- twiddle (vs :-> y) = do -- cv <- asks envVar -- let fvp = Map.fromList $ zip fvs [cv ..] -- fvs = freeVars vs -- local (\e -> e { envVar = head $ drop (length fvs) [cv .. ], envMap = fvp `Map.union` envMap e }) $ do -- (y,uv) <- censor (Set.filter (`notElem` take (length fvs) [cv .. ])) $ listen (twiddle y) -- let fvp' = fmap (\v -> if v `Set.member` uv then v else v0) fvp -- vs <- censor (const mempty) . local (\e -> e { envMap = fvp' }) $ twiddle vs -- return (vs :-> y) twiddleGrin grin = grinFunctions_s fs' grin where fs' = runR . twiddle $ grinFunctions grin instance Twiddle FuncDef where twiddle = funcDefBody_uM twiddle twiddleVal x = f x where f var@(Var v ty) = do em <- asks envMap case Map.lookup v em of Just n -> tell (Set.singleton n) >> return (Var n ty) Nothing -> tell (Set.singleton v) >> return var f x = mapValVal f x