summaryrefslogtreecommitdiff
path: root/ghc/compiler/simplCore/SimplUtils.lhs
blob: e0ac4aac258b4f69c8c93a3cc36e29e35485ca42 (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
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}