diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp index 6002f599ca71a..31db1d3164b77 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp @@ -4280,6 +4280,12 @@ Instruction *InstCombinerImpl::foldNot(BinaryOperator &I) { if (match(NotVal, m_AShr(m_Not(m_Value(X)), m_Value(Y)))) return BinaryOperator::CreateAShr(X, Y); + // Treat lshr with non-negative operand as ashr. + // ~(~X >>u Y) --> (X >>s Y) iff X is known negative + if (match(NotVal, m_LShr(m_Not(m_Value(X)), m_Value(Y))) && + isKnownNegative(X, SQ.getWithInstruction(NotVal))) + return BinaryOperator::CreateAShr(X, Y); + // Bit-hack form of a signbit test for iN type: // ~(X >>s (N - 1)) --> sext i1 (X > -1) to iN unsigned FullShift = Ty->getScalarSizeInBits() - 1; diff --git a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp index ba40ee7693636..6ac1fdb9252bf 100644 --- a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp +++ b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp @@ -2190,16 +2190,6 @@ Value *InstCombiner::getFreelyInvertedImpl(Value *V, bool WillInvertAllUses, return nullptr; } - // Treat lshr with non-negative operand as ashr. - if (match(V, m_LShr(m_Value(A), m_Value(B))) && - isKnownNonNegative(A, SQ.getWithInstruction(cast(V)), - Depth)) { - if (auto *AV = getFreelyInvertedImpl(A, A->hasOneUse(), Builder, - DoesConsume, Depth)) - return Builder ? Builder->CreateAShr(AV, B) : NonNull; - return nullptr; - } - Value *Cond; // LogicOps are special in that we canonicalize them at the cost of an // instruction. diff --git a/llvm/test/Transforms/InstCombine/pr75369.ll b/llvm/test/Transforms/InstCombine/pr75369.ll new file mode 100644 index 0000000000000..2f90753504b36 --- /dev/null +++ b/llvm/test/Transforms/InstCombine/pr75369.ll @@ -0,0 +1,36 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 4 +; RUN: opt -passes=instcombine -S < %s | FileCheck %s + +define i32 @main(ptr %a, i8 %a0, i32 %conv, i8 %a1) { +; CHECK-LABEL: define i32 @main( +; CHECK-SAME: ptr [[A:%.*]], i8 [[A0:%.*]], i32 [[CONV:%.*]], i8 [[A1:%.*]]) { +; CHECK-NEXT: [[A3:%.*]] = trunc i32 [[CONV]] to i8 +; CHECK-NEXT: [[OR11:%.*]] = or i8 [[A3]], [[A0]] +; CHECK-NEXT: store i8 [[OR11]], ptr [[A]], align 1 +; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[A1]], 0 +; CHECK-NEXT: call void @llvm.assume(i1 [[CMP]]) +; CHECK-NEXT: ret i32 [[CONV]] +; + %conv1 = sext i8 %a1 to i32 + %a2 = xor i32 %conv, 1 + %or = or i32 %conv1, %conv + %not = xor i32 %or, -1 + %shr = lshr i32 %not, 1 + %add.neg3 = sub i32 %a2, %shr + %conv24 = trunc i32 %add.neg3 to i8 + store i8 %conv24, ptr %a, align 1 + %sext = shl i32 %conv, 0 + %conv3 = ashr i32 %sext, 0 + %a3 = trunc i32 %conv to i8 + %conv5 = or i8 %a3, 0 + %xor6 = xor i8 %conv5, 0 + %xor816 = xor i8 %a0, 0 + %a4 = xor i8 %xor816, 0 + %or11 = or i8 %xor6, %a4 + store i8 %or11, ptr %a, align 1 + %cmp = icmp slt i8 %a1, 0 + call void @llvm.assume(i1 %cmp) + ret i32 %conv3 +} + +declare void @llvm.assume(i1)