diff options
Diffstat (limited to 'gcc/config/rs6000/rs6000-call.c')
-rw-r--r-- | gcc/config/rs6000/rs6000-call.c | 489 |
1 files changed, 480 insertions, 9 deletions
diff --git a/gcc/config/rs6000/rs6000-call.c b/gcc/config/rs6000/rs6000-call.c index 088264b..fdf136f 100644 --- a/gcc/config/rs6000/rs6000-call.c +++ b/gcc/config/rs6000/rs6000-call.c @@ -183,6 +183,7 @@ static tree builtin_function_type (machine_mode, machine_mode, enum rs6000_builtins, const char *name); static void rs6000_common_init_builtins (void); static void htm_init_builtins (void); +static void mma_init_builtins (void); /* Hash table to keep track of the argument types for builtin functions. */ @@ -243,6 +244,7 @@ builtin_hasher::equal (builtin_hash_struct *p1, builtin_hash_struct *p2) #undef RS6000_BUILTIN_A #undef RS6000_BUILTIN_D #undef RS6000_BUILTIN_H +#undef RS6000_BUILTIN_M #undef RS6000_BUILTIN_P #undef RS6000_BUILTIN_X @@ -270,6 +272,9 @@ builtin_hasher::equal (builtin_hash_struct *p1, builtin_hash_struct *p2) #define RS6000_BUILTIN_H(ENUM, NAME, MASK, ATTR, ICODE) \ { NAME, ICODE, MASK, ATTR }, +#define RS6000_BUILTIN_M(ENUM, NAME, MASK, ATTR, ICODE) \ + { NAME, ICODE, MASK, ATTR }, + #define RS6000_BUILTIN_P(ENUM, NAME, MASK, ATTR, ICODE) \ { NAME, ICODE, MASK, ATTR }, @@ -296,6 +301,7 @@ static const struct rs6000_builtin_info_type rs6000_builtin_info[] = #undef RS6000_BUILTIN_A #undef RS6000_BUILTIN_D #undef RS6000_BUILTIN_H +#undef RS6000_BUILTIN_M #undef RS6000_BUILTIN_P #undef RS6000_BUILTIN_X @@ -8354,6 +8360,9 @@ def_builtin (const char *name, tree type, enum rs6000_builtins code) attr_string = ", fp, const"; } } + else if ((classify & (RS6000_BTC_QUAD | RS6000_BTC_PAIR)) != 0) + /* The function uses a register quad and/or pair. Nothing to do. */ + ; else if ((classify & RS6000_BTC_ATTR_MASK) != 0) gcc_unreachable (); @@ -8372,6 +8381,7 @@ def_builtin (const char *name, tree type, enum rs6000_builtins code) #undef RS6000_BUILTIN_A #undef RS6000_BUILTIN_D #undef RS6000_BUILTIN_H +#undef RS6000_BUILTIN_M #undef RS6000_BUILTIN_P #undef RS6000_BUILTIN_X @@ -8385,6 +8395,7 @@ def_builtin (const char *name, tree type, enum rs6000_builtins code) #define RS6000_BUILTIN_A(ENUM, NAME, MASK, ATTR, ICODE) #define RS6000_BUILTIN_D(ENUM, NAME, MASK, ATTR, ICODE) #define RS6000_BUILTIN_H(ENUM, NAME, MASK, ATTR, ICODE) +#define RS6000_BUILTIN_M(ENUM, NAME, MASK, ATTR, ICODE) #define RS6000_BUILTIN_P(ENUM, NAME, MASK, ATTR, ICODE) #define RS6000_BUILTIN_X(ENUM, NAME, MASK, ATTR, ICODE) @@ -8403,6 +8414,7 @@ static const struct builtin_description bdesc_3arg[] = #undef RS6000_BUILTIN_A #undef RS6000_BUILTIN_D #undef RS6000_BUILTIN_H +#undef RS6000_BUILTIN_M #undef RS6000_BUILTIN_P #undef RS6000_BUILTIN_X @@ -8416,6 +8428,7 @@ static const struct builtin_description bdesc_3arg[] = #define RS6000_BUILTIN_A(ENUM, NAME, MASK, ATTR, ICODE) #define RS6000_BUILTIN_D(ENUM, NAME, MASK, ATTR, ICODE) #define RS6000_BUILTIN_H(ENUM, NAME, MASK, ATTR, ICODE) +#define RS6000_BUILTIN_M(ENUM, NAME, MASK, ATTR, ICODE) #define RS6000_BUILTIN_P(ENUM, NAME, MASK, ATTR, ICODE) #define RS6000_BUILTIN_X(ENUM, NAME, MASK, ATTR, ICODE) @@ -8434,6 +8447,7 @@ static const struct builtin_description bdesc_4arg[] = #undef RS6000_BUILTIN_A #undef RS6000_BUILTIN_D #undef RS6000_BUILTIN_H +#undef RS6000_BUILTIN_M #undef RS6000_BUILTIN_P #undef RS6000_BUILTIN_X @@ -8447,6 +8461,7 @@ static const struct builtin_description bdesc_4arg[] = { MASK, ICODE, NAME, ENUM }, #define RS6000_BUILTIN_H(ENUM, NAME, MASK, ATTR, ICODE) +#define RS6000_BUILTIN_M(ENUM, NAME, MASK, ATTR, ICODE) #define RS6000_BUILTIN_P(ENUM, NAME, MASK, ATTR, ICODE) #define RS6000_BUILTIN_X(ENUM, NAME, MASK, ATTR, ICODE) @@ -8465,6 +8480,7 @@ static const struct builtin_description bdesc_dst[] = #undef RS6000_BUILTIN_A #undef RS6000_BUILTIN_D #undef RS6000_BUILTIN_H +#undef RS6000_BUILTIN_M #undef RS6000_BUILTIN_P #undef RS6000_BUILTIN_X @@ -8478,6 +8494,7 @@ static const struct builtin_description bdesc_dst[] = #define RS6000_BUILTIN_A(ENUM, NAME, MASK, ATTR, ICODE) #define RS6000_BUILTIN_D(ENUM, NAME, MASK, ATTR, ICODE) #define RS6000_BUILTIN_H(ENUM, NAME, MASK, ATTR, ICODE) +#define RS6000_BUILTIN_M(ENUM, NAME, MASK, ATTR, ICODE) #define RS6000_BUILTIN_P(ENUM, NAME, MASK, ATTR, ICODE) #define RS6000_BUILTIN_X(ENUM, NAME, MASK, ATTR, ICODE) @@ -8494,6 +8511,7 @@ static const struct builtin_description bdesc_2arg[] = #undef RS6000_BUILTIN_A #undef RS6000_BUILTIN_D #undef RS6000_BUILTIN_H +#undef RS6000_BUILTIN_M #undef RS6000_BUILTIN_P #undef RS6000_BUILTIN_X @@ -8505,6 +8523,7 @@ static const struct builtin_description bdesc_2arg[] = #define RS6000_BUILTIN_A(ENUM, NAME, MASK, ATTR, ICODE) #define RS6000_BUILTIN_D(ENUM, NAME, MASK, ATTR, ICODE) #define RS6000_BUILTIN_H(ENUM, NAME, MASK, ATTR, ICODE) +#define RS6000_BUILTIN_M(ENUM, NAME, MASK, ATTR, ICODE) #define RS6000_BUILTIN_P(ENUM, NAME, MASK, ATTR, ICODE) \ { MASK, ICODE, NAME, ENUM }, @@ -8527,6 +8546,7 @@ static const struct builtin_description bdesc_altivec_preds[] = #undef RS6000_BUILTIN_A #undef RS6000_BUILTIN_D #undef RS6000_BUILTIN_H +#undef RS6000_BUILTIN_M #undef RS6000_BUILTIN_P #undef RS6000_BUILTIN_X @@ -8540,6 +8560,7 @@ static const struct builtin_description bdesc_altivec_preds[] = #define RS6000_BUILTIN_D(ENUM, NAME, MASK, ATTR, ICODE) #define RS6000_BUILTIN_H(ENUM, NAME, MASK, ATTR, ICODE) +#define RS6000_BUILTIN_M(ENUM, NAME, MASK, ATTR, ICODE) #define RS6000_BUILTIN_P(ENUM, NAME, MASK, ATTR, ICODE) #define RS6000_BUILTIN_X(ENUM, NAME, MASK, ATTR, ICODE) @@ -8559,6 +8580,7 @@ static const struct builtin_description bdesc_abs[] = #undef RS6000_BUILTIN_A #undef RS6000_BUILTIN_D #undef RS6000_BUILTIN_H +#undef RS6000_BUILTIN_M #undef RS6000_BUILTIN_P #undef RS6000_BUILTIN_X @@ -8572,6 +8594,7 @@ static const struct builtin_description bdesc_abs[] = #define RS6000_BUILTIN_A(ENUM, NAME, MASK, ATTR, ICODE) #define RS6000_BUILTIN_D(ENUM, NAME, MASK, ATTR, ICODE) #define RS6000_BUILTIN_H(ENUM, NAME, MASK, ATTR, ICODE) +#define RS6000_BUILTIN_M(ENUM, NAME, MASK, ATTR, ICODE) #define RS6000_BUILTIN_P(ENUM, NAME, MASK, ATTR, ICODE) #define RS6000_BUILTIN_X(ENUM, NAME, MASK, ATTR, ICODE) @@ -8590,6 +8613,7 @@ static const struct builtin_description bdesc_1arg[] = #undef RS6000_BUILTIN_A #undef RS6000_BUILTIN_D #undef RS6000_BUILTIN_H +#undef RS6000_BUILTIN_M #undef RS6000_BUILTIN_P #undef RS6000_BUILTIN_X @@ -8603,6 +8627,7 @@ static const struct builtin_description bdesc_1arg[] = #define RS6000_BUILTIN_A(ENUM, NAME, MASK, ATTR, ICODE) #define RS6000_BUILTIN_D(ENUM, NAME, MASK, ATTR, ICODE) #define RS6000_BUILTIN_H(ENUM, NAME, MASK, ATTR, ICODE) +#define RS6000_BUILTIN_M(ENUM, NAME, MASK, ATTR, ICODE) #define RS6000_BUILTIN_P(ENUM, NAME, MASK, ATTR, ICODE) #define RS6000_BUILTIN_X(ENUM, NAME, MASK, ATTR, ICODE) @@ -8620,6 +8645,7 @@ static const struct builtin_description bdesc_0arg[] = #undef RS6000_BUILTIN_A #undef RS6000_BUILTIN_D #undef RS6000_BUILTIN_H +#undef RS6000_BUILTIN_M #undef RS6000_BUILTIN_P #undef RS6000_BUILTIN_X @@ -8633,6 +8659,7 @@ static const struct builtin_description bdesc_0arg[] = #define RS6000_BUILTIN_H(ENUM, NAME, MASK, ATTR, ICODE) \ { MASK, ICODE, NAME, ENUM }, +#define RS6000_BUILTIN_M(ENUM, NAME, MASK, ATTR, ICODE) #define RS6000_BUILTIN_P(ENUM, NAME, MASK, ATTR, ICODE) #define RS6000_BUILTIN_X(ENUM, NAME, MASK, ATTR, ICODE) @@ -8641,6 +8668,7 @@ static const struct builtin_description bdesc_htm[] = #include "rs6000-builtin.def" }; +/* MMA builtins. */ #undef RS6000_BUILTIN_0 #undef RS6000_BUILTIN_1 #undef RS6000_BUILTIN_2 @@ -8649,7 +8677,40 @@ static const struct builtin_description bdesc_htm[] = #undef RS6000_BUILTIN_A #undef RS6000_BUILTIN_D #undef RS6000_BUILTIN_H +#undef RS6000_BUILTIN_M #undef RS6000_BUILTIN_P +#undef RS6000_BUILTIN_X + +#define RS6000_BUILTIN_0(ENUM, NAME, MASK, ATTR, ICODE) +#define RS6000_BUILTIN_1(ENUM, NAME, MASK, ATTR, ICODE) +#define RS6000_BUILTIN_2(ENUM, NAME, MASK, ATTR, ICODE) +#define RS6000_BUILTIN_3(ENUM, NAME, MASK, ATTR, ICODE) +#define RS6000_BUILTIN_4(ENUM, NAME, MASK, ATTR, ICODE) +#define RS6000_BUILTIN_A(ENUM, NAME, MASK, ATTR, ICODE) +#define RS6000_BUILTIN_D(ENUM, NAME, MASK, ATTR, ICODE) +#define RS6000_BUILTIN_H(ENUM, NAME, MASK, ATTR, ICODE) +#define RS6000_BUILTIN_M(ENUM, NAME, MASK, ATTR, ICODE) \ + { MASK, ICODE, NAME, ENUM }, + +#define RS6000_BUILTIN_P(ENUM, NAME, MASK, ATTR, ICODE) +#define RS6000_BUILTIN_X(ENUM, NAME, MASK, ATTR, ICODE) + +static const struct builtin_description bdesc_mma[] = +{ +#include "rs6000-builtin.def" +}; + +#undef RS6000_BUILTIN_0 +#undef RS6000_BUILTIN_1 +#undef RS6000_BUILTIN_2 +#undef RS6000_BUILTIN_3 +#undef RS6000_BUILTIN_4 +#undef RS6000_BUILTIN_A +#undef RS6000_BUILTIN_D +#undef RS6000_BUILTIN_H +#undef RS6000_BUILTIN_M +#undef RS6000_BUILTIN_P +#undef RS6000_BUILTIN_X /* Return true if a builtin function is overloaded. */ bool @@ -9393,6 +9454,133 @@ altivec_expand_stv_builtin (enum insn_code icode, tree exp) return NULL_RTX; } +/* Expand the MMA built-in in EXP. + Store true in *EXPANDEDP if we found a built-in to expand. */ + +static rtx +mma_expand_builtin (tree exp, rtx target, bool *expandedp) +{ + unsigned i; + tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0); + enum rs6000_builtins fcode + = (enum rs6000_builtins) DECL_MD_FUNCTION_CODE (fndecl); + const struct builtin_description *d = bdesc_mma; + + /* Expand the MMA built-in. */ + for (i = 0; i < ARRAY_SIZE (bdesc_mma); i++, d++) + if (d->code == fcode) + break; + + if (i >= ARRAY_SIZE (bdesc_mma)) + { + *expandedp = false; + return NULL_RTX; + } + + *expandedp = true; + + tree arg; + call_expr_arg_iterator iter; + enum insn_code icode = d->icode; + const struct insn_operand_data *insn_op; + rtx op[MAX_MMA_OPERANDS]; + unsigned nopnds = 0; + unsigned attr = rs6000_builtin_info[fcode].attr; + bool void_func = (attr & RS6000_BTC_VOID); + machine_mode tmode = VOIDmode; + + if (TREE_TYPE (TREE_TYPE (fndecl)) != void_type_node) + { + tmode = insn_data[icode].operand[0].mode; + if (!target + || GET_MODE (target) != tmode + || !(*insn_data[icode].operand[0].predicate) (target, tmode)) + target = gen_reg_rtx (tmode); + op[nopnds++] = target; + } + else + target = const0_rtx; + + FOR_EACH_CALL_EXPR_ARG (arg, iter, exp) + { + if (arg == error_mark_node) + return const0_rtx; + + rtx opnd; + insn_op = &insn_data[icode].operand[nopnds]; + if (TREE_CODE (arg) == ADDR_EXPR + && MEM_P (DECL_RTL (TREE_OPERAND (arg, 0)))) + opnd = DECL_RTL (TREE_OPERAND (arg, 0)); + else + opnd = expand_normal (arg); + + if (!(*insn_op->predicate) (opnd, insn_op->mode)) + { + if (!strcmp (insn_op->constraint, "n")) + { + if (!CONST_INT_P (opnd)) + error ("argument %d must be an unsigned literal", nopnds); + else + error ("argument %d is an unsigned literal that is " + "out of range", nopnds); + return const0_rtx; + } + opnd = copy_to_mode_reg (insn_op->mode, opnd); + } + + /* Some MMA instructions have INOUT accumulator operands, so force + their target register to be the same as their input register. */ + if (!void_func + && nopnds == 1 + && !strcmp (insn_op->constraint, "0") + && insn_op->mode == tmode + && REG_P (opnd) + && (*insn_data[icode].operand[0].predicate) (opnd, tmode)) + target = op[0] = opnd; + + op[nopnds++] = opnd; + } + + unsigned attr_args = attr & RS6000_BTC_OPND_MASK; + if (attr & RS6000_BTC_QUAD) + attr_args++; + + gcc_assert (nopnds == attr_args); + + rtx pat; + switch (nopnds) + { + case 1: + pat = GEN_FCN (icode) (op[0]); + break; + case 2: + pat = GEN_FCN (icode) (op[0], op[1]); + break; + case 3: + pat = GEN_FCN (icode) (op[0], op[1], op[2]); + break; + case 4: + pat = GEN_FCN (icode) (op[0], op[1], op[2], op[3]); + break; + case 5: + pat = GEN_FCN (icode) (op[0], op[1], op[2], op[3], op[4]); + break; + case 6: + pat = GEN_FCN (icode) (op[0], op[1], op[2], op[3], op[4], op[5]); + break; + case 7: + pat = GEN_FCN (icode) (op[0], op[1], op[2], op[3], op[4], op[5], op[6]); + break; + default: + gcc_unreachable (); + } + if (!pat) + return NULL_RTX; + emit_insn (pat); + + return target; +} + /* Return the appropriate SPR number associated with the given builtin. */ static inline HOST_WIDE_INT htm_spr_num (enum rs6000_builtins code) @@ -9539,11 +9727,11 @@ htm_expand_builtin (tree exp, rtx target, bool * expandedp) if (flag_checking) { int expected_nopnds = 0; - if ((attr & RS6000_BTC_TYPE_MASK) == RS6000_BTC_UNARY) + if ((attr & RS6000_BTC_OPND_MASK) == RS6000_BTC_UNARY) expected_nopnds = 1; - else if ((attr & RS6000_BTC_TYPE_MASK) == RS6000_BTC_BINARY) + else if ((attr & RS6000_BTC_OPND_MASK) == RS6000_BTC_BINARY) expected_nopnds = 2; - else if ((attr & RS6000_BTC_TYPE_MASK) == RS6000_BTC_TERNARY) + else if ((attr & RS6000_BTC_OPND_MASK) == RS6000_BTC_TERNARY) expected_nopnds = 3; else if ((attr & RS6000_BTC_TYPE_MASK) == RS6000_BTC_QUATERNARY) expected_nopnds = 4; @@ -10647,6 +10835,10 @@ rs6000_invalid_builtin (enum rs6000_builtins fncode) "-m64"); else if ((fnmask & RS6000_BTM_P9_MISC) == RS6000_BTM_P9_MISC) error ("%qs requires the %qs option", name, "-mcpu=power9"); + else if ((fnmask & RS6000_BTM_FUTURE) != 0) + error ("%qs requires the %qs option", name, "-mcpu=future"); + else if ((fnmask & RS6000_BTM_MMA) != 0) + error ("%qs requires the %qs option", name, "-mmma"); else if ((fnmask & RS6000_BTM_LDBL128) == RS6000_BTM_LDBL128) { if (!TARGET_HARD_FLOAT) @@ -10690,6 +10882,10 @@ rs6000_fold_builtin (tree fndecl ATTRIBUTE_UNUSED, static bool rs6000_builtin_valid_without_lhs (enum rs6000_builtins fn_code) { + /* Check for built-ins explicitly marked as a void function. */ + if (rs6000_builtin_info[fn_code].attr & RS6000_BTC_VOID) + return true; + switch (fn_code) { case ALTIVEC_BUILTIN_STVX_V16QI: @@ -10836,6 +11032,156 @@ fold_mergeeo_helper (gimple_stmt_iterator *gsi, gimple *stmt, int use_odd) gsi_replace (gsi, g, true); } +/* Expand the MMA built-ins early, so that we can convert the pass-by-reference + __vector_quad arguments into pass-by-value arguments, leading to more + efficient code generation. */ + +bool +rs6000_gimple_fold_mma_builtin (gimple_stmt_iterator *gsi) +{ + gimple *stmt = gsi_stmt (*gsi); + tree fndecl = gimple_call_fndecl (stmt); + enum rs6000_builtins fncode + = (enum rs6000_builtins) DECL_MD_FUNCTION_CODE (fndecl); + unsigned attr = rs6000_builtin_info[fncode].attr; + + if ((attr & RS6000_BTC_GIMPLE) == 0) + return false; + + unsigned nopnds = (attr & RS6000_BTC_OPND_MASK); + gimple_seq new_seq = NULL; + gimple *new_call; + tree new_decl; + + if (rs6000_builtin_info[fncode + 1].icode == CODE_FOR_nothing) + { + /* This is an MMA disassemble built-in function. */ + gcc_assert (fncode == MMA_BUILTIN_DISASSEMBLE_ACC + || fncode == MMA_BUILTIN_DISASSEMBLE_PAIR); + + push_gimplify_context (true); + tree dst_ptr = gimple_call_arg (stmt, 0); + tree src_ptr = gimple_call_arg (stmt, 1); + tree src_type = TREE_TYPE (src_ptr); + tree src = make_ssa_name (TREE_TYPE (src_type)); + gimplify_assign (src, build_simple_mem_ref (src_ptr), &new_seq); + + /* If we are not disassembling an accumulator or our destination is + another accumulator, then just copy the entire thing as is. */ + if (fncode != MMA_BUILTIN_DISASSEMBLE_ACC + || TREE_TYPE (TREE_TYPE (dst_ptr)) == vector_quad_type_node) + { + tree dst = build_simple_mem_ref (build1 (VIEW_CONVERT_EXPR, + src_type, dst_ptr)); + gimplify_assign (dst, src, &new_seq); + pop_gimplify_context (NULL); + gsi_replace_with_seq (gsi, new_seq, true); + return true; + } + + /* We're disassembling an accumulator into a different type, so we need + to emit a xxmfacc instruction now, since we cannot do it later. */ + new_decl = rs6000_builtin_decls[MMA_BUILTIN_XXMFACC_INTERNAL]; + new_call = gimple_build_call (new_decl, 1, src); + src = make_ssa_name (vector_quad_type_node); + gimple_call_set_lhs (new_call, src); + gimple_seq_add_stmt (&new_seq, new_call); + + /* Copy the accumulator vector by vector. */ + tree dst_type = build_pointer_type_for_mode (unsigned_V16QI_type_node, + ptr_mode, true); + tree dst_base = build1 (VIEW_CONVERT_EXPR, dst_type, dst_ptr); + tree array_type = build_array_type_nelts (unsigned_V16QI_type_node, 4); + tree src_array = build1 (VIEW_CONVERT_EXPR, array_type, src); + for (unsigned i = 0; i < 4; i++) + { + tree ref = build4 (ARRAY_REF, unsigned_V16QI_type_node, src_array, + build_int_cst (size_type_node, i), + NULL_TREE, NULL_TREE); + tree dst = build2 (MEM_REF, unsigned_V16QI_type_node, dst_base, + build_int_cst (dst_type, i * 16)); + gimplify_assign (dst, ref, &new_seq); + } + pop_gimplify_context (NULL); + gsi_replace_with_seq (gsi, new_seq, true); + return true; + } + + /* Convert this built-in into an internal version that uses pass-by-value + arguments. The internal built-in follows immediately after this one. */ + new_decl = rs6000_builtin_decls[fncode + 1]; + tree lhs, mem, op[MAX_MMA_OPERANDS]; + tree acc = gimple_call_arg (stmt, 0); + if (TREE_CODE (acc) == PARM_DECL) + mem = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (acc)), acc); + else + mem = build_simple_mem_ref (acc); + push_gimplify_context (true); + + if ((attr & RS6000_BTC_QUAD) != 0) + { + /* This built-in has a pass-by-reference accumulator input, so load it + into a temporary accumulator for use as a pass-by-value input. */ + op[0] = make_ssa_name (vector_quad_type_node); + for (unsigned i = 1; i < nopnds; i++) + op[i] = gimple_call_arg (stmt, i); + gimplify_assign (op[0], mem, &new_seq); + } + else + { + /* This built-in does not use its pass-by-reference accumulator argument + as an input argument, so remove it from the input list. */ + nopnds--; + for (unsigned i = 0; i < nopnds; i++) + op[i] = gimple_call_arg (stmt, i + 1); + } + + switch (nopnds) + { + case 0: + new_call = gimple_build_call (new_decl, 0); + break; + case 1: + new_call = gimple_build_call (new_decl, 1, op[0]); + break; + case 2: + new_call = gimple_build_call (new_decl, 2, op[0], op[1]); + break; + case 3: + new_call = gimple_build_call (new_decl, 3, op[0], op[1], op[2]); + break; + case 4: + new_call = gimple_build_call (new_decl, 4, op[0], op[1], op[2], op[3]); + break; + case 5: + new_call = gimple_build_call (new_decl, 5, op[0], op[1], op[2], op[3], + op[4]); + break; + case 6: + new_call = gimple_build_call (new_decl, 6, op[0], op[1], op[2], op[3], + op[4], op[5]); + break; + case 7: + new_call = gimple_build_call (new_decl, 7, op[0], op[1], op[2], op[3], + op[4], op[5], op[6]); + break; + default: + gcc_unreachable (); + } + + if (fncode == MMA_BUILTIN_ASSEMBLE_PAIR) + lhs = make_ssa_name (vector_pair_type_node); + else + lhs = make_ssa_name (vector_quad_type_node); + gimple_call_set_lhs (new_call, lhs); + gimple_seq_add_stmt (&new_seq, new_call); + gimplify_assign (mem, lhs, &new_seq); + pop_gimplify_context (NULL); + gsi_replace_with_seq (gsi, new_seq, true); + + return true; +} + /* Fold a machine-dependent built-in in GIMPLE. (For folding into a constant, use rs6000_fold_builtin.) */ @@ -10871,11 +11217,12 @@ rs6000_gimple_fold_builtin (gimple_stmt_iterator *gsi) return false; /* Don't fold invalid builtins, let rs6000_expand_builtin diagnose it. */ - HOST_WIDE_INT mask = rs6000_builtin_info[uns_fncode].mask; - bool func_valid_p = (rs6000_builtin_mask & mask) == mask; - if (!func_valid_p) + if (!rs6000_builtin_is_supported_p (fn_code)) return false; + if (rs6000_gimple_fold_mma_builtin (gsi)) + return true; + switch (fn_code) { /* Flavors of vec_add. We deliberately don't expand @@ -12010,6 +12357,13 @@ rs6000_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED, break; } + if (TARGET_MMA) + { + ret = mma_expand_builtin (exp, target, &success); + + if (success) + return ret; + } if (TARGET_ALTIVEC) { ret = altivec_expand_builtin (exp, target, &success); @@ -12025,7 +12379,7 @@ rs6000_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED, return ret; } - unsigned attr = rs6000_builtin_info[uns_fcode].attr & RS6000_BTC_TYPE_MASK; + unsigned attr = rs6000_builtin_info[uns_fcode].attr & RS6000_BTC_OPND_MASK; /* RS6000_BTC_SPECIAL represents no-operand operators. */ gcc_assert (attr == RS6000_BTC_UNARY || attr == RS6000_BTC_BINARY @@ -12208,7 +12562,7 @@ rs6000_init_builtins (void) else ieee128_float_type_node = ibm128_float_type_node = long_double_type_node; - /* Vector paired and vector quad support. */ + /* Vector pair and vector quad support. */ if (TARGET_MMA) { tree oi_uns_type = make_unsigned_type (256); @@ -12290,6 +12644,8 @@ rs6000_init_builtins (void) the target attribute. */ if (TARGET_EXTRA_BUILTINS) altivec_init_builtins (); + if (TARGET_MMA) + mma_init_builtins (); if (TARGET_HTM) htm_init_builtins (); @@ -13016,6 +13372,119 @@ altivec_init_builtins (void) } static void +mma_init_builtins (void) +{ + const struct builtin_description *d = bdesc_mma; + + for (unsigned i = 0; i < ARRAY_SIZE (bdesc_mma); i++, d++) + { + tree op[MAX_MMA_OPERANDS], type; + HOST_WIDE_INT mask = d->mask; + unsigned icode = (unsigned) d->icode; + unsigned attr = rs6000_builtin_info[d->code].attr; + int attr_args = (attr & RS6000_BTC_OPND_MASK); + bool gimple_func = (attr & RS6000_BTC_GIMPLE); + unsigned nopnds = 0; + + if ((mask & rs6000_builtin_mask) != mask) + { + if (TARGET_DEBUG_BUILTIN) + fprintf (stderr, "mma_builtin, skip binary %s\n", d->name); + continue; + } + + if (d->name == 0) + { + if (TARGET_DEBUG_BUILTIN) + fprintf (stderr, "mma_builtin, bdesc_mma[%ld] no name\n", + (long unsigned) i); + continue; + } + + if (gimple_func) + { + gcc_assert (icode == CODE_FOR_nothing); + op[nopnds++] = void_type_node; + /* Some MMA built-ins that are expanded into gimple are converted + into internal MMA built-ins that are expanded into rtl. + The internal built-in follows immediately after this built-in. */ + icode = d[1].icode; + } + else + { + if ((attr & RS6000_BTC_QUAD) == 0) + attr_args--; + + /* Ensure we have the correct number and type of operands. */ + gcc_assert (attr_args == insn_data[icode].n_operands - 1); + } + + if (icode == CODE_FOR_nothing) + { + /* This is a disassemble MMA built-in function. */ + gcc_assert (attr_args == RS6000_BTC_BINARY + && (d->code == MMA_BUILTIN_DISASSEMBLE_ACC + || d->code == MMA_BUILTIN_DISASSEMBLE_PAIR)); + op[nopnds++] = build_pointer_type (void_type_node); + if (attr & RS6000_BTC_QUAD) + op[nopnds++] = build_pointer_type (vector_quad_type_node); + else + op[nopnds++] = build_pointer_type (vector_pair_type_node); + } + else + { + /* This is a normal MMA built-in function. */ + unsigned j = (attr & RS6000_BTC_QUAD) ? 1 : 0; + for (; j < insn_data[icode].n_operands; j++) + { + machine_mode mode = insn_data[icode].operand[j].mode; + if (gimple_func && mode == PXImode) + op[nopnds++] = build_pointer_type (vector_quad_type_node); + else if (gimple_func && mode == POImode + && d->code == MMA_BUILTIN_ASSEMBLE_PAIR) + op[nopnds++] = build_pointer_type (vector_pair_type_node); + else + /* MMA uses unsigned types. */ + op[nopnds++] = builtin_mode_to_type[mode][1]; + } + } + + switch (nopnds) + { + case 1: + type = build_function_type_list (op[0], NULL_TREE); + break; + case 2: + type = build_function_type_list (op[0], op[1], NULL_TREE); + break; + case 3: + type = build_function_type_list (op[0], op[1], op[2], NULL_TREE); + break; + case 4: + type = build_function_type_list (op[0], op[1], op[2], op[3], + NULL_TREE); + break; + case 5: + type = build_function_type_list (op[0], op[1], op[2], op[3], op[4], + NULL_TREE); + break; + case 6: + type = build_function_type_list (op[0], op[1], op[2], op[3], op[4], + op[5], NULL_TREE); + break; + case 7: + type = build_function_type_list (op[0], op[1], op[2], op[3], op[4], + op[5], op[6], NULL_TREE); + break; + default: + gcc_unreachable (); + } + + def_builtin (d->name, type, d->code); + } +} + +static void htm_init_builtins (void) { HOST_WIDE_INT builtin_mask = rs6000_builtin_mask; @@ -13029,7 +13498,7 @@ htm_init_builtins (void) HOST_WIDE_INT mask = d->mask; unsigned attr = rs6000_builtin_info[d->code].attr; bool void_func = (attr & RS6000_BTC_VOID); - int attr_args = (attr & RS6000_BTC_TYPE_MASK); + int attr_args = (attr & RS6000_BTC_OPND_MASK); int nopnds = 0; tree gpr_type_node; tree rettype; @@ -13195,6 +13664,8 @@ builtin_function_type (machine_mode mode_ret, machine_mode mode_arg0, case P8V_BUILTIN_VGBBD: case MISC_BUILTIN_CDTBCD: case MISC_BUILTIN_CBCDTD: + case VSX_BUILTIN_XVCVSPBF16: + case VSX_BUILTIN_XVCVBF16SP: h.uns_p[0] = 1; h.uns_p[1] = 1; break; |