Implement forward substitution of constants in the Cmm mini-inliner
[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@(CmmLit _)) : stmts)
164         -- not used: just discard this assignment
165   | Nothing <- lookupUFM uses u
166   = cmmMiniInlineStmts uses stmts
167
168         -- used: try to inline at all the use sites
169   | Just n <- lookupUFM uses u
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 cmmMiniInlineStmts uses (stmt@(CmmAssign (CmmLocal (LocalReg u _)) expr : stmts))
181         -- not used at all: just discard this assignment
182   | Nothing <- lookupUFM uses u
183   = cmmMiniInlineStmts uses stmts
184
185         -- used once: try to inline at the use site
186   | Just 1 <- lookupUFM uses u,
187     Just stmts' <- lookForInline u expr stmts
188   = 
189 #ifdef NCG_DEBUG
190      trace ("nativeGen: inlining " ++ showSDoc (pprStmt stmt)) $
191 #endif
192      cmmMiniInlineStmts uses stmts'
193
194 cmmMiniInlineStmts uses (stmt:stmts)
195   = stmt : cmmMiniInlineStmts uses stmts
196
197 -- | Takes a register, a 'CmmLit' expression assigned to that
198 -- register, and a list of statements.  Inlines the expression at all
199 -- use sites of the register.  Returns the number of substituations
200 -- made and the, possibly modified, list of statements.
201 lookForInlineLit :: Unique -> CmmExpr -> [CmmStmt] -> (Int, [CmmStmt])
202 lookForInlineLit _ _ [] = (0, [])
203 lookForInlineLit u expr stmts@(stmt : rest)
204   | Just n <- lookupUFM (countUses stmt) u
205   = case lookForInlineLit u expr rest of
206       (m, stmts) -> let z = n + m
207                     in z `seq` (z, inlineStmt u expr stmt : stmts)
208
209   | ok_to_skip
210   = case lookForInlineLit u expr rest of
211       (n, stmts) -> (n, stmt : stmts)
212
213   | otherwise
214   = (0, stmts)
215   where
216     -- We skip over assignments to registers, unless the register
217     -- being assigned to is the one we're inlining.
218     ok_to_skip = case stmt of
219         CmmAssign (CmmLocal r@(LocalReg u' _)) _ | u' == u -> False
220         _other -> True
221
222 lookForInline u expr stmts = lookForInline' u expr regset stmts
223     where regset = foldRegsUsed extendRegSet emptyRegSet expr
224
225 lookForInline' u expr regset (stmt : rest)
226   | Just 1 <- lookupUFM (countUses stmt) u, ok_to_inline
227   = Just (inlineStmt u expr stmt : rest)
228
229   | ok_to_skip
230   = case lookForInline' u expr regset rest of
231            Nothing    -> Nothing
232            Just stmts -> Just (stmt:stmts)
233
234   | otherwise 
235   = Nothing
236
237   where
238         -- we don't inline into CmmCall if the expression refers to global
239         -- registers.  This is a HACK to avoid global registers clashing with
240         -- C argument-passing registers, really the back-end ought to be able
241         -- to handle it properly, but currently neither PprC nor the NCG can
242         -- do it.  See also CgForeignCall:load_args_into_temps.
243     ok_to_inline = case stmt of
244                      CmmCall{} -> hasNoGlobalRegs expr
245                      _ -> True
246
247    -- Expressions aren't side-effecting.  Temporaries may or may not
248    -- be single-assignment depending on the source (the old code
249    -- generator creates single-assignment code, but hand-written Cmm
250    -- and Cmm from the new code generator is not single-assignment.)
251    -- So we do an extra check to make sure that the register being
252    -- changed is not one we were relying on.  I don't know how much of a
253    -- performance hit this is (we have to create a regset for every
254    -- instruction.) -- EZY
255     ok_to_skip = case stmt of
256                  CmmNop -> True
257                  CmmComment{} -> True
258                  CmmAssign (CmmLocal r@(LocalReg u' _)) rhs | u' /= u && not (r `elemRegSet` regset) -> True
259                  CmmAssign g@(CmmGlobal _) rhs -> not (g `regUsedIn` expr)
260                  _other -> False
261
262
263 inlineStmt :: Unique -> CmmExpr -> CmmStmt -> CmmStmt
264 inlineStmt u a (CmmAssign r e) = CmmAssign r (inlineExpr u a e)
265 inlineStmt u a (CmmStore e1 e2) = CmmStore (inlineExpr u a e1) (inlineExpr u a e2)
266 inlineStmt u a (CmmCall target regs es srt ret)
267    = CmmCall (infn target) regs es' srt ret
268    where infn (CmmCallee fn cconv) = CmmCallee (inlineExpr u a fn) cconv
269          infn (CmmPrim p) = CmmPrim p
270          es' = [ (CmmHinted (inlineExpr u a e) hint) | (CmmHinted e hint) <- es ]
271 inlineStmt u a (CmmCondBranch e d) = CmmCondBranch (inlineExpr u a e) d
272 inlineStmt u a (CmmSwitch e d) = CmmSwitch (inlineExpr u a e) d
273 inlineStmt u a (CmmJump e d) = CmmJump (inlineExpr u a e) d
274 inlineStmt u a other_stmt = other_stmt
275
276 inlineExpr :: Unique -> CmmExpr -> CmmExpr -> CmmExpr
277 inlineExpr u a e@(CmmReg (CmmLocal (LocalReg u' _)))
278   | u == u' = a
279   | otherwise = e
280 inlineExpr u a e@(CmmRegOff (CmmLocal (LocalReg u' rep)) off)
281   | u == u' = CmmMachOp (MO_Add width) [a, CmmLit (CmmInt (fromIntegral off) width)]
282   | otherwise = e
283   where
284     width = typeWidth rep
285 inlineExpr u a (CmmLoad e rep) = CmmLoad (inlineExpr u a e) rep
286 inlineExpr u a (CmmMachOp op es) = CmmMachOp op (map (inlineExpr u a) es)
287 inlineExpr u a other_expr = other_expr
288
289 -- -----------------------------------------------------------------------------
290 -- MachOp constant folder
291
292 -- Now, try to constant-fold the MachOps.  The arguments have already
293 -- been optimized and folded.
294
295 cmmMachOpFold
296     :: MachOp           -- The operation from an CmmMachOp
297     -> [CmmExpr]        -- The optimized arguments
298     -> CmmExpr
299
300 cmmMachOpFold op arg@[CmmLit (CmmInt x rep)]
301   = case op of
302       MO_S_Neg r -> CmmLit (CmmInt (-x) rep)
303       MO_Not r   -> CmmLit (CmmInt (complement x) rep)
304
305         -- these are interesting: we must first narrow to the 
306         -- "from" type, in order to truncate to the correct size.
307         -- The final narrow/widen to the destination type
308         -- is implicit in the CmmLit.
309       MO_SF_Conv from to -> CmmLit (CmmFloat (fromInteger x) to)
310       MO_SS_Conv from to -> CmmLit (CmmInt (narrowS from x) to)
311       MO_UU_Conv from to -> CmmLit (CmmInt (narrowU from x) to)
312
313       _ -> panic "cmmMachOpFold: unknown unary op"
314
315
316 -- Eliminate conversion NOPs
317 cmmMachOpFold (MO_SS_Conv rep1 rep2) [x] | rep1 == rep2 = x
318 cmmMachOpFold (MO_UU_Conv rep1 rep2) [x] | rep1 == rep2 = x
319
320 -- Eliminate nested conversions where possible
321 cmmMachOpFold conv_outer args@[CmmMachOp conv_inner [x]]
322   | Just (rep1,rep2,signed1) <- isIntConversion conv_inner,
323     Just (_,   rep3,signed2) <- isIntConversion conv_outer
324   = case () of
325         -- widen then narrow to the same size is a nop
326       _ | rep1 < rep2 && rep1 == rep3 -> x
327         -- Widen then narrow to different size: collapse to single conversion
328         -- but remember to use the signedness from the widening, just in case
329         -- the final conversion is a widen.
330         | rep1 < rep2 && rep2 > rep3 ->
331             cmmMachOpFold (intconv signed1 rep1 rep3) [x]
332         -- Nested widenings: collapse if the signedness is the same
333         | rep1 < rep2 && rep2 < rep3 && signed1 == signed2 ->
334             cmmMachOpFold (intconv signed1 rep1 rep3) [x]
335         -- Nested narrowings: collapse
336         | rep1 > rep2 && rep2 > rep3 ->
337             cmmMachOpFold (MO_UU_Conv rep1 rep3) [x]
338         | otherwise ->
339             CmmMachOp conv_outer args
340   where
341         isIntConversion (MO_UU_Conv rep1 rep2) 
342           = Just (rep1,rep2,False)
343         isIntConversion (MO_SS_Conv rep1 rep2)
344           = Just (rep1,rep2,True)
345         isIntConversion _ = Nothing
346
347         intconv True  = MO_SS_Conv
348         intconv False = MO_UU_Conv
349
350 -- ToDo: a narrow of a load can be collapsed into a narrow load, right?
351 -- but what if the architecture only supports word-sized loads, should
352 -- we do the transformation anyway?
353
354 cmmMachOpFold mop args@[CmmLit (CmmInt x xrep), CmmLit (CmmInt y _)]
355   = case mop of
356         -- for comparisons: don't forget to narrow the arguments before
357         -- comparing, since they might be out of range.
358         MO_Eq r   -> CmmLit (CmmInt (if x_u == y_u then 1 else 0) wordWidth)
359         MO_Ne r   -> CmmLit (CmmInt (if x_u /= y_u then 1 else 0) wordWidth)
360
361         MO_U_Gt r -> CmmLit (CmmInt (if x_u >  y_u then 1 else 0) wordWidth)
362         MO_U_Ge r -> CmmLit (CmmInt (if x_u >= y_u then 1 else 0) wordWidth)
363         MO_U_Lt r -> CmmLit (CmmInt (if x_u <  y_u then 1 else 0) wordWidth)
364         MO_U_Le r -> CmmLit (CmmInt (if x_u <= y_u then 1 else 0) wordWidth)
365
366         MO_S_Gt r -> CmmLit (CmmInt (if x_s >  y_s then 1 else 0) wordWidth) 
367         MO_S_Ge r -> CmmLit (CmmInt (if x_s >= y_s then 1 else 0) wordWidth)
368         MO_S_Lt r -> CmmLit (CmmInt (if x_s <  y_s then 1 else 0) wordWidth)
369         MO_S_Le r -> CmmLit (CmmInt (if x_s <= y_s then 1 else 0) wordWidth)
370
371         MO_Add r -> CmmLit (CmmInt (x + y) r)
372         MO_Sub r -> CmmLit (CmmInt (x - y) r)
373         MO_Mul r -> CmmLit (CmmInt (x * y) r)
374         MO_U_Quot r | y /= 0 -> CmmLit (CmmInt (x_u `quot` y_u) r)
375         MO_U_Rem  r | y /= 0 -> CmmLit (CmmInt (x_u `rem`  y_u) r)
376         MO_S_Quot r | y /= 0 -> CmmLit (CmmInt (x `quot` y) r)
377         MO_S_Rem  r | y /= 0 -> CmmLit (CmmInt (x `rem` y) r)
378
379         MO_And   r -> CmmLit (CmmInt (x .&. y) r)
380         MO_Or    r -> CmmLit (CmmInt (x .|. y) r)
381         MO_Xor   r -> CmmLit (CmmInt (x `xor` y) r)
382
383         MO_Shl   r -> CmmLit (CmmInt (x `shiftL` fromIntegral y) r)
384         MO_U_Shr r -> CmmLit (CmmInt (x_u `shiftR` fromIntegral y) r)
385         MO_S_Shr r -> CmmLit (CmmInt (x `shiftR` fromIntegral y) r)
386
387         other      -> CmmMachOp mop args
388
389    where
390         x_u = narrowU xrep x
391         y_u = narrowU xrep y
392         x_s = narrowS xrep x
393         y_s = narrowS xrep y
394         
395
396 -- When possible, shift the constants to the right-hand side, so that we
397 -- can match for strength reductions.  Note that the code generator will
398 -- also assume that constants have been shifted to the right when
399 -- possible.
400
401 cmmMachOpFold op [x@(CmmLit _), y]
402    | not (isLit y) && isCommutableMachOp op 
403    = cmmMachOpFold op [y, x]
404
405 -- Turn (a+b)+c into a+(b+c) where possible.  Because literals are
406 -- moved to the right, it is more likely that we will find
407 -- opportunities for constant folding when the expression is
408 -- right-associated.
409 --
410 -- ToDo: this appears to introduce a quadratic behaviour due to the
411 -- nested cmmMachOpFold.  Can we fix this?
412 --
413 -- Why do we check isLit arg1?  If arg1 is a lit, it means that arg2
414 -- is also a lit (otherwise arg1 would be on the right).  If we
415 -- put arg1 on the left of the rearranged expression, we'll get into a
416 -- loop:  (x1+x2)+x3 => x1+(x2+x3)  => (x2+x3)+x1 => x2+(x3+x1) ...
417 --
418 -- Also don't do it if arg1 is PicBaseReg, so that we don't separate the
419 -- PicBaseReg from the corresponding label (or label difference).
420 --
421 cmmMachOpFold mop1 [CmmMachOp mop2 [arg1,arg2], arg3]
422    | mop2 `associates_with` mop1
423      && not (isLit arg1) && not (isPicReg arg1)
424    = cmmMachOpFold mop2 [arg1, cmmMachOpFold mop1 [arg2,arg3]]
425    where
426      MO_Add{} `associates_with` MO_Sub{} = True
427      mop1 `associates_with` mop2 =
428         mop1 == mop2 && isAssociativeMachOp mop1
429
430 -- special case: (a - b) + c  ==>  a + (c - b)
431 cmmMachOpFold mop1@(MO_Add{}) [CmmMachOp mop2@(MO_Sub{}) [arg1,arg2], arg3]
432    | not (isLit arg1) && not (isPicReg arg1)
433    = cmmMachOpFold mop1 [arg1, cmmMachOpFold mop2 [arg3,arg2]]
434
435 -- Make a RegOff if we can
436 cmmMachOpFold (MO_Add _) [CmmReg reg, CmmLit (CmmInt n rep)]
437   = CmmRegOff reg (fromIntegral (narrowS rep n))
438 cmmMachOpFold (MO_Add _) [CmmRegOff reg off, CmmLit (CmmInt n rep)]
439   = CmmRegOff reg (off + fromIntegral (narrowS rep n))
440 cmmMachOpFold (MO_Sub _) [CmmReg reg, CmmLit (CmmInt n rep)]
441   = CmmRegOff reg (- fromIntegral (narrowS rep n))
442 cmmMachOpFold (MO_Sub _) [CmmRegOff reg off, CmmLit (CmmInt n rep)]
443   = CmmRegOff reg (off - fromIntegral (narrowS rep n))
444
445 -- Fold label(+/-)offset into a CmmLit where possible
446
447 cmmMachOpFold (MO_Add _) [CmmLit (CmmLabel lbl), CmmLit (CmmInt i rep)]
448   = CmmLit (CmmLabelOff lbl (fromIntegral (narrowU rep i)))
449 cmmMachOpFold (MO_Add _) [CmmLit (CmmInt i rep), CmmLit (CmmLabel lbl)]
450   = CmmLit (CmmLabelOff lbl (fromIntegral (narrowU rep i)))
451 cmmMachOpFold (MO_Sub _) [CmmLit (CmmLabel lbl), CmmLit (CmmInt i rep)]
452   = CmmLit (CmmLabelOff lbl (fromIntegral (negate (narrowU rep i))))
453
454
455 -- Comparison of literal with widened operand: perform the comparison
456 -- at the smaller width, as long as the literal is within range.
457
458 -- We can't do the reverse trick, when the operand is narrowed:
459 -- narrowing throws away bits from the operand, there's no way to do
460 -- the same comparison at the larger size.
461
462 #if i386_TARGET_ARCH || x86_64_TARGET_ARCH
463 -- powerPC NCG has a TODO for I8/I16 comparisons, so don't try
464
465 cmmMachOpFold cmp [CmmMachOp conv [x], CmmLit (CmmInt i _)]
466   |     -- if the operand is widened:
467     Just (rep, signed, narrow_fn) <- maybe_conversion conv,
468         -- and this is a comparison operation:
469     Just narrow_cmp <- maybe_comparison cmp rep signed,
470         -- and the literal fits in the smaller size:
471     i == narrow_fn rep i
472         -- then we can do the comparison at the smaller size
473   = cmmMachOpFold narrow_cmp [x, CmmLit (CmmInt i rep)]
474  where
475     maybe_conversion (MO_UU_Conv from to)
476         | to > from
477         = Just (from, False, narrowU)
478     maybe_conversion (MO_SS_Conv from to)
479         | to > from
480         = Just (from, True, narrowS)
481
482         -- don't attempt to apply this optimisation when the source
483         -- is a float; see #1916
484     maybe_conversion _ = Nothing
485     
486         -- careful (#2080): if the original comparison was signed, but
487         -- we were doing an unsigned widen, then we must do an
488         -- unsigned comparison at the smaller size.
489     maybe_comparison (MO_U_Gt _) rep _     = Just (MO_U_Gt rep)
490     maybe_comparison (MO_U_Ge _) rep _     = Just (MO_U_Ge rep)
491     maybe_comparison (MO_U_Lt _) rep _     = Just (MO_U_Lt rep)
492     maybe_comparison (MO_U_Le _) rep _     = Just (MO_U_Le rep)
493     maybe_comparison (MO_Eq   _) rep _     = Just (MO_Eq   rep)
494     maybe_comparison (MO_S_Gt _) rep True  = Just (MO_S_Gt rep)
495     maybe_comparison (MO_S_Ge _) rep True  = Just (MO_S_Ge rep)
496     maybe_comparison (MO_S_Lt _) rep True  = Just (MO_S_Lt rep)
497     maybe_comparison (MO_S_Le _) rep True  = Just (MO_S_Le rep)
498     maybe_comparison (MO_S_Gt _) rep False = Just (MO_U_Gt rep)
499     maybe_comparison (MO_S_Ge _) rep False = Just (MO_U_Ge rep)
500     maybe_comparison (MO_S_Lt _) rep False = Just (MO_U_Lt rep)
501     maybe_comparison (MO_S_Le _) rep False = Just (MO_U_Le rep)
502     maybe_comparison _ _ _ = Nothing
503
504 #endif
505
506 -- We can often do something with constants of 0 and 1 ...
507
508 cmmMachOpFold mop args@[x, y@(CmmLit (CmmInt 0 _))]
509   = case mop of
510         MO_Add   r -> x
511         MO_Sub   r -> x
512         MO_Mul   r -> y
513         MO_And   r -> y
514         MO_Or    r -> x
515         MO_Xor   r -> x
516         MO_Shl   r -> x
517         MO_S_Shr r -> x
518         MO_U_Shr r -> x
519         MO_Ne    r | isComparisonExpr x -> x
520         MO_Eq    r | Just x' <- maybeInvertCmmExpr x -> x'
521         MO_U_Gt  r | isComparisonExpr x -> x
522         MO_S_Gt  r | isComparisonExpr x -> x
523         MO_U_Lt  r | isComparisonExpr x -> CmmLit (CmmInt 0 wordWidth)
524         MO_S_Lt  r | isComparisonExpr x -> CmmLit (CmmInt 0 wordWidth)
525         MO_U_Ge  r | isComparisonExpr x -> CmmLit (CmmInt 1 wordWidth)
526         MO_S_Ge  r | isComparisonExpr x -> CmmLit (CmmInt 1 wordWidth)
527         MO_U_Le  r | Just x' <- maybeInvertCmmExpr x -> x'
528         MO_S_Le  r | Just x' <- maybeInvertCmmExpr x -> x'
529         other    -> CmmMachOp mop args
530
531 cmmMachOpFold mop args@[x, y@(CmmLit (CmmInt 1 rep))]
532   = case mop of
533         MO_Mul    r -> x
534         MO_S_Quot r -> x
535         MO_U_Quot r -> x
536         MO_S_Rem  r -> CmmLit (CmmInt 0 rep)
537         MO_U_Rem  r -> CmmLit (CmmInt 0 rep)
538         MO_Ne    r | Just x' <- maybeInvertCmmExpr x -> x'
539         MO_Eq    r | isComparisonExpr x -> x
540         MO_U_Lt  r | Just x' <- maybeInvertCmmExpr x -> x'
541         MO_S_Lt  r | Just x' <- maybeInvertCmmExpr x -> x'
542         MO_U_Gt  r | isComparisonExpr x -> CmmLit (CmmInt 0 wordWidth)
543         MO_S_Gt  r | isComparisonExpr x -> CmmLit (CmmInt 0 wordWidth)
544         MO_U_Le  r | isComparisonExpr x -> CmmLit (CmmInt 1 wordWidth)
545         MO_S_Le  r | isComparisonExpr x -> CmmLit (CmmInt 1 wordWidth)
546         MO_U_Ge  r | isComparisonExpr x -> x
547         MO_S_Ge  r | isComparisonExpr x -> x
548         other       -> CmmMachOp mop args
549
550 -- Now look for multiplication/division by powers of 2 (integers).
551
552 cmmMachOpFold mop args@[x, y@(CmmLit (CmmInt n _))]
553   = case mop of
554         MO_Mul rep
555            | Just p <- exactLog2 n ->
556                  cmmMachOpFold (MO_Shl rep) [x, CmmLit (CmmInt p rep)]
557         MO_U_Quot rep
558            | Just p <- exactLog2 n ->
559                  cmmMachOpFold (MO_U_Shr rep) [x, CmmLit (CmmInt p rep)]
560         MO_S_Quot rep
561            | Just p <- exactLog2 n, 
562              CmmReg _ <- x ->   -- We duplicate x below, hence require
563                                 -- it is a reg.  FIXME: remove this restriction.
564                 -- shift right is not the same as quot, because it rounds
565                 -- to minus infinity, whereasq quot rounds toward zero.
566                 -- To fix this up, we add one less than the divisor to the
567                 -- dividend if it is a negative number.
568                 --
569                 -- to avoid a test/jump, we use the following sequence:
570                 --      x1 = x >> word_size-1  (all 1s if -ve, all 0s if +ve)
571                 --      x2 = y & (divisor-1)
572                 --      result = (x+x2) >>= log2(divisor)
573                 -- this could be done a bit more simply using conditional moves,
574                 -- but we're processor independent here.
575                 --
576                 -- we optimise the divide by 2 case slightly, generating
577                 --      x1 = x >> word_size-1  (unsigned)
578                 --      return = (x + x1) >>= log2(divisor)
579                 let 
580                     bits = fromIntegral (widthInBits rep) - 1
581                     shr = if p == 1 then MO_U_Shr rep else MO_S_Shr rep
582                     x1 = CmmMachOp shr [x, CmmLit (CmmInt bits rep)]
583                     x2 = if p == 1 then x1 else
584                          CmmMachOp (MO_And rep) [x1, CmmLit (CmmInt (n-1) rep)]
585                     x3 = CmmMachOp (MO_Add rep) [x, x2]
586                 in
587                 cmmMachOpFold (MO_S_Shr rep) [x3, CmmLit (CmmInt p rep)]
588         other
589            -> unchanged
590     where
591        unchanged = CmmMachOp mop args
592
593 -- Anything else is just too hard.
594
595 cmmMachOpFold mop args = CmmMachOp mop args
596
597 -- -----------------------------------------------------------------------------
598 -- exactLog2
599
600 -- This algorithm for determining the $\log_2$ of exact powers of 2 comes
601 -- from GCC.  It requires bit manipulation primitives, and we use GHC
602 -- extensions.  Tough.
603 -- 
604 -- Used to be in MachInstrs --SDM.
605 -- ToDo: remove use of unboxery --SDM.
606
607 -- Unboxery removed in favor of FastInt; but is the function supposed to fail
608 -- on inputs >= 2147483648, or was that just an implementation artifact?
609 -- And is this speed-critical, or can we just use Integer operations
610 -- (including Data.Bits)?
611 --  --Isaac Dupree
612
613 exactLog2 :: Integer -> Maybe Integer
614 exactLog2 x_
615   = if (x_ <= 0 || x_ >= 2147483648) then
616        Nothing
617     else
618        case iUnbox (fromInteger x_) of { x ->
619        if (x `bitAndFastInt` negateFastInt x) /=# x then
620           Nothing
621        else
622           Just (toInteger (iBox (pow2 x)))
623        }
624   where
625     pow2 x | x ==# _ILIT(1) = _ILIT(0)
626            | otherwise = _ILIT(1) +# pow2 (x `shiftR_FastInt` _ILIT(1))
627
628
629 -- -----------------------------------------------------------------------------
630 -- Loopify for C
631
632 {-
633  This is a simple pass that replaces tail-recursive functions like this:
634
635    fac() {
636      ...
637      jump fac();
638    }
639
640  with this:
641
642   fac() {
643    L:
644      ...
645      goto L;
646   }
647
648   the latter generates better C code, because the C compiler treats it
649   like a loop, and brings full loop optimisation to bear.
650
651   In my measurements this makes little or no difference to anything
652   except factorial, but what the hell.
653 -}
654
655 cmmLoopifyForC :: RawCmmTop -> RawCmmTop
656 cmmLoopifyForC p@(CmmProc info entry_lbl
657                  (ListGraph blocks@(BasicBlock top_id _ : _)))
658   | null info = p  -- only if there's an info table, ignore case alts
659   | otherwise =  
660 --  pprTrace "jump_lbl" (ppr jump_lbl <+> ppr entry_lbl) $
661   CmmProc info entry_lbl (ListGraph blocks')
662   where blocks' = [ BasicBlock id (map do_stmt stmts)
663                   | BasicBlock id stmts <- blocks ]
664
665         do_stmt (CmmJump (CmmLit (CmmLabel lbl)) _) | lbl == jump_lbl
666                 = CmmBranch top_id
667         do_stmt stmt = stmt
668
669         jump_lbl | tablesNextToCode = entryLblToInfoLbl entry_lbl
670                  | otherwise        = entry_lbl
671
672 cmmLoopifyForC top = top
673
674 -- -----------------------------------------------------------------------------
675 -- Utils
676
677 isLit (CmmLit _) = True
678 isLit _          = False
679
680 isComparisonExpr :: CmmExpr -> Bool
681 isComparisonExpr (CmmMachOp op _) = isComparisonMachOp op
682 isComparisonExpr _other             = False
683
684 isPicReg (CmmReg (CmmGlobal PicBaseReg)) = True
685 isPicReg _ = False
686