[llvm] [InstComb] Fold ashr (xor x, y), x -> ashr y, x (PR #165866)

Ramkumar Ramachandra via llvm-commits llvm-commits at lists.llvm.org
Fri Oct 31 07:17:51 PDT 2025


https://github.com/artagnon updated https://github.com/llvm/llvm-project/pull/165866

>From 433b8782bf793e51a66728e3bce85035c890acdf Mon Sep 17 00:00:00 2001
From: Ramkumar Ramachandra <ramkumar.ramachandra at codasip.com>
Date: Fri, 31 Oct 2025 13:57:42 +0000
Subject: [PATCH 1/2] [InstComb] Pre-commit ashr-xor test

---
 .../Transforms/InstCombine/shift-logic.ll     | 36 +++++++++++++++++++
 1 file changed, 36 insertions(+)

diff --git a/llvm/test/Transforms/InstCombine/shift-logic.ll b/llvm/test/Transforms/InstCombine/shift-logic.ll
index ab8d98a9523ba..27c5e66e56fa0 100644
--- a/llvm/test/Transforms/InstCombine/shift-logic.ll
+++ b/llvm/test/Transforms/InstCombine/shift-logic.ll
@@ -186,6 +186,7 @@ define i32 @ashr_xor(i32 %x, i32 %py) {
   ret i32 %sh1
 }
 
+
 define i32 @shr_mismatch_xor(i32 %x, i32 %y) {
 ; CHECK-LABEL: @shr_mismatch_xor(
 ; CHECK-NEXT:    [[SH0:%.*]] = ashr i32 [[X:%.*]], 5
@@ -225,6 +226,41 @@ define <2 x i32> @ashr_poison_poison_xor(<2 x i32> %x, <2 x i32> %y) {
   ret <2 x i32> %sh1
 }
 
+define i32 @ashr_xor_operand_match(i32 %x, i32 %y) {
+; CHECK-LABEL: @ashr_xor_operand_match(
+; CHECK-NEXT:    [[SH1:%.*]] = xor i32 [[TMP1:%.*]], [[TMP2:%.*]]
+; CHECK-NEXT:    [[RET:%.*]] = ashr i32 [[SH1]], [[TMP1]]
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %r = xor i32 %x, %y
+  %ret = ashr i32 %r, %x
+  ret i32 %ret
+}
+
+define i32 @ashr_xor_operand_match_multiuse(i32 %x, i32 %y) {
+; CHECK-LABEL: @ashr_xor_operand_match_multiuse(
+; CHECK-NEXT:    [[R:%.*]] = xor i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[Q:%.*]] = ashr i32 [[R]], [[X]]
+; CHECK-NEXT:    [[RET:%.*]] = xor i32 [[R]], [[Q]]
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %r = xor i32 %x, %y
+  %q = ashr i32 %r, %x
+  %ret = xor i32 %r, %q
+  ret i32 %ret
+}
+
+define i32 @ashr_xor_operand_mismtach(i32 %x, i32 %y) {
+; CHECK-LABEL: @ashr_xor_operand_mismtach(
+; CHECK-NEXT:    [[R:%.*]] = xor i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[RET:%.*]] = ashr i32 [[R]], [[Y]]
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %r = xor i32 %x, %y
+  %ret = ashr i32 %r, %y
+  ret i32 %ret
+}
+
 define i32 @lshr_or_extra_use(i32 %x, i32 %y, ptr %p) {
 ; CHECK-LABEL: @lshr_or_extra_use(
 ; CHECK-NEXT:    [[SH0:%.*]] = lshr i32 [[X:%.*]], 5

>From 2964a53bf1fd610332be0f6f43b06f00ff277bc8 Mon Sep 17 00:00:00 2001
From: Ramkumar Ramachandra <ramkumar.ramachandra at codasip.com>
Date: Fri, 31 Oct 2025 13:59:20 +0000
Subject: [PATCH 2/2] [InstComb] Fold ashr (xor x, y), x -> ashr y, x

Proof: https://alive2.llvm.org/ce/z/yWCmMd

Co-authored-by: John Regehr <regehr at cs.utah.edu>
---
 llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp |  5 +++++
 llvm/test/Transforms/InstCombine/shift-logic.ll       | 11 +++++------
 2 files changed, 10 insertions(+), 6 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp b/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp
index 899a3c16554c9..6410a509a48af 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp
@@ -1836,6 +1836,11 @@ Instruction *InstCombinerImpl::visitAShr(BinaryOperator &I) {
     return Lshr;
   }
 
+  // ashr (xor %x, %y), %x --> ashr %y, %x
+  Value *Y;
+  if (match(Op0, m_Xor(m_Value(X), m_Value(Y))) && Op1 == X)
+    return BinaryOperator::CreateAShr(Y, X);
+
   // ashr (xor %x, -1), %y  -->  xor (ashr %x, %y), -1
   if (match(Op0, m_OneUse(m_Not(m_Value(X))))) {
     // Note that we must drop 'exact'-ness of the shift!
diff --git a/llvm/test/Transforms/InstCombine/shift-logic.ll b/llvm/test/Transforms/InstCombine/shift-logic.ll
index 27c5e66e56fa0..7954e2842f4bc 100644
--- a/llvm/test/Transforms/InstCombine/shift-logic.ll
+++ b/llvm/test/Transforms/InstCombine/shift-logic.ll
@@ -228,8 +228,7 @@ define <2 x i32> @ashr_poison_poison_xor(<2 x i32> %x, <2 x i32> %y) {
 
 define i32 @ashr_xor_operand_match(i32 %x, i32 %y) {
 ; CHECK-LABEL: @ashr_xor_operand_match(
-; CHECK-NEXT:    [[SH1:%.*]] = xor i32 [[TMP1:%.*]], [[TMP2:%.*]]
-; CHECK-NEXT:    [[RET:%.*]] = ashr i32 [[SH1]], [[TMP1]]
+; CHECK-NEXT:    [[RET:%.*]] = ashr i32 [[Y:%.*]], [[X:%.*]]
 ; CHECK-NEXT:    ret i32 [[RET]]
 ;
   %r = xor i32 %x, %y
@@ -239,10 +238,10 @@ define i32 @ashr_xor_operand_match(i32 %x, i32 %y) {
 
 define i32 @ashr_xor_operand_match_multiuse(i32 %x, i32 %y) {
 ; CHECK-LABEL: @ashr_xor_operand_match_multiuse(
-; CHECK-NEXT:    [[R:%.*]] = xor i32 [[X:%.*]], [[Y:%.*]]
-; CHECK-NEXT:    [[Q:%.*]] = ashr i32 [[R]], [[X]]
-; CHECK-NEXT:    [[RET:%.*]] = xor i32 [[R]], [[Q]]
-; CHECK-NEXT:    ret i32 [[RET]]
+; CHECK-NEXT:    [[Q:%.*]] = ashr i32 [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT:    [[RET:%.*]] = xor i32 [[Y]], [[Q]]
+; CHECK-NEXT:    [[RET1:%.*]] = xor i32 [[RET]], [[X]]
+; CHECK-NEXT:    ret i32 [[RET1]]
 ;
   %r = xor i32 %x, %y
   %q = ashr i32 %r, %x



More information about the llvm-commits mailing list