[llvm] [Mips] Implement MIPS64R6 preferred sequence for 64-bit MSA constant splats (PR #204986)

via llvm-commits llvm-commits at lists.llvm.org
Sun Jun 21 08:44:29 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-backend-mips

Author: AZero13 (AZero13)

<details>
<summary>Changes</summary>

This PR resolves a `FIXME` in `MipsSEISelDAGToDAG.cpp` by implementing the preferred MIPS64R6 instruction sequence (`ori`, `daui`, `dahi`, `dati`, `fill.d`) for materializing 64-bit constant vector splats.

---
Full diff: https://github.com/llvm/llvm-project/pull/204986.diff


2 Files Affected:

- (modified) llvm/lib/Target/Mips/MipsSEISelDAGToDAG.cpp (+95-66) 
- (added) llvm/test/CodeGen/Mips/msa/r6_constant_splat.ll (+66) 


``````````diff
diff --git a/llvm/lib/Target/Mips/MipsSEISelDAGToDAG.cpp b/llvm/lib/Target/Mips/MipsSEISelDAGToDAG.cpp
index 8c60824a42a26..a716106c44827 100644
--- a/llvm/lib/Target/Mips/MipsSEISelDAGToDAG.cpp
+++ b/llvm/lib/Target/Mips/MipsSEISelDAGToDAG.cpp
@@ -1218,88 +1218,117 @@ bool MipsSEDAGToDAGISel::trySelect(SDNode *Node) {
       //        bits that's a negative number we can do better than LUi/ORi
       //        for the upper 32bits.
 
-      if (Hi)
-        Res = CurDAG->getMachineNode(Mips::LUi, DL, MVT::i32, HiVal);
+      if (Subtarget->hasMips64r6() && (ABI.IsN64() || ABI.IsN32())) {
+        uint64_t Val = SplatValue.getZExtValue();
+        const unsigned R6Lo = Val & 0xFFFF;
+        uint64_t Remainder = Val - R6Lo;
+        const unsigned R6Hi = (Remainder >> 16) & 0xFFFF;
+        Remainder -= SignExtend64<16>(R6Hi) << 16;
+        const unsigned R6Higher = (Remainder >> 32) & 0xFFFF;
+        Remainder -= SignExtend64<16>(R6Higher) << 32;
+        const unsigned R6Highest = (Remainder >> 48) & 0xFFFF;
+
+        SDValue R6LoVal = CurDAG->getTargetConstant(R6Lo, DL, MVT::i64);
+        SDValue R6HiVal = CurDAG->getTargetConstant(R6Hi, DL, MVT::i64);
+        SDValue R6HigherVal = CurDAG->getTargetConstant(R6Higher, DL, MVT::i64);
+        SDValue R6HighestVal = CurDAG->getTargetConstant(R6Highest, DL, MVT::i64);
+        SDValue Zero64Val = CurDAG->getRegister(Mips::ZERO_64, MVT::i64);
 
-      if (Lo)
-        Res = CurDAG->getMachineNode(Mips::ORi, DL, MVT::i32,
-                                     Hi ? SDValue(Res, 0) : ZeroVal, LoVal);
+        Res = CurDAG->getMachineNode(Mips::ORi64, DL, MVT::i64, Zero64Val, R6LoVal);
 
-      SDNode *HiRes;
-      if (Highest)
-        HiRes = CurDAG->getMachineNode(Mips::LUi, DL, MVT::i32, HighestVal);
+        if (R6Hi)
+          Res = CurDAG->getMachineNode(Mips::DAUI, DL, MVT::i64, SDValue(Res, 0), R6HiVal);
 
-      if (Higher)
-        HiRes = CurDAG->getMachineNode(Mips::ORi, DL, MVT::i32,
-                                       Highest ? SDValue(HiRes, 0) : ZeroVal,
-                                       HigherVal);
+        if (R6Higher)
+          Res = CurDAG->getMachineNode(Mips::DAHI, DL, MVT::i64, SDValue(Res, 0), R6HigherVal);
 
+        if (R6Highest)
+          Res = CurDAG->getMachineNode(Mips::DATI, DL, MVT::i64, SDValue(Res, 0), R6HighestVal);
 
-      if (ABI.IsO32()) {
-        Res = CurDAG->getMachineNode(Mips::FILL_W, DL, MVT::v4i32,
-                                     (Hi || Lo) ? SDValue(Res, 0) : ZeroVal);
+        Res = CurDAG->getMachineNode(Mips::FILL_D, DL, MVT::v2i64, SDValue(Res, 0));
+      } else {
+        if (Hi)
+          Res = CurDAG->getMachineNode(Mips::LUi, DL, MVT::i32, HiVal);
 
-        Res = CurDAG->getMachineNode(
-            Mips::INSERT_W, DL, MVT::v4i32, SDValue(Res, 0),
-            (Highest || Higher) ? SDValue(HiRes, 0) : ZeroVal,
-            CurDAG->getTargetConstant(1, DL, MVT::i32));
+        if (Lo)
+          Res = CurDAG->getMachineNode(Mips::ORi, DL, MVT::i32,
+                                       Hi ? SDValue(Res, 0) : ZeroVal, LoVal);
 
-        const TargetLowering *TLI = getTargetLowering();
-        const TargetRegisterClass *RC =
-            TLI->getRegClassFor(ViaVecTy.getSimpleVT());
+        SDNode *HiRes;
+        if (Highest)
+          HiRes = CurDAG->getMachineNode(Mips::LUi, DL, MVT::i32, HighestVal);
 
-        Res = CurDAG->getMachineNode(
-            Mips::COPY_TO_REGCLASS, DL, ViaVecTy, SDValue(Res, 0),
-            CurDAG->getTargetConstant(RC->getID(), DL, MVT::i32));
+        if (Higher)
+          HiRes = CurDAG->getMachineNode(Mips::ORi, DL, MVT::i32,
+                                         Highest ? SDValue(HiRes, 0) : ZeroVal,
+                                         HigherVal);
 
-        Res = CurDAG->getMachineNode(
-            Mips::SPLATI_D, DL, MVT::v2i64, SDValue(Res, 0),
-            CurDAG->getTargetConstant(0, DL, MVT::i32));
-      } else if (ABI.IsN64() || ABI.IsN32()) {
+        if (ABI.IsO32()) {
+          Res = CurDAG->getMachineNode(Mips::FILL_W, DL, MVT::v4i32,
+                                       (Hi || Lo) ? SDValue(Res, 0) : ZeroVal);
 
-        SDValue Zero64Val = CurDAG->getRegister(Mips::ZERO_64, MVT::i64);
-        const bool HiResNonZero = Highest || Higher;
-        const bool ResNonZero = Hi || Lo;
+          Res = CurDAG->getMachineNode(
+              Mips::INSERT_W, DL, MVT::v4i32, SDValue(Res, 0),
+              (Highest || Higher) ? SDValue(HiRes, 0) : ZeroVal,
+              CurDAG->getTargetConstant(1, DL, MVT::i32));
 
-        if (HiResNonZero)
-          HiRes = CurDAG->getMachineNode(
-              Mips::SUBREG_TO_REG, DL, MVT::i64, SDValue(HiRes, 0),
-              CurDAG->getTargetConstant(Mips::sub_32, DL, MVT::i64));
+          const TargetLowering *TLI = getTargetLowering();
+          const TargetRegisterClass *RC =
+              TLI->getRegClassFor(ViaVecTy.getSimpleVT());
 
-        if (ResNonZero)
           Res = CurDAG->getMachineNode(
-              Mips::SUBREG_TO_REG, DL, MVT::i64, SDValue(Res, 0),
-              CurDAG->getTargetConstant(Mips::sub_32, DL, MVT::i64));
-
-        // We have 3 cases:
-        //   The HiRes is nonzero but Res is $zero  => dsll32 HiRes, 0
-        //   The Res is nonzero but HiRes is $zero  => dinsu Res, $zero, 32, 32
-        //   Both are non zero                      => dinsu Res, HiRes, 32, 32
-        //
-        // The obvious "missing" case is when both are zero, but that case is
-        // handled by the ldi case.
-        if (ResNonZero) {
-          IntegerType *Int32Ty =
-              IntegerType::get(MF->getFunction().getContext(), 32);
-          const ConstantInt *Const32 = ConstantInt::get(Int32Ty, 32);
-          SDValue Ops[4] = {HiResNonZero ? SDValue(HiRes, 0) : Zero64Val,
-                            CurDAG->getConstant(*Const32, DL, MVT::i32),
-                            CurDAG->getConstant(*Const32, DL, MVT::i32),
-                            SDValue(Res, 0)};
-
-          Res = CurDAG->getMachineNode(Mips::DINSU, DL, MVT::i64, Ops);
-        } else if (HiResNonZero) {
+              Mips::COPY_TO_REGCLASS, DL, ViaVecTy, SDValue(Res, 0),
+              CurDAG->getTargetConstant(RC->getID(), DL, MVT::i32));
+
           Res = CurDAG->getMachineNode(
-              Mips::DSLL32, DL, MVT::i64, SDValue(HiRes, 0),
+              Mips::SPLATI_D, DL, MVT::v2i64, SDValue(Res, 0),
               CurDAG->getTargetConstant(0, DL, MVT::i32));
+        } else if (ABI.IsN64() || ABI.IsN32()) {
+
+          SDValue Zero64Val = CurDAG->getRegister(Mips::ZERO_64, MVT::i64);
+          const bool HiResNonZero = Highest || Higher;
+          const bool ResNonZero = Hi || Lo;
+
+          if (HiResNonZero)
+            HiRes = CurDAG->getMachineNode(
+                Mips::SUBREG_TO_REG, DL, MVT::i64, SDValue(HiRes, 0),
+                CurDAG->getTargetConstant(Mips::sub_32, DL, MVT::i64));
+
+          if (ResNonZero)
+            Res = CurDAG->getMachineNode(
+                Mips::SUBREG_TO_REG, DL, MVT::i64, SDValue(Res, 0),
+                CurDAG->getTargetConstant(Mips::sub_32, DL, MVT::i64));
+
+          // We have 3 cases:
+          //   The HiRes is nonzero but Res is $zero  => dsll32 HiRes, 0
+          //   The Res is nonzero but HiRes is $zero  => dinsu Res, $zero, 32, 32
+          //   Both are non zero                      => dinsu Res, HiRes, 32, 32
+          //
+          // The obvious "missing" case is when both are zero, but that case is
+          // handled by the ldi case.
+          if (ResNonZero) {
+            IntegerType *Int32Ty =
+                IntegerType::get(MF->getFunction().getContext(), 32);
+            const ConstantInt *Const32 = ConstantInt::get(Int32Ty, 32);
+            SDValue Ops[4] = {HiResNonZero ? SDValue(HiRes, 0) : Zero64Val,
+                              CurDAG->getConstant(*Const32, DL, MVT::i32),
+                              CurDAG->getConstant(*Const32, DL, MVT::i32),
+                              SDValue(Res, 0)};
+
+            Res = CurDAG->getMachineNode(Mips::DINSU, DL, MVT::i64, Ops);
+          } else if (HiResNonZero) {
+            Res = CurDAG->getMachineNode(
+                Mips::DSLL32, DL, MVT::i64, SDValue(HiRes, 0),
+                CurDAG->getTargetConstant(0, DL, MVT::i32));
+          } else
+            llvm_unreachable(
+                "Zero splat value handled by non-zero 64bit splat synthesis!");
+
+          Res = CurDAG->getMachineNode(Mips::FILL_D, DL, MVT::v2i64,
+                                       SDValue(Res, 0));
         } else
-          llvm_unreachable(
-              "Zero splat value handled by non-zero 64bit splat synthesis!");
-
-        Res = CurDAG->getMachineNode(Mips::FILL_D, DL, MVT::v2i64,
-                                     SDValue(Res, 0));
-      } else
-        llvm_unreachable("Unknown ABI in MipsISelDAGToDAG!");
+          llvm_unreachable("Unknown ABI in MipsISelDAGToDAG!");
+      }
 
     } else
       return false;
diff --git a/llvm/test/CodeGen/Mips/msa/r6_constant_splat.ll b/llvm/test/CodeGen/Mips/msa/r6_constant_splat.ll
new file mode 100644
index 0000000000000..d51a949f2439b
--- /dev/null
+++ b/llvm/test/CodeGen/Mips/msa/r6_constant_splat.ll
@@ -0,0 +1,66 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc -mtriple=mips64 -mcpu=mips64r6 -mattr=+msa,+fp64 < %s | FileCheck %s
+
+ at v2i64 = global <2 x i64> <i64 0, i64 0>
+
+define void @splat_edge1() nounwind {
+; CHECK-LABEL: splat_edge1:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    lui $1, %highest(v2i64)
+; CHECK-NEXT:    daddiu $1, $1, %higher(v2i64)
+; CHECK-NEXT:    dsll $1, $1, 16
+; CHECK-NEXT:    daddiu $1, $1, %hi(v2i64)
+; CHECK-NEXT:    dsll $1, $1, 16
+; CHECK-NEXT:    daddiu $1, $1, %lo(v2i64)
+; CHECK-NEXT:    ori $2, $zero, 32769
+; CHECK-NEXT:    daui $2, $2, 32768
+; CHECK-NEXT:    dahi $2, $2, 32769
+; CHECK-NEXT:    dati $2, $2, 32769
+; CHECK-NEXT:    fill.d $w0, $2
+; CHECK-NEXT:    jr $ra
+; CHECK-NEXT:    st.d $w0, 0($1)
+entry:
+  store volatile <2 x i64> <i64 9223512776490647553, i64 9223512776490647553>, ptr @v2i64 ; 0x8000800080008001
+  ret void
+}
+
+define void @splat_edge2() nounwind {
+; CHECK-LABEL: splat_edge2:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    lui $1, %highest(v2i64)
+; CHECK-NEXT:    daddiu $1, $1, %higher(v2i64)
+; CHECK-NEXT:    dsll $1, $1, 16
+; CHECK-NEXT:    daddiu $1, $1, %hi(v2i64)
+; CHECK-NEXT:    dsll $1, $1, 16
+; CHECK-NEXT:    daddiu $1, $1, %lo(v2i64)
+; CHECK-NEXT:    ori $2, $zero, 32768
+; CHECK-NEXT:    daui $2, $2, 65535
+; CHECK-NEXT:    dahi $2, $2, 1
+; CHECK-NEXT:    fill.d $w0, $2
+; CHECK-NEXT:    jr $ra
+; CHECK-NEXT:    st.d $w0, 0($1)
+entry:
+  store volatile <2 x i64> <i64 4294934528, i64 4294934528>, ptr @v2i64 ; 0x00000000FFFF8000
+  ret void
+}
+
+define void @splat_generic() nounwind {
+; CHECK-LABEL: splat_generic:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    lui $1, %highest(v2i64)
+; CHECK-NEXT:    daddiu $1, $1, %higher(v2i64)
+; CHECK-NEXT:    dsll $1, $1, 16
+; CHECK-NEXT:    daddiu $1, $1, %hi(v2i64)
+; CHECK-NEXT:    dsll $1, $1, 16
+; CHECK-NEXT:    daddiu $1, $1, %lo(v2i64)
+; CHECK-NEXT:    ori $2, $zero, 57072
+; CHECK-NEXT:    daui $2, $2, 39612
+; CHECK-NEXT:    dahi $2, $2, 22137
+; CHECK-NEXT:    dati $2, $2, 4660
+; CHECK-NEXT:    fill.d $w0, $2
+; CHECK-NEXT:    jr $ra
+; CHECK-NEXT:    st.d $w0, 0($1)
+entry:
+  store volatile <2 x i64> <i64 1311768467463790320, i64 1311768467463790320>, ptr @v2i64 ; 0x123456789abcdef0
+  ret void
+}

``````````

</details>


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


More information about the llvm-commits mailing list