Skip to content

Commit

Permalink
[SimplifyCFG] Constant fold a branch implied by it's incoming edge
Browse files Browse the repository at this point in the history
The most common use case is when eliminating redundant range checks in an example like the following:
c = a[i+1] + a[i];

Note that all the smarts of the transform (the implication engine) is already in ValueTracking and is tested directly through InstructionSimplify.

Differential Revision: http://reviews.llvm.org/D13040

llvm-svn: 251596
  • Loading branch information
preames committed Oct 29, 2015
1 parent a904e52 commit 846e3e4
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 0 deletions.
13 changes: 13 additions & 0 deletions llvm/lib/Transforms/Utils/SimplifyCFG.cpp
Expand Up @@ -2390,6 +2390,19 @@ static bool SimplifyCondBranchToCondBranch(BranchInst *PBI, BranchInst *BI,
if (CE->canTrap())
return false;

// If BI is reached from the true path of PBI and PBI's condition implies
// BI's condition, we know the direction of the BI branch.
if (PBI->getSuccessor(0) == BI->getParent() &&
isImpliedCondition(PBI->getCondition(), BI->getCondition()) &&
PBI->getSuccessor(0) != PBI->getSuccessor(1) &&
BB->getSinglePredecessor()) {
// Turn this into a branch on constant.
auto *OldCond = BI->getCondition();
BI->setCondition(ConstantInt::getTrue(BB->getContext()));
RecursivelyDeleteTriviallyDeadInstructions(OldCond);
return true; // Nuke the branch on constant.
}

// If this is a conditional branch in an empty block, and if any
// predecessors are a conditional branch to one of our destinations,
// fold the conditions into logical ops and one cond br.
Expand Down
81 changes: 81 additions & 0 deletions llvm/test/Transforms/SimplifyCFG/implied-cond.ll
@@ -0,0 +1,81 @@
; RUN: opt %s -S -simplifycfg | FileCheck %s
; Check for when one branch implies the value of a successors conditional and
; it's not simply the same conditional repeated.

define void @test(i32 %length.i, i32 %i) {
; CHECK-LABEL: @test
%iplus1 = add nsw i32 %i, 1
%var29 = icmp slt i32 %iplus1, %length.i
; CHECK: br i1 %var29, label %in_bounds, label %out_of_bounds
br i1 %var29, label %next, label %out_of_bounds

next:
; CHECK-LABEL: in_bounds:
; CHECK-NEXT: ret void
%var30 = icmp slt i32 %i, %length.i
br i1 %var30, label %in_bounds, label %out_of_bounds2

in_bounds:
ret void

out_of_bounds:
call void @foo(i64 0)
unreachable

out_of_bounds2:
call void @foo(i64 1)
unreachable
}

; If the add is not nsw, it's not safe to use the fact about i+1 to imply the
; i condition since it could have overflowed.
define void @test_neg(i32 %length.i, i32 %i) {
; CHECK-LABEL: @test_neg
%iplus1 = add i32 %i, 1
%var29 = icmp slt i32 %iplus1, %length.i
; CHECK: br i1 %var29, label %next, label %out_of_bounds
br i1 %var29, label %next, label %out_of_bounds

next:
%var30 = icmp slt i32 %i, %length.i
; CHECK: br i1 %var30, label %in_bounds, label %out_of_bounds2
br i1 %var30, label %in_bounds, label %out_of_bounds2

in_bounds:
ret void

out_of_bounds:
call void @foo(i64 0)
unreachable

out_of_bounds2:
call void @foo(i64 1)
unreachable
}


define void @test2(i32 %length.i, i32 %i) {
; CHECK-LABEL: @test2
%iplus100 = add nsw i32 %i, 100
%var29 = icmp slt i32 %iplus100, %length.i
; CHECK: br i1 %var29, label %in_bounds, label %out_of_bounds
br i1 %var29, label %next, label %out_of_bounds

next:
%var30 = icmp slt i32 %i, %length.i
br i1 %var30, label %in_bounds, label %out_of_bounds2

in_bounds:
ret void

out_of_bounds:
call void @foo(i64 0)
unreachable

out_of_bounds2:
call void @foo(i64 1)
unreachable
}

declare void @foo(i64)

0 comments on commit 846e3e4

Please sign in to comment.