packages feed

optimusprime-0.0.1.20091114: Optimus/Simplify.hs

module Optimus.Simplify where -- (simplify) where
	import Flite.Syntax
	import Flite.Traversals hiding (freshen)
	import Flite.Descend
	import Flite.Fresh
	import Optimus.Util
	import Data.List
	import Data.Maybe
	import Control.Monad
	import Optimus.Trace
	
	-- Issues are going to be with additional Apps in places
	
	-- |Not traced as too common and simply.
	stripApp :: Exp -> Exp
	stripApp e@(App (Fun _) []) = e
	stripApp (App x []) = stripApp x
	stripApp e = descend stripApp e
	
	-- |Not traced as too common and simply.
	appOfApp :: Exp -> Exp
	appOfApp (App (App x xs) ys) = appOfApp $ App x (xs ++ ys)
	appOfApp e = descend appOfApp e
			
	caseOfCons :: Exp -> Fresh Exp
	caseOfCons (Case (App (Con c) xs) ps) | isJust y' = fromJust y' >>= (caseOfCons . t_S "caseOfCons")
		where
			y' = listToMaybe [ mapM (const fresh) vs' >>=
							   \ws -> return $ Let (zip ws xs) (substMany y $ zipWith (\w v -> (Var w, v)) ws vs')
							| ( App (Con c') vs , y ) <- ps, c == c', length xs == length vs, let vs' = concatMap patVars vs ]
	caseOfCons (Case (Con c) ps) = caseOfCons $ Case (App (Con c) []) ps
	caseOfCons e = descendM caseOfCons e
			
	appToCase :: Exp -> Fresh Exp
	appToCase (App e@(Case _ _) zs) = do
		Case x ps <- freshenMany e (concatMap freeVars zs)
		appToCase $ t_S "appToCase" $ Case x [ (p, App y zs) | (p, y) <- ps ]
	appToCase e = descendM appToCase e
			
	appToLet :: Exp -> Fresh Exp
	appToLet (App e@(Let _ _) zs) = do
		Let bs y <- freshenMany e (concatMap freeVars zs)
		appToLet $ t_S "appToLet" $ Let bs (App y zs)
	appToLet e = descendM appToLet e
			
	caseOfLet :: Exp -> Fresh Exp
	caseOfLet (Case e@(Let _ _) as) = do
		Let bs y <- freshenMany e $ concat [ freeVarsExcept (patVars p) x | (p, x) <- as ]
		caseOfLet $ t_S "caseOfLet" $ Let bs (Case y as)
	caseOfLet e = descendM caseOfLet e
			
	caseOfCase :: Exp -> Fresh Exp
	caseOfCase (Case e@(Case _ _) as') = do
		Case x as <- freshenMany e $ concat [ freeVarsExcept (freeVars p) y | (p, y) <- as' ]
		caseOfCase $ t_S "caseOfCase" $ Case x [ (p, Case y as') | (p, y) <- as]
	caseOfCase e = descendM caseOfCase e
			
	substituteVar :: Exp -> Fresh Exp
	substituteVar e@(Case (Var v) as_) | v `elem` (freeVars $ Case Bottom as_) = do
		Case _ as <- freshen e v
		as' <- sequence [ liftM ((,) p) $ freshenMD y $ patVars p | (p, y) <- as ]
		--freshenMany e $ v : concat [ patVars p | Case _ as' <- extract universe e, (p, _) <- as' ]
		substituteVar $ t_S "substituteVar" $ Case (Var v) [ (p, subst p v y) | (p, y) <- as' ]
	substituteVar e = descendM substituteVar e
			
	letInCase :: Exp -> Fresh Exp
	letInCase (Let bs e@(Case y _)) | (not . null) safe_bs = do
			Case _ as <- freshenMany e (v:freeVars x)
			letInCase $ t_S "letInCase" $ Let rem_bs (Case y [ (p, Let [(v, x)] z) | (p, z) <- as ])
		where
			yFree = freeVars y
			bsFrees = [ (v, freeVars x) | (v, x) <- bs ]
			safe_bs = [ (v, x) | (v, x) <- bs, v `notElem` (yFree ++ concat [ ws | (w, ws) <- bsFrees, v /= w ]) ]
			(v, x) = head safe_bs
			rem_bs = [ (v', x') | (v', x') <- bs, v /= v' ]
	letInCase e = descendM letInCase e
			
	inlineLet :: Exp -> Fresh Exp
	inlineLet (Let bs y) | (not . null) safe_bs = do
			y' <- freshenMD y $ freeVars x_i
			inlineLet $ t_S "inlineLet" $ subst x_i v_i (Let rem_bs y')
		where
			(_, xs) = unzip bs
			(v_i, x_i) = head safe_bs
			rem_bs = [ b | b@(v_j, _) <- bs, v_j /= v_i ]
			safe_bs = 	[ b |
						  b@(v_j, x_j) <- bs
						, v_j `notElem` freeVars x_j
						, (sum . map (varRefs v_j)) (y:xs) <= 1 || isOk x_j ]
			isOk (Var _) = True
			isOk (Con _) = True
			isOk (Int _) = True
			isOk (Fun _) = True
			isOk (App e []) = isOk e
			isOk _ = False
	inlineLet e = descendM inlineLet e
			
	splitLet :: Exp -> Fresh Exp
	splitLet (Let bs y) | (not . null) safe_bs
		= do
			new_bs <- mapM build args
			splitLet $ t_S "splitLet" $ subst (App (Con c) (map Var (fst . unzip $ new_bs))) v_i (Let (rem_bs ++ new_bs) y)
		where
			(v_i, App (Con c) args) = head safe_bs
			rem_bs = [ b | b@(v_j, _) <- bs, v_j /= v_i ]
			safe_bs = [ b | b@(v_j, x_j@(App (Con _) _)) <- bs, v_j `notElem` freeVars x_j ]
			build x_j = fresh >>= \vF -> return (vF, x_j)
	splitLet e = descendM splitLet e
	
	removeLet :: Exp -> Exp
	removeLet (Let [] x) = descend removeLet x
	removeLet e = descend removeLet e
			
	letInLet :: Exp -> Fresh Exp
	letInLet (Let bs1 e@(Let _ _)) = do
			Let bs2 x <- freshenMany e (concatMap (freeVars . snd) bs1 ++ map fst bs1)
			letInLet $ t_S "letInLet" $ Let (bs1 ++ bs2) x
	letInLet e = descendM letInLet e
			
	simplify :: Exp -> Fresh Exp
	simplify p = do
			p' <- (return . stripApp . appOfApp . removeLet) =<< appToCase =<< appToLet =<< caseOfLet =<< caseOfCons
				=<< caseOfCase =<< substituteVar =<< letInCase
				=<< inlineLet =<< letInLet =<< ( splitLet . appOfApp
					. removeLet . stripApp ) p
			if p == p' then return p else simplify p'
	
	simplifyInlines :: Exp -> Fresh Exp
	simplifyInlines e = do
		e' <- (return . removeLet <=< inlineLet <=< return . stripApp) e
		if e == e' then return e else simplifyInlines e'
		
	simplifyProg :: Prog -> Fresh Prog
	simplifyProg p = sequence [ return . Func f a =<< (\x -> t_S' (show x) (simplify x)) =<< simplifyInlines (t_S' ("Simplifying " ++ f) r) | Func f a r <- p]