| 1 | % |
|---|
| 2 | % (c) The University of Glasgow 2006 |
|---|
| 3 | % (c) The AQUA Project, Glasgow University, 1996-1998 |
|---|
| 4 | % |
|---|
| 5 | |
|---|
| 6 | This module contains "tidying" code for *nested* expressions, bindings, rules. |
|---|
| 7 | The code for *top-level* bindings is in TidyPgm. |
|---|
| 8 | |
|---|
| 9 | \begin{code} |
|---|
| 10 | {-# OPTIONS -fno-warn-tabs #-} |
|---|
| 11 | -- The above warning supression flag is a temporary kludge. |
|---|
| 12 | -- While working on this module you are encouraged to remove it and |
|---|
| 13 | -- detab the module (please do the detabbing in a separate patch). See |
|---|
| 14 | -- http://hackage.haskell.org/trac/ghc/wiki/Commentary/CodingStyle#TabsvsSpaces |
|---|
| 15 | -- for details |
|---|
| 16 | |
|---|
| 17 | module CoreTidy ( |
|---|
| 18 | tidyExpr, tidyVarOcc, tidyRule, tidyRules, tidyUnfolding |
|---|
| 19 | ) where |
|---|
| 20 | |
|---|
| 21 | #include "HsVersions.h" |
|---|
| 22 | |
|---|
| 23 | import CoreSyn |
|---|
| 24 | import CoreArity |
|---|
| 25 | import Id |
|---|
| 26 | import IdInfo |
|---|
| 27 | import TcType( tidyType, tidyCo, tidyTyVarBndr ) |
|---|
| 28 | import Var |
|---|
| 29 | import VarEnv |
|---|
| 30 | import UniqFM |
|---|
| 31 | import Name hiding (tidyNameOcc) |
|---|
| 32 | import SrcLoc |
|---|
| 33 | import Maybes |
|---|
| 34 | import Data.List |
|---|
| 35 | import Outputable |
|---|
| 36 | \end{code} |
|---|
| 37 | |
|---|
| 38 | |
|---|
| 39 | %************************************************************************ |
|---|
| 40 | %* * |
|---|
| 41 | \subsection{Tidying expressions, rules} |
|---|
| 42 | %* * |
|---|
| 43 | %************************************************************************ |
|---|
| 44 | |
|---|
| 45 | \begin{code} |
|---|
| 46 | tidyBind :: TidyEnv |
|---|
| 47 | -> CoreBind |
|---|
| 48 | -> (TidyEnv, CoreBind) |
|---|
| 49 | |
|---|
| 50 | tidyBind env (NonRec bndr rhs) |
|---|
| 51 | = tidyLetBndr env env (bndr,rhs) =: \ (env', bndr') -> |
|---|
| 52 | (env', NonRec bndr' (tidyExpr env' rhs)) |
|---|
| 53 | |
|---|
| 54 | tidyBind env (Rec prs) |
|---|
| 55 | = let |
|---|
| 56 | (env', bndrs') = mapAccumL (tidyLetBndr env') env prs |
|---|
| 57 | in |
|---|
| 58 | map (tidyExpr env') (map snd prs) =: \ rhss' -> |
|---|
| 59 | (env', Rec (zip bndrs' rhss')) |
|---|
| 60 | |
|---|
| 61 | |
|---|
| 62 | ------------ Expressions -------------- |
|---|
| 63 | tidyExpr :: TidyEnv -> CoreExpr -> CoreExpr |
|---|
| 64 | tidyExpr env (Var v) = Var (tidyVarOcc env v) |
|---|
| 65 | tidyExpr env (Type ty) = Type (tidyType env ty) |
|---|
| 66 | tidyExpr env (Coercion co) = Coercion (tidyCo env co) |
|---|
| 67 | tidyExpr _ (Lit lit) = Lit lit |
|---|
| 68 | tidyExpr env (App f a) = App (tidyExpr env f) (tidyExpr env a) |
|---|
| 69 | tidyExpr env (Tick t e) = Tick (tidyTickish env t) (tidyExpr env e) |
|---|
| 70 | tidyExpr env (Cast e co) = Cast (tidyExpr env e) (tidyCo env co) |
|---|
| 71 | |
|---|
| 72 | tidyExpr env (Let b e) |
|---|
| 73 | = tidyBind env b =: \ (env', b') -> |
|---|
| 74 | Let b' (tidyExpr env' e) |
|---|
| 75 | |
|---|
| 76 | tidyExpr env (Case e b ty alts) |
|---|
| 77 | = tidyBndr env b =: \ (env', b) -> |
|---|
| 78 | Case (tidyExpr env e) b (tidyType env ty) |
|---|
| 79 | (map (tidyAlt b env') alts) |
|---|
| 80 | |
|---|
| 81 | tidyExpr env (Lam b e) |
|---|
| 82 | = tidyBndr env b =: \ (env', b) -> |
|---|
| 83 | Lam b (tidyExpr env' e) |
|---|
| 84 | |
|---|
| 85 | ------------ Case alternatives -------------- |
|---|
| 86 | tidyAlt :: CoreBndr -> TidyEnv -> CoreAlt -> CoreAlt |
|---|
| 87 | tidyAlt _case_bndr env (con, vs, rhs) |
|---|
| 88 | = tidyBndrs env vs =: \ (env', vs) -> |
|---|
| 89 | (con, vs, tidyExpr env' rhs) |
|---|
| 90 | |
|---|
| 91 | ------------ Tickish -------------- |
|---|
| 92 | tidyTickish :: TidyEnv -> Tickish Id -> Tickish Id |
|---|
| 93 | tidyTickish env (Breakpoint ix ids) = Breakpoint ix (map (tidyVarOcc env) ids) |
|---|
| 94 | tidyTickish _ other_tickish = other_tickish |
|---|
| 95 | |
|---|
| 96 | ------------ Rules -------------- |
|---|
| 97 | tidyRules :: TidyEnv -> [CoreRule] -> [CoreRule] |
|---|
| 98 | tidyRules _ [] = [] |
|---|
| 99 | tidyRules env (rule : rules) |
|---|
| 100 | = tidyRule env rule =: \ rule -> |
|---|
| 101 | tidyRules env rules =: \ rules -> |
|---|
| 102 | (rule : rules) |
|---|
| 103 | |
|---|
| 104 | tidyRule :: TidyEnv -> CoreRule -> CoreRule |
|---|
| 105 | tidyRule _ rule@(BuiltinRule {}) = rule |
|---|
| 106 | tidyRule env rule@(Rule { ru_bndrs = bndrs, ru_args = args, ru_rhs = rhs, |
|---|
| 107 | ru_fn = fn, ru_rough = mb_ns }) |
|---|
| 108 | = tidyBndrs env bndrs =: \ (env', bndrs) -> |
|---|
| 109 | map (tidyExpr env') args =: \ args -> |
|---|
| 110 | rule { ru_bndrs = bndrs, ru_args = args, |
|---|
| 111 | ru_rhs = tidyExpr env' rhs, |
|---|
| 112 | ru_fn = tidyNameOcc env fn, |
|---|
| 113 | ru_rough = map (fmap (tidyNameOcc env')) mb_ns } |
|---|
| 114 | \end{code} |
|---|
| 115 | |
|---|
| 116 | |
|---|
| 117 | %************************************************************************ |
|---|
| 118 | %* * |
|---|
| 119 | \subsection{Tidying non-top-level binders} |
|---|
| 120 | %* * |
|---|
| 121 | %************************************************************************ |
|---|
| 122 | |
|---|
| 123 | \begin{code} |
|---|
| 124 | tidyNameOcc :: TidyEnv -> Name -> Name |
|---|
| 125 | -- In rules and instances, we have Names, and we must tidy them too |
|---|
| 126 | -- Fortunately, we can lookup in the VarEnv with a name |
|---|
| 127 | tidyNameOcc (_, var_env) n = case lookupUFM var_env n of |
|---|
| 128 | Nothing -> n |
|---|
| 129 | Just v -> idName v |
|---|
| 130 | |
|---|
| 131 | tidyVarOcc :: TidyEnv -> Var -> Var |
|---|
| 132 | tidyVarOcc (_, var_env) v = lookupVarEnv var_env v `orElse` v |
|---|
| 133 | |
|---|
| 134 | -- tidyBndr is used for lambda and case binders |
|---|
| 135 | tidyBndr :: TidyEnv -> Var -> (TidyEnv, Var) |
|---|
| 136 | tidyBndr env var |
|---|
| 137 | | isTyVar var = tidyTyVarBndr env var |
|---|
| 138 | | otherwise = tidyIdBndr env var |
|---|
| 139 | |
|---|
| 140 | tidyBndrs :: TidyEnv -> [Var] -> (TidyEnv, [Var]) |
|---|
| 141 | tidyBndrs env vars = mapAccumL tidyBndr env vars |
|---|
| 142 | |
|---|
| 143 | tidyLetBndr :: TidyEnv -- Knot-tied version for unfoldings |
|---|
| 144 | -> TidyEnv -- The one to extend |
|---|
| 145 | -> (Id, CoreExpr) -> (TidyEnv, Var) |
|---|
| 146 | -- Used for local (non-top-level) let(rec)s |
|---|
| 147 | tidyLetBndr rec_tidy_env env (id,rhs) |
|---|
| 148 | = ((tidy_occ_env,new_var_env), final_id) |
|---|
| 149 | where |
|---|
| 150 | ((tidy_occ_env,var_env), new_id) = tidyIdBndr env id |
|---|
| 151 | new_var_env = extendVarEnv var_env id final_id |
|---|
| 152 | -- Override the env we get back from tidyId with the |
|---|
| 153 | -- new IdInfo so it gets propagated to the usage sites. |
|---|
| 154 | |
|---|
| 155 | -- We need to keep around any interesting strictness and |
|---|
| 156 | -- demand info because later on we may need to use it when |
|---|
| 157 | -- converting to A-normal form. |
|---|
| 158 | -- eg. |
|---|
| 159 | -- f (g x), where f is strict in its argument, will be converted |
|---|
| 160 | -- into case (g x) of z -> f z by CorePrep, but only if f still |
|---|
| 161 | -- has its strictness info. |
|---|
| 162 | -- |
|---|
| 163 | -- Similarly for the demand info - on a let binder, this tells |
|---|
| 164 | -- CorePrep to turn the let into a case. |
|---|
| 165 | -- |
|---|
| 166 | -- Similarly arity info for eta expansion in CorePrep |
|---|
| 167 | -- |
|---|
| 168 | -- Set inline-prag info so that we preseve it across |
|---|
| 169 | -- separate compilation boundaries |
|---|
| 170 | final_id = new_id `setIdInfo` new_info |
|---|
| 171 | idinfo = idInfo id |
|---|
| 172 | new_info = idInfo new_id |
|---|
| 173 | `setArityInfo` exprArity rhs |
|---|
| 174 | `setStrictnessInfo` strictnessInfo idinfo |
|---|
| 175 | `setDemandInfo` demandInfo idinfo |
|---|
| 176 | `setInlinePragInfo` inlinePragInfo idinfo |
|---|
| 177 | `setUnfoldingInfo` new_unf |
|---|
| 178 | |
|---|
| 179 | new_unf | isStableUnfolding unf = tidyUnfolding rec_tidy_env unf (panic "tidy_unf") |
|---|
| 180 | | otherwise = noUnfolding |
|---|
| 181 | unf = unfoldingInfo idinfo |
|---|
| 182 | |
|---|
| 183 | -- Non-top-level variables |
|---|
| 184 | tidyIdBndr :: TidyEnv -> Id -> (TidyEnv, Id) |
|---|
| 185 | tidyIdBndr env@(tidy_env, var_env) id |
|---|
| 186 | = -- Do this pattern match strictly, otherwise we end up holding on to |
|---|
| 187 | -- stuff in the OccName. |
|---|
| 188 | case tidyOccName tidy_env (getOccName id) of { (tidy_env', occ') -> |
|---|
| 189 | let |
|---|
| 190 | -- Give the Id a fresh print-name, *and* rename its type |
|---|
| 191 | -- The SrcLoc isn't important now, |
|---|
| 192 | -- though we could extract it from the Id |
|---|
| 193 | -- |
|---|
| 194 | ty' = tidyType env (idType id) |
|---|
| 195 | name' = mkInternalName (idUnique id) occ' noSrcSpan |
|---|
| 196 | id' = mkLocalIdWithInfo name' ty' new_info |
|---|
| 197 | var_env' = extendVarEnv var_env id id' |
|---|
| 198 | |
|---|
| 199 | -- Note [Tidy IdInfo] |
|---|
| 200 | new_info = vanillaIdInfo `setOccInfo` occInfo old_info |
|---|
| 201 | old_info = idInfo id |
|---|
| 202 | in |
|---|
| 203 | ((tidy_env', var_env'), id') |
|---|
| 204 | } |
|---|
| 205 | |
|---|
| 206 | ------------ Unfolding -------------- |
|---|
| 207 | tidyUnfolding :: TidyEnv -> Unfolding -> Unfolding -> Unfolding |
|---|
| 208 | tidyUnfolding tidy_env (DFunUnfolding ar con ids) _ |
|---|
| 209 | = DFunUnfolding ar con (map (tidyExpr tidy_env) ids) |
|---|
| 210 | tidyUnfolding tidy_env |
|---|
| 211 | unf@(CoreUnfolding { uf_tmpl = unf_rhs, uf_src = src }) |
|---|
| 212 | unf_from_rhs |
|---|
| 213 | | isStableSource src |
|---|
| 214 | = unf { uf_tmpl = tidyExpr tidy_env unf_rhs, -- Preserves OccInfo |
|---|
| 215 | uf_src = tidySrc tidy_env src } |
|---|
| 216 | | otherwise |
|---|
| 217 | = unf_from_rhs |
|---|
| 218 | tidyUnfolding _ unf _ = unf -- NoUnfolding or OtherCon |
|---|
| 219 | |
|---|
| 220 | tidySrc :: TidyEnv -> UnfoldingSource -> UnfoldingSource |
|---|
| 221 | tidySrc tidy_env (InlineWrapper w) = InlineWrapper (tidyVarOcc tidy_env w) |
|---|
| 222 | tidySrc _ inl_info = inl_info |
|---|
| 223 | \end{code} |
|---|
| 224 | |
|---|
| 225 | Note [Tidy IdInfo] |
|---|
| 226 | ~~~~~~~~~~~~~~~~~~ |
|---|
| 227 | All nested Ids now have the same IdInfo, namely vanillaIdInfo, which |
|---|
| 228 | should save some space; except that we preserve occurrence info for |
|---|
| 229 | two reasons: |
|---|
| 230 | |
|---|
| 231 | (a) To make printing tidy core nicer |
|---|
| 232 | |
|---|
| 233 | (b) Because we tidy RULES and InlineRules, which may then propagate |
|---|
| 234 | via --make into the compilation of the next module, and we want |
|---|
| 235 | the benefit of that occurrence analysis when we use the rule or |
|---|
| 236 | or inline the function. In particular, it's vital not to lose |
|---|
| 237 | loop-breaker info, else we get an infinite inlining loop |
|---|
| 238 | |
|---|
| 239 | Note that tidyLetBndr puts more IdInfo back. |
|---|
| 240 | |
|---|
| 241 | |
|---|
| 242 | \begin{code} |
|---|
| 243 | (=:) :: a -> (a -> b) -> b |
|---|
| 244 | m =: k = m `seq` k m |
|---|
| 245 | \end{code} |
|---|