Skip to content

Conversation

@artagnon
Copy link
Contributor

@artagnon artagnon commented Oct 31, 2025

@artagnon artagnon requested review from dtcxzyw and regehr October 31, 2025 14:04
@artagnon artagnon requested a review from nikic as a code owner October 31, 2025 14:04
@llvmbot llvmbot added llvm:instcombine Covers the InstCombine, InstSimplify and AggressiveInstCombine passes llvm:transforms labels Oct 31, 2025
@llvmbot
Copy link
Member

llvmbot commented Oct 31, 2025

@llvm/pr-subscribers-llvm-transforms

Author: Ramkumar Ramachandra (artagnon)

Changes

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


Full diff: https://github.com/llvm/llvm-project/pull/165866.diff

2 Files Affected:

  • (modified) llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp (+5)
  • (modified) llvm/test/Transforms/InstCombine/shift-logic.ll (+22)
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 ab8d98a9523ba..2de2073a183b7 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,27 @@ 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:    [[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_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

Copy link
Member

@dtcxzyw dtcxzyw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't like to special handle this case. It works because the number of active bits of x is never greater than x itself: https://alive2.llvm.org/ce/z/sYnoVM
All the patterns like [la]shr (bitop x, y), x can be simplified.

@artagnon artagnon changed the title [InstComb] Fold ashr (xor x, y), x -> ashr y, x [InstComb] Fold shr ([x]or x, y), x -> shr y, x Oct 31, 2025
Proof: https://alive2.llvm.org/ce/z/yWCmMd

Co-authored-by: John Regehr <regehr@cs.utah.edu>
@artagnon
Copy link
Contributor Author

All the patterns like [la]shr (bitop x, y), x can be simplified.

Thanks, this is a good generalization! However, it doesn't work for and: https://alive2.llvm.org/ce/z/vE3MEi

@artagnon
Copy link
Contributor Author

Looks like this pattern doesn't appear in the wild? Zero diff on llvm-opt-benchmark? Can someone confirm that there wasn't some error so we can close this?

@dtcxzyw
Copy link
Member

dtcxzyw commented Nov 1, 2025

Looks like this pattern doesn't appear in the wild? Zero diff on llvm-opt-benchmark?

Confirmed. Does this pattern come from a real-world issue?

@artagnon
Copy link
Contributor Author

artagnon commented Nov 1, 2025

Looks like this pattern doesn't appear in the wild? Zero diff on llvm-opt-benchmark?

Confirmed. Does this pattern come from a real-world issue?

No, unfortunately it comes from a SuperOptimizer.

@artagnon artagnon closed this Nov 1, 2025
@artagnon artagnon deleted the ic-ashr-xor branch November 1, 2025 09:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

llvm:instcombine Covers the InstCombine, InstSimplify and AggressiveInstCombine passes llvm:transforms

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants