Hello,
Below patch is bootstrapped and regtested on Power64le-linux-gnu.
Thank You,
Kishan
A future PowerPC processor may provide the Dense Math Facility (DMF),
where accumulators are backed by dedicated Dense Math Registers (DMRs)
instead of aliased VSX/FPR registers. Since DMRs do not require
priming or depriming, xxmtacc/xxmfacc become no-op operations.
Update accumulator assembly to build accumulators in DMRs using DMR
insert operations instead of relying on aliased VSX/FPR registers.
Enable the required OOmode VSX pair patterns under TARGET_DMF and avoid
emitting xxmtacc/xxmfacc during internal accumulator moves and GIMPLE
folding when DMF is enabled.
This patch depends on the following prerequisite patches and can be
upstream after they have been upstreamed:
rs6000: Add support for Dense Math Facility (DMF) registers
https://patchwork.ozlabs.org/project/gcc/patch/
[email protected]/
rs6000: Add the __dmr1024 opaque type
https://patchwork.ozlabs.org/project/gcc/patch/
[email protected]/
rs6000: Add %wD constraint and predicate for accumulators
https://patchwork.ozlabs.org/project/gcc/patch/
[email protected]/
[PATCH v3] rs6000: Add Dense Math builtin infrastructure
https://patchwork.ozlabs.org/project/gcc/patch/
[email protected]/
[PATCH v2] rs6000: Add Dense Math (DMF/MMA+) built-in/instruction
support
https://patchwork.ozlabs.org/project/gcc/patch/
[email protected]/
2026-07-14 Kishan Parmar <[email protected]>
gcc/ChangeLog:
* config/rs6000/mma.md (movoo): Enable for TARGET_DMF.
(*movoo): Likewise.
(vsx_assemble_pair): Likewise.
(*vsx_assemble_pair): Likewise.
(vsx_disassemble_pair): Likewise.
(*vsx_disassemble_pair): Likewise.
(mma_assemble_acc): Use accumulator_operand.
Build accumulators via DMR insert operations when TARGET_DMF.
(*mma_assemble_acc): Use accumulator_operand.
(mma_<acc>): New define_expand treating xxmtacc/xxmfacc as no-ops
for TARGET_DMF.
(*mma_<acc>): Restrict to !TARGET_DMF and use accumulator_operand.
(mma_disassemble_acc): Use accumulator_operand.
* config/rs6000/rs6000-builtin.cc (rs6000_gimple_fold_mma_builtin): Do
not emit xxmfacc for DISASSEMBLE_ACC when TARGET_DMF.
* config/rs6000/rs6000.cc (rs6000_hard_regno_mode_ok_uncached): Allow
OOmode in VSX register pairs for TARGET_DMF.
(rs6000_split_multireg_move): Avoid emitting xxmtacc/xxmfacc when
TARGET_DMF.
gcc/testsuite/ChangeLog:
* gcc.target/powerpc/future-dmf-xxacc.c: New test.
* gcc.target/powerpc/future-nodmf-xxacc.c: New test.
---
gcc/config/rs6000/mma.md | 72 +++++++++++++------
gcc/config/rs6000/rs6000-builtin.cc | 2 +-
gcc/config/rs6000/rs6000.cc | 37 ++++++----
.../gcc.target/powerpc/future-dmf-xxacc.c | 18 +++++
.../gcc.target/powerpc/future-nodmf-xxacc.c | 18 +++++
5 files changed, 111 insertions(+), 36 deletions(-)
create mode 100644 gcc/testsuite/gcc.target/powerpc/future-dmf-xxacc.c
create mode 100644 gcc/testsuite/gcc.target/powerpc/future-nodmf-xxacc.c
diff --git a/gcc/config/rs6000/mma.md b/gcc/config/rs6000/mma.md
index 7f0c26c6eb5..85c4fcbfc62 100644
--- a/gcc/config/rs6000/mma.md
+++ b/gcc/config/rs6000/mma.md
@@ -298,7 +298,7 @@ (define_expand "movoo"
(match_operand:OO 1 "input_operand"))]
""
{
- if (TARGET_MMA)
+ if (TARGET_MMA || TARGET_DMF)
{
rs6000_emit_move (operands[0], operands[1], OOmode);
DONE;
@@ -323,7 +323,7 @@ (define_expand "movoo"
(define_insn_and_split "*movoo"
[(set (match_operand:OO 0 "nonimmediate_operand" "=wa,ZwO,wa")
(match_operand:OO 1 "input_operand" "ZwO,wa,wa"))]
- "TARGET_MMA
+ "(TARGET_MMA || TARGET_DMF)
&& (gpc_reg_operand (operands[0], OOmode)
|| gpc_reg_operand (operands[1], OOmode))"
"@
@@ -391,7 +391,7 @@ (define_expand "vsx_assemble_pair"
[(match_operand:OO 0 "vsx_register_operand")
(match_operand:V16QI 1 "mma_assemble_input_operand")
(match_operand:V16QI 2 "mma_assemble_input_operand")]
- "TARGET_MMA"
+ "TARGET_MMA || TARGET_DMF"
{
rtx src = gen_rtx_UNSPEC (OOmode,
gen_rtvec (2, operands[1], operands[2]),
@@ -408,7 +408,7 @@ (define_insn_and_split "*vsx_assemble_pair"
(unspec:OO [(match_operand:V16QI 1 "mma_assemble_input_operand" "mwa")
(match_operand:V16QI 2 "mma_assemble_input_operand" "mwa")]
UNSPEC_VSX_ASSEMBLE))]
- "TARGET_MMA"
+ "TARGET_MMA || TARGET_DMF"
"#"
"&& reload_completed"
[(const_int 0)]
@@ -424,7 +424,7 @@ (define_expand "vsx_disassemble_pair"
[(match_operand:V16QI 0 "mma_disassemble_output_operand")
(match_operand:OO 1 "vsx_register_operand")
(match_operand 2 "const_0_to_1_operand")]
- "TARGET_MMA"
+ "TARGET_MMA || TARGET_DMF"
{
rtx src;
int regoff = INTVAL (operands[2]);
@@ -440,7 +440,7 @@ (define_insn_and_split "*vsx_disassemble_pair"
(unspec:V16QI [(match_operand:OO 1 "vsx_register_operand" "wa")
(match_operand 2 "const_0_to_1_operand")]
UNSPEC_MMA_EXTRACT))]
- "TARGET_MMA
+ "(TARGET_MMA || TARGET_DMF)
&& vsx_register_operand (operands[1], OOmode)"
"#"
"&& reload_completed"
@@ -477,18 +477,29 @@ (define_insn "dm_insert1024"
[(set_attr "type" "dmf")])
(define_expand "mma_assemble_acc"
- [(match_operand:XO 0 "fpr_reg_operand")
+ [(match_operand:XO 0 "accumulator_operand")
(match_operand:V16QI 1 "mma_assemble_input_operand")
(match_operand:V16QI 2 "mma_assemble_input_operand")
(match_operand:V16QI 3 "mma_assemble_input_operand")
(match_operand:V16QI 4 "mma_assemble_input_operand")]
- "TARGET_MMA"
+ "TARGET_MMA || TARGET_DMF"
{
- rtx src = gen_rtx_UNSPEC_VOLATILE (XOmode,
- gen_rtvec (4, operands[1], operands[2],
- operands[3], operands[4]),
- UNSPECV_MMA_ASSEMBLE);
- emit_move_insn (operands[0], src);
+ if (TARGET_DMF)
+ {
+ rtx vp0 = gen_reg_rtx (OOmode);
+ rtx vp1 = gen_reg_rtx (OOmode);
+ emit_insn (gen_vsx_assemble_pair (vp0, operands[1], operands[2]));
+ emit_insn (gen_vsx_assemble_pair (vp1, operands[3], operands[4]));
+ emit_insn (gen_dm_insert512 (operands[0], vp0, vp1, const0_rtx));
+ }
+ else
+ {
+ rtx src = gen_rtx_UNSPEC_VOLATILE (XOmode,
+ gen_rtvec (4, operands[1], operands[2],
+ operands[3], operands[4]),
+ UNSPECV_MMA_ASSEMBLE);
+ emit_move_insn (operands[0], src);
+ }
DONE;
})
@@ -496,7 +507,7 @@ (define_expand "mma_assemble_acc"
;; as an early clobber so we don't accidentally clobber the input operands. */
(define_insn_and_split "*mma_assemble_acc"
- [(set (match_operand:XO 0 "fpr_reg_operand" "=&d")
+ [(set (match_operand:XO 0 "accumulator_operand" "=&wD")
(unspec_volatile:XO
[(match_operand:V16QI 1 "mma_assemble_input_operand" "mwa")
(match_operand:V16QI 2 "mma_assemble_input_operand" "mwa")
@@ -504,7 +515,7 @@ (define_insn_and_split "*mma_assemble_acc"
(match_operand:V16QI 4 "mma_assemble_input_operand" "mwa")]
UNSPECV_MMA_ASSEMBLE))]
"TARGET_MMA
- && fpr_reg_operand (operands[0], XOmode)"
+ && accumulator_operand (operands[0], XOmode)"
"#"
"&& reload_completed"
[(const_int 0)]
@@ -543,7 +554,7 @@ (define_expand "dmf_build_dmr"
(define_expand "mma_disassemble_acc"
[(match_operand:V16QI 0 "mma_disassemble_output_operand")
- (match_operand:XO 1 "fpr_reg_operand")
+ (match_operand:XO 1 "accumulator_operand")
(match_operand 2 "const_0_to_3_operand")]
"TARGET_MMA"
{
@@ -574,15 +585,36 @@ (define_insn_and_split "*mma_disassemble_acc"
DONE;
})
+;; xxmtacc/xxmfacc prime/deprime an accumulator that lives in 4 adjacent
+;; FPRs -- they reformat that shared FPR/accumulator storage in place. On
+;; TARGET_DMF, DMRs are a register file entirely separate from the FPRs,
+;; so there is no such format to convert and these are a nop. This expand
+;; only exists so __builtin_mma_xxmfacc/xxmtacc (which always resolve to
+;; this pattern) correctly do nothing on TARGET_DMF instead of failing
+;; to match any insn.
+(define_expand "mma_<acc>"
+ [(set (match_operand:XO 0 "accumulator_operand")
+ (unspec:XO [(match_operand:XO 1 "accumulator_operand")]
+ MMA_ACC))]
+ "TARGET_MMA || TARGET_DMF"
+{
+ if (TARGET_DMF)
+ {
+ emit_move_insn (operands[0], operands[1]);
+ DONE;
+ }
+})
+
+
;; MMA instructions that do not use their accumulators as an input, still
;; must not allow their vector operands to overlap the registers used by
;; the accumulator. We enforce this by marking the output as early clobber.
-(define_insn "mma_<acc>"
- [(set (match_operand:XO 0 "fpr_reg_operand" "=&d")
- (unspec:XO [(match_operand:XO 1 "fpr_reg_operand" "0")]
+(define_insn "*mma_<acc>"
+ [(set (match_operand:XO 0 "accumulator_operand" "=&wD")
+ (unspec:XO [(match_operand:XO 1 "accumulator_operand" "0")]
MMA_ACC))]
- "TARGET_MMA"
+ "TARGET_MMA && !TARGET_DMF"
"<acc> %A0"
[(set_attr "type" "mma")])
diff --git a/gcc/config/rs6000/rs6000-builtin.cc
b/gcc/config/rs6000/rs6000-builtin.cc
index 95372aaac71..16cfa87c343 100644
--- a/gcc/config/rs6000/rs6000-builtin.cc
+++ b/gcc/config/rs6000/rs6000-builtin.cc
@@ -1180,7 +1180,7 @@ rs6000_gimple_fold_mma_builtin (gimple_stmt_iterator *gsi,
/* If we're disassembling an accumulator into a different type, we need
to emit a xxmfacc instruction now, since we cannot do it later. */
- if (fncode == RS6000_BIF_DISASSEMBLE_ACC)
+ if (fncode == RS6000_BIF_DISASSEMBLE_ACC && !TARGET_DMF)
{
new_decl = rs6000_builtin_decls[RS6000_BIF_XXMFACC_INTERNAL];
new_call = gimple_build_call (new_decl, 1, src);
diff --git a/gcc/config/rs6000/rs6000.cc b/gcc/config/rs6000/rs6000.cc
index 231d07caf20..4e2345644d8 100644
--- a/gcc/config/rs6000/rs6000.cc
+++ b/gcc/config/rs6000/rs6000.cc
@@ -1888,7 +1888,7 @@ rs6000_hard_regno_mode_ok_uncached (int regno,
machine_mode mode)
/* Vector pair modes need even/odd VSX register pairs. Only allow vector
registers. */
if (mode == OOmode)
- return (TARGET_MMA && VSX_REGNO_P (regno) && (regno & 1) == 0);
+ return ((TARGET_MMA || TARGET_DMF) && VSX_REGNO_P (regno) && (regno & 1)
== 0);
/* MMA accumulator modes need FPR registers divisible by 4.
If TARGET_DMF is true, XOmode value can be held in a DMR register. */
@@ -27584,8 +27584,9 @@ rs6000_split_multireg_move (rtx dst, rtx src)
unsigned size = GET_MODE_SIZE (reg_mode);
/* If we are reading an accumulator register, we have to
- deprime it before we can access it. */
- if (TARGET_MMA
+ deprime it before we can access it, unless we have dense math
+ registers, which do not need priming/depriming. */
+ if (TARGET_MMA && !TARGET_DMF
&& GET_MODE (src) == XOmode && FP_REGNO_P (REGNO (src)))
emit_insn (gen_mma_xxmfacc (src, src));
@@ -27618,8 +27619,9 @@ rs6000_split_multireg_move (rtx dst, rtx src)
}
/* If we are writing an accumulator register, we have to
- prime it after we've written it. */
- if (TARGET_MMA
+ prime it after we've written it, unless we have dense math
+ registers, which do not need priming/depriming. */
+ if (TARGET_MMA && !TARGET_DMF
&& GET_MODE (dst) == XOmode && FP_REGNO_P (REGNO (dst)))
emit_insn (gen_mma_xxmtacc (dst, dst));
@@ -27687,8 +27689,9 @@ rs6000_split_multireg_move (rtx dst, rtx src)
}
/* We are writing an accumulator register, so we have to
- prime it after we've written it. */
- if (GET_MODE (src) == XOmode)
+ prime it after we've written it, unless we have dense math
+ registers, which do not need priming/depriming. */
+ if (GET_MODE (src) == XOmode && !TARGET_DMF)
emit_insn (gen_mma_xxmtacc (dst, dst));
return;
@@ -27700,8 +27703,9 @@ rs6000_split_multireg_move (rtx dst, rtx src)
if (REG_P (src) && REG_P (dst) && (REGNO (src) < REGNO (dst)))
{
/* If we are reading an accumulator register, we have to
- deprime it before we can access it. */
- if (TARGET_MMA
+ deprime it before we can access it, unless we have dense math
+ registers, which do not need priming/depriming. */
+ if (TARGET_MMA && !TARGET_DMF
&& GET_MODE (src) == XOmode && FP_REGNO_P (REGNO (src)))
emit_insn (gen_mma_xxmfacc (src, src));
@@ -27728,8 +27732,9 @@ rs6000_split_multireg_move (rtx dst, rtx src)
}
/* If we are writing an accumulator register, we have to
- prime it after we've written it. */
- if (TARGET_MMA
+ prime it after we've written it, unless we have dense math
+ registers, which do not need priming/depriming. */
+ if (TARGET_MMA && !TARGET_DMF
&& GET_MODE (dst) == XOmode && FP_REGNO_P (REGNO (dst)))
emit_insn (gen_mma_xxmtacc (dst, dst));
}
@@ -27865,8 +27870,9 @@ rs6000_split_multireg_move (rtx dst, rtx src)
}
/* If we are reading an accumulator register, we have to
- deprime it before we can access it. */
- if (TARGET_MMA && REG_P (src)
+ deprime it before we can access it, unless we have dense math
+ registers, which do not need priming/depriming. */
+ if (TARGET_MMA && !TARGET_DMF && REG_P (src)
&& GET_MODE (src) == XOmode && FP_REGNO_P (REGNO (src)))
emit_insn (gen_mma_xxmfacc (src, src));
@@ -27897,8 +27903,9 @@ rs6000_split_multireg_move (rtx dst, rtx src)
}
/* If we are writing an accumulator register, we have to
- prime it after we've written it. */
- if (TARGET_MMA && REG_P (dst)
+ prime it after we've written it, unless we have dense math
+ registers, which do not need priming/depriming. */
+ if (TARGET_MMA && !TARGET_DMF && REG_P (dst)
&& GET_MODE (dst) == XOmode && FP_REGNO_P (REGNO (dst)))
emit_insn (gen_mma_xxmtacc (dst, dst));
diff --git a/gcc/testsuite/gcc.target/powerpc/future-dmf-xxacc.c
b/gcc/testsuite/gcc.target/powerpc/future-dmf-xxacc.c
new file mode 100644
index 00000000000..2242f6693d0
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/future-dmf-xxacc.c
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-mdejagnu-cpu=future -O2" } */
+/* { dg-require-effective-target powerpc_future_compile_ok } */
+
+void
+foo (__vector_quad *acc)
+{
+ __builtin_mma_xxmtacc (acc);
+}
+
+void
+bar (__vector_quad *acc)
+{
+ __builtin_mma_xxmfacc (acc);
+}
+
+/* { dg-final { scan-assembler-not {\mxxmtacc\M} } } */
+/* { dg-final { scan-assembler-not {\mxxmfacc\M} } } */
diff --git a/gcc/testsuite/gcc.target/powerpc/future-nodmf-xxacc.c
b/gcc/testsuite/gcc.target/powerpc/future-nodmf-xxacc.c
new file mode 100644
index 00000000000..a643dc5f638
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/future-nodmf-xxacc.c
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-mdejagnu-cpu=future -O2 -mno-dense-math" } */
+/* { dg-require-effective-target powerpc_future_compile_ok } */
+
+void
+foo (__vector_quad *acc)
+{
+ __builtin_mma_xxmtacc (acc);
+}
+
+void
+bar (__vector_quad *acc)
+{
+ __builtin_mma_xxmfacc (acc);
+}
+
+/* { dg-final { scan-assembler {\mxxmtacc\M} } } */
+/* { dg-final { scan-assembler {\mxxmfacc\M} } } */
--
2.52.0