PageRenderTime 53ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/ghc-7.0.4/compiler/cmm/CmmOpt.hs

http://picorec.googlecode.com/
Haskell | 565 lines | 298 code | 78 blank | 189 comment | 38 complexity | 7447f9ebdbf7b14eebbb65299093ec01 MD5 | raw file
Possible License(s): BSD-3-Clause, BSD-2-Clause
  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. -- Cmm optimisation
  10. --
  11. -- (c) The University of Glasgow 2006
  12. --
  13. -----------------------------------------------------------------------------
  14. module CmmOpt (
  15. cmmMiniInline,
  16. cmmMachOpFold,
  17. cmmLoopifyForC,
  18. ) where
  19. #include "HsVersions.h"
  20. import Cmm
  21. import CmmExpr
  22. import CmmUtils
  23. import CLabel
  24. import StaticFlags
  25. import UniqFM
  26. import Unique
  27. import FastTypes
  28. import Outputable
  29. import Data.Bits
  30. import Data.Word
  31. import Data.Int
  32. -- -----------------------------------------------------------------------------
  33. -- The mini-inliner
  34. {-
  35. This pass inlines assignments to temporaries that are used just
  36. once. It works as follows:
  37. - count uses of each temporary
  38. - for each temporary that occurs just once:
  39. - attempt to push it forward to the statement that uses it
  40. - only push forward past assignments to other temporaries
  41. (assumes that temporaries are single-assignment)
  42. - if we reach the statement that uses it, inline the rhs
  43. and delete the original assignment.
  44. [N.B. In the Quick C-- compiler, this optimization is achieved by a
  45. combination of two dataflow passes: forward substitution (peephole
  46. optimization) and dead-assignment elimination. ---NR]
  47. Possible generalisations: here is an example from factorial
  48. Fac_zdwfac_entry:
  49. cmG:
  50. _smi = R2;
  51. if (_smi != 0) goto cmK;
  52. R1 = R3;
  53. jump I64[Sp];
  54. cmK:
  55. _smn = _smi * R3;
  56. R2 = _smi + (-1);
  57. R3 = _smn;
  58. jump Fac_zdwfac_info;
  59. We want to inline _smi and _smn. To inline _smn:
  60. - we must be able to push forward past assignments to global regs.
  61. We can do this if the rhs of the assignment we are pushing
  62. forward doesn't refer to the global reg being assigned to; easy
  63. to test.
  64. To inline _smi:
  65. - It is a trivial replacement, reg for reg, but it occurs more than
  66. once.
  67. - We can inline trivial assignments even if the temporary occurs
  68. more than once, as long as we don't eliminate the original assignment
  69. (this doesn't help much on its own).
  70. - We need to be able to propagate the assignment forward through jumps;
  71. if we did this, we would find that it can be inlined safely in all
  72. its occurrences.
  73. -}
  74. countUses :: UserOfLocalRegs a => a -> UniqFM Int
  75. countUses a = foldRegsUsed (\m r -> addToUFM m r (count m r + 1)) emptyUFM a
  76. where count m r = lookupWithDefaultUFM m (0::Int) r
  77. cmmMiniInline :: [CmmBasicBlock] -> [CmmBasicBlock]
  78. cmmMiniInline blocks = map do_inline blocks
  79. where do_inline (BasicBlock id stmts)
  80. = BasicBlock id (cmmMiniInlineStmts (countUses blocks) stmts)
  81. cmmMiniInlineStmts :: UniqFM Int -> [CmmStmt] -> [CmmStmt]
  82. cmmMiniInlineStmts uses [] = []
  83. cmmMiniInlineStmts uses (stmt@(CmmAssign (CmmLocal (LocalReg u _)) expr) : stmts)
  84. -- not used at all: just discard this assignment
  85. | Nothing <- lookupUFM uses u
  86. = cmmMiniInlineStmts uses stmts
  87. -- used once: try to inline at the use site
  88. | Just 1 <- lookupUFM uses u,
  89. Just stmts' <- lookForInline u expr stmts
  90. =
  91. #ifdef NCG_DEBUG
  92. trace ("nativeGen: inlining " ++ showSDoc (pprStmt stmt)) $
  93. #endif
  94. cmmMiniInlineStmts uses stmts'
  95. cmmMiniInlineStmts uses (stmt:stmts)
  96. = stmt : cmmMiniInlineStmts uses stmts
  97. lookForInline u expr (stmt : rest)
  98. | Just 1 <- lookupUFM (countUses stmt) u, ok_to_inline
  99. = Just (inlineStmt u expr stmt : rest)
  100. | ok_to_skip
  101. = case lookForInline u expr rest of
  102. Nothing -> Nothing
  103. Just stmts -> Just (stmt:stmts)
  104. | otherwise
  105. = Nothing
  106. where
  107. -- we don't inline into CmmCall if the expression refers to global
  108. -- registers. This is a HACK to avoid global registers clashing with
  109. -- C argument-passing registers, really the back-end ought to be able
  110. -- to handle it properly, but currently neither PprC nor the NCG can
  111. -- do it. See also CgForeignCall:load_args_into_temps.
  112. ok_to_inline = case stmt of
  113. CmmCall{} -> hasNoGlobalRegs expr
  114. _ -> True
  115. -- We can skip over assignments to other tempoararies, because we
  116. -- know that expressions aren't side-effecting and temporaries are
  117. -- single-assignment.
  118. ok_to_skip = case stmt of
  119. CmmNop -> True
  120. CmmAssign (CmmLocal (LocalReg u' _)) rhs | u' /= u -> True
  121. CmmAssign g@(CmmGlobal _) rhs -> not (g `regUsedIn` expr)
  122. _other -> False
  123. inlineStmt :: Unique -> CmmExpr -> CmmStmt -> CmmStmt
  124. inlineStmt u a (CmmAssign r e) = CmmAssign r (inlineExpr u a e)
  125. inlineStmt u a (CmmStore e1 e2) = CmmStore (inlineExpr u a e1) (inlineExpr u a e2)
  126. inlineStmt u a (CmmCall target regs es srt ret)
  127. = CmmCall (infn target) regs es' srt ret
  128. where infn (CmmCallee fn cconv) = CmmCallee (inlineExpr u a fn) cconv
  129. infn (CmmPrim p) = CmmPrim p
  130. es' = [ (CmmHinted (inlineExpr u a e) hint) | (CmmHinted e hint) <- es ]
  131. inlineStmt u a (CmmCondBranch e d) = CmmCondBranch (inlineExpr u a e) d
  132. inlineStmt u a (CmmSwitch e d) = CmmSwitch (inlineExpr u a e) d
  133. inlineStmt u a (CmmJump e d) = CmmJump (inlineExpr u a e) d
  134. inlineStmt u a other_stmt = other_stmt
  135. inlineExpr :: Unique -> CmmExpr -> CmmExpr -> CmmExpr
  136. inlineExpr u a e@(CmmReg (CmmLocal (LocalReg u' _)))
  137. | u == u' = a
  138. | otherwise = e
  139. inlineExpr u a e@(CmmRegOff (CmmLocal (LocalReg u' rep)) off)
  140. | u == u' = CmmMachOp (MO_Add width) [a, CmmLit (CmmInt (fromIntegral off) width)]
  141. | otherwise = e
  142. where
  143. width = typeWidth rep
  144. inlineExpr u a (CmmLoad e rep) = CmmLoad (inlineExpr u a e) rep
  145. inlineExpr u a (CmmMachOp op es) = CmmMachOp op (map (inlineExpr u a) es)
  146. inlineExpr u a other_expr = other_expr
  147. -- -----------------------------------------------------------------------------
  148. -- MachOp constant folder
  149. -- Now, try to constant-fold the MachOps. The arguments have already
  150. -- been optimized and folded.
  151. cmmMachOpFold
  152. :: MachOp -- The operation from an CmmMachOp
  153. -> [CmmExpr] -- The optimized arguments
  154. -> CmmExpr
  155. cmmMachOpFold op arg@[CmmLit (CmmInt x rep)]
  156. = case op of
  157. MO_S_Neg r -> CmmLit (CmmInt (-x) rep)
  158. MO_Not r -> CmmLit (CmmInt (complement x) rep)
  159. -- these are interesting: we must first narrow to the
  160. -- "from" type, in order to truncate to the correct size.
  161. -- The final narrow/widen to the destination type
  162. -- is implicit in the CmmLit.
  163. MO_SF_Conv from to -> CmmLit (CmmFloat (fromInteger x) to)
  164. MO_SS_Conv from to -> CmmLit (CmmInt (narrowS from x) to)
  165. MO_UU_Conv from to -> CmmLit (CmmInt (narrowU from x) to)
  166. _ -> panic "cmmMachOpFold: unknown unary op"
  167. -- Eliminate conversion NOPs
  168. cmmMachOpFold (MO_SS_Conv rep1 rep2) [x] | rep1 == rep2 = x
  169. cmmMachOpFold (MO_UU_Conv rep1 rep2) [x] | rep1 == rep2 = x
  170. -- Eliminate nested conversions where possible
  171. cmmMachOpFold conv_outer args@[CmmMachOp conv_inner [x]]
  172. | Just (rep1,rep2,signed1) <- isIntConversion conv_inner,
  173. Just (_, rep3,signed2) <- isIntConversion conv_outer
  174. = case () of
  175. -- widen then narrow to the same size is a nop
  176. _ | rep1 < rep2 && rep1 == rep3 -> x
  177. -- Widen then narrow to different size: collapse to single conversion
  178. -- but remember to use the signedness from the widening, just in case
  179. -- the final conversion is a widen.
  180. | rep1 < rep2 && rep2 > rep3 ->
  181. cmmMachOpFold (intconv signed1 rep1 rep3) [x]
  182. -- Nested widenings: collapse if the signedness is the same
  183. | rep1 < rep2 && rep2 < rep3 && signed1 == signed2 ->
  184. cmmMachOpFold (intconv signed1 rep1 rep3) [x]
  185. -- Nested narrowings: collapse
  186. | rep1 > rep2 && rep2 > rep3 ->
  187. cmmMachOpFold (MO_UU_Conv rep1 rep3) [x]
  188. | otherwise ->
  189. CmmMachOp conv_outer args
  190. where
  191. isIntConversion (MO_UU_Conv rep1 rep2)
  192. = Just (rep1,rep2,False)
  193. isIntConversion (MO_SS_Conv rep1 rep2)
  194. = Just (rep1,rep2,True)
  195. isIntConversion _ = Nothing
  196. intconv True = MO_SS_Conv
  197. intconv False = MO_UU_Conv
  198. -- ToDo: a narrow of a load can be collapsed into a narrow load, right?
  199. -- but what if the architecture only supports word-sized loads, should
  200. -- we do the transformation anyway?
  201. cmmMachOpFold mop args@[CmmLit (CmmInt x xrep), CmmLit (CmmInt y _)]
  202. = case mop of
  203. -- for comparisons: don't forget to narrow the arguments before
  204. -- comparing, since they might be out of range.
  205. MO_Eq r -> CmmLit (CmmInt (if x_u == y_u then 1 else 0) wordWidth)
  206. MO_Ne r -> CmmLit (CmmInt (if x_u /= y_u then 1 else 0) wordWidth)
  207. MO_U_Gt r -> CmmLit (CmmInt (if x_u > y_u then 1 else 0) wordWidth)
  208. MO_U_Ge r -> CmmLit (CmmInt (if x_u >= y_u then 1 else 0) wordWidth)
  209. MO_U_Lt r -> CmmLit (CmmInt (if x_u < y_u then 1 else 0) wordWidth)
  210. MO_U_Le r -> CmmLit (CmmInt (if x_u <= y_u then 1 else 0) wordWidth)
  211. MO_S_Gt r -> CmmLit (CmmInt (if x_s > y_s then 1 else 0) wordWidth)
  212. MO_S_Ge r -> CmmLit (CmmInt (if x_s >= y_s then 1 else 0) wordWidth)
  213. MO_S_Lt r -> CmmLit (CmmInt (if x_s < y_s then 1 else 0) wordWidth)
  214. MO_S_Le r -> CmmLit (CmmInt (if x_s <= y_s then 1 else 0) wordWidth)
  215. MO_Add r -> CmmLit (CmmInt (x + y) r)
  216. MO_Sub r -> CmmLit (CmmInt (x - y) r)
  217. MO_Mul r -> CmmLit (CmmInt (x * y) r)
  218. MO_U_Quot r | y /= 0 -> CmmLit (CmmInt (x_u `quot` y_u) r)
  219. MO_U_Rem r | y /= 0 -> CmmLit (CmmInt (x_u `rem` y_u) r)
  220. MO_S_Quot r | y /= 0 -> CmmLit (CmmInt (x `quot` y) r)
  221. MO_S_Rem r | y /= 0 -> CmmLit (CmmInt (x `rem` y) r)
  222. MO_And r -> CmmLit (CmmInt (x .&. y) r)
  223. MO_Or r -> CmmLit (CmmInt (x .|. y) r)
  224. MO_Xor r -> CmmLit (CmmInt (x `xor` y) r)
  225. MO_Shl r -> CmmLit (CmmInt (x `shiftL` fromIntegral y) r)
  226. MO_U_Shr r -> CmmLit (CmmInt (x_u `shiftR` fromIntegral y) r)
  227. MO_S_Shr r -> CmmLit (CmmInt (x `shiftR` fromIntegral y) r)
  228. other -> CmmMachOp mop args
  229. where
  230. x_u = narrowU xrep x
  231. y_u = narrowU xrep y
  232. x_s = narrowS xrep x
  233. y_s = narrowS xrep y
  234. -- When possible, shift the constants to the right-hand side, so that we
  235. -- can match for strength reductions. Note that the code generator will
  236. -- also assume that constants have been shifted to the right when
  237. -- possible.
  238. cmmMachOpFold op [x@(CmmLit _), y]
  239. | not (isLit y) && isCommutableMachOp op
  240. = cmmMachOpFold op [y, x]
  241. -- Turn (a+b)+c into a+(b+c) where possible. Because literals are
  242. -- moved to the right, it is more likely that we will find
  243. -- opportunities for constant folding when the expression is
  244. -- right-associated.
  245. --
  246. -- ToDo: this appears to introduce a quadratic behaviour due to the
  247. -- nested cmmMachOpFold. Can we fix this?
  248. --
  249. -- Why do we check isLit arg1? If arg1 is a lit, it means that arg2
  250. -- is also a lit (otherwise arg1 would be on the right). If we
  251. -- put arg1 on the left of the rearranged expression, we'll get into a
  252. -- loop: (x1+x2)+x3 => x1+(x2+x3) => (x2+x3)+x1 => x2+(x3+x1) ...
  253. --
  254. -- Also don't do it if arg1 is PicBaseReg, so that we don't separate the
  255. -- PicBaseReg from the corresponding label (or label difference).
  256. --
  257. cmmMachOpFold mop1 [CmmMachOp mop2 [arg1,arg2], arg3]
  258. | mop1 == mop2 && isAssociativeMachOp mop1
  259. && not (isLit arg1) && not (isPicReg arg1)
  260. = cmmMachOpFold mop1 [arg1, cmmMachOpFold mop2 [arg2,arg3]]
  261. -- Make a RegOff if we can
  262. cmmMachOpFold (MO_Add _) [CmmReg reg, CmmLit (CmmInt n rep)]
  263. = CmmRegOff reg (fromIntegral (narrowS rep n))
  264. cmmMachOpFold (MO_Add _) [CmmRegOff reg off, CmmLit (CmmInt n rep)]
  265. = CmmRegOff reg (off + fromIntegral (narrowS rep n))
  266. cmmMachOpFold (MO_Sub _) [CmmReg reg, CmmLit (CmmInt n rep)]
  267. = CmmRegOff reg (- fromIntegral (narrowS rep n))
  268. cmmMachOpFold (MO_Sub _) [CmmRegOff reg off, CmmLit (CmmInt n rep)]
  269. = CmmRegOff reg (off - fromIntegral (narrowS rep n))
  270. -- Fold label(+/-)offset into a CmmLit where possible
  271. cmmMachOpFold (MO_Add _) [CmmLit (CmmLabel lbl), CmmLit (CmmInt i rep)]
  272. = CmmLit (CmmLabelOff lbl (fromIntegral (narrowU rep i)))
  273. cmmMachOpFold (MO_Add _) [CmmLit (CmmInt i rep), CmmLit (CmmLabel lbl)]
  274. = CmmLit (CmmLabelOff lbl (fromIntegral (narrowU rep i)))
  275. cmmMachOpFold (MO_Sub _) [CmmLit (CmmLabel lbl), CmmLit (CmmInt i rep)]
  276. = CmmLit (CmmLabelOff lbl (fromIntegral (negate (narrowU rep i))))
  277. -- Comparison of literal with widened operand: perform the comparison
  278. -- at the smaller width, as long as the literal is within range.
  279. -- We can't do the reverse trick, when the operand is narrowed:
  280. -- narrowing throws away bits from the operand, there's no way to do
  281. -- the same comparison at the larger size.
  282. #if i386_TARGET_ARCH || x86_64_TARGET_ARCH
  283. -- powerPC NCG has a TODO for I8/I16 comparisons, so don't try
  284. cmmMachOpFold cmp [CmmMachOp conv [x], CmmLit (CmmInt i _)]
  285. | -- if the operand is widened:
  286. Just (rep, signed, narrow_fn) <- maybe_conversion conv,
  287. -- and this is a comparison operation:
  288. Just narrow_cmp <- maybe_comparison cmp rep signed,
  289. -- and the literal fits in the smaller size:
  290. i == narrow_fn rep i
  291. -- then we can do the comparison at the smaller size
  292. = cmmMachOpFold narrow_cmp [x, CmmLit (CmmInt i rep)]
  293. where
  294. maybe_conversion (MO_UU_Conv from to)
  295. | to > from
  296. = Just (from, False, narrowU)
  297. maybe_conversion (MO_SS_Conv from to)
  298. | to > from
  299. = Just (from, True, narrowS)
  300. -- don't attempt to apply this optimisation when the source
  301. -- is a float; see #1916
  302. maybe_conversion _ = Nothing
  303. -- careful (#2080): if the original comparison was signed, but
  304. -- we were doing an unsigned widen, then we must do an
  305. -- unsigned comparison at the smaller size.
  306. maybe_comparison (MO_U_Gt _) rep _ = Just (MO_U_Gt rep)
  307. maybe_comparison (MO_U_Ge _) rep _ = Just (MO_U_Ge rep)
  308. maybe_comparison (MO_U_Lt _) rep _ = Just (MO_U_Lt rep)
  309. maybe_comparison (MO_U_Le _) rep _ = Just (MO_U_Le rep)
  310. maybe_comparison (MO_Eq _) rep _ = Just (MO_Eq rep)
  311. maybe_comparison (MO_S_Gt _) rep True = Just (MO_S_Gt rep)
  312. maybe_comparison (MO_S_Ge _) rep True = Just (MO_S_Ge rep)
  313. maybe_comparison (MO_S_Lt _) rep True = Just (MO_S_Lt rep)
  314. maybe_comparison (MO_S_Le _) rep True = Just (MO_S_Le rep)
  315. maybe_comparison (MO_S_Gt _) rep False = Just (MO_U_Gt rep)
  316. maybe_comparison (MO_S_Ge _) rep False = Just (MO_U_Ge rep)
  317. maybe_comparison (MO_S_Lt _) rep False = Just (MO_U_Lt rep)
  318. maybe_comparison (MO_S_Le _) rep False = Just (MO_U_Le rep)
  319. maybe_comparison _ _ _ = Nothing
  320. #endif
  321. -- We can often do something with constants of 0 and 1 ...
  322. cmmMachOpFold mop args@[x, y@(CmmLit (CmmInt 0 _))]
  323. = case mop of
  324. MO_Add r -> x
  325. MO_Sub r -> x
  326. MO_Mul r -> y
  327. MO_And r -> y
  328. MO_Or r -> x
  329. MO_Xor r -> x
  330. MO_Shl r -> x
  331. MO_S_Shr r -> x
  332. MO_U_Shr r -> x
  333. MO_Ne r | isComparisonExpr x -> x
  334. MO_Eq r | Just x' <- maybeInvertCmmExpr x -> x'
  335. MO_U_Gt r | isComparisonExpr x -> x
  336. MO_S_Gt r | isComparisonExpr x -> x
  337. MO_U_Lt r | isComparisonExpr x -> CmmLit (CmmInt 0 wordWidth)
  338. MO_S_Lt r | isComparisonExpr x -> CmmLit (CmmInt 0 wordWidth)
  339. MO_U_Ge r | isComparisonExpr x -> CmmLit (CmmInt 1 wordWidth)
  340. MO_S_Ge r | isComparisonExpr x -> CmmLit (CmmInt 1 wordWidth)
  341. MO_U_Le r | Just x' <- maybeInvertCmmExpr x -> x'
  342. MO_S_Le r | Just x' <- maybeInvertCmmExpr x -> x'
  343. other -> CmmMachOp mop args
  344. cmmMachOpFold mop args@[x, y@(CmmLit (CmmInt 1 rep))]
  345. = case mop of
  346. MO_Mul r -> x
  347. MO_S_Quot r -> x
  348. MO_U_Quot r -> x
  349. MO_S_Rem r -> CmmLit (CmmInt 0 rep)
  350. MO_U_Rem r -> CmmLit (CmmInt 0 rep)
  351. MO_Ne r | Just x' <- maybeInvertCmmExpr x -> x'
  352. MO_Eq r | isComparisonExpr x -> x
  353. MO_U_Lt r | Just x' <- maybeInvertCmmExpr x -> x'
  354. MO_S_Lt r | Just x' <- maybeInvertCmmExpr x -> x'
  355. MO_U_Gt r | isComparisonExpr x -> CmmLit (CmmInt 0 wordWidth)
  356. MO_S_Gt r | isComparisonExpr x -> CmmLit (CmmInt 0 wordWidth)
  357. MO_U_Le r | isComparisonExpr x -> CmmLit (CmmInt 1 wordWidth)
  358. MO_S_Le r | isComparisonExpr x -> CmmLit (CmmInt 1 wordWidth)
  359. MO_U_Ge r | isComparisonExpr x -> x
  360. MO_S_Ge r | isComparisonExpr x -> x
  361. other -> CmmMachOp mop args
  362. -- Now look for multiplication/division by powers of 2 (integers).
  363. cmmMachOpFold mop args@[x, y@(CmmLit (CmmInt n _))]
  364. = case mop of
  365. MO_Mul rep
  366. | Just p <- exactLog2 n ->
  367. CmmMachOp (MO_Shl rep) [x, CmmLit (CmmInt p rep)]
  368. MO_U_Quot rep
  369. | Just p <- exactLog2 n ->
  370. CmmMachOp (MO_U_Shr rep) [x, CmmLit (CmmInt p rep)]
  371. MO_S_Quot rep
  372. | Just p <- exactLog2 n,
  373. CmmReg _ <- x -> -- We duplicate x below, hence require
  374. -- it is a reg. FIXME: remove this restriction.
  375. -- shift right is not the same as quot, because it rounds
  376. -- to minus infinity, whereasq quot rounds toward zero.
  377. -- To fix this up, we add one less than the divisor to the
  378. -- dividend if it is a negative number.
  379. --
  380. -- to avoid a test/jump, we use the following sequence:
  381. -- x1 = x >> word_size-1 (all 1s if -ve, all 0s if +ve)
  382. -- x2 = y & (divisor-1)
  383. -- result = (x+x2) >>= log2(divisor)
  384. -- this could be done a bit more simply using conditional moves,
  385. -- but we're processor independent here.
  386. --
  387. -- we optimise the divide by 2 case slightly, generating
  388. -- x1 = x >> word_size-1 (unsigned)
  389. -- return = (x + x1) >>= log2(divisor)
  390. let
  391. bits = fromIntegral (widthInBits rep) - 1
  392. shr = if p == 1 then MO_U_Shr rep else MO_S_Shr rep
  393. x1 = CmmMachOp shr [x, CmmLit (CmmInt bits rep)]
  394. x2 = if p == 1 then x1 else
  395. CmmMachOp (MO_And rep) [x1, CmmLit (CmmInt (n-1) rep)]
  396. x3 = CmmMachOp (MO_Add rep) [x, x2]
  397. in
  398. CmmMachOp (MO_S_Shr rep) [x3, CmmLit (CmmInt p rep)]
  399. other
  400. -> unchanged
  401. where
  402. unchanged = CmmMachOp mop args
  403. -- Anything else is just too hard.
  404. cmmMachOpFold mop args = CmmMachOp mop args
  405. -- -----------------------------------------------------------------------------
  406. -- exactLog2
  407. -- This algorithm for determining the $\log_2$ of exact powers of 2 comes
  408. -- from GCC. It requires bit manipulation primitives, and we use GHC
  409. -- extensions. Tough.
  410. --
  411. -- Used to be in MachInstrs --SDM.
  412. -- ToDo: remove use of unboxery --SDM.
  413. -- Unboxery removed in favor of FastInt; but is the function supposed to fail
  414. -- on inputs >= 2147483648, or was that just an implementation artifact?
  415. -- And is this speed-critical, or can we just use Integer operations
  416. -- (including Data.Bits)?
  417. -- --Isaac Dupree
  418. exactLog2 :: Integer -> Maybe Integer
  419. exactLog2 x_
  420. = if (x_ <= 0 || x_ >= 2147483648) then
  421. Nothing
  422. else
  423. case iUnbox (fromInteger x_) of { x ->
  424. if (x `bitAndFastInt` negateFastInt x) /=# x then
  425. Nothing
  426. else
  427. Just (toInteger (iBox (pow2 x)))
  428. }
  429. where
  430. pow2 x | x ==# _ILIT(1) = _ILIT(0)
  431. | otherwise = _ILIT(1) +# pow2 (x `shiftR_FastInt` _ILIT(1))
  432. -- -----------------------------------------------------------------------------
  433. -- Loopify for C
  434. {-
  435. This is a simple pass that replaces tail-recursive functions like this:
  436. fac() {
  437. ...
  438. jump fac();
  439. }
  440. with this:
  441. fac() {
  442. L:
  443. ...
  444. goto L;
  445. }
  446. the latter generates better C code, because the C compiler treats it
  447. like a loop, and brings full loop optimisation to bear.
  448. In my measurements this makes little or no difference to anything
  449. except factorial, but what the hell.
  450. -}
  451. cmmLoopifyForC :: RawCmmTop -> RawCmmTop
  452. cmmLoopifyForC p@(CmmProc info entry_lbl []
  453. (ListGraph blocks@(BasicBlock top_id _ : _)))
  454. | null info = p -- only if there's an info table, ignore case alts
  455. | otherwise =
  456. -- pprTrace "jump_lbl" (ppr jump_lbl <+> ppr entry_lbl) $
  457. CmmProc info entry_lbl [] (ListGraph blocks')
  458. where blocks' = [ BasicBlock id (map do_stmt stmts)
  459. | BasicBlock id stmts <- blocks ]
  460. do_stmt (CmmJump (CmmLit (CmmLabel lbl)) _) | lbl == jump_lbl
  461. = CmmBranch top_id
  462. do_stmt stmt = stmt
  463. jump_lbl | tablesNextToCode = entryLblToInfoLbl entry_lbl
  464. | otherwise = entry_lbl
  465. cmmLoopifyForC top = top
  466. -- -----------------------------------------------------------------------------
  467. -- Utils
  468. isLit (CmmLit _) = True
  469. isLit _ = False
  470. isComparisonExpr :: CmmExpr -> Bool
  471. isComparisonExpr (CmmMachOp op _) = isComparisonMachOp op
  472. isComparisonExpr _other = False
  473. isPicReg (CmmReg (CmmGlobal PicBaseReg)) = True
  474. isPicReg _ = False