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