https://gcc.gnu.org/g:67a92a8521d5ad033d1c4a3b59286e4f25ee3ab8

commit 67a92a8521d5ad033d1c4a3b59286e4f25ee3ab8
Author: Jeevitha <[email protected]>
Date:   Wed Jul 15 05:30:06 2026 -0500

    rs6000: Add TDOmode move patterns
    
    Add move support for the new TDOmode opaque type used to represent
    1024-bit Dense Math Registers that may be supported by future Power
    processors.
    
    Implement the movtdo pattern to support moves between memory, VSX
    registers, and Dense Math Registers. Memory moves and VSX
    register-to-register moves are handled by the generic multi-register
    splitter. Dense Math Register-to-Register moves use dmmr, while moves
    between VSX and Dense Math Registers are expanded using dm_insert1024
    and dm_extract512.
    
    2026-07-14  Jeevitha Palanisamy  <[email protected]>
    
    gcc/
            * config/rs6000/mma.md (UNSPEC_DMF_EXTRACT512): New unspec.
            (dm_extract512): New insn.
            (movtdo): New expander.
            (*movtdo): New insn_and_split to support TDOmode moves between
            memory, VSX registers, and Dense Math Registers.
            * config/rs6000/rs6000.cc (rs6000_emit_move): Diagnose constant
            assignments to TDOmode objects.
            (rs6000_split_multireg_move): Handle TDOmode when splitting
            multi-register moves.

Diff:
---
 gcc/config/rs6000/mma.md    | 85 +++++++++++++++++++++++++++++++++++++++++++++
 gcc/config/rs6000/rs6000.cc | 27 ++++++++------
 2 files changed, 102 insertions(+), 10 deletions(-)

diff --git a/gcc/config/rs6000/mma.md b/gcc/config/rs6000/mma.md
index 1fadc5cd8869..2b0736d86a64 100644
--- a/gcc/config/rs6000/mma.md
+++ b/gcc/config/rs6000/mma.md
@@ -92,6 +92,7 @@
    UNSPEC_MMA_XXMFACC
    UNSPEC_MMA_XXMTACC
    UNSPEC_DMF_INSERT512
+   UNSPEC_DMF_EXTRACT512
    UNSPEC_DMF_INSERT1024
   ])
 
@@ -450,6 +451,90 @@
   "dmxxinstdmr512 %0,%x1,%x2,0\n\tdmxxinstdmr512 %0,%x3,%x4,1"
   [(set_attr "type" "dmf")])
 
