[commit: ghc] master: Discard dead assignments in tryToInline (29be1a8)
git at git.haskell.org
git at git.haskell.org
Fri Oct 25 11:19:12 UTC 2013
Repository : ssh://git@git.haskell.org/ghc
On branch : master
Link : http://ghc.haskell.org/trac/ghc/changeset/29be1a8afa6aece04ca85060662510a14d2ff8b0/ghc
>---------------------------------------------------------------
commit 29be1a8afa6aece04ca85060662510a14d2ff8b0
Author: Simon Marlow <marlowsd at gmail.com>
Date: Fri Oct 25 10:32:48 2013 +0100
Discard dead assignments in tryToInline
Inlining global registers and constants made code slightly larger in
some cases. I finally got around to looking into why, and discovered
one reason: we weren't discarding dead code in some cases. This patch
fixes it.
>---------------------------------------------------------------
29be1a8afa6aece04ca85060662510a14d2ff8b0
compiler/cmm/CmmSink.hs | 30 ++++++++++++++++++++++++++----
1 file changed, 26 insertions(+), 4 deletions(-)
diff --git a/compiler/cmm/CmmSink.hs b/compiler/cmm/CmmSink.hs
index 17b72c0..6a3bcb7 100644
--- a/compiler/cmm/CmmSink.hs
+++ b/compiler/cmm/CmmSink.hs
@@ -295,8 +295,8 @@ walk :: DynFlags
-> Assignments -- The current list of
-- assignments we are sinking.
- -- Later assignments may refer
- -- to earlier ones.
+ -- Earlier assignments may refer
+ -- to later ones.
-> ( Block CmmNode O O -- The new block
, Assignments -- Assignments to sink further
@@ -405,6 +405,7 @@ tryToInline dflags live node assigs = go usages node [] assigs
go usages node skipped (a@(l,rhs,_) : rest)
| cannot_inline = dont_inline
+ | occurs_none = discard -- Note [discard during inlining]
| occurs_once = inline_and_discard
| isTrivial rhs = inline_and_keep
| otherwise = dont_inline
@@ -412,6 +413,8 @@ tryToInline dflags live node assigs = go usages node [] assigs
inline_and_discard = go usages' inl_node skipped rest
where usages' = foldLocalRegsUsed dflags addUsage usages rhs
+ discard = go usages node skipped rest
+
dont_inline = keep node -- don't inline the assignment, keep it
inline_and_keep = keep inl_node -- inline the assignment, keep it
@@ -427,8 +430,11 @@ tryToInline dflags live node assigs = go usages node [] assigs
|| l `elem` skipped
|| not (okToInline dflags rhs node)
- occurs_once = not (l `elemRegSet` live)
- && lookupUFM usages l == Just 1
+ l_usages = lookupUFM usages l
+ l_live = l `elemRegSet` live
+
+ occurs_once = not l_live && l_usages == Just 1
+ occurs_none = not l_live && l_usages == Nothing
inl_node = mapExpDeep inline node
-- mapExpDeep is where the inlining actually takes place!
@@ -468,6 +474,22 @@ tryToInline dflags live node assigs = go usages node [] assigs
-- trivial rhs's). But of course we can't, because y is equal to e,
-- not z.
+-- Note [discard during inlining]
+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+-- Opportunities to discard assignments sometimes appear after we've
+-- done some inlining. Here's an example:
+--
+-- x = R1;
+-- y = P64[x + 7];
+-- z = P64[x + 15];
+-- /* z is dead */
+-- R1 = y & (-8);
+--
+-- The x assignment is trivial, so we inline it in the RHS of y, and
+-- keep both x and y. z gets dropped because it is dead, then we
+-- inline y, and we have a dead assignment to x. If we don't notice
+-- that x is dead in tryToInline, we end up retaining it.
+
addUsage :: UniqFM Int -> LocalReg -> UniqFM Int
addUsage m r = addToUFM_C (+) m r 1
More information about the ghc-commits
mailing list