Index: llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp +++ llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp @@ -3411,9 +3411,9 @@ NotVal); } - // Use DeMorgan and reassociation to eliminate a 'not' op. Constant *C1; if (match(Op1, m_Constant(C1))) { + // Use DeMorgan and reassociation to eliminate a 'not' op. Constant *C2; if (match(Op0, m_OneUse(m_Or(m_Not(m_Value(X)), m_Constant(C2))))) { // (~X | C2) ^ C1 --> ((X & ~C2) ^ -1) ^ C1 --> (X & ~C2) ^ ~C1 @@ -3425,6 +3425,20 @@ Value *Or = Builder.CreateOr(X, ConstantExpr::getNot(C2)); return BinaryOperator::CreateXor(Or, ConstantExpr::getNot(C1)); } + + // Convert xor ([trunc] (ashr X, BW-1)), C => + // select(X >s -1, C, ~C) + // The ashr creates "AllZeroOrAllOne's", which then optionally inverses the + // constant depending on whether this input is less than 0. + const APInt *CA; + if (match(Op0, m_TruncOrSelf(m_OneUse(m_AShr(m_Value(X), m_APInt(CA))))) && + *CA == X->getType()->getScalarSizeInBits() - 1 && + !C1->isAllOnesValue()) { + assert(!C1->isZeroValue() && "Unexpected xor with 0"); + Value *ICmp = + Builder.CreateICmpSGT(X, Constant::getAllOnesValue(X->getType())); + return SelectInst::Create(ICmp, Op1, Builder.CreateNot(Op1)); + } } // not (cmp A, B) = !cmp A, B Index: llvm/test/Transforms/InstCombine/truncating-saturate.ll =================================================================== --- llvm/test/Transforms/InstCombine/truncating-saturate.ll +++ llvm/test/Transforms/InstCombine/truncating-saturate.ll @@ -10,9 +10,8 @@ ; CHECK-NEXT: [[CONV1_I:%.*]] = trunc i16 [[ADD:%.*]] to i8 ; CHECK-NEXT: [[TMP1:%.*]] = add i16 [[ADD]], 128 ; CHECK-NEXT: [[CMP_NOT_I:%.*]] = icmp ult i16 [[TMP1]], 256 -; CHECK-NEXT: [[SHR4_I:%.*]] = ashr i16 [[ADD]], 15 -; CHECK-NEXT: [[CONV5_I:%.*]] = trunc i16 [[SHR4_I]] to i8 -; CHECK-NEXT: [[XOR_I:%.*]] = xor i8 [[CONV5_I]], 127 +; CHECK-NEXT: [[TMP2:%.*]] = icmp sgt i16 [[ADD]], -1 +; CHECK-NEXT: [[XOR_I:%.*]] = select i1 [[TMP2]], i8 127, i8 -128 ; CHECK-NEXT: [[COND_I:%.*]] = select i1 [[CMP_NOT_I]], i8 [[CONV1_I]], i8 [[XOR_I]] ; CHECK-NEXT: ret i8 [[COND_I]] ; @@ -33,9 +32,8 @@ ; CHECK-NEXT: [[CONV1_I:%.*]] = trunc i64 [[ADD:%.*]] to i32 ; CHECK-NEXT: [[TMP1:%.*]] = add i64 [[ADD]], 2147483648 ; CHECK-NEXT: [[CMP_NOT_I:%.*]] = icmp ult i64 [[TMP1]], 4294967296 -; CHECK-NEXT: [[SHR4_I:%.*]] = ashr i64 [[ADD]], 63 -; CHECK-NEXT: [[CONV5_I:%.*]] = trunc i64 [[SHR4_I]] to i32 -; CHECK-NEXT: [[XOR_I:%.*]] = xor i32 [[CONV5_I]], 2147483647 +; CHECK-NEXT: [[TMP2:%.*]] = icmp sgt i64 [[ADD]], -1 +; CHECK-NEXT: [[XOR_I:%.*]] = select i1 [[TMP2]], i32 2147483647, i32 -2147483648 ; CHECK-NEXT: [[COND_I:%.*]] = select i1 [[CMP_NOT_I]], i32 [[CONV1_I]], i32 [[XOR_I]] ; CHECK-NEXT: ret i32 [[COND_I]] ; @@ -59,9 +57,8 @@ ; CHECK-NEXT: [[CONV1_I:%.*]] = trunc i64 [[ADD]] to i32 ; CHECK-NEXT: [[TMP1:%.*]] = add nsw i64 [[ADD]], 2147483648 ; CHECK-NEXT: [[CMP_NOT_I:%.*]] = icmp ult i64 [[TMP1]], 4294967296 -; CHECK-NEXT: [[SHR4_I:%.*]] = ashr i64 [[ADD]], 63 -; CHECK-NEXT: [[CONV5_I:%.*]] = trunc i64 [[SHR4_I]] to i32 -; CHECK-NEXT: [[XOR_I:%.*]] = xor i32 [[CONV5_I]], 2147483647 +; CHECK-NEXT: [[TMP2:%.*]] = icmp sgt i64 [[ADD]], -1 +; CHECK-NEXT: [[XOR_I:%.*]] = select i1 [[TMP2]], i32 2147483647, i32 -2147483648 ; CHECK-NEXT: [[COND_I:%.*]] = select i1 [[CMP_NOT_I]], i32 [[CONV1_I]], i32 [[XOR_I]] ; CHECK-NEXT: ret i32 [[COND_I]] ; @@ -85,9 +82,8 @@ ; CHECK-NEXT: [[CONV1_I:%.*]] = trunc <4 x i16> [[ADD:%.*]] to <4 x i8> ; CHECK-NEXT: [[TMP1:%.*]] = add <4 x i16> [[ADD]], ; CHECK-NEXT: [[CMP_NOT_I:%.*]] = icmp ult <4 x i16> [[TMP1]], -; CHECK-NEXT: [[SHR4_I:%.*]] = ashr <4 x i16> [[ADD]], -; CHECK-NEXT: [[CONV5_I:%.*]] = trunc <4 x i16> [[SHR4_I]] to <4 x i8> -; CHECK-NEXT: [[XOR_I:%.*]] = xor <4 x i8> [[CONV5_I]], +; CHECK-NEXT: [[TMP2:%.*]] = icmp sgt <4 x i16> [[ADD]], +; CHECK-NEXT: [[XOR_I:%.*]] = select <4 x i1> [[TMP2]], <4 x i8> , <4 x i8> ; CHECK-NEXT: [[COND_I:%.*]] = select <4 x i1> [[CMP_NOT_I]], <4 x i8> [[CONV1_I]], <4 x i8> [[XOR_I]] ; CHECK-NEXT: ret <4 x i8> [[COND_I]] ; @@ -111,9 +107,8 @@ ; CHECK-NEXT: [[CONV1_I:%.*]] = trunc <4 x i16> [[ADD]] to <4 x i8> ; CHECK-NEXT: [[TMP1:%.*]] = add nsw <4 x i16> [[ADD]], ; CHECK-NEXT: [[CMP_NOT_I:%.*]] = icmp ult <4 x i16> [[TMP1]], -; CHECK-NEXT: [[SHR4_I:%.*]] = ashr <4 x i16> [[ADD]], -; CHECK-NEXT: [[CONV5_I:%.*]] = trunc <4 x i16> [[SHR4_I]] to <4 x i8> -; CHECK-NEXT: [[XOR_I:%.*]] = xor <4 x i8> [[CONV5_I]], +; CHECK-NEXT: [[TMP2:%.*]] = icmp sgt <4 x i16> [[ADD]], +; CHECK-NEXT: [[XOR_I:%.*]] = select <4 x i1> [[TMP2]], <4 x i8> , <4 x i8> ; CHECK-NEXT: [[COND_I:%.*]] = select <4 x i1> [[CMP_NOT_I]], <4 x i8> [[CONV1_I]], <4 x i8> [[XOR_I]] ; CHECK-NEXT: ret <4 x i8> [[COND_I]] ; @@ -137,9 +132,8 @@ ; CHECK-NEXT: [[CONV1_I:%.*]] = trunc i16 [[ADD:%.*]] to i8 ; CHECK-NEXT: [[TMP1:%.*]] = add i16 [[ADD]], 128 ; CHECK-NEXT: [[CMP_NOT_I:%.*]] = icmp ult i16 [[TMP1]], 256 -; CHECK-NEXT: [[SHR4_I:%.*]] = ashr i16 [[ADD]], 15 -; CHECK-NEXT: [[CONV5_I:%.*]] = trunc i16 [[SHR4_I]] to i8 -; CHECK-NEXT: [[XOR_I:%.*]] = xor i8 [[CONV5_I]], 127 +; CHECK-NEXT: [[TMP2:%.*]] = icmp sgt i16 [[ADD]], -1 +; CHECK-NEXT: [[XOR_I:%.*]] = select i1 [[TMP2]], i8 127, i8 -128 ; CHECK-NEXT: [[COND_I:%.*]] = select i1 [[CMP_NOT_I]], i8 [[CONV1_I]], i8 [[XOR_I]] ; CHECK-NEXT: ret i8 [[COND_I]] ; @@ -160,9 +154,8 @@ ; CHECK-NEXT: [[CONV1_I:%.*]] = trunc i16 [[ADD:%.*]] to i8 ; CHECK-NEXT: [[TMP1:%.*]] = add i16 [[ADD]], 128 ; CHECK-NEXT: [[CMP_NOT_I_NOT:%.*]] = icmp ult i16 [[TMP1]], 256 -; CHECK-NEXT: [[SHR4_I:%.*]] = ashr i16 [[ADD]], 15 -; CHECK-NEXT: [[CONV5_I:%.*]] = trunc i16 [[SHR4_I]] to i8 -; CHECK-NEXT: [[XOR_I:%.*]] = xor i8 [[CONV5_I]], 127 +; CHECK-NEXT: [[TMP2:%.*]] = icmp sgt i16 [[ADD]], -1 +; CHECK-NEXT: [[XOR_I:%.*]] = select i1 [[TMP2]], i8 127, i8 -128 ; CHECK-NEXT: [[COND_I:%.*]] = select i1 [[CMP_NOT_I_NOT]], i8 [[CONV1_I]], i8 [[XOR_I]] ; CHECK-NEXT: ret i8 [[COND_I]] ; @@ -212,9 +205,8 @@ ; CHECK-NEXT: [[CONV1_I:%.*]] = trunc i16 [[ADD]] to i8 ; CHECK-NEXT: [[SHR2_I:%.*]] = ashr i8 [[CONV1_I]], 7 ; CHECK-NEXT: [[CMP_NOT_I:%.*]] = icmp eq i8 [[SHR2_I]], [[CONV_I]] -; CHECK-NEXT: [[SHR4_I:%.*]] = ashr i16 [[ADD]], 15 -; CHECK-NEXT: [[CONV5_I:%.*]] = trunc i16 [[SHR4_I]] to i8 -; CHECK-NEXT: [[XOR_I:%.*]] = xor i8 [[CONV5_I]], 127 +; CHECK-NEXT: [[TMP1:%.*]] = icmp sgt i16 [[ADD]], -1 +; CHECK-NEXT: [[XOR_I:%.*]] = select i1 [[TMP1]], i8 127, i8 -128 ; CHECK-NEXT: [[COND_I:%.*]] = select i1 [[CMP_NOT_I]], i8 [[CONV1_I]], i8 [[XOR_I]] ; CHECK-NEXT: ret i8 [[COND_I]] ; @@ -237,9 +229,8 @@ ; CHECK-NEXT: [[CONV1_I:%.*]] = trunc i16 [[ADD]] to i8 ; CHECK-NEXT: [[SHR2_I:%.*]] = ashr i8 [[CONV1_I]], 6 ; CHECK-NEXT: [[CMP_NOT_I:%.*]] = icmp eq i8 [[SHR2_I]], [[CONV_I]] -; CHECK-NEXT: [[SHR4_I:%.*]] = ashr i16 [[ADD]], 15 -; CHECK-NEXT: [[CONV5_I:%.*]] = trunc i16 [[SHR4_I]] to i8 -; CHECK-NEXT: [[XOR_I:%.*]] = xor i8 [[CONV5_I]], 127 +; CHECK-NEXT: [[TMP1:%.*]] = icmp sgt i16 [[ADD]], -1 +; CHECK-NEXT: [[XOR_I:%.*]] = select i1 [[TMP1]], i8 127, i8 -128 ; CHECK-NEXT: [[COND_I:%.*]] = select i1 [[CMP_NOT_I]], i8 [[CONV1_I]], i8 [[XOR_I]] ; CHECK-NEXT: ret i8 [[COND_I]] ; @@ -283,9 +274,8 @@ ; CHECK-NEXT: [[CONV1_I:%.*]] = trunc i16 [[ADD:%.*]] to i8 ; CHECK-NEXT: [[TMP1:%.*]] = add i16 [[ADD]], 128 ; CHECK-NEXT: [[CMP_NOT_I:%.*]] = icmp ult i16 [[TMP1]], 256 -; CHECK-NEXT: [[SHR4_I:%.*]] = ashr i16 [[ADD]], 15 -; CHECK-NEXT: [[CONV5_I:%.*]] = trunc i16 [[SHR4_I]] to i8 -; CHECK-NEXT: [[XOR_I:%.*]] = xor i8 [[CONV5_I]], 126 +; CHECK-NEXT: [[TMP2:%.*]] = icmp sgt i16 [[ADD]], -1 +; CHECK-NEXT: [[XOR_I:%.*]] = select i1 [[TMP2]], i8 126, i8 -127 ; CHECK-NEXT: [[COND_I:%.*]] = select i1 [[CMP_NOT_I]], i8 [[CONV1_I]], i8 [[XOR_I]] ; CHECK-NEXT: ret i8 [[COND_I]] ; @@ -308,9 +298,8 @@ ; CHECK-NEXT: [[CONV1_I:%.*]] = trunc i64 [[ADD:%.*]] to i32 ; CHECK-NEXT: [[TMP1:%.*]] = add i64 [[ADD]], 2147483648 ; CHECK-NEXT: [[CMP_NOT_I:%.*]] = icmp ult i64 [[TMP1]], 4294967296 -; CHECK-NEXT: [[SHR4_I:%.*]] = ashr i64 [[ADD]], 63 -; CHECK-NEXT: [[CONV5_I:%.*]] = trunc i64 [[SHR4_I]] to i32 -; CHECK-NEXT: [[XOR_I:%.*]] = xor i32 [[CONV5_I]], 2147483647 +; CHECK-NEXT: [[TMP2:%.*]] = icmp sgt i64 [[ADD]], -1 +; CHECK-NEXT: [[XOR_I:%.*]] = select i1 [[TMP2]], i32 2147483647, i32 -2147483648 ; CHECK-NEXT: [[COND_I:%.*]] = select i1 [[CMP_NOT_I]], i32 [[CONV1_I]], i32 [[XOR_I]] ; CHECK-NEXT: call void @use(i32 [[XOR_I]]) ; CHECK-NEXT: ret i32 [[COND_I]] @@ -333,9 +322,8 @@ ; CHECK-NEXT: [[CONV1_I:%.*]] = trunc i64 [[ADD:%.*]] to i32 ; CHECK-NEXT: [[TMP1:%.*]] = add i64 [[ADD]], 2147483648 ; CHECK-NEXT: [[CMP_NOT_I:%.*]] = icmp ult i64 [[TMP1]], 4294967296 -; CHECK-NEXT: [[SHR4_I:%.*]] = ashr i64 [[ADD]], 63 -; CHECK-NEXT: [[CONV5_I:%.*]] = trunc i64 [[SHR4_I]] to i32 -; CHECK-NEXT: [[XOR_I:%.*]] = xor i32 [[CONV5_I]], 2147483647 +; CHECK-NEXT: [[TMP2:%.*]] = icmp sgt i64 [[ADD]], -1 +; CHECK-NEXT: [[XOR_I:%.*]] = select i1 [[TMP2]], i32 2147483647, i32 -2147483648 ; CHECK-NEXT: [[COND_I:%.*]] = select i1 [[CMP_NOT_I]], i32 [[CONV1_I]], i32 [[XOR_I]] ; CHECK-NEXT: call void @use(i32 [[CONV1_I]]) ; CHECK-NEXT: ret i32 [[COND_I]] @@ -358,9 +346,8 @@ ; CHECK-NEXT: [[CONV1_I:%.*]] = trunc i64 [[ADD:%.*]] to i32 ; CHECK-NEXT: [[TMP1:%.*]] = add i64 [[ADD]], 2147483648 ; CHECK-NEXT: [[CMP_NOT_I:%.*]] = icmp ult i64 [[TMP1]], 4294967296 -; CHECK-NEXT: [[SHR4_I:%.*]] = ashr i64 [[ADD]], 63 -; CHECK-NEXT: [[CONV5_I:%.*]] = trunc i64 [[SHR4_I]] to i32 -; CHECK-NEXT: [[XOR_I:%.*]] = xor i32 [[CONV5_I]], 2147483647 +; CHECK-NEXT: [[TMP2:%.*]] = icmp sgt i64 [[ADD]], -1 +; CHECK-NEXT: [[XOR_I:%.*]] = select i1 [[TMP2]], i32 2147483647, i32 -2147483648 ; CHECK-NEXT: [[COND_I:%.*]] = select i1 [[CMP_NOT_I]], i32 [[CONV1_I]], i32 [[XOR_I]] ; CHECK-NEXT: call void @use1(i1 [[CMP_NOT_I]]) ; CHECK-NEXT: ret i32 [[COND_I]] @@ -383,9 +370,8 @@ ; CHECK-NEXT: [[CONV1_I:%.*]] = trunc i64 [[ADD:%.*]] to i32 ; CHECK-NEXT: [[TMP1:%.*]] = add i64 [[ADD]], 2147483648 ; CHECK-NEXT: [[CMP_NOT_I:%.*]] = icmp ult i64 [[TMP1]], 4294967296 -; CHECK-NEXT: [[SHR4_I:%.*]] = ashr i64 [[ADD]], 63 -; CHECK-NEXT: [[CONV5_I:%.*]] = trunc i64 [[SHR4_I]] to i32 -; CHECK-NEXT: [[XOR_I:%.*]] = xor i32 [[CONV5_I]], 2147483647 +; CHECK-NEXT: [[TMP2:%.*]] = icmp sgt i64 [[ADD]], -1 +; CHECK-NEXT: [[XOR_I:%.*]] = select i1 [[TMP2]], i32 2147483647, i32 -2147483648 ; CHECK-NEXT: [[COND_I:%.*]] = select i1 [[CMP_NOT_I]], i32 [[CONV1_I]], i32 [[XOR_I]] ; CHECK-NEXT: call void @use(i32 [[XOR_I]]) ; CHECK-NEXT: call void @use(i32 [[CONV1_I]]) @@ -410,9 +396,8 @@ ; CHECK-NEXT: [[CONV1_I:%.*]] = trunc i64 [[ADD:%.*]] to i32 ; CHECK-NEXT: [[TMP1:%.*]] = add i64 [[ADD]], 2147483648 ; CHECK-NEXT: [[CMP_NOT_I:%.*]] = icmp ult i64 [[TMP1]], 4294967296 -; CHECK-NEXT: [[SHR4_I:%.*]] = ashr i64 [[ADD]], 63 -; CHECK-NEXT: [[CONV5_I:%.*]] = trunc i64 [[SHR4_I]] to i32 -; CHECK-NEXT: [[XOR_I:%.*]] = xor i32 [[CONV5_I]], 2147483647 +; CHECK-NEXT: [[TMP2:%.*]] = icmp sgt i64 [[ADD]], -1 +; CHECK-NEXT: [[XOR_I:%.*]] = select i1 [[TMP2]], i32 2147483647, i32 -2147483648 ; CHECK-NEXT: [[COND_I:%.*]] = select i1 [[CMP_NOT_I]], i32 [[CONV1_I]], i32 [[XOR_I]] ; CHECK-NEXT: call void @use(i32 [[XOR_I]]) ; CHECK-NEXT: call void @use(i32 [[CONV1_I]]) Index: llvm/test/Transforms/InstCombine/xor-ashr.ll =================================================================== --- llvm/test/Transforms/InstCombine/xor-ashr.ll +++ llvm/test/Transforms/InstCombine/xor-ashr.ll @@ -7,8 +7,8 @@ define i8 @testi8i8(i8 %add) { ; CHECK-LABEL: @testi8i8( -; CHECK-NEXT: [[SH:%.*]] = ashr i8 [[ADD:%.*]], 7 -; CHECK-NEXT: [[X:%.*]] = xor i8 [[SH]], 127 +; CHECK-NEXT: [[TMP1:%.*]] = icmp sgt i8 [[ADD:%.*]], -1 +; CHECK-NEXT: [[X:%.*]] = select i1 [[TMP1]], i8 127, i8 -128 ; CHECK-NEXT: ret i8 [[X]] ; %sh = ashr i8 %add, 7 @@ -18,9 +18,8 @@ define i8 @testi16i8(i16 %add) { ; CHECK-LABEL: @testi16i8( -; CHECK-NEXT: [[SH:%.*]] = ashr i16 [[ADD:%.*]], 15 -; CHECK-NEXT: [[T:%.*]] = trunc i16 [[SH]] to i8 -; CHECK-NEXT: [[X:%.*]] = xor i8 [[T]], 27 +; CHECK-NEXT: [[TMP1:%.*]] = icmp sgt i16 [[ADD:%.*]], -1 +; CHECK-NEXT: [[X:%.*]] = select i1 [[TMP1]], i8 27, i8 -28 ; CHECK-NEXT: ret i8 [[X]] ; %sh = ashr i16 %add, 15 @@ -31,9 +30,8 @@ define i32 @testi64i32(i64 %add) { ; CHECK-LABEL: @testi64i32( -; CHECK-NEXT: [[SH:%.*]] = ashr i64 [[ADD:%.*]], 63 -; CHECK-NEXT: [[T:%.*]] = trunc i64 [[SH]] to i32 -; CHECK-NEXT: [[X:%.*]] = xor i32 [[T]], 127 +; CHECK-NEXT: [[TMP1:%.*]] = icmp sgt i64 [[ADD:%.*]], -1 +; CHECK-NEXT: [[X:%.*]] = select i1 [[TMP1]], i32 127, i32 -128 ; CHECK-NEXT: ret i32 [[X]] ; %sh = ashr i64 %add, 63 @@ -44,8 +42,8 @@ define i128 @testi128i128(i128 %add) { ; CHECK-LABEL: @testi128i128( -; CHECK-NEXT: [[SH:%.*]] = ashr i128 [[ADD:%.*]], 127 -; CHECK-NEXT: [[X:%.*]] = xor i128 [[SH]], 27 +; CHECK-NEXT: [[TMP1:%.*]] = icmp sgt i128 [[ADD:%.*]], -1 +; CHECK-NEXT: [[X:%.*]] = select i1 [[TMP1]], i128 27, i128 -28 ; CHECK-NEXT: ret i128 [[X]] ; %sh = ashr i128 %add, 127