From 641ae741bc73642dfaf774c48aa8d4ec936be0d4 Mon Sep 17 00:00:00 2001 From: Rose Date: Thu, 17 Jul 2025 12:52:53 -0400 Subject: [PATCH 1/2] Pre-commit test (NFC) --- llvm/test/Transforms/InstCombine/not.ll | 28 +++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/llvm/test/Transforms/InstCombine/not.ll b/llvm/test/Transforms/InstCombine/not.ll index d693b9d8f8557..82fb94b6928e9 100644 --- a/llvm/test/Transforms/InstCombine/not.ll +++ b/llvm/test/Transforms/InstCombine/not.ll @@ -436,6 +436,34 @@ define <3 x i5> @not_or_neg_commute_vec(<3 x i5> %x, <3 x i5> %p) { ret <3 x i5> %not } +define i8 @not_or_neg_nsw(i8 %x, i8 %y) { +; CHECK-LABEL: @not_or_neg_nsw( +; CHECK-NEXT: [[TMP1:%.*]] = add i8 [[Y:%.*]], -1 +; CHECK-NEXT: [[TMP2:%.*]] = xor i8 [[X:%.*]], -1 +; CHECK-NEXT: [[NOT:%.*]] = and i8 [[TMP1]], [[TMP2]] +; CHECK-NEXT: ret i8 [[NOT]] +; + %s = sub nsw i8 0, %y + %o = or i8 %s, %x + %not = xor i8 %o, -1 + ret i8 %not +} + +define <3 x i5> @not_or_neg_commute_vec_nsw(<3 x i5> %x, <3 x i5> %p) { +; CHECK-LABEL: @not_or_neg_commute_vec_nsw( +; CHECK-NEXT: [[Y:%.*]] = mul <3 x i5> [[P:%.*]], +; CHECK-NEXT: [[TMP1:%.*]] = add <3 x i5> [[X:%.*]], splat (i5 -1) +; CHECK-NEXT: [[TMP2:%.*]] = xor <3 x i5> [[Y]], splat (i5 -1) +; CHECK-NEXT: [[NOT:%.*]] = and <3 x i5> [[TMP1]], [[TMP2]] +; CHECK-NEXT: ret <3 x i5> [[NOT]] +; + %y = mul <3 x i5> %p, ; thwart complexity-based-canonicalization + %s = sub nsw <3 x i5> , %x + %o = or <3 x i5> %y, %s + %not = xor <3 x i5> %o, + ret <3 x i5> %not +} + ; negative test define i8 @not_or_neg_use1(i8 %x, i8 %y) { From a8e39c230472d98387b54f16e4915b0caefc2f73 Mon Sep 17 00:00:00 2001 From: Rose Date: Thu, 17 Jul 2025 12:51:23 -0400 Subject: [PATCH 2/2] Propagate NSW in ~((-X) | Y) --> (X - 1) & (~Y) https://alive2.llvm.org/ce/z/qojyPF If -X is nsw, then X - 1 must be too. This is because -X can only be nsw if X is any number that is not INT_MIN. And if X is not INT_MIN, then X - 1 must be nsw. --- .../Transforms/InstCombine/InstCombineAndOrXor.cpp | 14 ++++++++++++++ llvm/test/Transforms/InstCombine/not.ll | 4 ++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp index 3beda6bc5ba38..18fa95dfa1497 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp @@ -4750,8 +4750,22 @@ Instruction *InstCombinerImpl::foldNot(BinaryOperator &I) { BinaryOperator *NotVal; if (match(NotOp, m_BinOp(NotVal))) { // ~((-X) | Y) --> (X - 1) & (~Y) + if (match(NotVal, + m_OneUse(m_c_Or(m_OneUse(m_NSWNeg(m_Value(X))), m_Value(Y))))) { + // If -X is nsw, then X - 1 must be too. + // This is because -X can only be nsw if X is any number that is not + // INT_MIN. And if X is not INT_MIN, then X - 1 must be nsw. + Value *DecX = Builder.CreateAdd(X, ConstantInt::getAllOnesValue(Ty), "", + /*HasNUW=*/false, /*HasNSW=*/true); + Value *NotY = Builder.CreateNot(Y); + return BinaryOperator::CreateAnd(DecX, NotY); + } + if (match(NotVal, m_OneUse(m_c_Or(m_OneUse(m_Neg(m_Value(X))), m_Value(Y))))) { + // If -X is nsw, then X - 1 must be too. + // This is because -X can only be nsw if X is any number that is not + // INT_MIN. And if X is not INT_MIN, then X - 1 must be nsw. Value *DecX = Builder.CreateAdd(X, ConstantInt::getAllOnesValue(Ty)); Value *NotY = Builder.CreateNot(Y); return BinaryOperator::CreateAnd(DecX, NotY); diff --git a/llvm/test/Transforms/InstCombine/not.ll b/llvm/test/Transforms/InstCombine/not.ll index 82fb94b6928e9..9de46c290b363 100644 --- a/llvm/test/Transforms/InstCombine/not.ll +++ b/llvm/test/Transforms/InstCombine/not.ll @@ -438,7 +438,7 @@ define <3 x i5> @not_or_neg_commute_vec(<3 x i5> %x, <3 x i5> %p) { define i8 @not_or_neg_nsw(i8 %x, i8 %y) { ; CHECK-LABEL: @not_or_neg_nsw( -; CHECK-NEXT: [[TMP1:%.*]] = add i8 [[Y:%.*]], -1 +; CHECK-NEXT: [[TMP1:%.*]] = add nsw i8 [[Y:%.*]], -1 ; CHECK-NEXT: [[TMP2:%.*]] = xor i8 [[X:%.*]], -1 ; CHECK-NEXT: [[NOT:%.*]] = and i8 [[TMP1]], [[TMP2]] ; CHECK-NEXT: ret i8 [[NOT]] @@ -452,7 +452,7 @@ define i8 @not_or_neg_nsw(i8 %x, i8 %y) { define <3 x i5> @not_or_neg_commute_vec_nsw(<3 x i5> %x, <3 x i5> %p) { ; CHECK-LABEL: @not_or_neg_commute_vec_nsw( ; CHECK-NEXT: [[Y:%.*]] = mul <3 x i5> [[P:%.*]], -; CHECK-NEXT: [[TMP1:%.*]] = add <3 x i5> [[X:%.*]], splat (i5 -1) +; CHECK-NEXT: [[TMP1:%.*]] = add nsw <3 x i5> [[X:%.*]], splat (i5 -1) ; CHECK-NEXT: [[TMP2:%.*]] = xor <3 x i5> [[Y]], splat (i5 -1) ; CHECK-NEXT: [[NOT:%.*]] = and <3 x i5> [[TMP1]], [[TMP2]] ; CHECK-NEXT: ret <3 x i5> [[NOT]]