[llvm] [InstCombine] Recognize more rotation patterns (Part 1) (PR #78107)
via llvm-commits
llvm-commits at lists.llvm.org
Sun Jan 14 09:21:41 PST 2024
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-transforms
Author: Yingwei Zheng (dtcxzyw)
<details>
<summary>Changes</summary>
InstCombine already handles the pattern `(shl ShVal, (X & (Width - 1))) | (lshr ShVal, ((-X) & (Width - 1)))`. Under certain circumstances, `X & (Width - 1)` will be simplified to `X`. Therefore, this patch adds support for the pattern `(shl ShVal, X) | (lshr ShVal, ((-X) & (Width - 1)))`.
Alive2: https://alive2.llvm.org/ce/z/P7JQ2V
---
Full diff: https://github.com/llvm/llvm-project/pull/78107.diff
2 Files Affected:
- (modified) llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp (+4)
- (modified) llvm/test/Transforms/InstCombine/funnel.ll (+76)
``````````diff
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
index 0620752e321394..c97fd418e1b11d 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
@@ -2809,6 +2809,10 @@ static Instruction *matchFunnelShift(Instruction &Or, InstCombinerImpl &IC,
match(R, m_And(m_Neg(m_Specific(X)), m_SpecificInt(Mask))))
return X;
+ // (shl ShVal, X) | (lshr ShVal, ((-X) & (Width - 1)))
+ if (match(R, m_And(m_Neg(m_Specific(L)), m_SpecificInt(Mask))))
+ return L;
+
// Similar to above, but the shift amount may be extended after masking,
// so return the extended value as the parameter for the intrinsic.
if (match(L, m_ZExt(m_And(m_Value(X), m_SpecificInt(Mask)))) &&
diff --git a/llvm/test/Transforms/InstCombine/funnel.ll b/llvm/test/Transforms/InstCombine/funnel.ll
index 772a052b3a4f84..162519e648f3e4 100644
--- a/llvm/test/Transforms/InstCombine/funnel.ll
+++ b/llvm/test/Transforms/InstCombine/funnel.ll
@@ -559,3 +559,79 @@ define i8 @unmasked_shlop_masked_shift_amount(i16 %x, i16 %y, i16 %shamt) {
%t8 = trunc i16 %t7 to i8
ret i8 %t8
}
+
+define i32 @test_rotl_and_neg(i32 %x, i32 %shamt) {
+; CHECK-LABEL: @test_rotl_and_neg(
+; CHECK-NEXT: [[OR:%.*]] = call i32 @llvm.fshl.i32(i32 [[X:%.*]], i32 [[X]], i32 [[SHAMT:%.*]])
+; CHECK-NEXT: ret i32 [[OR]]
+;
+ %shl = shl i32 %x, %shamt
+ %neg = sub i32 0, %shamt
+ %and = and i32 %neg, 31
+ %shr = lshr i32 %x, %and
+ %or = or i32 %shl, %shr
+ ret i32 %or
+}
+
+define i32 @test_rotl_and_neg_commuted(i32 %x, i32 %shamt) {
+; CHECK-LABEL: @test_rotl_and_neg_commuted(
+; CHECK-NEXT: [[OR:%.*]] = call i32 @llvm.fshl.i32(i32 [[X:%.*]], i32 [[X]], i32 [[SHAMT:%.*]])
+; CHECK-NEXT: ret i32 [[OR]]
+;
+ %shl = shl i32 %x, %shamt
+ %neg = sub i32 0, %shamt
+ %and = and i32 %neg, 31
+ %shr = lshr i32 %x, %and
+ %or = or i32 %shr, %shl
+ ret i32 %or
+}
+
+define i32 @test_rotr_and_neg(i32 %x, i32 %shamt) {
+; CHECK-LABEL: @test_rotr_and_neg(
+; CHECK-NEXT: [[OR:%.*]] = call i32 @llvm.fshr.i32(i32 [[X:%.*]], i32 [[X]], i32 [[SHAMT:%.*]])
+; CHECK-NEXT: ret i32 [[OR]]
+;
+ %shr = lshr i32 %x, %shamt
+ %neg = sub i32 0, %shamt
+ %and = and i32 %neg, 31
+ %shl = shl i32 %x, %and
+ %or = or i32 %shl, %shr
+ ret i32 %or
+}
+
+; Negative tests
+
+; Only work for rotation patterns
+define i32 @test_fshl_and_neg(i32 %x, i32 %y, i32 %shamt) {
+; CHECK-LABEL: @test_fshl_and_neg(
+; CHECK-NEXT: [[SHL:%.*]] = shl i32 [[X:%.*]], [[SHAMT:%.*]]
+; CHECK-NEXT: [[NEG:%.*]] = sub i32 0, [[SHAMT]]
+; CHECK-NEXT: [[AND:%.*]] = and i32 [[NEG]], 31
+; CHECK-NEXT: [[SHR:%.*]] = lshr i32 [[Y:%.*]], [[AND]]
+; CHECK-NEXT: [[OR:%.*]] = or i32 [[SHL]], [[SHR]]
+; CHECK-NEXT: ret i32 [[OR]]
+;
+ %shl = shl i32 %x, %shamt
+ %neg = sub i32 0, %shamt
+ %and = and i32 %neg, 31
+ %shr = lshr i32 %y, %and
+ %or = or i32 %shl, %shr
+ ret i32 %or
+}
+
+define i32 @test_rotl_and_neg_wrong_mask(i32 %x, i32 %shamt) {
+; CHECK-LABEL: @test_rotl_and_neg_wrong_mask(
+; CHECK-NEXT: [[SHL:%.*]] = shl i32 [[X:%.*]], [[SHAMT:%.*]]
+; CHECK-NEXT: [[NEG:%.*]] = sub i32 0, [[SHAMT]]
+; CHECK-NEXT: [[AND:%.*]] = and i32 [[NEG]], 15
+; CHECK-NEXT: [[SHR:%.*]] = lshr i32 [[X]], [[AND]]
+; CHECK-NEXT: [[OR:%.*]] = or i32 [[SHL]], [[SHR]]
+; CHECK-NEXT: ret i32 [[OR]]
+;
+ %shl = shl i32 %x, %shamt
+ %neg = sub i32 0, %shamt
+ %and = and i32 %neg, 15
+ %shr = lshr i32 %x, %and
+ %or = or i32 %shl, %shr
+ ret i32 %or
+}
``````````
</details>
https://github.com/llvm/llvm-project/pull/78107
More information about the llvm-commits
mailing list