+(define_insn "dm_extract512"
+  [(set (match_operand:XO 0 "vsx_register_operand" "=wa")
+        (unspec:XO [(match_operand:TDO 1 "dmr_register_operand" "wD")
+                   (match_operand 2 "const_0_to_1_operand" "n")]
+                  UNSPEC_DMF_EXTRACT512))]
+  "TARGET_DMF"
+  "dmxxextfdmr512 %x0,%W0,%1,%2"
+  [(set_attr "type" "dmf")])
+
+;; TDO (1024-bit dense-math) move expander.
+(define_expand "movtdo"
+  [(set (match_operand:TDO 0 "nonimmediate_operand")
+        (match_operand:TDO 1 "input_operand"))]
+  "TARGET_DMF"
+{
+  rs6000_emit_move (operands[0], operands[1], TDOmode);
+  DONE;
+})
+
+(define_insn_and_split "*movtdo"
+  [(set (match_operand:TDO 0 "nonimmediate_operand" "=wa,m,wa,wD,wa,wD")
+        (match_operand:TDO 1 "input_operand"         "m,wa,wa,wD,wD,wa"))]
+  "TARGET_DMF
+   && (gpc_reg_operand (operands[0], TDOmode)
+       || gpc_reg_operand (operands[1], TDOmode))"
+{
+  if (which_alternative == 3)
+    return "dmmr %0,%1";
+  else
+    return "#";
+}
+"reload_completed
+ && (!dmr_register_operand (operands[0], TDOmode)
+     || !dmr_register_operand (operands[1], TDOmode))"
+  [(const_int 0)]
+{
+  rtx dst = operands[0];
+  rtx src = operands[1];
+
+  /* Memory-involving moves (alt 0/1) and wa<-wa VSX moves (alt 2)
+     both go through the generic multiregister splitter.  */
+  if (!REG_P (dst) || !REG_P (src)
+      || (VSX_REGNO_P (REGNO (dst)) && VSX_REGNO_P (REGNO (src))))
+    {
+      rs6000_split_multireg_move (dst, src);
+      DONE;
+    }
+
+  unsigned dst_regno = REGNO (dst);
+  unsigned src_regno = REGNO (src);
+  bool dst_is_dmr = DMR_REGNO_P (dst_regno);
+  bool src_is_dmr = DMR_REGNO_P (src_regno);
+  bool dst_is_vsx = VSX_REGNO_P (dst_regno);
+  bool src_is_vsx = VSX_REGNO_P (src_regno);
+
+  /* wD <- wD: already a dmmr move, nothing to split.  */
+  if (dst_is_dmr && src_is_dmr)
+    DONE;
+
+  /* wD <- wa  */
+  if (dst_is_dmr && src_is_vsx)
+    {
+      rtx chunk0 = gen_rtx_REG (OOmode, src_regno);
+      rtx chunk1 = gen_rtx_REG (OOmode, src_regno + 2);
+      rtx chunk2 = gen_rtx_REG (OOmode, src_regno + 4);
+      rtx chunk3 = gen_rtx_REG (OOmode, src_regno + 6);
+
+      emit_insn (gen_dm_insert1024 (dst, chunk0, chunk1, chunk2, chunk3));
+      DONE;
+    }
+
+  /* wa <- wD  */
+  if (dst_is_vsx && src_is_dmr)
+    {
+      rtx chunk0 = gen_rtx_REG (XOmode, dst_regno);
+      rtx chunk1 = gen_rtx_REG (XOmode, dst_regno + 4);
+      emit_insn (gen_dm_extract512 (chunk0, src, const0_rtx));
+      emit_insn (gen_dm_extract512 (chunk1, src, const1_rtx));
+      DONE;
+    }
+
+  gcc_unreachable ();
+})
+
 (define_expand "mma_assemble_acc"
   [(match_operand:XO 0 "accumulator_operand")
    (match_operand:V16QI 1 "mma_assemble_input_operand")
diff --git a/gcc/config/rs6000/rs6000.cc b/gcc/config/rs6000/rs6000.cc
index f92ab14ac4a3..58103fd059b7 100644
--- a/gcc/config/rs6000/rs6000.cc
+++ b/gcc/config/rs6000/rs6000.cc
@@ -11298,6 +11298,12 @@ rs6000_emit_move (rtx dest, rtx source, machine_mode 
mode)
               (mode == OOmode) ? "__vector_pair" : "__vector_quad");
       break;
 
+    case E_TDOmode:
+      if (CONST_INT_P (operands[1]))
+       error ("%qs is an opaque type, and you cannot set it to constants",
+              "__dmr1024");
+      break;
+
     case E_SImode:
     case E_DImode:
       /* Use default pattern for address of ELF small data */
@@ -27531,9 +27537,10 @@ rs6000_split_multireg_move (rtx dst, rtx src)
   mode = GET_MODE (dst);
   nregs = hard_regno_nregs (reg, mode);
 
-  /* If we have a vector quad register for MMA, and this is a load or store,
-     see if we can use vector paired load/stores.  */
-  if (mode == XOmode && TARGET_MMA
+  /* If we have a vector quad register for MMA or DMR register for Dense Math,
+     and this is a load or store, see if we can use vector paired
+     load/stores.  */
+  if ((mode == XOmode || mode == TDOmode) && (TARGET_MMA || TARGET_DMF)
       && (MEM_P (dst) || MEM_P (src)))
     {
       reg_mode = OOmode;
@@ -27541,7 +27548,7 @@ rs6000_split_multireg_move (rtx dst, rtx src)
     }
   /* If we have a vector pair/quad mode, split it into two/four separate
      vectors.  */
-  else if (mode == OOmode || mode == XOmode)
+  else if (mode == OOmode || mode == XOmode || mode == TDOmode)
     reg_mode = V1TImode;
   else if (FP_REGNO_P (reg))
     reg_mode = DECIMAL_FLOAT_MODE_P (mode) ? DDmode :
@@ -27587,13 +27594,13 @@ rs6000_split_multireg_move (rtx dst, rtx src)
       return;
     }
 
-  /* The __vector_pair and __vector_quad modes are multi-register
+  /* The __vector_pair, __vector_quad and __dmr1024 modes are multi-register
      modes, so if we have to load or store the registers, we have to be
      careful to properly swap them if we're in little endian mode
      below.  This means the last register gets the first memory
      location.  We also need to be careful of using the right register
      numbers if we are splitting XO to OO.  */
-  if (mode == OOmode || mode == XOmode)
+  if (mode == OOmode || mode == XOmode || mode == TDOmode)
     {
       nregs = hard_regno_nregs (reg, mode);
       int reg_mode_nregs = hard_regno_nregs (reg, reg_mode);
@@ -27731,8 +27738,8 @@ rs6000_split_multireg_move (rtx dst, rtx src)
       /* Move register range backwards, if we might have destructive
         overlap.  */
       int i;
-      /* XO/OO are opaque so cannot use subregs. */
-      if (mode == OOmode || mode == XOmode )
+      /* XO/OO/TDO are opaque so cannot use subregs. */
+      if (mode == OOmode || mode == XOmode || mode == TDOmode)
        {
          for (i = nregs - 1; i >= 0; i--)
            {
@@ -27907,8 +27914,8 @@ rs6000_split_multireg_move (rtx dst, rtx src)
          if (j == 0 && used_update)
            continue;
 
-         /* XO/OO are opaque so cannot use subregs. */
-         if (mode == OOmode || mode == XOmode )
+         /* XO/OO/TDO are opaque so cannot use subregs. */
+         if (mode == OOmode || mode == XOmode || mode == TDOmode)
            {
              rtx dst_i = gen_rtx_REG (reg_mode, REGNO (dst) + j);
              rtx src_i = gen_rtx_REG (reg_mode, REGNO (src) + j);

Reply via email to