Index: lib/Transforms/InstCombine/InstCombineAndOrXor.cpp =================================================================== --- lib/Transforms/InstCombine/InstCombineAndOrXor.cpp +++ lib/Transforms/InstCombine/InstCombineAndOrXor.cpp @@ -2898,6 +2898,17 @@ return SelectInst::Create( Builder.CreateICmp(getInverseMinMaxPred(SPF), NotX, Y), NotX, Y); } + + // If both sides are freely invertible, then we can get rid of the xor + // completely. + if (IsFreeToInvert(LHS, !LHS->hasNUsesOrMore(3)) && + IsFreeToInvert(RHS, !RHS->hasNUsesOrMore(3))) { + Value *NotLHS = Builder.CreateNot(LHS); + Value *NotRHS = Builder.CreateNot(RHS); + return SelectInst::Create( + Builder.CreateICmp(getInverseMinMaxPred(SPF), NotLHS, NotRHS), + NotLHS, NotRHS); + } } } Index: lib/Transforms/InstCombine/InstCombineSelect.cpp =================================================================== --- lib/Transforms/InstCombine/InstCombineSelect.cpp +++ lib/Transforms/InstCombine/InstCombineSelect.cpp @@ -1830,6 +1830,8 @@ // 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); Index: test/Transforms/InstCombine/xor.ll =================================================================== --- test/Transforms/InstCombine/xor.ll +++ test/Transforms/InstCombine/xor.ll @@ -802,3 +802,123 @@ %res = mul i32 %umin, %add ret i32 %res } + +define i32 @test48(i32 %x) { +; CHECK-LABEL: @test48( +; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[X:%.*]], 1 +; CHECK-NEXT: [[TMP2:%.*]] = icmp slt i32 [[TMP1]], -1 +; CHECK-NEXT: [[D:%.*]] = select i1 [[TMP2]], i32 [[TMP1]], i32 -1 +; CHECK-NEXT: ret i32 [[D]] +; + %a = sub i32 -2, %x + %b = icmp sgt i32 %a, 0 + %c = select i1 %b, i32 %a, i32 0 + %d = xor i32 %c, -1 + ret i32 %d +} + +define <2 x i32> @test48vec(<2 x i32> %x) { +; CHECK-LABEL: @test48vec( +; CHECK-NEXT: [[TMP1:%.*]] = add <2 x i32> [[X:%.*]], +; CHECK-NEXT: [[TMP2:%.*]] = icmp slt <2 x i32> [[TMP1]], +; CHECK-NEXT: [[D:%.*]] = select <2 x i1> [[TMP2]], <2 x i32> [[TMP1]], <2 x i32> +; CHECK-NEXT: ret <2 x i32> [[D]] +; + %a = sub <2 x i32> , %x + %b = icmp sgt <2 x i32> %a, zeroinitializer + %c = select <2 x i1> %b, <2 x i32> %a, <2 x i32> zeroinitializer + %d = xor <2 x i32> %c, + ret <2 x i32> %d +} + +define i32 @test49(i32 %x) { +; CHECK-LABEL: @test49( +; CHECK-NEXT: [[TMP1:%.*]] = sub i32 1, [[X:%.*]] +; CHECK-NEXT: [[TMP2:%.*]] = icmp sgt i32 [[TMP1]], 0 +; CHECK-NEXT: [[D:%.*]] = select i1 [[TMP2]], i32 [[TMP1]], i32 0 +; CHECK-NEXT: ret i32 [[D]] +; + %a = add i32 %x, -2 + %b = icmp slt i32 %a, -1 + %c = select i1 %b, i32 %a, i32 -1 + %d = xor i32 %c, -1 + ret i32 %d +} + +define <2 x i32> @test49vec(<2 x i32> %x) { +; CHECK-LABEL: @test49vec( +; CHECK-NEXT: [[TMP1:%.*]] = sub <2 x i32> , [[X:%.*]] +; CHECK-NEXT: [[TMP2:%.*]] = icmp sgt <2 x i32> [[TMP1]], zeroinitializer +; CHECK-NEXT: [[D:%.*]] = select <2 x i1> [[TMP2]], <2 x i32> [[TMP1]], <2 x i32> zeroinitializer +; CHECK-NEXT: ret <2 x i32> [[D]] +; + %a = add <2 x i32> %x, + %b = icmp slt <2 x i32> %a, + %c = select <2 x i1> %b, <2 x i32> %a, <2 x i32> + %d = xor <2 x i32> %c, + ret <2 x i32> %d +} + +define i32 @test50(i32 %x, i32 %y) { +; CHECK-LABEL: @test50( +; CHECK-NEXT: [[TMP1:%.*]] = sub i32 1, [[X:%.*]] +; CHECK-NEXT: [[TMP2:%.*]] = add i32 [[Y:%.*]], 1 +; CHECK-NEXT: [[TMP3:%.*]] = icmp slt i32 [[TMP2]], [[TMP1]] +; CHECK-NEXT: [[E:%.*]] = select i1 [[TMP3]], i32 [[TMP1]], i32 [[TMP2]] +; CHECK-NEXT: ret i32 [[E]] +; + %a = add i32 %x, -2 + %b = sub i32 -2, %y + %c = icmp slt i32 %a, %b + %d = select i1 %c, i32 %a, i32 %b + %e = xor i32 %d, -1 + ret i32 %e +} + +define <2 x i32> @test50vec(<2 x i32> %x, <2 x i32> %y) { +; CHECK-LABEL: @test50vec( +; CHECK-NEXT: [[TMP1:%.*]] = sub <2 x i32> , [[X:%.*]] +; CHECK-NEXT: [[TMP2:%.*]] = add <2 x i32> [[Y:%.*]], +; CHECK-NEXT: [[TMP3:%.*]] = icmp slt <2 x i32> [[TMP2]], [[TMP1]] +; CHECK-NEXT: [[E:%.*]] = select <2 x i1> [[TMP3]], <2 x i32> [[TMP1]], <2 x i32> [[TMP2]] +; CHECK-NEXT: ret <2 x i32> [[E]] +; + %a = add <2 x i32> %x, + %b = sub <2 x i32> , %y + %c = icmp slt <2 x i32> %a, %b + %d = select <2 x i1> %c, <2 x i32> %a, <2 x i32> %b + %e = xor <2 x i32> %d, + ret <2 x i32> %e +} + +define i32 @test51(i32 %x, i32 %y) { +; CHECK-LABEL: @test51( +; CHECK-NEXT: [[TMP1:%.*]] = sub i32 -3, [[X:%.*]] +; CHECK-NEXT: [[TMP2:%.*]] = add i32 [[Y:%.*]], -3 +; CHECK-NEXT: [[TMP3:%.*]] = icmp sgt i32 [[TMP2]], [[TMP1]] +; CHECK-NEXT: [[E:%.*]] = select i1 [[TMP3]], i32 [[TMP1]], i32 [[TMP2]] +; CHECK-NEXT: ret i32 [[E]] +; + %a = add i32 %x, 2 + %b = sub i32 2, %y + %c = icmp sgt i32 %a, %b + %d = select i1 %c, i32 %a, i32 %b + %e = xor i32 %d, -1 + ret i32 %e +} + +define <2 x i32> @test51vec(<2 x i32> %x, <2 x i32> %y) { +; CHECK-LABEL: @test51vec( +; CHECK-NEXT: [[TMP1:%.*]] = sub <2 x i32> , [[X:%.*]] +; CHECK-NEXT: [[TMP2:%.*]] = add <2 x i32> [[Y:%.*]], +; CHECK-NEXT: [[TMP3:%.*]] = icmp sgt <2 x i32> [[TMP2]], [[TMP1]] +; CHECK-NEXT: [[E:%.*]] = select <2 x i1> [[TMP3]], <2 x i32> [[TMP1]], <2 x i32> [[TMP2]] +; CHECK-NEXT: ret <2 x i32> [[E]] +; + %a = add <2 x i32> %x, + %b = sub <2 x i32> , %y + %c = icmp sgt <2 x i32> %a, %b + %d = select <2 x i1> %c, <2 x i32> %a, <2 x i32> %b + %e = xor <2 x i32> %d, + ret <2 x i32> %e +}