[llvm] [RISCV][P-ext] Custom lower v8i8 mulh* on RV64. NFC (PR #218160)

Craig Topper via llvm-commits llvm-commits at lists.llvm.org
Sat Aug 22 13:24:10 PDT 2026


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

Assisted-by: Claude

>From 5ced921c30be23e75b62fcff65e37b4b3570e028 Mon Sep 17 00:00:00 2001
From: Craig Topper <craig.topper at sifive.com>
Date: Fri, 21 Aug 2026 23:26:23 -0700
Subject: [PATCH] [RISCV][P-ext] Custom lower v8i8 mulh* on RV64. NFC

Assisted-by: Claude
---
 llvm/lib/Target/RISCV/RISCVISelLowering.cpp | 44 ++++++++++++++++++++-
 llvm/lib/Target/RISCV/RISCVInstrInfoP.td    | 33 ++++++++++------
 2 files changed, 64 insertions(+), 13 deletions(-)

diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index 9406b697882d7..0fdadff79b5e3 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -724,7 +724,10 @@ RISCVTargetLowering::RISCVTargetLowering(const TargetMachine &TM,
       setOperationAction(ISD::INSERT_SUBVECTOR, {MVT::v4i16, MVT::v8i8},
                          Custom);
     } else {
-      setOperationAction({ISD::MUL, ISD::MULHS, ISD::MULHU}, P64VecVTs, Legal);
+      setOperationAction(ISD::MUL, P64VecVTs, Legal);
+      setOperationAction({ISD::MULHS, ISD::MULHU}, {MVT::v2i32, MVT::v4i16},
+                         Legal);
+      setOperationAction({ISD::MULHS, ISD::MULHU}, MVT::v8i8, Custom);
       setOperationAction(ISD::ZERO_EXTEND_VECTOR_INREG,
                          {MVT::v4i16, MVT::v2i32}, Legal);
       setOperationAction(ISD::ANY_EXTEND_VECTOR_INREG, {MVT::v4i16, MVT::v2i32},
@@ -9439,6 +9442,22 @@ SDValue RISCVTargetLowering::LowerOperation(SDValue Op,
       }
       return DAG.getNode(ISD::TRUNCATE, DL, VT, Res);
     }
+    // Lower v8i8 MULHS/MULHU on RV64 via a pair of widening byte multiplies
+    // (picking out the even/odd result lanes) recombined with PPAIRO.
+    if (Subtarget.hasStdExtP() && Subtarget.is64Bit() && VT == MVT::v8i8 &&
+        Opc != ISD::MUL) {
+      SDLoc DL(Op);
+      SDValue LHS = Op.getOperand(0);
+      SDValue RHS = Op.getOperand(1);
+      unsigned LoOpc =
+          Opc == ISD::MULHU ? RISCVISD::PMULU_H_B00 : RISCVISD::PMUL_H_B00;
+      unsigned HiOpc =
+          Opc == ISD::MULHU ? RISCVISD::PMULU_H_B11 : RISCVISD::PMUL_H_B11;
+      SDValue Lo = DAG.getNode(LoOpc, DL, MVT::v4i16, LHS, RHS);
+      SDValue Hi = DAG.getNode(HiOpc, DL, MVT::v4i16, LHS, RHS);
+      return DAG.getNode(RISCVISD::PPAIRO, DL, VT, DAG.getBitcast(VT, Lo),
+                         DAG.getBitcast(VT, Hi));
+    }
     return lowerToScalableOp(Op, DAG);
   }
   case ISD::ANY_EXTEND_VECTOR_INREG: {
@@ -17737,7 +17756,8 @@ static SDValue combineAddMulh(SDNode *N, SelectionDAG &DAG,
   bool IsPExtPackedDoubleType =
       VT.isSimple() && Subtarget.isPExtPackedDoubleType(VT.getSimpleVT());
   if (!TLI.isOperationLegal(ISD::MULHS, VT) && !IsPExtPackedDoubleType &&
-      !(Subtarget.hasStdExtP() && !Subtarget.is64Bit() && VT == MVT::v4i8))
+      !(Subtarget.hasStdExtP() && !Subtarget.is64Bit() && VT == MVT::v4i8) &&
+      !(Subtarget.hasStdExtP() && Subtarget.is64Bit() && VT == MVT::v8i8))
     return SDValue();
 
   using namespace SDPatternMatch;
@@ -17780,6 +17800,16 @@ static SDValue combineAddMulh(SDNode *N, SelectionDAG &DAG,
   if (Subtarget.hasStdExtP() && !Subtarget.is64Bit() && VT == MVT::v4i8)
     return MakePWMulSU(X, Mulh.getOperand(1));
 
+  // We don't have a v8i8 MULHSU instruction on RV64 either; build it from a
+  // pair of widening byte multiplies recombined with PPAIRO.
+  if (Subtarget.hasStdExtP() && Subtarget.is64Bit() && VT == MVT::v8i8) {
+    SDValue C = Mulh.getOperand(1);
+    SDValue Lo = DAG.getNode(RISCVISD::PMULSU_H_B00, DL, MVT::v4i16, X, C);
+    SDValue Hi = DAG.getNode(RISCVISD::PMULSU_H_B11, DL, MVT::v4i16, X, C);
+    return DAG.getNode(RISCVISD::PPAIRO, DL, VT, DAG.getBitcast(VT, Lo),
+                       DAG.getBitcast(VT, Hi));
+  }
+
   return DAG.getNode(RISCVISD::MULHSU, DL, VT, X, Mulh.getOperand(1));
 }
 
@@ -18174,6 +18204,16 @@ static SDValue combinePExtTruncate(SDNode *N, SelectionDAG &DAG,
       SDValue Hi = DAG.getNode(Opc, DL, MVT::i32, AHi, BHi);
       return DAG.getNode(ISD::BUILD_VECTOR, DL, VT, Lo, Hi);
     }
+
+    // On RV64, v8i8 MULHSU is built from a pair of widening byte multiplies
+    // (picking out the even/odd result lanes) recombined with PPAIRO.
+    if (Subtarget.is64Bit() && VT == MVT::v8i8 && Opc == RISCVISD::MULHSU) {
+      SDLoc DL(N);
+      SDValue Lo = DAG.getNode(RISCVISD::PMULSU_H_B00, DL, MVT::v4i16, A, B);
+      SDValue Hi = DAG.getNode(RISCVISD::PMULSU_H_B11, DL, MVT::v4i16, A, B);
+      return DAG.getNode(RISCVISD::PPAIRO, DL, VT, DAG.getBitcast(VT, Lo),
+                         DAG.getBitcast(VT, Hi));
+    }
     break;
   }
 
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoP.td b/llvm/lib/Target/RISCV/RISCVInstrInfoP.td
index ac893d83cf3ac..ceece53cb51bc 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoP.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoP.td
@@ -1871,6 +1871,16 @@ def riscv_pmulsu_h_b00
     : RVSDNode<"PMULSU_H_B00", SDT_RISCVPackedWideningMulByHalves>;
 def riscv_pmulsu_w_h00
     : RVSDNode<"PMULSU_W_H00", SDT_RISCVPackedWideningMulByHalves>;
+def riscv_pmul_h_b00
+    : RVSDNode<"PMUL_H_B00", SDT_RISCVPackedWideningMulByHalves>;
+def riscv_pmul_h_b11
+    : RVSDNode<"PMUL_H_B11", SDT_RISCVPackedWideningMulByHalves>;
+def riscv_pmulu_h_b00
+    : RVSDNode<"PMULU_H_B00", SDT_RISCVPackedWideningMulByHalves>;
+def riscv_pmulu_h_b11
+    : RVSDNode<"PMULU_H_B11", SDT_RISCVPackedWideningMulByHalves>;
+def riscv_pmulsu_h_b11
+    : RVSDNode<"PMULSU_H_B11", SDT_RISCVPackedWideningMulByHalves>;
 
 def SDT_RISCVWideningShiftLeft : SDTypeProfile<2, 2, [SDTCisVT<0, i32>,
                                                       SDTCisSameAs<0, 1>,
@@ -2878,17 +2888,18 @@ let append Predicates = [IsRV64] in {
   def : Pat<(v2i32 (riscv_pmulsu_w_h00 (v4i16 GPR:$rs1), (v4i16 GPR:$rs2))),
             (PMULSU_W_H00 GPR:$rs1, GPR:$rs2)>;
 
-  // 8-bit multiply high patterns
-  // FIXME custom lower
-  def : Pat<(v8i8 (mulhs GPR:$rs1, GPR:$rs2)),
-            (PPAIRO_B (PMUL_H_B00 GPR:$rs1, GPR:$rs2),
-                      (PMUL_H_B11 GPR:$rs1, GPR:$rs2))>;
-  def : Pat<(v8i8 (mulhu GPR:$rs1, GPR:$rs2)),
-            (PPAIRO_B (PMULU_H_B00 GPR:$rs1, GPR:$rs2),
-                      (PMULU_H_B11 GPR:$rs1, GPR:$rs2))>;
-  def : Pat<(v8i8 (riscv_mulhsu GPR:$rs1, GPR:$rs2)),
-            (PPAIRO_B (PMULSU_H_B00 GPR:$rs1, GPR:$rs2),
-                      (PMULSU_H_B11 GPR:$rs1, GPR:$rs2))>;
+  // 8-bit multiply high patterns. The mulhs/mulhu/mulhsu themselves are
+  // custom-lowered to riscv_pmul(u|su)_h_b00/b11 + riscv_ppairo.
+  def : Pat<(v4i16 (riscv_pmul_h_b00 (v8i8 GPR:$rs1), (v8i8 GPR:$rs2))),
+            (PMUL_H_B00 GPR:$rs1, GPR:$rs2)>;
+  def : Pat<(v4i16 (riscv_pmul_h_b11 (v8i8 GPR:$rs1), (v8i8 GPR:$rs2))),
+            (PMUL_H_B11 GPR:$rs1, GPR:$rs2)>;
+  def : Pat<(v4i16 (riscv_pmulu_h_b00 (v8i8 GPR:$rs1), (v8i8 GPR:$rs2))),
+            (PMULU_H_B00 GPR:$rs1, GPR:$rs2)>;
+  def : Pat<(v4i16 (riscv_pmulu_h_b11 (v8i8 GPR:$rs1), (v8i8 GPR:$rs2))),
+            (PMULU_H_B11 GPR:$rs1, GPR:$rs2)>;
+  def : Pat<(v4i16 (riscv_pmulsu_h_b11 (v8i8 GPR:$rs1), (v8i8 GPR:$rs2))),
+            (PMULSU_H_B11 GPR:$rs1, GPR:$rs2)>;
 
   // 32-bit logical shift left/right patterns
   def : PatGprImm<riscv_pshl, PSLLI_W, uimm5, v2i32>;



More information about the llvm-commits mailing list