[llvm] [InstComb] Fold shr ([x]or x, y), x -> shr y, x (PR #165866)
Ramkumar Ramachandra via llvm-commits
llvm-commits at lists.llvm.org
Fri Oct 31 08:40:38 PDT 2025
https://github.com/artagnon updated https://github.com/llvm/llvm-project/pull/165866
>From abb1953b82b6319b9a5d166c5896ec64ff971c2e 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 (l|a)shr-[x]or test
---
.../Transforms/InstCombine/shift-logic.ll | 102 ++++++++++++++++++
1 file changed, 102 insertions(+)
diff --git a/llvm/test/Transforms/InstCombine/shift-logic.ll b/llvm/test/Transforms/InstCombine/shift-logic.ll
index ab8d98a9523ba..5cb24b37684fc 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
@@ -546,3 +547,104 @@ define <2 x i64> @lshr_sub_poison(<2 x i64> %x, <2 x i64> %py) {
%sh1 = lshr <2 x i64> %r, <i64 7, i64 poison>
ret <2 x i64> %sh1
}
+
+define i32 @ashr_xor_operand_match(i32 %x, i32 %y) {
+; CHECK-LABEL: @ashr_xor_operand_match(
+; CHECK-NEXT: [[R:%.*]] = xor i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT: [[RET:%.*]] = ashr i32 [[R]], [[X]]
+; 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_xor_operand_match(i32 %x, i32 %y) {
+; CHECK-LABEL: @lshr_xor_operand_match(
+; CHECK-NEXT: [[R:%.*]] = xor i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT: [[RET:%.*]] = lshr i32 [[R]], [[X]]
+; CHECK-NEXT: ret i32 [[RET]]
+;
+ %r = xor i32 %x, %y
+ %ret = lshr i32 %r, %x
+ ret i32 %ret
+}
+
+define i32 @lshr_xor_operand_mismtach(i32 %x, i32 %y) {
+; CHECK-LABEL: @lshr_xor_operand_mismtach(
+; CHECK-NEXT: [[R:%.*]] = xor i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT: [[RET:%.*]] = lshr i32 [[R]], [[Y]]
+; CHECK-NEXT: ret i32 [[RET]]
+;
+ %r = xor i32 %x, %y
+ %ret = lshr i32 %r, %y
+ ret i32 %ret
+}
+
+define i32 @ashr_or_operand_match(i32 %x, i32 %y) {
+; CHECK-LABEL: @ashr_or_operand_match(
+; CHECK-NEXT: [[R:%.*]] = or i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT: [[RET:%.*]] = ashr i32 [[R]], [[X]]
+; CHECK-NEXT: ret i32 [[RET]]
+;
+ %r = or i32 %x, %y
+ %ret = ashr i32 %r, %x
+ ret i32 %ret
+}
+
+define i32 @ashr_or_operand_mismtach(i32 %x, i32 %y) {
+; CHECK-LABEL: @ashr_or_operand_mismtach(
+; CHECK-NEXT: [[R:%.*]] = or i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT: [[RET:%.*]] = ashr i32 [[R]], [[Y]]
+; CHECK-NEXT: ret i32 [[RET]]
+;
+ %r = or i32 %x, %y
+ %ret = ashr i32 %r, %y
+ ret i32 %ret
+}
+
+define i32 @lshr_or_operand_match(i32 %x, i32 %y) {
+; CHECK-LABEL: @lshr_or_operand_match(
+; CHECK-NEXT: [[R:%.*]] = or i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT: [[RET:%.*]] = lshr i32 [[R]], [[X]]
+; CHECK-NEXT: ret i32 [[RET]]
+;
+ %r = or i32 %x, %y
+ %ret = lshr i32 %r, %x
+ ret i32 %ret
+}
+
+define i32 @lshr_or_operand_mismtach(i32 %x, i32 %y) {
+; CHECK-LABEL: @lshr_or_operand_mismtach(
+; CHECK-NEXT: [[R:%.*]] = or i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT: [[RET:%.*]] = lshr i32 [[R]], [[Y]]
+; CHECK-NEXT: ret i32 [[RET]]
+;
+ %r = or i32 %x, %y
+ %ret = lshr i32 %r, %y
+ 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
+}
>From 65a88fa1e5671fd35af75ad9646e338626fe94b5 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 shr ([x]or x, y), x -> shr y, x
Proof: https://alive2.llvm.org/ce/z/yWCmMd
Co-authored-by: John Regehr <regehr at cs.utah.edu>
---
.../InstCombine/InstCombineShifts.cpp | 34 ++++++++++++-------
.../Transforms/InstCombine/shift-logic.ll | 18 ++++------
2 files changed, 28 insertions(+), 24 deletions(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp b/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp
index 899a3c16554c9..10bf908108aef 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp
@@ -512,19 +512,27 @@ Instruction *InstCombinerImpl::commonShiftTransforms(BinaryOperator &I) {
if (match(Op1, m_Or(m_Value(), m_SpecificInt(BitWidth - 1))))
return replaceOperand(I, 1, ConstantInt::get(Ty, BitWidth - 1));
- Instruction *CmpIntr;
- if ((I.getOpcode() == Instruction::LShr ||
- I.getOpcode() == Instruction::AShr) &&
- match(Op0, m_OneUse(m_Instruction(CmpIntr))) &&
- isa<CmpIntrinsic>(CmpIntr) &&
- match(Op1, m_SpecificInt(Ty->getScalarSizeInBits() - 1))) {
- Value *Cmp =
- Builder.CreateICmp(cast<CmpIntrinsic>(CmpIntr)->getLTPredicate(),
- CmpIntr->getOperand(0), CmpIntr->getOperand(1));
- return CastInst::Create(I.getOpcode() == Instruction::LShr
- ? Instruction::ZExt
- : Instruction::SExt,
- Cmp, Ty);
+ if (I.getOpcode() == Instruction::LShr ||
+ I.getOpcode() == Instruction::AShr) {
+ // (l|a)shr ([x]or x, y), x --> (l|a)shr y, x
+ Value *X;
+ if (match(Op0, m_CombineOr(m_Xor(m_Value(X), m_Value(Y)),
+ m_Or(m_Value(X), m_Value(Y)))) &&
+ Op1 == X)
+ return BinaryOperator::Create(I.getOpcode(), Y, X);
+
+ Instruction *CmpIntr;
+ if (match(Op0, m_OneUse(m_Instruction(CmpIntr))) &&
+ isa<CmpIntrinsic>(CmpIntr) &&
+ match(Op1, m_SpecificInt(Ty->getScalarSizeInBits() - 1))) {
+ Value *Cmp =
+ Builder.CreateICmp(cast<CmpIntrinsic>(CmpIntr)->getLTPredicate(),
+ CmpIntr->getOperand(0), CmpIntr->getOperand(1));
+ return CastInst::Create(I.getOpcode() == Instruction::LShr
+ ? Instruction::ZExt
+ : Instruction::SExt,
+ Cmp, Ty);
+ }
}
return nullptr;
diff --git a/llvm/test/Transforms/InstCombine/shift-logic.ll b/llvm/test/Transforms/InstCombine/shift-logic.ll
index 5cb24b37684fc..3b58af47b84ae 100644
--- a/llvm/test/Transforms/InstCombine/shift-logic.ll
+++ b/llvm/test/Transforms/InstCombine/shift-logic.ll
@@ -550,8 +550,7 @@ define <2 x i64> @lshr_sub_poison(<2 x i64> %x, <2 x i64> %py) {
define i32 @ashr_xor_operand_match(i32 %x, i32 %y) {
; CHECK-LABEL: @ashr_xor_operand_match(
-; CHECK-NEXT: [[R:%.*]] = xor i32 [[X:%.*]], [[Y:%.*]]
-; CHECK-NEXT: [[RET:%.*]] = ashr i32 [[R]], [[X]]
+; CHECK-NEXT: [[RET:%.*]] = ashr i32 [[R:%.*]], [[X:%.*]]
; CHECK-NEXT: ret i32 [[RET]]
;
%r = xor i32 %x, %y
@@ -572,8 +571,7 @@ define i32 @ashr_xor_operand_mismtach(i32 %x, i32 %y) {
define i32 @lshr_xor_operand_match(i32 %x, i32 %y) {
; CHECK-LABEL: @lshr_xor_operand_match(
-; CHECK-NEXT: [[R:%.*]] = xor i32 [[X:%.*]], [[Y:%.*]]
-; CHECK-NEXT: [[RET:%.*]] = lshr i32 [[R]], [[X]]
+; CHECK-NEXT: [[RET:%.*]] = lshr i32 [[R:%.*]], [[X:%.*]]
; CHECK-NEXT: ret i32 [[RET]]
;
%r = xor i32 %x, %y
@@ -594,8 +592,7 @@ define i32 @lshr_xor_operand_mismtach(i32 %x, i32 %y) {
define i32 @ashr_or_operand_match(i32 %x, i32 %y) {
; CHECK-LABEL: @ashr_or_operand_match(
-; CHECK-NEXT: [[R:%.*]] = or i32 [[X:%.*]], [[Y:%.*]]
-; CHECK-NEXT: [[RET:%.*]] = ashr i32 [[R]], [[X]]
+; CHECK-NEXT: [[RET:%.*]] = ashr i32 [[R:%.*]], [[X:%.*]]
; CHECK-NEXT: ret i32 [[RET]]
;
%r = or i32 %x, %y
@@ -616,8 +613,7 @@ define i32 @ashr_or_operand_mismtach(i32 %x, i32 %y) {
define i32 @lshr_or_operand_match(i32 %x, i32 %y) {
; CHECK-LABEL: @lshr_or_operand_match(
-; CHECK-NEXT: [[R:%.*]] = or i32 [[X:%.*]], [[Y:%.*]]
-; CHECK-NEXT: [[RET:%.*]] = lshr i32 [[R]], [[X]]
+; CHECK-NEXT: [[RET:%.*]] = lshr i32 [[R:%.*]], [[X:%.*]]
; CHECK-NEXT: ret i32 [[RET]]
;
%r = or i32 %x, %y
@@ -638,10 +634,10 @@ define i32 @lshr_or_operand_mismtach(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: [[Q:%.*]] = ashr i32 [[R:%.*]], [[X:%.*]]
; CHECK-NEXT: [[RET:%.*]] = xor i32 [[R]], [[Q]]
-; CHECK-NEXT: ret i32 [[RET]]
+; 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