[llvm] [InstCombine] Fold rotate patterns with ZExt/Trunc at different Points (PR #142578)

Nikita Popov via llvm-commits llvm-commits at lists.llvm.org
Mon Jun 16 06:00:02 PDT 2025


================
@@ -698,6 +698,104 @@ define i64 @rotateleft_64_zext_neg_mask_amount(i64 %0, i32 %1) {
   ret i64 %10
 }
 
+define i64 @rotateright_64_zext_double_conversion(i64 %x, i32 %y) {
+; CHECK-LABEL: @rotateright_64_zext_double_conversion(
+; CHECK-NEXT:    [[Z:%.*]] = zext nneg i32 [[Y:%.*]] to i64
+; CHECK-NEXT:    [[OR:%.*]] = call i64 @llvm.fshr.i64(i64 [[X:%.*]], i64 [[X]], i64 [[Z]])
+; CHECK-NEXT:    ret i64 [[OR]]
+;
+  %z = zext i32 %y to i64
+  %neg = sub nsw i32 0, %y
+  %and2 = and i32 %neg, 63
+  %conv = zext i32 %and2 to i64
+  %shl = shl i64 %x, %conv
+  %shr = lshr i64 %x, %z
+  %or = or i64 %shr, %shl
+  ret i64 %or
+}
+
+define i32 @rotateright_32_trunc_early(i32 %x, i64 %y) {
+; CHECK-LABEL: @rotateright_32_trunc_early(
+; CHECK-NEXT:    [[Z:%.*]] = trunc i64 [[Y:%.*]] to i32
+; CHECK-NEXT:    [[OR:%.*]] = call i32 @llvm.fshr.i32(i32 [[X:%.*]], i32 [[X]], i32 [[Z]])
+; CHECK-NEXT:    ret i32 [[OR]]
+;
+  %z = trunc i64 %y to i32
+  %neg = sub nsw i32 0, %z
+  %and2 = and i32 %neg, 31
+  %shl = shl i32 %x, %and2
+  %shr = lshr i32 %x, %z
+  %or = or i32 %shr, %shl
+  ret i32 %or
+}
+
+define i32 @rotateright_32_trunc_neg_mask_amount(i32 %x, i64 %y) {
+; CHECK-LABEL: @rotateright_32_trunc_neg_mask_amount(
+; CHECK-NEXT:    [[Z:%.*]] = trunc i64 [[Y:%.*]] to i32
+; CHECK-NEXT:    [[OR:%.*]] = call i32 @llvm.fshr.i32(i32 [[X:%.*]], i32 [[X]], i32 [[Z]])
+; CHECK-NEXT:    ret i32 [[OR]]
+;
+  %z = trunc i64 %y to i32
+  %neg = sub  i64 0, %y
+  %and2 = and i64 %neg, 31
+  %conv = trunc i64 %and2 to i32
+  %shl = shl i32 %x, %conv
+  %shr = lshr i32 %x, %z
+  %or = or i32 %shr, %shl
+  ret i32 %or
+}
+
+; restrict the shift amount before rotating
+
+define i32 @rotateleft_32_restricted_shamt(i32 %x, i32 %shAmt) {
+; CHECK-LABEL: @rotateleft_32_restricted_shamt(
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[SHAMT:%.*]], 30
+; CHECK-NEXT:    [[OR:%.*]] = call i32 @llvm.fshl.i32(i32 [[X:%.*]], i32 [[X]], i32 [[AND]])
+; CHECK-NEXT:    ret i32 [[OR]]
+;
+  %and = and i32 %shAmt, 30
+  %shl = shl i32 %x, %and
+  %sub = sub i32 0, %and
+  %shr = lshr i32 %x, %sub
+  %or = or i32 %shl, %shr
+  ret i32 %or
+}
----------------
nikic wrote:

This improvement seems unrelated to the extension changes? Can we split it off?

https://github.com/llvm/llvm-project/pull/142578


More information about the llvm-commits mailing list