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
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
|
%
% (c) The AQUA Project, Glasgow University, 1993-1995
%
\section[SimplUtils]{The simplifier utilities}
\begin{code}
#include "HsVersions.h"
module SimplUtils (
floatExposesHNF,
mkCoTyLamTryingEta, mkCoLamTryingEta,
etaExpandCount,
mkIdentityAlts,
simplIdWantsToBeINLINEd,
type_ok_for_let_to_case
) where
IMPORT_Trace -- ToDo: rm (debugging)
import Pretty
import TaggedCore
import PlainCore
import SimplEnv
import SimplMonad
import BinderInfo
import AbsPrel ( primOpIsCheap, realWorldStateTy, buildId
IF_ATTACK_PRAGMAS(COMMA realWorldTy)
IF_ATTACK_PRAGMAS(COMMA tagOf_PrimOp)
IF_ATTACK_PRAGMAS(COMMA pprPrimOp)
)
import AbsUniType ( extractTyVarsFromTy, getTyVarMaybe, isPrimType,
splitTypeWithDictsAsArgs, getUniDataTyCon_maybe,
applyTy, isFunType, TyVar, TyVarTemplate
IF_ATTACK_PRAGMAS(COMMA cmpTyVar COMMA cmpClass)
)
import Id ( getInstantiatedDataConSig, isDataCon, getIdUniType,
getIdArity, isBottomingId, idWantsToBeINLINEd,
DataCon(..), Id
)
import IdInfo
import CmdLineOpts ( SimplifierSwitch(..) )
import Maybes ( maybeToBool, Maybe(..) )
import Outputable -- isExported ...
import Util
\end{code}
Floating
~~~~~~~~
The function @floatExposesHNF@ tells whether let/case floating will
expose a head normal form. It is passed booleans indicating the
desired strategy.
\begin{code}
floatExposesHNF
:: Bool -- Float let(rec)s out of rhs
-> Bool -- Float cheap primops out of rhs
-> Bool -- OK to duplicate code
-> CoreExpr bdr Id
-> Bool
floatExposesHNF float_lets float_primops ok_to_dup rhs
= try rhs
where
try (CoCase (CoPrim _ _ _) (CoPrimAlts alts deflt) )
| float_primops && (null alts || ok_to_dup)
= or (try_deflt deflt : map try_alt alts)
try (CoLet bind body) | float_lets = try body
-- `build g'
-- is like a HNF,
-- because it *will* become one.
try (CoApp (CoTyApp (CoVar bld) _) _) | bld == buildId = True
try other = manifestlyWHNF other
{- but *not* necessarily "manifestlyBottom other"...
We may want to float a let out of a let to expose WHNFs,
but to do that to expose a "bottom" is a Bad Idea:
let x = let y = ...
in ...error ...y... -- manifestly bottom using y
in ...
=/=>
let y = ...
in let x = ...error ...y...
in ...
as y is only used in case of an error, we do not want
to allocate it eagerly as that's a waste.
-}
try_alt (lit,rhs) = try rhs
try_deflt CoNoDefault = False
try_deflt (CoBindDefault _ rhs) = try rhs
\end{code}
Eta reduction on ordinary lambdas
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
We have a go at doing
\ x y -> f x y ===> f
But we only do this if it gets rid of a whole lambda, not part.
The idea is that lambdas are often quite helpful: they indicate
head normal forms, so we don't want to chuck them away lightly.
But if they expose a simple variable then we definitely win. Even
if they expose a type application we win. So we check for this special
case.
It does arise:
f xs = [y | (y,_) <- xs]
gives rise to a recursive function for the list comprehension, and
f turns out to be just a single call to this recursive function.
\begin{code}
mkCoLamTryingEta :: [Id] -- Args to the lambda
-> PlainCoreExpr -- Lambda body
-> PlainCoreExpr
mkCoLamTryingEta [] body = body
mkCoLamTryingEta orig_ids body
= reduce_it (reverse orig_ids) body
where
bale_out = mkCoLam orig_ids body
reduce_it [] residual
| residual_ok residual = residual
| otherwise = bale_out
reduce_it (id:ids) (CoApp fun (CoVarAtom arg))
| id == arg
&& getIdUniType id /= realWorldStateTy
-- *never* eta-reduce away a PrimIO state token! (WDP 94/11)
= reduce_it ids fun
reduce_it ids other = bale_out
is_elem = isIn "mkCoLamTryingEta"
-----------
residual_ok :: PlainCoreExpr -> Bool -- Checks for type application
-- and function not one of the
-- bound vars
residual_ok (CoTyApp fun ty) = residual_ok fun
residual_ok (CoVar v) = not (v `is_elem` orig_ids) -- Fun mustn't be one of
-- the bound ids
residual_ok other = False
\end{code}
Eta expansion
~~~~~~~~~~~~~
@etaExpandCount@ takes an expression, E, and returns an integer n,
such that
E ===> (\x1::t1 x1::t2 ... xn::tn -> E x1 x2 ... xn)
is a safe transformation. In particular, the transformation should not
cause work to be duplicated, unless it is ``cheap'' (see @manifestlyCheap@ below).
@etaExpandCount@ errs on the conservative side. It is always safe to return 0.
An application of @error@ is special, because it can absorb as many
arguments as you care to give it. For this special case we return 100,
to represent "infinity", which is a bit of a hack.
\begin{code}
etaExpandCount :: CoreExpr bdr Id
-> Int -- Number of extra args you can safely abstract
etaExpandCount (CoLam ids body)
= length ids + etaExpandCount body
etaExpandCount (CoLet bind body)
| all manifestlyCheap (rhssOfBind bind)
= etaExpandCount body
etaExpandCount (CoCase scrut alts)
| manifestlyCheap scrut
= minimum [etaExpandCount rhs | rhs <- rhssOfAlts alts]
etaExpandCount (CoApp fun _) = case etaExpandCount fun of
0 -> 0
n -> n-1 -- Knock off one
etaExpandCount fun@(CoTyApp _ _) = eta_fun fun
etaExpandCount fun@(CoVar _) = eta_fun fun
etaExpandCount other = 0 -- Give up
-- CoLit, CoCon, CoPrim,
-- CoTyLam,
-- CoScc (pessimistic; ToDo),
-- CoLet with non-whnf rhs(s),
-- CoCase with non-whnf scrutinee
eta_fun :: CoreExpr bdr Id -- The function
-> Int -- How many args it can safely be applied to
eta_fun (CoTyApp fun ty) = eta_fun fun
eta_fun expr@(CoVar v)
| isBottomingId v -- Bottoming ids have "infinite arity"
= 10000 -- Blargh. Infinite enough!
eta_fun expr@(CoVar v)
| maybeToBool arity_maybe -- We know the arity
= arity
where
arity_maybe = arityMaybe (getIdArity v)
arity = case arity_maybe of { Just arity -> arity }
eta_fun other = 0 -- Give up
\end{code}
@manifestlyCheap@ looks at a Core expression and returns \tr{True} if
it is obviously in weak head normal form, or is cheap to get to WHNF.
By ``cheap'' we mean a computation we're willing to duplicate in order
to bring a couple of lambdas together. The main examples of things
which aren't WHNF but are ``cheap'' are:
* case e of
pi -> ei
where e, and all the ei are cheap; and
* let x = e
in b
where e and b are cheap; and
* op x1 ... xn
where op is a cheap primitive operator
\begin{code}
manifestlyCheap :: CoreExpr bndr Id -> Bool
manifestlyCheap (CoVar _) = True
manifestlyCheap (CoLit _) = True
manifestlyCheap (CoCon _ _ _) = True
manifestlyCheap (CoLam _ _) = True
manifestlyCheap (CoTyLam _ e) = manifestlyCheap e
manifestlyCheap (CoSCC _ e) = manifestlyCheap e
manifestlyCheap (CoPrim op _ _) = primOpIsCheap op
manifestlyCheap (CoLet bind body)
= manifestlyCheap body && all manifestlyCheap (rhssOfBind bind)
manifestlyCheap (CoCase scrut alts)
= manifestlyCheap scrut && all manifestlyCheap (rhssOfAlts alts)
manifestlyCheap other_expr -- look for manifest partial application
= case (collectArgs other_expr) of { (fun, args) ->
case fun of
CoVar f | isBottomingId f -> True -- Application of a function which
-- always gives bottom; we treat this as
-- a WHNF, because it certainly doesn't
-- need to be shared!
CoVar f -> let
num_val_args = length [ a | (ValArg a) <- args ]
in
num_val_args == 0 || -- Just a type application of
-- a variable (f t1 t2 t3)
-- counts as WHNF
case (arityMaybe (getIdArity f)) of
Nothing -> False
Just arity -> num_val_args < arity
_ -> False
}
-- ToDo: Move to CoreFuns
rhssOfBind :: CoreBinding bndr bdee -> [CoreExpr bndr bdee]
rhssOfBind (CoNonRec _ rhs) = [rhs]
rhssOfBind (CoRec pairs) = [rhs | (_,rhs) <- pairs]
rhssOfAlts :: CoreCaseAlternatives bndr bdee -> [CoreExpr bndr bdee]
rhssOfAlts (CoAlgAlts alts deflt) = rhssOfDeflt deflt ++
[rhs | (_,_,rhs) <- alts]
rhssOfAlts (CoPrimAlts alts deflt) = rhssOfDeflt deflt ++
[rhs | (_,rhs) <- alts]
rhssOfDeflt CoNoDefault = []
rhssOfDeflt (CoBindDefault _ rhs) = [rhs]
\end{code}
Eta reduction on type lambdas
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
We have a go at doing
/\a -> <expr> a ===> <expr>
where <expr> doesn't mention a.
This is sometimes quite useful, because we can get the sequence:
f ab d = let d1 = ...d... in
letrec f' b x = ...d...(f' b)... in
f' b
specialise ==>
f.Int b = letrec f' b x = ...dInt...(f' b)... in
f' b
float ==>
f' b x = ...dInt...(f' b)...
f.Int b = f' b
Now we really want to simplify to
f.Int = f'
and then replace all the f's with f.Ints.
N.B. We are careful not to partially eta-reduce a sequence of type
applications since this breaks the specialiser:
/\ a -> f Char# a =NO=> f Char#
\begin{code}
mkCoTyLamTryingEta :: [TyVar] -> PlainCoreExpr -> PlainCoreExpr
mkCoTyLamTryingEta tyvars tylam_body
= if
tyvars == tyvar_args && -- Same args in same order
check_fun fun -- Function left is ok
then
-- Eta reduction worked
fun
else
-- The vastly common case
mkCoTyLam tyvars tylam_body
where
(tyvar_args, fun) = strip_tyvar_args [] tylam_body
strip_tyvar_args args_so_far tyapp@(CoTyApp fun ty)
= case getTyVarMaybe ty of
Just tyvar_arg -> strip_tyvar_args (tyvar_arg:args_so_far) fun
Nothing -> (args_so_far, tyapp)
strip_tyvar_args args_so_far fun
= (args_so_far, fun)
check_fun (CoVar f) = True -- Claim: tyvars not mentioned by type of f
check_fun other = False
{- OLD:
mkCoTyLamTryingEta :: TyVar -> PlainCoreExpr -> PlainCoreExpr
mkCoTyLamTryingEta tyvar body
= case body of
CoTyApp fun ty ->
case getTyVarMaybe ty of
Just tyvar' | tyvar == tyvar' &&
ok fun -> fun
-- Ha! So it's /\ a -> fun a, and fun is "ok"
other -> CoTyLam tyvar body
other -> CoTyLam tyvar body
where
is_elem = isIn "mkCoTyLamTryingEta"
ok :: PlainCoreExpr -> Bool -- Returns True iff the expression doesn't
-- mention tyvar
ok (CoVar v) = True -- Claim: tyvar not mentioned by type of v
ok (CoApp fun arg) = ok fun -- Claim: tyvar not mentioned by type of arg
ok (CoTyApp fun ty) = not (tyvar `is_elem` extractTyVarsFromTy ty) &&
ok fun
ok other = False
-}
\end{code}
Let to case
~~~~~~~~~~~
Given a type generate the case alternatives
C a b -> C a b
if there's one constructor, or
x -> x
if there's many, or if it's a primitive type.
\begin{code}
mkIdentityAlts
:: UniType -- type of RHS
-> SmplM InAlts -- result
mkIdentityAlts rhs_ty
| isPrimType rhs_ty
= newId rhs_ty `thenSmpl` \ binder ->
returnSmpl (CoPrimAlts [] (CoBindDefault (binder, bad_occ_info) (CoVar binder)))
| otherwise
= case getUniDataTyCon_maybe rhs_ty of
Just (tycon, ty_args, [data_con]) -> -- algebraic type suitable for unpacking
let
(_,inst_con_arg_tys,_) = getInstantiatedDataConSig data_con ty_args
in
newIds inst_con_arg_tys `thenSmpl` \ new_bindees ->
let
new_binders = [ (b, bad_occ_info) | b <- new_bindees ]
in
returnSmpl (
CoAlgAlts
[(data_con, new_binders, CoCon data_con ty_args (map CoVarAtom new_bindees))]
CoNoDefault
)
_ -> -- Multi-constructor or abstract algebraic type
newId rhs_ty `thenSmpl` \ binder ->
returnSmpl (CoAlgAlts [] (CoBindDefault (binder,bad_occ_info) (CoVar binder)))
where
bad_occ_info = ManyOcc 0 -- Non-committal!
\end{code}
\begin{code}
simplIdWantsToBeINLINEd :: Id -> SimplEnv -> Bool
simplIdWantsToBeINLINEd id env
= if switchIsSet env IgnoreINLINEPragma
then False
else idWantsToBeINLINEd id
type_ok_for_let_to_case :: UniType -> Bool
type_ok_for_let_to_case ty
= case getUniDataTyCon_maybe ty of
Nothing -> False
Just (tycon, ty_args, []) -> False
Just (tycon, ty_args, non_null_data_cons) -> True
-- Null data cons => type is abstract
\end{code}
|