|
| 1 | +{-# LANGUAGE LambdaCase, TupleSections, ViewPatterns #-} |
| 2 | +module Transformations.ExtendedSyntax.Optimising.CSE where |
| 3 | + |
| 4 | +-- HINT: common sub-expression elimination |
| 5 | + |
| 6 | +import Data.Map.Strict (Map) |
| 7 | +import qualified Data.Map.Strict as Map |
| 8 | +import Data.Functor.Foldable as Foldable |
| 9 | + |
| 10 | +import Text.Printf |
| 11 | + |
| 12 | +import Lens.Micro ((^.)) |
| 13 | +import Lens.Micro.Extra (isn't) |
| 14 | + |
| 15 | +import Grin.ExtendedSyntax.Grin |
| 16 | +import Grin.ExtendedSyntax.TypeEnv |
| 17 | +import Grin.ExtendedSyntax.EffectMap |
| 18 | +import Transformations.ExtendedSyntax.Util |
| 19 | + |
| 20 | + |
| 21 | +type Env = (Map SimpleExp SimpleExp) |
| 22 | + |
| 23 | +-- TODO: track if function parameters with location type can be updated in the called function to improve CSE |
| 24 | + |
| 25 | +{- TODO: remove skipUnit, it does nothing with the new syntax (SDVE will get rid of the unused unit-binds) |
| 26 | + TODO: CSE could be taught to remember pattern binds: |
| 27 | + (CInt k1)@n0 <- pure (CInt k0) |
| 28 | + n1 <- pure (CInt k0) |
| 29 | + n2 <- pure (CInt k1) |
| 30 | +
|
| 31 | + could be transformed to: |
| 32 | +
|
| 33 | + (CInt k1)@n0 <- pure (CInt k0) |
| 34 | + n1 <- pure n0 |
| 35 | + n2 <- pure n0 |
| 36 | +-} |
| 37 | +commonSubExpressionElimination :: TypeEnv -> EffectMap -> Exp -> Exp |
| 38 | +commonSubExpressionElimination typeEnv effMap e = hylo skipUnit builder (mempty, e) where |
| 39 | + |
| 40 | + builder :: (Env, Exp) -> ExpF (Env, Exp) |
| 41 | + builder (env, subst env -> exp) = case exp of |
| 42 | + EBind leftExp bPat rightExp -> EBindF (env, leftExp) bPat (newEnv, rightExp) where |
| 43 | + newEnv = case leftExp of |
| 44 | + -- HINT: also save fetch (the inverse operation) for store and update |
| 45 | + SUpdate ptr var -> Map.insert (SFetch ptr) (SReturn (Var var)) env |
| 46 | + SStore var |
| 47 | + -- TODO: AsPat |
| 48 | + | VarPat ptr <- bPat -> Map.insert (SFetch ptr) (SReturn (Var var)) extEnvKeepOld |
| 49 | + -- HINT: location parameters might be updated in the called function, so forget their content |
| 50 | + SApp defName args -> foldr |
| 51 | + Map.delete |
| 52 | + (if (hasTrueSideEffect defName effMap) then env else extEnvKeepOld) |
| 53 | + [SFetch var | var <- args, isLocation var] |
| 54 | + SReturn val | isn't _Var val -> extEnvKeepOld |
| 55 | + SFetch{} -> extEnvKeepOld |
| 56 | + _ -> env |
| 57 | + |
| 58 | + extEnvKeepOld = Map.insertWith (\new old -> old) leftExp (SReturn . Var $ bPat ^. _BPatVar) env |
| 59 | + |
| 60 | + -- TODO: Investigate this. Will the fetched variable, and the variable to be updated with |
| 61 | + -- always have the same name? If not, will copy propagation solve it? |
| 62 | + SUpdate ptr var | Just (SReturn (Var fetchedVar)) <- Map.lookup (SFetch ptr) env |
| 63 | + , fetchedVar == var |
| 64 | + -> SReturnF Unit |
| 65 | + |
| 66 | + ECase scrut alts -> ECaseF scrut [(altEnv env scrut cpat, alt) | alt@(Alt cpat _altName _) <- alts] |
| 67 | + |
| 68 | + _ -> (env,) <$> project exp |
| 69 | + |
| 70 | + isLocation :: Name -> Bool |
| 71 | + isLocation name = case variableType typeEnv name of |
| 72 | + T_SimpleType T_Location{} -> True |
| 73 | + _ -> False |
| 74 | + |
| 75 | + altEnv :: Env -> Name -> CPat -> Env |
| 76 | + altEnv env scrut cpat = case cpat of |
| 77 | + NodePat tag args -> env -- When we use scrutinee variable already HPT will include all the |
| 78 | + -- possible values, instead of the matching one. As result it will |
| 79 | + -- overapproximate the values more than needed. |
| 80 | + |
| 81 | + -- NOTE: We could extend the env with [ SReturn (ConstTagNode tag args) -> SReturn val ] |
| 82 | + -- HPT would _not_ overapproximate the possible type of the variable, |
| 83 | + -- since it restricts the scrutinee to the alternative's domain |
| 84 | + LitPat lit -> Map.insertWith (\new old -> old) (SReturn (Lit lit)) (SReturn (Var scrut)) env |
| 85 | + DefaultPat -> env |
| 86 | + |
0 commit comments