Index: lib/Transforms/InstCombine/InstCombineCompares.cpp =================================================================== --- lib/Transforms/InstCombine/InstCombineCompares.cpp +++ lib/Transforms/InstCombine/InstCombineCompares.cpp @@ -2441,6 +2441,22 @@ Less = ConstantInt::get(Greater->getContext(), LessI); return true; } + + // Try to recognize: + // select i1 (a < 0), i32 Less, i32 Greater + // simplified in form: + // (a s>> 31) & (Less - Greater) | Greater + // It is used instead of the pattern above in case if we can prove that + // ((Less - Greater) & Greater) = 0. + if (match(SI->getFalseValue(), + m_Or(m_And(m_AShr(m_Specific(LHS), m_Specific(ShiftValue)), + m_ConstantInt(LessMinusGreater)), + m_ConstantInt(Greater))) && + (LessMinusGreater->getValue() & Greater->getValue()).isNullValue()) { + APInt LessI = LessMinusGreater->getValue() + Greater->getValue(); + Less = ConstantInt::get(Greater->getContext(), LessI); + return true; + } } } return false; Index: test/Transforms/InstCombine/three-way-comparison.ll =================================================================== --- test/Transforms/InstCombine/three-way-comparison.ll +++ test/Transforms/InstCombine/three-way-comparison.ll @@ -307,3 +307,68 @@ exit: ret i32 42 } + +; Same as @compare_against_arbitrary_value, but now the three-way comparison +; returns not idiomatic comparator's result (-1, 0, 1) but some other constants. +define i32 @compare_against_arbitrary_value_non_idiomatic_2(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 425. +; CHECK-LABEL: @compare_against_arbitrary_value_non_idiomatic_2( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[TMP0:%.*]] = icmp sgt i32 [[X:%.*]], [[C:%.*]] +; CHECK-NEXT: br i1 [[TMP0]], label [[CALLFOO:%.*]], label [[EXIT:%.*]] +; CHECK: callfoo: +; CHECK-NEXT: call void @foo(i32 425) +; CHECK-NEXT: br label [[EXIT]] +; CHECK: exit: +; CHECK-NEXT: ret i32 42 +; + +entry: + %cmp1 = icmp eq i32 %x, %c + %cmp2 = icmp slt i32 %x, %c + %select1 = select i1 %cmp2, i32 -5, i32 425 + %select2 = select i1 %cmp1, i32 0, i32 %select1 + %cond = icmp sgt i32 %select2, 0 + br i1 %cond, label %callfoo, label %exit + +callfoo: + call void @foo(i32 %select2) + br label %exit + +exit: + ret i32 42 +} + +define i32 @compare_against_zero_non_idiomatic_or(i32 %x) { +; 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 425. +; CHECK-LABEL: @compare_against_zero_non_idiomatic_or( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[TMP0:%.*]] = icmp sgt i32 [[X:%.*]], 0 +; CHECK-NEXT: br i1 [[TMP0]], label [[CALLFOO:%.*]], label [[EXIT:%.*]] +; CHECK: callfoo: +; CHECK-NEXT: [[TMP1:%.*]] = ashr i32 [[X]], 31 +; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], -430 +; CHECK-NEXT: [[TMP3:%.*]] = or i32 [[TMP2]], 425 +; CHECK-NEXT: call void @foo(i32 [[TMP3]]) +; CHECK-NEXT: br label [[EXIT]] +; CHECK: exit: +; CHECK-NEXT: ret i32 42 +; + +entry: + %cmp1 = icmp eq i32 %x, 0 + %cmp2 = icmp slt i32 %x, 0 + %select1 = select i1 %cmp2, i32 -5, i32 425 + %select2 = select i1 %cmp1, i32 0, i32 %select1 + %cond = icmp sgt i32 %select2, 0 + br i1 %cond, label %callfoo, label %exit + +callfoo: + call void @foo(i32 %select2) + br label %exit + +exit: + ret i32 42 +}