https://gcc.gnu.org/g:cd8f2706b8df99bce312f9be5b8ae577e8f889c5
commit cd8f2706b8df99bce312f9be5b8ae577e8f889c5 Author: Jeevitha <[email protected]> Date: Wed Jul 8 06:03:17 2026 -0500 rs6000: Add TDOmode move patterns Add support for moving TDOmode (1024-bit Dense Math Register) objects between memory, VSX registers, and Dense Math Registers. Diff: --- gcc/config/rs6000/mma.md | 85 +++++++++++++++++++++++++++++++++++ gcc/config/rs6000/rs6000-builtin.cc | 3 +- gcc/config/rs6000/rs6000-builtins.def | 6 +++ gcc/config/rs6000/rs6000.cc | 23 ++++++---- 4 files changed, 107 insertions(+), 10 deletions(-) diff --git a/gcc/config/rs6000/mma.md b/gcc/config/rs6000/mma.md index 5f15e3b2e8f6..07274bc54d05 100644 --- a/gcc/config/rs6000/mma.md +++ b/gcc/config/rs6000/mma.md @@ -92,6 +92,7 @@ UNSPEC_MMA_XXMFACC UNSPEC_MMA_XXMTACC UNSPEC_DM_INSERT512 + UNSPEC_DMF_EXTRACT512 UNSPEC_DMF_INSERT1024 UNSPEC_DMF_DMXOR UNSPEC_DMF_DMXVI8GERX4 @@ -476,6 +477,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,%Y0,%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 == 4) + 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 plain 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-builtin.cc b/gcc/config/rs6000/rs6000-builtin.cc index 1cf6976cb7b4..e16ebb54065b 100644 --- a/gcc/config/rs6000/rs6000-builtin.cc +++ b/gcc/config/rs6000/rs6000-builtin.cc @@ -1130,7 +1130,8 @@ rs6000_gimple_fold_mma_builtin (gimple_stmt_iterator *gsi, already expanded it! Exceptions: lxvp and stxvp. */ if (rs6000_builtin_info[fncode].assoc_bif == RS6000_BIF_NONE && fncode != RS6000_BIF_LXVP - && fncode != RS6000_BIF_STXVP) + && fncode != RS6000_BIF_STXVP + && fncode != RS6000_BIF_DMMR) return false; bifdata *bd = &rs6000_builtin_info[fncode]; diff --git a/gcc/config/rs6000/rs6000-builtins.def b/gcc/config/rs6000/rs6000-builtins.def index e4183d847508..dc39ef2e5262 100644 --- a/gcc/config/rs6000/rs6000-builtins.def +++ b/gcc/config/rs6000/rs6000-builtins.def @@ -4050,6 +4050,12 @@ dmr1024 __builtin_dmsetdmrz_internal (); DMSETDMRZ_INTERNAL dmf_dmsetdmrz {dm} + void __builtin_dmmr (dmr1024 *, dmr1024 *); + DMMR nothing {dm,dmint} + + dmr1024 __builtin_dmmr_internal (dmr1024); + DMMR_INTERNAL movtdo {dm} + void __builtin_dmxor (dmr1024 *, dmr1024 *); DMXOR nothing {dm,dmint,dmr} diff --git a/gcc/config/rs6000/rs6000.cc b/gcc/config/rs6000/rs6000.cc index 7017c2d3d43a..09a453efcb39 100644 --- a/gcc/config/rs6000/rs6000.cc +++ b/gcc/config/rs6000/rs6000.cc @@ -11294,6 +11294,11 @@ 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 */ @@ -27584,9 +27589,9 @@ 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; @@ -27594,7 +27599,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 : @@ -27646,7 +27651,7 @@ rs6000_split_multireg_move (rtx dst, rtx src) 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); @@ -27784,8 +27789,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--) { @@ -27960,8 +27965,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);
