summaryrefslogtreecommitdiff
path: root/ghc/compiler/coreSyn/CoreTidy.lhs
blob: 3f5626ddb0f290d7fe41047749f80740d3f2ff52 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
%
% (c) The GRASP/AQUA Project, Glasgow University, 1992-1998
%
\section{Tidying up Core}

\begin{code}
module CoreTidy (
	tidyCorePgm, tidyExpr, 
	tidyBndr, tidyBndrs
    ) where

#include "HsVersions.h"

import CmdLineOpts	( opt_D_dump_simpl, opt_D_verbose_core2core, opt_UsageSPOn )
import CoreSyn
import CoreUnfold	( noUnfolding )
import CoreLint		( beginPass, endPass )
import Rules		( ProtoCoreRule(..) )
import UsageSPInf       ( doUsageSPInf )
import VarEnv
import VarSet
import Var		( Id, Var )
import Id		( idType, idInfo, idName, 
			  mkVanillaId, mkId, exportWithOrigOccName,
			  idStrictness, setIdStrictness,
			  idDemandInfo, setIdDemandInfo,
			) 
import IdInfo		( specInfo, setSpecInfo, 
			  inlinePragInfo, setInlinePragInfo, InlinePragInfo(..),
			  setUnfoldingInfo, setDemandInfo,
			  workerInfo, setWorkerInfo, WorkerInfo(..)
			)
import Demand		( wwLazy )
import Name		( getOccName, tidyTopName, mkLocalName, isLocallyDefined )
import OccName		( initTidyOccEnv, tidyOccName )
import Type		( tidyTopType, tidyType, tidyTypes, tidyTyVar, tidyTyVars )
import Module		( Module )
import UniqSupply	( UniqSupply )
import Unique		( Uniquable(..) )
import SrcLoc		( noSrcLoc )
import Util		( mapAccumL )
import Outputable
\end{code}



%************************************************************************
%*									*
\subsection{Tidying core}
%*									*
%************************************************************************

Several tasks are done by @tidyCorePgm@

1.  Make certain top-level bindings into Globals. The point is that 
    Global things get externally-visible labels at code generation
    time


2. Give all binders a nice print-name.  Their uniques aren't changed;
   rather we give them lexically unique occ-names, so that we can
   safely print the OccNae only in the interface file.  [Bad idea to
   change the uniques, because the code generator makes global labels
   from the uniques for local thunks etc.]


3. If @opt_UsageSPOn@ then compute usage information (which is
   needed by Core2Stg).  ** NOTE _scc_ HERE **

\begin{code}
tidyCorePgm :: UniqSupply -> Module -> [CoreBind] -> [ProtoCoreRule]
	    -> IO ([CoreBind], [ProtoCoreRule])
tidyCorePgm us module_name binds_in rules
  = do
	beginPass "Tidy Core"

	let (tidy_env1, binds_tidy) = mapAccumL (tidyBind (Just module_name)) init_tidy_env binds_in
	    rules_out	  	    = tidyProtoRules tidy_env1 rules

        binds_out <- if opt_UsageSPOn
                     then _scc_ "CoreUsageSPInf" doUsageSPInf us binds_tidy
                     else return binds_tidy

	endPass "Tidy Core" (opt_D_dump_simpl || opt_D_verbose_core2core) binds_out
	return (binds_out, rules_out)
  where
	-- We also make sure to avoid any exported binders.  Consider
	--	f{-u1-} = 1	-- Local decl
	--	...
	--	f{-u2-} = 2	-- Exported decl
	--
	-- The second exported decl must 'get' the name 'f', so we
	-- have to put 'f' in the avoids list before we get to the first
	-- decl.  tidyTopId then does a no-op on exported binders.
    init_tidy_env = (initTidyOccEnv avoids, emptyVarEnv)
    avoids	  = [getOccName bndr | bndr <- bindersOfBinds binds_in,
				       exportWithOrigOccName bndr]

tidyBind :: Maybe Module		-- (Just m) for top level, Nothing for nested
	 -> TidyEnv
	 -> CoreBind
	 -> (TidyEnv, CoreBind)
tidyBind maybe_mod env (NonRec bndr rhs)
  = let
	(env', bndr') = tidy_bndr maybe_mod env' env bndr
	rhs'	      = tidyExpr env' rhs
	-- We use env' when tidying the RHS even though it's not
	-- strictly necessary; it makes the code pretty hard to read
	-- if we don't!
    in
    (env', NonRec bndr' rhs')

tidyBind maybe_mod env (Rec pairs)
  = let
	-- We use env' when tidying the rhss
	-- When tidying the binder itself we may tidy it's
	-- specialisations; if any of these mention other binders
	-- in the group we should really feed env' to them too;
	-- but that seems (a) unlikely and (b) a bit tiresome.
	-- So I left it out for now

	(bndrs, rhss)  = unzip pairs
	(env', bndrs') = mapAccumL (tidy_bndr maybe_mod env') env bndrs
	rhss'	       = map (tidyExpr env') rhss
  in
  (env', Rec (zip bndrs' rhss'))

tidyExpr env (Type ty)	     = Type (tidyType env ty)
tidyExpr env (Lit lit)	     = Lit lit
tidyExpr env (App f a)       = App (tidyExpr env f) (tidyExpr env a)
tidyExpr env (Note n e)      = Note (tidyNote env n) (tidyExpr env e)

tidyExpr env (Let b e)       = Let b' (tidyExpr env' e)
			     where
			       (env', b') = tidyBind Nothing env b

tidyExpr env (Case e b alts) = Case (tidyExpr env e) b' (map (tidyAlt env') alts)
			     where
			       (env', b') = tidyBndr env b

