From e5027cfbccb1183901595bd743840df17175245d Mon Sep 17 00:00:00 2001 From: Bjorn Pettersson Date: Thu, 2 Mar 2017 15:18:58 +0000 Subject: [PATCH] [InstCombine] Avoid faulty combines of select-cmp-br Summary: When InstCombine is optimizing certain select-cmp-br patterns it replaces the result of the select in uses outside of the basic block containing the select. This is only legal if the path from the select to the outside use is disjoint from all other paths out from the originating basic block. The problem found was that InstCombiner::replacedSelectWithOperand did not consider the case when both edges out from the br pointed to the same label. In that case the paths aren't disjoint and the transformation is illegal. This patch avoids the faulty rewrites by verifying that there is a single flow to the successor where we want to replace uses. Reviewers: llvm-commits, spatel, majnemer Differential Revision: https://reviews.llvm.org/D30455 llvm-svn: 296752 --- .../InstCombine/InstCombineCompares.cpp | 8 +++++--- .../Transforms/InstCombine/select-cmp-br.ll | 19 +++++++++++++++++++ 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp index ce11e470d05a..d14e8291e9e2 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp @@ -3950,7 +3950,7 @@ bool InstCombiner::replacedSelectWithOperand(SelectInst *SI, assert((SIOpd == 1 || SIOpd == 2) && "Invalid select operand!"); if (isChainSelectCmpBranch(SI) && Icmp->getPredicate() == ICmpInst::ICMP_EQ) { BasicBlock *Succ = SI->getParent()->getTerminator()->getSuccessor(1); - // The check for the unique predecessor is not the best that can be + // The check for the single predecessor is not the best that can be // done. But it protects efficiently against cases like when SI's // home block has two successors, Succ and Succ1, and Succ1 predecessor // of Succ. Then SI can't be replaced by SIOpd because the use that gets @@ -3958,8 +3958,10 @@ bool InstCombiner::replacedSelectWithOperand(SelectInst *SI, // guarantees that the path all uses of SI (outside SI's parent) are on // is disjoint from all other paths out of SI. But that information // is more expensive to compute, and the trade-off here is in favor - // of compile-time. - if (Succ->getUniquePredecessor() && dominatesAllUses(SI, Icmp, Succ)) { + // of compile-time. It should also be noticed that we check for a single + // predecessor and not only uniqueness. This to handle the situation when + // Succ and Succ1 points to the same basic block. + if (Succ->getSinglePredecessor() && dominatesAllUses(SI, Icmp, Succ)) { NumSel++; SI->replaceUsesOutsideBlock(SI->getOperand(SIOpd), SI->getParent()); return true; diff --git a/llvm/test/Transforms/InstCombine/select-cmp-br.ll b/llvm/test/Transforms/InstCombine/select-cmp-br.ll index 4afa5365e17b..e07bfd108995 100644 --- a/llvm/test/Transforms/InstCombine/select-cmp-br.ll +++ b/llvm/test/Transforms/InstCombine/select-cmp-br.ll @@ -242,3 +242,22 @@ bb5: ; preds = %entry br label %bb } +; Negative test. Must not trigger the select-cmp-br combine because the result +; of the select is used in both flows following the br (the special case where +; the conditional branch has the same target for both flows). +define i32 @test6(i32 %arg, i1 %arg1) { +; CHECK-LABEL: @test6( +; CHECK-NEXT: entry: +; CHECK-NEXT: br i1 undef, label [[BB:%.*]], label [[BB]] +; CHECK: bb: +; CHECK-NEXT: [[TMP:%.*]] = select i1 [[ARG1:%.*]], i32 [[ARG:%.*]], i32 0 +; CHECK-NEXT: ret i32 [[TMP]] +; +entry: + %tmp = select i1 %arg1, i32 %arg, i32 0 + %tmp2 = icmp eq i32 %tmp, 0 + br i1 %tmp2, label %bb, label %bb + +bb: ; preds = %entry, %entry + ret i32 %tmp +}