Index: lib/Transforms/InstCombine/InstCombineAndOrXor.cpp =================================================================== --- lib/Transforms/InstCombine/InstCombineAndOrXor.cpp +++ lib/Transforms/InstCombine/InstCombineAndOrXor.cpp @@ -2696,5 +2696,33 @@ return SelectInst::Create(Cmp, Builder.CreateNeg(A), A); } + // Perform canonicalization of the following min/max patterns: + // + // %Xor = xor i32 %V, -1 + // %Cmp = icmp sgt[slt/ugt/ult] i32 %Xor, C + // %Op0 = select i1 %Cmp, i32 %Xor, i32 C + // %res = xor i32 %Op0, -1 + // => + // %Cmp = icmp slt[sgt/ult/ugt] i32 %V, NewC + // %res = select i1 %Cmp, i32 %V, i32 NewC + // + // where NewC = -1 xor C. + { + const Value *LHS, *RHS; + SelectPatternFlavor SPF = matchSelectPattern(Op0, LHS, RHS).Flavor; + if (SelectPatternResult::isMinOrMax(SPF) && match(Op1, m_AllOnes())) { + const APInt *C; + Value *V; + if (match(LHS, m_Xor(m_Value(V), m_AllOnes())) && + match(RHS, m_APInt(C))) { + APInt FlippedC = APInt::getAllOnesValue(C->getBitWidth()); + FlippedC ^= *C; + Constant *NewC = ConstantInt::get(V->getType(), FlippedC); + Value *Cmp = Builder.CreateICmp(getInverseMinMaxPred(SPF), V, NewC); + return SelectInst::Create(Cmp, V, NewC); + } + } + } + return Changed ? &I : nullptr; } Index: test/Transforms/InstCombine/xor.ll =================================================================== --- test/Transforms/InstCombine/xor.ll +++ test/Transforms/InstCombine/xor.ll @@ -575,3 +575,85 @@ %xor = xor i32 %and, %B ret i32 %xor } + +; The following 5 tests are related to the canonicalization: +; https://rise4fun.com/Alive/8jH + +define i32 @test39(i32 %x) { +; CHECK-LABEL: @test39( +; CHECK-NEXT: [[TMP1:%.*]] = icmp slt i32 [[X:%.*]], 255 +; CHECK-NEXT: [[RES:%.*]] = select i1 [[TMP1]], i32 [[X]], i32 255 +; CHECK-NEXT: ret i32 [[RES]] +; + %1 = xor i32 %x, -1 + %2 = icmp sgt i32 %1, -256 + %3 = select i1 %2, i32 %1, i32 -256 + %res = xor i32 %3, -1 + ret i32 %res +} + +define i32 @test40(i32 %x) { +; CHECK-LABEL: @test40( +; CHECK-NEXT: [[TMP1:%.*]] = icmp sgt i32 [[X:%.*]], 255 +; CHECK-NEXT: [[RES:%.*]] = select i1 [[TMP1]], i32 [[X]], i32 255 +; CHECK-NEXT: ret i32 [[RES]] +; + %1 = xor i32 %x, -1 + %2 = icmp slt i32 %1, -256 + %3 = select i1 %2, i32 %1, i32 -256 + %res = xor i32 %3, -1 + ret i32 %res +} + +define i32 @test41(i32 %x) { +; CHECK-LABEL: @test41( +; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i32 [[X:%.*]], 255 +; CHECK-NEXT: [[RES:%.*]] = select i1 [[TMP1]], i32 [[X]], i32 255 +; CHECK-NEXT: ret i32 [[RES]] +; + %1 = xor i32 %x, -1 + %2 = icmp ugt i32 %1, -256 + %3 = select i1 %2, i32 %1, i32 -256 + %res = xor i32 %3, -1 + ret i32 %res +} + +define i32 @test42(i32 %x) { +; CHECK-LABEL: @test42( +; CHECK-NEXT: [[TMP1:%.*]] = icmp ugt i32 [[X:%.*]], 255 +; CHECK-NEXT: [[RES:%.*]] = select i1 [[TMP1]], i32 [[X]], i32 255 +; CHECK-NEXT: ret i32 [[RES]] +; + %1 = xor i32 %x, -1 + %2 = icmp ult i32 %1, -256 + %3 = select i1 %2, i32 %1, i32 -256 + %res = xor i32 %3, -1 + ret i32 %res +} + +define i8 @test43(i8 %x) { +; CHECK-LABEL: @test43( +; CHECK-NEXT: [[TMP1:%.*]] = icmp ugt i8 [[X:%.*]], 85 +; CHECK-NEXT: [[RES:%.*]] = select i1 [[TMP1]], i8 [[X]], i8 85 +; CHECK-NEXT: ret i8 [[RES]] +; + %1 = xor i8 %x, -1 + %2 = icmp ult i8 %1, 170 + %3 = select i1 %2, i8 %1, i8 170 + %res = xor i8 %3, -1 + ret i8 %res +} + +; Check that we work with splat vectors also. +define <4 x i32> @test44(<4 x i32> %x) { +; CHECK-LABEL: @test44( +; CHECK-NEXT: [[TMP1:%.*]] = icmp slt <4 x i32> [[X:%.*]], +; CHECK-NEXT: [[TMP2:%.*]] = select <4 x i1> [[TMP1]], <4 x i32> [[X]], <4 x i32> +; CHECK-NEXT: ret <4 x i32> [[TMP2]] +; + %1 = xor <4 x i32> %x, + %2 = icmp sgt <4 x i32> %1, + %3 = select <4 x i1> %2, <4 x i32> %1, <4 x i32> + %4 = xor <4 x i32> %3, + ret <4 x i32> %4 +}