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
8 -----------------------------------------------------------------------------
12 -- (c) The University of Glasgow 2006
14 -----------------------------------------------------------------------------
17 cmmEliminateDeadBlocks,
23 #include "HsVersions.h"
42 import Compiler.Hoopl hiding (Unique)
44 -- -----------------------------------------------------------------------------
45 -- Eliminates dead blocks
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
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
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
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
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
89 reachable = go [base_id] (setEmpty :: BlockSet)
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
98 -- -----------------------------------------------------------------------------
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
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.
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]
119 Possible generalisations: here is an example from factorial
124 if (_smi != 0) goto cmK;
131 jump Fac_zdwfac_info;
133 We want to inline _smi and _smn. To inline _smn:
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
142 - It is a trivial replacement, reg for reg, but it occurs more than
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
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
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)
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
168 -- used (literal): try to inline at all the use sites
169 | Just n <- lookupUFM uses u, isLit expr
172 trace ("nativeGen: inlining " ++ showSDoc (pprStmt stmt)) $
174 case lookForInlineLit u expr stmts of
176 | n == m -> cmmMiniInlineStmts (delFromUFM uses u) stmts'
178 stmt : cmmMiniInlineStmts (adjustUFM (\x -> x - m) uses u) stmts'
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
186 trace ("nativeGen: inlining " ++ showSDoc (pprStmt stmt)) $
188 case lookForInlineLit u e stmts of
190 | n == m -> cmmMiniInlineStmts (delFromUFM uses u) stmts'
192 stmt : cmmMiniInlineStmts (adjustUFM (\x -> x - m) uses u) stmts'
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
199 trace ("nativeGen: inlining " ++ showSDoc (pprStmt stmt)) $
201 cmmMiniInlineStmts uses stmts'
203 cmmMiniInlineStmts uses (stmt:stmts)
204 = stmt : cmmMiniInlineStmts uses stmts
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)
219 = case lookForInlineLit u expr rest of
220 (n, stmts) -> (n, stmt : stmts)
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
231 lookForInline u expr stmts = lookForInline' u expr regset stmts
232 where regset = foldRegsUsed extendRegSet emptyRegSet expr
234 lookForInline' u expr regset (stmt : rest)
235 | Just 1 <- lookupUFM (countUses stmt) u, ok_to_inline
236 = Just (inlineStmt u expr stmt : rest)
239 = case lookForInline' u expr regset rest of
241 Just stmts -> Just (stmt:stmts)
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
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
267 CmmAssign (CmmLocal r@(LocalReg u' _)) rhs | u' /= u && not (r `elemRegSet` regset) -> True
268 CmmAssign g@(CmmGlobal _) rhs -> not (g `regUsedIn` expr)
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
285 inlineExpr :: Unique -> CmmExpr -> CmmExpr -> CmmExpr
286 inlineExpr u a e@(CmmReg (CmmLocal (LocalReg u' _)))
289 inlineExpr u a e@(CmmRegOff (CmmLocal (LocalReg u' rep)) off)
290 | u == u' = CmmMachOp (MO_Add width) [a, CmmLit (CmmInt (fromIntegral off) width)]
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
298 -- -----------------------------------------------------------------------------
299 -- MachOp constant folder
301 -- Now, try to constant-fold the MachOps. The arguments have already
302 -- been optimized and folded.
305 :: MachOp -- The operation from an CmmMachOp
306 -> [CmmExpr] -- The optimized arguments
309 cmmMachOpFold op arg@[CmmLit (CmmInt x rep)]
311 MO_S_Neg r -> CmmLit (CmmInt (-x) rep)
312 MO_Not r -> CmmLit (CmmInt (complement x) rep)
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)
322 _ -> panic "cmmMachOpFold: unknown unary op"
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
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
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]
348 CmmMachOp conv_outer args
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
356 intconv True = MO_SS_Conv
357 intconv False = MO_UU_Conv
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?
363 cmmMachOpFold mop args@[CmmLit (CmmInt x xrep), CmmLit (CmmInt y _)]
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)
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)
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)
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)
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)
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)
396 other -> CmmMachOp mop args
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
410 cmmMachOpFold op [x@(CmmLit _), y]
411 | not (isLit y) && isCommutableMachOp op
412 = cmmMachOpFold op [y, x]
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
419 -- ToDo: this appears to introduce a quadratic behaviour due to the
420 -- nested cmmMachOpFold. Can we fix this?
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) ...
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).
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]]
435 MO_Add{} `associates_with` MO_Sub{} = True
436 mop1 `associates_with` mop2 =
437 mop1 == mop2 && isAssociativeMachOp mop1
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]]
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))
454 -- Fold label(+/-)offset into a CmmLit where possible
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))))
464 -- Comparison of literal with widened operand: perform the comparison
465 -- at the smaller width, as long as the literal is within range.
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.
471 #if i386_TARGET_ARCH || x86_64_TARGET_ARCH
472 -- powerPC NCG has a TODO for I8/I16 comparisons, so don't try
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:
481 -- then we can do the comparison at the smaller size
482 = cmmMachOpFold narrow_cmp [x, CmmLit (CmmInt i rep)]
484 maybe_conversion (MO_UU_Conv from to)
486 = Just (from, False, narrowU)
487 maybe_conversion (MO_SS_Conv from to)
489 = Just (from, True, narrowS)
491 -- don't attempt to apply this optimisation when the source
492 -- is a float; see #1916
493 maybe_conversion _ = Nothing
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
515 -- We can often do something with constants of 0 and 1 ...
517 cmmMachOpFold mop args@[x, y@(CmmLit (CmmInt 0 _))]
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
540 cmmMachOpFold mop args@[x, y@(CmmLit (CmmInt 1 rep))]
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
559 -- Now look for multiplication/division by powers of 2 (integers).
561 cmmMachOpFold mop args@[x, y@(CmmLit (CmmInt n _))]
564 | Just p <- exactLog2 n ->
565 cmmMachOpFold (MO_Shl rep) [x, CmmLit (CmmInt p rep)]
567 | Just p <- exactLog2 n ->
568 cmmMachOpFold (MO_U_Shr rep) [x, CmmLit (CmmInt p 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.
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.
585 -- we optimise the divide by 2 case slightly, generating
586 -- x1 = x >> word_size-1 (unsigned)
587 -- return = (x + x1) >>= log2(divisor)
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]
596 cmmMachOpFold (MO_S_Shr rep) [x3, CmmLit (CmmInt p rep)]
600 unchanged = CmmMachOp mop args
602 -- Anything else is just too hard.
604 cmmMachOpFold mop args = CmmMachOp mop args
606 -- -----------------------------------------------------------------------------
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.
613 -- Used to be in MachInstrs --SDM.
614 -- ToDo: remove use of unboxery --SDM.
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)?
622 exactLog2 :: Integer -> Maybe Integer
624 = if (x_ <= 0 || x_ >= 2147483648) then
627 case iUnbox (fromInteger x_) of { x ->
628 if (x `bitAndFastInt` negateFastInt x) /=# x then
631 Just (toInteger (iBox (pow2 x)))
634 pow2 x | x ==# _ILIT(1) = _ILIT(0)
635 | otherwise = _ILIT(1) +# pow2 (x `shiftR_FastInt` _ILIT(1))
638 -- -----------------------------------------------------------------------------
642 This is a simple pass that replaces tail-recursive functions like this:
657 the latter generates better C code, because the C compiler treats it
658 like a loop, and brings full loop optimisation to bear.
660 In my measurements this makes little or no difference to anything
661 except factorial, but what the hell.
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
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 ]
674 do_stmt (CmmJump (CmmLit (CmmLabel lbl)) _) | lbl == jump_lbl
678 jump_lbl | tablesNextToCode = entryLblToInfoLbl entry_lbl
679 | otherwise = entry_lbl
681 cmmLoopifyForC top = top
683 -- -----------------------------------------------------------------------------
686 isLit (CmmLit _) = True
689 isComparisonExpr :: CmmExpr -> Bool
690 isComparisonExpr (CmmMachOp op _) = isComparisonMachOp op
691 isComparisonExpr _other = False
693 isPicReg (CmmReg (CmmGlobal PicBaseReg)) = True