return nullptr;
}
+/// Try to determine the result of a select based on a dominating condition.
+static Value *foldSelectWithDominatingCond(Value *Cond, Value *TV, Value *FV,
+ const SimplifyQuery &Q) {
+ // First, make sure that we have a select in a basic block.
+ // We don't know if we are called from some incomplete state.
+ if (!Q.CxtI || !Q.CxtI->getParent())
+ return nullptr;
+
+ // TODO: This is a poor/cheap way to determine dominance. Should we use the
+ // dominator tree in the SimplifyQuery instead?
+ const BasicBlock *SelectBB = Q.CxtI->getParent();
+ const BasicBlock *PredBB = SelectBB->getSinglePredecessor();
+ if (!PredBB)
+ return nullptr;
+
+ // We need a conditional branch in the predecessor.
+ Value *PredCond;
+ BasicBlock *TrueBB, *FalseBB;
+ if (!match(PredBB->getTerminator(), m_Br(m_Value(PredCond), TrueBB, FalseBB)))
+ return nullptr;
+
+ // The branch should get simplified. Don't bother simplifying the select.
+ if (TrueBB == FalseBB)
+ return nullptr;
+
+ assert((TrueBB == SelectBB || FalseBB == SelectBB) &&
+ "Predecessor block does not point to successor?");
+
+ // Is the select condition implied by the predecessor condition?
+ bool CondIsTrue = TrueBB == SelectBB;
+ Optional<bool> Implied = isImpliedCondition(PredCond, Cond, Q.DL, CondIsTrue);
+ if (!Implied)
+ return nullptr;
+ return *Implied ? TV : FV;
+}
+
/// Given operands for a SelectInst, see if we can fold the result.
/// If not, this returns null.
static Value *SimplifySelectInst(Value *Cond, Value *TrueVal, Value *FalseVal,
if (Value *V = foldSelectWithBinaryOp(Cond, TrueVal, FalseVal))
return V;
+ if (Value *V = foldSelectWithDominatingCond(Cond, TrueVal, FalseVal, Q))
+ return V;
+
return nullptr;
}
}
}
- // See if we can determine the result of this select based on a dominating
- // condition.
- BasicBlock *Parent = SI.getParent();
- if (BasicBlock *Dom = Parent->getSinglePredecessor()) {
- auto *PBI = dyn_cast_or_null<BranchInst>(Dom->getTerminator());
- if (PBI && PBI->isConditional() &&
- PBI->getSuccessor(0) != PBI->getSuccessor(1) &&
- (PBI->getSuccessor(0) == Parent || PBI->getSuccessor(1) == Parent)) {
- bool CondIsTrue = PBI->getSuccessor(0) == Parent;
- Optional<bool> Implication = isImpliedCondition(
- PBI->getCondition(), SI.getCondition(), DL, CondIsTrue);
- if (Implication) {
- Value *V = *Implication ? TrueVal : FalseVal;
- return replaceInstUsesWith(SI, V);
- }
- }
- }
-
// If we can compute the condition, there's no need for a select.
// Like the above fold, we are attempting to reduce compile-time cost by
// putting this fold here with limitations rather than in InstSimplify.
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; Various patterns of three-ways comparison that are not currently recognized.
-
; RUN: opt < %s -instcombine -S | FileCheck %s
target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128"
declare void @foo(i32 %x)
define i32 @compare_against_arbitrary_value(i32 %x, i32 %c) {
-; TODO: We can prove that if %x s> %c then %x != c, so there should be no actual
-; calculations in callfoo block. @foo can be invoked with 1. We only do it
-; for constants that are not 0 currently while it could be generalized.
; CHECK-LABEL: @compare_against_arbitrary_value(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[TMP0:%.*]] = icmp sgt i32 [[X:%.*]], [[C:%.*]]
; CHECK-NEXT: br i1 [[TMP0]], label [[CALLFOO:%.*]], label [[EXIT:%.*]]
; CHECK: callfoo:
-; CHECK-NEXT: [[CMP1:%.*]] = icmp ne i32 [[X]], [[C]]
-; CHECK-NEXT: [[SELECT2:%.*]] = zext i1 [[CMP1]] to i32
-; CHECK-NEXT: call void @foo(i32 [[SELECT2]])
+; CHECK-NEXT: call void @foo(i32 1)
; CHECK-NEXT: br label [[EXIT]]
; CHECK: exit:
; CHECK-NEXT: ret i32 42
}
define i32 @compare_against_arbitrary_value_type_mismatch(i64 %x, i64 %c) {
-; TODO: We can prove that if %x s> %c then %x != c, so there should be no actual
-; calculations in callfoo block. @foo can be invoked with 1. We only do it
-; for constants that are not 0 currently while it could be generalized.
; CHECK-LABEL: @compare_against_arbitrary_value_type_mismatch(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[TMP0:%.*]] = icmp sgt i64 [[X:%.*]], [[C:%.*]]
; CHECK-NEXT: br i1 [[TMP0]], label [[CALLFOO:%.*]], label [[EXIT:%.*]]
; CHECK: callfoo:
-; CHECK-NEXT: [[CMP1:%.*]] = icmp ne i64 [[X]], [[C]]
-; CHECK-NEXT: [[SELECT2:%.*]] = zext i1 [[CMP1]] to i32
-; CHECK-NEXT: call void @foo(i32 [[SELECT2]])
+; CHECK-NEXT: call void @foo(i32 1)
; CHECK-NEXT: br label [[EXIT]]
; CHECK: exit:
; CHECK-NEXT: ret i32 42
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt < %s -instcombine -S | FileCheck %s
+; RUN: opt < %s -instsimplify -S | FileCheck %s
; A == B implies A >u B is false.
}
; We know the condition of the select is true based on a dominating condition.
-; Therefore, we can replace %cond with %len. However, now the inner icmp is
-; always false and can be elided.
+; Therefore, we can replace %cond with %len.
+; TODO: len == 8 is known false in bb. This is handled by other passes, but should it be handled here?
define void @test4(i32 %len) {
; CHECK-LABEL: @test4(
; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[LEN]], 4
; CHECK-NEXT: br i1 [[CMP]], label [[BB:%.*]], label [[B1:%.*]]
; CHECK: bb:
-; CHECK-NEXT: br i1 false, label [[B0:%.*]], label [[B1]]
+; CHECK-NEXT: [[CMP11:%.*]] = icmp eq i32 [[LEN]], 8
+; CHECK-NEXT: br i1 [[CMP11]], label [[B0:%.*]], label [[B1]]
; CHECK: b0:
+; CHECK-NEXT: call void @foo(i32 [[LEN]])
; CHECK-NEXT: br label [[B1]]
; CHECK: b1:
; CHECK-NEXT: [[TMP1:%.*]] = phi i32 [ [[LEN]], [[BB]] ], [ undef, [[B0]] ], [ [[TMP0]], [[ENTRY:%.*]] ]