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"
40 -- -----------------------------------------------------------------------------
44 This pass inlines assignments to temporaries that are used just
45 once. It works as follows:
47 - count uses of each temporary
48 - for each temporary that occurs just once:
49 - attempt to push it forward to the statement that uses it
50 - only push forward past assignments to other temporaries
51 (assumes that temporaries are single-assignment)
52 - if we reach the statement that uses it, inline the rhs
53 and delete the original assignment.
55 [N.B. In the Quick C-- compiler, this optimization is achieved by a
56 combination of two dataflow passes: forward substitution (peephole
57 optimization) and dead-assignment elimination. ---NR]
59 Possible generalisations: here is an example from factorial
64 if (_smi != 0) goto cmK;
73 We want to inline _smi and _smn. To inline _smn:
75 - we must be able to push forward past assignments to global regs.
76 We can do this if the rhs of the assignment we are pushing
77 forward doesn't refer to the global reg being assigned to; easy
82 - It is a trivial replacement, reg for reg, but it occurs more than
84 - We can inline trivial assignments even if the temporary occurs
85 more than once, as long as we don't eliminate the original assignment
86 (this doesn't help much on its own).
87 - We need to be able to propagate the assignment forward through jumps;
88 if we did this, we would find that it can be inlined safely in all
92 countUses :: UserOfLocalRegs a => a -> UniqFM Int
93 countUses a = foldRegsUsed (\m r -> addToUFM m r (count m r + 1)) emptyUFM a
94 where count m r = lookupWithDefaultUFM m (0::Int) r
96 cmmMiniInline :: [CmmBasicBlock] -> [CmmBasicBlock]
97 cmmMiniInline blocks = map do_inline blocks
98 where do_inline (BasicBlock id stmts)
99 = BasicBlock id (cmmMiniInlineStmts (countUses blocks) stmts)
101 cmmMiniInlineStmts :: UniqFM Int -> [CmmStmt] -> [CmmStmt]
102 cmmMiniInlineStmts uses [] = []
103 cmmMiniInlineStmts uses (stmt@(CmmAssign (CmmLocal (LocalReg u _ _)) expr) : stmts)
104 -- not used at all: just discard this assignment
105 | Nothing <- lookupUFM uses u
106 = cmmMiniInlineStmts uses stmts
108 -- used once: try to inline at the use site
109 | Just 1 <- lookupUFM uses u,
110 Just stmts' <- lookForInline u expr stmts
113 trace ("nativeGen: inlining " ++ showSDoc (pprStmt stmt)) $
115 cmmMiniInlineStmts uses stmts'
117 cmmMiniInlineStmts uses (stmt:stmts)
118 = stmt : cmmMiniInlineStmts uses stmts
121 -- Try to inline a temporary assignment. We can skip over assignments to
122 -- other tempoararies, because we know that expressions aren't side-effecting
123 -- and temporaries are single-assignment.
124 lookForInline u expr (stmt@(CmmAssign (CmmLocal (LocalReg u' _ _)) rhs) : rest)
126 = case lookupUFM (countUses rhs) u of
127 Just 1 -> Just (inlineStmt u expr stmt : rest)
128 _other -> case lookForInline u expr rest of
130 Just stmts -> Just (stmt:stmts)
132 lookForInline u expr (CmmNop : rest)
133 = lookForInline u expr rest
135 lookForInline _ _ [] = Nothing
137 lookForInline u expr (stmt:stmts)
138 = case lookupUFM (countUses stmt) u of
139 Just 1 | ok_to_inline -> Just (inlineStmt u expr stmt : stmts)
142 -- we don't inline into CmmCall if the expression refers to global
143 -- registers. This is a HACK to avoid global registers clashing with
144 -- C argument-passing registers, really the back-end ought to be able
145 -- to handle it properly, but currently neither PprC nor the NCG can
146 -- do it. See also CgForeignCall:load_args_into_temps.
147 ok_to_inline = case stmt of
148 CmmCall{} -> hasNoGlobalRegs expr
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 rep) [a, CmmLit (CmmInt (fromIntegral off) rep)]
171 inlineExpr u a (CmmLoad e rep) = CmmLoad (inlineExpr u a e) rep
172 inlineExpr u a (CmmMachOp op es) = CmmMachOp op (map (inlineExpr u a) es)
173 inlineExpr u a other_expr = other_expr
175 -- -----------------------------------------------------------------------------
176 -- MachOp constant folder
178 -- Now, try to constant-fold the MachOps. The arguments have already
179 -- been optimized and folded.
182 :: MachOp -- The operation from an CmmMachOp
183 -> [CmmExpr] -- The optimized arguments
186 cmmMachOpFold op arg@[CmmLit (CmmInt x rep)]
188 MO_S_Neg r -> CmmLit (CmmInt (-x) rep)
189 MO_Not r -> CmmLit (CmmInt (complement x) rep)
191 -- these are interesting: we must first narrow to the
192 -- "from" type, in order to truncate to the correct size.
193 -- The final narrow/widen to the destination type
194 -- is implicit in the CmmLit.
196 | isFloatingRep to -> CmmLit (CmmFloat (fromInteger x) to)
197 | otherwise -> CmmLit (CmmInt (narrowS from x) to)
198 MO_U_Conv from to -> CmmLit (CmmInt (narrowU from x) to)
200 _ -> panic "cmmMachOpFold: unknown unary op"
203 -- Eliminate conversion NOPs
204 cmmMachOpFold (MO_S_Conv rep1 rep2) [x] | rep1 == rep2 = x
205 cmmMachOpFold (MO_U_Conv rep1 rep2) [x] | rep1 == rep2 = x
207 -- Eliminate nested conversions where possible
208 cmmMachOpFold conv_outer args@[CmmMachOp conv_inner [x]]
209 | Just (rep1,rep2,signed1) <- isIntConversion conv_inner,
210 Just (_, rep3,signed2) <- isIntConversion conv_outer
212 -- widen then narrow to the same size is a nop
213 _ | rep1 < rep2 && rep1 == rep3 -> x
214 -- Widen then narrow to different size: collapse to single conversion
215 -- but remember to use the signedness from the widening, just in case
216 -- the final conversion is a widen.
217 | rep1 < rep2 && rep2 > rep3 ->
218 cmmMachOpFold (intconv signed1 rep1 rep3) [x]
219 -- Nested widenings: collapse if the signedness is the same
220 | rep1 < rep2 && rep2 < rep3 && signed1 == signed2 ->
221 cmmMachOpFold (intconv signed1 rep1 rep3) [x]
222 -- Nested narrowings: collapse
223 | rep1 > rep2 && rep2 > rep3 ->
224 cmmMachOpFold (MO_U_Conv rep1 rep3) [x]
226 CmmMachOp conv_outer args
228 isIntConversion (MO_U_Conv rep1 rep2)
229 | not (isFloatingRep rep1) && not (isFloatingRep rep2)
230 = Just (rep1,rep2,False)
231 isIntConversion (MO_S_Conv rep1 rep2)
232 | not (isFloatingRep rep1) && not (isFloatingRep rep2)
233 = Just (rep1,rep2,True)
234 isIntConversion _ = Nothing
236 intconv True = MO_S_Conv
237 intconv False = MO_U_Conv
239 -- ToDo: a narrow of a load can be collapsed into a narrow load, right?
240 -- but what if the architecture only supports word-sized loads, should
241 -- we do the transformation anyway?
243 cmmMachOpFold mop args@[CmmLit (CmmInt x xrep), CmmLit (CmmInt y _)]
245 -- for comparisons: don't forget to narrow the arguments before
246 -- comparing, since they might be out of range.
247 MO_Eq r -> CmmLit (CmmInt (if x_u == y_u then 1 else 0) wordRep)
248 MO_Ne r -> CmmLit (CmmInt (if x_u /= y_u then 1 else 0) wordRep)
250 MO_U_Gt r -> CmmLit (CmmInt (if x_u > y_u then 1 else 0) wordRep)
251 MO_U_Ge r -> CmmLit (CmmInt (if x_u >= y_u then 1 else 0) wordRep)
252 MO_U_Lt r -> CmmLit (CmmInt (if x_u < y_u then 1 else 0) wordRep)
253 MO_U_Le r -> CmmLit (CmmInt (if x_u <= y_u then 1 else 0) wordRep)
255 MO_S_Gt r -> CmmLit (CmmInt (if x_s > y_s then 1 else 0) wordRep)
256 MO_S_Ge r -> CmmLit (CmmInt (if x_s >= y_s then 1 else 0) wordRep)
257 MO_S_Lt r -> CmmLit (CmmInt (if x_s < y_s then 1 else 0) wordRep)
258 MO_S_Le r -> CmmLit (CmmInt (if x_s <= y_s then 1 else 0) wordRep)
260 MO_Add r -> CmmLit (CmmInt (x + y) r)
261 MO_Sub r -> CmmLit (CmmInt (x - y) r)
262 MO_Mul r -> CmmLit (CmmInt (x * y) r)
263 MO_S_Quot r | y /= 0 -> CmmLit (CmmInt (x `quot` y) r)
264 MO_S_Rem r | y /= 0 -> CmmLit (CmmInt (x `rem` y) r)
266 MO_And r -> CmmLit (CmmInt (x .&. y) r)
267 MO_Or r -> CmmLit (CmmInt (x .|. y) r)
268 MO_Xor r -> CmmLit (CmmInt (x `xor` y) r)
270 MO_Shl r -> CmmLit (CmmInt (x `shiftL` fromIntegral y) r)
271 MO_U_Shr r -> CmmLit (CmmInt (x_u `shiftR` fromIntegral y) r)
272 MO_S_Shr r -> CmmLit (CmmInt (x `shiftR` fromIntegral y) r)
274 other -> CmmMachOp mop args
283 -- When possible, shift the constants to the right-hand side, so that we
284 -- can match for strength reductions. Note that the code generator will
285 -- also assume that constants have been shifted to the right when
288 cmmMachOpFold op [x@(CmmLit _), y]
289 | not (isLit y) && isCommutableMachOp op
290 = cmmMachOpFold op [y, x]
292 -- Turn (a+b)+c into a+(b+c) where possible. Because literals are
293 -- moved to the right, it is more likely that we will find
294 -- opportunities for constant folding when the expression is
297 -- ToDo: this appears to introduce a quadratic behaviour due to the
298 -- nested cmmMachOpFold. Can we fix this?
300 -- Why do we check isLit arg1? If arg1 is a lit, it means that arg2
301 -- is also a lit (otherwise arg1 would be on the right). If we
302 -- put arg1 on the left of the rearranged expression, we'll get into a
303 -- loop: (x1+x2)+x3 => x1+(x2+x3) => (x2+x3)+x1 => x2+(x3+x1) ...
305 -- Also don't do it if arg1 is PicBaseReg, so that we don't separate the
306 -- PicBaseReg from the corresponding label (or label difference).
308 cmmMachOpFold mop1 [CmmMachOp mop2 [arg1,arg2], arg3]
309 | mop1 == mop2 && isAssociativeMachOp mop1
310 && not (isLit arg1) && not (isPicReg arg1)
311 = cmmMachOpFold mop1 [arg1, cmmMachOpFold mop2 [arg2,arg3]]
313 -- Make a RegOff if we can
314 cmmMachOpFold (MO_Add _) [CmmReg reg, CmmLit (CmmInt n rep)]
315 = CmmRegOff reg (fromIntegral (narrowS rep n))
316 cmmMachOpFold (MO_Add _) [CmmRegOff reg off, CmmLit (CmmInt n rep)]
317 = CmmRegOff reg (off + fromIntegral (narrowS rep n))
318 cmmMachOpFold (MO_Sub _) [CmmReg reg, CmmLit (CmmInt n rep)]
319 = CmmRegOff reg (- fromIntegral (narrowS rep n))
320 cmmMachOpFold (MO_Sub _) [CmmRegOff reg off, CmmLit (CmmInt n rep)]
321 = CmmRegOff reg (off - fromIntegral (narrowS rep n))
323 -- Fold label(+/-)offset into a CmmLit where possible
325 cmmMachOpFold (MO_Add _) [CmmLit (CmmLabel lbl), CmmLit (CmmInt i rep)]
326 = CmmLit (CmmLabelOff lbl (fromIntegral (narrowU rep i)))
327 cmmMachOpFold (MO_Add _) [CmmLit (CmmInt i rep), CmmLit (CmmLabel lbl)]
328 = CmmLit (CmmLabelOff lbl (fromIntegral (narrowU rep i)))
329 cmmMachOpFold (MO_Sub _) [CmmLit (CmmLabel lbl), CmmLit (CmmInt i rep)]
330 = CmmLit (CmmLabelOff lbl (fromIntegral (negate (narrowU rep i))))
333 -- Comparison of literal with widened operand: perform the comparison
334 -- at the smaller width, as long as the literal is within range.
336 -- We can't do the reverse trick, when the operand is narrowed:
337 -- narrowing throws away bits from the operand, there's no way to do
338 -- the same comparison at the larger size.
340 #if i386_TARGET_ARCH || x86_64_TARGET_ARCH
341 -- powerPC NCG has a TODO for I8/I16 comparisons, so don't try
343 cmmMachOpFold cmp [CmmMachOp conv [x], CmmLit (CmmInt i _)]
344 | -- if the operand is widened:
345 Just (rep, signed, narrow_fn) <- maybe_conversion conv,
346 -- and this is a comparison operation:
347 Just narrow_cmp <- maybe_comparison cmp rep signed,
348 -- and the literal fits in the smaller size:
350 -- then we can do the comparison at the smaller size
351 = cmmMachOpFold narrow_cmp [x, CmmLit (CmmInt i rep)]
353 maybe_conversion (MO_U_Conv from to)
355 = Just (from, False, narrowU)
356 maybe_conversion (MO_S_Conv from to)
357 | to > from, not (isFloatingRep from)
358 = Just (from, True, narrowS)
359 -- don't attempt to apply this optimisation when the source
360 -- is a float; see #1916
361 maybe_conversion _ = Nothing
363 -- careful (#2080): if the original comparison was signed, but
364 -- we were doing an unsigned widen, then we must do an
365 -- unsigned comparison at the smaller size.
366 maybe_comparison (MO_U_Gt _) rep _ = Just (MO_U_Gt rep)
367 maybe_comparison (MO_U_Ge _) rep _ = Just (MO_U_Ge rep)
368 maybe_comparison (MO_U_Lt _) rep _ = Just (MO_U_Lt rep)
369 maybe_comparison (MO_U_Le _) rep _ = Just (MO_U_Le rep)
370 maybe_comparison (MO_Eq _) rep _ = Just (MO_Eq rep)
371 maybe_comparison (MO_S_Gt _) rep True = Just (MO_S_Gt rep)
372 maybe_comparison (MO_S_Ge _) rep True = Just (MO_S_Ge rep)
373 maybe_comparison (MO_S_Lt _) rep True = Just (MO_S_Lt rep)
374 maybe_comparison (MO_S_Le _) rep True = Just (MO_S_Le rep)
375 maybe_comparison (MO_S_Gt _) rep False = Just (MO_U_Gt rep)
376 maybe_comparison (MO_S_Ge _) rep False = Just (MO_U_Ge rep)
377 maybe_comparison (MO_S_Lt _) rep False = Just (MO_U_Lt rep)
378 maybe_comparison (MO_S_Le _) rep False = Just (MO_U_Le rep)
379 maybe_comparison _ _ _ = Nothing
383 -- We can often do something with constants of 0 and 1 ...
385 cmmMachOpFold mop args@[x, y@(CmmLit (CmmInt 0 _))]
396 MO_Ne r | isComparisonExpr x -> x
397 MO_Eq r | Just x' <- maybeInvertCmmExpr x -> x'
398 MO_U_Gt r | isComparisonExpr x -> x
399 MO_S_Gt r | isComparisonExpr x -> x
400 MO_U_Lt r | isComparisonExpr x -> CmmLit (CmmInt 0 wordRep)
401 MO_S_Lt r | isComparisonExpr x -> CmmLit (CmmInt 0 wordRep)
402 MO_U_Ge r | isComparisonExpr x -> CmmLit (CmmInt 1 wordRep)
403 MO_S_Ge r | isComparisonExpr x -> CmmLit (CmmInt 1 wordRep)
404 MO_U_Le r | Just x' <- maybeInvertCmmExpr x -> x'
405 MO_S_Le r | Just x' <- maybeInvertCmmExpr x -> x'
406 other -> CmmMachOp mop args
408 cmmMachOpFold mop args@[x, y@(CmmLit (CmmInt 1 rep))]
413 MO_S_Rem r -> CmmLit (CmmInt 0 rep)
414 MO_U_Rem r -> CmmLit (CmmInt 0 rep)
415 MO_Ne r | Just x' <- maybeInvertCmmExpr x -> x'
416 MO_Eq r | isComparisonExpr x -> x
417 MO_U_Lt r | Just x' <- maybeInvertCmmExpr x -> x'
418 MO_S_Lt r | Just x' <- maybeInvertCmmExpr x -> x'
419 MO_U_Gt r | isComparisonExpr x -> CmmLit (CmmInt 0 wordRep)
420 MO_S_Gt r | isComparisonExpr x -> CmmLit (CmmInt 0 wordRep)
421 MO_U_Le r | isComparisonExpr x -> CmmLit (CmmInt 1 wordRep)
422 MO_S_Le r | isComparisonExpr x -> CmmLit (CmmInt 1 wordRep)
423 MO_U_Ge r | isComparisonExpr x -> x
424 MO_S_Ge r | isComparisonExpr x -> x
425 other -> CmmMachOp mop args
427 -- Now look for multiplication/division by powers of 2 (integers).
429 cmmMachOpFold mop args@[x, y@(CmmLit (CmmInt n _))]
432 | Just p <- exactLog2 n ->
433 CmmMachOp (MO_Shl rep) [x, CmmLit (CmmInt p rep)]
435 | Just p <- exactLog2 n,
436 CmmReg _ <- x -> -- We duplicate x below, hence require
437 -- it is a reg. FIXME: remove this restriction.
438 -- shift right is not the same as quot, because it rounds
439 -- to minus infinity, whereasq uot rounds toward zero.
440 -- To fix this up, we add one less than the divisor to the
441 -- dividend if it is a negative number.
443 -- to avoid a test/jump, we use the following sequence:
444 -- x1 = x >> word_size-1 (all 1s if -ve, all 0s if +ve)
445 -- x2 = y & (divisor-1)
446 -- result = (x+x2) >>= log2(divisor)
447 -- this could be done a bit more simply using conditional moves,
448 -- but we're processor independent here.
450 -- we optimise the divide by 2 case slightly, generating
451 -- x1 = x >> word_size-1 (unsigned)
452 -- return = (x + x1) >>= log2(divisor)
454 bits = fromIntegral (machRepBitWidth rep) - 1
455 shr = if p == 1 then MO_U_Shr rep else MO_S_Shr rep
456 x1 = CmmMachOp shr [x, CmmLit (CmmInt bits rep)]
457 x2 = if p == 1 then x1 else
458 CmmMachOp (MO_And rep) [x1, CmmLit (CmmInt (n-1) rep)]
459 x3 = CmmMachOp (MO_Add rep) [x, x2]
461 CmmMachOp (MO_S_Shr rep) [x3, CmmLit (CmmInt p rep)]
465 unchanged = CmmMachOp mop args
467 -- Anything else is just too hard.
469 cmmMachOpFold mop args = CmmMachOp mop args
471 -- -----------------------------------------------------------------------------
474 -- This algorithm for determining the $\log_2$ of exact powers of 2 comes
475 -- from GCC. It requires bit manipulation primitives, and we use GHC
476 -- extensions. Tough.
478 -- Used to be in MachInstrs --SDM.
479 -- ToDo: remove use of unboxery --SDM.
481 -- Unboxery removed in favor of FastInt; but is the function supposed to fail
482 -- on inputs >= 2147483648, or was that just an implementation artifact?
483 -- And is this speed-critical, or can we just use Integer operations
484 -- (including Data.Bits)?
487 exactLog2 :: Integer -> Maybe Integer
489 = if (x_ <= 0 || x_ >= 2147483648) then
492 case iUnbox (fromInteger x_) of { x ->
493 if (x `bitAndFastInt` negateFastInt x) /=# x then
496 Just (toInteger (iBox (pow2 x)))
499 pow2 x | x ==# _ILIT(1) = _ILIT(0)
500 | otherwise = _ILIT(1) +# pow2 (x `shiftR_FastInt` _ILIT(1))
503 -- -----------------------------------------------------------------------------
504 -- widening / narrowing
506 narrowU :: MachRep -> Integer -> Integer
507 narrowU I8 x = fromIntegral (fromIntegral x :: Word8)
508 narrowU I16 x = fromIntegral (fromIntegral x :: Word16)
509 narrowU I32 x = fromIntegral (fromIntegral x :: Word32)
510 narrowU I64 x = fromIntegral (fromIntegral x :: Word64)
511 narrowU _ _ = panic "narrowTo"
513 narrowS :: MachRep -> Integer -> Integer
514 narrowS I8 x = fromIntegral (fromIntegral x :: Int8)
515 narrowS I16 x = fromIntegral (fromIntegral x :: Int16)
516 narrowS I32 x = fromIntegral (fromIntegral x :: Int32)
517 narrowS I64 x = fromIntegral (fromIntegral x :: Int64)
518 narrowS _ _ = panic "narrowTo"
520 -- -----------------------------------------------------------------------------
524 This is a simple pass that replaces tail-recursive functions like this:
539 the latter generates better C code, because the C compiler treats it
540 like a loop, and brings full loop optimisation to bear.
542 In my measurements this makes little or no difference to anything
543 except factorial, but what the hell.
546 cmmLoopifyForC :: RawCmmTop -> RawCmmTop
547 cmmLoopifyForC p@(CmmProc info entry_lbl [] (ListGraph blocks@(BasicBlock top_id _ : _)))
548 | null info = p -- only if there's an info table, ignore case alts
550 -- pprTrace "jump_lbl" (ppr jump_lbl <+> ppr entry_lbl) $
551 CmmProc info entry_lbl [] (ListGraph blocks')
552 where blocks' = [ BasicBlock id (map do_stmt stmts)
553 | BasicBlock id stmts <- blocks ]
555 do_stmt (CmmJump (CmmLit (CmmLabel lbl)) _) | lbl == jump_lbl
559 jump_lbl | tablesNextToCode = entryLblToInfoLbl entry_lbl
560 | otherwise = entry_lbl
562 cmmLoopifyForC top = top
564 -- -----------------------------------------------------------------------------
567 isLit (CmmLit _) = True
570 isComparisonExpr :: CmmExpr -> Bool
571 isComparisonExpr (CmmMachOp op _) = isComparisonMachOp op
572 isComparisonExpr _other = False
574 isPicReg (CmmReg (CmmGlobal PicBaseReg)) = True
577 _unused :: FS.FastString -- stops a warning