public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc(refs/users/wschmidt/heads/builtins4)] rs6000: Support two builtin expansion algorithms
@ 2020-12-16 18:07 William Schmidt
0 siblings, 0 replies; 5+ messages in thread
From: William Schmidt @ 2020-12-16 18:07 UTC (permalink / raw)
To: gcc-cvs
https://gcc.gnu.org/g:9f2ee3d47fb34e5f86f95d7974708d09e0e02961
commit 9f2ee3d47fb34e5f86f95d7974708d09e0e02961
Author: Bill Schmidt <wschmidt@linux.ibm.com>
Date: Mon Nov 2 11:16:08 2020 -0500
rs6000: Support two builtin expansion algorithms
2020-11-02 Bill Schmidt <wschmidt@linux.ibm.com>
* config/rs6000/rs6000-call.c (rs6000_expand_builtin): Support two
kinds of masks and icodes; use a new algorithm under control of
new_builtins_are_live, while still supporting the old one; do lazy
enablement to support #pragma target.
Diff:
---
gcc/config/rs6000/rs6000-call.c | 618 ++++++++++++++++++++++++++++++----------
1 file changed, 463 insertions(+), 155 deletions(-)
diff --git a/gcc/config/rs6000/rs6000-call.c b/gcc/config/rs6000/rs6000-call.c
index cb2d6a05470..3ad544dcd7e 100644
--- a/gcc/config/rs6000/rs6000-call.c
+++ b/gcc/config/rs6000/rs6000-call.c
@@ -13513,6 +13513,10 @@ rs6000_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
int ignore ATTRIBUTE_UNUSED)
{
tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
+ /* #### This needs to be rs6000_gen_builtins now. Can't make this
+ whole until the full set of builtins has been added, and there
+ is no overlap between the two enumerations, so we can run the
+ two in parallel. */
enum rs6000_builtins fcode
= (enum rs6000_builtins) DECL_MD_FUNCTION_CODE (fndecl);
size_t uns_fcode = (size_t)fcode;
@@ -13520,9 +13524,18 @@ rs6000_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
size_t i;
rtx ret;
bool success;
- HOST_WIDE_INT mask = rs6000_builtin_info[uns_fcode].mask;
+ HOST_WIDE_INT mask = (new_builtins_are_live
+ ? 0
+ : rs6000_builtin_info[uns_fcode].mask);
+ /*
+ bif_enable enable = (new_builtins_are_live
+ ? rs6000_builtin_info_x[uns_fcode].enable
+ : (bif_enable) 0);
+ */
bool func_valid_p = ((rs6000_builtin_mask & mask) == mask);
- enum insn_code icode = rs6000_builtin_info[uns_fcode].icode;
+ enum insn_code icode = (new_builtins_are_live
+ ? rs6000_builtin_info_x[uns_fcode].icode
+ : rs6000_builtin_info[uns_fcode].icode);
/* We have two different modes (KFmode, TFmode) that are the IEEE 128-bit
floating point type, depending on whether long double is the IBM extended
@@ -13569,7 +13582,7 @@ rs6000_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
break;
}
- if (TARGET_DEBUG_BUILTIN)
+ if (!new_builtins_are_live && TARGET_DEBUG_BUILTIN)
{
const char *name1 = rs6000_builtin_info[uns_fcode].name;
const char *name2 = (icode != CODE_FOR_nothing)
@@ -13607,201 +13620,496 @@ rs6000_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
return expand_call (exp, target, ignore);
}
- switch (fcode)
+ if (new_builtins_are_live)
{
- case RS6000_BUILTIN_RECIP:
- return rs6000_expand_binop_builtin (CODE_FOR_recipdf3, exp, target);
-
- case RS6000_BUILTIN_RECIPF:
- return rs6000_expand_binop_builtin (CODE_FOR_recipsf3, exp, target);
-
- case RS6000_BUILTIN_RSQRTF:
- return rs6000_expand_unop_builtin (CODE_FOR_rsqrtsf2, exp, target);
-
- case RS6000_BUILTIN_RSQRT:
- return rs6000_expand_unop_builtin (CODE_FOR_rsqrtdf2, exp, target);
-
- case POWER7_BUILTIN_BPERMD:
- return rs6000_expand_binop_builtin (((TARGET_64BIT)
- ? CODE_FOR_bpermd_di
- : CODE_FOR_bpermd_si), exp, target);
+ bifdata *bifaddr = &rs6000_builtin_info_x[uns_fcode];
- case RS6000_BUILTIN_GET_TB:
- return rs6000_expand_zeroop_builtin (CODE_FOR_rs6000_get_timebase,
- target);
-
- case RS6000_BUILTIN_MFTB:
- return rs6000_expand_zeroop_builtin (((TARGET_64BIT)
- ? CODE_FOR_rs6000_mftb_di
- : CODE_FOR_rs6000_mftb_si),
- target);
-
- case RS6000_BUILTIN_MFFS:
- return rs6000_expand_zeroop_builtin (CODE_FOR_rs6000_mffs, target);
+ /* In case of "#pragma target" changes, we initialize all builtins
+ but check for actual availability during expand time. */
+ switch (bifaddr->enable)
+ {
+ default:
+ gcc_unreachable ();
+ case ENB_ALWAYS:
+ break;
+ case ENB_P5:
+ if (!TARGET_POPCNTB)
+ return const0_rtx;
+ break;
+ case ENB_P6:
+ if (!TARGET_CMPB)
+ return const0_rtx;
+ break;
+ case ENB_ALTIVEC:
+ if (!TARGET_ALTIVEC)
+ return const0_rtx;
+ break;
+ case ENB_CELL:
+ if (!TARGET_ALTIVEC || rs6000_cpu != PROCESSOR_CELL)
+ return const0_rtx;
+ break;
+ case ENB_VSX:
+ if (!TARGET_VSX)
+ return const0_rtx;
+ break;
+ case ENB_P7:
+ if (!TARGET_POPCNTD)
+ return const0_rtx;
+ break;
+ case ENB_P7_64:
+ if (!TARGET_POPCNTD || !TARGET_POWERPC64)
+ return const0_rtx;
+ break;
+ case ENB_P8:
+ if (!TARGET_DIRECT_MOVE)
+ return const0_rtx;
+ break;
+ case ENB_P8V:
+ if (!TARGET_P8_VECTOR)
+ return const0_rtx;
+ break;
+ case ENB_P9:
+ if (!TARGET_MODULO)
+ return const0_rtx;
+ break;
+ case ENB_P9_64:
+ if (!TARGET_MODULO || !TARGET_POWERPC64)
+ return const0_rtx;
+ break;
+ case ENB_P9V:
+ if (!TARGET_P9_VECTOR)
+ return const0_rtx;
+ break;
+ case ENB_IEEE128_HW:
+ if (!TARGET_FLOAT128_HW)
+ return const0_rtx;
+ break;
+ case ENB_DFP:
+ if (!TARGET_DFP)
+ return const0_rtx;
+ break;
+ case ENB_CRYPTO:
+ if (!TARGET_CRYPTO)
+ return const0_rtx;
+ break;
+ case ENB_HTM:
+ if (!TARGET_HTM)
+ return const0_rtx;
+ break;
+ case ENB_P10:
+ if (!TARGET_POWER10)
+ return const0_rtx;
+ break;
+ case ENB_MMA:
+ if (!TARGET_MMA)
+ return const0_rtx;
+ break;
+ };
- case RS6000_BUILTIN_MTFSB0:
- return rs6000_expand_mtfsb_builtin (CODE_FOR_rs6000_mtfsb0, exp);
+ if (bif_is_nosoft (*bifaddr)
+ && rs6000_isa_flags & OPTION_MASK_SOFT_FLOAT)
+ {
+ error ("%<%s%> not supported with %<-msoft-float%>",
+ bifaddr->bifname);
+ return const0_rtx;
+ }
- case RS6000_BUILTIN_MTFSB1:
- return rs6000_expand_mtfsb_builtin (CODE_FOR_rs6000_mtfsb1, exp);
+ if (bif_is_no32bit (*bifaddr) && TARGET_32BIT)
+ fatal_error (input_location,
+ "%<%s%> is not supported in 32-bit mode",
+ bifaddr->bifname);
- case RS6000_BUILTIN_SET_FPSCR_RN:
- return rs6000_expand_set_fpscr_rn_builtin (CODE_FOR_rs6000_set_fpscr_rn,
- exp);
+ if (bif_is_cpu (*bifaddr))
+ return cpu_expand_builtin (fcode, exp, target);
- case RS6000_BUILTIN_SET_FPSCR_DRN:
- return
- rs6000_expand_set_fpscr_drn_builtin (CODE_FOR_rs6000_set_fpscr_drn,
- exp);
+ if (bif_is_init (*bifaddr))
+ return altivec_expand_vec_init_builtin (TREE_TYPE (exp), exp, target);
- case RS6000_BUILTIN_MFFSL:
- return rs6000_expand_zeroop_builtin (CODE_FOR_rs6000_mffsl, target);
+ if (bif_is_set (*bifaddr))
+ return altivec_expand_vec_set_builtin (exp);
- case RS6000_BUILTIN_MTFSF:
- return rs6000_expand_mtfsf_builtin (CODE_FOR_rs6000_mtfsf, exp);
+ if (bif_is_extract (*bifaddr))
+ return altivec_expand_vec_ext_builtin (exp, target);
- case RS6000_BUILTIN_CPU_INIT:
- case RS6000_BUILTIN_CPU_IS:
- case RS6000_BUILTIN_CPU_SUPPORTS:
- return cpu_expand_builtin (fcode, exp, target);
+ if (bif_is_predicate (*bifaddr))
+ return altivec_expand_predicate_builtin (icode, exp, target);
- case MISC_BUILTIN_SPEC_BARRIER:
- {
- emit_insn (gen_speculation_barrier ());
- return NULL_RTX;
- }
+ if (bif_is_htm (*bifaddr))
+ return new_htm_expand_builtin (bifaddr, fcode, exp, target);
- case ALTIVEC_BUILTIN_MASK_FOR_LOAD:
- {
- int icode2 = (BYTES_BIG_ENDIAN ? (int) CODE_FOR_altivec_lvsr_direct
- : (int) CODE_FOR_altivec_lvsl_direct);
- machine_mode tmode = insn_data[icode2].operand[0].mode;
- machine_mode mode = insn_data[icode2].operand[1].mode;
- tree arg;
- rtx op, addr, pat;
+ rtx pat;
+ const int MAX_BUILTIN_ARGS = 5;
+ tree arg[MAX_BUILTIN_ARGS];
+ rtx op[MAX_BUILTIN_ARGS];
+ machine_mode mode[MAX_BUILTIN_ARGS + 1];
- gcc_assert (TARGET_ALTIVEC);
+ int nargs = bifaddr->nargs;
+ gcc_assert (nargs <= MAX_BUILTIN_ARGS);
- arg = CALL_EXPR_ARG (exp, 0);
- gcc_assert (POINTER_TYPE_P (TREE_TYPE (arg)));
- op = expand_expr (arg, NULL_RTX, Pmode, EXPAND_NORMAL);
- addr = memory_address (mode, op);
- /* We need to negate the address. */
- op = gen_reg_rtx (GET_MODE (addr));
- emit_insn (gen_rtx_SET (op, gen_rtx_NEG (GET_MODE (addr), addr)));
- op = gen_rtx_MEM (mode, op);
+ mode[0] = insn_data[icode].operand[0].mode;
+ for (int i = 0; i < nargs; i++)
+ {
+ arg[i] = CALL_EXPR_ARG (exp, i);
+ if (arg[i] == error_mark_node)
+ return const0_rtx;
+ op[i] = expand_normal (arg[i]);
+ mode[i+1] = insn_data[icode].operand[i+1].mode;
+ }
- if (target == 0
- || GET_MODE (target) != tmode
- || ! (*insn_data[icode2].operand[0].predicate) (target, tmode))
- target = gen_reg_rtx (tmode);
+ /* Check for restricted constant arguments. */
+ for (int i = 0; i < 2; i++)
+ {
+ switch (bifaddr->restr[i])
+ {
+ default:
+ case RES_NONE:
+ break;
+ case RES_BITS:
+ {
+ size_t mask = (1 << bifaddr->restr_val1[i]) - 1;
+ tree restr_arg = arg[bifaddr->restr_opnd[i] - 1];
+ STRIP_NOPS (restr_arg);
+ if (TREE_CODE (restr_arg) != INTEGER_CST
+ || TREE_INT_CST_LOW (restr_arg) & ~mask)
+ {
+ error ("argument %d must be a %d-bit unsigned literal",
+ bifaddr->restr_opnd[i], bifaddr->restr_val1[i]);
+ return CONST0_RTX (mode[0]);
+ }
+ break;
+ }
+ case RES_RANGE:
+ {
+ tree restr_arg = arg[bifaddr->restr_opnd[i] - 1];
+ STRIP_NOPS (restr_arg);
+ if (TREE_CODE (restr_arg) != INTEGER_CST
+ || !IN_RANGE (tree_to_shwi (restr_arg),
+ bifaddr->restr_val1[i],
+ bifaddr->restr_val2[i]))
+ {
+ error ("argument %d must be a literal between %d and %d,"
+ " inclusive",
+ bifaddr->restr_opnd[i], bifaddr->restr_val1[i],
+ bifaddr->restr_val2[i]);
+ return CONST0_RTX (mode[0]);
+ }
+ break;
+ }
+ case RES_VAR_RANGE:
+ {
+ tree restr_arg = arg[bifaddr->restr_opnd[i] - 1];
+ STRIP_NOPS (restr_arg);
+ if (TREE_CODE (restr_arg) == INTEGER_CST
+ && !IN_RANGE (tree_to_shwi (restr_arg),
+ bifaddr->restr_val1[i],
+ bifaddr->restr_val2[i]))
+ {
+ error ("argument %d must be a variable or a literal "
+ "between %d and %d, inclusive",
+ bifaddr->restr_opnd[i], bifaddr->restr_val1[i],
+ bifaddr->restr_val2[i]);
+ return CONST0_RTX (mode[0]);
+ }
+ break;
+ }
+ case RES_VALUES:
+ {
+ tree restr_arg = arg[bifaddr->restr_opnd[i] - 1];
+ STRIP_NOPS (restr_arg);
+ if (TREE_CODE (restr_arg) != INTEGER_CST
+ || (tree_to_shwi (restr_arg) != bifaddr->restr_val1[i]
+ && tree_to_shwi (restr_arg) != bifaddr->restr_val2[i]))
+ {
+ error ("argument %d must be either a literal %d or a "
+ "literal %d",
+ bifaddr->restr_opnd[i], bifaddr->restr_val1[i],
+ bifaddr->restr_val2[i]);
+ return CONST0_RTX (mode[0]);
+ }
+ break;
+ }
+ }
+ }
- pat = GEN_FCN (icode2) (target, op);
- if (!pat)
- return 0;
- emit_insn (pat);
+ if (bif_is_ldstmask (*bifaddr))
+ return rs6000_expand_ldst_mask (target, fcode, arg[0]);
- return target;
- }
+ if (bif_is_stvec (*bifaddr))
+ {
+ if (bif_is_reve (*bifaddr))
+ icode = elemrev_icode (fcode);
+ return stv_expand_builtin (icode, op, mode[0], mode[1]);
+ }
- case ALTIVEC_BUILTIN_VCFUX:
- case ALTIVEC_BUILTIN_VCFSX:
- case ALTIVEC_BUILTIN_VCTUXS:
- case ALTIVEC_BUILTIN_VCTSXS:
- /* FIXME: There's got to be a nicer way to handle this case than
- constructing a new CALL_EXPR. */
- if (call_expr_nargs (exp) == 1)
+ if (bif_is_ldvec (*bifaddr))
{
- exp = build_call_nary (TREE_TYPE (exp), CALL_EXPR_FN (exp),
- 2, CALL_EXPR_ARG (exp, 0), integer_zero_node);
+ if (bif_is_reve (*bifaddr))
+ icode = elemrev_icode (fcode);
+ return ldv_expand_builtin (target, icode, op, mode[0]);
}
- break;
- /* For the pack and unpack int128 routines, fix up the builtin so it
- uses the correct IBM128 type. */
- case MISC_BUILTIN_PACK_IF:
- if (TARGET_LONG_DOUBLE_128 && !TARGET_IEEEQUAD)
+ if (bif_is_mma (*bifaddr))
+ return new_mma_expand_builtin (exp, target, fcode, icode);
+
+ if (fcode == MISC_BUILTIN_PACK_IF
+ && TARGET_LONG_DOUBLE_128 && !TARGET_IEEEQUAD)
{
icode = CODE_FOR_packtf;
fcode = MISC_BUILTIN_PACK_TF;
uns_fcode = (size_t)fcode;
}
- break;
-
- case MISC_BUILTIN_UNPACK_IF:
- if (TARGET_LONG_DOUBLE_128 && !TARGET_IEEEQUAD)
+ else if (fcode == MISC_BUILTIN_UNPACK_IF
+ && TARGET_LONG_DOUBLE_128 && !TARGET_IEEEQUAD)
{
icode = CODE_FOR_unpacktf;
fcode = MISC_BUILTIN_UNPACK_TF;
uns_fcode = (size_t)fcode;
}
- break;
- default:
- break;
- }
+ if (target == 0
+ || GET_MODE (target) != mode[0]
+ || !(*insn_data[icode].operand[0].predicate) (target, mode[0]))
+ target = gen_reg_rtx (mode[0]);
- if (TARGET_MMA)
- {
- ret = mma_expand_builtin (exp, target, &success);
+ for (int i = 0; i < nargs; i++)
+ if (! (*insn_data[icode].operand[i+1].predicate) (op[i], mode[i+1]))
+ op[i] = copy_to_mode_reg (mode[i+1], op[i]);
- if (success)
- return ret;
- }
- if (TARGET_ALTIVEC)
- {
- ret = altivec_expand_builtin (exp, target, &success);
+ switch (nargs)
+ {
+ default:
+ gcc_assert (MAX_BUILTIN_ARGS == 5);
+ gcc_unreachable ();
+ case 0:
+ pat = GEN_FCN (icode) (target);
+ break;
+ case 1:
+ pat = GEN_FCN (icode) (target, op[0]);
+ break;
+ case 2:
+ pat = GEN_FCN (icode) (target, op[0], op[1]);
+ break;
+ case 3:
+ pat = GEN_FCN (icode) (target, op[0], op[1], op[2]);
+ break;
+ case 4:
+ pat = GEN_FCN (icode) (target, op[0], op[1], op[2], op[3]);
+ break;
+ case 5:
+ pat = GEN_FCN (icode) (target, op[0], op[1], op[2], op[3], op[4]);
+ break;
+ }
- if (success)
- return ret;
+ if (!pat)
+ return 0;
+ emit_insn (pat);
+
+ return target;
}
- if (TARGET_HTM)
+ else
{
- ret = htm_expand_builtin (exp, target, &success);
+ switch (fcode)
+ {
+ case RS6000_BUILTIN_RECIP:
+ return rs6000_expand_binop_builtin (CODE_FOR_recipdf3, exp, target);
- if (success)
- return ret;
- }
+ case RS6000_BUILTIN_RECIPF:
+ return rs6000_expand_binop_builtin (CODE_FOR_recipsf3, exp, target);
- 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
- || attr == RS6000_BTC_TERNARY
- || attr == RS6000_BTC_QUATERNARY
- || attr == RS6000_BTC_SPECIAL);
-
- /* Handle simple unary operations. */
- d = bdesc_1arg;
- for (i = 0; i < ARRAY_SIZE (bdesc_1arg); i++, d++)
- if (d->code == fcode)
- return rs6000_expand_unop_builtin (icode, exp, target);
+ case RS6000_BUILTIN_RSQRTF:
+ return rs6000_expand_unop_builtin (CODE_FOR_rsqrtsf2, exp, target);
- /* Handle simple binary operations. */
- d = bdesc_2arg;
- for (i = 0; i < ARRAY_SIZE (bdesc_2arg); i++, d++)
- if (d->code == fcode)
- return rs6000_expand_binop_builtin (icode, exp, target);
+ case RS6000_BUILTIN_RSQRT:
+ return rs6000_expand_unop_builtin (CODE_FOR_rsqrtdf2, exp, target);
- /* Handle simple ternary operations. */
- d = bdesc_3arg;
- for (i = 0; i < ARRAY_SIZE (bdesc_3arg); i++, d++)
- if (d->code == fcode)
- return rs6000_expand_ternop_builtin (icode, exp, target);
+ case POWER7_BUILTIN_BPERMD:
+ return rs6000_expand_binop_builtin (((TARGET_64BIT)
+ ? CODE_FOR_bpermd_di
+ : CODE_FOR_bpermd_si),
+ 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);
+ case RS6000_BUILTIN_GET_TB:
+ return rs6000_expand_zeroop_builtin (CODE_FOR_rs6000_get_timebase,
+ target);
- /* Handle simple no-argument operations. */
- d = bdesc_0arg;
- for (i = 0; i < ARRAY_SIZE (bdesc_0arg); i++, d++)
- if (d->code == fcode)
- return rs6000_expand_zeroop_builtin (icode, target);
+ case RS6000_BUILTIN_MFTB:
+ return rs6000_expand_zeroop_builtin (((TARGET_64BIT)
+ ? CODE_FOR_rs6000_mftb_di
+ : CODE_FOR_rs6000_mftb_si),
+ target);
- gcc_unreachable ();
+ case RS6000_BUILTIN_MFFS:
+ return rs6000_expand_zeroop_builtin (CODE_FOR_rs6000_mffs, target);
+
+ case RS6000_BUILTIN_MTFSB0:
+ return rs6000_expand_mtfsb_builtin (CODE_FOR_rs6000_mtfsb0, exp);
+
+ case RS6000_BUILTIN_MTFSB1:
+ return rs6000_expand_mtfsb_builtin (CODE_FOR_rs6000_mtfsb1, exp);
+
+ case RS6000_BUILTIN_SET_FPSCR_RN:
+ return rs6000_expand_set_fpscr_rn_builtin
+ (CODE_FOR_rs6000_set_fpscr_rn, exp);
+
+ case RS6000_BUILTIN_SET_FPSCR_DRN:
+ return
+ rs6000_expand_set_fpscr_drn_builtin (CODE_FOR_rs6000_set_fpscr_drn,
+ exp);
+
+ case RS6000_BUILTIN_MFFSL:
+ return rs6000_expand_zeroop_builtin (CODE_FOR_rs6000_mffsl, target);
+
+ case RS6000_BUILTIN_MTFSF:
+ return rs6000_expand_mtfsf_builtin (CODE_FOR_rs6000_mtfsf, exp);
+
+ case RS6000_BUILTIN_CPU_INIT:
+ case RS6000_BUILTIN_CPU_IS:
+ case RS6000_BUILTIN_CPU_SUPPORTS:
+ return cpu_expand_builtin (fcode, exp, target);
+
+ case MISC_BUILTIN_SPEC_BARRIER:
+ {
+ emit_insn (gen_speculation_barrier ());
+ return NULL_RTX;
+ }
+
+ case ALTIVEC_BUILTIN_MASK_FOR_LOAD:
+ {
+ int icode2 = (BYTES_BIG_ENDIAN ? (int) CODE_FOR_altivec_lvsr_direct
+ : (int) CODE_FOR_altivec_lvsl_direct);
+ machine_mode tmode = insn_data[icode2].operand[0].mode;
+ machine_mode mode = insn_data[icode2].operand[1].mode;
+ tree arg;
+ rtx op, addr, pat;
+
+ gcc_assert (TARGET_ALTIVEC);
+
+ arg = CALL_EXPR_ARG (exp, 0);
+ gcc_assert (POINTER_TYPE_P (TREE_TYPE (arg)));
+ op = expand_expr (arg, NULL_RTX, Pmode, EXPAND_NORMAL);
+ addr = memory_address (mode, op);
+ /* We need to negate the address. */
+ op = gen_reg_rtx (GET_MODE (addr));
+ emit_insn (gen_rtx_SET (op, gen_rtx_NEG (GET_MODE (addr), addr)));
+ op = gen_rtx_MEM (mode, op);
+
+ if (target == 0
+ || GET_MODE (target) != tmode
+ || ! (*insn_data[icode2].operand[0].predicate) (target, tmode))
+ target = gen_reg_rtx (tmode);
+
+ pat = GEN_FCN (icode2) (target, op);
+ if (!pat)
+ return 0;
+ emit_insn (pat);
+
+ return target;
+ }
+
+ case ALTIVEC_BUILTIN_VCFUX:
+ case ALTIVEC_BUILTIN_VCFSX:
+ case ALTIVEC_BUILTIN_VCTUXS:
+ case ALTIVEC_BUILTIN_VCTSXS:
+ /* #### Replace this nonsense with a separate built-in for the
+ vectorizer to use, which I believe is the only way we get
+ into this situation. */
+ /* FIXME: There's got to be a nicer way to handle this case than
+ constructing a new CALL_EXPR. */
+ if (call_expr_nargs (exp) == 1)
+ {
+ exp = build_call_nary (TREE_TYPE (exp), CALL_EXPR_FN (exp),
+ 2, CALL_EXPR_ARG (exp, 0),
+ integer_zero_node);
+ }
+ break;
+
+ /* For the pack and unpack int128 routines, fix up the builtin so it
+ uses the correct IBM128 type. */
+ case MISC_BUILTIN_PACK_IF:
+ if (TARGET_LONG_DOUBLE_128 && !TARGET_IEEEQUAD)
+ {
+ icode = CODE_FOR_packtf;
+ fcode = MISC_BUILTIN_PACK_TF;
+ uns_fcode = (size_t)fcode;
+ }
+ break;
+
+ case MISC_BUILTIN_UNPACK_IF:
+ if (TARGET_LONG_DOUBLE_128 && !TARGET_IEEEQUAD)
+ {
+ icode = CODE_FOR_unpacktf;
+ fcode = MISC_BUILTIN_UNPACK_TF;
+ uns_fcode = (size_t)fcode;
+ }
+ break;
+
+ default:
+ 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);
+
+ if (success)
+ return ret;
+ }
+ if (TARGET_HTM)
+ {
+ ret = htm_expand_builtin (exp, target, &success);
+
+ if (success)
+ return ret;
+ }
+
+ unsigned attr = (rs6000_builtin_info[uns_fcode].attr
+ & RS6000_BTC_TYPE_MASK);
+ /* RS6000_BTC_SPECIAL represents no-operand operators. */
+ 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. */
+ d = bdesc_1arg;
+ for (i = 0; i < ARRAY_SIZE (bdesc_1arg); i++, d++)
+ if (d->code == fcode)
+ return rs6000_expand_unop_builtin (icode, exp, target);
+
+ /* Handle simple binary operations. */
+ d = bdesc_2arg;
+ for (i = 0; i < ARRAY_SIZE (bdesc_2arg); i++, d++)
+ if (d->code == fcode)
+ return rs6000_expand_binop_builtin (icode, exp, target);
+
+ /* Handle simple ternary operations. */
+ d = bdesc_3arg;
+ for (i = 0; i < ARRAY_SIZE (bdesc_3arg); i++, d++)
+ 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++)
+ if (d->code == fcode)
+ return rs6000_expand_zeroop_builtin (icode, target);
+
+ gcc_unreachable ();
+ }
}
/* Create a builtin vector type with a name. Taking care not to give
^ permalink raw reply [flat|nested] 5+ messages in thread
* [gcc(refs/users/wschmidt/heads/builtins4)] rs6000: Support two builtin expansion algorithms
@ 2021-02-07 18:14 William Schmidt
0 siblings, 0 replies; 5+ messages in thread
From: William Schmidt @ 2021-02-07 18:14 UTC (permalink / raw)
To: gcc-cvs
https://gcc.gnu.org/g:650d82f2668a995ae17994787873424f129a8246
commit 650d82f2668a995ae17994787873424f129a8246
Author: Bill Schmidt <wschmidt@linux.ibm.com>
Date: Mon Nov 2 11:16:08 2020 -0500
rs6000: Support two builtin expansion algorithms
2020-11-02 Bill Schmidt <wschmidt@linux.ibm.com>
* config/rs6000/rs6000-call.c (rs6000_expand_builtin): Support two
kinds of masks and icodes; use a new algorithm under control of
new_builtins_are_live, while still supporting the old one; do lazy
enablement to support #pragma target.
Diff:
---
gcc/config/rs6000/rs6000-call.c | 618 ++++++++++++++++++++++++++++++----------
1 file changed, 463 insertions(+), 155 deletions(-)
diff --git a/gcc/config/rs6000/rs6000-call.c b/gcc/config/rs6000/rs6000-call.c
index 049f6ead7bf..5921c674439 100644
--- a/gcc/config/rs6000/rs6000-call.c
+++ b/gcc/config/rs6000/rs6000-call.c
@@ -13560,6 +13560,10 @@ rs6000_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
int ignore ATTRIBUTE_UNUSED)
{
tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
+ /* #### This needs to be rs6000_gen_builtins now. Can't make this
+ whole until the full set of builtins has been added, and there
+ is no overlap between the two enumerations, so we can run the
+ two in parallel. */
enum rs6000_builtins fcode
= (enum rs6000_builtins) DECL_MD_FUNCTION_CODE (fndecl);
size_t uns_fcode = (size_t)fcode;
@@ -13567,9 +13571,18 @@ rs6000_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
size_t i;
rtx ret;
bool success;
- HOST_WIDE_INT mask = rs6000_builtin_info[uns_fcode].mask;
+ HOST_WIDE_INT mask = (new_builtins_are_live
+ ? 0
+ : rs6000_builtin_info[uns_fcode].mask);
+ /*
+ bif_enable enable = (new_builtins_are_live
+ ? rs6000_builtin_info_x[uns_fcode].enable
+ : (bif_enable) 0);
+ */
bool func_valid_p = ((rs6000_builtin_mask & mask) == mask);
- enum insn_code icode = rs6000_builtin_info[uns_fcode].icode;
+ enum insn_code icode = (new_builtins_are_live
+ ? rs6000_builtin_info_x[uns_fcode].icode
+ : rs6000_builtin_info[uns_fcode].icode);
/* We have two different modes (KFmode, TFmode) that are the IEEE 128-bit
floating point type, depending on whether long double is the IBM extended
@@ -13616,7 +13629,7 @@ rs6000_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
break;
}
- if (TARGET_DEBUG_BUILTIN)
+ if (!new_builtins_are_live && TARGET_DEBUG_BUILTIN)
{
const char *name1 = rs6000_builtin_info[uns_fcode].name;
const char *name2 = (icode != CODE_FOR_nothing)
@@ -13654,201 +13667,496 @@ rs6000_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
return expand_call (exp, target, ignore);
}
- switch (fcode)
+ if (new_builtins_are_live)
{
- case RS6000_BUILTIN_RECIP:
- return rs6000_expand_binop_builtin (CODE_FOR_recipdf3, exp, target);
-
- case RS6000_BUILTIN_RECIPF:
- return rs6000_expand_binop_builtin (CODE_FOR_recipsf3, exp, target);
-
- case RS6000_BUILTIN_RSQRTF:
- return rs6000_expand_unop_builtin (CODE_FOR_rsqrtsf2, exp, target);
-
- case RS6000_BUILTIN_RSQRT:
- return rs6000_expand_unop_builtin (CODE_FOR_rsqrtdf2, exp, target);
-
- case POWER7_BUILTIN_BPERMD:
- return rs6000_expand_binop_builtin (((TARGET_64BIT)
- ? CODE_FOR_bpermd_di
- : CODE_FOR_bpermd_si), exp, target);
+ bifdata *bifaddr = &rs6000_builtin_info_x[uns_fcode];
- case RS6000_BUILTIN_GET_TB:
- return rs6000_expand_zeroop_builtin (CODE_FOR_rs6000_get_timebase,
- target);
-
- case RS6000_BUILTIN_MFTB:
- return rs6000_expand_zeroop_builtin (((TARGET_64BIT)
- ? CODE_FOR_rs6000_mftb_di
- : CODE_FOR_rs6000_mftb_si),
- target);
-
- case RS6000_BUILTIN_MFFS:
- return rs6000_expand_zeroop_builtin (CODE_FOR_rs6000_mffs, target);
+ /* In case of "#pragma target" changes, we initialize all builtins
+ but check for actual availability during expand time. */
+ switch (bifaddr->enable)
+ {
+ default:
+ gcc_unreachable ();
+ case ENB_ALWAYS:
+ break;
+ case ENB_P5:
+ if (!TARGET_POPCNTB)
+ return const0_rtx;
+ break;
+ case ENB_P6:
+ if (!TARGET_CMPB)
+ return const0_rtx;
+ break;
+ case ENB_ALTIVEC:
+ if (!TARGET_ALTIVEC)
+ return const0_rtx;
+ break;
+ case ENB_CELL:
+ if (!TARGET_ALTIVEC || rs6000_cpu != PROCESSOR_CELL)
+ return const0_rtx;
+ break;
+ case ENB_VSX:
+ if (!TARGET_VSX)
+ return const0_rtx;
+ break;
+ case ENB_P7:
+ if (!TARGET_POPCNTD)
+ return const0_rtx;
+ break;
+ case ENB_P7_64:
+ if (!TARGET_POPCNTD || !TARGET_POWERPC64)
+ return const0_rtx;
+ break;
+ case ENB_P8:
+ if (!TARGET_DIRECT_MOVE)
+ return const0_rtx;
+ break;
+ case ENB_P8V:
+ if (!TARGET_P8_VECTOR)
+ return const0_rtx;
+ break;
+ case ENB_P9:
+ if (!TARGET_MODULO)
+ return const0_rtx;
+ break;
+ case ENB_P9_64:
+ if (!TARGET_MODULO || !TARGET_POWERPC64)
+ return const0_rtx;
+ break;
+ case ENB_P9V:
+ if (!TARGET_P9_VECTOR)
+ return const0_rtx;
+ break;
+ case ENB_IEEE128_HW:
+ if (!TARGET_FLOAT128_HW)
+ return const0_rtx;
+ break;
+ case ENB_DFP:
+ if (!TARGET_DFP)
+ return const0_rtx;
+ break;
+ case ENB_CRYPTO:
+ if (!TARGET_CRYPTO)
+ return const0_rtx;
+ break;
+ case ENB_HTM:
+ if (!TARGET_HTM)
+ return const0_rtx;
+ break;
+ case ENB_P10:
+ if (!TARGET_POWER10)
+ return const0_rtx;
+ break;
+ case ENB_MMA:
+ if (!TARGET_MMA)
+ return const0_rtx;
+ break;
+ };
- case RS6000_BUILTIN_MTFSB0:
- return rs6000_expand_mtfsb_builtin (CODE_FOR_rs6000_mtfsb0, exp);
+ if (bif_is_nosoft (*bifaddr)
+ && rs6000_isa_flags & OPTION_MASK_SOFT_FLOAT)
+ {
+ error ("%<%s%> not supported with %<-msoft-float%>",
+ bifaddr->bifname);
+ return const0_rtx;
+ }
- case RS6000_BUILTIN_MTFSB1:
- return rs6000_expand_mtfsb_builtin (CODE_FOR_rs6000_mtfsb1, exp);
+ if (bif_is_no32bit (*bifaddr) && TARGET_32BIT)
+ fatal_error (input_location,
+ "%<%s%> is not supported in 32-bit mode",
+ bifaddr->bifname);
- case RS6000_BUILTIN_SET_FPSCR_RN:
- return rs6000_expand_set_fpscr_rn_builtin (CODE_FOR_rs6000_set_fpscr_rn,
- exp);
+ if (bif_is_cpu (*bifaddr))
+ return cpu_expand_builtin (fcode, exp, target);
- case RS6000_BUILTIN_SET_FPSCR_DRN:
- return
- rs6000_expand_set_fpscr_drn_builtin (CODE_FOR_rs6000_set_fpscr_drn,
- exp);
+ if (bif_is_init (*bifaddr))
+ return altivec_expand_vec_init_builtin (TREE_TYPE (exp), exp, target);
- case RS6000_BUILTIN_MFFSL:
- return rs6000_expand_zeroop_builtin (CODE_FOR_rs6000_mffsl, target);
+ if (bif_is_set (*bifaddr))
+ return altivec_expand_vec_set_builtin (exp);
- case RS6000_BUILTIN_MTFSF:
- return rs6000_expand_mtfsf_builtin (CODE_FOR_rs6000_mtfsf, exp);
+ if (bif_is_extract (*bifaddr))
+ return altivec_expand_vec_ext_builtin (exp, target);
- case RS6000_BUILTIN_CPU_INIT:
- case RS6000_BUILTIN_CPU_IS:
- case RS6000_BUILTIN_CPU_SUPPORTS:
- return cpu_expand_builtin (fcode, exp, target);
+ if (bif_is_predicate (*bifaddr))
+ return altivec_expand_predicate_builtin (icode, exp, target);
- case MISC_BUILTIN_SPEC_BARRIER:
- {
- emit_insn (gen_speculation_barrier ());
- return NULL_RTX;
- }
+ if (bif_is_htm (*bifaddr))
+ return new_htm_expand_builtin (bifaddr, fcode, exp, target);
- case ALTIVEC_BUILTIN_MASK_FOR_LOAD:
- {
- int icode2 = (BYTES_BIG_ENDIAN ? (int) CODE_FOR_altivec_lvsr_direct
- : (int) CODE_FOR_altivec_lvsl_direct);
- machine_mode tmode = insn_data[icode2].operand[0].mode;
- machine_mode mode = insn_data[icode2].operand[1].mode;
- tree arg;
- rtx op, addr, pat;
+ rtx pat;
+ const int MAX_BUILTIN_ARGS = 5;
+ tree arg[MAX_BUILTIN_ARGS];
+ rtx op[MAX_BUILTIN_ARGS];
+ machine_mode mode[MAX_BUILTIN_ARGS + 1];
- gcc_assert (TARGET_ALTIVEC);
+ int nargs = bifaddr->nargs;
+ gcc_assert (nargs <= MAX_BUILTIN_ARGS);
- arg = CALL_EXPR_ARG (exp, 0);
- gcc_assert (POINTER_TYPE_P (TREE_TYPE (arg)));
- op = expand_expr (arg, NULL_RTX, Pmode, EXPAND_NORMAL);
- addr = memory_address (mode, op);
- /* We need to negate the address. */
- op = gen_reg_rtx (GET_MODE (addr));
- emit_insn (gen_rtx_SET (op, gen_rtx_NEG (GET_MODE (addr), addr)));
- op = gen_rtx_MEM (mode, op);
+ mode[0] = insn_data[icode].operand[0].mode;
+ for (int i = 0; i < nargs; i++)
+ {
+ arg[i] = CALL_EXPR_ARG (exp, i);
+ if (arg[i] == error_mark_node)
+ return const0_rtx;
+ op[i] = expand_normal (arg[i]);
+ mode[i+1] = insn_data[icode].operand[i+1].mode;
+ }
- if (target == 0
- || GET_MODE (target) != tmode
- || ! (*insn_data[icode2].operand[0].predicate) (target, tmode))
- target = gen_reg_rtx (tmode);
+ /* Check for restricted constant arguments. */
+ for (int i = 0; i < 2; i++)
+ {
+ switch (bifaddr->restr[i])
+ {
+ default:
+ case RES_NONE:
+ break;
+ case RES_BITS:
+ {
+ size_t mask = (1 << bifaddr->restr_val1[i]) - 1;
+ tree restr_arg = arg[bifaddr->restr_opnd[i] - 1];
+ STRIP_NOPS (restr_arg);
+ if (TREE_CODE (restr_arg) != INTEGER_CST
+ || TREE_INT_CST_LOW (restr_arg) & ~mask)
+ {
+ error ("argument %d must be a %d-bit unsigned literal",
+ bifaddr->restr_opnd[i], bifaddr->restr_val1[i]);
+ return CONST0_RTX (mode[0]);
+ }
+ break;
+ }
+ case RES_RANGE:
+ {
+ tree restr_arg = arg[bifaddr->restr_opnd[i] - 1];
+ STRIP_NOPS (restr_arg);
+ if (TREE_CODE (restr_arg) != INTEGER_CST
+ || !IN_RANGE (tree_to_shwi (restr_arg),
+ bifaddr->restr_val1[i],
+ bifaddr->restr_val2[i]))
+ {
+ error ("argument %d must be a literal between %d and %d,"
+ " inclusive",
+ bifaddr->restr_opnd[i], bifaddr->restr_val1[i],
+ bifaddr->restr_val2[i]);
+ return CONST0_RTX (mode[0]);
+ }
+ break;
+ }
+ case RES_VAR_RANGE:
+ {
+ tree restr_arg = arg[bifaddr->restr_opnd[i] - 1];
+ STRIP_NOPS (restr_arg);
+ if (TREE_CODE (restr_arg) == INTEGER_CST
+ && !IN_RANGE (tree_to_shwi (restr_arg),
+ bifaddr->restr_val1[i],
+ bifaddr->restr_val2[i]))
+ {
+ error ("argument %d must be a variable or a literal "
+ "between %d and %d, inclusive",
+ bifaddr->restr_opnd[i], bifaddr->restr_val1[i],
+ bifaddr->restr_val2[i]);
+ return CONST0_RTX (mode[0]);
+ }
+ break;
+ }
+ case RES_VALUES:
+ {
+ tree restr_arg = arg[bifaddr->restr_opnd[i] - 1];
+ STRIP_NOPS (restr_arg);
+ if (TREE_CODE (restr_arg) != INTEGER_CST
+ || (tree_to_shwi (restr_arg) != bifaddr->restr_val1[i]
+ && tree_to_shwi (restr_arg) != bifaddr->restr_val2[i]))
+ {
+ error ("argument %d must be either a literal %d or a "
+ "literal %d",
+ bifaddr->restr_opnd[i], bifaddr->restr_val1[i],
+ bifaddr->restr_val2[i]);
+ return CONST0_RTX (mode[0]);
+ }
+ break;
+ }
+ }
+ }
- pat = GEN_FCN (icode2) (target, op);
- if (!pat)
- return 0;
- emit_insn (pat);
+ if (bif_is_ldstmask (*bifaddr))
+ return rs6000_expand_ldst_mask (target, fcode, arg[0]);
- return target;
- }
+ if (bif_is_stvec (*bifaddr))
+ {
+ if (bif_is_reve (*bifaddr))
+ icode = elemrev_icode (fcode);
+ return stv_expand_builtin (icode, op, mode[0], mode[1]);
+ }
- case ALTIVEC_BUILTIN_VCFUX:
- case ALTIVEC_BUILTIN_VCFSX:
- case ALTIVEC_BUILTIN_VCTUXS:
- case ALTIVEC_BUILTIN_VCTSXS:
- /* FIXME: There's got to be a nicer way to handle this case than
- constructing a new CALL_EXPR. */
- if (call_expr_nargs (exp) == 1)
+ if (bif_is_ldvec (*bifaddr))
{
- exp = build_call_nary (TREE_TYPE (exp), CALL_EXPR_FN (exp),
- 2, CALL_EXPR_ARG (exp, 0), integer_zero_node);
+ if (bif_is_reve (*bifaddr))
+ icode = elemrev_icode (fcode);
+ return ldv_expand_builtin (target, icode, op, mode[0]);
}
- break;
- /* For the pack and unpack int128 routines, fix up the builtin so it
- uses the correct IBM128 type. */
- case MISC_BUILTIN_PACK_IF:
- if (TARGET_LONG_DOUBLE_128 && !TARGET_IEEEQUAD)
+ if (bif_is_mma (*bifaddr))
+ return new_mma_expand_builtin (exp, target, fcode, icode);
+
+ if (fcode == MISC_BUILTIN_PACK_IF
+ && TARGET_LONG_DOUBLE_128 && !TARGET_IEEEQUAD)
{
icode = CODE_FOR_packtf;
fcode = MISC_BUILTIN_PACK_TF;
uns_fcode = (size_t)fcode;
}
- break;
-
- case MISC_BUILTIN_UNPACK_IF:
- if (TARGET_LONG_DOUBLE_128 && !TARGET_IEEEQUAD)
+ else if (fcode == MISC_BUILTIN_UNPACK_IF
+ && TARGET_LONG_DOUBLE_128 && !TARGET_IEEEQUAD)
{
icode = CODE_FOR_unpacktf;
fcode = MISC_BUILTIN_UNPACK_TF;
uns_fcode = (size_t)fcode;
}
- break;
- default:
- break;
- }
+ if (target == 0
+ || GET_MODE (target) != mode[0]
+ || !(*insn_data[icode].operand[0].predicate) (target, mode[0]))
+ target = gen_reg_rtx (mode[0]);
- if (TARGET_MMA)
- {
- ret = mma_expand_builtin (exp, target, &success);
+ for (int i = 0; i < nargs; i++)
+ if (! (*insn_data[icode].operand[i+1].predicate) (op[i], mode[i+1]))
+ op[i] = copy_to_mode_reg (mode[i+1], op[i]);
- if (success)
- return ret;
- }
- if (TARGET_ALTIVEC)
- {
- ret = altivec_expand_builtin (exp, target, &success);
+ switch (nargs)
+ {
+ default:
+ gcc_assert (MAX_BUILTIN_ARGS == 5);
+ gcc_unreachable ();
+ case 0:
+ pat = GEN_FCN (icode) (target);
+ break;
+ case 1:
+ pat = GEN_FCN (icode) (target, op[0]);
+ break;
+ case 2:
+ pat = GEN_FCN (icode) (target, op[0], op[1]);
+ break;
+ case 3:
+ pat = GEN_FCN (icode) (target, op[0], op[1], op[2]);
+ break;
+ case 4:
+ pat = GEN_FCN (icode) (target, op[0], op[1], op[2], op[3]);
+ break;
+ case 5:
+ pat = GEN_FCN (icode) (target, op[0], op[1], op[2], op[3], op[4]);
+ break;
+ }
- if (success)
- return ret;
+ if (!pat)
+ return 0;
+ emit_insn (pat);
+
+ return target;
}
- if (TARGET_HTM)
+ else
{
- ret = htm_expand_builtin (exp, target, &success);
+ switch (fcode)
+ {
+ case RS6000_BUILTIN_RECIP:
+ return rs6000_expand_binop_builtin (CODE_FOR_recipdf3, exp, target);
- if (success)
- return ret;
- }
+ case RS6000_BUILTIN_RECIPF:
+ return rs6000_expand_binop_builtin (CODE_FOR_recipsf3, exp, target);
- 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
- || attr == RS6000_BTC_TERNARY
- || attr == RS6000_BTC_QUATERNARY
- || attr == RS6000_BTC_SPECIAL);
-
- /* Handle simple unary operations. */
- d = bdesc_1arg;
- for (i = 0; i < ARRAY_SIZE (bdesc_1arg); i++, d++)
- if (d->code == fcode)
- return rs6000_expand_unop_builtin (icode, exp, target);
+ case RS6000_BUILTIN_RSQRTF:
+ return rs6000_expand_unop_builtin (CODE_FOR_rsqrtsf2, exp, target);
- /* Handle simple binary operations. */
- d = bdesc_2arg;
- for (i = 0; i < ARRAY_SIZE (bdesc_2arg); i++, d++)
- if (d->code == fcode)
- return rs6000_expand_binop_builtin (icode, exp, target);
+ case RS6000_BUILTIN_RSQRT:
+ return rs6000_expand_unop_builtin (CODE_FOR_rsqrtdf2, exp, target);
- /* Handle simple ternary operations. */
- d = bdesc_3arg;
- for (i = 0; i < ARRAY_SIZE (bdesc_3arg); i++, d++)
- if (d->code == fcode)
- return rs6000_expand_ternop_builtin (icode, exp, target);
+ case POWER7_BUILTIN_BPERMD:
+ return rs6000_expand_binop_builtin (((TARGET_64BIT)
+ ? CODE_FOR_bpermd_di
+ : CODE_FOR_bpermd_si),
+ 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);
+ case RS6000_BUILTIN_GET_TB:
+ return rs6000_expand_zeroop_builtin (CODE_FOR_rs6000_get_timebase,
+ target);
- /* Handle simple no-argument operations. */
- d = bdesc_0arg;
- for (i = 0; i < ARRAY_SIZE (bdesc_0arg); i++, d++)
- if (d->code == fcode)
- return rs6000_expand_zeroop_builtin (icode, target);
+ case RS6000_BUILTIN_MFTB:
+ return rs6000_expand_zeroop_builtin (((TARGET_64BIT)
+ ? CODE_FOR_rs6000_mftb_di
+ : CODE_FOR_rs6000_mftb_si),
+ target);
- gcc_unreachable ();
+ case RS6000_BUILTIN_MFFS:
+ return rs6000_expand_zeroop_builtin (CODE_FOR_rs6000_mffs, target);
+
+ case RS6000_BUILTIN_MTFSB0:
+ return rs6000_expand_mtfsb_builtin (CODE_FOR_rs6000_mtfsb0, exp);
+
+ case RS6000_BUILTIN_MTFSB1:
+ return rs6000_expand_mtfsb_builtin (CODE_FOR_rs6000_mtfsb1, exp);
+
+ case RS6000_BUILTIN_SET_FPSCR_RN:
+ return rs6000_expand_set_fpscr_rn_builtin
+ (CODE_FOR_rs6000_set_fpscr_rn, exp);
+
+ case RS6000_BUILTIN_SET_FPSCR_DRN:
+ return
+ rs6000_expand_set_fpscr_drn_builtin (CODE_FOR_rs6000_set_fpscr_drn,
+ exp);
+
+ case RS6000_BUILTIN_MFFSL:
+ return rs6000_expand_zeroop_builtin (CODE_FOR_rs6000_mffsl, target);
+
+ case RS6000_BUILTIN_MTFSF:
+ return rs6000_expand_mtfsf_builtin (CODE_FOR_rs6000_mtfsf, exp);
+
+ case RS6000_BUILTIN_CPU_INIT:
+ case RS6000_BUILTIN_CPU_IS:
+ case RS6000_BUILTIN_CPU_SUPPORTS:
+ return cpu_expand_builtin (fcode, exp, target);
+
+ case MISC_BUILTIN_SPEC_BARRIER:
+ {
+ emit_insn (gen_speculation_barrier ());
+ return NULL_RTX;
+ }
+
+ case ALTIVEC_BUILTIN_MASK_FOR_LOAD:
+ {
+ int icode2 = (BYTES_BIG_ENDIAN ? (int) CODE_FOR_altivec_lvsr_direct
+ : (int) CODE_FOR_altivec_lvsl_direct);
+ machine_mode tmode = insn_data[icode2].operand[0].mode;
+ machine_mode mode = insn_data[icode2].operand[1].mode;
+ tree arg;
+ rtx op, addr, pat;
+
+ gcc_assert (TARGET_ALTIVEC);
+
+ arg = CALL_EXPR_ARG (exp, 0);
+ gcc_assert (POINTER_TYPE_P (TREE_TYPE (arg)));
+ op = expand_expr (arg, NULL_RTX, Pmode, EXPAND_NORMAL);
+ addr = memory_address (mode, op);
+ /* We need to negate the address. */
+ op = gen_reg_rtx (GET_MODE (addr));
+ emit_insn (gen_rtx_SET (op, gen_rtx_NEG (GET_MODE (addr), addr)));
+ op = gen_rtx_MEM (mode, op);
+
+ if (target == 0
+ || GET_MODE (target) != tmode
+ || ! (*insn_data[icode2].operand[0].predicate) (target, tmode))
+ target = gen_reg_rtx (tmode);
+
+ pat = GEN_FCN (icode2) (target, op);
+ if (!pat)
+ return 0;
+ emit_insn (pat);
+
+ return target;
+ }
+
+ case ALTIVEC_BUILTIN_VCFUX:
+ case ALTIVEC_BUILTIN_VCFSX:
+ case ALTIVEC_BUILTIN_VCTUXS:
+ case ALTIVEC_BUILTIN_VCTSXS:
+ /* #### Replace this nonsense with a separate built-in for the
+ vectorizer to use, which I believe is the only way we get
+ into this situation. */
+ /* FIXME: There's got to be a nicer way to handle this case than
+ constructing a new CALL_EXPR. */
+ if (call_expr_nargs (exp) == 1)
+ {
+ exp = build_call_nary (TREE_TYPE (exp), CALL_EXPR_FN (exp),
+ 2, CALL_EXPR_ARG (exp, 0),
+ integer_zero_node);
+ }
+ break;
+
+ /* For the pack and unpack int128 routines, fix up the builtin so it
+ uses the correct IBM128 type. */
+ case MISC_BUILTIN_PACK_IF:
+ if (TARGET_LONG_DOUBLE_128 && !TARGET_IEEEQUAD)
+ {
+ icode = CODE_FOR_packtf;
+ fcode = MISC_BUILTIN_PACK_TF;
+ uns_fcode = (size_t)fcode;
+ }
+ break;
+
+ case MISC_BUILTIN_UNPACK_IF:
+ if (TARGET_LONG_DOUBLE_128 && !TARGET_IEEEQUAD)
+ {
+ icode = CODE_FOR_unpacktf;
+ fcode = MISC_BUILTIN_UNPACK_TF;
+ uns_fcode = (size_t)fcode;
+ }
+ break;
+
+ default:
+ 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);
+
+ if (success)
+ return ret;
+ }
+ if (TARGET_HTM)
+ {
+ ret = htm_expand_builtin (exp, target, &success);
+
+ if (success)
+ return ret;
+ }
+
+ unsigned attr = (rs6000_builtin_info[uns_fcode].attr
+ & RS6000_BTC_TYPE_MASK);
+ /* RS6000_BTC_SPECIAL represents no-operand operators. */
+ 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. */
+ d = bdesc_1arg;
+ for (i = 0; i < ARRAY_SIZE (bdesc_1arg); i++, d++)
+ if (d->code == fcode)
+ return rs6000_expand_unop_builtin (icode, exp, target);
+
+ /* Handle simple binary operations. */
+ d = bdesc_2arg;
+ for (i = 0; i < ARRAY_SIZE (bdesc_2arg); i++, d++)
+ if (d->code == fcode)
+ return rs6000_expand_binop_builtin (icode, exp, target);
+
+ /* Handle simple ternary operations. */
+ d = bdesc_3arg;
+ for (i = 0; i < ARRAY_SIZE (bdesc_3arg); i++, d++)
+ 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++)
+ if (d->code == fcode)
+ return rs6000_expand_zeroop_builtin (icode, target);
+
+ gcc_unreachable ();
+ }
}
/* Create a builtin vector type with a name. Taking care not to give
^ permalink raw reply [flat|nested] 5+ messages in thread
* [gcc(refs/users/wschmidt/heads/builtins4)] rs6000: Support two builtin expansion algorithms
@ 2020-11-24 16:45 William Schmidt
0 siblings, 0 replies; 5+ messages in thread
From: William Schmidt @ 2020-11-24 16:45 UTC (permalink / raw)
To: gcc-cvs
https://gcc.gnu.org/g:08fa03413bfcfbcf3f965e8279a12fde93407724
commit 08fa03413bfcfbcf3f965e8279a12fde93407724
Author: Bill Schmidt <wschmidt@linux.ibm.com>
Date: Mon Nov 2 11:16:08 2020 -0500
rs6000: Support two builtin expansion algorithms
2020-11-02 Bill Schmidt <wschmidt@linux.ibm.com>
* config/rs6000/rs6000-call.c (rs6000_expand_builtin): Support two
kinds of masks and icodes; use a new algorithm under control of
new_builtins_are_live, while still supporting the old one; do lazy
enablement to support #pragma target.
Diff:
---
gcc/config/rs6000/rs6000-call.c | 618 ++++++++++++++++++++++++++++++----------
1 file changed, 463 insertions(+), 155 deletions(-)
diff --git a/gcc/config/rs6000/rs6000-call.c b/gcc/config/rs6000/rs6000-call.c
index bd1ddbfd1b2..562f80e191b 100644
--- a/gcc/config/rs6000/rs6000-call.c
+++ b/gcc/config/rs6000/rs6000-call.c
@@ -13513,6 +13513,10 @@ rs6000_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
int ignore ATTRIBUTE_UNUSED)
{
tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
+ /* #### This needs to be rs6000_gen_builtins now. Can't make this
+ whole until the full set of builtins has been added, and there
+ is no overlap between the two enumerations, so we can run the
+ two in parallel. */
enum rs6000_builtins fcode
= (enum rs6000_builtins) DECL_MD_FUNCTION_CODE (fndecl);
size_t uns_fcode = (size_t)fcode;
@@ -13520,9 +13524,18 @@ rs6000_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
size_t i;
rtx ret;
bool success;
- HOST_WIDE_INT mask = rs6000_builtin_info[uns_fcode].mask;
+ HOST_WIDE_INT mask = (new_builtins_are_live
+ ? 0
+ : rs6000_builtin_info[uns_fcode].mask);
+ /*
+ bif_enable enable = (new_builtins_are_live
+ ? rs6000_builtin_info_x[uns_fcode].enable
+ : (bif_enable) 0);
+ */
bool func_valid_p = ((rs6000_builtin_mask & mask) == mask);
- enum insn_code icode = rs6000_builtin_info[uns_fcode].icode;
+ enum insn_code icode = (new_builtins_are_live
+ ? rs6000_builtin_info_x[uns_fcode].icode
+ : rs6000_builtin_info[uns_fcode].icode);
/* We have two different modes (KFmode, TFmode) that are the IEEE 128-bit
floating point type, depending on whether long double is the IBM extended
@@ -13569,7 +13582,7 @@ rs6000_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
break;
}
- if (TARGET_DEBUG_BUILTIN)
+ if (!new_builtins_are_live && TARGET_DEBUG_BUILTIN)
{
const char *name1 = rs6000_builtin_info[uns_fcode].name;
const char *name2 = (icode != CODE_FOR_nothing)
@@ -13607,201 +13620,496 @@ rs6000_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
return expand_call (exp, target, ignore);
}
- switch (fcode)
+ if (new_builtins_are_live)
{
- case RS6000_BUILTIN_RECIP:
- return rs6000_expand_binop_builtin (CODE_FOR_recipdf3, exp, target);
-
- case RS6000_BUILTIN_RECIPF:
- return rs6000_expand_binop_builtin (CODE_FOR_recipsf3, exp, target);
-
- case RS6000_BUILTIN_RSQRTF:
- return rs6000_expand_unop_builtin (CODE_FOR_rsqrtsf2, exp, target);
-
- case RS6000_BUILTIN_RSQRT:
- return rs6000_expand_unop_builtin (CODE_FOR_rsqrtdf2, exp, target);
-
- case POWER7_BUILTIN_BPERMD:
- return rs6000_expand_binop_builtin (((TARGET_64BIT)
- ? CODE_FOR_bpermd_di
- : CODE_FOR_bpermd_si), exp, target);
+ bifdata *bifaddr = &rs6000_builtin_info_x[uns_fcode];
- case RS6000_BUILTIN_GET_TB:
- return rs6000_expand_zeroop_builtin (CODE_FOR_rs6000_get_timebase,
- target);
-
- case RS6000_BUILTIN_MFTB:
- return rs6000_expand_zeroop_builtin (((TARGET_64BIT)
- ? CODE_FOR_rs6000_mftb_di
- : CODE_FOR_rs6000_mftb_si),
- target);
-
- case RS6000_BUILTIN_MFFS:
- return rs6000_expand_zeroop_builtin (CODE_FOR_rs6000_mffs, target);
+ /* In case of "#pragma target" changes, we initialize all builtins
+ but check for actual availability during expand time. */
+ switch (bifaddr->enable)
+ {
+ default:
+ gcc_unreachable ();
+ case ENB_ALWAYS:
+ break;
+ case ENB_P5:
+ if (!TARGET_POPCNTB)
+ return const0_rtx;
+ break;
+ case ENB_P6:
+ if (!TARGET_CMPB)
+ return const0_rtx;
+ break;
+ case ENB_ALTIVEC:
+ if (!TARGET_ALTIVEC)
+ return const0_rtx;
+ break;
+ case ENB_CELL:
+ if (!TARGET_ALTIVEC || rs6000_cpu != PROCESSOR_CELL)
+ return const0_rtx;
+ break;
+ case ENB_VSX:
+ if (!TARGET_VSX)
+ return const0_rtx;
+ break;
+ case ENB_P7:
+ if (!TARGET_POPCNTD)
+ return const0_rtx;
+ break;
+ case ENB_P7_64:
+ if (!TARGET_POPCNTD || !TARGET_POWERPC64)
+ return const0_rtx;
+ break;
+ case ENB_P8:
+ if (!TARGET_DIRECT_MOVE)
+ return const0_rtx;
+ break;
+ case ENB_P8V:
+ if (!TARGET_P8_VECTOR)
+ return const0_rtx;
+ break;
+ case ENB_P9:
+ if (!TARGET_MODULO)
+ return const0_rtx;
+ break;
+ case ENB_P9_64:
+ if (!TARGET_MODULO || !TARGET_POWERPC64)
+ return const0_rtx;
+ break;
+ case ENB_P9V:
+ if (!TARGET_P9_VECTOR)
+ return const0_rtx;
+ break;
+ case ENB_IEEE128_HW:
+ if (!TARGET_FLOAT128_HW)
+ return const0_rtx;
+ break;
+ case ENB_DFP:
+ if (!TARGET_DFP)
+ return const0_rtx;
+ break;
+ case ENB_CRYPTO:
+ if (!TARGET_CRYPTO)
+ return const0_rtx;
+ break;
+ case ENB_HTM:
+ if (!TARGET_HTM)
+ return const0_rtx;
+ break;
+ case ENB_P10:
+ if (!TARGET_POWER10)
+ return const0_rtx;
+ break;
+ case ENB_MMA:
+ if (!TARGET_MMA)
+ return const0_rtx;
+ break;
+ };
- case RS6000_BUILTIN_MTFSB0:
- return rs6000_expand_mtfsb_builtin (CODE_FOR_rs6000_mtfsb0, exp);
+ if (bif_is_nosoft (*bifaddr)
+ && rs6000_isa_flags & OPTION_MASK_SOFT_FLOAT)
+ {
+ error ("%<%s%> not supported with %<-msoft-float%>",
+ bifaddr->bifname);
+ return const0_rtx;
+ }
- case RS6000_BUILTIN_MTFSB1:
- return rs6000_expand_mtfsb_builtin (CODE_FOR_rs6000_mtfsb1, exp);
+ if (bif_is_no32bit (*bifaddr) && TARGET_32BIT)
+ fatal_error (input_location,
+ "%<%s%> is not supported in 32-bit mode",
+ bifaddr->bifname);
- case RS6000_BUILTIN_SET_FPSCR_RN:
- return rs6000_expand_set_fpscr_rn_builtin (CODE_FOR_rs6000_set_fpscr_rn,
- exp);
+ if (bif_is_cpu (*bifaddr))
+ return cpu_expand_builtin (fcode, exp, target);
- case RS6000_BUILTIN_SET_FPSCR_DRN:
- return
- rs6000_expand_set_fpscr_drn_builtin (CODE_FOR_rs6000_set_fpscr_drn,
- exp);
+ if (bif_is_init (*bifaddr))
+ return altivec_expand_vec_init_builtin (TREE_TYPE (exp), exp, target);
- case RS6000_BUILTIN_MFFSL:
- return rs6000_expand_zeroop_builtin (CODE_FOR_rs6000_mffsl, target);
+ if (bif_is_set (*bifaddr))
+ return altivec_expand_vec_set_builtin (exp);
- case RS6000_BUILTIN_MTFSF:
- return rs6000_expand_mtfsf_builtin (CODE_FOR_rs6000_mtfsf, exp);
+ if (bif_is_extract (*bifaddr))
+ return altivec_expand_vec_ext_builtin (exp, target);
- case RS6000_BUILTIN_CPU_INIT:
- case RS6000_BUILTIN_CPU_IS:
- case RS6000_BUILTIN_CPU_SUPPORTS:
- return cpu_expand_builtin (fcode, exp, target);
+ if (bif_is_predicate (*bifaddr))
+ return altivec_expand_predicate_builtin (icode, exp, target);
- case MISC_BUILTIN_SPEC_BARRIER:
- {
- emit_insn (gen_speculation_barrier ());
- return NULL_RTX;
- }
+ if (bif_is_htm (*bifaddr))
+ return new_htm_expand_builtin (bifaddr, fcode, exp, target);
- case ALTIVEC_BUILTIN_MASK_FOR_LOAD:
- {
- int icode2 = (BYTES_BIG_ENDIAN ? (int) CODE_FOR_altivec_lvsr_direct
- : (int) CODE_FOR_altivec_lvsl_direct);
- machine_mode tmode = insn_data[icode2].operand[0].mode;
- machine_mode mode = insn_data[icode2].operand[1].mode;
- tree arg;
- rtx op, addr, pat;
+ rtx pat;
+ const int MAX_BUILTIN_ARGS = 5;
+ tree arg[MAX_BUILTIN_ARGS];
+ rtx op[MAX_BUILTIN_ARGS];
+ machine_mode mode[MAX_BUILTIN_ARGS + 1];
- gcc_assert (TARGET_ALTIVEC);
+ int nargs = bifaddr->nargs;
+ gcc_assert (nargs <= MAX_BUILTIN_ARGS);
- arg = CALL_EXPR_ARG (exp, 0);
- gcc_assert (POINTER_TYPE_P (TREE_TYPE (arg)));
- op = expand_expr (arg, NULL_RTX, Pmode, EXPAND_NORMAL);
- addr = memory_address (mode, op);
- /* We need to negate the address. */
- op = gen_reg_rtx (GET_MODE (addr));
- emit_insn (gen_rtx_SET (op, gen_rtx_NEG (GET_MODE (addr), addr)));
- op = gen_rtx_MEM (mode, op);
+ mode[0] = insn_data[icode].operand[0].mode;
+ for (int i = 0; i < nargs; i++)
+ {
+ arg[i] = CALL_EXPR_ARG (exp, i);
+ if (arg[i] == error_mark_node)
+ return const0_rtx;
+ op[i] = expand_normal (arg[i]);
+ mode[i+1] = insn_data[icode].operand[i+1].mode;
+ }
- if (target == 0
- || GET_MODE (target) != tmode
- || ! (*insn_data[icode2].operand[0].predicate) (target, tmode))
- target = gen_reg_rtx (tmode);
+ /* Check for restricted constant arguments. */
+ for (int i = 0; i < 2; i++)
+ {
+ switch (bifaddr->restr[i])
+ {
+ default:
+ case RES_NONE:
+ break;
+ case RES_BITS:
+ {
+ size_t mask = (1 << bifaddr->restr_val1[i]) - 1;
+ tree restr_arg = arg[bifaddr->restr_opnd[i] - 1];
+ STRIP_NOPS (restr_arg);
+ if (TREE_CODE (restr_arg) != INTEGER_CST
+ || TREE_INT_CST_LOW (restr_arg) & ~mask)
+ {
+ error ("argument %d must be a %d-bit unsigned literal",
+ bifaddr->restr_opnd[i], bifaddr->restr_val1[i]);
+ return CONST0_RTX (mode[0]);
+ }
+ break;
+ }
+ case RES_RANGE:
+ {
+ tree restr_arg = arg[bifaddr->restr_opnd[i] - 1];
+ STRIP_NOPS (restr_arg);
+ if (TREE_CODE (restr_arg) != INTEGER_CST
+ || !IN_RANGE (tree_to_shwi (restr_arg),
+ bifaddr->restr_val1[i],
+ bifaddr->restr_val2[i]))
+ {
+ error ("argument %d must be a literal between %d and %d,"
+ " inclusive",
+ bifaddr->restr_opnd[i], bifaddr->restr_val1[i],
+ bifaddr->restr_val2[i]);
+ return CONST0_RTX (mode[0]);
+ }
+ break;
+ }
+ case RES_VAR_RANGE:
+ {
+ tree restr_arg = arg[bifaddr->restr_opnd[i] - 1];
+ STRIP_NOPS (restr_arg);
+ if (TREE_CODE (restr_arg) == INTEGER_CST
+ && !IN_RANGE (tree_to_shwi (restr_arg),
+ bifaddr->restr_val1[i],
+ bifaddr->restr_val2[i]))
+ {
+ error ("argument %d must be a variable or a literal "
+ "between %d and %d, inclusive",
+ bifaddr->restr_opnd[i], bifaddr->restr_val1[i],
+ bifaddr->restr_val2[i]);
+ return CONST0_RTX (mode[0]);
+ }
+ break;
+ }
+ case RES_VALUES:
+ {
+ tree restr_arg = arg[bifaddr->restr_opnd[i] - 1];
+ STRIP_NOPS (restr_arg);
+ if (TREE_CODE (restr_arg) != INTEGER_CST
+ || (tree_to_shwi (restr_arg) != bifaddr->restr_val1[i]
+ && tree_to_shwi (restr_arg) != bifaddr->restr_val2[i]))
+ {
+ error ("argument %d must be either a literal %d or a "
+ "literal %d",
+ bifaddr->restr_opnd[i], bifaddr->restr_val1[i],
+ bifaddr->restr_val2[i]);
+ return CONST0_RTX (mode[0]);
+ }
+ break;
+ }
+ }
+ }
- pat = GEN_FCN (icode2) (target, op);
- if (!pat)
- return 0;
- emit_insn (pat);
+ if (bif_is_ldstmask (*bifaddr))
+ return rs6000_expand_ldst_mask (target, fcode, arg[0]);
- return target;
- }
+ if (bif_is_stvec (*bifaddr))
+ {
+ if (bif_is_reve (*bifaddr))
+ icode = elemrev_icode (fcode);
+ return stv_expand_builtin (icode, op, mode[0], mode[1]);
+ }
- case ALTIVEC_BUILTIN_VCFUX:
- case ALTIVEC_BUILTIN_VCFSX:
- case ALTIVEC_BUILTIN_VCTUXS:
- case ALTIVEC_BUILTIN_VCTSXS:
- /* FIXME: There's got to be a nicer way to handle this case than
- constructing a new CALL_EXPR. */
- if (call_expr_nargs (exp) == 1)
+ if (bif_is_ldvec (*bifaddr))
{
- exp = build_call_nary (TREE_TYPE (exp), CALL_EXPR_FN (exp),
- 2, CALL_EXPR_ARG (exp, 0), integer_zero_node);
+ if (bif_is_reve (*bifaddr))
+ icode = elemrev_icode (fcode);
+ return ldv_expand_builtin (target, icode, op, mode[0]);
}
- break;
- /* For the pack and unpack int128 routines, fix up the builtin so it
- uses the correct IBM128 type. */
- case MISC_BUILTIN_PACK_IF:
- if (TARGET_LONG_DOUBLE_128 && !TARGET_IEEEQUAD)
+ if (bif_is_mma (*bifaddr))
+ return new_mma_expand_builtin (exp, target, fcode, icode);
+
+ if (fcode == MISC_BUILTIN_PACK_IF
+ && TARGET_LONG_DOUBLE_128 && !TARGET_IEEEQUAD)
{
icode = CODE_FOR_packtf;
fcode = MISC_BUILTIN_PACK_TF;
uns_fcode = (size_t)fcode;
}
- break;
-
- case MISC_BUILTIN_UNPACK_IF:
- if (TARGET_LONG_DOUBLE_128 && !TARGET_IEEEQUAD)
+ else if (fcode == MISC_BUILTIN_UNPACK_IF
+ && TARGET_LONG_DOUBLE_128 && !TARGET_IEEEQUAD)
{
icode = CODE_FOR_unpacktf;
fcode = MISC_BUILTIN_UNPACK_TF;
uns_fcode = (size_t)fcode;
}
- break;
- default:
- break;
- }
+ if (target == 0
+ || GET_MODE (target) != mode[0]
+ || !(*insn_data[icode].operand[0].predicate) (target, mode[0]))
+ target = gen_reg_rtx (mode[0]);
- if (TARGET_MMA)
- {
- ret = mma_expand_builtin (exp, target, &success);
+ for (int i = 0; i < nargs; i++)
+ if (! (*insn_data[icode].operand[i+1].predicate) (op[i], mode[i+1]))
+ op[i] = copy_to_mode_reg (mode[i+1], op[i]);
- if (success)
- return ret;
- }
- if (TARGET_ALTIVEC)
- {
- ret = altivec_expand_builtin (exp, target, &success);
+ switch (nargs)
+ {
+ default:
+ gcc_assert (MAX_BUILTIN_ARGS == 5);
+ gcc_unreachable ();
+ case 0:
+ pat = GEN_FCN (icode) (target);
+ break;
+ case 1:
+ pat = GEN_FCN (icode) (target, op[0]);
+ break;
+ case 2:
+ pat = GEN_FCN (icode) (target, op[0], op[1]);
+ break;
+ case 3:
+ pat = GEN_FCN (icode) (target, op[0], op[1], op[2]);
+ break;
+ case 4:
+ pat = GEN_FCN (icode) (target, op[0], op[1], op[2], op[3]);
+ break;
+ case 5:
+ pat = GEN_FCN (icode) (target, op[0], op[1], op[2], op[3], op[4]);
+ break;
+ }
- if (success)
- return ret;
+ if (!pat)
+ return 0;
+ emit_insn (pat);
+
+ return target;
}
- if (TARGET_HTM)
+ else
{
- ret = htm_expand_builtin (exp, target, &success);
+ switch (fcode)
+ {
+ case RS6000_BUILTIN_RECIP:
+ return rs6000_expand_binop_builtin (CODE_FOR_recipdf3, exp, target);
- if (success)
- return ret;
- }
+ case RS6000_BUILTIN_RECIPF:
+ return rs6000_expand_binop_builtin (CODE_FOR_recipsf3, exp, target);
- 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
- || attr == RS6000_BTC_TERNARY
- || attr == RS6000_BTC_QUATERNARY
- || attr == RS6000_BTC_SPECIAL);
-
- /* Handle simple unary operations. */
- d = bdesc_1arg;
- for (i = 0; i < ARRAY_SIZE (bdesc_1arg); i++, d++)
- if (d->code == fcode)
- return rs6000_expand_unop_builtin (icode, exp, target);
+ case RS6000_BUILTIN_RSQRTF:
+ return rs6000_expand_unop_builtin (CODE_FOR_rsqrtsf2, exp, target);
- /* Handle simple binary operations. */
- d = bdesc_2arg;
- for (i = 0; i < ARRAY_SIZE (bdesc_2arg); i++, d++)
- if (d->code == fcode)
- return rs6000_expand_binop_builtin (icode, exp, target);
+ case RS6000_BUILTIN_RSQRT:
+ return rs6000_expand_unop_builtin (CODE_FOR_rsqrtdf2, exp, target);
- /* Handle simple ternary operations. */
- d = bdesc_3arg;
- for (i = 0; i < ARRAY_SIZE (bdesc_3arg); i++, d++)
- if (d->code == fcode)
- return rs6000_expand_ternop_builtin (icode, exp, target);
+ case POWER7_BUILTIN_BPERMD:
+ return rs6000_expand_binop_builtin (((TARGET_64BIT)
+ ? CODE_FOR_bpermd_di
+ : CODE_FOR_bpermd_si),
+ 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);
+ case RS6000_BUILTIN_GET_TB:
+ return rs6000_expand_zeroop_builtin (CODE_FOR_rs6000_get_timebase,
+ target);
- /* Handle simple no-argument operations. */
- d = bdesc_0arg;
- for (i = 0; i < ARRAY_SIZE (bdesc_0arg); i++, d++)
- if (d->code == fcode)
- return rs6000_expand_zeroop_builtin (icode, target);
+ case RS6000_BUILTIN_MFTB:
+ return rs6000_expand_zeroop_builtin (((TARGET_64BIT)
+ ? CODE_FOR_rs6000_mftb_di
+ : CODE_FOR_rs6000_mftb_si),
+ target);
- gcc_unreachable ();
+ case RS6000_BUILTIN_MFFS:
+ return rs6000_expand_zeroop_builtin (CODE_FOR_rs6000_mffs, target);
+
+ case RS6000_BUILTIN_MTFSB0:
+ return rs6000_expand_mtfsb_builtin (CODE_FOR_rs6000_mtfsb0, exp);
+
+ case RS6000_BUILTIN_MTFSB1:
+ return rs6000_expand_mtfsb_builtin (CODE_FOR_rs6000_mtfsb1, exp);
+
+ case RS6000_BUILTIN_SET_FPSCR_RN:
+ return rs6000_expand_set_fpscr_rn_builtin
+ (CODE_FOR_rs6000_set_fpscr_rn, exp);
+
+ case RS6000_BUILTIN_SET_FPSCR_DRN:
+ return
+ rs6000_expand_set_fpscr_drn_builtin (CODE_FOR_rs6000_set_fpscr_drn,
+ exp);
+
+ case RS6000_BUILTIN_MFFSL:
+ return rs6000_expand_zeroop_builtin (CODE_FOR_rs6000_mffsl, target);
+
+ case RS6000_BUILTIN_MTFSF:
+ return rs6000_expand_mtfsf_builtin (CODE_FOR_rs6000_mtfsf, exp);
+
+ case RS6000_BUILTIN_CPU_INIT:
+ case RS6000_BUILTIN_CPU_IS:
+ case RS6000_BUILTIN_CPU_SUPPORTS:
+ return cpu_expand_builtin (fcode, exp, target);
+
+ case MISC_BUILTIN_SPEC_BARRIER:
+ {
+ emit_insn (gen_speculation_barrier ());
+ return NULL_RTX;
+ }
+
+ case ALTIVEC_BUILTIN_MASK_FOR_LOAD:
+ {
+ int icode2 = (BYTES_BIG_ENDIAN ? (int) CODE_FOR_altivec_lvsr_direct
+ : (int) CODE_FOR_altivec_lvsl_direct);
+ machine_mode tmode = insn_data[icode2].operand[0].mode;
+ machine_mode mode = insn_data[icode2].operand[1].mode;
+ tree arg;
+ rtx op, addr, pat;
+
+ gcc_assert (TARGET_ALTIVEC);
+
+ arg = CALL_EXPR_ARG (exp, 0);
+ gcc_assert (POINTER_TYPE_P (TREE_TYPE (arg)));
+ op = expand_expr (arg, NULL_RTX, Pmode, EXPAND_NORMAL);
+ addr = memory_address (mode, op);
+ /* We need to negate the address. */
+ op = gen_reg_rtx (GET_MODE (addr));
+ emit_insn (gen_rtx_SET (op, gen_rtx_NEG (GET_MODE (addr), addr)));
+ op = gen_rtx_MEM (mode, op);
+
+ if (target == 0
+ || GET_MODE (target) != tmode
+ || ! (*insn_data[icode2].operand[0].predicate) (target, tmode))
+ target = gen_reg_rtx (tmode);
+
+ pat = GEN_FCN (icode2) (target, op);
+ if (!pat)
+ return 0;
+ emit_insn (pat);
+
+ return target;
+ }
+
+ case ALTIVEC_BUILTIN_VCFUX:
+ case ALTIVEC_BUILTIN_VCFSX:
+ case ALTIVEC_BUILTIN_VCTUXS:
+ case ALTIVEC_BUILTIN_VCTSXS:
+ /* #### Replace this nonsense with a separate built-in for the
+ vectorizer to use, which I believe is the only way we get
+ into this situation. */
+ /* FIXME: There's got to be a nicer way to handle this case than
+ constructing a new CALL_EXPR. */
+ if (call_expr_nargs (exp) == 1)
+ {
+ exp = build_call_nary (TREE_TYPE (exp), CALL_EXPR_FN (exp),
+ 2, CALL_EXPR_ARG (exp, 0),
+ integer_zero_node);
+ }
+ break;
+
+ /* For the pack and unpack int128 routines, fix up the builtin so it
+ uses the correct IBM128 type. */
+ case MISC_BUILTIN_PACK_IF:
+ if (TARGET_LONG_DOUBLE_128 && !TARGET_IEEEQUAD)
+ {
+ icode = CODE_FOR_packtf;
+ fcode = MISC_BUILTIN_PACK_TF;
+ uns_fcode = (size_t)fcode;
+ }
+ break;
+
+ case MISC_BUILTIN_UNPACK_IF:
+ if (TARGET_LONG_DOUBLE_128 && !TARGET_IEEEQUAD)
+ {
+ icode = CODE_FOR_unpacktf;
+ fcode = MISC_BUILTIN_UNPACK_TF;
+ uns_fcode = (size_t)fcode;
+ }
+ break;
+
+ default:
+ 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);
+
+ if (success)
+ return ret;
+ }
+ if (TARGET_HTM)
+ {
+ ret = htm_expand_builtin (exp, target, &success);
+
+ if (success)
+ return ret;
+ }
+
+ unsigned attr = (rs6000_builtin_info[uns_fcode].attr
+ & RS6000_BTC_TYPE_MASK);
+ /* RS6000_BTC_SPECIAL represents no-operand operators. */
+ 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. */
+ d = bdesc_1arg;
+ for (i = 0; i < ARRAY_SIZE (bdesc_1arg); i++, d++)
+ if (d->code == fcode)
+ return rs6000_expand_unop_builtin (icode, exp, target);
+
+ /* Handle simple binary operations. */
+ d = bdesc_2arg;
+ for (i = 0; i < ARRAY_SIZE (bdesc_2arg); i++, d++)
+ if (d->code == fcode)
+ return rs6000_expand_binop_builtin (icode, exp, target);
+
+ /* Handle simple ternary operations. */
+ d = bdesc_3arg;
+ for (i = 0; i < ARRAY_SIZE (bdesc_3arg); i++, d++)
+ 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++)
+ if (d->code == fcode)
+ return rs6000_expand_zeroop_builtin (icode, target);
+
+ gcc_unreachable ();
+ }
}
/* Create a builtin vector type with a name. Taking care not to give
^ permalink raw reply [flat|nested] 5+ messages in thread
* [gcc(refs/users/wschmidt/heads/builtins4)] rs6000: Support two builtin expansion algorithms
@ 2020-11-02 22:08 William Schmidt
0 siblings, 0 replies; 5+ messages in thread
From: William Schmidt @ 2020-11-02 22:08 UTC (permalink / raw)
To: gcc-cvs
https://gcc.gnu.org/g:175c5286cc4a31e08a55f2db24b63d00a3b6f0cf
commit 175c5286cc4a31e08a55f2db24b63d00a3b6f0cf
Author: Bill Schmidt <wschmidt@linux.ibm.com>
Date: Mon Nov 2 11:16:08 2020 -0500
rs6000: Support two builtin expansion algorithms
2020-11-02 Bill Schmidt <wschmidt@linux.ibm.com>
* config/rs6000/rs6000-call.c (rs6000_expand_builtin): Support two
kinds of masks and icodes; use a new algorithm under control of
new_builtins_are_live, while still supporting the old one; do lazy
enablement to support #pragma target.
Diff:
---
gcc/config/rs6000/rs6000-call.c | 618 ++++++++++++++++++++++++++++++----------
1 file changed, 463 insertions(+), 155 deletions(-)
diff --git a/gcc/config/rs6000/rs6000-call.c b/gcc/config/rs6000/rs6000-call.c
index 4080ffb4681..12ff8a4bb92 100644
--- a/gcc/config/rs6000/rs6000-call.c
+++ b/gcc/config/rs6000/rs6000-call.c
@@ -13428,6 +13428,10 @@ rs6000_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
int ignore ATTRIBUTE_UNUSED)
{
tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
+ /* #### This needs to be rs6000_gen_builtins now. Can't make this
+ whole until the full set of builtins has been added, and there
+ is no overlap between the two enumerations, so we can run the
+ two in parallel. */
enum rs6000_builtins fcode
= (enum rs6000_builtins) DECL_MD_FUNCTION_CODE (fndecl);
size_t uns_fcode = (size_t)fcode;
@@ -13435,9 +13439,18 @@ rs6000_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
size_t i;
rtx ret;
bool success;
- HOST_WIDE_INT mask = rs6000_builtin_info[uns_fcode].mask;
+ HOST_WIDE_INT mask = (new_builtins_are_live
+ ? 0
+ : rs6000_builtin_info[uns_fcode].mask);
+ /*
+ bif_enable enable = (new_builtins_are_live
+ ? rs6000_builtin_info_x[uns_fcode].enable
+ : (bif_enable) 0);
+ */
bool func_valid_p = ((rs6000_builtin_mask & mask) == mask);
- enum insn_code icode = rs6000_builtin_info[uns_fcode].icode;
+ enum insn_code icode = (new_builtins_are_live
+ ? rs6000_builtin_info_x[uns_fcode].icode
+ : rs6000_builtin_info[uns_fcode].icode);
/* We have two different modes (KFmode, TFmode) that are the IEEE 128-bit
floating point type, depending on whether long double is the IBM extended
@@ -13468,7 +13481,7 @@ rs6000_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
case CODE_FOR_xststdcqp_kf: icode = CODE_FOR_xststdcqp_tf; break;
}
- if (TARGET_DEBUG_BUILTIN)
+ if (!new_builtins_are_live && TARGET_DEBUG_BUILTIN)
{
const char *name1 = rs6000_builtin_info[uns_fcode].name;
const char *name2 = (icode != CODE_FOR_nothing)
@@ -13506,201 +13519,496 @@ rs6000_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
return expand_call (exp, target, ignore);
}
- switch (fcode)
+ if (new_builtins_are_live)
{
- case RS6000_BUILTIN_RECIP:
- return rs6000_expand_binop_builtin (CODE_FOR_recipdf3, exp, target);
-
- case RS6000_BUILTIN_RECIPF:
- return rs6000_expand_binop_builtin (CODE_FOR_recipsf3, exp, target);
-
- case RS6000_BUILTIN_RSQRTF:
- return rs6000_expand_unop_builtin (CODE_FOR_rsqrtsf2, exp, target);
-
- case RS6000_BUILTIN_RSQRT:
- return rs6000_expand_unop_builtin (CODE_FOR_rsqrtdf2, exp, target);
-
- case POWER7_BUILTIN_BPERMD:
- return rs6000_expand_binop_builtin (((TARGET_64BIT)
- ? CODE_FOR_bpermd_di
- : CODE_FOR_bpermd_si), exp, target);
+ bifdata *bifaddr = &rs6000_builtin_info_x[uns_fcode];
- case RS6000_BUILTIN_GET_TB:
- return rs6000_expand_zeroop_builtin (CODE_FOR_rs6000_get_timebase,
- target);
-
- case RS6000_BUILTIN_MFTB:
- return rs6000_expand_zeroop_builtin (((TARGET_64BIT)
- ? CODE_FOR_rs6000_mftb_di
- : CODE_FOR_rs6000_mftb_si),
- target);
-
- case RS6000_BUILTIN_MFFS:
- return rs6000_expand_zeroop_builtin (CODE_FOR_rs6000_mffs, target);
+ /* In case of "#pragma target" changes, we initialize all builtins
+ but check for actual availability during expand time. */
+ switch (bifaddr->enable)
+ {
+ default:
+ gcc_unreachable ();
+ case ENB_ALWAYS:
+ break;
+ case ENB_P5:
+ if (!TARGET_POPCNTB)
+ return const0_rtx;
+ break;
+ case ENB_P6:
+ if (!TARGET_CMPB)
+ return const0_rtx;
+ break;
+ case ENB_ALTIVEC:
+ if (!TARGET_ALTIVEC)
+ return const0_rtx;
+ break;
+ case ENB_CELL:
+ if (!TARGET_ALTIVEC || rs6000_cpu != PROCESSOR_CELL)
+ return const0_rtx;
+ break;
+ case ENB_VSX:
+ if (!TARGET_VSX)
+ return const0_rtx;
+ break;
+ case ENB_P7:
+ if (!TARGET_POPCNTD)
+ return const0_rtx;
+ break;
+ case ENB_P7_64:
+ if (!TARGET_POPCNTD || !TARGET_POWERPC64)
+ return const0_rtx;
+ break;
+ case ENB_P8:
+ if (!TARGET_DIRECT_MOVE)
+ return const0_rtx;
+ break;
+ case ENB_P8V:
+ if (!TARGET_P8_VECTOR)
+ return const0_rtx;
+ break;
+ case ENB_P9:
+ if (!TARGET_MODULO)
+ return const0_rtx;
+ break;
+ case ENB_P9_64:
+ if (!TARGET_MODULO || !TARGET_POWERPC64)
+ return const0_rtx;
+ break;
+ case ENB_P9V:
+ if (!TARGET_P9_VECTOR)
+ return const0_rtx;
+ break;
+ case ENB_IEEE128_HW:
+ if (!TARGET_FLOAT128_HW)
+ return const0_rtx;
+ break;
+ case ENB_DFP:
+ if (!TARGET_DFP)
+ return const0_rtx;
+ break;
+ case ENB_CRYPTO:
+ if (!TARGET_CRYPTO)
+ return const0_rtx;
+ break;
+ case ENB_HTM:
+ if (!TARGET_HTM)
+ return const0_rtx;
+ break;
+ case ENB_P10:
+ if (!TARGET_POWER10)
+ return const0_rtx;
+ break;
+ case ENB_MMA:
+ if (!TARGET_MMA)
+ return const0_rtx;
+ break;
+ };
- case RS6000_BUILTIN_MTFSB0:
- return rs6000_expand_mtfsb_builtin (CODE_FOR_rs6000_mtfsb0, exp);
+ if (bif_is_nosoft (*bifaddr)
+ && rs6000_isa_flags & OPTION_MASK_SOFT_FLOAT)
+ {
+ error ("%<%s%> not supported with %<-msoft-float%>",
+ bifaddr->bifname);
+ return const0_rtx;
+ }
- case RS6000_BUILTIN_MTFSB1:
- return rs6000_expand_mtfsb_builtin (CODE_FOR_rs6000_mtfsb1, exp);
+ if (bif_is_no32bit (*bifaddr) && TARGET_32BIT)
+ fatal_error (input_location,
+ "%<%s%> is not supported in 32-bit mode",
+ bifaddr->bifname);
- case RS6000_BUILTIN_SET_FPSCR_RN:
- return rs6000_expand_set_fpscr_rn_builtin (CODE_FOR_rs6000_set_fpscr_rn,
- exp);
+ if (bif_is_cpu (*bifaddr))
+ return cpu_expand_builtin (fcode, exp, target);
- case RS6000_BUILTIN_SET_FPSCR_DRN:
- return
- rs6000_expand_set_fpscr_drn_builtin (CODE_FOR_rs6000_set_fpscr_drn,
- exp);
+ if (bif_is_init (*bifaddr))
+ return altivec_expand_vec_init_builtin (TREE_TYPE (exp), exp, target);
- case RS6000_BUILTIN_MFFSL:
- return rs6000_expand_zeroop_builtin (CODE_FOR_rs6000_mffsl, target);
+ if (bif_is_set (*bifaddr))
+ return altivec_expand_vec_set_builtin (exp);
- case RS6000_BUILTIN_MTFSF:
- return rs6000_expand_mtfsf_builtin (CODE_FOR_rs6000_mtfsf, exp);
+ if (bif_is_extract (*bifaddr))
+ return altivec_expand_vec_ext_builtin (exp, target);
- case RS6000_BUILTIN_CPU_INIT:
- case RS6000_BUILTIN_CPU_IS:
- case RS6000_BUILTIN_CPU_SUPPORTS:
- return cpu_expand_builtin (fcode, exp, target);
+ if (bif_is_predicate (*bifaddr))
+ return altivec_expand_predicate_builtin (icode, exp, target);
- case MISC_BUILTIN_SPEC_BARRIER:
- {
- emit_insn (gen_speculation_barrier ());
- return NULL_RTX;
- }
+ if (bif_is_htm (*bifaddr))
+ return new_htm_expand_builtin (bifaddr, fcode, exp, target);
- case ALTIVEC_BUILTIN_MASK_FOR_LOAD:
- {
- int icode2 = (BYTES_BIG_ENDIAN ? (int) CODE_FOR_altivec_lvsr_direct
- : (int) CODE_FOR_altivec_lvsl_direct);
- machine_mode tmode = insn_data[icode2].operand[0].mode;
- machine_mode mode = insn_data[icode2].operand[1].mode;
- tree arg;
- rtx op, addr, pat;
+ rtx pat;
+ const int MAX_BUILTIN_ARGS = 5;
+ tree arg[MAX_BUILTIN_ARGS];
+ rtx op[MAX_BUILTIN_ARGS];
+ machine_mode mode[MAX_BUILTIN_ARGS + 1];
- gcc_assert (TARGET_ALTIVEC);
+ int nargs = bifaddr->nargs;
+ gcc_assert (nargs <= MAX_BUILTIN_ARGS);
- arg = CALL_EXPR_ARG (exp, 0);
- gcc_assert (POINTER_TYPE_P (TREE_TYPE (arg)));
- op = expand_expr (arg, NULL_RTX, Pmode, EXPAND_NORMAL);
- addr = memory_address (mode, op);
- /* We need to negate the address. */
- op = gen_reg_rtx (GET_MODE (addr));
- emit_insn (gen_rtx_SET (op, gen_rtx_NEG (GET_MODE (addr), addr)));
- op = gen_rtx_MEM (mode, op);
+ mode[0] = insn_data[icode].operand[0].mode;
+ for (int i = 0; i < nargs; i++)
+ {
+ arg[i] = CALL_EXPR_ARG (exp, i);
+ if (arg[i] == error_mark_node)
+ return const0_rtx;
+ op[i] = expand_normal (arg[i]);
+ mode[i+1] = insn_data[icode].operand[i+1].mode;
+ }
- if (target == 0
- || GET_MODE (target) != tmode
- || ! (*insn_data[icode2].operand[0].predicate) (target, tmode))
- target = gen_reg_rtx (tmode);
+ /* Check for restricted constant arguments. */
+ for (int i = 0; i < 2; i++)
+ {
+ switch (bifaddr->restr[i])
+ {
+ default:
+ case RES_NONE:
+ break;
+ case RES_BITS:
+ {
+ size_t mask = (1 << bifaddr->restr_val1[i]) - 1;
+ tree restr_arg = arg[bifaddr->restr_opnd[i] - 1];
+ STRIP_NOPS (restr_arg);
+ if (TREE_CODE (restr_arg) != INTEGER_CST
+ || TREE_INT_CST_LOW (restr_arg) & ~mask)
+ {
+ error ("argument %d must be a %d-bit unsigned literal",
+ bifaddr->restr_opnd[i], bifaddr->restr_val1[i]);
+ return CONST0_RTX (mode[0]);
+ }
+ break;
+ }
+ case RES_RANGE:
+ {
+ tree restr_arg = arg[bifaddr->restr_opnd[i] - 1];
+ STRIP_NOPS (restr_arg);
+ if (TREE_CODE (restr_arg) != INTEGER_CST
+ || !IN_RANGE (tree_to_shwi (restr_arg),
+ bifaddr->restr_val1[i],
+ bifaddr->restr_val2[i]))
+ {
+ error ("argument %d must be a literal between %d and %d,"
+ " inclusive",
+ bifaddr->restr_opnd[i], bifaddr->restr_val1[i],
+ bifaddr->restr_val2[i]);
+ return CONST0_RTX (mode[0]);
+ }
+ break;
+ }
+ case RES_VAR_RANGE:
+ {
+ tree restr_arg = arg[bifaddr->restr_opnd[i] - 1];
+ STRIP_NOPS (restr_arg);
+ if (TREE_CODE (restr_arg) == INTEGER_CST
+ && !IN_RANGE (tree_to_shwi (restr_arg),
+ bifaddr->restr_val1[i],
+ bifaddr->restr_val2[i]))
+ {
+ error ("argument %d must be a variable or a literal "
+ "between %d and %d, inclusive",
+ bifaddr->restr_opnd[i], bifaddr->restr_val1[i],
+ bifaddr->restr_val2[i]);
+ return CONST0_RTX (mode[0]);
+ }
+ break;
+ }
+ case RES_VALUES:
+ {
+ tree restr_arg = arg[bifaddr->restr_opnd[i] - 1];
+ STRIP_NOPS (restr_arg);
+ if (TREE_CODE (restr_arg) != INTEGER_CST
+ || (tree_to_shwi (restr_arg) != bifaddr->restr_val1[i]
+ && tree_to_shwi (restr_arg) != bifaddr->restr_val2[i]))
+ {
+ error ("argument %d must be either a literal %d or a "
+ "literal %d",
+ bifaddr->restr_opnd[i], bifaddr->restr_val1[i],
+ bifaddr->restr_val2[i]);
+ return CONST0_RTX (mode[0]);
+ }
+ break;
+ }
+ }
+ }
- pat = GEN_FCN (icode2) (target, op);
- if (!pat)
- return 0;
- emit_insn (pat);
+ if (bif_is_ldstmask (*bifaddr))
+ return rs6000_expand_ldst_mask (target, fcode, arg[0]);
- return target;
- }
+ if (bif_is_stvec (*bifaddr))
+ {
+ if (bif_is_reve (*bifaddr))
+ icode = elemrev_icode (fcode);
+ return stv_expand_builtin (icode, op, mode[0], mode[1]);
+ }
- case ALTIVEC_BUILTIN_VCFUX:
- case ALTIVEC_BUILTIN_VCFSX:
- case ALTIVEC_BUILTIN_VCTUXS:
- case ALTIVEC_BUILTIN_VCTSXS:
- /* FIXME: There's got to be a nicer way to handle this case than
- constructing a new CALL_EXPR. */
- if (call_expr_nargs (exp) == 1)
+ if (bif_is_ldvec (*bifaddr))
{
- exp = build_call_nary (TREE_TYPE (exp), CALL_EXPR_FN (exp),
- 2, CALL_EXPR_ARG (exp, 0), integer_zero_node);
+ if (bif_is_reve (*bifaddr))
+ icode = elemrev_icode (fcode);
+ return ldv_expand_builtin (target, icode, op, mode[0]);
}
- break;
- /* For the pack and unpack int128 routines, fix up the builtin so it
- uses the correct IBM128 type. */
- case MISC_BUILTIN_PACK_IF:
- if (TARGET_LONG_DOUBLE_128 && !TARGET_IEEEQUAD)
+ if (bif_is_mma (*bifaddr))
+ return new_mma_expand_builtin (exp, target, fcode, icode);
+
+ if (fcode == MISC_BUILTIN_PACK_IF
+ && TARGET_LONG_DOUBLE_128 && !TARGET_IEEEQUAD)
{
icode = CODE_FOR_packtf;
fcode = MISC_BUILTIN_PACK_TF;
uns_fcode = (size_t)fcode;
}
- break;
-
- case MISC_BUILTIN_UNPACK_IF:
- if (TARGET_LONG_DOUBLE_128 && !TARGET_IEEEQUAD)
+ else if (fcode == MISC_BUILTIN_UNPACK_IF
+ && TARGET_LONG_DOUBLE_128 && !TARGET_IEEEQUAD)
{
icode = CODE_FOR_unpacktf;
fcode = MISC_BUILTIN_UNPACK_TF;
uns_fcode = (size_t)fcode;
}
- break;
- default:
- break;
- }
+ if (target == 0
+ || GET_MODE (target) != mode[0]
+ || !(*insn_data[icode].operand[0].predicate) (target, mode[0]))
+ target = gen_reg_rtx (mode[0]);
- if (TARGET_MMA)
- {
- ret = mma_expand_builtin (exp, target, &success);
+ for (int i = 0; i < nargs; i++)
+ if (! (*insn_data[icode].operand[i+1].predicate) (op[i], mode[i+1]))
+ op[i] = copy_to_mode_reg (mode[i+1], op[i]);
- if (success)
- return ret;
- }
- if (TARGET_ALTIVEC)
- {
- ret = altivec_expand_builtin (exp, target, &success);
+ switch (nargs)
+ {
+ default:
+ gcc_assert (MAX_BUILTIN_ARGS == 5);
+ gcc_unreachable ();
+ case 0:
+ pat = GEN_FCN (icode) (target);
+ break;
+ case 1:
+ pat = GEN_FCN (icode) (target, op[0]);
+ break;
+ case 2:
+ pat = GEN_FCN (icode) (target, op[0], op[1]);
+ break;
+ case 3:
+ pat = GEN_FCN (icode) (target, op[0], op[1], op[2]);
+ break;
+ case 4:
+ pat = GEN_FCN (icode) (target, op[0], op[1], op[2], op[3]);
+ break;
+ case 5:
+ pat = GEN_FCN (icode) (target, op[0], op[1], op[2], op[3], op[4]);
+ break;
+ }
- if (success)
- return ret;
+ if (!pat)
+ return 0;
+ emit_insn (pat);
+
+ return target;
}
- if (TARGET_HTM)
+ else
{
- ret = htm_expand_builtin (exp, target, &success);
+ switch (fcode)
+ {
+ case RS6000_BUILTIN_RECIP:
+ return rs6000_expand_binop_builtin (CODE_FOR_recipdf3, exp, target);
- if (success)
- return ret;
- }
+ case RS6000_BUILTIN_RECIPF:
+ return rs6000_expand_binop_builtin (CODE_FOR_recipsf3, exp, target);
- 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
- || attr == RS6000_BTC_TERNARY
- || attr == RS6000_BTC_QUATERNARY
- || attr == RS6000_BTC_SPECIAL);
-
- /* Handle simple unary operations. */
- d = bdesc_1arg;
- for (i = 0; i < ARRAY_SIZE (bdesc_1arg); i++, d++)
- if (d->code == fcode)
- return rs6000_expand_unop_builtin (icode, exp, target);
+ case RS6000_BUILTIN_RSQRTF:
+ return rs6000_expand_unop_builtin (CODE_FOR_rsqrtsf2, exp, target);
- /* Handle simple binary operations. */
- d = bdesc_2arg;
- for (i = 0; i < ARRAY_SIZE (bdesc_2arg); i++, d++)
- if (d->code == fcode)
- return rs6000_expand_binop_builtin (icode, exp, target);
+ case RS6000_BUILTIN_RSQRT:
+ return rs6000_expand_unop_builtin (CODE_FOR_rsqrtdf2, exp, target);
- /* Handle simple ternary operations. */
- d = bdesc_3arg;
- for (i = 0; i < ARRAY_SIZE (bdesc_3arg); i++, d++)
- if (d->code == fcode)
- return rs6000_expand_ternop_builtin (icode, exp, target);
+ case POWER7_BUILTIN_BPERMD:
+ return rs6000_expand_binop_builtin (((TARGET_64BIT)
+ ? CODE_FOR_bpermd_di
+ : CODE_FOR_bpermd_si),
+ 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);
+ case RS6000_BUILTIN_GET_TB:
+ return rs6000_expand_zeroop_builtin (CODE_FOR_rs6000_get_timebase,
+ target);
- /* Handle simple no-argument operations. */
- d = bdesc_0arg;
- for (i = 0; i < ARRAY_SIZE (bdesc_0arg); i++, d++)
- if (d->code == fcode)
- return rs6000_expand_zeroop_builtin (icode, target);
+ case RS6000_BUILTIN_MFTB:
+ return rs6000_expand_zeroop_builtin (((TARGET_64BIT)
+ ? CODE_FOR_rs6000_mftb_di
+ : CODE_FOR_rs6000_mftb_si),
+ target);
- gcc_unreachable ();
+ case RS6000_BUILTIN_MFFS:
+ return rs6000_expand_zeroop_builtin (CODE_FOR_rs6000_mffs, target);
+
+ case RS6000_BUILTIN_MTFSB0:
+ return rs6000_expand_mtfsb_builtin (CODE_FOR_rs6000_mtfsb0, exp);
+
+ case RS6000_BUILTIN_MTFSB1:
+ return rs6000_expand_mtfsb_builtin (CODE_FOR_rs6000_mtfsb1, exp);
+
+ case RS6000_BUILTIN_SET_FPSCR_RN:
+ return rs6000_expand_set_fpscr_rn_builtin
+ (CODE_FOR_rs6000_set_fpscr_rn, exp);
+
+ case RS6000_BUILTIN_SET_FPSCR_DRN:
+ return
+ rs6000_expand_set_fpscr_drn_builtin (CODE_FOR_rs6000_set_fpscr_drn,
+ exp);
+
+ case RS6000_BUILTIN_MFFSL:
+ return rs6000_expand_zeroop_builtin (CODE_FOR_rs6000_mffsl, target);
+
+ case RS6000_BUILTIN_MTFSF:
+ return rs6000_expand_mtfsf_builtin (CODE_FOR_rs6000_mtfsf, exp);
+
+ case RS6000_BUILTIN_CPU_INIT:
+ case RS6000_BUILTIN_CPU_IS:
+ case RS6000_BUILTIN_CPU_SUPPORTS:
+ return cpu_expand_builtin (fcode, exp, target);
+
+ case MISC_BUILTIN_SPEC_BARRIER:
+ {
+ emit_insn (gen_speculation_barrier ());
+ return NULL_RTX;
+ }
+
+ case ALTIVEC_BUILTIN_MASK_FOR_LOAD:
+ {
+ int icode2 = (BYTES_BIG_ENDIAN ? (int) CODE_FOR_altivec_lvsr_direct
+ : (int) CODE_FOR_altivec_lvsl_direct);
+ machine_mode tmode = insn_data[icode2].operand[0].mode;
+ machine_mode mode = insn_data[icode2].operand[1].mode;
+ tree arg;
+ rtx op, addr, pat;
+
+ gcc_assert (TARGET_ALTIVEC);
+
+ arg = CALL_EXPR_ARG (exp, 0);
+ gcc_assert (POINTER_TYPE_P (TREE_TYPE (arg)));
+ op = expand_expr (arg, NULL_RTX, Pmode, EXPAND_NORMAL);
+ addr = memory_address (mode, op);
+ /* We need to negate the address. */
+ op = gen_reg_rtx (GET_MODE (addr));
+ emit_insn (gen_rtx_SET (op, gen_rtx_NEG (GET_MODE (addr), addr)));
+ op = gen_rtx_MEM (mode, op);
+
+ if (target == 0
+ || GET_MODE (target) != tmode
+ || ! (*insn_data[icode2].operand[0].predicate) (target, tmode))
+ target = gen_reg_rtx (tmode);
+
+ pat = GEN_FCN (icode2) (target, op);
+ if (!pat)
+ return 0;
+ emit_insn (pat);
+
+ return target;
+ }
+
+ case ALTIVEC_BUILTIN_VCFUX:
+ case ALTIVEC_BUILTIN_VCFSX:
+ case ALTIVEC_BUILTIN_VCTUXS:
+ case ALTIVEC_BUILTIN_VCTSXS:
+ /* #### Replace this nonsense with a separate built-in for the
+ vectorizer to use, which I believe is the only way we get
+ into this situation. */
+ /* FIXME: There's got to be a nicer way to handle this case than
+ constructing a new CALL_EXPR. */
+ if (call_expr_nargs (exp) == 1)
+ {
+ exp = build_call_nary (TREE_TYPE (exp), CALL_EXPR_FN (exp),
+ 2, CALL_EXPR_ARG (exp, 0),
+ integer_zero_node);
+ }
+ break;
+
+ /* For the pack and unpack int128 routines, fix up the builtin so it
+ uses the correct IBM128 type. */
+ case MISC_BUILTIN_PACK_IF:
+ if (TARGET_LONG_DOUBLE_128 && !TARGET_IEEEQUAD)
+ {
+ icode = CODE_FOR_packtf;
+ fcode = MISC_BUILTIN_PACK_TF;
+ uns_fcode = (size_t)fcode;
+ }
+ break;
+
+ case MISC_BUILTIN_UNPACK_IF:
+ if (TARGET_LONG_DOUBLE_128 && !TARGET_IEEEQUAD)
+ {
+ icode = CODE_FOR_unpacktf;
+ fcode = MISC_BUILTIN_UNPACK_TF;
+ uns_fcode = (size_t)fcode;
+ }
+ break;
+
+ default:
+ 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);
+
+ if (success)
+ return ret;
+ }
+ if (TARGET_HTM)
+ {
+ ret = htm_expand_builtin (exp, target, &success);
+
+ if (success)
+ return ret;
+ }
+
+ unsigned attr = (rs6000_builtin_info[uns_fcode].attr
+ & RS6000_BTC_TYPE_MASK);
+ /* RS6000_BTC_SPECIAL represents no-operand operators. */
+ 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. */
+ d = bdesc_1arg;
+ for (i = 0; i < ARRAY_SIZE (bdesc_1arg); i++, d++)
+ if (d->code == fcode)
+ return rs6000_expand_unop_builtin (icode, exp, target);
+
+ /* Handle simple binary operations. */
+ d = bdesc_2arg;
+ for (i = 0; i < ARRAY_SIZE (bdesc_2arg); i++, d++)
+ if (d->code == fcode)
+ return rs6000_expand_binop_builtin (icode, exp, target);
+
+ /* Handle simple ternary operations. */
+ d = bdesc_3arg;
+ for (i = 0; i < ARRAY_SIZE (bdesc_3arg); i++, d++)
+ 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++)
+ if (d->code == fcode)
+ return rs6000_expand_zeroop_builtin (icode, target);
+
+ gcc_unreachable ();
+ }
}
/* Create a builtin vector type with a name. Taking care not to give
^ permalink raw reply [flat|nested] 5+ messages in thread
* [gcc(refs/users/wschmidt/heads/builtins4)] rs6000: Support two builtin expansion algorithms
@ 2020-11-02 16:16 William Schmidt
0 siblings, 0 replies; 5+ messages in thread
From: William Schmidt @ 2020-11-02 16:16 UTC (permalink / raw)
To: gcc-cvs
https://gcc.gnu.org/g:c7b91f347aad6ec0224e4dde1760ffe41ab4ec78
commit c7b91f347aad6ec0224e4dde1760ffe41ab4ec78
Author: Bill Schmidt <wschmidt@linux.ibm.com>
Date: Mon Nov 2 11:16:08 2020 -0500
rs6000: Support two builtin expansion algorithms
2020-11-02 Bill Schmidt <wschmidt@linux.ibm.com>
* config/rs6000/rs6000-call.c (rs6000_expand_builtin): Support two
kinds of masks and icodes; use a new algorithm under control of
new_builtins_are_live, while still supporting the old one; do lazy
enablement to support #pragma target.
Diff:
---
gcc/config/rs6000/rs6000-call.c | 618 ++++++++++++++++++++++++++++++----------
1 file changed, 463 insertions(+), 155 deletions(-)
diff --git a/gcc/config/rs6000/rs6000-call.c b/gcc/config/rs6000/rs6000-call.c
index 6ee1e7833aa..1001cc1e1e7 100644
--- a/gcc/config/rs6000/rs6000-call.c
+++ b/gcc/config/rs6000/rs6000-call.c
@@ -10138,6 +10138,10 @@ mma_expand_builtin (tree exp, rtx target, bool *expandedp)
{
unsigned i;
tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
+ /* #### This needs to be rs6000_gen_builtins now. Can't make this
+ whole until the full set of builtins has been added, and there
+ is no overlap between the two enumerations, so we can run the
+ two in parallel. */
enum rs6000_builtins fcode
= (enum rs6000_builtins) DECL_MD_FUNCTION_CODE (fndecl);
const struct builtin_description *d = bdesc_mma;
@@ -13307,9 +13311,18 @@ rs6000_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
size_t i;
rtx ret;
bool success;
- HOST_WIDE_INT mask = rs6000_builtin_info[uns_fcode].mask;
+ HOST_WIDE_INT mask = (new_builtins_are_live
+ ? 0
+ : rs6000_builtin_info[uns_fcode].mask);
+ /*
+ bif_enable enable = (new_builtins_are_live
+ ? rs6000_builtin_info_x[uns_fcode].enable
+ : (bif_enable) 0);
+ */
bool func_valid_p = ((rs6000_builtin_mask & mask) == mask);
- enum insn_code icode = rs6000_builtin_info[uns_fcode].icode;
+ enum insn_code icode = (new_builtins_are_live
+ ? rs6000_builtin_info_x[uns_fcode].icode
+ : rs6000_builtin_info[uns_fcode].icode);
/* We have two different modes (KFmode, TFmode) that are the IEEE 128-bit
floating point type, depending on whether long double is the IBM extended
@@ -13340,7 +13353,7 @@ rs6000_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
case CODE_FOR_xststdcqp_kf: icode = CODE_FOR_xststdcqp_tf; break;
}
- if (TARGET_DEBUG_BUILTIN)
+ if (!new_builtins_are_live && TARGET_DEBUG_BUILTIN)
{
const char *name1 = rs6000_builtin_info[uns_fcode].name;
const char *name2 = (icode != CODE_FOR_nothing)
@@ -13378,201 +13391,496 @@ rs6000_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
return expand_call (exp, target, ignore);
}
- switch (fcode)
+ if (new_builtins_are_live)
{
- case RS6000_BUILTIN_RECIP:
- return rs6000_expand_binop_builtin (CODE_FOR_recipdf3, exp, target);
-
- case RS6000_BUILTIN_RECIPF:
- return rs6000_expand_binop_builtin (CODE_FOR_recipsf3, exp, target);
-
- case RS6000_BUILTIN_RSQRTF:
- return rs6000_expand_unop_builtin (CODE_FOR_rsqrtsf2, exp, target);
-
- case RS6000_BUILTIN_RSQRT:
- return rs6000_expand_unop_builtin (CODE_FOR_rsqrtdf2, exp, target);
-
- case POWER7_BUILTIN_BPERMD:
- return rs6000_expand_binop_builtin (((TARGET_64BIT)
- ? CODE_FOR_bpermd_di
- : CODE_FOR_bpermd_si), exp, target);
+ bifdata *bifaddr = &rs6000_builtin_info_x[uns_fcode];
- case RS6000_BUILTIN_GET_TB:
- return rs6000_expand_zeroop_builtin (CODE_FOR_rs6000_get_timebase,
- target);
-
- case RS6000_BUILTIN_MFTB:
- return rs6000_expand_zeroop_builtin (((TARGET_64BIT)
- ? CODE_FOR_rs6000_mftb_di
- : CODE_FOR_rs6000_mftb_si),
- target);
-
- case RS6000_BUILTIN_MFFS:
- return rs6000_expand_zeroop_builtin (CODE_FOR_rs6000_mffs, target);
+ /* In case of "#pragma target" changes, we initialize all builtins
+ but check for actual availability during expand time. */
+ switch (bifaddr->enable)
+ {
+ default:
+ gcc_unreachable ();
+ case ENB_ALWAYS:
+ break;
+ case ENB_P5:
+ if (!TARGET_POPCNTB)
+ return const0_rtx;
+ break;
+ case ENB_P6:
+ if (!TARGET_CMPB)
+ return const0_rtx;
+ break;
+ case ENB_ALTIVEC:
+ if (!TARGET_ALTIVEC)
+ return const0_rtx;
+ break;
+ case ENB_CELL:
+ if (!TARGET_ALTIVEC || rs6000_cpu != PROCESSOR_CELL)
+ return const0_rtx;
+ break;
+ case ENB_VSX:
+ if (!TARGET_VSX)
+ return const0_rtx;
+ break;
+ case ENB_P7:
+ if (!TARGET_POPCNTD)
+ return const0_rtx;
+ break;
+ case ENB_P7_64:
+ if (!TARGET_POPCNTD || !TARGET_POWERPC64)
+ return const0_rtx;
+ break;
+ case ENB_P8:
+ if (!TARGET_DIRECT_MOVE)
+ return const0_rtx;
+ break;
+ case ENB_P8V:
+ if (!TARGET_P8_VECTOR)
+ return const0_rtx;
+ break;
+ case ENB_P9:
+ if (!TARGET_MODULO)
+ return const0_rtx;
+ break;
+ case ENB_P9_64:
+ if (!TARGET_MODULO || !TARGET_POWERPC64)
+ return const0_rtx;
+ break;
+ case ENB_P9V:
+ if (!TARGET_P9_VECTOR)
+ return const0_rtx;
+ break;
+ case ENB_IEEE128_HW:
+ if (!TARGET_FLOAT128_HW)
+ return const0_rtx;
+ break;
+ case ENB_DFP:
+ if (!TARGET_DFP)
+ return const0_rtx;
+ break;
+ case ENB_CRYPTO:
+ if (!TARGET_CRYPTO)
+ return const0_rtx;
+ break;
+ case ENB_HTM:
+ if (!TARGET_HTM)
+ return const0_rtx;
+ break;
+ case ENB_P10:
+ if (!TARGET_POWER10)
+ return const0_rtx;
+ break;
+ case ENB_MMA:
+ if (!TARGET_MMA)
+ return const0_rtx;
+ break;
+ };
- case RS6000_BUILTIN_MTFSB0:
- return rs6000_expand_mtfsb_builtin (CODE_FOR_rs6000_mtfsb0, exp);
+ if (bif_is_nosoft (*bifaddr)
+ && rs6000_isa_flags & OPTION_MASK_SOFT_FLOAT)
+ {
+ error ("%<%s%> not supported with %<-msoft-float%>",
+ bifaddr->bifname);
+ return const0_rtx;
+ }
- case RS6000_BUILTIN_MTFSB1:
- return rs6000_expand_mtfsb_builtin (CODE_FOR_rs6000_mtfsb1, exp);
+ if (bif_is_no32bit (*bifaddr) && TARGET_32BIT)
+ fatal_error (input_location,
+ "%<%s%> is not supported in 32-bit mode",
+ bifaddr->bifname);
- case RS6000_BUILTIN_SET_FPSCR_RN:
- return rs6000_expand_set_fpscr_rn_builtin (CODE_FOR_rs6000_set_fpscr_rn,
- exp);
+ if (bif_is_cpu (*bifaddr))
+ return cpu_expand_builtin (fcode, exp, target);
- case RS6000_BUILTIN_SET_FPSCR_DRN:
- return
- rs6000_expand_set_fpscr_drn_builtin (CODE_FOR_rs6000_set_fpscr_drn,
- exp);
+ if (bif_is_init (*bifaddr))
+ return altivec_expand_vec_init_builtin (TREE_TYPE (exp), exp, target);
- case RS6000_BUILTIN_MFFSL:
- return rs6000_expand_zeroop_builtin (CODE_FOR_rs6000_mffsl, target);
+ if (bif_is_set (*bifaddr))
+ return altivec_expand_vec_set_builtin (exp);
- case RS6000_BUILTIN_MTFSF:
- return rs6000_expand_mtfsf_builtin (CODE_FOR_rs6000_mtfsf, exp);
+ if (bif_is_extract (*bifaddr))
+ return altivec_expand_vec_ext_builtin (exp, target);
- case RS6000_BUILTIN_CPU_INIT:
- case RS6000_BUILTIN_CPU_IS:
- case RS6000_BUILTIN_CPU_SUPPORTS:
- return cpu_expand_builtin (fcode, exp, target);
+ if (bif_is_predicate (*bifaddr))
+ return altivec_expand_predicate_builtin (icode, exp, target);
- case MISC_BUILTIN_SPEC_BARRIER:
- {
- emit_insn (gen_speculation_barrier ());
- return NULL_RTX;
- }
+ if (bif_is_htm (*bifaddr))
+ return new_htm_expand_builtin (bifaddr, fcode, exp, target);
- case ALTIVEC_BUILTIN_MASK_FOR_LOAD:
- {
- int icode2 = (BYTES_BIG_ENDIAN ? (int) CODE_FOR_altivec_lvsr_direct
- : (int) CODE_FOR_altivec_lvsl_direct);
- machine_mode tmode = insn_data[icode2].operand[0].mode;
- machine_mode mode = insn_data[icode2].operand[1].mode;
- tree arg;
- rtx op, addr, pat;
+ rtx pat;
+ const int MAX_BUILTIN_ARGS = 5;
+ tree arg[MAX_BUILTIN_ARGS];
+ rtx op[MAX_BUILTIN_ARGS];
+ machine_mode mode[MAX_BUILTIN_ARGS + 1];
- gcc_assert (TARGET_ALTIVEC);
+ int nargs = bifaddr->nargs;
+ gcc_assert (nargs <= MAX_BUILTIN_ARGS);
- arg = CALL_EXPR_ARG (exp, 0);
- gcc_assert (POINTER_TYPE_P (TREE_TYPE (arg)));
- op = expand_expr (arg, NULL_RTX, Pmode, EXPAND_NORMAL);
- addr = memory_address (mode, op);
- /* We need to negate the address. */
- op = gen_reg_rtx (GET_MODE (addr));
- emit_insn (gen_rtx_SET (op, gen_rtx_NEG (GET_MODE (addr), addr)));
- op = gen_rtx_MEM (mode, op);
+ mode[0] = insn_data[icode].operand[0].mode;
+ for (int i = 0; i < nargs; i++)
+ {
+ arg[i] = CALL_EXPR_ARG (exp, i);
+ if (arg[i] == error_mark_node)
+ return const0_rtx;
+ op[i] = expand_normal (arg[i]);
+ mode[i+1] = insn_data[icode].operand[i+1].mode;
+ }
- if (target == 0
- || GET_MODE (target) != tmode
- || ! (*insn_data[icode2].operand[0].predicate) (target, tmode))
- target = gen_reg_rtx (tmode);
+ /* Check for restricted constant arguments. */
+ for (int i = 0; i < 2; i++)
+ {
+ switch (bifaddr->restr[i])
+ {
+ default:
+ case RES_NONE:
+ break;
+ case RES_BITS:
+ {
+ size_t mask = (1 << bifaddr->restr_val1[i]) - 1;
+ tree restr_arg = arg[bifaddr->restr_opnd[i] - 1];
+ STRIP_NOPS (restr_arg);
+ if (TREE_CODE (restr_arg) != INTEGER_CST
+ || TREE_INT_CST_LOW (restr_arg) & ~mask)
+ {
+ error ("argument %d must be a %d-bit unsigned literal",
+ bifaddr->restr_opnd[i], bifaddr->restr_val1[i]);
+ return CONST0_RTX (mode[0]);
+ }
+ break;
+ }
+ case RES_RANGE:
+ {
+ tree restr_arg = arg[bifaddr->restr_opnd[i] - 1];
+ STRIP_NOPS (restr_arg);
+ if (TREE_CODE (restr_arg) != INTEGER_CST
+ || !IN_RANGE (tree_to_shwi (restr_arg),
+ bifaddr->restr_val1[i],
+ bifaddr->restr_val2[i]))
+ {
+ error ("argument %d must be a literal between %d and %d,"
+ " inclusive",
+ bifaddr->restr_opnd[i], bifaddr->restr_val1[i],
+ bifaddr->restr_val2[i]);
+ return CONST0_RTX (mode[0]);
+ }
+ break;
+ }
+ case RES_VAR_RANGE:
+ {
+ tree restr_arg = arg[bifaddr->restr_opnd[i] - 1];
+ STRIP_NOPS (restr_arg);
+ if (TREE_CODE (restr_arg) == INTEGER_CST
+ && !IN_RANGE (tree_to_shwi (restr_arg),
+ bifaddr->restr_val1[i],
+ bifaddr->restr_val2[i]))
+ {
+ error ("argument %d must be a variable or a literal "
+ "between %d and %d, inclusive",
+ bifaddr->restr_opnd[i], bifaddr->restr_val1[i],
+ bifaddr->restr_val2[i]);
+ return CONST0_RTX (mode[0]);
+ }
+ break;
+ }
+ case RES_VALUES:
+ {
+ tree restr_arg = arg[bifaddr->restr_opnd[i] - 1];
+ STRIP_NOPS (restr_arg);
+ if (TREE_CODE (restr_arg) != INTEGER_CST
+ || (tree_to_shwi (restr_arg) != bifaddr->restr_val1[i]
+ && tree_to_shwi (restr_arg) != bifaddr->restr_val2[i]))
+ {
+ error ("argument %d must be either a literal %d or a "
+ "literal %d",
+ bifaddr->restr_opnd[i], bifaddr->restr_val1[i],
+ bifaddr->restr_val2[i]);
+ return CONST0_RTX (mode[0]);
+ }
+ break;
+ }
+ }
+ }
- pat = GEN_FCN (icode2) (target, op);
- if (!pat)
- return 0;
- emit_insn (pat);
+ if (bif_is_ldstmask (*bifaddr))
+ return rs6000_expand_ldst_mask (target, fcode, arg[0]);
- return target;
- }
+ if (bif_is_stvec (*bifaddr))
+ {
+ if (bif_is_reve (*bifaddr))
+ icode = elemrev_icode (fcode);
+ return stv_expand_builtin (icode, op, mode[0], mode[1]);
+ }
- case ALTIVEC_BUILTIN_VCFUX:
- case ALTIVEC_BUILTIN_VCFSX:
- case ALTIVEC_BUILTIN_VCTUXS:
- case ALTIVEC_BUILTIN_VCTSXS:
- /* FIXME: There's got to be a nicer way to handle this case than
- constructing a new CALL_EXPR. */
- if (call_expr_nargs (exp) == 1)
+ if (bif_is_ldvec (*bifaddr))
{
- exp = build_call_nary (TREE_TYPE (exp), CALL_EXPR_FN (exp),
- 2, CALL_EXPR_ARG (exp, 0), integer_zero_node);
+ if (bif_is_reve (*bifaddr))
+ icode = elemrev_icode (fcode);
+ return ldv_expand_builtin (target, icode, op, mode[0]);
}
- break;
- /* For the pack and unpack int128 routines, fix up the builtin so it
- uses the correct IBM128 type. */
- case MISC_BUILTIN_PACK_IF:
- if (TARGET_LONG_DOUBLE_128 && !TARGET_IEEEQUAD)
+ if (bif_is_mma (*bifaddr))
+ return new_mma_expand_builtin (exp, target, fcode, icode);
+
+ if (fcode == MISC_BUILTIN_PACK_IF
+ && TARGET_LONG_DOUBLE_128 && !TARGET_IEEEQUAD)
{
icode = CODE_FOR_packtf;
fcode = MISC_BUILTIN_PACK_TF;
uns_fcode = (size_t)fcode;
}
- break;
-
- case MISC_BUILTIN_UNPACK_IF:
- if (TARGET_LONG_DOUBLE_128 && !TARGET_IEEEQUAD)
+ else if (fcode == MISC_BUILTIN_UNPACK_IF
+ && TARGET_LONG_DOUBLE_128 && !TARGET_IEEEQUAD)
{
icode = CODE_FOR_unpacktf;
fcode = MISC_BUILTIN_UNPACK_TF;
uns_fcode = (size_t)fcode;
}
- break;
- default:
- break;
- }
+ if (target == 0
+ || GET_MODE (target) != mode[0]
+ || !(*insn_data[icode].operand[0].predicate) (target, mode[0]))
+ target = gen_reg_rtx (mode[0]);
- if (TARGET_MMA)
- {
- ret = mma_expand_builtin (exp, target, &success);
+ for (int i = 0; i < nargs; i++)
+ if (! (*insn_data[icode].operand[i+1].predicate) (op[i], mode[i+1]))
+ op[i] = copy_to_mode_reg (mode[i+1], op[i]);
- if (success)
- return ret;
- }
- if (TARGET_ALTIVEC)
- {
- ret = altivec_expand_builtin (exp, target, &success);
+ switch (nargs)
+ {
+ default:
+ gcc_assert (MAX_BUILTIN_ARGS == 5);
+ gcc_unreachable ();
+ case 0:
+ pat = GEN_FCN (icode) (target);
+ break;
+ case 1:
+ pat = GEN_FCN (icode) (target, op[0]);
+ break;
+ case 2:
+ pat = GEN_FCN (icode) (target, op[0], op[1]);
+ break;
+ case 3:
+ pat = GEN_FCN (icode) (target, op[0], op[1], op[2]);
+ break;
+ case 4:
+ pat = GEN_FCN (icode) (target, op[0], op[1], op[2], op[3]);
+ break;
+ case 5:
+ pat = GEN_FCN (icode) (target, op[0], op[1], op[2], op[3], op[4]);
+ break;
+ }
- if (success)
- return ret;
+ if (!pat)
+ return 0;
+ emit_insn (pat);
+
+ return target;
}
- if (TARGET_HTM)
+ else
{
- ret = htm_expand_builtin (exp, target, &success);
+ switch (fcode)
+ {
+ case RS6000_BUILTIN_RECIP:
+ return rs6000_expand_binop_builtin (CODE_FOR_recipdf3, exp, target);
- if (success)
- return ret;
- }
+ case RS6000_BUILTIN_RECIPF:
+ return rs6000_expand_binop_builtin (CODE_FOR_recipsf3, exp, target);
- 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
- || attr == RS6000_BTC_TERNARY
- || attr == RS6000_BTC_QUATERNARY
- || attr == RS6000_BTC_SPECIAL);
-
- /* Handle simple unary operations. */
- d = bdesc_1arg;
- for (i = 0; i < ARRAY_SIZE (bdesc_1arg); i++, d++)
- if (d->code == fcode)
- return rs6000_expand_unop_builtin (icode, exp, target);
+ case RS6000_BUILTIN_RSQRTF:
+ return rs6000_expand_unop_builtin (CODE_FOR_rsqrtsf2, exp, target);
- /* Handle simple binary operations. */
- d = bdesc_2arg;
- for (i = 0; i < ARRAY_SIZE (bdesc_2arg); i++, d++)
- if (d->code == fcode)
- return rs6000_expand_binop_builtin (icode, exp, target);
+ case RS6000_BUILTIN_RSQRT:
+ return rs6000_expand_unop_builtin (CODE_FOR_rsqrtdf2, exp, target);
- /* Handle simple ternary operations. */
- d = bdesc_3arg;
- for (i = 0; i < ARRAY_SIZE (bdesc_3arg); i++, d++)
- if (d->code == fcode)
- return rs6000_expand_ternop_builtin (icode, exp, target);
+ case POWER7_BUILTIN_BPERMD:
+ return rs6000_expand_binop_builtin (((TARGET_64BIT)
+ ? CODE_FOR_bpermd_di
+ : CODE_FOR_bpermd_si),
+ 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);
+ case RS6000_BUILTIN_GET_TB:
+ return rs6000_expand_zeroop_builtin (CODE_FOR_rs6000_get_timebase,
+ target);
- /* Handle simple no-argument operations. */
- d = bdesc_0arg;
- for (i = 0; i < ARRAY_SIZE (bdesc_0arg); i++, d++)
- if (d->code == fcode)
- return rs6000_expand_zeroop_builtin (icode, target);
+ case RS6000_BUILTIN_MFTB:
+ return rs6000_expand_zeroop_builtin (((TARGET_64BIT)
+ ? CODE_FOR_rs6000_mftb_di
+ : CODE_FOR_rs6000_mftb_si),
+ target);
- gcc_unreachable ();
+ case RS6000_BUILTIN_MFFS:
+ return rs6000_expand_zeroop_builtin (CODE_FOR_rs6000_mffs, target);
+
+ case RS6000_BUILTIN_MTFSB0:
+ return rs6000_expand_mtfsb_builtin (CODE_FOR_rs6000_mtfsb0, exp);
+
+ case RS6000_BUILTIN_MTFSB1:
+ return rs6000_expand_mtfsb_builtin (CODE_FOR_rs6000_mtfsb1, exp);
+
+ case RS6000_BUILTIN_SET_FPSCR_RN:
+ return rs6000_expand_set_fpscr_rn_builtin
+ (CODE_FOR_rs6000_set_fpscr_rn, exp);
+
+ case RS6000_BUILTIN_SET_FPSCR_DRN:
+ return
+ rs6000_expand_set_fpscr_drn_builtin (CODE_FOR_rs6000_set_fpscr_drn,
+ exp);
+
+ case RS6000_BUILTIN_MFFSL:
+ return rs6000_expand_zeroop_builtin (CODE_FOR_rs6000_mffsl, target);
+
+ case RS6000_BUILTIN_MTFSF:
+ return rs6000_expand_mtfsf_builtin (CODE_FOR_rs6000_mtfsf, exp);
+
+ case RS6000_BUILTIN_CPU_INIT:
+ case RS6000_BUILTIN_CPU_IS:
+ case RS6000_BUILTIN_CPU_SUPPORTS:
+ return cpu_expand_builtin (fcode, exp, target);
+
+ case MISC_BUILTIN_SPEC_BARRIER:
+ {
+ emit_insn (gen_speculation_barrier ());
+ return NULL_RTX;
+ }
+
+ case ALTIVEC_BUILTIN_MASK_FOR_LOAD:
+ {
+ int icode2 = (BYTES_BIG_ENDIAN ? (int) CODE_FOR_altivec_lvsr_direct
+ : (int) CODE_FOR_altivec_lvsl_direct);
+ machine_mode tmode = insn_data[icode2].operand[0].mode;
+ machine_mode mode = insn_data[icode2].operand[1].mode;
+ tree arg;
+ rtx op, addr, pat;
+
+ gcc_assert (TARGET_ALTIVEC);
+
+ arg = CALL_EXPR_ARG (exp, 0);
+ gcc_assert (POINTER_TYPE_P (TREE_TYPE (arg)));
+ op = expand_expr (arg, NULL_RTX, Pmode, EXPAND_NORMAL);
+ addr = memory_address (mode, op);
+ /* We need to negate the address. */
+ op = gen_reg_rtx (GET_MODE (addr));
+ emit_insn (gen_rtx_SET (op, gen_rtx_NEG (GET_MODE (addr), addr)));
+ op = gen_rtx_MEM (mode, op);
+
+ if (target == 0
+ || GET_MODE (target) != tmode
+ || ! (*insn_data[icode2].operand[0].predicate) (target, tmode))
+ target = gen_reg_rtx (tmode);
+
+ pat = GEN_FCN (icode2) (target, op);
+ if (!pat)
+ return 0;
+ emit_insn (pat);
+
+ return target;
+ }
+
+ case ALTIVEC_BUILTIN_VCFUX:
+ case ALTIVEC_BUILTIN_VCFSX:
+ case ALTIVEC_BUILTIN_VCTUXS:
+ case ALTIVEC_BUILTIN_VCTSXS:
+ /* #### Replace this nonsense with a separate built-in for the
+ vectorizer to use, which I believe is the only way we get
+ into this situation. */
+ /* FIXME: There's got to be a nicer way to handle this case than
+ constructing a new CALL_EXPR. */
+ if (call_expr_nargs (exp) == 1)
+ {
+ exp = build_call_nary (TREE_TYPE (exp), CALL_EXPR_FN (exp),
+ 2, CALL_EXPR_ARG (exp, 0),
+ integer_zero_node);
+ }
+ break;
+
+ /* For the pack and unpack int128 routines, fix up the builtin so it
+ uses the correct IBM128 type. */
+ case MISC_BUILTIN_PACK_IF:
+ if (TARGET_LONG_DOUBLE_128 && !TARGET_IEEEQUAD)
+ {
+ icode = CODE_FOR_packtf;
+ fcode = MISC_BUILTIN_PACK_TF;
+ uns_fcode = (size_t)fcode;
+ }
+ break;
+
+ case MISC_BUILTIN_UNPACK_IF:
+ if (TARGET_LONG_DOUBLE_128 && !TARGET_IEEEQUAD)
+ {
+ icode = CODE_FOR_unpacktf;
+ fcode = MISC_BUILTIN_UNPACK_TF;
+ uns_fcode = (size_t)fcode;
+ }
+ break;
+
+ default:
+ 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);
+
+ if (success)
+ return ret;
+ }
+ if (TARGET_HTM)
+ {
+ ret = htm_expand_builtin (exp, target, &success);
+
+ if (success)
+ return ret;
+ }
+
+ unsigned attr = (rs6000_builtin_info[uns_fcode].attr
+ & RS6000_BTC_TYPE_MASK);
+ /* RS6000_BTC_SPECIAL represents no-operand operators. */
+ 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. */
+ d = bdesc_1arg;
+ for (i = 0; i < ARRAY_SIZE (bdesc_1arg); i++, d++)
+ if (d->code == fcode)
+ return rs6000_expand_unop_builtin (icode, exp, target);
+
+ /* Handle simple binary operations. */
+ d = bdesc_2arg;
+ for (i = 0; i < ARRAY_SIZE (bdesc_2arg); i++, d++)
+ if (d->code == fcode)
+ return rs6000_expand_binop_builtin (icode, exp, target);
+
+ /* Handle simple ternary operations. */
+ d = bdesc_3arg;
+ for (i = 0; i < ARRAY_SIZE (bdesc_3arg); i++, d++)
+ 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++)
+ if (d->code == fcode)
+ return rs6000_expand_zeroop_builtin (icode, target);
+
+ gcc_unreachable ();
+ }
}
/* Create a builtin vector type with a name. Taking care not to give
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2021-02-07 18:14 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-12-16 18:07 [gcc(refs/users/wschmidt/heads/builtins4)] rs6000: Support two builtin expansion algorithms William Schmidt
-- strict thread matches above, loose matches on Subject: below --
2021-02-07 18:14 William Schmidt
2020-11-24 16:45 William Schmidt
2020-11-02 22:08 William Schmidt
2020-11-02 16:16 William Schmidt
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).