Index: llvm/trunk/lib/Transforms/InstCombine/InstCombineSelect.cpp =================================================================== --- llvm/trunk/lib/Transforms/InstCombine/InstCombineSelect.cpp +++ llvm/trunk/lib/Transforms/InstCombine/InstCombineSelect.cpp @@ -1844,17 +1844,43 @@ } // MAX(~a, ~b) -> ~MIN(a, b) + // MAX(~a, C) -> ~MIN(a, ~C) // MIN(~a, ~b) -> ~MAX(a, b) - Value *A, *B; - if (match(LHS, m_Not(m_Value(A))) && match(RHS, m_Not(m_Value(B))) && - !IsFreeToInvert(A, A->hasOneUse()) && - !IsFreeToInvert(B, B->hasOneUse()) && - (!LHS->hasNUsesOrMore(3) || !RHS->hasNUsesOrMore(3))) { - CmpInst::Predicate InvertedPred = getInverseMinMaxPred(SPF); - Value *InvertedCmp = Builder.CreateICmp(InvertedPred, A, B); - Value *NewSel = Builder.CreateSelect(InvertedCmp, A, B); - return BinaryOperator::CreateNot(NewSel); - } + // MIN(~a, C) -> ~MAX(a, ~C) + auto moveNotAfterMinMax = [&](Value *X, Value *Y, + bool Swapped) -> Instruction * { + Value *A; + if (match(X, m_Not(m_Value(A))) && !X->hasNUsesOrMore(3) && + !IsFreeToInvert(A, A->hasOneUse()) && + // Passing false to only consider m_Not and constants. + IsFreeToInvert(Y, false)) { + Value *B = Builder.CreateNot(Y); + Value *NewMinMax = createMinMax(Builder, getInverseMinMaxFlavor(SPF), + A, B); + // Copy the profile metadata. + if (MDNode *MD = SI.getMetadata(LLVMContext::MD_prof)) { + cast(NewMinMax)->setMetadata(LLVMContext::MD_prof, MD); + // Swap the metadata if the operands are swapped. + if (Swapped) { + assert(X == SI.getFalseValue() && Y == SI.getTrueValue() && + "Unexpected operands."); + cast(NewMinMax)->swapProfMetadata(); + } else { + assert(X == SI.getTrueValue() && Y == SI.getFalseValue() && + "Unexpected operands."); + } + } + + return BinaryOperator::CreateNot(NewMinMax); + } + + return nullptr; + }; + + if (Instruction *I = moveNotAfterMinMax(LHS, RHS, /*Swapped*/false)) + return I; + if (Instruction *I = moveNotAfterMinMax(RHS, LHS, /*Swapped*/true)) + return I; if (Instruction *I = factorizeMinMaxTree(SPF, LHS, RHS, Builder)) return I; Index: llvm/trunk/test/Transforms/InstCombine/max-of-nots.ll =================================================================== --- llvm/trunk/test/Transforms/InstCombine/max-of-nots.ll +++ llvm/trunk/test/Transforms/InstCombine/max-of-nots.ll @@ -3,7 +3,7 @@ define <2 x i32> @umin_of_nots(<2 x i32> %x, <2 x i32> %y) { ; CHECK-LABEL: @umin_of_nots( -; CHECK-NEXT: [[TMP1:%.*]] = icmp ugt <2 x i32> [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: [[TMP1:%.*]] = icmp ult <2 x i32> [[Y:%.*]], [[X:%.*]] ; CHECK-NEXT: [[TMP2:%.*]] = select <2 x i1> [[TMP1]], <2 x i32> [[X]], <2 x i32> [[Y]] ; CHECK-NEXT: [[MIN:%.*]] = xor <2 x i32> [[TMP2]], ; CHECK-NEXT: ret <2 x i32> [[MIN]] @@ -17,7 +17,7 @@ define <2 x i32> @smin_of_nots(<2 x i32> %x, <2 x i32> %y) { ; CHECK-LABEL: @smin_of_nots( -; CHECK-NEXT: [[TMP1:%.*]] = icmp sgt <2 x i32> [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: [[TMP1:%.*]] = icmp slt <2 x i32> [[Y:%.*]], [[X:%.*]] ; CHECK-NEXT: [[TMP2:%.*]] = select <2 x i1> [[TMP1]], <2 x i32> [[X]], <2 x i32> [[Y]] ; CHECK-NEXT: [[MIN:%.*]] = xor <2 x i32> [[TMP2]], ; CHECK-NEXT: ret <2 x i32> [[MIN]] @@ -31,7 +31,7 @@ define i32 @compute_min_2(i32 %x, i32 %y) { ; CHECK-LABEL: @compute_min_2( -; CHECK-NEXT: [[TMP1:%.*]] = icmp slt i32 [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: [[TMP1:%.*]] = icmp sgt i32 [[Y:%.*]], [[X:%.*]] ; CHECK-NEXT: [[TMP2:%.*]] = select i1 [[TMP1]], i32 [[X]], i32 [[Y]] ; CHECK-NEXT: ret i32 [[TMP2]] ; @@ -47,8 +47,8 @@ define i8 @umin_not_1_extra_use(i8 %x, i8 %y) { ; CHECK-LABEL: @umin_not_1_extra_use( ; CHECK-NEXT: [[NX:%.*]] = xor i8 [[X:%.*]], -1 -; CHECK-NEXT: [[TMP1:%.*]] = icmp ugt i8 [[X]], [[Y:%.*]] -; CHECK-NEXT: [[TMP2:%.*]] = select i1 [[TMP1]], i8 [[X]], i8 [[Y]] +; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i8 [[X]], [[Y:%.*]] +; CHECK-NEXT: [[TMP2:%.*]] = select i1 [[TMP1]], i8 [[Y]], i8 [[X]] ; CHECK-NEXT: [[MINXY:%.*]] = xor i8 [[TMP2]], -1 ; CHECK-NEXT: call void @extra_use(i8 [[NX]]) ; CHECK-NEXT: ret i8 [[MINXY]] @@ -84,7 +84,7 @@ define i8 @umin3_not(i8 %x, i8 %y, i8 %z) { ; CHECK-LABEL: @umin3_not( -; CHECK-NEXT: [[TMP1:%.*]] = icmp ugt i8 [[X:%.*]], [[Z:%.*]] +; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i8 [[Z:%.*]], [[X:%.*]] ; CHECK-NEXT: [[TMP2:%.*]] = select i1 [[TMP1]], i8 [[X]], i8 [[Z]] ; CHECK-NEXT: [[TMP3:%.*]] = icmp ugt i8 [[TMP2]], [[Y:%.*]] ; CHECK-NEXT: [[R_V:%.*]] = select i1 [[TMP3]], i8 [[TMP2]], i8 [[Y]] @@ -109,8 +109,8 @@ ; CHECK-LABEL: @umin3_not_more_uses( ; CHECK-NEXT: [[NX:%.*]] = xor i8 [[X:%.*]], -1 ; CHECK-NEXT: [[NY:%.*]] = xor i8 [[Y:%.*]], -1 -; CHECK-NEXT: [[TMP1:%.*]] = icmp ugt i8 [[X]], [[Z:%.*]] -; CHECK-NEXT: [[TMP2:%.*]] = select i1 [[TMP1]], i8 [[X]], i8 [[Z]] +; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i8 [[X]], [[Z:%.*]] +; CHECK-NEXT: [[TMP2:%.*]] = select i1 [[TMP1]], i8 [[Z]], i8 [[X]] ; CHECK-NEXT: [[TMP3:%.*]] = icmp ugt i8 [[TMP2]], [[Y]] ; CHECK-NEXT: [[TMP4:%.*]] = select i1 [[TMP3]], i8 [[TMP2]], i8 [[Y]] ; CHECK-NEXT: [[R:%.*]] = xor i8 [[TMP4]], -1 @@ -198,7 +198,7 @@ define i32 @compute_min_3(i32 %x, i32 %y, i32 %z) { ; CHECK-LABEL: @compute_min_3( -; CHECK-NEXT: [[TMP1:%.*]] = icmp slt i32 [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: [[TMP1:%.*]] = icmp sgt i32 [[Y:%.*]], [[X:%.*]] ; CHECK-NEXT: [[TMP2:%.*]] = select i1 [[TMP1]], i32 [[X]], i32 [[Y]] ; CHECK-NEXT: [[TMP3:%.*]] = icmp slt i32 [[TMP2]], [[Z:%.*]] ; CHECK-NEXT: [[TMP4:%.*]] = select i1 [[TMP3]], i32 [[TMP2]], i32 [[Z]] Index: llvm/trunk/test/Transforms/InstCombine/pr38897.ll =================================================================== --- llvm/trunk/test/Transforms/InstCombine/pr38897.ll +++ llvm/trunk/test/Transforms/InstCombine/pr38897.ll @@ -0,0 +1,28 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt %s -instcombine -S | FileCheck %s + +define i32 @sharpening(i32 %b340, i1 %c, i1 %d, i32 %e, i32 %f, i32 %g, i32 %h) { +; CHECK-LABEL: @sharpening( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[SMAX58:%.*]] = select i1 [[C:%.*]], i32 [[E:%.*]], i32 [[F:%.*]] +; CHECK-NEXT: [[SMAX59:%.*]] = select i1 [[D:%.*]], i32 [[G:%.*]], i32 [[H:%.*]] +; CHECK-NEXT: [[TMP0:%.*]] = add i32 [[SMAX59]], 1 +; CHECK-NEXT: [[TMP1:%.*]] = icmp slt i32 [[TMP0]], -1 +; CHECK-NEXT: [[TMP12:%.*]] = select i1 [[TMP1]], i32 [[TMP0]], i32 -1 +; CHECK-NEXT: [[TMP13:%.*]] = icmp sgt i32 [[SMAX58]], [[TMP12]] +; CHECK-NEXT: [[SMAX61:%.*]] = select i1 [[TMP13]], i32 [[SMAX58]], i32 [[TMP12]] +; CHECK-NEXT: [[TMP14:%.*]] = xor i32 [[SMAX61]], -1 +; CHECK-NEXT: ret i32 [[TMP14]] +; +entry: + %smax58 = select i1 %c, i32 %e, i32 %f + %smax59 = select i1 %d, i32 %g, i32 %h + %tmp10 = sub i32 -2, %smax59 + %tmp11 = icmp sgt i32 %tmp10, 0 + %smax60 = select i1 %tmp11, i32 %tmp10, i32 0 + %tmp12 = xor i32 %smax60, -1 + %tmp13 = icmp sgt i32 %smax58, %tmp12 + %smax61 = select i1 %tmp13, i32 %smax58, i32 %tmp12 + %tmp14 = xor i32 %smax61, -1 + ret i32 %tmp14 +} Index: llvm/trunk/test/Transforms/InstCombine/select.ll =================================================================== --- llvm/trunk/test/Transforms/InstCombine/select.ll +++ llvm/trunk/test/Transforms/InstCombine/select.ll @@ -1329,13 +1329,13 @@ ret i32 %sel } -; max(max(~a, -1), -1) --> max(~a, -1) +; max(max(~a, -1), -1) --> ~min(a, 0) define i32 @PR27137(i32 %a) { ; CHECK-LABEL: @PR27137( -; CHECK-NEXT: [[NOT_A:%.*]] = xor i32 [[A:%.*]], -1 -; CHECK-NEXT: [[TMP1:%.*]] = icmp sgt i32 [[NOT_A]], -1 -; CHECK-NEXT: [[S1:%.*]] = select i1 [[TMP1]], i32 [[NOT_A]], i32 -1 +; CHECK-NEXT: [[TMP1:%.*]] = icmp slt i32 [[A:%.*]], 0 +; CHECK-NEXT: [[TMP2:%.*]] = select i1 [[TMP1]], i32 [[A]], i32 0 +; CHECK-NEXT: [[S1:%.*]] = xor i32 [[TMP2]], -1 ; CHECK-NEXT: ret i32 [[S1]] ; %not_a = xor i32 %a, -1 Index: llvm/trunk/test/Transforms/InstCombine/select_meta.ll =================================================================== --- llvm/trunk/test/Transforms/InstCombine/select_meta.ll +++ llvm/trunk/test/Transforms/InstCombine/select_meta.ll @@ -194,12 +194,12 @@ ret i32 %retval } -; The compare should change, but the metadata remains the same because the select operands are not swapped. +; The xor is moved after the select. The metadata remains the same because the select operands are not swapped only inverted. define i32 @smin1(i32 %x) { ; CHECK-LABEL: @smin1( -; CHECK-NEXT: [[NOT_X:%.*]] = xor i32 %x, -1 -; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[NOT_X]], -1 -; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i32 [[NOT_X]], i32 -1, !prof ![[$MD1]] +; CHECK-NEXT: [[TMP1:%.*]] = icmp sgt i32 [[X:%.*]], 0 +; CHECK-NEXT: [[TMP2:%.*]] = select i1 [[TMP1]], i32 [[X]], i32 0, !prof ![[$MD1]] +; CHECK-NEXT: [[SEL:%.*]] = xor i32 [[TMP2]], -1 ; CHECK-NEXT: ret i32 [[SEL]] ; %not_x = xor i32 %x, -1 @@ -208,12 +208,12 @@ ret i32 %sel } -; The compare should change, and the metadata is swapped because the select operands are swapped. +; The compare should change, and the metadata is swapped because the select operands are swapped and inverted. define i32 @smin2(i32 %x) { ; CHECK-LABEL: @smin2( -; CHECK-NEXT: [[NOT_X:%.*]] = xor i32 %x, -1 -; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[NOT_X]], -1 -; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i32 [[NOT_X]], i32 -1, !prof ![[$MD3]] +; CHECK-NEXT: [[TMP1:%.*]] = icmp sgt i32 [[X:%.*]], 0 +; CHECK-NEXT: [[TMP2:%.*]] = select i1 [[TMP1]], i32 [[X]], i32 0, !prof ![[$MD3]] +; CHECK-NEXT: [[SEL:%.*]] = xor i32 [[TMP2]], -1 ; CHECK-NEXT: ret i32 [[SEL]] ; %not_x = xor i32 %x, -1 @@ -222,12 +222,12 @@ ret i32 %sel } -; The compare should change, but the metadata remains the same because the select operands are not swapped. +; The xor is moved after the select. The metadata remains the same because the select operands are not swapped only inverted. define i32 @smax1(i32 %x) { ; CHECK-LABEL: @smax1( -; CHECK-NEXT: [[NOT_X:%.*]] = xor i32 %x, -1 -; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[NOT_X]], -1 -; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i32 [[NOT_X]], i32 -1, !prof ![[$MD1]] +; CHECK-NEXT: [[TMP1:%.*]] = icmp slt i32 [[X:%.*]], 0 +; CHECK-NEXT: [[TMP2:%.*]] = select i1 [[TMP1]], i32 [[X]], i32 0, !prof ![[$MD1]] +; CHECK-NEXT: [[SEL:%.*]] = xor i32 [[TMP2]], -1 ; CHECK-NEXT: ret i32 [[SEL]] ; %not_x = xor i32 %x, -1 @@ -236,12 +236,12 @@ ret i32 %sel } -; The compare should change, and the metadata is swapped because the select operands are swapped. +; The compare should change, and the metadata is swapped because the select operands are swapped and inverted. define i32 @smax2(i32 %x) { ; CHECK-LABEL: @smax2( -; CHECK-NEXT: [[NOT_X:%.*]] = xor i32 %x, -1 -; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[NOT_X]], -1 -; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i32 [[NOT_X]], i32 -1, !prof ![[$MD3]] +; CHECK-NEXT: [[TMP1:%.*]] = icmp slt i32 [[X:%.*]], 0 +; CHECK-NEXT: [[TMP2:%.*]] = select i1 [[TMP1]], i32 [[X]], i32 0, !prof ![[$MD3]] +; CHECK-NEXT: [[SEL:%.*]] = xor i32 [[TMP2]], -1 ; CHECK-NEXT: ret i32 [[SEL]] ; %not_x = xor i32 %x, -1 Index: llvm/trunk/test/Transforms/InstCombine/sub.ll =================================================================== --- llvm/trunk/test/Transforms/InstCombine/sub.ll +++ llvm/trunk/test/Transforms/InstCombine/sub.ll @@ -1060,10 +1060,9 @@ ; FIXME: Transform (neg (max ~X, C)) -> ((min X, ~C) + 1). Same for min. define i32 @test64(i32 %x) { ; CHECK-LABEL: @test64( -; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[X:%.*]], -1 -; CHECK-NEXT: [[TMP2:%.*]] = icmp sgt i32 [[TMP1]], -256 -; CHECK-NEXT: [[TMP3:%.*]] = select i1 [[TMP2]], i32 [[TMP1]], i32 -256 -; CHECK-NEXT: [[RES:%.*]] = sub i32 0, [[TMP3]] +; CHECK-NEXT: [[TMP1:%.*]] = icmp slt i32 [[X:%.*]], 255 +; CHECK-NEXT: [[TMP2:%.*]] = select i1 [[TMP1]], i32 [[X]], i32 255 +; CHECK-NEXT: [[RES:%.*]] = add i32 [[TMP2]], 1 ; CHECK-NEXT: ret i32 [[RES]] ; %1 = xor i32 %x, -1 @@ -1075,10 +1074,9 @@ define i32 @test65(i32 %x) { ; CHECK-LABEL: @test65( -; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[X:%.*]], -1 -; CHECK-NEXT: [[TMP2:%.*]] = icmp slt i32 [[TMP1]], 255 -; CHECK-NEXT: [[TMP3:%.*]] = select i1 [[TMP2]], i32 [[TMP1]], i32 255 -; CHECK-NEXT: [[RES:%.*]] = sub i32 0, [[TMP3]] +; CHECK-NEXT: [[TMP1:%.*]] = icmp sgt i32 [[X:%.*]], -256 +; CHECK-NEXT: [[TMP2:%.*]] = select i1 [[TMP1]], i32 [[X]], i32 -256 +; CHECK-NEXT: [[RES:%.*]] = add i32 [[TMP2]], 1 ; CHECK-NEXT: ret i32 [[RES]] ; %1 = xor i32 %x, -1 @@ -1090,10 +1088,9 @@ define i32 @test66(i32 %x) { ; CHECK-LABEL: @test66( -; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[X:%.*]], -1 -; CHECK-NEXT: [[TMP2:%.*]] = icmp ugt i32 [[TMP1]], 100 -; CHECK-NEXT: [[TMP3:%.*]] = select i1 [[TMP2]], i32 [[TMP1]], i32 100 -; CHECK-NEXT: [[RES:%.*]] = sub i32 0, [[TMP3]] +; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i32 [[X:%.*]], -101 +; CHECK-NEXT: [[TMP2:%.*]] = select i1 [[TMP1]], i32 [[X]], i32 -101 +; CHECK-NEXT: [[RES:%.*]] = add i32 [[TMP2]], 1 ; CHECK-NEXT: ret i32 [[RES]] ; %1 = xor i32 %x, -1 @@ -1105,10 +1102,9 @@ define i32 @test67(i32 %x) { ; CHECK-LABEL: @test67( -; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[X:%.*]], -1 -; CHECK-NEXT: [[TMP2:%.*]] = icmp ult i32 [[TMP1]], -101 -; CHECK-NEXT: [[TMP3:%.*]] = select i1 [[TMP2]], i32 [[TMP1]], i32 -101 -; CHECK-NEXT: [[RES:%.*]] = sub i32 0, [[TMP3]] +; CHECK-NEXT: [[TMP1:%.*]] = icmp ugt i32 [[X:%.*]], 100 +; CHECK-NEXT: [[TMP2:%.*]] = select i1 [[TMP1]], i32 [[X]], i32 100 +; CHECK-NEXT: [[RES:%.*]] = add i32 [[TMP2]], 1 ; CHECK-NEXT: ret i32 [[RES]] ; %1 = xor i32 %x, -1 @@ -1121,10 +1117,9 @@ ; Check splat vectors too define <2 x i32> @test68(<2 x i32> %x) { ; CHECK-LABEL: @test68( -; CHECK-NEXT: [[TMP1:%.*]] = xor <2 x i32> [[X:%.*]], -; CHECK-NEXT: [[TMP2:%.*]] = icmp sgt <2 x i32> [[TMP1]], -; CHECK-NEXT: [[TMP3:%.*]] = select <2 x i1> [[TMP2]], <2 x i32> [[TMP1]], <2 x i32> -; CHECK-NEXT: [[RES:%.*]] = sub <2 x i32> zeroinitializer, [[TMP3]] +; CHECK-NEXT: [[TMP1:%.*]] = icmp slt <2 x i32> [[X:%.*]], +; CHECK-NEXT: [[TMP2:%.*]] = select <2 x i1> [[TMP1]], <2 x i32> [[X]], <2 x i32> +; CHECK-NEXT: [[RES:%.*]] = add <2 x i32> [[TMP2]], ; CHECK-NEXT: ret <2 x i32> [[RES]] ; %1 = xor <2 x i32> %x, @@ -1137,10 +1132,9 @@ ; And non-splat constant vectors. define <2 x i32> @test69(<2 x i32> %x) { ; CHECK-LABEL: @test69( -; CHECK-NEXT: [[TMP1:%.*]] = xor <2 x i32> [[X:%.*]], -; CHECK-NEXT: [[TMP2:%.*]] = icmp sgt <2 x i32> [[TMP1]], -; CHECK-NEXT: [[TMP3:%.*]] = select <2 x i1> [[TMP2]], <2 x i32> [[TMP1]], <2 x i32> -; CHECK-NEXT: [[RES:%.*]] = sub <2 x i32> zeroinitializer, [[TMP3]] +; CHECK-NEXT: [[TMP1:%.*]] = icmp slt <2 x i32> [[X:%.*]], +; CHECK-NEXT: [[TMP2:%.*]] = select <2 x i1> [[TMP1]], <2 x i32> [[X]], <2 x i32> +; CHECK-NEXT: [[RES:%.*]] = add <2 x i32> [[TMP2]], ; CHECK-NEXT: ret <2 x i32> [[RES]] ; %1 = xor <2 x i32> %x, Index: llvm/trunk/test/Transforms/InstCombine/xor.ll =================================================================== --- llvm/trunk/test/Transforms/InstCombine/xor.ll +++ llvm/trunk/test/Transforms/InstCombine/xor.ll @@ -757,7 +757,7 @@ define i32 @test45(i32 %x, i32 %y) { ; CHECK-LABEL: @test45( -; CHECK-NEXT: [[TMP1:%.*]] = icmp ugt i32 [[Y:%.*]], [[X:%.*]] +; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i32 [[X:%.*]], [[Y:%.*]] ; CHECK-NEXT: [[TMP2:%.*]] = select i1 [[TMP1]], i32 [[Y]], i32 [[X]] ; CHECK-NEXT: ret i32 [[TMP2]] ;