[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