diff options
Diffstat (limited to 'gcc/config/rs6000/rs6000-call.c')
-rw-r--r-- | gcc/config/rs6000/rs6000-call.c | 251 |
1 files changed, 251 insertions, 0 deletions
diff --git a/gcc/config/rs6000/rs6000-call.c b/gcc/config/rs6000/rs6000-call.c index 9da5b48463e..7c43db18d65 100644 --- a/gcc/config/rs6000/rs6000-call.c +++ b/gcc/config/rs6000/rs6000-call.c @@ -237,6 +237,7 @@ builtin_hasher::equal (builtin_hash_struct *p1, builtin_hash_struct *p2) #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 @@ -255,6 +256,9 @@ builtin_hasher::equal (builtin_hash_struct *p1, builtin_hash_struct *p2) #define RS6000_BUILTIN_3(ENUM, NAME, MASK, ATTR, ICODE) \ { NAME, ICODE, MASK, ATTR }, +#define RS6000_BUILTIN_4(ENUM, NAME, MASK, ATTR, ICODE) \ + { NAME, ICODE, MASK, ATTR }, + #define RS6000_BUILTIN_A(ENUM, NAME, MASK, ATTR, ICODE) \ { NAME, ICODE, MASK, ATTR }, @@ -286,6 +290,7 @@ static const struct rs6000_builtin_info_type rs6000_builtin_info[] = #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 @@ -5527,6 +5532,25 @@ const struct altivec_builtin_types altivec_overloaded_builtins[] = { RS6000_BTI_unsigned_V2DI, RS6000_BTI_UINTQI, 0 }, { FUTURE_BUILTIN_VEC_GNB, FUTURE_BUILTIN_VGNB, RS6000_BTI_unsigned_long_long, RS6000_BTI_unsigned_V1TI, RS6000_BTI_UINTQI, 0 }, + + /* The overloaded XXEVAL definitions are handled specially because the + fourth unsigned char operand is not encoded in this table. */ + { FUTURE_BUILTIN_VEC_XXEVAL, FUTURE_BUILTIN_XXEVAL, + RS6000_BTI_unsigned_V16QI, RS6000_BTI_unsigned_V16QI, + RS6000_BTI_unsigned_V16QI, RS6000_BTI_unsigned_V16QI }, + { FUTURE_BUILTIN_VEC_XXEVAL, FUTURE_BUILTIN_XXEVAL, + RS6000_BTI_unsigned_V8HI, RS6000_BTI_unsigned_V8HI, + RS6000_BTI_unsigned_V8HI, RS6000_BTI_unsigned_V8HI }, + { FUTURE_BUILTIN_VEC_XXEVAL, FUTURE_BUILTIN_XXEVAL, + RS6000_BTI_unsigned_V4SI, RS6000_BTI_unsigned_V4SI, + RS6000_BTI_unsigned_V4SI, RS6000_BTI_unsigned_V4SI }, + { FUTURE_BUILTIN_VEC_XXEVAL, FUTURE_BUILTIN_XXEVAL, + RS6000_BTI_unsigned_V2DI, RS6000_BTI_unsigned_V2DI, + RS6000_BTI_unsigned_V2DI, RS6000_BTI_unsigned_V2DI }, + { FUTURE_BUILTIN_VEC_XXEVAL, FUTURE_BUILTIN_XXEVAL, + RS6000_BTI_unsigned_V1TI, RS6000_BTI_unsigned_V1TI, + RS6000_BTI_unsigned_V1TI, RS6000_BTI_unsigned_V1TI }, + { RS6000_BUILTIN_NONE, RS6000_BUILTIN_NONE, 0, 0, 0, 0 } }; @@ -8275,6 +8299,7 @@ def_builtin (const char *name, tree type, enum rs6000_builtins code) #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 @@ -8287,6 +8312,7 @@ def_builtin (const char *name, tree type, enum rs6000_builtins code) #define RS6000_BUILTIN_3(ENUM, NAME, MASK, ATTR, ICODE) \ { MASK, ICODE, NAME, ENUM }, +#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) @@ -8298,12 +8324,44 @@ static const struct builtin_description bdesc_3arg[] = #include "rs6000-builtin.def" }; +/* Simple quaternary operations: VECd = foo (VECa, VECb, VECc, VECd). */ + +#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_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) \ + { MASK, ICODE, NAME, ENUM }, + +#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_P(ENUM, NAME, MASK, ATTR, ICODE) +#define RS6000_BUILTIN_X(ENUM, NAME, MASK, ATTR, ICODE) + +static const struct builtin_description bdesc_4arg[] = +{ +#include "rs6000-builtin.def" +}; + /* DST operations: void foo (void *, const int, const char). */ #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 @@ -8314,6 +8372,7 @@ static const struct builtin_description bdesc_3arg[] = #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) \ { MASK, ICODE, NAME, ENUM }, @@ -8333,6 +8392,7 @@ static const struct builtin_description bdesc_dst[] = #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 @@ -8345,6 +8405,7 @@ static const struct builtin_description bdesc_dst[] = { MASK, ICODE, NAME, ENUM }, #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) @@ -8360,6 +8421,7 @@ static const struct builtin_description bdesc_2arg[] = #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 @@ -8370,6 +8432,7 @@ static const struct builtin_description bdesc_2arg[] = #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) @@ -8391,6 +8454,7 @@ static const struct builtin_description bdesc_altivec_preds[] = #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 @@ -8401,6 +8465,7 @@ static const struct builtin_description bdesc_altivec_preds[] = #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) \ { MASK, ICODE, NAME, ENUM }, @@ -8421,6 +8486,7 @@ static const struct builtin_description bdesc_abs[] = #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 @@ -8433,6 +8499,7 @@ static const struct builtin_description bdesc_abs[] = #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) @@ -8450,6 +8517,7 @@ static const struct builtin_description bdesc_1arg[] = #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 @@ -8462,6 +8530,7 @@ static const struct builtin_description bdesc_1arg[] = #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) @@ -8478,6 +8547,7 @@ static const struct builtin_description bdesc_0arg[] = #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 @@ -8488,6 +8558,7 @@ static const struct builtin_description bdesc_0arg[] = #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) \ @@ -8505,6 +8576,7 @@ static const struct builtin_description bdesc_htm[] = #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 @@ -9404,6 +9476,8 @@ htm_expand_builtin (tree exp, rtx target, bool * expandedp) expected_nopnds = 2; else if ((attr & RS6000_BTC_TYPE_MASK) == RS6000_BTC_TERNARY) expected_nopnds = 3; + else if ((attr & RS6000_BTC_TYPE_MASK) == RS6000_BTC_QUATERNARY) + expected_nopnds = 4; if (!(attr & RS6000_BTC_VOID)) expected_nopnds += 1; if (uses_spr) @@ -9581,6 +9655,76 @@ cpu_expand_builtin (enum rs6000_builtins fcode, tree exp ATTRIBUTE_UNUSED, } static rtx +rs6000_expand_quaternop_builtin (enum insn_code icode, tree exp, rtx target) +{ + rtx pat; + tree arg0 = CALL_EXPR_ARG (exp, 0); + tree arg1 = CALL_EXPR_ARG (exp, 1); + tree arg2 = CALL_EXPR_ARG (exp, 2); + tree arg3 = CALL_EXPR_ARG (exp, 3); + rtx op0 = expand_normal (arg0); + rtx op1 = expand_normal (arg1); + rtx op2 = expand_normal (arg2); + rtx op3 = expand_normal (arg3); + machine_mode tmode = insn_data[icode].operand[0].mode; + machine_mode mode0 = insn_data[icode].operand[1].mode; + machine_mode mode1 = insn_data[icode].operand[2].mode; + machine_mode mode2 = insn_data[icode].operand[3].mode; + machine_mode mode3 = insn_data[icode].operand[4].mode; + + if (icode == CODE_FOR_nothing) + /* Builtin not supported on this processor. */ + return 0; + + /* If we got invalid arguments bail out before generating bad rtl. */ + if (arg0 == error_mark_node + || arg1 == error_mark_node + || arg2 == error_mark_node + || arg3 == error_mark_node) + return const0_rtx; + + /* Check and prepare argument depending on the instruction code. + + Note that a switch statement instead of the sequence of tests + would be incorrect as many of the CODE_FOR values could be + CODE_FOR_nothing and that would yield multiple alternatives + with identical values. We'd never reach here at runtime in + this case. */ + if (icode == CODE_FOR_xxeval) + { + /* Only allow 8-bit unsigned literals. */ + STRIP_NOPS (arg3); + if (TREE_CODE (arg3) != INTEGER_CST + || TREE_INT_CST_LOW (arg3) & ~0xff) + { + error ("argument 4 must be an 8-bit unsigned literal"); + return CONST0_RTX (tmode); + } + } + + if (target == 0 + || GET_MODE (target) != tmode + || ! (*insn_data[icode].operand[0].predicate) (target, tmode)) + target = gen_reg_rtx (tmode); + + if (! (*insn_data[icode].operand[1].predicate) (op0, mode0)) + op0 = copy_to_mode_reg (mode0, op0); + if (! (*insn_data[icode].operand[2].predicate) (op1, mode1)) + op1 = copy_to_mode_reg (mode1, op1); + if (! (*insn_data[icode].operand[3].predicate) (op2, mode2)) + op2 = copy_to_mode_reg (mode2, op2); + if (! (*insn_data[icode].operand[4].predicate) (op3, mode3)) + op3 = copy_to_mode_reg (mode3, op3); + + pat = GEN_FCN (icode) (target, op0, op1, op2, op3); + if (! pat) + return 0; + emit_insn (pat); + + return target; +} + +static rtx rs6000_expand_ternop_builtin (enum insn_code icode, tree exp, rtx target) { rtx pat; @@ -11613,6 +11757,7 @@ rs6000_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED, case RS6000_BTC_UNARY: name3 = "unary"; break; case RS6000_BTC_BINARY: name3 = "binary"; break; case RS6000_BTC_TERNARY: name3 = "ternary"; break; + case RS6000_BTC_QUATERNARY:name3 = "quaternary";break; case RS6000_BTC_PREDICATE: name3 = "predicate"; break; case RS6000_BTC_ABS: name3 = "abs"; break; case RS6000_BTC_DST: name3 = "dst"; break; @@ -11795,6 +11940,7 @@ rs6000_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED, gcc_assert (attr == RS6000_BTC_UNARY || attr == RS6000_BTC_BINARY || attr == RS6000_BTC_TERNARY + || attr == RS6000_BTC_QUATERNARY || attr == RS6000_BTC_SPECIAL); /* Handle simple unary operations. */ @@ -11815,6 +11961,12 @@ rs6000_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED, if (d->code == fcode) return rs6000_expand_ternop_builtin (icode, exp, target); + /* Handle simple quaternary operations. */ + d = bdesc_4arg; + for (i = 0; i < ARRAY_SIZE (bdesc_4arg); i++, d++) + if (d->code == fcode) + return rs6000_expand_quaternop_builtin (icode, exp, target); + /* Handle simple no-argument operations. */ d = bdesc_0arg; for (i = 0; i < ARRAY_SIZE (bdesc_0arg); i++, d++) @@ -11969,7 +12121,9 @@ rs6000_init_builtins (void) /* Initialize the modes for builtin_function_type, mapping a machine mode to tree type node. */ builtin_mode_to_type[QImode][0] = integer_type_node; + builtin_mode_to_type[QImode][1] = unsigned_intSI_type_node; builtin_mode_to_type[HImode][0] = integer_type_node; + builtin_mode_to_type[HImode][1] = unsigned_intSI_type_node; builtin_mode_to_type[SImode][0] = intSI_type_node; builtin_mode_to_type[SImode][1] = unsigned_intSI_type_node; builtin_mode_to_type[DImode][0] = intDI_type_node; @@ -12850,6 +13004,46 @@ htm_init_builtins (void) } } +/* Map types for builtin functions with an explicit return type and + exactly 4 arguments. Functions with fewer than 3 arguments use + builtin_function_type. The number of quaternary built-in + functions is very small. Handle each case specially. */ +static tree +builtin_quaternary_function_type (machine_mode mode_ret, + machine_mode mode_arg0, + machine_mode mode_arg1, + machine_mode mode_arg2, + machine_mode mode_arg3, + enum rs6000_builtins builtin) +{ + tree function_type = NULL; + + static tree v2udi_type = builtin_mode_to_type[V2DImode][1]; + static tree uchar_type = builtin_mode_to_type[QImode][1]; + + static tree xxeval_type = + build_function_type_list (v2udi_type, v2udi_type, v2udi_type, + v2udi_type, uchar_type, NULL_TREE); + + switch (builtin) { + + case FUTURE_BUILTIN_XXEVAL: + gcc_assert ((mode_ret == V2DImode) + && (mode_arg0 == V2DImode) + && (mode_arg1 == V2DImode) + && (mode_arg2 == V2DImode) + && (mode_arg3 == QImode)); + function_type = xxeval_type; + break; + + default: + /* A case for each quaternary built-in must be provided above. */ + gcc_unreachable (); + } + + return function_type; +} + /* Map types for builtin functions with an explicit return type and up to 3 arguments. Functions with fewer than 3 arguments use VOIDmode as the type of the argument. */ @@ -13145,6 +13339,63 @@ rs6000_common_init_builtins (void) if (TARGET_EXTRA_BUILTINS) builtin_mask |= RS6000_BTM_COMMON; + /* Add the quaternary operators. */ + d = bdesc_4arg; + for (i = 0; i < ARRAY_SIZE (bdesc_4arg); i++, d++) + { + tree type; + HOST_WIDE_INT mask = d->mask; + + if ((mask & builtin_mask) != mask) + { + if (TARGET_DEBUG_BUILTIN) + fprintf (stderr, "rs6000_builtin, skip quaternary %s\n", d->name); + continue; + } + + if (rs6000_overloaded_builtin_p (d->code)) + { + type = opaque_ftype_opaque_opaque_opaque; + if (!type) + type = opaque_ftype_opaque_opaque_opaque + = build_function_type_list (opaque_V4SI_type_node, + opaque_V4SI_type_node, + opaque_V4SI_type_node, + opaque_V4SI_type_node, + opaque_V4SI_type_node, + NULL_TREE); + } + else + { + enum insn_code icode = d->icode; + if (d->name == 0) + { + if (TARGET_DEBUG_BUILTIN) + fprintf (stderr, "rs6000_builtin, bdesc_4arg[%ld] no name\n", + (long) i); + continue; + } + + if (icode == CODE_FOR_nothing) + { + if (TARGET_DEBUG_BUILTIN) + fprintf (stderr, + "rs6000_builtin, skip quaternary %s (no code)\n", + d->name); + continue; + } + + type = + builtin_quaternary_function_type (insn_data[icode].operand[0].mode, + insn_data[icode].operand[1].mode, + insn_data[icode].operand[2].mode, + insn_data[icode].operand[3].mode, + insn_data[icode].operand[4].mode, + d->code); + } + def_builtin (d->name, type, d->code); + } + /* Add the ternary operators. */ d = bdesc_3arg; for (i = 0; i < ARRAY_SIZE (bdesc_3arg); i++, d++) |