add comment
[ghc-hetmet.git] / compiler / cmm / CmmOpt.hs
1 {-# OPTIONS -w #-}
2 -- The above warning supression flag is a temporary kludge.
3 -- While working on this module you are encouraged to remove it and fix
4 -- any warnings in the module. See
5 --     http://hackage.haskell.org/trac/ghc/wiki/Commentary/CodingStyle#Warnings
6 -- for details
7
8 -----------------------------------------------------------------------------
9 --
10 -- Cmm optimisation
11 --
12 -- (c) The University of Glasgow 2006
13 --
14 -----------------------------------------------------------------------------
15
16 module CmmOpt (
17         cmmMiniInline,
18         cmmMachOpFold,
19         cmmLoopifyForC,
20  ) where
21
22 #include "HsVersions.h"
23
24 import Cmm
25 import CmmExpr
26 import CmmUtils
27 import CLabel
28 import MachOp
29 import StaticFlags
30
31 import UniqFM
32 import Unique
33
34 import Outputable
35
36 import Data.Bits
37 import Data.Word
38 import Data.Int
39 import GHC.Exts
40
41 -- -----------------------------------------------------------------------------
42 -- The mini-inliner
43
44 {-
45 This pass inlines assignments to temporaries that are used just
46 once.  It works as follows:
47
48   - count uses of each temporary
49   - for each temporary that occurs just once:
50         - attempt to push it forward to the statement that uses it
51         - only push forward past assignments to other temporaries
52           (assumes that temporaries are single-assignment)
53         - if we reach the statement that uses it, inline the rhs
54           and delete the original assignment.
55
56 [N.B. In the Quick C-- compiler, this optimization is achieved by a
57  combination of two dataflow passes: forward substitution (peephole
58  optimization) and dead-assignment elimination.  ---NR]
59
60 Possible generalisations: here is an example from factorial
61
62 Fac_zdwfac_entry:
63     cmG:
64         _smi = R2;
65         if (_smi != 0) goto cmK;
66         R1 = R3;
67         jump I64[Sp];
68     cmK:
69         _smn = _smi * R3;
70         R2 = _smi + (-1);
71         R3 = _smn;
72         jump Fac_zdwfac_info;
73
74 We want to inline _smi and _smn.  To inline _smn:
75
76    - we must be able to push forward past assignments to global regs.
77      We can do this if the rhs of the assignment we are pushing
78      forward doesn't refer to the global reg being assigned to; easy
79      to test.
80
81 To inline _smi:
82
83    - It is a trivial replacement, reg for reg, but it occurs more than
84      once.
85    - We can inline trivial assignments even if the temporary occurs
86      more than once, as long as we don't eliminate the original assignment
87      (this doesn't help much on its own).
88    - We need to be able to propagate the assignment forward through jumps;
89      if we did this, we would find that it can be inlined safely in all
90      its occurrences.
91 -}
92
93 countUses :: UserOfLocalRegs a => a -> UniqFM Int
94 countUses a = foldRegsUsed (\m r -> addToUFM m r (count m r + 1)) emptyUFM a
95   where count m r = lookupWithDefaultUFM m (0::Int) r
96
97 cmmMiniInline :: [CmmBasicBlock] -> [CmmBasicBlock]
98 cmmMiniInline blocks = map do_inline blocks 
99   where do_inline (BasicBlock id stmts)
100           = BasicBlock id (cmmMiniInlineStmts (countUses blocks) stmts)
101
102 cmmMiniInlineStmts :: UniqFM Int -> [CmmStmt] -> [CmmStmt]
103 cmmMiniInlineStmts uses [] = []
104 cmmMiniInlineStmts uses (stmt@(CmmAssign (CmmLocal (LocalReg u _ _)) expr) : stmts)
105   | Just 1 <- lookupUFM uses u,
106     Just stmts' <- lookForInline u expr stmts
107   = 
108 #ifdef NCG_DEBUG
109      trace ("nativeGen: inlining " ++ showSDoc (pprStmt stmt)) $
110 #endif
111      cmmMiniInlineStmts uses stmts'
112
113 cmmMiniInlineStmts uses (stmt:stmts)
114   = stmt : cmmMiniInlineStmts uses stmts
115
116
117 -- Try to inline a temporary assignment.  We can skip over assignments to
118 -- other tempoararies, because we know that expressions aren't side-effecting
119 -- and temporaries are single-assignment.
120 lookForInline u expr (stmt@(CmmAssign (CmmLocal (LocalReg u' _ _)) rhs) : rest)
121   | u /= u' 
122   = case lookupUFM (countUses rhs) u of
123         Just 1 -> Just (inlineStmt u expr stmt : rest)
124         _other -> case lookForInline u expr rest of
125                      Nothing    -> Nothing
126                      Just stmts -> Just (stmt:stmts)
127
128 lookForInline u expr (CmmNop : rest)
129   = lookForInline u expr rest
130
131 lookForInline _ _ [] = Nothing
132
133 lookForInline u expr (stmt:stmts)
134   = case lookupUFM (countUses stmt) u of
135         Just 1 | ok_to_inline -> Just (inlineStmt u expr stmt : stmts)
136         _other -> Nothing
137   where
138         -- we don't inline into CmmCall if the expression refers to global
139         -- registers.  This is a HACK to avoid global registers clashing with
140         -- C argument-passing registers, really the back-end ought to be able
141         -- to handle it properly, but currently neither PprC nor the NCG can
142         -- do it.  See also CgForeignCall:load_args_into_temps.
143     ok_to_inline = case stmt of
144                      CmmCall{} -> hasNoGlobalRegs expr
145                      _ -> True
146
147 inlineStmt :: Unique -> CmmExpr -> CmmStmt -> CmmStmt
148 inlineStmt u a (CmmAssign r e) = CmmAssign r (inlineExpr u a e)
149 inlineStmt u a (CmmStore e1 e2) = CmmStore (inlineExpr u a e1) (inlineExpr u a e2)
150 inlineStmt u a (CmmCall target regs es srt ret)
151    = CmmCall (infn target) regs es' srt ret
152    where infn (CmmCallee fn cconv) = CmmCallee fn cconv
153          infn (CmmPrim p) = CmmPrim p
154          es' = [ (inlineExpr u a e, hint) | (e,hint) <- es ]
155 inlineStmt u a (CmmCondBranch e d) = CmmCondBranch (inlineExpr u a e) d
156 inlineStmt u a (CmmSwitch e d) = CmmSwitch (inlineExpr u a e) d
157 inlineStmt u a (CmmJump e d) = CmmJump (inlineExpr u a e) d
158 inlineStmt u a other_stmt = other_stmt
159
160 inlineExpr :: Unique -> CmmExpr -> CmmExpr -> CmmExpr
161 inlineExpr u a e@(CmmReg (CmmLocal (LocalReg u' _ _)))
162   | u == u' = a
163   | otherwise = e
164 inlineExpr u a e@(CmmRegOff (CmmLocal (LocalReg u' rep _)) off)
165   | u == u' = CmmMachOp (MO_Add rep) [a, CmmLit (CmmInt (fromIntegral off) rep)]
166   | otherwise = e
167 inlineExpr u a (CmmLoad e rep) = CmmLoad (inlineExpr u a e) rep
168 inlineExpr u a (CmmMachOp op es) = CmmMachOp op (map (inlineExpr u a) es)
169 inlineExpr u a other_expr = other_expr
170
171 -- -----------------------------------------------------------------------------
172 -- MachOp constant folder
173
174 -- Now, try to constant-fold the MachOps.  The arguments have already
175 -- been optimized and folded.
176
177 cmmMachOpFold
178     :: MachOp           -- The operation from an CmmMachOp
179     -> [CmmExpr]        -- The optimized arguments
180     -> CmmExpr
181
182 cmmMachOpFold op arg@[CmmLit (CmmInt x rep)]
183   = case op of
184       MO_S_Neg r -> CmmLit (CmmInt (-x) rep)
185       MO_Not r   -> CmmLit (CmmInt (complement x) rep)
186
187         -- these are interesting: we must first narrow to the 
188         -- "from" type, in order to truncate to the correct size.
189         -- The final narrow/widen to the destination type
190         -- is implicit in the CmmLit.
191       MO_S_Conv from to
192            | isFloatingRep to -> CmmLit (CmmFloat (fromInteger x) to)
193            | otherwise        -> CmmLit (CmmInt (narrowS from x) to)
194       MO_U_Conv from to -> CmmLit (CmmInt (narrowU from x) to)
195
196       _ -> panic "cmmMachOpFold: unknown unary op"
197
198
199 -- Eliminate conversion NOPs
200 cmmMachOpFold (MO_S_Conv rep1 rep2) [x] | rep1 == rep2 = x
201 cmmMachOpFold (MO_U_Conv rep1 rep2) [x] | rep1 == rep2 = x
202
203 -- Eliminate nested conversions where possible
204 cmmMachOpFold conv_outer args@[CmmMachOp conv_inner [x]]
205   | Just (rep1,rep2,signed1) <- isIntConversion conv_inner,
206     Just (_,   rep3,signed2) <- isIntConversion conv_outer
207   = case () of
208         -- widen then narrow to the same size is a nop
209       _ | rep1 < rep2 && rep1 == rep3 -> x
210         -- Widen then narrow to different size: collapse to single conversion
211         -- but remember to use the signedness from the widening, just in case
212         -- the final conversion is a widen.
213         | rep1 < rep2 && rep2 > rep3 ->
214             cmmMachOpFold (intconv signed1 rep1 rep3) [x]
215         -- Nested widenings: collapse if the signedness is the same
216         | rep1 < rep2 && rep2 < rep3 && signed1 == signed2 ->
217             cmmMachOpFold (intconv signed1 rep1 rep3) [x]
218         -- Nested narrowings: collapse
219         | rep1 > rep2 && rep2 > rep3 ->
220             cmmMachOpFold (MO_U_Conv rep1 rep3) [x]
221         | otherwise ->
222             CmmMachOp conv_outer args
223   where
224         isIntConversion (MO_U_Conv rep1 rep2) 
225           | not (isFloatingRep rep1) && not (isFloatingRep rep2) 
226           = Just (rep1,rep2,False)
227         isIntConversion (MO_S_Conv rep1 rep2)
228           | not (isFloatingRep rep1) && not (isFloatingRep rep2) 
229           = Just (rep1,rep2,True)
230         isIntConversion _ = Nothing
231
232         intconv True  = MO_S_Conv
233         intconv False = MO_U_Conv
234
235 -- ToDo: a narrow of a load can be collapsed into a narrow load, right?
236 -- but what if the architecture only supports word-sized loads, should
237 -- we do the transformation anyway?
238
239 cmmMachOpFold mop args@[CmmLit (CmmInt x xrep), CmmLit (CmmInt y _)]
240   = case mop of
241         -- for comparisons: don't forget to narrow the arguments before
242         -- comparing, since they might be out of range.
243         MO_Eq r   -> CmmLit (CmmInt (if x_u == y_u then 1 else 0) wordRep)
244         MO_Ne r   -> CmmLit (CmmInt (if x_u /= y_u then 1 else 0) wordRep)
245
246         MO_U_Gt r -> CmmLit (CmmInt (if x_u >  y_u then 1 else 0) wordRep)
247         MO_U_Ge r -> CmmLit (CmmInt (if x_u >= y_u then 1 else 0) wordRep)
248         MO_U_Lt r -> CmmLit (CmmInt (if x_u <  y_u then 1 else 0) wordRep)
249         MO_U_Le r -> CmmLit (CmmInt (if x_u <= y_u then 1 else 0) wordRep)
250
251         MO_S_Gt r -> CmmLit (CmmInt (if x_s >  y_s then 1 else 0) wordRep) 
252         MO_S_Ge r -> CmmLit (CmmInt (if x_s >= y_s then 1 else 0) wordRep)
253         MO_S_Lt r -> CmmLit (CmmInt (if x_s <  y_s then 1 else 0) wordRep)
254         MO_S_Le r -> CmmLit (CmmInt (if x_s <= y_s then 1 else 0) wordRep)
255
256         MO_Add r -> CmmLit (CmmInt (x + y) r)
257         MO_Sub r -> CmmLit (CmmInt (x - y) r)
258         MO_Mul r -> CmmLit (CmmInt (x * y) r)
259         MO_S_Quot r | y /= 0 -> CmmLit (CmmInt (x `quot` y) r)
260         MO_S_Rem  r | y /= 0 -> CmmLit (CmmInt (x `rem` y) r)
261
262         MO_And   r -> CmmLit (CmmInt (x .&. y) r)
263         MO_Or    r -> CmmLit (CmmInt (x .|. y) r)
264         MO_Xor   r -> CmmLit (CmmInt (x `xor` y) r)
265
266         MO_Shl   r -> CmmLit (CmmInt (x `shiftL` fromIntegral y) r)
267         MO_U_Shr r -> CmmLit (CmmInt (x_u `shiftR` fromIntegral y) r)
268         MO_S_Shr r -> CmmLit (CmmInt (x `shiftR` fromIntegral y) r)
269
270         other      -> CmmMachOp mop args
271
272    where
273         x_u = narrowU xrep x
274         y_u = narrowU xrep y
275         x_s = narrowS xrep x
276         y_s = narrowS xrep y
277         
278
279 -- When possible, shift the constants to the right-hand side, so that we
280 -- can match for strength reductions.  Note that the code generator will
281 -- also assume that constants have been shifted to the right when
282 -- possible.
283
284 cmmMachOpFold op [x@(CmmLit _), y]
285    | not (isLit y) && isCommutableMachOp op 
286    = cmmMachOpFold op [y, x]
287
288 -- Turn (a+b)+c into a+(b+c) where possible.  Because literals are
289 -- moved to the right, it is more likely that we will find
290 -- opportunities for constant folding when the expression is
291 -- right-associated.
292 --
293 -- ToDo: this appears to introduce a quadratic behaviour due to the
294 -- nested cmmMachOpFold.  Can we fix this?
295 --
296 -- Why do we check isLit arg1?  If arg1 is a lit, it means that arg2
297 -- is also a lit (otherwise arg1 would be on the right).  If we
298 -- put arg1 on the left of the rearranged expression, we'll get into a
299 -- loop:  (x1+x2)+x3 => x1+(x2+x3)  => (x2+x3)+x1 => x2+(x3+x1) ...
300 --
301 -- Also don't do it if arg1 is PicBaseReg, so that we don't separate the
302 -- PicBaseReg from the corresponding label (or label difference).
303 --
304 cmmMachOpFold mop1 [CmmMachOp mop2 [arg1,arg2], arg3]
305    | mop1 == mop2 && isAssociativeMachOp mop1
306      && not (isLit arg1) && not (isPicReg arg1)
307    = cmmMachOpFold mop1 [arg1, cmmMachOpFold mop2 [arg2,arg3]]
308
309 -- Make a RegOff if we can
310 cmmMachOpFold (MO_Add _) [CmmReg reg, CmmLit (CmmInt n rep)]
311   = CmmRegOff reg (fromIntegral (narrowS rep n))
312 cmmMachOpFold (MO_Add _) [CmmRegOff reg off, CmmLit (CmmInt n rep)]
313   = CmmRegOff reg (off + fromIntegral (narrowS rep n))
314 cmmMachOpFold (MO_Sub _) [CmmReg reg, CmmLit (CmmInt n rep)]
315   = CmmRegOff reg (- fromIntegral (narrowS rep n))
316 cmmMachOpFold (MO_Sub _) [CmmRegOff reg off, CmmLit (CmmInt n rep)]
317   = CmmRegOff reg (off - fromIntegral (narrowS rep n))
318
319 -- Fold label(+/-)offset into a CmmLit where possible
320
321 cmmMachOpFold (MO_Add _) [CmmLit (CmmLabel lbl), CmmLit (CmmInt i rep)]
322   = CmmLit (CmmLabelOff lbl (fromIntegral (narrowU rep i)))
323 cmmMachOpFold (MO_Add _) [CmmLit (CmmInt i rep), CmmLit (CmmLabel lbl)]
324   = CmmLit (CmmLabelOff lbl (fromIntegral (narrowU rep i)))
325 cmmMachOpFold (MO_Sub _) [CmmLit (CmmLabel lbl), CmmLit (CmmInt i rep)]
326   = CmmLit (CmmLabelOff lbl (fromIntegral (negate (narrowU rep i))))
327
328
329 -- Comparison of literal with narrowed/widened operand: perform
330 -- the comparison at a different width, as long as the literal is
331 -- within range.
332
333 #if i386_TARGET_ARCH || x86_64_TARGET_ARCH
334 -- powerPC NCG has a TODO for I8/I16 comparisons, so don't try
335
336 cmmMachOpFold cmp [CmmMachOp conv [x], CmmLit (CmmInt i _)]
337   | Just (rep, narrow) <- maybe_conversion conv,
338     Just narrow_cmp <- maybe_comparison cmp rep,
339     let narrow_i = narrow rep i,
340     narrow_i == i
341   = cmmMachOpFold narrow_cmp [x, CmmLit (CmmInt narrow_i rep)]
342  where
343     maybe_conversion (MO_U_Conv from _) = Just (from, narrowU)
344     maybe_conversion (MO_S_Conv from _)
345         | not (isFloatingRep from) = Just (from, narrowS)
346         -- don't attempt to apply this optimisation when the source
347         -- is a float; see #1916
348     maybe_conversion _ = Nothing
349     
350     maybe_comparison (MO_U_Gt _) rep = Just (MO_U_Gt rep)
351     maybe_comparison (MO_U_Ge _) rep = Just (MO_U_Ge rep)
352     maybe_comparison (MO_U_Lt _) rep = Just (MO_U_Lt rep)
353     maybe_comparison (MO_U_Le _) rep = Just (MO_U_Le rep)
354     maybe_comparison (MO_S_Gt _) rep = Just (MO_S_Gt rep)
355     maybe_comparison (MO_S_Ge _) rep = Just (MO_S_Ge rep)
356     maybe_comparison (MO_S_Lt _) rep = Just (MO_S_Lt rep)
357     maybe_comparison (MO_S_Le _) rep = Just (MO_S_Le rep)
358     maybe_comparison (MO_Eq   _) rep = Just (MO_Eq   rep)
359     maybe_comparison _ _ = Nothing
360
361 #endif
362
363 -- We can often do something with constants of 0 and 1 ...
364
365 cmmMachOpFold mop args@[x, y@(CmmLit (CmmInt 0 _))]
366   = case mop of
367         MO_Add   r -> x
368         MO_Sub   r -> x
369         MO_Mul   r -> y
370         MO_And   r -> y
371         MO_Or    r -> x
372         MO_Xor   r -> x
373         MO_Shl   r -> x
374         MO_S_Shr r -> x
375         MO_U_Shr r -> x
376         MO_Ne    r | isComparisonExpr x -> x
377         MO_Eq    r | Just x' <- maybeInvertCmmExpr x -> x'
378         MO_U_Gt  r | isComparisonExpr x -> x
379         MO_S_Gt  r | isComparisonExpr x -> x
380         MO_U_Lt  r | isComparisonExpr x -> CmmLit (CmmInt 0 wordRep)
381         MO_S_Lt  r | isComparisonExpr x -> CmmLit (CmmInt 0 wordRep)
382         MO_U_Ge  r | isComparisonExpr x -> CmmLit (CmmInt 1 wordRep)
383         MO_S_Ge  r | isComparisonExpr x -> CmmLit (CmmInt 1 wordRep)
384         MO_U_Le  r | Just x' <- maybeInvertCmmExpr x -> x'
385         MO_S_Le  r | Just x' <- maybeInvertCmmExpr x -> x'
386         other    -> CmmMachOp mop args
387
388 cmmMachOpFold mop args@[x, y@(CmmLit (CmmInt 1 rep))]
389   = case mop of
390         MO_Mul    r -> x
391         MO_S_Quot r -> x
392         MO_U_Quot r -> x
393         MO_S_Rem  r -> CmmLit (CmmInt 0 rep)
394         MO_U_Rem  r -> CmmLit (CmmInt 0 rep)
395         MO_Ne    r | Just x' <- maybeInvertCmmExpr x -> x'
396         MO_Eq    r | isComparisonExpr x -> x
397         MO_U_Lt  r | Just x' <- maybeInvertCmmExpr x -> x'
398         MO_S_Lt  r | Just x' <- maybeInvertCmmExpr x -> x'
399         MO_U_Gt  r | isComparisonExpr x -> CmmLit (CmmInt 0 wordRep)
400         MO_S_Gt  r | isComparisonExpr x -> CmmLit (CmmInt 0 wordRep)
401         MO_U_Le  r | isComparisonExpr x -> CmmLit (CmmInt 1 wordRep)
402         MO_S_Le  r | isComparisonExpr x -> CmmLit (CmmInt 1 wordRep)
403         MO_U_Ge  r | isComparisonExpr x -> x
404         MO_S_Ge  r | isComparisonExpr x -> x
405         other       -> CmmMachOp mop args
406
407 -- Now look for multiplication/division by powers of 2 (integers).
408
409 cmmMachOpFold mop args@[x, y@(CmmLit (CmmInt n _))]
410   = case mop of
411         MO_Mul rep
412            | Just p <- exactLog2 n ->
413                  CmmMachOp (MO_Shl rep) [x, CmmLit (CmmInt p rep)]
414         MO_S_Quot rep
415            | Just p <- exactLog2 n, 
416              CmmReg _ <- x ->   -- We duplicate x below, hence require
417                                 -- it is a reg.  FIXME: remove this restriction.
418                 -- shift right is not the same as quot, because it rounds
419                 -- to minus infinity, whereasq uot rounds toward zero.
420                 -- To fix this up, we add one less than the divisor to the
421                 -- dividend if it is a negative number.
422                 --
423                 -- to avoid a test/jump, we use the following sequence:
424                 --      x1 = x >> word_size-1  (all 1s if -ve, all 0s if +ve)
425                 --      x2 = y & (divisor-1)
426                 --      result = (x+x2) >>= log2(divisor)
427                 -- this could be done a bit more simply using conditional moves,
428                 -- but we're processor independent here.
429                 --
430                 -- we optimise the divide by 2 case slightly, generating
431                 --      x1 = x >> word_size-1  (unsigned)
432                 --      return = (x + x1) >>= log2(divisor)
433                 let 
434                     bits = fromIntegral (machRepBitWidth rep) - 1
435                     shr = if p == 1 then MO_U_Shr rep else MO_S_Shr rep
436                     x1 = CmmMachOp shr [x, CmmLit (CmmInt bits rep)]
437                     x2 = if p == 1 then x1 else
438                          CmmMachOp (MO_And rep) [x1, CmmLit (CmmInt (n-1) rep)]
439                     x3 = CmmMachOp (MO_Add rep) [x, x2]
440                 in
441                 CmmMachOp (MO_S_Shr rep) [x3, CmmLit (CmmInt p rep)]
442         other
443            -> unchanged
444     where
445        unchanged = CmmMachOp mop args
446
447 -- Anything else is just too hard.
448
449 cmmMachOpFold mop args = CmmMachOp mop args
450
451 -- -----------------------------------------------------------------------------
452 -- exactLog2
453
454 -- This algorithm for determining the $\log_2$ of exact powers of 2 comes
455 -- from GCC.  It requires bit manipulation primitives, and we use GHC
456 -- extensions.  Tough.
457 -- 
458 -- Used to be in MachInstrs --SDM.
459 -- ToDo: remove use of unboxery --SDM.
460
461 w2i x = word2Int# x
462 i2w x = int2Word# x
463
464 exactLog2 :: Integer -> Maybe Integer
465 exactLog2 x
466   = if (x <= 0 || x >= 2147483648) then
467        Nothing
468     else
469        case fromInteger x of { I# x# ->
470        if (w2i ((i2w x#) `and#` (i2w (0# -# x#))) /=# x#) then
471           Nothing
472        else
473           Just (toInteger (I# (pow2 x#)))
474        }
475   where
476     pow2 x# | x# ==# 1# = 0#
477             | otherwise = 1# +# pow2 (w2i (i2w x# `shiftRL#` 1#))
478
479
480 -- -----------------------------------------------------------------------------
481 -- widening / narrowing
482
483 narrowU :: MachRep -> Integer -> Integer
484 narrowU I8  x = fromIntegral (fromIntegral x :: Word8)
485 narrowU I16 x = fromIntegral (fromIntegral x :: Word16)
486 narrowU I32 x = fromIntegral (fromIntegral x :: Word32)
487 narrowU I64 x = fromIntegral (fromIntegral x :: Word64)
488 narrowU _ _ = panic "narrowTo"
489
490 narrowS :: MachRep -> Integer -> Integer
491 narrowS I8  x = fromIntegral (fromIntegral x :: Int8)
492 narrowS I16 x = fromIntegral (fromIntegral x :: Int16)
493 narrowS I32 x = fromIntegral (fromIntegral x :: Int32)
494 narrowS I64 x = fromIntegral (fromIntegral x :: Int64)
495 narrowS _ _ = panic "narrowTo"
496
497 -- -----------------------------------------------------------------------------
498 -- Loopify for C
499
500 {-
501  This is a simple pass that replaces tail-recursive functions like this:
502
503    fac() {
504      ...
505      jump fac();
506    }
507
508  with this:
509
510   fac() {
511    L:
512      ...
513      goto L;
514   }
515
516   the latter generates better C code, because the C compiler treats it
517   like a loop, and brings full loop optimisation to bear.
518
519   In my measurements this makes little or no difference to anything
520   except factorial, but what the hell.
521 -}
522
523 cmmLoopifyForC :: RawCmmTop -> RawCmmTop
524 cmmLoopifyForC p@(CmmProc info entry_lbl [] (ListGraph blocks@(BasicBlock top_id _ : _)))
525   | null info = p  -- only if there's an info table, ignore case alts
526   | otherwise =  
527 --  pprTrace "jump_lbl" (ppr jump_lbl <+> ppr entry_lbl) $
528   CmmProc info entry_lbl [] (ListGraph blocks')
529   where blocks' = [ BasicBlock id (map do_stmt stmts)
530                   | BasicBlock id stmts <- blocks ]
531
532         do_stmt (CmmJump (CmmLit (CmmLabel lbl)) _) | lbl == jump_lbl
533                 = CmmBranch top_id
534         do_stmt stmt = stmt
535
536         jump_lbl | tablesNextToCode = entryLblToInfoLbl entry_lbl
537                  | otherwise        = entry_lbl
538
539 cmmLoopifyForC top = top
540
541 -- -----------------------------------------------------------------------------
542 -- Utils
543
544 isLit (CmmLit _) = True
545 isLit _          = False
546
547 isComparisonExpr :: CmmExpr -> Bool
548 isComparisonExpr (CmmMachOp op _) = isComparisonMachOp op
549 isComparisonExpr _other             = False
550
551 isPicReg (CmmReg (CmmGlobal PicBaseReg)) = True
552 isPicReg _ = False
553
554 _unused :: FS.FastString -- stops a warning
555 _unused = undefined