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