summaryrefslogtreecommitdiff
path: root/compiler/codeGen/CgExpr.lhs
blob: cb3a86ef7f8cdbe87a153538e12f0f01f071792d (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
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
%
% (c) The University of Glasgow 2006
% (c) The GRASP/AQUA Project, Glasgow University, 1992-1998
%

\begin{code}
{-# OPTIONS -fno-warn-tabs #-}
-- The above warning supression flag is a temporary kludge.
-- While working on this module you are encouraged to remove it and
-- detab the module (please do the detabbing in a separate patch). See
--     http://hackage.haskell.org/trac/ghc/wiki/Commentary/CodingStyle#TabsvsSpaces
-- for details

module CgExpr ( cgExpr ) where

#include "HsVersions.h"

import Constants
import StgSyn
import CgMonad

import CostCentre
import SMRep
import CoreSyn
import CgProf
import CgHeapery
import CgBindery
import CgCase
import CgClosure
import CgCon
import CgLetNoEscape
import CgTailCall
import CgInfoTbls
import CgForeignCall
import CgPrimOp
import CgHpc
import CgUtils
import ClosureInfo
import OldCmm
import OldCmmUtils
import VarSet
import Literal
import PrimOp
import Id
import TyCon
import Type
import Maybes
import ListSetOps
import BasicTypes
import Util
import Outputable
import StaticFlags
\end{code}

This module provides the support code for @StgToAbstractC@ to deal
with STG {\em expressions}.  See also @CgClosure@, which deals
with closures, and @CgCon@, which deals with constructors.

\begin{code}
cgExpr	:: StgExpr		-- input
	-> Code			-- output
\end{code}

%********************************************************
%*							*
%*		Tail calls				*
%*							*
%********************************************************

``Applications'' mean {\em tail calls}, a service provided by module
@CgTailCall@.  This includes literals, which show up as
@(STGApp (StgLitArg 42) [])@.

\begin{code}
cgExpr (StgApp fun args) = cgTailCall fun args
\end{code}

%********************************************************
%*							*
%*		STG ConApps  (for inline versions)	*
%*							*
%********************************************************

\begin{code}
cgExpr (StgConApp con args)
  = do	{ amodes <- getArgAmodes args
	; cgReturnDataCon con amodes }
\end{code}

Literals are similar to constructors; they return by putting
themselves in an appropriate register and returning to the address on
top of the stack.

\begin{code}
cgExpr (StgLit lit)
  = do  { cmm_lit <- cgLit lit
	; performPrimReturn rep (CmmLit cmm_lit) }
  where
    rep = (typeCgRep) (literalType lit)
\end{code}


%********************************************************
%*							*
%* 	PrimOps and foreign calls.
%*							*
%********************************************************

NOTE about "safe" foreign calls: a safe foreign call is never compiled
inline in a case expression.  When we see

	case (ccall ...) of { ... }

We generate a proper return address for the alternatives and push the
stack frame before doing the call, so that in the event that the call
re-enters the RTS the stack is in a sane state.

\begin{code}
cgExpr (StgOpApp (StgFCallOp fcall _) stg_args res_ty) = do
    {-
	First, copy the args into temporaries.  We're going to push
	a return address right before doing the call, so the args
	must be out of the way.
    -}
    reps_n_amodes <- getArgAmodes stg_args
    let 
	-- Get the *non-void* args, and jiggle them with shimForeignCall
	arg_exprs = [ (shimForeignCallArg stg_arg expr, stg_arg)
		    | (stg_arg, (rep,expr)) <- stg_args `zip` reps_n_amodes, 
		      nonVoidArg rep]

    arg_tmps <- sequence [ assignTemp arg
                         | (arg, _) <- arg_exprs]
    let	arg_hints = zipWith CmmHinted arg_tmps (map (typeForeignHint.stgArgType) stg_args)
    {-
	Now, allocate some result regs.
    -}
    (res_reps,res_regs,res_hints)  <- newUnboxedTupleRegs res_ty
    ccallReturnUnboxedTuple (zip res_reps (map (CmmReg . CmmLocal) res_regs)) $
	emitForeignCall (zipWith CmmHinted res_regs res_hints) fcall 
	   arg_hints emptyVarSet{-no live vars-}
      
-- tagToEnum# is special: we need to pull the constructor out of the table,
-- and perform an appropriate return.

cgExpr (StgOpApp (StgPrimOp TagToEnumOp) [arg] res_ty) 
  = ASSERT(isEnumerationTyCon tycon)
    do	{ (_rep,amode) <- getArgAmode arg
	; amode' <- assignTemp amode	-- We're going to use it twice,
					-- so save in a temp if non-trivial
	; stmtC (CmmAssign nodeReg (tagToClosure tycon amode'))
	; performReturn $ emitReturnInstr (Just [node]) }
   where
	  -- If you're reading this code in the attempt to figure
	  -- out why the compiler panic'ed here, it is probably because
	  -- you used tagToEnum# in a non-monomorphic setting, e.g., 
	  --         intToTg :: Enum a => Int -> a ; intToTg (I# x#) = tagToEnum# x#
	  -- That won't work.
	tycon = tyConAppTyCon res_ty


cgExpr (StgOpApp (StgPrimOp SeqOp) [StgVarArg a, _] _res_ty)
  = cgTailCall a []
  -- seq# :: a -> State# -> (# State# , a #)
  -- but the return convention for (# State#, a #) is exactly the same as
  -- for just a, so we can implment seq# by
  --   seq# a s  ==>  a

cgExpr (StgOpApp (StgPrimOp primop) args res_ty)
  | primOpOutOfLine primop
	= tailCallPrimOp primop args

  | ReturnsPrim VoidRep <- result_info
	= do cgPrimOp [] primop args emptyVarSet
             -- ToDo: STG Live -- worried about this
	     performReturn $ emitReturnInstr (Just [])

  | ReturnsPrim rep <- result_info
	= do res <- newTemp (typeCmmType res_ty)
             cgPrimOp [res] primop args emptyVarSet
	     performPrimReturn (primRepToCgRep rep) (CmmReg (CmmLocal res))

  | ReturnsAlg tycon <- result_info, isUnboxedTupleTyCon tycon
	= do (reps, regs, _hints) <- newUnboxedTupleRegs res_ty
	     cgPrimOp regs primop args emptyVarSet{-no live vars-}
	     returnUnboxedTuple (zip reps (map (CmmReg . CmmLocal) regs))

  | ReturnsAlg tycon <- result_info, isEnumerationTyCon tycon
	-- c.f. cgExpr (...TagToEnumOp...)
	= do tag_reg <- newTemp bWord	-- The tag is a word
	     cgPrimOp [tag_reg] primop args emptyVarSet
	     stmtC (CmmAssign nodeReg
                    (tagToClosure tycon
                     (CmmReg (CmmLocal tag_reg))))
             -- ToDo: STG Live -- worried about this
	     performReturn $ emitReturnInstr (Just [node])
  where
	result_info = getPrimOpResultInfo primop

cgExpr (StgOpApp (StgPrimCallOp primcall) args _res_ty)
  = tailCallPrimCall primcall args
\end{code}

%********************************************************
%*							*
%*		Case expressions			*
%*							*
%********************************************************
Case-expression conversion is complicated enough to have its own
module, @CgCase@.
\begin{code}

cgExpr (StgCase expr live_vars save_vars bndr srt alt_type alts)
  = setSRT srt $ cgCase expr live_vars save_vars bndr alt_type alts
\end{code}


%********************************************************
%*							*
%* 		Let and letrec				*
%*							*
%********************************************************
\subsection[let-and-letrec-codegen]{Converting @StgLet@ and @StgLetrec@}

\begin{code}
cgExpr (StgLet (StgNonRec name rhs) expr)
  = cgRhs name rhs	`thenFC` \ (name, info) ->
    addBindC name info 	`thenC`
    cgExpr expr

cgExpr (StgLet (StgRec pairs) expr)
  = fixC (\ new_bindings -> addBindsC new_bindings `thenC`
			    listFCs [ cgRhs b e | (b,e) <- pairs ]
    ) `thenFC` \ new_bindings ->

    addBindsC new_bindings `thenC`
    cgExpr expr
\end{code}

\begin{code}
cgExpr (StgLetNoEscape live_in_whole_let live_in_rhss bindings body)
  = do	{  	-- Figure out what volatile variables to save
	; nukeDeadBindings live_in_whole_let
	; (save_assts, rhs_eob_info, maybe_cc_slot) 
		<- saveVolatileVarsAndRegs live_in_rhss

	-- Save those variables right now!
	; emitStmts save_assts

	-- Produce code for the rhss
	-- and add suitable bindings to the environment
	; cgLetNoEscapeBindings live_in_rhss rhs_eob_info 
			 	maybe_cc_slot bindings

	-- Do the body
	; setEndOfBlockInfo rhs_eob_info (cgExpr body) }
\end{code}


%********************************************************
%*							*
%*		SCC Expressions				*
%*							*
%********************************************************

SCC expressions are treated specially. They set the current cost
centre.

\begin{code}
cgExpr (StgSCC cc tick push expr) = do emitSetCCC cc tick push; cgExpr expr
\end{code}

%********************************************************
%*                                                     *
%*             Hpc Tick Boxes                          *
%*                                                     *
%********************************************************

\begin{code}
cgExpr (StgTick m n expr) = do cgTickBox m n; cgExpr expr
\end{code}

%********************************************************
%*                                                     *
%*             Anything else                           *
%*                                                     *
%********************************************************

\begin{code}
cgExpr _ = panic "cgExpr"
\end{code}

%********************************************************
%*							*
%*		Non-top-level bindings			*
%*							*
%********************************************************
\subsection[non-top-level-bindings]{Converting non-top-level bindings}

We rely on the support code in @CgCon@ (to do constructors) and
in @CgClosure@ (to do closures).

\begin{code}
cgRhs :: Id -> StgRhs -> FCode (Id, CgIdInfo)
	-- the Id is passed along so a binding can be set up

cgRhs name (StgRhsCon maybe_cc con args)
  = do	{ amodes <- getArgAmodes args
	; idinfo <- buildDynCon name maybe_cc con amodes
	; returnFC (name, idinfo) }

cgRhs name (StgRhsClosure cc bi fvs upd_flag srt args body)
  = setSRT srt $ mkRhsClosure name cc bi fvs upd_flag args body
\end{code}

mkRhsClosure looks for two special forms of the right-hand side:
	a) selector thunks.
	b) AP thunks

If neither happens, it just calls mkClosureLFInfo.  You might think
that mkClosureLFInfo should do all this, but it seems wrong for the
latter to look at the structure of an expression

Selectors
~~~~~~~~~
We look at the body of the closure to see if it's a selector---turgid,
but nothing deep.  We are looking for a closure of {\em exactly} the
form:

...  = [the_fv] \ u [] ->
	 case the_fv of
	   con a_1 ... a_n -> a_i


\begin{code}
mkRhsClosure :: Id -> CostCentreStack -> StgBinderInfo
             -> [Id] -> UpdateFlag -> [Id] -> GenStgExpr Id Id
             -> FCode (Id, CgIdInfo)
mkRhsClosure	bndr cc bi
		[the_fv]   		-- Just one free var
		upd_flag		-- Updatable thunk
		[]			-- A thunk
		body@(StgCase (StgApp scrutinee [{-no args-}])
		      _ _ _ srt   -- ignore uniq, etc.
		      (AlgAlt _)
		      [(DataAlt con, params, _use_mask,
			    (StgApp selectee [{-no args-}]))])
  |  the_fv == scrutinee		-- Scrutinee is the only free variable
  && maybeToBool maybe_offset		-- Selectee is a component of the tuple
  && offset_into_int <= mAX_SPEC_SELECTEE_SIZE	-- Offset is small enough
  = -- NOT TRUE: ASSERT(is_single_constructor)
    -- The simplifier may have statically determined that the single alternative
    -- is the only possible case and eliminated the others, even if there are
    -- other constructors in the datatype.  It's still ok to make a selector
    -- thunk in this case, because we *know* which constructor the scrutinee
    -- will evaluate to.
    setSRT srt $ cgStdRhsClosure bndr cc bi [the_fv] [] body lf_info [StgVarArg the_fv]
  where
    lf_info 		  = mkSelectorLFInfo bndr offset_into_int
				 (isUpdatable upd_flag)
    (_, params_w_offsets) = layOutDynConstr con (addIdReps params)
			-- Just want the layout
    maybe_offset	  = assocMaybe params_w_offsets selectee
    Just the_offset 	  = maybe_offset
    offset_into_int       = the_offset - fixedHdrSize
\end{code}

Ap thunks
~~~~~~~~~

A more generic AP thunk of the form

	x = [ x_1...x_n ] \.. [] -> x_1 ... x_n

A set of these is compiled statically into the RTS, so we just use
those.  We could extend the idea to thunks where some of the x_i are
global ids (and hence not free variables), but this would entail
generating a larger thunk.  It might be an option for non-optimising
compilation, though.

We only generate an Ap thunk if all the free variables are pointers,
for semi-obvious reasons.

\begin{code}
mkRhsClosure    bndr cc bi
		fvs
		upd_flag
		[]			-- No args; a thunk
		body@(StgApp fun_id args)

  | args `lengthIs` (arity-1)
 	&& all isFollowableArg (map idCgRep fvs) 
 	&& isUpdatable upd_flag
 	&& arity <= mAX_SPEC_AP_SIZE 
        && not opt_SccProfilingOn -- not when profiling: we don't want to
                                  -- lose information about this particular
                                  -- thunk (e.g. its type) (#949)

 		   -- Ha! an Ap thunk
	= cgStdRhsClosure bndr cc bi fvs [] body lf_info payload

   where
	lf_info = mkApLFInfo bndr upd_flag arity
	-- the payload has to be in the correct order, hence we can't
 	-- just use the fvs.
	payload = StgVarArg fun_id : args
	arity 	= length fvs
\end{code}

The default case
~~~~~~~~~~~~~~~~
\begin{code}
mkRhsClosure bndr cc bi fvs upd_flag args body
  = cgRhsClosure bndr cc bi fvs upd_flag args body
\end{code}


%********************************************************
%*							*
%*		Let-no-escape bindings
%*							*
%********************************************************
\begin{code}
cgLetNoEscapeBindings :: StgLiveVars -> EndOfBlockInfo
                      -> Maybe VirtualSpOffset -> GenStgBinding Id Id
                      -> Code
cgLetNoEscapeBindings live_in_rhss rhs_eob_info maybe_cc_slot 
	(StgNonRec binder rhs)
  = do	{ (binder,info) <- cgLetNoEscapeRhs live_in_rhss rhs_eob_info 
					    maybe_cc_slot 	
					    NonRecursive binder rhs 
	; addBindC binder info }

cgLetNoEscapeBindings live_in_rhss rhs_eob_info maybe_cc_slot (StgRec pairs)
  = do	{ new_bindings <- fixC (\ new_bindings -> do
		{ addBindsC new_bindings
		; listFCs [ cgLetNoEscapeRhs full_live_in_rhss 
				rhs_eob_info maybe_cc_slot Recursive b e 
			  | (b,e) <- pairs ] })

	; addBindsC new_bindings }
  where
    -- We add the binders to the live-in-rhss set so that we don't
    -- delete the bindings for the binder from the environment!
    full_live_in_rhss = live_in_rhss `unionVarSet` (mkVarSet [b | (b,_) <- pairs])

cgLetNoEscapeRhs
    :: StgLiveVars	-- Live in rhss
    -> EndOfBlockInfo
    -> Maybe VirtualSpOffset
    -> RecFlag
    -> Id
    -> StgRhs
    -> FCode (Id, CgIdInfo)

cgLetNoEscapeRhs full_live_in_rhss rhs_eob_info maybe_cc_slot rec binder
		 (StgRhsClosure cc bi _ _upd_flag srt args body)
  = -- We could check the update flag, but currently we don't switch it off
    -- for let-no-escaped things, so we omit the check too!
    -- case upd_flag of
    --     Updatable -> panic "cgLetNoEscapeRhs"	-- Nothing to update!
    --     other     -> cgLetNoEscapeClosure binder cc bi live_in_whole_let live_in_rhss args body
    setSRT srt $ cgLetNoEscapeClosure binder cc bi full_live_in_rhss rhs_eob_info
	maybe_cc_slot rec args body

-- For a constructor RHS we want to generate a single chunk of code which
-- can be jumped to from many places, which will return the constructor.
-- It's easy; just behave as if it was an StgRhsClosure with a ConApp inside!
cgLetNoEscapeRhs full_live_in_rhss rhs_eob_info maybe_cc_slot rec binder
    	    	 (StgRhsCon cc con args)
  = setSRT NoSRT $ cgLetNoEscapeClosure binder cc noBinderInfo{-safe-}
			 full_live_in_rhss rhs_eob_info maybe_cc_slot rec
	[] 	--No args; the binder is data structure, not a function
	(StgConApp con args)
\end{code}

Little helper for primitives that return unboxed tuples.

\begin{code}
newUnboxedTupleRegs :: Type -> FCode ([CgRep], [LocalReg], [ForeignHint])
newUnboxedTupleRegs res_ty =
   let
	ty_args = tyConAppArgs (repType res_ty)
	(reps,hints) = unzip [ (rep, typeForeignHint ty) | ty <- ty_args,
					   	    let rep = typeCgRep ty,
					 	    nonVoidArg rep ]
	make_new_temp rep = newTemp (argMachRep rep)
   in do
   regs <- mapM make_new_temp reps
   return (reps,regs,hints)
\end{code}