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