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