The following patch has been bootstrapped and regtested on powerpc64le.
Please review and approve for trunk & gcc 16.
The Dense Math Facility, which may be present in a future processor,
extends the Power architecture's computational capabilities by providing
eight dedicated registers (dmr0-dmr7) that can efficiently handle large
matrix operations. These registers will also be used in cryptographic
operations.
There are no operations to load/store Dense Math registers from/to
memory. For loading from memory, the 1024 bit value is first loaded into
8 VSX registers which are then copied into a DMR register. Similarly,
to store the contents of a DMR register into memory, the the contents
of the DMR are copied to 8 VSX registers which are then loaded into
memory.
Key Features:
1. Register Infrastructure:
- Adds 8 new DMR registers (dmr0-dmr7), numbered 111-118
- Each register is 1024 bits (128 bytes) in size
- Registers are call-used (caller-saved) following ABI conventions
- Increases total pseudo registers from 111 to 119
2. Data Type Support:
- TDOmode: New 1024-bit mode specifically for DMR operations
- XOmode: Extended to support both MMA accumulators (in FPRs) and
DMR registers, providing flexibility in register allocation
- Both modes support DMR registers when TARGET_DMF is enabled
3. Register Allocation:
- Integrated DMR_REGS into the register class hierarchy
- Added to register pressure classes for optimal allocation
- Implements proper register allocation ordering
- DMR registers can be allocated for XOmode and TDOmode values
4. Addressing and Memory Operations:
- Supports offset addressing mode for TDOmode values
- Implements secondary reload mechanisms for DMR ↔ VSX transfers
- Ensures proper alignment requirements (vector alignment)
5. Register Moves and Transfers:
- Enables simple moves between DMR and VSX registers
6. Debugging and Toolchain Support:
- Assigns debugger register numbers 112-119 for DMR registers
2027-07-13 Surya Kumari jangala <[email protected]>
gcc:
* config/rs6000/rs6000.cc (enum rs6000_reg_type): Add DMR_REG_TYPE.
(enum rs6000_reload_reg_type): Add RELOAD_REG_DMR.
(LAST_RELOAD_REG_CLASS): Update to RELOAD_REG_DMR.
(reload_reg_map): Add DMR entry.
(rs6000_reg_names): Add DMR register names.
(alt_reg_names): Add alternate DMR register names.
(rs6000_hard_regno_nregs_internal): Handle DMR registers.
(rs6000_hard_regno_mode_ok_uncached): Add TDOmode and XOmode support for
DMR registers.
(rs6000_debug_reg_global): Add TDOmode to debug modes and print DMR
register range.
(rs6000_setup_reg_addr_masks): Handle RELOAD_REG_DMR.
Allow offset loads for TDOmode values.
(rs6000_init_hard_regno_mode_ok): Add DMR_REGS to reg_class_to_reg_type
mapping.
Update precalculation of CLASS_MAX_NREGS.
(rs6000_secondary_reload_memory): Handle DMR_REGS class.
(rs6000_secondary_reload_simple_move): Add DMR to VSX moves.
(rs6000_preferred_reload_class): Handle DMR_REGS.
(rs6000_compute_pressure_classes): Add DMR_REGS when TARGET_DMF.
(rs6000_debugger_regno): Add DMR register numbering.
* config/rs6000/rs6000.h (UNITS_PER_DMR_WORD): Define as 128.
(FIRST_PSEUDO_REGISTER): Increase from 111 to 119.
(FIXED_REGISTERS): Add 8 DMR registers as non-fixed.
(CALL_USED_REGISTERS): Mark all DMR registers as call-used.
(REG_ALLOC_ORDER): Add DMR registers to allocation order.
(DMR_REGNO_P): New macro.
(VECTOR_ALIGNMENT_P): Add TDOmode.
(enum reg_class): Add DMR_REGS entry.
(REG_CLASS_CONTENTS): Add DMR_REGS bitmask.
(REGISTER_NAMES): Add dmr0-dmr7 register names.
(ADDITIONAL_REGISTER_NAMES): Add dmr0-dmr7 mappings.
* config/rs6000/rs6000.md (FIRST_DMR_REGNO): Define as 111.
(LAST_DMR_REGNO): Define as 118.
---
gcc/config/rs6000/rs6000.cc | 101 ++++++++++++++++++++++++++++++++----
gcc/config/rs6000/rs6000.h | 42 ++++++++++++---
gcc/config/rs6000/rs6000.md | 2 +
3 files changed, 129 insertions(+), 16 deletions(-)
diff --git a/gcc/config/rs6000/rs6000.cc b/gcc/config/rs6000/rs6000.cc
index 7743c9cdc4a..1d4d4e88bab 100644
--- a/gcc/config/rs6000/rs6000.cc
+++ b/gcc/config/rs6000/rs6000.cc
@@ -292,7 +292,8 @@ enum rs6000_reg_type {
ALTIVEC_REG_TYPE,
FPR_REG_TYPE,
SPR_REG_TYPE,
- CR_REG_TYPE
+ CR_REG_TYPE,
+ DMR_REG_TYPE
};
/* Map register class to register type. */
@@ -313,6 +314,7 @@ enum rs6000_reload_reg_type {
RELOAD_REG_GPR, /* General purpose registers. */
RELOAD_REG_FPR, /* Traditional floating point regs. */
RELOAD_REG_VMX, /* Altivec (VMX) registers. */
+ RELOAD_REG_DMR, /* Dense Math Facility registers. */
RELOAD_REG_ANY, /* OR of GPR, FPR, Altivec masks. */
N_RELOAD_REG
};
@@ -321,7 +323,7 @@ enum rs6000_reload_reg_type {
into real registers, and skip the ANY class, which is just an OR of the
bits. */
#define FIRST_RELOAD_REG_CLASS RELOAD_REG_GPR
-#define LAST_RELOAD_REG_CLASS RELOAD_REG_VMX
+#define LAST_RELOAD_REG_CLASS RELOAD_REG_DMR
/* Map reload register type to a register in the register class. */
struct reload_reg_map_type {
@@ -333,6 +335,7 @@ static const struct reload_reg_map_type
reload_reg_map[N_RELOAD_REG] = {
{ "Gpr", FIRST_GPR_REGNO }, /* RELOAD_REG_GPR. */
{ "Fpr", FIRST_FPR_REGNO }, /* RELOAD_REG_FPR. */
{ "VMX", FIRST_ALTIVEC_REGNO }, /* RELOAD_REG_VMX. */
+ { "DMR", FIRST_DMR_REGNO }, /* RELOAD_REG_DMR. */
{ "Any", -1 }, /* RELOAD_REG_ANY. */
};
@@ -1226,6 +1229,8 @@ char rs6000_reg_names[][8] =
"0", "1", "2", "3", "4", "5", "6", "7",
/* vrsave vscr sfp */
"vrsave", "vscr", "sfp",
+ /* DMRs */
+ "0", "1", "2", "3", "4", "5", "6", "7",
};
#ifdef TARGET_REGNAMES
@@ -1252,6 +1257,8 @@ static const char alt_reg_names[][8] =
"%cr0", "%cr1", "%cr2", "%cr3", "%cr4", "%cr5", "%cr6", "%cr7",
/* vrsave vscr sfp */
"vrsave", "vscr", "sfp",
+ /* DMRs */
+ "%dm0", "%dm1", "%dm2", "%dm3", "%dm4", "%dm5", "%dm6", "%dm7",
};
#endif
@@ -1842,6 +1849,9 @@ rs6000_hard_regno_nregs_internal (int regno, machine_mode
mode)
else if (ALTIVEC_REGNO_P (regno))
reg_size = UNITS_PER_ALTIVEC_WORD;
+ else if (DMR_REGNO_P (regno))
+ reg_size = UNITS_PER_DMR_WORD;
+
else
reg_size = UNITS_PER_WORD;
@@ -1858,14 +1868,33 @@ rs6000_hard_regno_mode_ok_uncached (int regno,
machine_mode mode)
if (COMPLEX_MODE_P (mode))
mode = GET_MODE_INNER (mode);
+ /* No other types other than XOmode or TDOmode can go in DMRs. */
+ if (DMR_REGNO_P (regno) && !(mode ==XOmode || mode == TDOmode))
+ return 0;
+
+ /* TDOmode value can be held in either 1 DMR register or 8 VSX
+ registers. */
+ if (mode == TDOmode)
+ {
+ if (TARGET_DMF)
+ return (DMR_REGNO_P (regno)
+ || (VSX_REGNO_P (regno)
+ && VSX_REGNO_P (last_regno)
+ && (regno & 1) == 0));
+ else
+ return 0;
+ }
+
/* 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);
- /* MMA accumulator modes need FPR registers divisible by 4. */
+ /* MMA accumulator modes need FPR registers divisible by 4.
+ If TARGET_DMF is true, XOmode value can be held in a DMR register. */
if (mode == XOmode)
- return (TARGET_MMA && FP_REGNO_P (regno) && (regno & 3) == 0);
+ return ((TARGET_DMF && DMR_REGNO_P (regno))
+ || (TARGET_MMA && FP_REGNO_P (regno) && (regno & 3) == 0));
/* PTImode can only go in GPRs. Quad word memory operations require even/odd
register combinations, and use PTImode where we need to deal with quad
@@ -2273,6 +2302,7 @@ rs6000_debug_reg_global (void)
V4DFmode,
OOmode,
XOmode,
+ TDOmode,
CCmode,
CCUNSmode,
CCEQmode,
@@ -2308,6 +2338,7 @@ rs6000_debug_reg_global (void)
rs6000_debug_reg_print (FIRST_ALTIVEC_REGNO,
LAST_ALTIVEC_REGNO,
"vs");
+ rs6000_debug_reg_print (FIRST_DMR_REGNO, LAST_DMR_REGNO, "dmr");
rs6000_debug_reg_print (LR_REGNO, LR_REGNO, "lr");
rs6000_debug_reg_print (CTR_REGNO, CTR_REGNO, "ctr");
rs6000_debug_reg_print (CR0_REGNO, CR7_REGNO, "cr");
@@ -2632,6 +2663,20 @@ rs6000_setup_reg_addr_masks (void)
addr_mask = 0;
reg = reload_reg_map[rc].reg;
+ if (rc == RELOAD_REG_DMR)
+ {
+ if (TARGET_DMF && (m2 == XOmode || m2 == TDOmode))
+ {
+ addr_mask = RELOAD_REG_VALID;
+ reg_addr[m].addr_mask[rc] = addr_mask;
+ any_addr_mask |= addr_mask;
+ }
+ else
+ reg_addr[m].addr_mask[rc] = 0;
+
+ continue;
+ }
+
/* Can mode values go in the GPR/FPR/Altivec registers? */
if (reg >= 0 && rs6000_hard_regno_mode_ok_p[m][reg])
{
@@ -2727,10 +2772,12 @@ rs6000_setup_reg_addr_masks (void)
/* Vector pairs can do both indexed and offset loads if the
instructions are enabled, otherwise they can only do offset loads
- since it will be broken into two vector moves. Vector quads can
- only do offset loads. */
- else if ((addr_mask != 0) && TARGET_MMA
- && (m2 == OOmode || m2 == XOmode))
+ since it will be broken into two vector moves. Vector quads and
+ dmr1024 type can only do offset loads. */
+ else if ((addr_mask != 0)
+ && ((TARGET_MMA && (m2 == OOmode || m2 == XOmode))
+ || (TARGET_DMF
+ && (m2 == TDOmode || m2 == OOmode || m2 ==
XOmode))))
{
addr_mask |= RELOAD_REG_OFFSET;
if (rc == RELOAD_REG_FPR || rc == RELOAD_REG_VMX)
@@ -2778,6 +2825,9 @@ rs6000_init_hard_regno_mode_ok (bool global_init_p)
for (r = FIRST_ALTIVEC_REGNO; r <= LAST_ALTIVEC_REGNO; ++r)
rs6000_regno_regclass[r] = ALTIVEC_REGS;
+ for (r = FIRST_DMR_REGNO; r <= LAST_DMR_REGNO; ++r)
+ rs6000_regno_regclass[r] = DMR_REGS;
+
rs6000_regno_regclass[CR0_REGNO] = CR0_REGS;
for (r = CR1_REGNO; r <= CR7_REGNO; ++r)
rs6000_regno_regclass[r] = CR_REGS;
@@ -2806,6 +2856,7 @@ rs6000_init_hard_regno_mode_ok (bool global_init_p)
reg_class_to_reg_type[(int)LINK_OR_CTR_REGS] = SPR_REG_TYPE;
reg_class_to_reg_type[(int)CR_REGS] = CR_REG_TYPE;
reg_class_to_reg_type[(int)CR0_REGS] = CR_REG_TYPE;
+ reg_class_to_reg_type[(int)DMR_REGS] = DMR_REG_TYPE;
if (TARGET_VSX)
{
@@ -3186,6 +3237,9 @@ rs6000_init_hard_regno_mode_ok (bool global_init_p)
else if (c == FLOAT_REGS)
reg_size = UNITS_PER_FP_WORD;
+ else if (c == DMR_REGS)
+ reg_size = UNITS_PER_DMR_WORD;
+
else
reg_size = UNITS_PER_WORD;
@@ -12365,6 +12419,15 @@ rs6000_secondary_reload_memory (rtx addr,
addr_mask = (reg_addr[mode].addr_mask[RELOAD_REG_VMX]
& ~RELOAD_REG_AND_M16);
+ /* DMR registers have no load/store instructions; memory access goes
+ through an intermediate VSX stage: DMR registers are first copied to
+ VSX registers which are then stored to memory, or value in memory is
+ first loaded into VSX registers which are then copied ot DMR registers.
+ Use the DMR addr_mask so the address-code checks below can determine
+ whether a scratch GPR is needed to simplify the address. */
+ else if (rclass == DMR_REGS)
+ addr_mask = reg_addr[mode].addr_mask[RELOAD_REG_DMR];
+
/* If the register allocator hasn't made up its mind yet on the register
class to use, settle on defaults to use. */
else if (rclass == NO_REGS)
@@ -12693,6 +12756,12 @@ rs6000_secondary_reload_simple_move (enum
rs6000_reg_type to_type,
|| (to_type == SPR_REG_TYPE && from_type == GPR_REG_TYPE)))
return true;
+ /* DMRs can be copied to VSX register, and vice versa. */
+ if (TARGET_DMF && (mode == XOmode || mode == TDOmode)
+ && ((to_type == DMR_REG_TYPE && from_type == VSX_REG_TYPE)
+ || (to_type == VSX_REG_TYPE && from_type == DMR_REG_TYPE)))
+ return true;
+
return false;
}
@@ -13387,6 +13456,10 @@ rs6000_preferred_reload_class (rtx x, enum reg_class
rclass)
machine_mode mode = GET_MODE (x);
bool is_constant = CONSTANT_P (x);
+ /* Values cannot be loaded into DMR registers. */
+ if (rclass == DMR_REGS)
+ return NO_REGS;
+
/* If a mode can't go in FPR/ALTIVEC/VSX registers, don't return a preferred
reload class for it. */
if ((rclass == ALTIVEC_REGS || rclass == VSX_REGS)
@@ -13483,7 +13556,10 @@ rs6000_preferred_reload_class (rtx x, enum reg_class
rclass)
return VSX_REGS;
if (mode == XOmode)
- return FLOAT_REGS;
+ return (TARGET_DMF ? VSX_REGS : FLOAT_REGS);
+
+ if (mode == TDOmode)
+ return VSX_REGS;
if (GET_MODE_CLASS (mode) == MODE_INT)
return GENERAL_REGS;
@@ -24088,6 +24164,8 @@ rs6000_compute_pressure_classes (enum reg_class
*pressure_classes)
if (TARGET_HARD_FLOAT)
pressure_classes[n++] = FLOAT_REGS;
}
+ if (TARGET_DMF)
+ pressure_classes[n++] = DMR_REGS;
pressure_classes[n++] = CR_REGS;
pressure_classes[n++] = SPECIAL_REGS;
@@ -24253,6 +24331,11 @@ rs6000_debugger_regno (unsigned int regno, unsigned
int format)
if (regno == 64)
return 64;
+ /* Note that the debug format register numbers may be changed
+ later. */
+ if (DMR_REGNO_P (regno))
+ return regno - FIRST_DMR_REGNO + 112;
+
gcc_unreachable ();
}
diff --git a/gcc/config/rs6000/rs6000.h b/gcc/config/rs6000/rs6000.h
index 8235e095bcc..7c417039d86 100644
--- a/gcc/config/rs6000/rs6000.h
+++ b/gcc/config/rs6000/rs6000.h
@@ -657,6 +657,7 @@ extern unsigned char rs6000_recip_bits[];
#define UNITS_PER_FP_WORD 8
#define UNITS_PER_ALTIVEC_WORD 16
#define UNITS_PER_VSX_WORD 16
+#define UNITS_PER_DMR_WORD 128
/* Type used for ptrdiff_t, as a string used in a declaration. */
#define PTRDIFF_TYPE "int"
@@ -752,7 +753,9 @@ enum data_align { align_abi, align_opt, align_both };
RS/6000 has 32 fixed-point registers, 32 floating-point registers,
a count register, a link register, and 8 condition register fields,
which we view here as separate registers. AltiVec adds 32 vector
- registers and a VRsave register.
+ registers and a VRsave register. The Dense Math Facility, which may be
+ present in a future processor, introduces 8 DMR registers each having
+ 1024 bits.
In addition, the difference between the frame and argument pointers is
a function of the number of registers saved, so we need to have a
@@ -767,7 +770,7 @@ enum data_align { align_abi, align_opt, align_both };
Another pseudo (not included in DWARF_FRAME_REGISTERS) is soft frame
pointer, which is eventually eliminated in favor of SP or FP. */
-#define FIRST_PSEUDO_REGISTER 111
+#define FIRST_PSEUDO_REGISTER 119
/* Use standard DWARF numbering for DWARF debugging information. */
#define DEBUGGER_REGNO(REGNO) rs6000_debugger_regno ((REGNO), 0)
@@ -804,7 +807,9 @@ enum data_align { align_abi, align_opt, align_both };
/* cr0..cr7 */ \
0, 0, 0, 0, 0, 0, 0, 0, \
/* vrsave vscr sfp */ \
- 1, 1, 1 \
+ 1, 1, 1, \
+ /* DMRs */ \
+ 0, 0, 0, 0, 0, 0, 0, 0 \
}
/* Like `CALL_USED_REGISTERS' except this macro doesn't require that
@@ -828,7 +833,9 @@ enum data_align { align_abi, align_opt, align_both };
/* cr0..cr7 */ \
1, 1, 0, 0, 0, 1, 1, 1, \
/* vrsave vscr sfp */ \
- 0, 0, 0 \
+ 0, 0, 0, \
+ /* DMRs */ \
+ 1, 1, 1, 1, 1, 1, 1, 1 \
}
#define TOTAL_ALTIVEC_REGS (LAST_ALTIVEC_REGNO - FIRST_ALTIVEC_REGNO + 1)
@@ -865,6 +872,7 @@ enum data_align { align_abi, align_opt, align_both };
v2 (not saved; incoming vector arg reg; return value)
v19 - v14 (not saved or used for anything)
v31 - v20 (saved; order given to save least number)
+ dmr0 - dmr7 (not saved)
vrsave, vscr (fixed)
sfp (fixed)
*/
@@ -907,6 +915,8 @@ enum data_align { align_abi, align_opt, align_both };
66, \
83, 82, 81, 80, 79, 78, \
95, 94, 93, 92, 91, 90, 89, 88, 87, 86, 85, 84, \
+ /* DMRs */ \
+ 111, 112, 113, 114, 115, 116, 117, 118, \
108, 109, \
110 \
}
@@ -933,6 +943,9 @@ enum data_align { align_abi, align_opt, align_both };
/* True if register is a VSX register. */
#define VSX_REGNO_P(N) (FP_REGNO_P (N) || ALTIVEC_REGNO_P (N))
+/* True if register is a DMR register. */
+#define DMR_REGNO_P(N) ((N) >= FIRST_DMR_REGNO && (N) <= LAST_DMR_REGNO)
+
/* Alternate name for any vector register supporting floating point, no matter
which instruction set(s) are available. */
#define VFLOAT_REGNO_P(N) \
@@ -972,7 +985,7 @@ enum data_align { align_abi, align_opt, align_both };
/* Modes that are not vectors, but require vector alignment. Treat these like
vectors in terms of loads and stores. */
#define VECTOR_ALIGNMENT_P(MODE) \
- (FLOAT128_VECTOR_P (MODE) || (MODE) == OOmode || (MODE) == XOmode)
+ (FLOAT128_VECTOR_P (MODE) || (MODE) == OOmode || (MODE) == XOmode || (MODE)
== TDOmode)
#define ALTIVEC_VECTOR_MODE(MODE) \
((MODE) == V16QImode \
@@ -1070,6 +1083,7 @@ enum reg_class
FLOAT_REGS,
ALTIVEC_REGS,
VSX_REGS,
+ DMR_REGS,
VRSAVE_REGS,
VSCR_REGS,
GEN_OR_FLOAT_REGS,
@@ -1099,6 +1113,7 @@ enum reg_class
"FLOAT_REGS",
\
"ALTIVEC_REGS", \
"VSX_REGS", \
+ "DMR_REGS", \
"VRSAVE_REGS", \
"VSCR_REGS", \
"GEN_OR_FLOAT_REGS", \
@@ -1133,6 +1148,8 @@ enum reg_class
{ 0x00000000, 0x00000000, 0xffffffff, 0x00000000 }, \
/* VSX_REGS. */ \
{ 0x00000000, 0xffffffff, 0xffffffff, 0x00000000 }, \
+ /* DMR_REGS. */ \
+ { 0x00000000, 0x00000000, 0x00000000, 0x007f8000 }, \
/* VRSAVE_REGS. */ \
{ 0x00000000, 0x00000000, 0x00000000, 0x00001000 }, \
/* VSCR_REGS. */ \
@@ -1160,7 +1177,7 @@ enum reg_class
/* CA_REGS. */ \
{ 0x00000000, 0x00000000, 0x00000000, 0x00000004 }, \
/* ALL_REGS. */ \
- { 0xffffffff, 0xffffffff, 0xffffffff, 0x00007fff } \
+ { 0xffffffff, 0xffffffff, 0xffffffff, 0x007fffff } \
}
/* The same information, inverted:
@@ -2060,7 +2077,16 @@ extern char rs6000_reg_names[][8]; /* register
names (0 vs. %r0). */
&rs6000_reg_names[108][0], /* vrsave */ \
&rs6000_reg_names[109][0], /* vscr */ \
\
- &rs6000_reg_names[110][0] /* sfp */ \
+ &rs6000_reg_names[110][0], /* sfp */ \
+ \
+ &rs6000_reg_names[111][0], /* dmr0 */ \
+ &rs6000_reg_names[112][0], /* dmr1 */ \
+ &rs6000_reg_names[113][0], /* dmr2 */ \
+ &rs6000_reg_names[114][0], /* dmr3 */ \
+ &rs6000_reg_names[115][0], /* dmr4 */ \
+ &rs6000_reg_names[116][0], /* dmr5 */ \
+ &rs6000_reg_names[117][0], /* dmr6 */ \
+ &rs6000_reg_names[118][0] /* dmr7 */ \
}
/* Table of additional register names to use in user input. */
@@ -2114,6 +2140,8 @@ extern char rs6000_reg_names[][8]; /* register
names (0 vs. %r0). */
{"vs52", 84}, {"vs53", 85}, {"vs54", 86}, {"vs55", 87}, \
{"vs56", 88}, {"vs57", 89}, {"vs58", 90}, {"vs59", 91}, \
{"vs60", 92}, {"vs61", 93}, {"vs62", 94}, {"vs63", 95}, \
+ {"dmr0", 111}, {"dmr1", 112}, {"dmr2", 113}, {"dmr3", 114}, \
+ {"dmr4", 115}, {"dmr5", 116}, {"dmr6", 117}, {"dmr7", 118}, \
}
/* This is how to output an element of a case-vector that is relative. */
diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md
index 4ec3d3da8a9..86d79d92258 100644
--- a/gcc/config/rs6000/rs6000.md
+++ b/gcc/config/rs6000/rs6000.md
@@ -51,6 +51,8 @@
(VRSAVE_REGNO 108)
(VSCR_REGNO 109)
(FRAME_POINTER_REGNUM 110)
+ (FIRST_DMR_REGNO 111)
+ (LAST_DMR_REGNO 118)
])
;;
--
2.52.0