tidyExpr env (Var v)         = Var (tidyVarOcc env v)

tidyExpr env (Lam b e)	     = Lam b' (tidyExpr env' e)
			     where
			       (env', b') = tidyBndr env b

tidyAlt env (con, vs, rhs)   = (con, vs', tidyExpr env' rhs)
			     where
			       (env', vs') = tidyBndrs env vs

tidyNote env (Coerce t1 t2)  = Coerce (tidyType env t1) (tidyType env t2)

tidyNote env note            = note

tidyVarOcc (_, var_env) v = case lookupVarEnv var_env v of
				  Just v' -> v'
				  Nothing -> v
\end{code}

\begin{code}
tidy_bndr (Just mod) env_idinfo env var = tidyTopId mod env env_idinfo var
tidy_bndr Nothing    env_idinfo env var = tidyBndr      env            var
\end{code}



%************************************************************************
%*									*
\subsection{Tidying up a binder}
%*									*
%************************************************************************

\begin{code}
tidyBndr :: TidyEnv -> Var -> (TidyEnv, Var)
tidyBndr env var | isTyVar var = tidyTyVar env var
		 | otherwise   = tidyId    env var

tidyBndrs :: TidyEnv -> [Var] -> (TidyEnv, [Var])
tidyBndrs env vars = mapAccumL tidyBndr env vars

tidyId :: TidyEnv -> Id -> (TidyEnv, Id)
tidyId env@(tidy_env, var_env) id
  = 	-- Non-top-level variables
    let 
	-- Give the Id a fresh print-name, *and* rename its type
	-- The SrcLoc isn't important now, though we could extract it from the Id
	name'        	  = mkLocalName (getUnique id) occ' noSrcLoc
	(tidy_env', occ') = tidyOccName tidy_env (getOccName id)
        ty'          	  = tidyType env (idType id)
	id'          	  = mkVanillaId name' ty'
			    `setIdStrictness` idStrictness id
			    `setIdDemandInfo` idDemandInfo id
			-- NB: This throws away the IdInfo of the Id, which we
			-- no longer need.  That means we don't need to
			-- run over it with env, nor renumber it.
			--
			-- The exception is strictness and demand info, which 
			-- is used to decide whether to use let or case for
			-- function arguments and let bindings

	var_env'	  = extendVarEnv var_env id id'
    in
    ((tidy_env', var_env'), id')

tidyTopId :: Module -> TidyEnv -> TidyEnv -> Id -> (TidyEnv, Id)
	-- The second env is the one to use for the IdInfo
	-- It's necessary because when we are dealing with a recursive
	-- group, a variable late in the group might be mentioned
	-- in the IdInfo of one early in the group
tidyTopId mod env@(tidy_env, var_env) env_idinfo id
  =	-- Top level variables
    let
	(tidy_env', name') | exportWithOrigOccName id = (tidy_env, idName id)
			   | otherwise	              = tidyTopName mod tidy_env (idName id)
	ty'	           = tidyTopType (idType id)
	idinfo'		   = tidyIdInfo env_idinfo (idInfo id)
	id'		   = mkId name' ty' idinfo'
	var_env'	   = extendVarEnv var_env id id'
    in
    ((tidy_env', var_env'), id')
\end{code}

\begin{code}
-- tidyIdInfo does these things:
--	a) tidy the specialisation info and worker info (if any)
--	b) zap the unfolding and demand info
-- The latter two are to avoid space leaks

tidyIdInfo env info
  = info5
  where
    rules = specInfo info

    info2 | isEmptyCoreRules rules = info 
	  | otherwise	           = info `setSpecInfo` tidyRules env rules
		
    info3 = info2 `setUnfoldingInfo` noUnfolding 
    info4 = info3 `setDemandInfo`    wwLazy		-- I don't understand why...

    info5 = case workerInfo info of
		NoWorker -> info4
		HasWorker w a  -> info4 `setWorkerInfo` HasWorker (tidyVarOcc env w) a

tidyProtoRules :: TidyEnv -> [ProtoCoreRule] -> [ProtoCoreRule]
tidyProtoRules env rules
  = [ ProtoCoreRule is_local (tidyVarOcc env fn) (tidyRule env rule)
    | ProtoCoreRule is_local fn rule <- rules
    ]

tidyRules :: TidyEnv -> CoreRules -> CoreRules
tidyRules env (Rules rules fvs) 
  = Rules (map (tidyRule env) rules)
	  (foldVarSet tidy_set_elem emptyVarSet fvs)
  where
    tidy_set_elem var new_set = extendVarSet new_set (tidyVarOcc env var)

tidyRule :: TidyEnv -> CoreRule -> CoreRule
tidyRule env rule@(BuiltinRule _) = rule
tidyRule env (Rule name vars tpl_args rhs)
  = (Rule name vars' (map (tidyExpr env') tpl_args) (tidyExpr env' rhs))
  where
    (env', vars') = tidyBndrs env vars
\end{code}