Instruction *InstCombinerImpl::foldSelectICmp(ICmpInst::Predicate Pred,
SelectInst *SI, Value *RHS,
const ICmpInst &I) {
- // If either operand of the select is a constant, we can fold the
- // comparison into the select arms, which will cause one to be
- // constant folded and the select turned into a bitwise or.
- auto *RHSC = dyn_cast<Constant>(RHS);
- if (!RHSC)
- return nullptr;
-
- auto SimplifyOp = [&](Value *V) {
- Value *Op = nullptr;
- if (Constant *C = dyn_cast<Constant>(V)) {
- Op = ConstantExpr::getICmp(Pred, C, RHSC);
- } else if (RHSC->isNullValue()) {
- // If null is being compared, check if it can be further simplified.
- Op = SimplifyICmpInst(Pred, V, RHSC, SQ);
- }
- return Op;
- };
-
+ // Try to fold the comparison into the select arms, which will cause the
+ // select to be converted into a logical and/or.
ConstantInt *CI = nullptr;
- Value *Op1 = SimplifyOp(SI->getOperand(1));
+ Value *Op1 = SimplifyICmpInst(Pred, SI->getOperand(1), RHS, SQ);
if (Op1)
CI = dyn_cast<ConstantInt>(Op1);
- Value *Op2 = SimplifyOp(SI->getOperand(2));
+ Value *Op2 = SimplifyICmpInst(Pred, SI->getOperand(2), RHS, SQ);
if (Op2)
CI = dyn_cast<ConstantInt>(Op2);
}
if (Transform) {
if (!Op1)
- Op1 = Builder.CreateICmp(Pred, SI->getOperand(1), RHSC, I.getName());
+ Op1 = Builder.CreateICmp(Pred, SI->getOperand(1), RHS, I.getName());
if (!Op2)
- Op2 = Builder.CreateICmp(Pred, SI->getOperand(2), RHSC, I.getName());
+ Op2 = Builder.CreateICmp(Pred, SI->getOperand(2), RHS, I.getName());
return SelectInst::Create(SI->getOperand(0), Op1, Op2);
}
if (auto *SI = dyn_cast<SelectInst>(Op0))
if (Instruction *NI = foldSelectICmp(I.getPredicate(), SI, Op1, I))
return NI;
+ if (auto *SI = dyn_cast<SelectInst>(Op1))
+ if (Instruction *NI = foldSelectICmp(I.getSwappedPredicate(), SI, Op0, I))
+ return NI;
// Try to optimize equality comparisons against alloca-based pointers.
if (Op0->getType()->isPointerTy() && I.isEquality()) {
define i1 @icmp_select_var(i8 %x, i8 %y, i8 %z) {
; CHECK-LABEL: @icmp_select_var(
; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i8 [[X:%.*]], 0
-; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP1]], i8 [[Z:%.*]], i8 [[Y:%.*]]
-; CHECK-NEXT: [[CMP2:%.*]] = icmp eq i8 [[SEL]], [[Z]]
+; CHECK-NEXT: [[CMP21:%.*]] = icmp eq i8 [[Y:%.*]], [[Z:%.*]]
+; CHECK-NEXT: [[CMP2:%.*]] = select i1 [[CMP1]], i1 true, i1 [[CMP21]]
; CHECK-NEXT: ret i1 [[CMP2]]
;
%cmp1 = icmp eq i8 %x, 0
; CHECK-LABEL: @icmp_select_var_commuted(
; CHECK-NEXT: [[Z:%.*]] = udiv i8 42, [[_Z:%.*]]
; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i8 [[X:%.*]], 0
-; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP1]], i8 [[Z]], i8 [[Y:%.*]]
-; CHECK-NEXT: [[CMP2:%.*]] = icmp eq i8 [[Z]], [[SEL]]
+; CHECK-NEXT: [[CMP21:%.*]] = icmp eq i8 [[Z]], [[Y:%.*]]
+; CHECK-NEXT: [[CMP2:%.*]] = select i1 [[CMP1]], i1 true, i1 [[CMP21]]
; CHECK-NEXT: ret i1 [[CMP2]]
;
%z = udiv i8 42, %_z ; thwart complexity-based canonicalization
define i1 @icmp_select_var_select(i8 %x, i8 %y, i1 %c) {
; CHECK-LABEL: @icmp_select_var_select(
-; CHECK-NEXT: [[Z:%.*]] = select i1 [[C:%.*]], i8 [[X:%.*]], i8 [[Y:%.*]]
-; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i8 [[X]], 0
-; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP1]], i8 [[Z]], i8 [[Y]]
-; CHECK-NEXT: [[CMP2:%.*]] = icmp eq i8 [[Z]], [[SEL]]
+; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i8 [[X:%.*]], 0
+; CHECK-NEXT: [[CMP212:%.*]] = icmp eq i8 [[X]], [[Y:%.*]]
+; CHECK-NEXT: [[NOT_C:%.*]] = xor i1 [[C:%.*]], true
+; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[CMP1]], i1 true, i1 [[NOT_C]]
+; CHECK-NEXT: [[CMP2:%.*]] = select i1 [[TMP1]], i1 true, i1 [[CMP212]]
; CHECK-NEXT: ret i1 [[CMP2]]
;
%z = select i1 %c, i8 %x, i8 %y
define i1 @icmp_select_var_pred_ne(i8 %x, i8 %y, i8 %z) {
; CHECK-LABEL: @icmp_select_var_pred_ne(
-; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i8 [[X:%.*]], 0
-; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP1]], i8 [[Z:%.*]], i8 [[Y:%.*]]
-; CHECK-NEXT: [[CMP2:%.*]] = icmp ne i8 [[SEL]], [[Z]]
+; CHECK-NEXT: [[CMP1:%.*]] = icmp ne i8 [[X:%.*]], 0
+; CHECK-NEXT: [[CMP21:%.*]] = icmp ne i8 [[Y:%.*]], [[Z:%.*]]
+; CHECK-NEXT: [[CMP2:%.*]] = select i1 [[CMP1]], i1 [[CMP21]], i1 false
; CHECK-NEXT: ret i1 [[CMP2]]
;
%cmp1 = icmp eq i8 %x, 0
; CHECK-LABEL: @icmp_select_var_pred_ult(
; CHECK-NEXT: [[Z1:%.*]] = add nuw i8 [[Z:%.*]], 2
; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i8 [[X:%.*]], 0
-; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP1]], i8 [[Z]], i8 [[Y:%.*]]
-; CHECK-NEXT: [[CMP2:%.*]] = icmp ult i8 [[SEL]], [[Z1]]
+; CHECK-NEXT: [[CMP21:%.*]] = icmp ugt i8 [[Z1]], [[Y:%.*]]
+; CHECK-NEXT: [[CMP2:%.*]] = select i1 [[CMP1]], i1 true, i1 [[CMP21]]
; CHECK-NEXT: ret i1 [[CMP2]]
;
%z1 = add nuw i8 %z, 2
define i1 @icmp_select_var_pred_uge(i8 %x, i8 %y, i8 %z) {
; CHECK-LABEL: @icmp_select_var_pred_uge(
; CHECK-NEXT: [[Z1:%.*]] = add nuw i8 [[Z:%.*]], 2
-; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i8 [[X:%.*]], 0
-; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP1]], i8 [[Z]], i8 [[Y:%.*]]
-; CHECK-NEXT: [[CMP2:%.*]] = icmp uge i8 [[SEL]], [[Z1]]
+; CHECK-NEXT: [[CMP1:%.*]] = icmp ne i8 [[X:%.*]], 0
+; CHECK-NEXT: [[CMP21:%.*]] = icmp ule i8 [[Z1]], [[Y:%.*]]
+; CHECK-NEXT: [[CMP2:%.*]] = select i1 [[CMP1]], i1 [[CMP21]], i1 false
; CHECK-NEXT: ret i1 [[CMP2]]
;
%z1 = add nuw i8 %z, 2
; CHECK-LABEL: @icmp_select_var_pred_uge_commuted(
; CHECK-NEXT: [[Z1:%.*]] = add nuw i8 [[Z:%.*]], 2
; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i8 [[X:%.*]], 0
-; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP1]], i8 [[Z]], i8 [[Y:%.*]]
-; CHECK-NEXT: [[CMP2:%.*]] = icmp uge i8 [[Z1]], [[SEL]]
+; CHECK-NEXT: [[CMP21:%.*]] = icmp uge i8 [[Z1]], [[Y:%.*]]
+; CHECK-NEXT: [[CMP2:%.*]] = select i1 [[CMP1]], i1 true, i1 [[CMP21]]
; CHECK-NEXT: ret i1 [[CMP2]]
;
%z1 = add nuw i8 %z, 2
define i32 @test40(i32 %a, i32 %b) nounwind {
; CHECK-LABEL: @test40(
; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[B:%.*]], 2
-; CHECK-NEXT: [[DIV:%.*]] = lshr i32 [[A:%.*]], [[TMP1]]
-; CHECK-NEXT: ret i32 [[DIV]]
+; CHECK-NEXT: [[DIV1:%.*]] = lshr i32 [[A:%.*]], [[TMP1]]
+; CHECK-NEXT: ret i32 [[DIV1]]
;
%shl1 = shl i32 1, %b
%shl2 = shl i32 %shl1, 2
define i32 @test43(i32 %a, i32 %b) nounwind {
; CHECK-LABEL: @test43(
; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[B:%.*]], 12
-; CHECK-NEXT: [[DIV2:%.*]] = lshr i32 [[A:%.*]], [[TMP1]]
-; CHECK-NEXT: ret i32 [[DIV2]]
+; CHECK-NEXT: [[DIV21:%.*]] = lshr i32 [[A:%.*]], [[TMP1]]
+; CHECK-NEXT: ret i32 [[DIV21]]
;
%div = shl i32 4096, %b ; must be exact otherwise we'd divide by zero
%div2 = udiv i32 %a, %div
; CHECK-NEXT: [[TMP2:%.*]] = select i1 [[TMP1]], i64 -1, i64 -2
; CHECK-NEXT: [[G11:%.*]] = getelementptr i177, i177* [[A]], i64 [[TMP2]]
; CHECK-NEXT: [[L7:%.*]] = load i177, i177* [[G11]], align 4
-; CHECK-NEXT: [[B36:%.*]] = select i1 [[TMP1]], i177 0, i177 [[L7]]
-; CHECK-NEXT: [[C17:%.*]] = icmp sgt i177 [[B36]], [[L7]]
+; CHECK-NEXT: [[C171:%.*]] = icmp slt i177 [[L7]], 0
+; CHECK-NEXT: [[C17:%.*]] = select i1 [[TMP1]], i1 [[C171]], i1 false
; CHECK-NEXT: [[TMP3:%.*]] = sext i1 [[C17]] to i64
; CHECK-NEXT: [[G62:%.*]] = getelementptr i177, i177* [[G11]], i64 [[TMP3]]
; CHECK-NEXT: [[TMP4:%.*]] = icmp eq i177 [[L7]], -1