Hi, Thank you for reviewing the previous versions, Surya.
Changes from v2: - Handle endianness while loading/storing QDOmode values in *movqdo. - Added a comment for QDOmode in rs6000_hard_regno_mode_ok_uncached. - Reverted the unrelated whitespace change in rs6000_secondary_reload_simple_move. - Added a test that verifies the code generated when copying and spilling/filling 2048-bit values. Changes from v1: - Corrected nits in commit message. - Updated the logic to do register move backwards if REGNO(src) < REGNO(dst) in *movqdo, if both are VSX regs. - Updated preferred reload class for QDOmode to VSX_REGS. - Removed changes in rs6000_split_multireg_move for QDO mode. - Fixed all indentations. Bootstrapped and regtested on ppc64le-linux-gnu, with no regressions. Kindly review. Thanks, Avinash Jayakar This patch introduces a new mode called QDOmode which is a 256 byte opaque mode that maps to __dmr2048 type. The sha3hash instructions take a pair of dense math registers, therefore we need this type for those builtins. The DMR pair register maps to even numbered pair of consecutive DMR register. For example, the DMR pair register 2 represents 2 DMR registers 2 and 3. movqdo pattern has been implemented, which splits the 2048 bit moves into smaller 1024 bit tdo moves after the reload pass is completed. 2026-10-28 Avinash Jayakar <[email protected]> gcc/ChangeLog: * config/rs6000/mma.md (movqdo): New define_expand. (*movqdo): New define_insn_and_split. * config/rs6000/rs6000-builtin.cc (rs6000_type_string): Add __dmr2048. (rs6000_init_builtins): Register dmr2048 type. (rs6000_gimple_fold_mma_builtin): Handle QDOmode. * config/rs6000/rs6000-call.cc (rs6000_return_in_memory): Reject QDOmode and emit "Dense Math" diagnostics. (rs6000_function_arg): Likewise. * config/rs6000/rs6000-gen-builtins.cc (enum basetype): Add DMR2048. (match_type): Likewise. (complete_vector_type): Likewise. * config/rs6000/rs6000-modes.def: Define QDO mode. * config/rs6000/rs6000.cc (rs6000_hard_regno_mode_ok_uncached): Allow even number DMR regno for QDOmode. (rs6000_modes_tieable_p): Do not allow QDO with other mode. (rs6000_debug_reg_global): Add QDOmode. (rs6000_setup_reg_addr_masks): Allow QDOmode. (reg_offset_addressing_ok_p): QDOmode return TARGET_DMF. (rs6000_emit_move): Do not allow QDO mode to set to constants. (rs6000_secondary_reload_simple_move): Allow QDOmode. (rs6000_preferred_reload_class): QDOmode prefers VSX_REGS. (rs6000_mangle_type): Add __dmr2048 type. (rs6000_dmr_register_move_cost): QDOmode move cost is double of TDOmode. (rs6000_register_move_cost): Allow QDOmode. (rs6000_invalid_conversion): Handle QDOmode. * config/rs6000/rs6000.h (VECTOR_ALIGNMENT_P): True if mode is QDOmode. (enum rs6000_builtin_type_index): Add dmr2048 and its ptr type. (dmr2048_type_node): Define __dmr2048 node. (ptr_dmr2048_type_node): Define pointer type for __dmr2048 node. gcc/testsuite/ChangeLog: * gcc.target/powerpc/dmr2048-copy.c: New test. --- gcc/config/rs6000/mma.md | 71 +++++++++++++++++++ gcc/config/rs6000/rs6000-builtin.cc | 17 +++++ gcc/config/rs6000/rs6000-call.cc | 10 +-- gcc/config/rs6000/rs6000-gen-builtins.cc | 19 ++++- gcc/config/rs6000/rs6000-modes.def | 3 +- gcc/config/rs6000/rs6000.cc | 61 +++++++++++++--- gcc/config/rs6000/rs6000.h | 7 +- .../gcc.target/powerpc/dmr2048-copy.c | 70 ++++++++++++++++++ 8 files changed, 240 insertions(+), 18 deletions(-) create mode 100644 gcc/testsuite/gcc.target/powerpc/dmr2048-copy.c diff --git a/gcc/config/rs6000/mma.md b/gcc/config/rs6000/mma.md index f5085cd967e..a70426d4be9 100644 --- a/gcc/config/rs6000/mma.md +++ b/gcc/config/rs6000/mma.md @@ -662,6 +662,77 @@ (define_insn_and_split "*movtdo" gcc_unreachable (); }) +;; QDO (2048-bit dense-math pair) move expander. +;; Split into 2 TDO moves for the even and odd DMR. +(define_expand "movqdo" + [(set (match_operand:QDO 0 "nonimmediate_operand") + (match_operand:QDO 1 "input_operand"))] + "TARGET_DMF" +{ + rs6000_emit_move (operands[0], operands[1], QDOmode); + DONE; +}) + +(define_insn_and_split "*movqdo" + [(set (match_operand:QDO 0 "nonimmediate_operand" "=wa,m,wa,wD,wa,wD") + (match_operand:QDO 1 "input_operand" "m,wa,wa,wD,wD,wa"))] + "TARGET_DMF + && (gpc_reg_operand (operands[0], QDOmode) + || gpc_reg_operand (operands[1], QDOmode))" + "#" + "reload_completed" + [(const_int 0)] +{ + rtx dst = operands[0]; + rtx src = operands[1]; + + /* Of the two TDO halves, the first one holds the most significant part + of the value. In little endian mode it lives at the higher address, + so the offsets of the two memory halves are swapped. */ + if (REG_P (dst) && MEM_P (src)) + { + rtx tdo1 = gen_rtx_REG (TDOmode, REGNO (dst)); + rtx tdo2 = gen_rtx_REG (TDOmode, REGNO (dst) + 8); + rtx mem1 = adjust_address (src, TDOmode, BYTES_BIG_ENDIAN ? 0 : 128); + rtx mem2 = adjust_address (src, TDOmode, BYTES_BIG_ENDIAN ? 128 : 0); + emit_insn (gen_move_insn (tdo1, mem1)); + emit_insn (gen_move_insn (tdo2, mem2)); + DONE; + } + else if (REG_P (src) && MEM_P (dst)) + { + rtx tdo1 = gen_rtx_REG (TDOmode, REGNO (src)); + rtx tdo2 = gen_rtx_REG (TDOmode, REGNO (src) + 8); + rtx mem1 = adjust_address (dst, TDOmode, BYTES_BIG_ENDIAN ? 0 : 128); + rtx mem2 = adjust_address (dst, TDOmode, BYTES_BIG_ENDIAN ? 128 : 0); + emit_insn (gen_move_insn (mem1, tdo1)); + emit_insn (gen_move_insn (mem2, tdo2)); + DONE; + } + else if (REG_P (src) && REG_P (dst)) + { + bool is_src_vsx = VSX_REGNO_P (REGNO (src)); + bool is_dst_vsx = VSX_REGNO_P (REGNO (dst)); + rtx stdo1 = gen_rtx_REG (TDOmode, REGNO (src)); + rtx stdo2 = gen_rtx_REG (TDOmode, REGNO (src) + (is_src_vsx ? 8 : 1)); + rtx dtdo1 = gen_rtx_REG (TDOmode, REGNO (dst)); + rtx dtdo2 = gen_rtx_REG (TDOmode, REGNO (dst) + (is_dst_vsx ? 8 : 1)); + + if (is_src_vsx && is_dst_vsx && REGNO (src) < REGNO (dst)) + { + emit_insn (gen_move_insn (dtdo2, stdo2)); + emit_insn (gen_move_insn (dtdo1, stdo1)); + } + else + { + emit_insn (gen_move_insn (dtdo1, stdo1)); + emit_insn (gen_move_insn (dtdo2, stdo2)); + } + DONE; + } + gcc_unreachable (); +}) + (define_insn_and_split "reload_tdo_load" [(set (match_operand:TDO 0 "dmr_register_operand" "=wD") diff --git a/gcc/config/rs6000/rs6000-builtin.cc b/gcc/config/rs6000/rs6000-builtin.cc index 33c82b94952..65e411e1cfa 100644 --- a/gcc/config/rs6000/rs6000-builtin.cc +++ b/gcc/config/rs6000/rs6000-builtin.cc @@ -519,6 +519,8 @@ const char *rs6000_type_string (tree type_node) return "__vector_quad"; else if (type_node == dmr1024_type_node) return "__dmr1024"; + else if (type_node == dmr2048_type_node) + return "__dmr2048"; return "unknown"; } @@ -835,6 +837,18 @@ rs6000_init_builtins (void) t = build_qualified_type (dmr1024_type_node, TYPE_QUAL_CONST); ptr_dmr1024_type_node = build_pointer_type (t); + /* QDOmode (2048-bit dmr pair). Use 512-bit alignment like dmr1024. */ + dmr2048_type_node = make_node (OPAQUE_TYPE); + SET_TYPE_MODE (dmr2048_type_node, QDOmode); + TYPE_SIZE (dmr2048_type_node) = bitsize_int (GET_MODE_BITSIZE (QDOmode)); + TYPE_PRECISION (dmr2048_type_node) = GET_MODE_BITSIZE (QDOmode); + TYPE_SIZE_UNIT (dmr2048_type_node) = size_int (GET_MODE_SIZE (QDOmode)); + SET_TYPE_ALIGN (dmr2048_type_node, 512); + TYPE_USER_ALIGN (dmr2048_type_node) = 0; + lang_hooks.types.register_builtin_type (dmr2048_type_node, "__dmr2048"); + t = build_qualified_type (dmr2048_type_node, TYPE_QUAL_CONST); + ptr_dmr2048_type_node = build_pointer_type (t); + tdecl = add_builtin_type ("__bool char", bool_char_type_node); TYPE_NAME (bool_char_type_node) = tdecl; @@ -1331,6 +1345,9 @@ rs6000_gimple_fold_mma_builtin (gimple_stmt_iterator *gsi, case TDOmode: lhs_type = dmr1024_type_node; break; + case QDOmode: + lhs_type = dmr2048_type_node; + break; case XOmode: lhs_type = vector_quad_type_node; break; diff --git a/gcc/config/rs6000/rs6000-call.cc b/gcc/config/rs6000/rs6000-call.cc index 742751465fa..ac393182c77 100644 --- a/gcc/config/rs6000/rs6000-call.cc +++ b/gcc/config/rs6000/rs6000-call.cc @@ -454,7 +454,8 @@ rs6000_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED) && TREE_TYPE (cfun->decl) == fntype && (TYPE_MODE (type) == OOmode || TYPE_MODE (type) == XOmode - || TYPE_MODE (type) == TDOmode)) + || TYPE_MODE (type) == TDOmode + || TYPE_MODE (type) == QDOmode)) { /* Record we have now handled function CFUN, so the next time we are called, we do not re-report the same error. */ @@ -462,7 +463,8 @@ rs6000_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED) if (TYPE_CANONICAL (type) != NULL_TREE) type = TYPE_CANONICAL (type); const char *type_class = - (TYPE_MODE (type) == TDOmode) ? "Dense Math" : "MMA"; + (TYPE_MODE (type) == TDOmode || TYPE_MODE (type) == QDOmode) + ? "Dense Math" : "MMA"; error ("invalid use of %s type %qs as a function return value", type_class, IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type)))); @@ -1660,12 +1662,12 @@ rs6000_function_arg (cumulative_args_t cum_v, const function_arg_info &arg) int n_elts; /* We do not allow Dense Math/MMA types being used as function arguments. */ - if (mode == OOmode || mode == XOmode || mode == TDOmode) + if (mode == OOmode || mode == XOmode || mode == TDOmode || mode == QDOmode) { if (TYPE_CANONICAL (type) != NULL_TREE) type = TYPE_CANONICAL (type); const char *type_class = - (mode == TDOmode) ? "Dense Math" : "MMA"; + (mode == TDOmode || mode == QDOmode) ? "Dense Math" : "MMA"; error ("invalid use of %s operand of type %qs as a function parameter", type_class, IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type)))); diff --git a/gcc/config/rs6000/rs6000-gen-builtins.cc b/gcc/config/rs6000/rs6000-gen-builtins.cc index 08068ba78fd..86b3fe9df47 100644 --- a/gcc/config/rs6000/rs6000-gen-builtins.cc +++ b/gcc/config/rs6000/rs6000-gen-builtins.cc @@ -340,7 +340,8 @@ enum basetype BT_IBM128, BT_VPAIR, BT_VQUAD, - BT_DMR + BT_DMR, + BT_DMR2048 }; /* Ways in which a const int value can be restricted. RES_BITS indicates @@ -562,6 +563,7 @@ static typemap type_map[] = { "pv16qi", "ptr_V16QI" }, { "pv1poi", "ptr_vector_pair" }, { "pv1pxi", "ptr_vector_quad" }, + { "pv1qdoi", "ptr_dmr2048" }, { "pv1tdoi", "ptr_dmr1024" }, { "pv1ti", "ptr_V1TI" }, { "pv2df", "ptr_V2DF" }, @@ -593,7 +595,8 @@ static typemap type_map[] = { "v16qi", "V16QI" }, { "v1poi", "vector_pair" }, { "v1pxi", "vector_quad" }, - { "v1tdoi", "dmr1024" }, + { "v1qdoi", "dmr2048" }, + { "v1tdoi", "dmr1024" }, { "v1ti", "V1TI" }, { "v2df", "V2DF" }, { "v2di", "V2DI" }, @@ -1080,6 +1083,7 @@ match_type (typeinfo *typedata, int voidok) v256 __vector_pair v512 __vector_quad dmr1024 __dmr1024 + dmr2048 __dmr2048 For simplicity, We don't support "short int" and "long long int". We don't currently support a <basetype> of "_Float16". "signed" @@ -1268,6 +1272,13 @@ match_type (typeinfo *typedata, int voidok) handle_pointer (typedata); return 1; } + else if (!strcmp (token, "dmr2048")) + { + typedata->isvector = 1; + typedata->base = BT_DMR2048; + handle_pointer (typedata); + return 1; + } else if (!strcmp (token, "signed")) typedata->issigned = 1; else if (!strcmp (token, "unsigned")) @@ -1578,6 +1589,10 @@ complete_vector_type (typeinfo *typeptr, char *buf, int *bufi) memcpy (&buf[*bufi], "1tdoi", 5); *bufi += 5; break; + case BT_DMR2048: + memcpy (&buf[*bufi], "1qdoi", 5); + *bufi += 5; + break; default: diag (pos, "unhandled basetype %d.\n", typeptr->base); exit (1); diff --git a/gcc/config/rs6000/rs6000-modes.def b/gcc/config/rs6000/rs6000-modes.def index 0ad326751c4..899c08bf061 100644 --- a/gcc/config/rs6000/rs6000-modes.def +++ b/gcc/config/rs6000/rs6000-modes.def @@ -76,7 +76,8 @@ VECTOR_MODE (INT, SI, 2); /* V2SI */ combination. */ PARTIAL_INT_MODE (TI, 128, PTI); -/* Modes used by __vector_pair, __vector_quad and __dmr1024. */ +/* Modes used by __vector_pair, __vector_quad, __dmr1024 and __dmr2048. */ OPAQUE_MODE (OO, 32); OPAQUE_MODE (XO, 64); OPAQUE_MODE (TDO, 128); +OPAQUE_MODE (QDO, 256); diff --git a/gcc/config/rs6000/rs6000.cc b/gcc/config/rs6000/rs6000.cc index 9581d122a9d..37ae56554a1 100644 --- a/gcc/config/rs6000/rs6000.cc +++ b/gcc/config/rs6000/rs6000.cc @@ -1871,8 +1871,9 @@ 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)) + /* No other types other than XOmode, TDOmode or QDOmode can go in DMRs. */ + if (DMR_REGNO_P (regno) + && !(mode ==XOmode || mode == TDOmode || mode == QDOmode)) return 0; /* TDOmode value can be held in either 1 DMR register or 8 VSX @@ -1888,6 +1889,21 @@ rs6000_hard_regno_mode_ok_uncached (int regno, machine_mode mode) return 0; } + /* QDOmode value can be held in 2 consecutive DMR registers starting with + an even numbered DMR, or in 16 consecutive VSX registers. */ + if (mode == QDOmode) + { + if (TARGET_DMF) + return ((DMR_REGNO_P (regno) + && DMR_REGNO_P (last_regno) + && ((regno - FIRST_DMR_REGNO) % 2 == 0)) + || (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) @@ -2014,8 +2030,9 @@ static bool rs6000_modes_tieable_p (machine_mode mode1, machine_mode mode2) { if (mode1 == PTImode || mode1 == OOmode || mode1 == XOmode - || mode1 == TDOmode || mode2 == PTImode || mode2 == OOmode - || mode2 == XOmode || mode2 == TDOmode) + || mode1 == TDOmode || mode1 == QDOmode + || mode2 == PTImode || mode2 == OOmode + || mode2 == XOmode || mode2 == TDOmode || mode2 == QDOmode) return mode1 == mode2; if (ALTIVEC_OR_VSX_VECTOR_MODE (mode1)) @@ -2307,6 +2324,7 @@ rs6000_debug_reg_global (void) OOmode, XOmode, TDOmode, + QDOmode, CCmode, CCUNSmode, CCEQmode, @@ -2671,7 +2689,8 @@ rs6000_setup_reg_addr_masks (void) if (rc == RELOAD_REG_DMR) { - if (TARGET_DMF && (m2 == XOmode || m2 == TDOmode)) + if (TARGET_DMF + && (m2 == XOmode || m2 == TDOmode || m2 == QDOmode)) { addr_mask = RELOAD_REG_VALID; reg_addr[m].addr_mask[rc] = addr_mask; @@ -2782,8 +2801,9 @@ rs6000_setup_reg_addr_masks (void) 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)))) + || (TARGET_DMF + && (m2 == TDOmode || m2 == QDOmode + || m2 == OOmode || m2 == XOmode)))) { addr_mask |= RELOAD_REG_OFFSET; if (rc == RELOAD_REG_FPR || rc == RELOAD_REG_VMX) @@ -8756,6 +8776,7 @@ reg_offset_addressing_ok_p (machine_mode mode) return TARGET_MMA || TARGET_DMF; case E_TDOmode: + case E_QDOmode: return TARGET_DMF; case E_SDmode: @@ -11317,6 +11338,12 @@ rs6000_emit_move (rtx dest, rtx source, machine_mode mode) "__dmr1024"); break; + case E_QDOmode: + if (CONST_INT_P (operands[1])) + error ("%qs is an opaque type, and you cannot set it to constants", + "__dmr2048"); + break; + case E_SImode: case E_DImode: /* Use default pattern for address of ELF small data */ @@ -12789,7 +12816,7 @@ rs6000_secondary_reload_simple_move (enum rs6000_reg_type to_type, return true; /* DMRs can be copied to VSX register, and vice versa. */ - if (TARGET_DMF && (mode == XOmode || mode == TDOmode) + if (TARGET_DMF && (mode == XOmode || mode == TDOmode || mode == QDOmode) && ((to_type == DMR_REG_TYPE && from_type == VSX_REG_TYPE) || (to_type == VSX_REG_TYPE && from_type == DMR_REG_TYPE))) return true; @@ -13593,6 +13620,9 @@ rs6000_preferred_reload_class (rtx x, enum reg_class rclass) if (mode == TDOmode) return VSX_REGS; + if (mode == QDOmode) + return VSX_REGS; + if (GET_MODE_CLASS (mode) == MODE_INT) return GENERAL_REGS; } @@ -20821,6 +20851,8 @@ rs6000_mangle_type (const_tree type) return "u13__vector_quad"; if (type == dmr1024_type_node) return "u9__dmr1024"; + if (type == dmr2048_type_node) + return "u9__dmr2048"; /* For all other types, use the default mangling. */ return NULL; @@ -22950,6 +22982,10 @@ rs6000_dmr_register_move_cost (machine_mode mode, reg_class_t rclass) else if (mode == TDOmode) return base_cost * 2; + /* QDOmode (dmr pair) can be copied in 4 instructions. */ + else if (mode == QDOmode) + return base_cost * 4; + else return base_cost * 2 * hard_regno_nregs (FIRST_DMR_REGNO, mode); } @@ -22979,7 +23015,8 @@ rs6000_register_move_cost (machine_mode mode, to_vsx = reg_class_contents[to] & reg_class_contents[VSX_REGS]; from_vsx = reg_class_contents[from] & reg_class_contents[VSX_REGS]; - if ((mode == TDOmode || mode==XOmode) && from == DMR_REGS && to == DMR_REGS) + if ((mode == TDOmode || mode == XOmode || mode == QDOmode) + && from == DMR_REGS && to == DMR_REGS) ret = 2 * hard_regno_nregs (FIRST_DMR_REGNO, mode); else if (from == DMR_REGS) @@ -29093,7 +29130,7 @@ rs6000_invalid_conversion (const_tree fromtype, const_tree totype) if (frommode != tomode) { - /* Do not allow conversions to/from XOmode, OOmode and TDOmode + /* Do not allow conversions to/from XOmode, OOmode, TDOmode and QDOmode types. */ if (frommode == XOmode) return N_("invalid conversion from type %<__vector_quad%>"); @@ -29107,6 +29144,10 @@ rs6000_invalid_conversion (const_tree fromtype, const_tree totype) return N_("invalid conversion from type %<__dmr1024%>"); if (tomode == TDOmode) return N_("invalid conversion to type %<__dmr1024%>"); + if (frommode == QDOmode) + return N_("invalid conversion from type %<__dmr2048%>"); + if (tomode == QDOmode) + return N_("invalid conversion to type %<__dmr2048%>"); } /* Conversion allowed. */ diff --git a/gcc/config/rs6000/rs6000.h b/gcc/config/rs6000/rs6000.h index ecd415a9b2f..6c21be8c8a5 100644 --- a/gcc/config/rs6000/rs6000.h +++ b/gcc/config/rs6000/rs6000.h @@ -997,7 +997,8 @@ 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 || (MODE) == TDOmode) + (FLOAT128_VECTOR_P (MODE) || (MODE) == OOmode || (MODE) == XOmode \ + || (MODE) == TDOmode || (MODE) == QDOmode) #define ALTIVEC_VECTOR_MODE(MODE) \ ((MODE) == V16QImode \ @@ -2289,6 +2290,7 @@ enum rs6000_builtin_type_index RS6000_BTI_vector_pair, /* unsigned 256-bit types (vector pair). */ RS6000_BTI_vector_quad, /* unsigned 512-bit types (vector quad). */ RS6000_BTI_dmr1024, /* unsigned 1024-bit type (dmr1024). */ + RS6000_BTI_dmr2048, /* unsigned 2048-bit type (dmr2048). */ RS6000_BTI_const_ptr_void, /* const pointer to void */ RS6000_BTI_ptr_V16QI, RS6000_BTI_ptr_V1TI, @@ -2328,6 +2330,7 @@ enum rs6000_builtin_type_index RS6000_BTI_ptr_vector_pair, RS6000_BTI_ptr_vector_quad, RS6000_BTI_ptr_dmr1024, + RS6000_BTI_ptr_dmr2048, RS6000_BTI_ptr_long_long, RS6000_BTI_ptr_long_long_unsigned, RS6000_BTI_INTPTI, @@ -2390,6 +2393,7 @@ enum rs6000_builtin_type_index #define vector_pair_type_node (rs6000_builtin_types[RS6000_BTI_vector_pair]) #define vector_quad_type_node (rs6000_builtin_types[RS6000_BTI_vector_quad]) #define dmr1024_type_node (rs6000_builtin_types[RS6000_BTI_dmr1024]) +#define dmr2048_type_node (rs6000_builtin_types[RS6000_BTI_dmr2048]) #define pcvoid_type_node (rs6000_builtin_types[RS6000_BTI_const_ptr_void]) #define ptr_V16QI_type_node (rs6000_builtin_types[RS6000_BTI_ptr_V16QI]) #define ptr_V1TI_type_node (rs6000_builtin_types[RS6000_BTI_ptr_V1TI]) @@ -2429,6 +2433,7 @@ enum rs6000_builtin_type_index #define ptr_vector_pair_type_node (rs6000_builtin_types[RS6000_BTI_ptr_vector_pair]) #define ptr_vector_quad_type_node (rs6000_builtin_types[RS6000_BTI_ptr_vector_quad]) #define ptr_dmr1024_type_node (rs6000_builtin_types[RS6000_BTI_ptr_dmr1024]) +#define ptr_dmr2048_type_node (rs6000_builtin_types[RS6000_BTI_ptr_dmr2048]) #define ptr_long_long_integer_type_node (rs6000_builtin_types[RS6000_BTI_ptr_long_long]) #define ptr_long_long_unsigned_type_node (rs6000_builtin_types[RS6000_BTI_ptr_long_long_unsigned]) diff --git a/gcc/testsuite/gcc.target/powerpc/dmr2048-copy.c b/gcc/testsuite/gcc.target/powerpc/dmr2048-copy.c new file mode 100644 index 00000000000..fc83f72850f --- /dev/null +++ b/gcc/testsuite/gcc.target/powerpc/dmr2048-copy.c @@ -0,0 +1,70 @@ +/* { dg-do compile } */ +/* { dg-require-effective-target powerpc_future_compile_ok } */ +/* { dg-require-effective-target lp64 } */ +/* { dg-options "-mdejagnu-cpu=future -O2" } */ + +/* Verify the code generated when loading, storing and spilling/filling a + 2048-bit __dmr2048 value. + + A __dmr2048 value is made of two 1024-bit TDO halves. The first half + holds the most significant bits, so in big endian mode it must be + loaded from and stored to the lower address, while in little endian + mode it must be loaded from and stored to the higher address. The two + halves are held in VSX registers 32..39 and 40..47 respectively. */ + +typedef __dmr2048 qdo_t; + +extern void clobber (void); + +/* Copying a value exercises the memory <-> register moves. */ +void +copy (qdo_t *dst, qdo_t *src) +{ + *dst = *src; +} + +/* Keeping a value live across a call exercises spills and fills. */ +void +spill (void) +{ + qdo_t v; + + /* Force the value into a DMR pair, then keep it live across the call + so that it has to be spilled to the stack and filled back again. */ + asm volatile ("" : "=wD" (v)); + clobber (); + asm volatile ("" : "+wD" (v)); +} + +/* Eight vector-pair loads and eight vector-pair stores make up the copy. + The spill/fill pair around the call adds another eight of each. */ +/* { dg-final { scan-assembler-times {\mlxvp\M} 16 } } */ +/* { dg-final { scan-assembler-times {\mstxvp\M} 16 } } */ + +/* Little endian: the first half is at the higher address. */ +/* { dg-final { scan-assembler-times {\mlxvp\s+3[0-9],128\(4\)} 1 { target { powerpc64le-*-* } } } } */ +/* { dg-final { scan-assembler-times {\mlxvp\s+3[0-9],224\(4\)} 1 { target { powerpc64le-*-* } } } } */ +/* { dg-final { scan-assembler-times {\mlxvp\s+4[0-7],0\(4\)} 1 { target { powerpc64le-*-* } } } } */ +/* { dg-final { scan-assembler-times {\mlxvp\s+4[0-7],96\(4\)} 1 { target { powerpc64le-*-* } } } } */ +/* { dg-final { scan-assembler-times {\mstxvp\s+3[0-9],128\(3\)} 1 { target { powerpc64le-*-* } } } } */ +/* { dg-final { scan-assembler-times {\mstxvp\s+4[0-7],0\(3\)} 1 { target { powerpc64le-*-* } } } } */ + +/* Little endian: the first half is spilled to the higher stack address. */ +/* { dg-final { scan-assembler-times {\mstxvp\s+3[0-9],160\(1\)} 1 { target { powerpc64le-*-* } } } } */ +/* { dg-final { scan-assembler-times {\mstxvp\s+4[0-7],32\(1\)} 1 { target { powerpc64le-*-* } } } } */ +/* { dg-final { scan-assembler-times {\mlxvp\s+3[0-9],160\(1\)} 1 { target { powerpc64le-*-* } } } } */ +/* { dg-final { scan-assembler-times {\mlxvp\s+4[0-7],32\(1\)} 1 { target { powerpc64le-*-* } } } } */ + +/* Big endian: the first half is at the lower address. */ +/* { dg-final { scan-assembler-times {\mlxvp\s+3[0-9],0\(4\)} 1 { target { ! powerpc64le-*-* } } } } */ +/* { dg-final { scan-assembler-times {\mlxvp\s+3[0-9],96\(4\)} 1 { target { ! powerpc64le-*-* } } } } */ +/* { dg-final { scan-assembler-times {\mlxvp\s+4[0-7],128\(4\)} 1 { target { ! powerpc64le-*-* } } } } */ +/* { dg-final { scan-assembler-times {\mlxvp\s+4[0-7],224\(4\)} 1 { target { ! powerpc64le-*-* } } } } */ +/* { dg-final { scan-assembler-times {\mstxvp\s+3[0-9],0\(3\)} 1 { target { ! powerpc64le-*-* } } } } */ +/* { dg-final { scan-assembler-times {\mstxvp\s+4[0-7],128\(3\)} 1 { target { ! powerpc64le-*-* } } } } */ + +/* Big endian: the first half is spilled to the lower stack address. */ +/* { dg-final { scan-assembler-times {\mstxvp\s+3[0-9],32\(1\)} 1 { target { ! powerpc64le-*-* } } } } */ +/* { dg-final { scan-assembler-times {\mstxvp\s+4[0-7],160\(1\)} 1 { target { ! powerpc64le-*-* } } } } */ +/* { dg-final { scan-assembler-times {\mlxvp\s+3[0-9],32\(1\)} 1 { target { ! powerpc64le-*-* } } } } */ +/* { dg-final { scan-assembler-times {\mlxvp\s+4[0-7],160\(1\)} 1 { target { ! powerpc64le-*-* } } } } */ -- 2.54.0
