fix haddock submodule pointer
[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         cmmEliminateDeadBlocks,
18         cmmMiniInline,
19         cmmMachOpFold,
20         cmmLoopifyForC,
21  ) where
22
23 #include "HsVersions.h"
24
25 import OldCmm
26 import CmmUtils
27 import CLabel
28 import StaticFlags
29
30 import UniqFM
31 import Unique
32 import FastTypes
33 import Outputable
34 import BlockId
35
36 import Data.Bits
37 import Data.Word
38 import Data.Int
39 import Data.Maybe
40 import Data.List
41
42 import Compiler.Hoopl hiding (Unique)
43
44 -- -----------------------------------------------------------------------------
45 -- Eliminates dead blocks
46
47 {-
48 We repeatedly expand the set of reachable blocks until we hit a
49 fixpoint, and then prune any blocks that were not in this set.  This is
50 actually a required optimization, as dead blocks can cause problems
51 for invariants in the linear register allocator (and possibly other
52 places.)
53 -}
54
55 -- Deep fold over statements could probably be abstracted out, but it
56 -- might not be worth the effort since OldCmm is moribund
57 cmmEliminateDeadBlocks :: [CmmBasicBlock] -> [CmmBasicBlock]
58 cmmEliminateDeadBlocks [] = []
59 cmmEliminateDeadBlocks blocks@(BasicBlock base_id _:_) =
60     let -- Calculate what's reachable from what block
61         reachableMap = foldl' f emptyUFM blocks -- lazy in values
62             where f m (BasicBlock block_id stmts) = addToUFM m block_id (reachableFrom stmts)
63         reachableFrom stmts = foldl stmt [] stmts
64             where
65                 stmt m CmmNop = m
66                 stmt m (CmmComment _) = m
67                 stmt m (CmmAssign _ e) = expr m e
68                 stmt m (CmmStore e1 e2) = expr (expr m e1) e2
69                 stmt m (CmmCall c _ as _ _) = f (actuals m as) c
70                     where f m (CmmCallee e _) = expr m e
71                           f m (CmmPrim _) = m
72                 stmt m (CmmBranch b) = b:m
73                 stmt m (CmmCondBranch e b) = b:(expr m e)
74                 stmt m (CmmSwitch e bs) = catMaybes bs ++ expr m e
75                 stmt m (CmmJump e as) = expr (actuals m as) e
76                 stmt m (CmmReturn as) = actuals m as
77                 actuals m as = foldl' (\m h -> expr m (hintlessCmm h)) m as
78                 -- We have to do a deep fold into CmmExpr because
79                 -- there may be a BlockId in the CmmBlock literal.
80                 expr m (CmmLit l) = lit m l
81                 expr m (CmmLoad e _) = expr m e
82                 expr m (CmmReg _) = m
83                 expr m (CmmMachOp _ es) = foldl' expr m es
84                 expr m (CmmStackSlot _ _) = m
85                 expr m (CmmRegOff _ _) = m
86                 lit m (CmmBlock b) = b:m
87                 lit m _ = m
88         -- go todo done
89         reachable = go [base_id] (setEmpty :: BlockSet)
90           where go []     m = m
91                 go (x:xs) m
92                     | setMember x m = go xs m
93                     | otherwise     = go (add ++ xs) (setInsert x m)
94                         where add = fromMaybe (panic "cmmEliminateDeadBlocks: unknown block")
95                                               (lookupUFM reachableMap x)
96     in filter (\(BasicBlock block_id _) -> setMember block_id reachable) blocks
97
98 -- -----------------------------------------------------------------------------
99 -- The mini-inliner
100
101 {-
102 This pass inlines assignments to temporaries.  Temporaries that are
103 only used once are unconditionally inlined.  Temporaries that are used
104 two or more times are only inlined if they are assigned a literal.  It
105 works as follows:
106
107   - count uses of each temporary
108   - for each temporary:
109         - attempt to push it forward to the statement that uses it
110         - only push forward past assignments to other temporaries
111           (assumes that temporaries are single-assignment)
112         - if we reach the statement that uses it, inline the rhs
113           and delete the original assignment.
114
115 [N.B. In the Quick C-- compiler, this optimization is achieved by a
116  combination of two dataflow passes: forward substitution (peephole
117  optimization) and dead-assignment elimination.  ---NR]
118
119 Possible generalisations: here is an example from factorial
120
121 Fac_zdwfac_entry:
122     cmG:
123         _smi = R2;
124         if (_smi != 0) goto cmK;
125         R1 = R3;
126         jump I64[Sp];
127     cmK:
128         _smn = _smi * R3;
129         R2 = _smi + (-1);
130         R3 = _smn;
131         jump Fac_zdwfac_info;
132
133 We want to inline _smi and _smn.  To inline _smn:
134
135    - we must be able to push forward past assignments to global regs.
136      We can do this if the rhs of the assignment we are pushing
137      forward doesn't refer to the global reg being assigned to; easy
138      to test.
139
140 To inline _smi:
141
142    - It is a trivial replacement, reg for reg, but it occurs more than
143      once.
144    - We can inline trivial assignments even if the temporary occurs
145      more than once, as long as we don't eliminate the original assignment
146      (this doesn't help much on its own).
147    - We need to be able to propagate the assignment forward through jumps;
148      if we did this, we would find that it can be inlined safely in all
149      its occurrences.
150 -}
151
152 countUses :: UserOfLocalRegs a => a -> UniqFM Int
153 countUses a = foldRegsUsed (\m r -> addToUFM m r (count m r + 1)) emptyUFM a
154   where count m r = lookupWithDefaultUFM m (0::Int) r
155
156 cmmMiniInline :: [CmmBasicBlock] -> [CmmBasicBlock]
157 cmmMiniInline blocks = map do_inline blocks 
158   where do_inline (BasicBlock id stmts)
159           = BasicBlock id (cmmMiniInlineStmts (countUses blocks) stmts)
160
161 cmmMiniInlineStmts :: UniqFM Int -> [CmmStmt] -> [CmmStmt]
162 cmmMiniInlineStmts uses [] = []
163 cmmMiniInlineStmts uses (stmt@(CmmAssign (CmmLocal (LocalReg u _)) expr) : stmts)
164         -- not used: just discard this assignment
165   | Nothing <- lookupUFM uses u
166   = cmmMiniInlineStmts uses stmts
167
168         -- used (literal): try to inline at all the use sites
169   | Just n <- lookupUFM uses u, isLit expr
170   =
171 #ifdef NCG_DEBUG
172      trace ("nativeGen: inlining " ++ showSDoc (pprStmt stmt)) $
173 #endif
174      case lookForInlineLit u expr stmts of
175          (m, stmts')
176              | n == m -> cmmMiniInlineStmts (delFromUFM uses u) stmts'
177              | otherwise ->
178                  stmt : cmmMiniInlineStmts (adjustUFM (\x -> x - m) uses u) stmts'
179
180         -- used (foldable to literal): try to inline at all the use sites
181   | Just n <- lookupUFM uses u,
182     CmmMachOp op es <- expr,
183     e@(CmmLit _) <- cmmMachOpFold op es
184   =
185 #ifdef NCG_DEBUG
186      trace ("nativeGen: inlining " ++ showSDoc (pprStmt stmt)) $
187 #endif
188      case lookForInlineLit u e stmts of
189          (m, stmts')
190              | n == m -> cmmMiniInlineStmts (delFromUFM uses u) stmts'
191              | otherwise ->
192                  stmt : cmmMiniInlineStmts (adjustUFM (\x -> x - m) uses u) stmts'
193
194         -- used once (non-literal): try to inline at the use site
195   | Just 1 <- lookupUFM uses u,
196     Just stmts' <- lookForInline u expr stmts
197   = 
198 #ifdef NCG_DEBUG
199      trace ("nativeGen: inlining " ++ showSDoc (pprStmt stmt)) $
200 #endif
201      cmmMiniInlineStmts uses stmts'
202
203 cmmMiniInlineStmts uses (stmt:stmts)
204   = stmt : cmmMiniInlineStmts uses stmts
205
206 -- | Takes a register, a 'CmmLit' expression assigned to that
207 -- register, and a list of statements.  Inlines the expression at all
208 -- use sites of the register.  Returns the number of substituations
209 -- made and the, possibly modified, list of statements.
210 lookForInlineLit :: Unique -> CmmExpr -> [CmmStmt] -> (Int, [CmmStmt])
211 lookForInlineLit _ _ [] = (0, [])
212 lookForInlineLit u expr stmts@(stmt : rest)
213   | Just n <- lookupUFM (countUses stmt) u
214   = case lookForInlineLit u expr rest of
215       (m, stmts) -> let z = n + m
216                     in z `seq` (z, inlineStmt u expr stmt : stmts)
217
218   | ok_to_skip
219   = case lookForInlineLit u expr rest of
220       (n, stmts) -> (n, stmt : stmts)
221
222   | otherwise
223   = (0, stmts)
224   where
225     -- We skip over assignments to registers, unless the register
226     -- being assigned to is the one we're inlining.
227     ok_to_skip = case stmt of
228         CmmAssign (CmmLocal r@(LocalReg u' _)) _ | u' == u -> False
229         _other -> True
230
231 lookForInline u expr stmts = lookForInline' u expr regset stmts
232     where regset = foldRegsUsed extendRegSet emptyRegSet expr
233
234 lookForInline' u expr regset (stmt : rest)
235   | Just 1 <- lookupUFM (countUses stmt) u, ok_to_inline
236   = Just (inlineStmt u expr stmt : rest)
237
238   | ok_to_skip
239   = case lookForInline' u expr regset rest of
240            Nothing    -> Nothing
241            Just stmts -> Just (stmt:stmts)
242
243   | otherwise 
244   = Nothing
245
246   where
247         -- we don't inline into CmmCall if the expression refers to global
248         -- registers.  This is a HACK to avoid global registers clashing with
249         -- C argument-passing registers, really the back-end ought to be able
250         -- to handle it properly, but currently neither PprC nor the NCG can
251         -- do it.  See also CgForeignCall:load_args_into_temps.
252     ok_to_inline = case stmt of
253                      CmmCall{} -> hasNoGlobalRegs expr
254                      _ -> True
255
256    -- Expressions aren't side-effecting.  Temporaries may or may not
257    -- be single-assignment depending on the source (the old code
258    -- generator creates single-assignment code, but hand-written Cmm
259    -- and Cmm from the new code generator is not single-assignment.)
260    -- So we do an extra check to make sure that the register being
261    -- changed is not one we were relying on.  I don't know how much of a
262    -- performance hit this is (we have to create a regset for every
263    -- instruction.) -- EZY
264     ok_to_skip = case stmt of
265                  CmmNop -> True
266                  CmmComment{} -> True
267                  CmmAssign (CmmLocal r@(LocalReg u' _)) rhs | u' /= u && not (r `elemRegSet` regset) -> True
268                  CmmAssign g@(CmmGlobal _) rhs -> not (g `regUsedIn` expr)
269                  _other -> False
270
271
272 inlineStmt :: Unique -> CmmExpr -> CmmStmt -> CmmStmt
273 inlineStmt u a (CmmAssign r e) = CmmAssign r (inlineExpr u a e)
274 inlineStmt u a (CmmStore e1 e2) = CmmStore (inlineExpr u a e1) (inlineExpr u a e2)
275 inlineStmt u a (CmmCall target regs es srt ret)
276    = CmmCall (infn target) regs es' srt ret
277    where infn (CmmCallee fn cconv) = CmmCallee (inlineExpr u a fn) cconv
278          infn (CmmPrim p) = CmmPrim p
279          es' = [ (CmmHinted (inlineExpr u a e) hint) | (CmmHinted e hint) <- es ]
280 inlineStmt u a (CmmCondBranch e d) = CmmCondBranch (inlineExpr u a e) d
281 inlineStmt u a (CmmSwitch e d) = CmmSwitch (inlineExpr u a e) d
282 inlineStmt u a (CmmJump e d) = CmmJump (inlineExpr u a e) d
283 inlineStmt u a other_stmt = other_stmt
284
285 inlineExpr :: Unique -> CmmExpr -> CmmExpr -> CmmExpr
286 inlineExpr u a e@(CmmReg (CmmLocal (LocalReg u' _)))
287   | u == u' = a
288   | otherwise = e
289 inlineExpr u a e@(CmmRegOff (CmmLocal (LocalReg u' rep)) off)
290   | u == u' = CmmMachOp (MO_Add width) [a, CmmLit (CmmInt (fromIntegral off) width)]
291   | otherwise = e
292   where
293     width = typeWidth rep
294 inlineExpr u a (CmmLoad e rep) = CmmLoad (inlineExpr u a e) rep
295 inlineExpr u a (CmmMachOp op es) = CmmMachOp op (map (inlineExpr u a) es)
296 inlineExpr u a other_expr = other_expr
297
298 -- -----------------------------------------------------------------------------
299 -- MachOp constant folder
300
301 -- Now, try to constant-fold the MachOps.  The arguments have already
302 -- been optimized and folded.
303
304 cmmMachOpFold
305     :: MachOp           -- The operation from an CmmMachOp
306     -> [CmmExpr]        -- The optimized arguments
307     -> CmmExpr
308
309 cmmMachOpFold op arg@[CmmLit (CmmInt x rep)]
310   = case op of
311       MO_S_Neg r -> CmmLit (CmmInt (-x) rep)
312       MO_Not r   -> CmmLit (CmmInt (complement x) rep)
313
314         -- these are interesting: we must first narrow to the 
315         -- "from" type, in order to truncate to the correct size.
316         -- The final narrow/widen to the destination type
317         -- is implicit in the CmmLit.
318       MO_SF_Conv from to -> CmmLit (CmmFloat (fromInteger x) to)
319       MO_SS_Conv from to -> CmmLit (CmmInt (narrowS from x) to)
320       MO_UU_Conv from to -> CmmLit (CmmInt (narrowU from x) to)
321
322       _ -> panic "cmmMachOpFold: unknown unary op"
323
324
325 -- Eliminate conversion NOPs
326 cmmMachOpFold (MO_SS_Conv rep1 rep2) [x] | rep1 == rep2 = x
327 cmmMachOpFold (MO_UU_Conv rep1 rep2) [x] | rep1 == rep2 = x
328
329 -- Eliminate nested conversions where possible
330 cmmMachOpFold conv_outer args@[CmmMachOp conv_inner [x]]
331   | Just (rep1,rep2,signed1) <- isIntConversion conv_inner,
332     Just (_,   rep3,signed2) <- isIntConversion conv_outer
333   = case () of
334         -- widen then narrow to the same size is a nop
335       _ | rep1 < rep2 && rep1 == rep3 -> x
336         -- Widen then narrow to different size: collapse to single conversion
337         -- but remember to use the signedness from the widening, just in case
338         -- the final conversion is a widen.
339         | rep1 < rep2 && rep2 > rep3 ->
340             cmmMachOpFold (intconv signed1 rep1 rep3) [x]
341         -- Nested widenings: collapse if the signedness is the same
342         | rep1 < rep2 && rep2 < rep3 && signed1 == signed2 ->
343             cmmMachOpFold (intconv signed1 rep1 rep3) [x]
344         -- Nested narrowings: collapse
345         | rep1 > rep2 && rep2 > rep3 ->
346             cmmMachOpFold (MO_UU_Conv rep1 rep3) [x]
347         | otherwise ->
348             CmmMachOp conv_outer args
349   where
350         isIntConversion (MO_UU_Conv rep1 rep2) 
351           = Just (rep1,rep2,False)
352         isIntConversion (MO_SS_Conv rep1 rep2)
353           = Just (rep1,rep2,True)
354         isIntConversion _ = Nothing
355
356         intconv True  = MO_SS_Conv
357         intconv False = MO_UU_Conv
358
359 -- ToDo: a narrow of a load can be collapsed into a narrow load, right?
360 -- but what if the architecture only supports word-sized loads, should
361 -- we do the transformation anyway?
362
363 cmmMachOpFold mop args@[CmmLit (CmmInt x xrep), CmmLit (CmmInt y _)]
364   = case mop of
365         -- for comparisons: don't forget to narrow the arguments before
366         -- comparing, since they might be out of range.
367         MO_Eq r   -> CmmLit (CmmInt (if x_u == y_u then 1 else 0) wordWidth)
368         MO_Ne r   -> CmmLit (CmmInt (if x_u /= y_u then 1 else 0) wordWidth)
369
370         MO_U_Gt r -> CmmLit (CmmInt (if x_u >  y_u then 1 else 0) wordWidth)
371         MO_U_Ge r -> CmmLit (CmmInt (if x_u >= y_u then 1 else 0) wordWidth)
372         MO_U_Lt r -> CmmLit (CmmInt (if x_u <  y_u then 1 else 0) wordWidth)
373         MO_U_Le r -> CmmLit (CmmInt (if x_u <= y_u then 1 else 0) wordWidth)
374
375         MO_S_Gt r -> CmmLit (CmmInt (if x_s >  y_s then 1 else 0) wordWidth) 
376         MO_S_Ge r -> CmmLit (CmmInt (if x_s >= y_s then 1 else 0) wordWidth)
377         MO_S_Lt r -> CmmLit (CmmInt (if x_s <  y_s then 1 else 0) wordWidth)
378         MO_S_Le r -> CmmLit (CmmInt (if x_s <= y_s then 1 else 0) wordWidth)
379
380         MO_Add r -> CmmLit (CmmInt (x + y) r)
381         MO_Sub r -> CmmLit (CmmInt (x - y) r)
382         MO_Mul r -> CmmLit (CmmInt (x * y) r)
383         MO_U_Quot r | y /= 0 -> CmmLit (CmmInt (x_u `quot` y_u) r)
384         MO_U_Rem  r | y /= 0 -> CmmLit (CmmInt (x_u `rem`  y_u) r)
385         MO_S_Quot r | y /= 0 -> CmmLit (CmmInt (x `quot` y) r)
386         MO_S_Rem  r | y /= 0 -> CmmLit (CmmInt (x `rem` y) r)
387
388         MO_And   r -> CmmLit (CmmInt (x .&. y) r)
389         MO_Or    r -> CmmLit (CmmInt (x .|. y) r)
390         MO_Xor   r -> CmmLit (CmmInt (x `xor` y) r)
391
392         MO_Shl   r -> CmmLit (CmmInt (x `shiftL` fromIntegral y) r)
393         MO_U_Shr r -> CmmLit (CmmInt (x_u `shiftR` fromIntegral y) r)
394         MO_S_Shr r -> CmmLit (CmmInt (x `shiftR` fromIntegral y) r)
395
396         other      -> CmmMachOp mop args
397
398    where
399         x_u = narrowU xrep x
400         y_u = narrowU xrep y
401         x_s = narrowS xrep x
402         y_s = narrowS xrep y
403         
404
405 -- When possible, shift the constants to the right-hand side, so that we
406 -- can match for strength reductions.  Note that the code generator will
407 -- also assume that constants have been shifted to the right when
408 -- possible.
409
410 cmmMachOpFold op [x@(CmmLit _), y]
411    | not (isLit y) && isCommutableMachOp op 
412    = cmmMachOpFold op [y, x]
413
414 -- Turn (a+b)+c into a+(b+c) where possible.  Because literals are
415 -- moved to the right, it is more likely that we will find
416 -- opportunities for constant folding when the expression is
417 -- right-associated.
418 --
419 -- ToDo: this appears to introduce a quadratic behaviour due to the
420 -- nested cmmMachOpFold.  Can we fix this?
421 --
422 -- Why do we check isLit arg1?  If arg1 is a lit, it means that arg2
423 -- is also a lit (otherwise arg1 would be on the right).  If we
424 -- put arg1 on the left of the rearranged expression, we'll get into a
425 -- loop:  (x1+x2)+x3 => x1+(x2+x3)  => (x2+x3)+x1 => x2+(x3+x1) ...
426 --
427 -- Also don't do it if arg1 is PicBaseReg, so that we don't separate the
428 -- PicBaseReg from the corresponding label (or label difference).
429 --
430 cmmMachOpFold mop1 [CmmMachOp mop2 [arg1,arg2], arg3]
431    | mop2 `associates_with` mop1
432      && not (isLit arg1) && not (isPicReg arg1)
433    = cmmMachOpFold mop2 [arg1, cmmMachOpFold mop1 [arg2,arg3]]
434    where
435      MO_Add{} `associates_with` MO_Sub{} = True
436      mop1 `associates_with` mop2 =
437         mop1 == mop2 && isAssociativeMachOp mop1
438
439 -- special case: (a - b) + c  ==>  a + (c - b)
440 cmmMachOpFold mop1@(MO_Add{}) [CmmMachOp mop2@(MO_Sub{}) [arg1,arg2], arg3]
441    | not (isLit arg1) && not (isPicReg arg1)
442    = cmmMachOpFold mop1 [arg1, cmmMachOpFold mop2 [arg3,arg2]]
443
444 -- Make a RegOff if we can
445 cmmMachOpFold (MO_Add _) [CmmReg reg, CmmLit (CmmInt n rep)]
446   = CmmRegOff reg (fromIntegral (narrowS rep n))
447 cmmMachOpFold (MO_Add _) [CmmRegOff reg off, CmmLit (CmmInt n rep)]
448   = CmmRegOff reg (off + fromIntegral (narrowS rep n))
449 cmmMachOpFold (MO_Sub _) [CmmReg reg, CmmLit (CmmInt n rep)]
450   = CmmRegOff reg (- fromIntegral (narrowS rep n))
451 cmmMachOpFold (MO_Sub _) [CmmRegOff reg off, CmmLit (CmmInt n rep)]
452   = CmmRegOff reg (off - fromIntegral (narrowS rep n))
453
454 -- Fold label(+/-)offset into a CmmLit where possible
455
456 cmmMachOpFold (MO_Add _) [CmmLit (CmmLabel lbl), CmmLit (CmmInt i rep)]
457   = CmmLit (CmmLabelOff lbl (fromIntegral (narrowU rep i)))
458 cmmMachOpFold (MO_Add _) [CmmLit (CmmInt i rep), CmmLit (CmmLabel lbl)]
459   = CmmLit (CmmLabelOff lbl (fromIntegral (narrowU rep i)))
460 cmmMachOpFold (MO_Sub _) [CmmLit (CmmLabel lbl), CmmLit (CmmInt i rep)]
461   = CmmLit (CmmLabelOff lbl (fromIntegral (negate (narrowU rep i))))
462
463
464 -- Comparison of literal with widened operand: perform the comparison
465 -- at the smaller width, as long as the literal is within range.
466
467 -- We can't do the reverse trick, when the operand is narrowed:
468 -- narrowing throws away bits from the operand, there's no way to do
469 -- the same comparison at the larger size.
470
471 #if i386_TARGET_ARCH || x86_64_TARGET_ARCH
472 -- powerPC NCG has a TODO for I8/I16 comparisons, so don't try
473
474 cmmMachOpFold cmp [CmmMachOp conv [x], CmmLit (CmmInt i _)]
475   |     -- if the operand is widened:
476     Just (rep, signed, narrow_fn) <- maybe_conversion conv,
477         -- and this is a comparison operation:
478     Just narrow_cmp <- maybe_comparison cmp rep signed,
479         -- and the literal fits in the smaller size:
480     i == narrow_fn rep i
481         -- then we can do the comparison at the smaller size
482   = cmmMachOpFold narrow_cmp [x, CmmLit (CmmInt i rep)]
483  where
484     maybe_conversion (MO_UU_Conv from to)
485         | to > from
486         = Just (from, False, narrowU)
487     maybe_conversion (MO_SS_Conv from to)
488         | to > from
489         = Just (from, True, narrowS)
490
491         -- don't attempt to apply this optimisation when the source
492         -- is a float; see #1916
493     maybe_conversion _ = Nothing
494     
495         -- careful (#2080): if the original comparison was signed, but
496         -- we were doing an unsigned widen, then we must do an
497         -- unsigned comparison at the smaller size.
498     maybe_comparison (MO_U_Gt _) rep _     = Just (MO_U_Gt rep)
499     maybe_comparison (MO_U_Ge _) rep _     = Just (MO_U_Ge rep)
500     maybe_comparison (MO_U_Lt _) rep _     = Just (MO_U_Lt rep)
501     maybe_comparison (MO_U_Le _) rep _     = Just (MO_U_Le rep)
502     maybe_comparison (MO_Eq   _) rep _     = Just (MO_Eq   rep)
503     maybe_comparison (MO_S_Gt _) rep True  = Just (MO_S_Gt rep)
504     maybe_comparison (MO_S_Ge _) rep True  = Just (MO_S_Ge rep)
505     maybe_comparison (MO_S_Lt _) rep True  = Just (MO_S_Lt rep)
506     maybe_comparison (MO_S_Le _) rep True  = Just (MO_S_Le rep)
507     maybe_comparison (MO_S_Gt _) rep False = Just (MO_U_Gt rep)
508     maybe_comparison (MO_S_Ge _) rep False = Just (MO_U_Ge rep)
509     maybe_comparison (MO_S_Lt _) rep False = Just (MO_U_Lt rep)
510     maybe_comparison (MO_S_Le _) rep False = Just (MO_U_Le rep)
511     maybe_comparison _ _ _ = Nothing
512
513 #endif
514
515 -- We can often do something with constants of 0 and 1 ...
516
517 cmmMachOpFold mop args@[x, y@(CmmLit (CmmInt 0 _))]
518   = case mop of
519         MO_Add   r -> x
520         MO_Sub   r -> x
521         MO_Mul   r -> y
522         MO_And   r -> y
523         MO_Or    r -> x
524         MO_Xor   r -> x
525         MO_Shl   r -> x
526         MO_S_Shr r -> x
527         MO_U_Shr r -> x
528         MO_Ne    r | isComparisonExpr x -> x
529         MO_Eq    r | Just x' <- maybeInvertCmmExpr x -> x'
530         MO_U_Gt  r | isComparisonExpr x -> x
531         MO_S_Gt  r | isComparisonExpr x -> x
532         MO_U_Lt  r | isComparisonExpr x -> CmmLit (CmmInt 0 wordWidth)
533         MO_S_Lt  r | isComparisonExpr x -> CmmLit (CmmInt 0 wordWidth)
534         MO_U_Ge  r | isComparisonExpr x -> CmmLit (CmmInt 1 wordWidth)
535         MO_S_Ge  r | isComparisonExpr x -> CmmLit (CmmInt 1 wordWidth)
536         MO_U_Le  r | Just x' <- maybeInvertCmmExpr x -> x'
537         MO_S_Le  r | Just x' <- maybeInvertCmmExpr x -> x'
538         other    -> CmmMachOp mop args
539
540 cmmMachOpFold mop args@[x, y@(CmmLit (CmmInt 1 rep))]
541   = case mop of
542         MO_Mul    r -> x
543         MO_S_Quot r -> x
544         MO_U_Quot r -> x
545         MO_S_Rem  r -> CmmLit (CmmInt 0 rep)
546         MO_U_Rem  r -> CmmLit (CmmInt 0 rep)
547         MO_Ne    r | Just x' <- maybeInvertCmmExpr x -> x'
548         MO_Eq    r | isComparisonExpr x -> x
549         MO_U_Lt  r | Just x' <- maybeInvertCmmExpr x -> x'
550         MO_S_Lt  r | Just x' <- maybeInvertCmmExpr x -> x'
551         MO_U_Gt  r | isComparisonExpr x -> CmmLit (CmmInt 0 wordWidth)
552         MO_S_Gt  r | isComparisonExpr x -> CmmLit (CmmInt 0 wordWidth)
553         MO_U_Le  r | isComparisonExpr x -> CmmLit (CmmInt 1 wordWidth)
554         MO_S_Le  r | isComparisonExpr x -> CmmLit (CmmInt 1 wordWidth)
555         MO_U_Ge  r | isComparisonExpr x -> x
556         MO_S_Ge  r | isComparisonExpr x -> x
557         other       -> CmmMachOp mop args
558
559 -- Now look for multiplication/division by powers of 2 (integers).
560
561 cmmMachOpFold mop args@[x, y@(CmmLit (CmmInt n _))]
562   = case mop of
563         MO_Mul rep
564            | Just p <- exactLog2 n ->
565                  cmmMachOpFold (MO_Shl rep) [x, CmmLit (CmmInt p rep)]
566         MO_U_Quot rep
567            | Just p <- exactLog2 n ->
568                  cmmMachOpFold (MO_U_Shr rep) [x, CmmLit (CmmInt p rep)]
569         MO_S_Quot rep
570            | Just p <- exactLog2 n, 
571              CmmReg _ <- x ->   -- We duplicate x below, hence require
572                                 -- it is a reg.  FIXME: remove this restriction.
573                 -- shift right is not the same as quot, because it rounds
574                 -- to minus infinity, whereasq quot rounds toward zero.
575                 -- To fix this up, we add one less than the divisor to the
576                 -- dividend if it is a negative number.
577                 --
578                 -- to avoid a test/jump, we use the following sequence:
579                 --      x1 = x >> word_size-1  (all 1s if -ve, all 0s if +ve)
580                 --      x2 = y & (divisor-1)
581                 --      result = (x+x2) >>= log2(divisor)
582                 -- this could be done a bit more simply using conditional moves,
583                 -- but we're processor independent here.
584                 --
585                 -- we optimise the divide by 2 case slightly, generating
586                 --      x1 = x >> word_size-1  (unsigned)
587                 --      return = (x + x1) >>= log2(divisor)
588                 let 
589                     bits = fromIntegral (widthInBits rep) - 1
590                     shr = if p == 1 then MO_U_Shr rep else MO_S_Shr rep
591                     x1 = CmmMachOp shr [x, CmmLit (CmmInt bits rep)]
592                     x2 = if p == 1 then x1 else
593                          CmmMachOp (MO_And rep) [x1, CmmLit (CmmInt (n-1) rep)]
594                     x3 = CmmMachOp (MO_Add rep) [x, x2]
595                 in
596                 cmmMachOpFold (MO_S_Shr rep) [x3, CmmLit (CmmInt p rep)]
597         other
598            -> unchanged
599     where
600        unchanged = CmmMachOp mop args
601
602 -- Anything else is just too hard.
603
604 cmmMachOpFold mop args = CmmMachOp mop args
605
606 -- -----------------------------------------------------------------------------
607 -- exactLog2
608
609 -- This algorithm for determining the $\log_2$ of exact powers of 2 comes
610 -- from GCC.  It requires bit manipulation primitives, and we use GHC
611 -- extensions.  Tough.
612 -- 
613 -- Used to be in MachInstrs --SDM.
614 -- ToDo: remove use of unboxery --SDM.
615
616 -- Unboxery removed in favor of FastInt; but is the function supposed to fail
617 -- on inputs >= 2147483648, or was that just an implementation artifact?
618 -- And is this speed-critical, or can we just use Integer operations
619 -- (including Data.Bits)?
620 --  --Isaac Dupree
621
622 exactLog2 :: Integer -> Maybe Integer
623 exactLog2 x_
624   = if (x_ <= 0 || x_ >= 2147483648) then
625        Nothing
626     else
627        case iUnbox (fromInteger x_) of { x ->
628        if (x `bitAndFastInt` negateFastInt x) /=# x then
629           Nothing
630        else
631           Just (toInteger (iBox (pow2 x)))
632        }
633   where
634     pow2 x | x ==# _ILIT(1) = _ILIT(0)
635            | otherwise = _ILIT(1) +# pow2 (x `shiftR_FastInt` _ILIT(1))
636
637
638 -- -----------------------------------------------------------------------------
639 -- Loopify for C
640
641 {-
642  This is a simple pass that replaces tail-recursive functions like this:
643
644    fac() {
645      ...
646      jump fac();
647    }
648
649  with this:
650
651   fac() {
652    L:
653      ...
654      goto L;
655   }
656
657   the latter generates better C code, because the C compiler treats it
658   like a loop, and brings full loop optimisation to bear.
659
660   In my measurements this makes little or no difference to anything
661   except factorial, but what the hell.
662 -}
663
664 cmmLoopifyForC :: RawCmmTop -> RawCmmTop
665 cmmLoopifyForC p@(CmmProc info entry_lbl
666                  (ListGraph blocks@(BasicBlock top_id _ : _)))
667   | null info = p  -- only if there's an info table, ignore case alts
668   | otherwise =  
669 --  pprTrace "jump_lbl" (ppr jump_lbl <+> ppr entry_lbl) $
670   CmmProc info entry_lbl (ListGraph blocks')
671   where blocks' = [ BasicBlock id (map do_stmt stmts)
672                   | BasicBlock id stmts <- blocks ]
673
674         do_stmt (CmmJump (CmmLit (CmmLabel lbl)) _) | lbl == jump_lbl
675                 = CmmBranch top_id
676         do_stmt stmt = stmt
677
678         jump_lbl | tablesNextToCode = entryLblToInfoLbl entry_lbl
679                  | otherwise        = entry_lbl
680
681 cmmLoopifyForC top = top
682
683 -- -----------------------------------------------------------------------------
684 -- Utils
685
686 isLit (CmmLit _) = True
687 isLit _          = False
688
689 isComparisonExpr :: CmmExpr -> Bool
690 isComparisonExpr (CmmMachOp op _) = isComparisonMachOp op
691 isComparisonExpr _other             = False
692
693 isPicReg (CmmReg (CmmGlobal PicBaseReg)) = True
694 isPicReg _ = False
695