[llvm] [RISCV] Simplify one of the RV32 PACK isel patterns. (PR #152045)

Craig Topper via llvm-commits llvm-commits at lists.llvm.org
Tue Aug 5 10:34:11 PDT 2025


https://github.com/topperc updated https://github.com/llvm/llvm-project/pull/152045

>From 421b30f2d2aac401a69289fbcd8d16fd3f862696 Mon Sep 17 00:00:00 2001
From: Craig Topper <craig.topper at sifive.com>
Date: Tue, 5 Aug 2025 09:53:43 -0700
Subject: [PATCH 1/2] Pre-commit test

---
 llvm/test/CodeGen/RISCV/rv32zbkb.ll | 82 +++++++++++++++++++++++++++++
 1 file changed, 82 insertions(+)

diff --git a/llvm/test/CodeGen/RISCV/rv32zbkb.ll b/llvm/test/CodeGen/RISCV/rv32zbkb.ll
index 4aa6dd4dba6c2..5a73613fb046f 100644
--- a/llvm/test/CodeGen/RISCV/rv32zbkb.ll
+++ b/llvm/test/CodeGen/RISCV/rv32zbkb.ll
@@ -319,3 +319,85 @@ define i64 @zext_i16_to_i64(i16 %a) nounwind {
   %1 = zext i16 %a to i64
   ret i64 %1
 }
+
+define i32 @pack_lo_packh_hi_packh(i8 zeroext %0, i8 zeroext %1, i8 zeroext %2, i8 zeroext %3) nounwind {
+; RV32I-LABEL: pack_lo_packh_hi_packh:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    slli a1, a1, 8
+; RV32I-NEXT:    slli a2, a2, 16
+; RV32I-NEXT:    slli a3, a3, 24
+; RV32I-NEXT:    or a0, a0, a1
+; RV32I-NEXT:    or a2, a2, a3
+; RV32I-NEXT:    or a0, a0, a2
+; RV32I-NEXT:    ret
+;
+; RV32ZBKB-LABEL: pack_lo_packh_hi_packh:
+; RV32ZBKB:       # %bb.0:
+; RV32ZBKB-NEXT:    slli a3, a3, 24
+; RV32ZBKB-NEXT:    packh a0, a0, a1
+; RV32ZBKB-NEXT:    pack a0, a0, a2
+; RV32ZBKB-NEXT:    or a0, a0, a3
+; RV32ZBKB-NEXT:    ret
+  %a = zext i8 %0 to i32
+  %b = zext i8 %1 to i32
+  %c = zext i8 %2 to i32
+  %d = zext i8 %3 to i32
+  %e = shl i32 %b, 8
+  %f = shl i32 %c, 16
+  %g = shl i32 %d, 24
+  %h = or i32 %a, %e
+  %i = or i32 %h, %f
+  %j = or i32 %i, %g
+  ret i32 %j
+}
+
+define i32 @pack_lo_zext_hi_packh(i16 zeroext %0, i8 zeroext %1, i8 zeroext %2) nounwind {
+; RV32I-LABEL: pack_lo_zext_hi_packh:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    slli a1, a2, 16
+; RV32I-NEXT:    slli a2, a2, 24
+; RV32I-NEXT:    or a1, a2, a1
+; RV32I-NEXT:    or a0, a1, a0
+; RV32I-NEXT:    ret
+;
+; RV32ZBKB-LABEL: pack_lo_zext_hi_packh:
+; RV32ZBKB:       # %bb.0:
+; RV32ZBKB-NEXT:    packh a1, a2, a2
+; RV32ZBKB-NEXT:    slli a1, a1, 16
+; RV32ZBKB-NEXT:    or a0, a1, a0
+; RV32ZBKB-NEXT:    ret
+  %a = zext i16 %0 to i32
+  %b = zext i8 %1 to i32
+  %c = zext i8 %2 to i32
+  %d = shl i32 %c, 8
+  %e = or i32 %c, %d
+  %f = shl i32 %e, 16
+  %g = or i32 %f, %a
+  ret i32 %g
+}
+
+; Negative test, %a isn't extended so we can't use pack for the outer or, but
+; we can use packh for the high half.
+define i32 @pack_lo_noext_hi_packh(i32 %a, i8 zeroext %1, i8 zeroext %2) nounwind {
+; RV32I-LABEL: pack_lo_noext_hi_packh:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    slli a1, a2, 16
+; RV32I-NEXT:    slli a2, a2, 24
+; RV32I-NEXT:    or a1, a2, a1
+; RV32I-NEXT:    or a0, a1, a0
+; RV32I-NEXT:    ret
+;
+; RV32ZBKB-LABEL: pack_lo_noext_hi_packh:
+; RV32ZBKB:       # %bb.0:
+; RV32ZBKB-NEXT:    packh a1, a2, a2
+; RV32ZBKB-NEXT:    slli a1, a1, 16
+; RV32ZBKB-NEXT:    or a0, a1, a0
+; RV32ZBKB-NEXT:    ret
+  %b = zext i8 %1 to i32
+  %c = zext i8 %2 to i32
+  %d = shl i32 %c, 8
+  %e = or i32 %c, %d
+  %f = shl i32 %e, 16
+  %g = or i32 %f, %a
+  ret i32 %g
+}

>From 1ae00c1353e4203255743204b19108f9edb8108c Mon Sep 17 00:00:00 2001
From: Craig Topper <craig.topper at sifive.com>
Date: Mon, 4 Aug 2025 15:04:09 -0700
Subject: [PATCH 2/2] [RISCV] Simplify one of the RV32 PACK isel patterns.

This pattern previously checked a specific variant of 4 bytes
being packed that is generated by unaligned load expansion.

Our simplest PACK patterns misses this case because we don't have
a single shift left by 16. We have two shift lefts hidden behind
another OR.

We only need the pattern to find the 2 shifts in the upper part,
for the lower part we only care that the upper 16 bits are zero.
If the lower bits can also be a PACKH that can be selected separately
after.

I believe this allows tablegen to create more patterns for permutations
of this pattern. The associative and commutative variant expansion
is limited to 3 children.
---
 llvm/lib/Target/RISCV/RISCVInstrInfoZb.td | 14 ++++++++------
 llvm/test/CodeGen/RISCV/rv32zbkb.ll       |  8 +++-----
 2 files changed, 11 insertions(+), 11 deletions(-)

diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoZb.td b/llvm/lib/Target/RISCV/RISCVInstrInfoZb.td
index d2a651444169c..04ffb05c513f4 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoZb.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoZb.td
@@ -641,13 +641,15 @@ def : Pat<(binop_allhusers<or> (shl GPR:$rs2, (XLenVT 8)),
 let Predicates = [HasStdExtZbkb, IsRV32] in {
 def : Pat<(i32 (or (zexti16 (i32 GPR:$rs1)), (shl GPR:$rs2, (i32 16)))),
           (PACK GPR:$rs1, GPR:$rs2)>;
-def : Pat<(or (or
-                  (shl (zexti8 (XLenVT GPR:$op1rs2)), (XLenVT 24)),
+
+// Match a pattern of 2 bytes being inserted into bits [31:16], with bits
+// bits [15:0] coming from a zero extended value. We can use pack with packh for
+// bits [31:16]. If bits [15:0] can also be a packh, it can be matched
+// separately.
+def : Pat<(or (or (shl (zexti8 (XLenVT GPR:$op1rs2)), (XLenVT 24)),
                   (shl (zexti8 (XLenVT GPR:$op1rs1)), (XLenVT 16))),
-              (or
-                  (shl (zexti8 (XLenVT GPR:$op0rs2)), (XLenVT 8)),
-                  (zexti8 (XLenVT GPR:$op0rs1)))),
-          (PACK (XLenVT (PACKH GPR:$op0rs1, GPR:$op0rs2)),
+              (zexti16 (XLenVT GPR:$rs1))),
+          (PACK (XLenVT GPR:$rs1),
                 (XLenVT (PACKH GPR:$op1rs1, GPR:$op1rs2)))>;
 }
 
diff --git a/llvm/test/CodeGen/RISCV/rv32zbkb.ll b/llvm/test/CodeGen/RISCV/rv32zbkb.ll
index 5a73613fb046f..7ebbd7802b70f 100644
--- a/llvm/test/CodeGen/RISCV/rv32zbkb.ll
+++ b/llvm/test/CodeGen/RISCV/rv32zbkb.ll
@@ -333,10 +333,9 @@ define i32 @pack_lo_packh_hi_packh(i8 zeroext %0, i8 zeroext %1, i8 zeroext %2,
 ;
 ; RV32ZBKB-LABEL: pack_lo_packh_hi_packh:
 ; RV32ZBKB:       # %bb.0:
-; RV32ZBKB-NEXT:    slli a3, a3, 24
 ; RV32ZBKB-NEXT:    packh a0, a0, a1
-; RV32ZBKB-NEXT:    pack a0, a0, a2
-; RV32ZBKB-NEXT:    or a0, a0, a3
+; RV32ZBKB-NEXT:    packh a1, a2, a3
+; RV32ZBKB-NEXT:    pack a0, a0, a1
 ; RV32ZBKB-NEXT:    ret
   %a = zext i8 %0 to i32
   %b = zext i8 %1 to i32
@@ -363,8 +362,7 @@ define i32 @pack_lo_zext_hi_packh(i16 zeroext %0, i8 zeroext %1, i8 zeroext %2)
 ; RV32ZBKB-LABEL: pack_lo_zext_hi_packh:
 ; RV32ZBKB:       # %bb.0:
 ; RV32ZBKB-NEXT:    packh a1, a2, a2
-; RV32ZBKB-NEXT:    slli a1, a1, 16
-; RV32ZBKB-NEXT:    or a0, a1, a0
+; RV32ZBKB-NEXT:    pack a0, a0, a1
 ; RV32ZBKB-NEXT:    ret
   %a = zext i16 %0 to i32
   %b = zext i8 %1 to i32



More information about the llvm-commits mailing list