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);
