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 -----------------------------------------------------------------------------
22 #include "HsVersions.h"
39 -- -----------------------------------------------------------------------------
43 This pass inlines assignments to temporaries that are used just
44 once. It works as follows:
46 - count uses of each temporary
47 - for each temporary that occurs just once:
48 - attempt to push it forward to the statement that uses it
49 - only push forward past assignments to other temporaries
50 (assumes that temporaries are single-assignment)
51 - if we reach the statement that uses it, inline the rhs
52 and delete the original assignment.
54 [N.B. In the Quick C-- compiler, this optimization is achieved by a
55 combination of two dataflow passes: forward substitution (peephole
56 optimization) and dead-assignment elimination. ---NR]
58 Possible generalisations: here is an example from factorial
63 if (_smi != 0) goto cmK;
72 We want to inline _smi and _smn. To inline _smn:
74 - we must be able to push forward past assignments to global regs.
75 We can do this if the rhs of the assignment we are pushing
76 forward doesn't refer to the global reg being assigned to; easy
81 - It is a trivial replacement, reg for reg, but it occurs more than
83 - We can inline trivial assignments even if the temporary occurs
84 more than once, as long as we don't eliminate the original assignment
85 (this doesn't help much on its own).
86 - We need to be able to propagate the assignment forward through jumps;
87 if we did this, we would find that it can be inlined safely in all
91 countUses :: UserOfLocalRegs a => a -> UniqFM Int
92 countUses a = foldRegsUsed (\m r -> addToUFM m r (count m r + 1)) emptyUFM a
93 where count m r = lookupWithDefaultUFM m (0::Int) r
95 cmmMiniInline :: [CmmBasicBlock] -> [CmmBasicBlock]
96 cmmMiniInline blocks = map do_inline blocks
97 where do_inline (BasicBlock id stmts)
98 = BasicBlock id (cmmMiniInlineStmts (countUses blocks) stmts)
100 cmmMiniInlineStmts :: UniqFM Int -> [CmmStmt] -> [CmmStmt]
101 cmmMiniInlineStmts uses [] = []
102 cmmMiniInlineStmts uses (stmt@(CmmAssign (CmmLocal (LocalReg u _)) expr) : stmts)
103 -- not used at all: just discard this assignment
104 | Nothing <- lookupUFM uses u
105 = cmmMiniInlineStmts uses stmts
107 -- used once: try to inline at the use site
108 | Just 1 <- lookupUFM uses u,
109 Just stmts' <- lookForInline u expr stmts
112 trace ("nativeGen: inlining " ++ showSDoc (pprStmt stmt)) $
114 cmmMiniInlineStmts uses stmts'
116 cmmMiniInlineStmts uses (stmt:stmts)
117 = stmt : cmmMiniInlineStmts uses stmts
119 lookForInline u expr (stmt : rest)
120 | Just 1 <- lookupUFM (countUses stmt) u, ok_to_inline
121 = Just (inlineStmt u expr stmt : rest)
124 = case lookForInline u expr rest of
126 Just stmts -> Just (stmt:stmts)
132 -- we don't inline into CmmCall if the expression refers to global
133 -- registers. This is a HACK to avoid global registers clashing with
134 -- C argument-passing registers, really the back-end ought to be able
135 -- to handle it properly, but currently neither PprC nor the NCG can
136 -- do it. See also CgForeignCall:load_args_into_temps.
137 ok_to_inline = case stmt of
138 CmmCall{} -> hasNoGlobalRegs expr
141 -- We can skip over assignments to other tempoararies, because we
142 -- know that expressions aren't side-effecting and temporaries are
143 -- single-assignment.
144 ok_to_skip = case stmt of
146 CmmAssign (CmmLocal (LocalReg u' _)) rhs | u' /= u -> True
147 CmmAssign g@(CmmGlobal _) rhs -> not (g `regUsedIn` expr)
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
164 inlineExpr :: Unique -> CmmExpr -> CmmExpr -> CmmExpr
165 inlineExpr u a e@(CmmReg (CmmLocal (LocalReg u' _)))
168 inlineExpr u a e@(CmmRegOff (CmmLocal (LocalReg u' rep)) off)
169 | u == u' = CmmMachOp (MO_Add width) [a, CmmLit (CmmInt (fromIntegral off) width)]
172 width = typeWidth rep
173 inlineExpr u a (CmmLoad e rep) = CmmLoad (inlineExpr u a e) rep
174 inlineExpr u a (CmmMachOp op es) = CmmMachOp op (map (inlineExpr u a) es)
175 inlineExpr u a other_expr = other_expr
177 -- -----------------------------------------------------------------------------
178 -- MachOp constant folder
180 -- Now, try to constant-fold the MachOps. The arguments have already
181 -- been optimized and folded.
184 :: MachOp -- The operation from an CmmMachOp
185 -> [CmmExpr] -- The optimized arguments
188 cmmMachOpFold op arg@[CmmLit (CmmInt x rep)]
190 MO_S_Neg r -> CmmLit (CmmInt (-x) rep)
191 MO_Not r -> CmmLit (CmmInt (complement x) rep)
193 -- these are interesting: we must first narrow to the
194 -- "from" type, in order to truncate to the correct size.
195 -- The final narrow/widen to the destination type
196 -- is implicit in the CmmLit.
197 MO_SF_Conv from to -> CmmLit (CmmFloat (fromInteger x) to)
198 MO_SS_Conv from to -> CmmLit (CmmInt (narrowS from x) to)
199 MO_UU_Conv from to -> CmmLit (CmmInt (narrowU from x) to)
201 _ -> panic "cmmMachOpFold: unknown unary op"
204 -- Eliminate conversion NOPs
205 cmmMachOpFold (MO_SS_Conv rep1 rep2) [x] | rep1 == rep2 = x
206 cmmMachOpFold (MO_UU_Conv rep1 rep2) [x] | rep1 == rep2 = x
208 -- Eliminate nested conversions where possible
209 cmmMachOpFold conv_outer args@[CmmMachOp conv_inner [x]]
210 | Just (rep1,rep2,signed1) <- isIntConversion conv_inner,
211 Just (_, rep3,signed2) <- isIntConversion conv_outer
213 -- widen then narrow to the same size is a nop
214 _ | rep1 < rep2 && rep1 == rep3 -> x
215 -- Widen then narrow to different size: collapse to single conversion
216 -- but remember to use the signedness from the widening, just in case
217 -- the final conversion is a widen.
218 | rep1 < rep2 && rep2 > rep3 ->
219 cmmMachOpFold (intconv signed1 rep1 rep3) [x]
220 -- Nested widenings: collapse if the signedness is the same
221 | rep1 < rep2 && rep2 < rep3 && signed1 == signed2 ->
222 cmmMachOpFold (intconv signed1 rep1 rep3) [x]
223 -- Nested narrowings: collapse
224 | rep1 > rep2 && rep2 > rep3 ->
225 cmmMachOpFold (MO_UU_Conv rep1 rep3) [x]
227 CmmMachOp conv_outer args
229 isIntConversion (MO_UU_Conv rep1 rep2)
230 = Just (rep1,rep2,False)
231 isIntConversion (MO_SS_Conv rep1 rep2)
232 = Just (rep1,rep2,True)
233 isIntConversion _ = Nothing
235 intconv True = MO_SS_Conv
236 intconv False = MO_UU_Conv
238 -- ToDo: a narrow of a load can be collapsed into a narrow load, right?
239 -- but what if the architecture only supports word-sized loads, should
240 -- we do the transformation anyway?
242 cmmMachOpFold mop args@[CmmLit (CmmInt x xrep), CmmLit (CmmInt y _)]
244 -- for comparisons: don't forget to narrow the arguments before
245 -- comparing, since they might be out of range.
246 MO_Eq r -> CmmLit (CmmInt (if x_u == y_u then 1 else 0) wordWidth)
247 MO_Ne r -> CmmLit (CmmInt (if x_u /= y_u then 1 else 0) wordWidth)
249 MO_U_Gt r -> CmmLit (CmmInt (if x_u > y_u then 1 else 0) wordWidth)
250 MO_U_Ge r -> CmmLit (CmmInt (if x_u >= y_u then 1 else 0) wordWidth)
251 MO_U_Lt r -> CmmLit (CmmInt (if x_u < y_u then 1 else 0) wordWidth)
252 MO_U_Le r -> CmmLit (CmmInt (if x_u <= y_u then 1 else 0) wordWidth)
254 MO_S_Gt r -> CmmLit (CmmInt (if x_s > y_s then 1 else 0) wordWidth)
255 MO_S_Ge r -> CmmLit (CmmInt (if x_s >= y_s then 1 else 0) wordWidth)
256 MO_S_Lt r -> CmmLit (CmmInt (if x_s < y_s then 1 else 0) wordWidth)
257 MO_S_Le r -> CmmLit (CmmInt (if x_s <= y_s then 1 else 0) wordWidth)
259 MO_Add r -> CmmLit (CmmInt (x + y) r)
260 MO_Sub r -> CmmLit (CmmInt (x - y) r)
261 MO_Mul r -> CmmLit (CmmInt (x * y) r)
262 MO_U_Quot r | y /= 0 -> CmmLit (CmmInt (x_u `quot` y_u) r)
263 MO_U_Rem r | y /= 0 -> CmmLit (CmmInt (x_u `rem` y_u) r)
264 MO_S_Quot r | y /= 0 -> CmmLit (CmmInt (x `quot` y) r)
265 MO_S_Rem r | y /= 0 -> CmmLit (CmmInt (x `rem` y) r)
267 MO_And r -> CmmLit (CmmInt (x .&. y) r)
268 MO_Or r -> CmmLit (CmmInt (x .|. y) r)
269 MO_Xor r -> CmmLit (CmmInt (x `xor` y) r)
271 MO_Shl r -> CmmLit (CmmInt (x `shiftL` fromIntegral y) r)
272 MO_U_Shr r -> CmmLit (CmmInt (x_u `shiftR` fromIntegral y) r)
273 MO_S_Shr r -> CmmLit (CmmInt (x `shiftR` fromIntegral y) r)
275 other -> CmmMachOp mop args
284 -- When possible, shift the constants to the right-hand side, so that we
285 -- can match for strength reductions. Note that the code generator will
286 -- also assume that constants have been shifted to the right when
289 cmmMachOpFold op [x@(CmmLit _), y]
290 | not (isLit y) && isCommutableMachOp op
291 = cmmMachOpFold op [y, x]
293 -- Turn (a+b)+c into a+(b+c) where possible. Because literals are
294 -- moved to the right, it is more likely that we will find
295 -- opportunities for constant folding when the expression is
298 -- ToDo: this appears to introduce a quadratic behaviour due to the
299 -- nested cmmMachOpFold. Can we fix this?
301 -- Why do we check isLit arg1? If arg1 is a lit, it means that arg2
302 -- is also a lit (otherwise arg1 would be on the right). If we
303 -- put arg1 on the left of the rearranged expression, we'll get into a
304 -- loop: (x1+x2)+x3 => x1+(x2+x3) => (x2+x3)+x1 => x2+(x3+x1) ...
306 -- Also don't do it if arg1 is PicBaseReg, so that we don't separate the
307 -- PicBaseReg from the corresponding label (or label difference).
309 cmmMachOpFold mop1 [CmmMachOp mop2 [arg1,arg2], arg3]
310 | mop1 == mop2 && isAssociativeMachOp mop1
311 && not (isLit arg1) && not (isPicReg arg1)
312 = cmmMachOpFold mop1 [arg1, cmmMachOpFold mop2 [arg2,arg3]]
314 -- Make a RegOff if we can
315 cmmMachOpFold (MO_Add _) [CmmReg reg, CmmLit (CmmInt n rep)]
316 = CmmRegOff reg (fromIntegral (narrowS rep n))
317 cmmMachOpFold (MO_Add _) [CmmRegOff reg off, CmmLit (CmmInt n rep)]
318 = CmmRegOff reg (off + fromIntegral (narrowS rep n))
319 cmmMachOpFold (MO_Sub _) [CmmReg reg, CmmLit (CmmInt n rep)]
320 = CmmRegOff reg (- fromIntegral (narrowS rep n))
321 cmmMachOpFold (MO_Sub _) [CmmRegOff reg off, CmmLit (CmmInt n rep)]
322 = CmmRegOff reg (off - fromIntegral (narrowS rep n))
324 -- Fold label(+/-)offset into a CmmLit where possible
326 cmmMachOpFold (MO_Add _) [CmmLit (CmmLabel lbl), CmmLit (CmmInt i rep)]
327 = CmmLit (CmmLabelOff lbl (fromIntegral (narrowU rep i)))
328 cmmMachOpFold (MO_Add _) [CmmLit (CmmInt i rep), CmmLit (CmmLabel lbl)]
329 = CmmLit (CmmLabelOff lbl (fromIntegral (narrowU rep i)))
330 cmmMachOpFold (MO_Sub _) [CmmLit (CmmLabel lbl), CmmLit (CmmInt i rep)]
331 = CmmLit (CmmLabelOff lbl (fromIntegral (negate (narrowU rep i))))
334 -- Comparison of literal with widened operand: perform the comparison
335 -- at the smaller width, as long as the literal is within range.
337 -- We can't do the reverse trick, when the operand is narrowed:
338 -- narrowing throws away bits from the operand, there's no way to do
339 -- the same comparison at the larger size.
341 #if i386_TARGET_ARCH || x86_64_TARGET_ARCH
342 -- powerPC NCG has a TODO for I8/I16 comparisons, so don't try
344 cmmMachOpFold cmp [CmmMachOp conv [x], CmmLit (CmmInt i _)]
345 | -- if the operand is widened:
346 Just (rep, signed, narrow_fn) <- maybe_conversion conv,
347 -- and this is a comparison operation:
348 Just narrow_cmp <- maybe_comparison cmp rep signed,
349 -- and the literal fits in the smaller size:
351 -- then we can do the comparison at the smaller size
352 = cmmMachOpFold narrow_cmp [x, CmmLit (CmmInt i rep)]
354 maybe_conversion (MO_UU_Conv from to)
356 = Just (from, False, narrowU)
357 maybe_conversion (MO_SS_Conv from to)
359 = Just (from, True, narrowS)
361 -- don't attempt to apply this optimisation when the source
362 -- is a float; see #1916
363 maybe_conversion _ = Nothing
365 -- careful (#2080): if the original comparison was signed, but
366 -- we were doing an unsigned widen, then we must do an
367 -- unsigned comparison at the smaller size.
368 maybe_comparison (MO_U_Gt _) rep _ = Just (MO_U_Gt rep)
369 maybe_comparison (MO_U_Ge _) rep _ = Just (MO_U_Ge rep)
370 maybe_comparison (MO_U_Lt _) rep _ = Just (MO_U_Lt rep)
371 maybe_comparison (MO_U_Le _) rep _ = Just (MO_U_Le rep)
372 maybe_comparison (MO_Eq _) rep _ = Just (MO_Eq rep)
373 maybe_comparison (MO_S_Gt _) rep True = Just (MO_S_Gt rep)
374 maybe_comparison (MO_S_Ge _) rep True = Just (MO_S_Ge rep)
375 maybe_comparison (MO_S_Lt _) rep True = Just (MO_S_Lt rep)
376 maybe_comparison (MO_S_Le _) rep True = Just (MO_S_Le rep)
377 maybe_comparison (MO_S_Gt _) rep False = Just (MO_U_Gt rep)
378 maybe_comparison (MO_S_Ge _) rep False = Just (MO_U_Ge rep)
379 maybe_comparison (MO_S_Lt _) rep False = Just (MO_U_Lt rep)
380 maybe_comparison (MO_S_Le _) rep False = Just (MO_U_Le rep)
381 maybe_comparison _ _ _ = Nothing
385 -- We can often do something with constants of 0 and 1 ...
387 cmmMachOpFold mop args@[x, y@(CmmLit (CmmInt 0 _))]
398 MO_Ne r | isComparisonExpr x -> x
399 MO_Eq r | Just x' <- maybeInvertCmmExpr x -> x'
400 MO_U_Gt r | isComparisonExpr x -> x
401 MO_S_Gt r | isComparisonExpr x -> x
402 MO_U_Lt r | isComparisonExpr x -> CmmLit (CmmInt 0 wordWidth)
403 MO_S_Lt r | isComparisonExpr x -> CmmLit (CmmInt 0 wordWidth)
404 MO_U_Ge r | isComparisonExpr x -> CmmLit (CmmInt 1 wordWidth)
405 MO_S_Ge r | isComparisonExpr x -> CmmLit (CmmInt 1 wordWidth)
406 MO_U_Le r | Just x' <- maybeInvertCmmExpr x -> x'
407 MO_S_Le r | Just x' <- maybeInvertCmmExpr x -> x'
408 other -> CmmMachOp mop args
410 cmmMachOpFold mop args@[x, y@(CmmLit (CmmInt 1 rep))]
415 MO_S_Rem r -> CmmLit (CmmInt 0 rep)
416 MO_U_Rem r -> CmmLit (CmmInt 0 rep)
417 MO_Ne r | Just x' <- maybeInvertCmmExpr x -> x'
418 MO_Eq r | isComparisonExpr x -> x
419 MO_U_Lt r | Just x' <- maybeInvertCmmExpr x -> x'
420 MO_S_Lt r | Just x' <- maybeInvertCmmExpr x -> x'
421 MO_U_Gt r | isComparisonExpr x -> CmmLit (CmmInt 0 wordWidth)
422 MO_S_Gt r | isComparisonExpr x -> CmmLit (CmmInt 0 wordWidth)
423 MO_U_Le r | isComparisonExpr x -> CmmLit (CmmInt 1 wordWidth)
424 MO_S_Le r | isComparisonExpr x -> CmmLit (CmmInt 1 wordWidth)
425 MO_U_Ge r | isComparisonExpr x -> x
426 MO_S_Ge r | isComparisonExpr x -> x
427 other -> CmmMachOp mop args
429 -- Now look for multiplication/division by powers of 2 (integers).
431 cmmMachOpFold mop args@[x, y@(CmmLit (CmmInt n _))]
434 | Just p <- exactLog2 n ->
435 CmmMachOp (MO_Shl rep) [x, CmmLit (CmmInt p rep)]
437 | Just p <- exactLog2 n ->
438 CmmMachOp (MO_U_Shr rep) [x, CmmLit (CmmInt p rep)]
440 | Just p <- exactLog2 n,
441 CmmReg _ <- x -> -- We duplicate x below, hence require
442 -- it is a reg. FIXME: remove this restriction.
443 -- shift right is not the same as quot, because it rounds
444 -- to minus infinity, whereasq quot rounds toward zero.
445 -- To fix this up, we add one less than the divisor to the
446 -- dividend if it is a negative number.
448 -- to avoid a test/jump, we use the following sequence:
449 -- x1 = x >> word_size-1 (all 1s if -ve, all 0s if +ve)
450 -- x2 = y & (divisor-1)
451 -- result = (x+x2) >>= log2(divisor)
452 -- this could be done a bit more simply using conditional moves,
453 -- but we're processor independent here.
455 -- we optimise the divide by 2 case slightly, generating
456 -- x1 = x >> word_size-1 (unsigned)
457 -- return = (x + x1) >>= log2(divisor)
459 bits = fromIntegral (widthInBits rep) - 1
460 shr = if p == 1 then MO_U_Shr rep else MO_S_Shr rep
461 x1 = CmmMachOp shr [x, CmmLit (CmmInt bits rep)]
462 x2 = if p == 1 then x1 else
463 CmmMachOp (MO_And rep) [x1, CmmLit (CmmInt (n-1) rep)]
464 x3 = CmmMachOp (MO_Add rep) [x, x2]
466 CmmMachOp (MO_S_Shr rep) [x3, CmmLit (CmmInt p rep)]
470 unchanged = CmmMachOp mop args
472 -- Anything else is just too hard.
474 cmmMachOpFold mop args = CmmMachOp mop args
476 -- -----------------------------------------------------------------------------
479 -- This algorithm for determining the $\log_2$ of exact powers of 2 comes
480 -- from GCC. It requires bit manipulation primitives, and we use GHC
481 -- extensions. Tough.
483 -- Used to be in MachInstrs --SDM.
484 -- ToDo: remove use of unboxery --SDM.
486 -- Unboxery removed in favor of FastInt; but is the function supposed to fail
487 -- on inputs >= 2147483648, or was that just an implementation artifact?
488 -- And is this speed-critical, or can we just use Integer operations
489 -- (including Data.Bits)?
492 exactLog2 :: Integer -> Maybe Integer
494 = if (x_ <= 0 || x_ >= 2147483648) then
497 case iUnbox (fromInteger x_) of { x ->
498 if (x `bitAndFastInt` negateFastInt x) /=# x then
501 Just (toInteger (iBox (pow2 x)))
504 pow2 x | x ==# _ILIT(1) = _ILIT(0)
505 | otherwise = _ILIT(1) +# pow2 (x `shiftR_FastInt` _ILIT(1))
508 -- -----------------------------------------------------------------------------
512 This is a simple pass that replaces tail-recursive functions like this:
527 the latter generates better C code, because the C compiler treats it
528 like a loop, and brings full loop optimisation to bear.
530 In my measurements this makes little or no difference to anything
531 except factorial, but what the hell.
534 cmmLoopifyForC :: RawCmmTop -> RawCmmTop
535 cmmLoopifyForC p@(CmmProc info entry_lbl []
536 (ListGraph blocks@(BasicBlock top_id _ : _)))
537 | null info = p -- only if there's an info table, ignore case alts
539 -- pprTrace "jump_lbl" (ppr jump_lbl <+> ppr entry_lbl) $
540 CmmProc info entry_lbl [] (ListGraph blocks')
541 where blocks' = [ BasicBlock id (map do_stmt stmts)
542 | BasicBlock id stmts <- blocks ]
544 do_stmt (CmmJump (CmmLit (CmmLabel lbl)) _) | lbl == jump_lbl
548 jump_lbl | tablesNextToCode = entryLblToInfoLbl entry_lbl
549 | otherwise = entry_lbl
551 cmmLoopifyForC top = top
553 -- -----------------------------------------------------------------------------
556 isLit (CmmLit _) = True
559 isComparisonExpr :: CmmExpr -> Bool
560 isComparisonExpr (CmmMachOp op _) = isComparisonMachOp op
561 isComparisonExpr _other = False
563 isPicReg (CmmReg (CmmGlobal PicBaseReg)) = True