https://gcc.gnu.org/g:cd19d1f60817e95b708fd714bf2e050906b417ed
commit cd19d1f60817e95b708fd714bf2e050906b417ed Author: Surya Kumari Jangala <[email protected]> Date: Wed Jul 15 02:01:12 2026 -0500 rs6000: Add support for Dense Math Facility (DMF) registers 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 - TDOmode and XOmode excluded from register tying to prevent incorrect cross-class allocation 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 - New rs6000_dmr_register_move_cost helper computes move costs between a DMR register and any register class via VSX: XOmode costs 2, TDOmode costs 4, other modes scale by nregs - Ensures proper alignment requirements (vector alignment) - rs6000_register_move_cost and rs6000_memory_move_cost extended to handle DMR_REGS as source or destination 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-15 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_modes_tieable_p): Exclude TDOmode from register tying. (reg_offset_addressing_ok_p): Allow XOmode with TARGET_DMF. Add TDOmode support with TARGET_DMF. (rs6000_secondary_reload_class): Handle DMR_REGS reload routing: direct move to/from VSX or DMR; route through VSX_REGS for memory. (rs6000_dmr_register_move_cost): New helper. (rs6000_register_move_cost): Handle DMR_REGS as source or destination. (rs6000_memory_move_cost): Add DMR_REGS case routing cost through VSX. (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. Diff: --- 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 64683102e9e6..4b17b250708d 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; @@ -24109,6 +24185,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; @@ -24274,6 +24352,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 8235e095bcce..7c417039d86b 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 4ec3d3da8a99..86d79d922586 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) ]) ;;
