Index: llvm/trunk/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp =================================================================== --- llvm/trunk/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp +++ llvm/trunk/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: llvm/trunk/lib/Transforms/InstCombine/InstCombineSelect.cpp =================================================================== --- llvm/trunk/lib/Transforms/InstCombine/InstCombineSelect.cpp +++ llvm/trunk/lib/Transforms/InstCombine/InstCombineSelect.cpp @@ -1847,6 +1847,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: llvm/trunk/test/Transforms/InstCombine/pr38915.ll =================================================================== --- llvm/trunk/test/Transforms/InstCombine/pr38915.ll +++ llvm/trunk/test/Transforms/InstCombine/pr38915.ll @@ -0,0 +1,24 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt %s -instcombine -S | FileCheck %s + +define i32 @PR38915(i32 %x, i32 %y, i32 %z) { +; CHECK-LABEL: @PR38915( +; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[X:%.*]], -1 +; CHECK-NEXT: [[TMP2:%.*]] = add i32 [[Y:%.*]], -1 +; CHECK-NEXT: [[TMP3:%.*]] = icmp sgt i32 [[TMP2]], [[TMP1]] +; CHECK-NEXT: [[M1N:%.*]] = select i1 [[TMP3]], i32 [[TMP1]], i32 [[TMP2]] +; CHECK-NEXT: [[C2:%.*]] = icmp sgt i32 [[M1N]], [[Z:%.*]] +; CHECK-NEXT: [[M2:%.*]] = select i1 [[C2]], i32 [[M1N]], i32 [[Z]] +; CHECK-NEXT: [[M2N:%.*]] = xor i32 [[M2]], -1 +; CHECK-NEXT: ret i32 [[M2N]] +; + %xn = sub i32 0, %x + %yn = sub i32 0, %y + %c1 = icmp sgt i32 %xn, %yn + %m1 = select i1 %c1, i32 %xn, i32 %yn + %m1n = xor i32 %m1, -1 + %c2 = icmp sgt i32 %m1n, %z + %m2 = select i1 %c2, i32 %m1n, i32 %z + %m2n = xor i32 %m2, -1 + ret i32 %m2n +} Index: llvm/trunk/test/Transforms/InstCombine/xor.ll =================================================================== --- llvm/trunk/test/Transforms/InstCombine/xor.ll +++ llvm/trunk/test/Transforms/InstCombine/xor.ll @@ -805,10 +805,9 @@ define i32 @test48(i32 %x) { ; CHECK-LABEL: @test48( -; CHECK-NEXT: [[A:%.*]] = sub i32 -2, [[X:%.*]] -; CHECK-NEXT: [[B:%.*]] = icmp sgt i32 [[A]], 0 -; CHECK-NEXT: [[C:%.*]] = select i1 [[B]], i32 [[A]], i32 0 -; CHECK-NEXT: [[D:%.*]] = xor i32 [[C]], -1 +; 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 @@ -820,10 +819,9 @@ define <2 x i32> @test48vec(<2 x i32> %x) { ; CHECK-LABEL: @test48vec( -; CHECK-NEXT: [[A:%.*]] = sub <2 x i32> , [[X:%.*]] -; CHECK-NEXT: [[B:%.*]] = icmp sgt <2 x i32> [[A]], zeroinitializer -; CHECK-NEXT: [[C:%.*]] = select <2 x i1> [[B]], <2 x i32> [[A]], <2 x i32> zeroinitializer -; CHECK-NEXT: [[D:%.*]] = xor <2 x i32> [[C]], +; 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 @@ -835,10 +833,9 @@ define i32 @test49(i32 %x) { ; CHECK-LABEL: @test49( -; CHECK-NEXT: [[A:%.*]] = add i32 [[X:%.*]], -2 -; CHECK-NEXT: [[B:%.*]] = icmp slt i32 [[A]], -1 -; CHECK-NEXT: [[C:%.*]] = select i1 [[B]], i32 [[A]], i32 -1 -; CHECK-NEXT: [[D:%.*]] = xor i32 [[C]], -1 +; 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 @@ -850,10 +847,9 @@ define <2 x i32> @test49vec(<2 x i32> %x) { ; CHECK-LABEL: @test49vec( -; CHECK-NEXT: [[A:%.*]] = add <2 x i32> [[X:%.*]], -; CHECK-NEXT: [[B:%.*]] = icmp slt <2 x i32> [[A]], -; CHECK-NEXT: [[C:%.*]] = select <2 x i1> [[B]], <2 x i32> [[A]], <2 x i32> -; CHECK-NEXT: [[D:%.*]] = xor <2 x i32> [[C]], +; 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, @@ -865,11 +861,10 @@ define i32 @test50(i32 %x, i32 %y) { ; CHECK-LABEL: @test50( -; CHECK-NEXT: [[A:%.*]] = add i32 [[X:%.*]], -2 -; CHECK-NEXT: [[B:%.*]] = sub i32 -2, [[Y:%.*]] -; CHECK-NEXT: [[C:%.*]] = icmp slt i32 [[A]], [[B]] -; CHECK-NEXT: [[D:%.*]] = select i1 [[C]], i32 [[A]], i32 [[B]] -; CHECK-NEXT: [[E:%.*]] = xor i32 [[D]], -1 +; 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 @@ -882,11 +877,10 @@ define <2 x i32> @test50vec(<2 x i32> %x, <2 x i32> %y) { ; CHECK-LABEL: @test50vec( -; CHECK-NEXT: [[A:%.*]] = add <2 x i32> [[X:%.*]], -; CHECK-NEXT: [[B:%.*]] = sub <2 x i32> , [[Y:%.*]] -; CHECK-NEXT: [[C:%.*]] = icmp slt <2 x i32> [[A]], [[B]] -; CHECK-NEXT: [[D:%.*]] = select <2 x i1> [[C]], <2 x i32> [[A]], <2 x i32> [[B]] -; CHECK-NEXT: [[E:%.*]] = xor <2 x i32> [[D]], +; 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, @@ -899,11 +893,10 @@ define i32 @test51(i32 %x, i32 %y) { ; CHECK-LABEL: @test51( -; CHECK-NEXT: [[A:%.*]] = add i32 [[X:%.*]], 2 -; CHECK-NEXT: [[B:%.*]] = sub i32 2, [[Y:%.*]] -; CHECK-NEXT: [[C:%.*]] = icmp sgt i32 [[A]], [[B]] -; CHECK-NEXT: [[D:%.*]] = select i1 [[C]], i32 [[A]], i32 [[B]] -; CHECK-NEXT: [[E:%.*]] = xor i32 [[D]], -1 +; 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 @@ -916,11 +909,10 @@ define <2 x i32> @test51vec(<2 x i32> %x, <2 x i32> %y) { ; CHECK-LABEL: @test51vec( -; CHECK-NEXT: [[A:%.*]] = add <2 x i32> [[X:%.*]], -; CHECK-NEXT: [[B:%.*]] = sub <2 x i32> , [[Y:%.*]] -; CHECK-NEXT: [[C:%.*]] = icmp sgt <2 x i32> [[A]], [[B]] -; CHECK-NEXT: [[D:%.*]] = select <2 x i1> [[C]], <2 x i32> [[A]], <2 x i32> [[B]] -; CHECK-NEXT: [[E:%.*]] = xor <2 x i32> [[D]], +; 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,