summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Gamari <bgamari.foss@gmail.com>2017-11-06 15:33:26 -0500
committerBen Gamari <ben@smart-cactus.org>2017-11-06 15:33:27 -0500
commit6f990c54f922beae80362fe62426beededc21290 (patch)
tree466c0dee18666b43abb588d87fb9c42eab591915
parent4dfb790ca0611d4024cd01ba4c28d145f1deb7cb (diff)
downloadhaskell-6f990c54f922beae80362fe62426beededc21290.tar.gz
cmm/CBE: Fix comparison between blocks of different lengths
Previously CBE computed equality by taking the lists of middle nodes of the blocks being compared and zipping them together. It would then map over this list with the equality relation, and accumulate the result. However, this is completely wrong: Consider what will happen when we compare a block with no middle nodes with one with one or more. The result of `zip` will be empty and consequently the pass may conclude that the two are indeed equivalent (if their last nodes also match). This is very bad and the cause of #14361. The solution I chose was just to write out an explicit recursion, like I distinctly recall considering doing when I first wrote this code. Unfortunately I was feeling clever at the time. Unfortunately this case was just rare enough not to be triggered by the testsuite. I still need to find a testcase that doesn't have external dependencies. Test Plan: Need to find a more minimal testcase Reviewers: austin, simonmar, michalt Reviewed By: michalt Subscribers: michalt, rwbarton, thomie, hvr GHC Trac Issues: #14361 Differential Revision: https://phabricator.haskell.org/D4152
-rw-r--r--compiler/cmm/CmmCommonBlockElim.hs14
1 files changed, 9 insertions, 5 deletions
diff --git a/compiler/cmm/CmmCommonBlockElim.hs b/compiler/cmm/CmmCommonBlockElim.hs
index c83497e036..b3a0b6ffa4 100644
--- a/compiler/cmm/CmmCommonBlockElim.hs
+++ b/compiler/cmm/CmmCommonBlockElim.hs
@@ -371,11 +371,15 @@ eqBlockBodyWith dflags eqBid block block'
(_,m',l') = blockSplit block'
nodes' = filter (not . dont_care) (blockToList m')
- (env_mid, eqs_mid) =
- List.mapAccumL (\acc (a,b) -> eqMiddleWith dflags eqBid acc a b)
- emptyUFM
- (List.zip nodes nodes')
- equal = and eqs_mid && eqLastWith eqBid env_mid l l'
+ eqMids :: LocalRegMapping -> [CmmNode O O] -> [CmmNode O O] -> Bool
+ eqMids env (a:as) (b:bs)
+ | eq = eqMids env' as bs
+ where
+ (env', eq) = eqMiddleWith dflags eqBid env a b
+ eqMids env [] [] = eqLastWith eqBid env l l'
+ eqMids _ _ _ = False
+
+ equal = eqMids emptyUFM nodes nodes'
eqLastWith :: (BlockId -> BlockId -> Bool) -> LocalRegMapping