Index: lib/Transforms/InstCombine/InstCombineCompares.cpp =================================================================== --- lib/Transforms/InstCombine/InstCombineCompares.cpp +++ lib/Transforms/InstCombine/InstCombineCompares.cpp @@ -2427,6 +2427,20 @@ Less = ConstantInt::get(Greater->getType(), -1, true); return true; } + + // Try to recognize: + // select i1 (a < 0), i32 Less, i32 Greater + // simplified in form: + // (a s>> 31) & (Less - Greater) + Greater + ConstantInt *LessMinusGreater; + if (match(SI->getFalseValue(), + m_Add(m_And(m_AShr(m_Specific(LHS), m_Specific(ShiftValue)), + m_ConstantInt(LessMinusGreater)), + m_ConstantInt(Greater)))) { + 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 @@ -242,3 +242,71 @@ 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_1(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_1 +; CHECK: entry: +; CHECK-NEXT: [[COND:%.*]] = icmp sgt i32 %x, %c +; CHECK-NEXT: br i1 [[COND]], 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 -6, 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_add(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_add +; CHECK: entry: +; CHECK-NEXT: [[COND:%.*]] = icmp sgt i32 %x, 0 +; CHECK-NEXT: br i1 [[COND]], label %callfoo, label %exit +; CHECK: callfoo: +; CHECK-NEXT: [[SHR:%.*]] = ashr i32 %x, 31 +; CHECK-NEXT: [[AND:%.*]] = and i32 [[SHR]], -431 +; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[AND]], 425 +; CHECK-NEXT: call void @foo(i32 [[ADD]]) +; 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 -6, 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 +}