Ignore comments when inlining.
[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 OldCmm
25 import CmmUtils
26 import CLabel
27 import StaticFlags
28
29 import UniqFM
30 import Unique
31 import FastTypes
32 import Outputable
33
34 import Data.Bits
35 import Data.Word
36 import Data.Int
37
38 -- -----------------------------------------------------------------------------
39 -- The mini-inliner
40
41 {-
42 This pass inlines assignments to temporaries that are used just
43 once.  It works as follows:
44
45   - count uses of each temporary
46   - for each temporary that occurs just once:
47         - attempt to push it forward to the statement that uses it
48         - only push forward past assignments to other temporaries
49           (assumes that temporaries are single-assignment)
50         - if we reach the statement that uses it, inline the rhs
51           and delete the original assignment.
52
53 [N.B. In the Quick C-- compiler, this optimization is achieved by a
54  combination of two dataflow passes: forward substitution (peephole
55  optimization) and dead-assignment elimination.  ---NR]
56
57 Possible generalisations: here is an example from factorial
58
59 Fac_zdwfac_entry:
60     cmG:
61         _smi = R2;
62         if (_smi != 0) goto cmK;
63         R1 = R3;
64         jump I64[Sp];
65     cmK:
66         _smn = _smi * R3;
67         R2 = _smi + (-1);
68         R3 = _smn;
69         jump Fac_zdwfac_info;
70
71 We want to inline _smi and _smn.  To inline _smn:
72
73    - we must be able to push forward past assignments to global regs.
74      We can do this if the rhs of the assignment we are pushing
75      forward doesn't refer to the global reg being assigned to; easy
76      to test.
77
78 To inline _smi:
79
80    - It is a trivial replacement, reg for reg, but it occurs more than
81      once.
82    - We can inline trivial assignments even if the temporary occurs
83      more than once, as long as we don't eliminate the original assignment
84      (this doesn't help much on its own).
85    - We need to be able to propagate the assignment forward through jumps;
86      if we did this, we would find that it can be inlined safely in all
87      its occurrences.
88 -}
89
90 countUses :: UserOfLocalRegs a => a -> UniqFM Int
91 countUses a = foldRegsUsed (\m r -> addToUFM m r (count m r + 1)) emptyUFM a
92   where count m r = lookupWithDefaultUFM m (0::Int) r
93
94 cmmMiniInline :: [CmmBasicBlock] -> [CmmBasicBlock]
95 cmmMiniInline blocks = map do_inline blocks 
96   where do_inline (BasicBlock id stmts)
97           = BasicBlock id (cmmMiniInlineStmts (countUses blocks) stmts)
98
99 cmmMiniInlineStmts :: UniqFM Int -> [CmmStmt] -> [CmmStmt]
100 cmmMiniInlineStmts uses [] = []
101 cmmMiniInlineStmts uses (stmt@(CmmAssign (CmmLocal (LocalReg u _)) expr) : stmts)
102         -- not used at all: just discard this assignment
103   | Nothing <- lookupUFM uses u
104   = cmmMiniInlineStmts uses stmts
105
106         -- used once: try to inline at the use site
107   | Just 1 <- lookupUFM uses u,
108     Just stmts' <- lookForInline u expr stmts
109   = 
110 #ifdef NCG_DEBUG
111      trace ("nativeGen: inlining " ++ showSDoc (pprStmt stmt)) $
112 #endif
113      cmmMiniInlineStmts uses stmts'
114
115 cmmMiniInlineStmts uses (stmt:stmts)
116   = stmt : cmmMiniInlineStmts uses stmts
117
118 lookForInline u expr (stmt : rest)
119   | Just 1 <- lookupUFM (countUses stmt) u, ok_to_inline
120   = Just (inlineStmt u expr stmt : rest)
121
122   | ok_to_skip
123   = case lookForInline u expr rest of
124            Nothing    -> Nothing
125            Just stmts -> Just (stmt:stmts)
126
127   | otherwise 
128   = Nothing
129
130   where
131         -- we don't inline into CmmCall if the expression refers to global
132         -- registers.  This is a HACK to avoid global registers clashing with
133         -- C argument-passing registers, really the back-end ought to be able
134         -- to handle it properly, but currently neither PprC nor the NCG can
135         -- do it.  See also CgForeignCall:load_args_into_temps.
136     ok_to_inline = case stmt of
137                      CmmCall{} -> hasNoGlobalRegs expr
138                      _ -> True
139
140    -- We can skip over assignments to other tempoararies, because we
141    -- know that expressions aren't side-effecting and temporaries are
142    -- single-assignment.
143     ok_to_skip = case stmt of
144                  CmmNop -> True
145                  CmmComment{} -> 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 (inlineExpr u a 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_U_Quot r | y /= 0 -> CmmLit (CmmInt (x_u `quot` y_u) r)
263         MO_U_Rem  r | y /= 0 -> CmmLit (CmmInt (x_u `rem`  y_u) 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    | mop2 `associates_with` mop1
311      && not (isLit arg1) && not (isPicReg arg1)
312    = cmmMachOpFold mop2 [arg1, cmmMachOpFold mop1 [arg2,arg3]]
313    where
314      MO_Add{} `associates_with` MO_Sub{} = True
315      mop1 `associates_with` mop2 =
316         mop1 == mop2 && isAssociativeMachOp mop1
317
318 -- special case: (a - b) + c  ==>  a + (c - b)
319 cmmMachOpFold mop1@(MO_Add{}) [CmmMachOp mop2@(MO_Sub{}) [arg1,arg2], arg3]
320    | not (isLit arg1) && not (isPicReg arg1)
321    = cmmMachOpFold mop1 [arg1, cmmMachOpFold mop2 [arg3,arg2]]
322
323 -- Make a RegOff if we can
324 cmmMachOpFold (MO_Add _) [CmmReg reg, CmmLit (CmmInt n rep)]
325   = CmmRegOff reg (fromIntegral (narrowS rep n))
326 cmmMachOpFold (MO_Add _) [CmmRegOff reg off, CmmLit (CmmInt n rep)]
327   = CmmRegOff reg (off + fromIntegral (narrowS rep n))
328 cmmMachOpFold (MO_Sub _) [CmmReg reg, CmmLit (CmmInt n rep)]
329   = CmmRegOff reg (- fromIntegral (narrowS rep n))
330 cmmMachOpFold (MO_Sub _) [CmmRegOff reg off, CmmLit (CmmInt n rep)]
331   = CmmRegOff reg (off - fromIntegral (narrowS rep n))
332
333 -- Fold label(+/-)offset into a CmmLit where possible
334
335 cmmMachOpFold (MO_Add _) [CmmLit (CmmLabel lbl), CmmLit (CmmInt i rep)]
336   = CmmLit (CmmLabelOff lbl (fromIntegral (narrowU rep i)))
337 cmmMachOpFold (MO_Add _) [CmmLit (CmmInt i rep), CmmLit (CmmLabel lbl)]
338   = CmmLit (CmmLabelOff lbl (fromIntegral (narrowU rep i)))
339 cmmMachOpFold (MO_Sub _) [CmmLit (CmmLabel lbl), CmmLit (CmmInt i rep)]
340   = CmmLit (CmmLabelOff lbl (fromIntegral (negate (narrowU rep i))))
341
342
343 -- Comparison of literal with widened operand: perform the comparison
344 -- at the smaller width, as long as the literal is within range.
345
346 -- We can't do the reverse trick, when the operand is narrowed:
347 -- narrowing throws away bits from the operand, there's no way to do
348 -- the same comparison at the larger size.
349
350 #if i386_TARGET_ARCH || x86_64_TARGET_ARCH
351 -- powerPC NCG has a TODO for I8/I16 comparisons, so don't try
352
353 cmmMachOpFold cmp [CmmMachOp conv [x], CmmLit (CmmInt i _)]
354   |     -- if the operand is widened:
355     Just (rep, signed, narrow_fn) <- maybe_conversion conv,
356         -- and this is a comparison operation:
357     Just narrow_cmp <- maybe_comparison cmp rep signed,
358         -- and the literal fits in the smaller size:
359     i == narrow_fn rep i
360         -- then we can do the comparison at the smaller size
361   = cmmMachOpFold narrow_cmp [x, CmmLit (CmmInt i rep)]
362  where
363     maybe_conversion (MO_UU_Conv from to)
364         | to > from
365         = Just (from, False, narrowU)
366     maybe_conversion (MO_SS_Conv from to)
367         | to > from
368         = Just (from, True, narrowS)
369
370         -- don't attempt to apply this optimisation when the source
371         -- is a float; see #1916
372     maybe_conversion _ = Nothing
373     
374         -- careful (#2080): if the original comparison was signed, but
375         -- we were doing an unsigned widen, then we must do an
376         -- unsigned comparison at the smaller size.
377     maybe_comparison (MO_U_Gt _) rep _     = Just (MO_U_Gt rep)
378     maybe_comparison (MO_U_Ge _) rep _     = Just (MO_U_Ge rep)
379     maybe_comparison (MO_U_Lt _) rep _     = Just (MO_U_Lt rep)
380     maybe_comparison (MO_U_Le _) rep _     = Just (MO_U_Le rep)
381     maybe_comparison (MO_Eq   _) rep _     = Just (MO_Eq   rep)
382     maybe_comparison (MO_S_Gt _) rep True  = Just (MO_S_Gt rep)
383     maybe_comparison (MO_S_Ge _) rep True  = Just (MO_S_Ge rep)
384     maybe_comparison (MO_S_Lt _) rep True  = Just (MO_S_Lt rep)
385     maybe_comparison (MO_S_Le _) rep True  = Just (MO_S_Le rep)
386     maybe_comparison (MO_S_Gt _) rep False = Just (MO_U_Gt rep)
387     maybe_comparison (MO_S_Ge _) rep False = Just (MO_U_Ge rep)
388     maybe_comparison (MO_S_Lt _) rep False = Just (MO_U_Lt rep)
389     maybe_comparison (MO_S_Le _) rep False = Just (MO_U_Le rep)
390     maybe_comparison _ _ _ = Nothing
391
392 #endif
393
394 -- We can often do something with constants of 0 and 1 ...
395
396 cmmMachOpFold mop args@[x, y@(CmmLit (CmmInt 0 _))]
397   = case mop of
398         MO_Add   r -> x
399         MO_Sub   r -> x
400         MO_Mul   r -> y
401         MO_And   r -> y
402         MO_Or    r -> x
403         MO_Xor   r -> x
404         MO_Shl   r -> x
405         MO_S_Shr r -> x
406         MO_U_Shr r -> x
407         MO_Ne    r | isComparisonExpr x -> x
408         MO_Eq    r | Just x' <- maybeInvertCmmExpr x -> x'
409         MO_U_Gt  r | isComparisonExpr x -> x
410         MO_S_Gt  r | isComparisonExpr x -> x
411         MO_U_Lt  r | isComparisonExpr x -> CmmLit (CmmInt 0 wordWidth)
412         MO_S_Lt  r | isComparisonExpr x -> CmmLit (CmmInt 0 wordWidth)
413         MO_U_Ge  r | isComparisonExpr x -> CmmLit (CmmInt 1 wordWidth)
414         MO_S_Ge  r | isComparisonExpr x -> CmmLit (CmmInt 1 wordWidth)
415         MO_U_Le  r | Just x' <- maybeInvertCmmExpr x -> x'
416         MO_S_Le  r | Just x' <- maybeInvertCmmExpr x -> x'
417         other    -> CmmMachOp mop args
418
419 cmmMachOpFold mop args@[x, y@(CmmLit (CmmInt 1 rep))]
420   = case mop of
421         MO_Mul    r -> x
422         MO_S_Quot r -> x
423         MO_U_Quot r -> x
424         MO_S_Rem  r -> CmmLit (CmmInt 0 rep)
425         MO_U_Rem  r -> CmmLit (CmmInt 0 rep)
426         MO_Ne    r | Just x' <- maybeInvertCmmExpr x -> x'
427         MO_Eq    r | isComparisonExpr x -> x
428         MO_U_Lt  r | Just x' <- maybeInvertCmmExpr x -> x'
429         MO_S_Lt  r | Just x' <- maybeInvertCmmExpr x -> x'
430         MO_U_Gt  r | isComparisonExpr x -> CmmLit (CmmInt 0 wordWidth)
431         MO_S_Gt  r | isComparisonExpr x -> CmmLit (CmmInt 0 wordWidth)
432         MO_U_Le  r | isComparisonExpr x -> CmmLit (CmmInt 1 wordWidth)
433         MO_S_Le  r | isComparisonExpr x -> CmmLit (CmmInt 1 wordWidth)
434         MO_U_Ge  r | isComparisonExpr x -> x
435         MO_S_Ge  r | isComparisonExpr x -> x
436         other       -> CmmMachOp mop args
437
438 -- Now look for multiplication/division by powers of 2 (integers).
439
440 cmmMachOpFold mop args@[x, y@(CmmLit (CmmInt n _))]
441   = case mop of
442         MO_Mul rep
443            | Just p <- exactLog2 n ->
444                  cmmMachOpFold (MO_Shl rep) [x, CmmLit (CmmInt p rep)]
445         MO_U_Quot rep
446            | Just p <- exactLog2 n ->
447                  cmmMachOpFold (MO_U_Shr rep) [x, CmmLit (CmmInt p rep)]
448         MO_S_Quot rep
449            | Just p <- exactLog2 n, 
450              CmmReg _ <- x ->   -- We duplicate x below, hence require
451                                 -- it is a reg.  FIXME: remove this restriction.
452                 -- shift right is not the same as quot, because it rounds
453                 -- to minus infinity, whereasq quot rounds toward zero.
454                 -- To fix this up, we add one less than the divisor to the
455                 -- dividend if it is a negative number.
456                 --
457                 -- to avoid a test/jump, we use the following sequence:
458                 --      x1 = x >> word_size-1  (all 1s if -ve, all 0s if +ve)
459                 --      x2 = y & (divisor-1)
460                 --      result = (x+x2) >>= log2(divisor)
461                 -- this could be done a bit more simply using conditional moves,
462                 -- but we're processor independent here.
463                 --
464                 -- we optimise the divide by 2 case slightly, generating
465                 --      x1 = x >> word_size-1  (unsigned)
466                 --      return = (x + x1) >>= log2(divisor)
467                 let 
468                     bits = fromIntegral (widthInBits rep) - 1
469                     shr = if p == 1 then MO_U_Shr rep else MO_S_Shr rep
470                     x1 = CmmMachOp shr [x, CmmLit (CmmInt bits rep)]
471                     x2 = if p == 1 then x1 else
472                          CmmMachOp (MO_And rep) [x1, CmmLit (CmmInt (n-1) rep)]
473                     x3 = CmmMachOp (MO_Add rep) [x, x2]
474                 in
475                 cmmMachOpFold (MO_S_Shr rep) [x3, CmmLit (CmmInt p rep)]
476         other
477            -> unchanged
478     where
479        unchanged = CmmMachOp mop args
480
481 -- Anything else is just too hard.
482
483 cmmMachOpFold mop args = CmmMachOp mop args
484
485 -- -----------------------------------------------------------------------------
486 -- exactLog2
487
488 -- This algorithm for determining the $\log_2$ of exact powers of 2 comes
489 -- from GCC.  It requires bit manipulation primitives, and we use GHC
490 -- extensions.  Tough.
491 -- 
492 -- Used to be in MachInstrs --SDM.
493 -- ToDo: remove use of unboxery --SDM.
494
495 -- Unboxery removed in favor of FastInt; but is the function supposed to fail
496 -- on inputs >= 2147483648, or was that just an implementation artifact?
497 -- And is this speed-critical, or can we just use Integer operations
498 -- (including Data.Bits)?
499 --  --Isaac Dupree
500
501 exactLog2 :: Integer -> Maybe Integer
502 exactLog2 x_
503   = if (x_ <= 0 || x_ >= 2147483648) then
504        Nothing
505     else
506        case iUnbox (fromInteger x_) of { x ->
507        if (x `bitAndFastInt` negateFastInt x) /=# x then
508           Nothing
509        else
510           Just (toInteger (iBox (pow2 x)))
511        }
512   where
513     pow2 x | x ==# _ILIT(1) = _ILIT(0)
514            | otherwise = _ILIT(1) +# pow2 (x `shiftR_FastInt` _ILIT(1))
515
516
517 -- -----------------------------------------------------------------------------
518 -- Loopify for C
519
520 {-
521  This is a simple pass that replaces tail-recursive functions like this:
522
523    fac() {
524      ...
525      jump fac();
526    }
527
528  with this:
529
530   fac() {
531    L:
532      ...
533      goto L;
534   }
535
536   the latter generates better C code, because the C compiler treats it
537   like a loop, and brings full loop optimisation to bear.
538
539   In my measurements this makes little or no difference to anything
540   except factorial, but what the hell.
541 -}
542
543 cmmLoopifyForC :: RawCmmTop -> RawCmmTop
544 cmmLoopifyForC p@(CmmProc info entry_lbl
545                  (ListGraph blocks@(BasicBlock top_id _ : _)))
546   | null info = p  -- only if there's an info table, ignore case alts
547   | otherwise =  
548 --  pprTrace "jump_lbl" (ppr jump_lbl <+> ppr entry_lbl) $
549   CmmProc info entry_lbl (ListGraph blocks')
550   where blocks' = [ BasicBlock id (map do_stmt stmts)
551                   | BasicBlock id stmts <- blocks ]
552
553         do_stmt (CmmJump (CmmLit (CmmLabel lbl)) _) | lbl == jump_lbl
554                 = CmmBranch top_id
555         do_stmt stmt = stmt
556
557         jump_lbl | tablesNextToCode = entryLblToInfoLbl entry_lbl
558                  | otherwise        = entry_lbl
559
560 cmmLoopifyForC top = top
561
562 -- -----------------------------------------------------------------------------
563 -- Utils
564
565 isLit (CmmLit _) = True
566 isLit _          = False
567
568 isComparisonExpr :: CmmExpr -> Bool
569 isComparisonExpr (CmmMachOp op _) = isComparisonMachOp op
570 isComparisonExpr _other             = False
571
572 isPicReg (CmmReg (CmmGlobal PicBaseReg)) = True
573 isPicReg _ = False
574