[llvm] [RISCV][P-ext] Use pli.b when only the lower 2 bytes are used. (PR #192400)

Craig Topper via llvm-commits llvm-commits at lists.llvm.org
Wed Apr 15 23:27:06 PDT 2026


https://github.com/topperc created https://github.com/llvm/llvm-project/pull/192400

If the lower 2 bytes are the same and are the only bytes used we
can use pli.b instead of lui+addi.

>From 7028e118bc30212fa8678d89d7a5e814e0d0b1d9 Mon Sep 17 00:00:00 2001
From: Craig Topper <craig.topper at sifive.com>
Date: Wed, 15 Apr 2026 23:20:57 -0700
Subject: [PATCH 1/2] Pre-commit tests

---
 llvm/test/CodeGen/RISCV/rv32p.ll | 23 +++++++++++++++++------
 llvm/test/CodeGen/RISCV/rv64p.ll | 11 +++++++++++
 2 files changed, 28 insertions(+), 6 deletions(-)

diff --git a/llvm/test/CodeGen/RISCV/rv32p.ll b/llvm/test/CodeGen/RISCV/rv32p.ll
index 154319f221d2a..0e25b5822e2da 100644
--- a/llvm/test/CodeGen/RISCV/rv32p.ll
+++ b/llvm/test/CodeGen/RISCV/rv32p.ll
@@ -58,6 +58,17 @@ define void @pli_b_store_i32(ptr %p) {
   ret void
 }
 
+define void @pli_b_store_i16(ptr %p) {
+; CHECK-LABEL: pli_b_store_i16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    lui a1, 8
+; CHECK-NEXT:    addi a1, a1, 385
+; CHECK-NEXT:    sh a1, 0(a0)
+; CHECK-NEXT:    ret
+  store i16 u0x8181, ptr %p
+  ret void
+}
+
 define i32 @plui_h_i32(ptr %p) {
 ; CHECK-LABEL: plui_h_i32:
 ; CHECK:       # %bb.0:
@@ -190,16 +201,16 @@ define i64 @cls_i64(i64 %x) {
 ; CHECK-LABEL: cls_i64:
 ; CHECK:       # %bb.0:
 ; CHECK-NEXT:    srai a2, a1, 31
-; CHECK-NEXT:    bne a1, a2, .LBB16_2
+; CHECK-NEXT:    bne a1, a2, .LBB17_2
 ; CHECK-NEXT:  # %bb.1:
 ; CHECK-NEXT:    xor a0, a0, a2
 ; CHECK-NEXT:    clz a0, a0
 ; CHECK-NEXT:    addi a0, a0, 32
-; CHECK-NEXT:    j .LBB16_3
-; CHECK-NEXT:  .LBB16_2:
+; CHECK-NEXT:    j .LBB17_3
+; CHECK-NEXT:  .LBB17_2:
 ; CHECK-NEXT:    xor a1, a1, a2
 ; CHECK-NEXT:    clz a0, a1
-; CHECK-NEXT:  .LBB16_3:
+; CHECK-NEXT:  .LBB17_3:
 ; CHECK-NEXT:    li a1, 1
 ; CHECK-NEXT:    wsubu a0, a0, a1
 ; CHECK-NEXT:    ret
@@ -217,7 +228,7 @@ define i64 @cls_i64_2(i64 %x) {
 ; CHECK-NEXT:    xor a1, a1, a2
 ; CHECK-NEXT:    xor a0, a0, a2
 ; CHECK-NEXT:    nsrli a1, a0, 31
-; CHECK-NEXT:    bnez a1, .LBB17_2
+; CHECK-NEXT:    bnez a1, .LBB18_2
 ; CHECK-NEXT:  # %bb.1:
 ; CHECK-NEXT:    slli a0, a0, 1
 ; CHECK-NEXT:    addi a0, a0, 1
@@ -225,7 +236,7 @@ define i64 @cls_i64_2(i64 %x) {
 ; CHECK-NEXT:    addi a0, a0, 32
 ; CHECK-NEXT:    li a1, 0
 ; CHECK-NEXT:    ret
-; CHECK-NEXT:  .LBB17_2:
+; CHECK-NEXT:  .LBB18_2:
 ; CHECK-NEXT:    clz a0, a1
 ; CHECK-NEXT:    li a1, 0
 ; CHECK-NEXT:    ret
diff --git a/llvm/test/CodeGen/RISCV/rv64p.ll b/llvm/test/CodeGen/RISCV/rv64p.ll
index d4a5e054d312d..5eb682a41130a 100644
--- a/llvm/test/CodeGen/RISCV/rv64p.ll
+++ b/llvm/test/CodeGen/RISCV/rv64p.ll
@@ -173,6 +173,17 @@ define void @pli_b_store_i32(ptr %p) {
   ret void
 }
 
+define void @pli_b_store_i16(ptr %p) {
+; CHECK-LABEL: pli_b_store_i16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    lui a1, 8
+; CHECK-NEXT:    addi a1, a1, 385
+; CHECK-NEXT:    sh a1, 0(a0)
+; CHECK-NEXT:    ret
+  store i16 u0x8181, ptr %p
+  ret void
+}
+
 define i64 @plui_h_i64() {
 ; CHECK-LABEL: plui_h_i64:
 ; CHECK:       # %bb.0:

>From efcd4d8bcfccbe344e97a9209bea9af943c6eb65 Mon Sep 17 00:00:00 2001
From: Craig Topper <craig.topper at sifive.com>
Date: Wed, 15 Apr 2026 23:24:25 -0700
Subject: [PATCH 2/2] [RISCV][P-ext] Use pli.b when only the lower 2 bytes are
 used.

If the lower 2 bytes are the same and are the only bytes used we
can use pli.b instead of lui+addi.
---
 llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp | 36 ++++++++++++++-------
 llvm/test/CodeGen/RISCV/rv32p.ll            |  3 +-
 llvm/test/CodeGen/RISCV/rv64p.ll            |  3 +-
 3 files changed, 27 insertions(+), 15 deletions(-)

diff --git a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
index e7be2938c2256..acdb05ae546c0 100644
--- a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
@@ -1133,17 +1133,31 @@ void RISCVDAGToDAGISel::Select(SDNode *Node) {
     else if (!isInt<16>(Imm) && isUInt<16>(Imm) &&
              isInt<12>(SignExtend64<16>(Imm)) && hasAllHUsers(Node))
       Imm = SignExtend64<16>(Imm);
-    // If the upper 32-bits are not used try to convert this into a simm32 by
-    // sign extending bit 32.
-    else if (!isInt<32>(Imm) && isUInt<32>(Imm) && hasAllWUsers(Node))
-      Imm = SignExtend64<32>(Imm);
-
-    if (VT == MVT::i64 && Subtarget->hasStdExtP() && isApplicableToPLI(Imm) &&
-        hasAllWUsers(Node)) {
-      // If it's 4 packed 8-bit integers or 2 packed signed 16-bit integers, we
-      // can simply copy lower 32 bits to higher 32 bits to make it able to
-      // rematerialize to PLI_B or PLI_H
-      Imm = ((uint64_t)Imm << 32) | (Imm & 0xFFFFFFFF);
+
+    // If the upper XLen-16 bits are not used, the lower 2 bytes are the same,
+    // and we can't use li, convert to an xlen splat so we can use pli.b.
+    if (Subtarget->hasStdExtP() && !isInt<12>(Imm) &&
+        (Imm & 0xff) == ((Imm >> 8) & 0xff) && hasAllHUsers(Node)) {
+      // Splat the lower 16 bits to XLen. Sign extend for RV32.
+      uint64_t Splat = Imm & 0xffff;
+      Splat = (Splat << 16) | Splat;
+      if (VT == MVT::i64)
+        Imm = Splat << 32 | Splat;
+      else
+        Imm = SignExtend64<32>(Splat);
+    } else {
+      // If the upper 32-bits are not used try to convert this into a simm32 by
+      // sign extending bit 32.
+      if (!isInt<32>(Imm) && isUInt<32>(Imm) && hasAllWUsers(Node))
+        Imm = SignExtend64<32>(Imm);
+
+      if (VT == MVT::i64 && Subtarget->hasStdExtP() && isApplicableToPLI(Imm) &&
+          hasAllWUsers(Node)) {
+        // If it's 4 packed 8-bit integers or 2 packed signed 16-bit integers, we
+        // can simply copy lower 32 bits to higher 32 bits to make it able to
+        // rematerialize to PLI_B or PLI_H
+        Imm = ((uint64_t)Imm << 32) | (Imm & 0xFFFFFFFF);
+      }
     }
 
     ReplaceNode(Node, selectImm(CurDAG, DL, VT, Imm, *Subtarget).getNode());
diff --git a/llvm/test/CodeGen/RISCV/rv32p.ll b/llvm/test/CodeGen/RISCV/rv32p.ll
index 0e25b5822e2da..ebec3f57cae5c 100644
--- a/llvm/test/CodeGen/RISCV/rv32p.ll
+++ b/llvm/test/CodeGen/RISCV/rv32p.ll
@@ -61,8 +61,7 @@ define void @pli_b_store_i32(ptr %p) {
 define void @pli_b_store_i16(ptr %p) {
 ; CHECK-LABEL: pli_b_store_i16:
 ; CHECK:       # %bb.0:
-; CHECK-NEXT:    lui a1, 8
-; CHECK-NEXT:    addi a1, a1, 385
+; CHECK-NEXT:    pli.b a1, -127
 ; CHECK-NEXT:    sh a1, 0(a0)
 ; CHECK-NEXT:    ret
   store i16 u0x8181, ptr %p
diff --git a/llvm/test/CodeGen/RISCV/rv64p.ll b/llvm/test/CodeGen/RISCV/rv64p.ll
index 5eb682a41130a..21630c8dbb37f 100644
--- a/llvm/test/CodeGen/RISCV/rv64p.ll
+++ b/llvm/test/CodeGen/RISCV/rv64p.ll
@@ -176,8 +176,7 @@ define void @pli_b_store_i32(ptr %p) {
 define void @pli_b_store_i16(ptr %p) {
 ; CHECK-LABEL: pli_b_store_i16:
 ; CHECK:       # %bb.0:
-; CHECK-NEXT:    lui a1, 8
-; CHECK-NEXT:    addi a1, a1, 385
+; CHECK-NEXT:    pli.b a1, -127
 ; CHECK-NEXT:    sh a1, 0(a0)
 ; CHECK-NEXT:    ret
   store i16 u0x8181, ptr %p



More information about the llvm-commits mailing list