We were shoe-horning all built-in enumerations (including frontend and target-specific ones) into a field of type built_in_function. This was accessed as either an lvalue or an rvalue using DECL_FUNCTION_CODE. The obvious danger with this (as was noted by several ??? comments) is that the ranges have nothing to do with each other, and targets can easily have more built-in functions than generic code. But my patch to make the field bigger was the straw that finally made the problem visible. This patch therefore: - replaces the field with a plain unsigned int - turns DECL_FUNCTION_CODE into an rvalue-only accessor that checks that the function really is BUILT_IN_NORMAL - adds corresponding DECL_MD_FUNCTION_CODE and DECL_FE_FUNCTION_CODE accessors for BUILT_IN_MD and BUILT_IN_FRONTEND respectively - adds DECL_UNCHECKED_FUNCTION_CODE for places that need to access the underlying field (should be low-level code only) - adds new helpers for setting the built-in class and function code - makes DECL_BUILT_IN_CLASS an rvalue-only accessor too, since all assignments should go through the new helpers 2019-08-13 Richard Sandiford <richard.sandiford@arm.com> gcc/ PR middle-end/91421 * tree-core.h (function_decl::function_code): Change type to unsigned int. * tree.h (DECL_FUNCTION_CODE): Rename old definition to... (DECL_UNCHECKED_FUNCTION_CODE): ...this. (DECL_BUILT_IN_CLASS): Make an rvalue macro only. (DECL_FUNCTION_CODE): New function. Assert that the built-in class is BUILT_IN_NORMAL. (DECL_MD_FUNCTION_CODE, DECL_FE_FUNCTION_CODE): New functions. (set_decl_built_in_function, copy_decl_built_in_function): Likewise. (fndecl_built_in_p): Change the type of the "name" argument to unsigned int. * builtins.c (expand_builtin): Move DECL_FUNCTION_CODE use after check for DECL_BUILT_IN_CLASS. * cgraphclones.c (build_function_decl_skip_args): Use set_decl_built_in_function. * ipa-param-manipulation.c (ipa_modify_formal_parameters): Likewise. * ipa-split.c (split_function): Likewise. * langhooks.c (add_builtin_function_common): Likewise. * omp-simd-clone.c (simd_clone_create): Likewise. * tree-streamer-in.c (unpack_ts_function_decl_value_fields): Likewise. * config/darwin.c (darwin_init_cfstring_builtins): Likewise. (darwin_fold_builtin): Use DECL_MD_FUNCTION_CODE instead of DECL_FUNCTION_CODE. * fold-const.c (operand_equal_p): Compare DECL_UNCHECKED_FUNCTION_CODE instead of DECL_FUNCTION_CODE. * lto-streamer-out.c (hash_tree): Use DECL_UNCHECKED_FUNCTION_CODE instead of DECL_FUNCTION_CODE. * tree-streamer-out.c (pack_ts_function_decl_value_fields): Likewise. * print-tree.c (print_node): Use DECL_MD_FUNCTION_CODE when printing DECL_BUILT_IN_MD. Handle DECL_BUILT_IN_FRONTEND. * config/aarch64/aarch64-builtins.c (aarch64_expand_builtin) (aarch64_fold_builtin, aarch64_gimple_fold_builtin): Use DECL_MD_FUNCTION_CODE instead of DECL_FUNCTION_CODE. * config/aarch64/aarch64.c (aarch64_builtin_reciprocal): Likewise. * config/alpha/alpha.c (alpha_expand_builtin, alpha_fold_builtin): (alpha_gimple_fold_builtin): Likewise. * config/arc/arc.c (arc_expand_builtin): Likewise. * config/arm/arm-builtins.c (arm_expand_builtin): Likewise. * config/avr/avr-c.c (avr_resolve_overloaded_builtin): Likewise. * config/avr/avr.c (avr_expand_builtin, avr_fold_builtin): Likewise. * config/bfin/bfin.c (bfin_expand_builtin): Likewise. * config/c6x/c6x.c (c6x_expand_builtin): Likewise. * config/frv/frv.c (frv_expand_builtin): Likewise. * config/gcn/gcn.c (gcn_expand_builtin_1): Likewise. (gcn_expand_builtin): Likewise. * config/i386/i386-builtins.c (ix86_builtin_reciprocal): Likewise. (fold_builtin_cpu): Likewise. * config/i386/i386-expand.c (ix86_expand_builtin): Likewise. * config/i386/i386.c (ix86_fold_builtin): Likewise. (ix86_gimple_fold_builtin): Likewise. * config/ia64/ia64.c (ia64_fold_builtin): Likewise. (ia64_expand_builtin): Likewise. * config/iq2000/iq2000.c (iq2000_expand_builtin): Likewise. * config/mips/mips.c (mips_expand_builtin): Likewise. * config/msp430/msp430.c (msp430_expand_builtin): Likewise. * config/nds32/nds32-intrinsic.c (nds32_expand_builtin_impl): Likewise. * config/nios2/nios2.c (nios2_expand_builtin): Likewise. * config/nvptx/nvptx.c (nvptx_expand_builtin): Likewise. * config/pa/pa.c (pa_expand_builtin): Likewise. * config/pru/pru.c (pru_expand_builtin): Likewise. * config/riscv/riscv-builtins.c (riscv_expand_builtin): Likewise. * config/rs6000/rs6000-c.c (altivec_resolve_overloaded_builtin): Likewise. * config/rs6000/rs6000-call.c (htm_expand_builtin): Likewise. (altivec_expand_dst_builtin, altivec_expand_builtin): Likewise. (rs6000_gimple_fold_builtin, rs6000_expand_builtin): Likewise. * config/rs6000/rs6000.c (rs6000_builtin_md_vectorized_function) (rs6000_builtin_reciprocal): Likewise. * config/rx/rx.c (rx_expand_builtin): Likewise. * config/s390/s390-c.c (s390_resolve_overloaded_builtin): Likewise. * config/s390/s390.c (s390_expand_builtin): Likewise. * config/sh/sh.c (sh_expand_builtin): Likewise. * config/sparc/sparc.c (sparc_expand_builtin): Likewise. (sparc_fold_builtin): Likewise. * config/spu/spu-c.c (spu_resolve_overloaded_builtin): Likewise. * config/spu/spu.c (spu_expand_builtin): Likewise. * config/stormy16/stormy16.c (xstormy16_expand_builtin): Likewise. * config/tilegx/tilegx.c (tilegx_expand_builtin): Likewise. * config/tilepro/tilepro.c (tilepro_expand_builtin): Likewise. * config/xtensa/xtensa.c (xtensa_fold_builtin): Likewise. (xtensa_expand_builtin): Likewise. gcc/ada/ PR middle-end/91421 * gcc-interface/trans.c (gigi): Call set_decl_buillt_in_function. (Call_to_gnu): Use DECL_FE_FUNCTION_CODE instead of DECL_FUNCTION_CODE. gcc/c/ PR middle-end/91421 * c-decl.c (merge_decls): Use copy_decl_built_in_function. gcc/c-family/ PR middle-end/91421 * c-common.c (resolve_overloaded_builtin): Use copy_decl_built_in_function. gcc/cp/ PR middle-end/91421 * decl.c (duplicate_decls): Use copy_decl_built_in_function. * pt.c (declare_integer_pack): Use set_decl_built_in_function. gcc/d/ PR middle-end/91421 * intrinsics.cc (maybe_set_intrinsic): Use set_decl_built_in_function. gcc/jit/ PR middle-end/91421 * jit-playback.c (new_function): Use set_decl_built_in_function. gcc/lto/ PR middle-end/91421 * lto-common.c (compare_tree_sccs_1): Use DECL_UNCHECKED_FUNCTION_CODE instead of DECL_FUNCTION_CODE. * lto-symtab.c (lto_symtab_merge_p): Likewise. From-SVN: r274404
234 lines
6.7 KiB
C
234 lines
6.7 KiB
C
/* Copyright (C) 2006-2019 Free Software Foundation, Inc.
|
||
|
||
This file is free software; you can redistribute it and/or modify it under
|
||
the terms of the GNU General Public License as published by the Free
|
||
Software Foundation; either version 3 of the License, or (at your option)
|
||
any later version.
|
||
|
||
This file is distributed in the hope that it will be useful, but WITHOUT
|
||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||
for more details.
|
||
|
||
You should have received a copy of the GNU General Public License
|
||
along with GCC; see the file COPYING3. If not see
|
||
<http://www.gnu.org/licenses/>. */
|
||
|
||
#define IN_TARGET_CODE 1
|
||
|
||
#include "config.h"
|
||
#include "system.h"
|
||
#include "coretypes.h"
|
||
#include "target.h"
|
||
#include "c-family/c-common.h"
|
||
#include "stringpool.h"
|
||
#include "langhooks.h"
|
||
|
||
|
||
/* Keep the vector keywords handy for fast comparisons. */
|
||
static GTY(()) tree __vector_keyword;
|
||
static GTY(()) tree vector_keyword;
|
||
|
||
static cpp_hashnode *
|
||
spu_categorize_keyword (const cpp_token *tok)
|
||
{
|
||
if (tok->type == CPP_NAME)
|
||
{
|
||
cpp_hashnode *ident = tok->val.node.node;
|
||
|
||
if (ident == C_CPP_HASHNODE (vector_keyword)
|
||
|| ident == C_CPP_HASHNODE (__vector_keyword))
|
||
return C_CPP_HASHNODE (__vector_keyword);
|
||
else
|
||
return ident;
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
/* Called to decide whether a conditional macro should be expanded.
|
||
Since we have exactly one such macro (i.e, 'vector'), we do not
|
||
need to examine the 'tok' parameter. */
|
||
|
||
static cpp_hashnode *
|
||
spu_macro_to_expand (cpp_reader *pfile, const cpp_token *tok)
|
||
{
|
||
cpp_hashnode *expand_this = tok->val.node.node;
|
||
cpp_hashnode *ident;
|
||
|
||
ident = spu_categorize_keyword (tok);
|
||
if (ident == C_CPP_HASHNODE (__vector_keyword))
|
||
{
|
||
tok = cpp_peek_token (pfile, 0);
|
||
ident = spu_categorize_keyword (tok);
|
||
|
||
if (ident)
|
||
{
|
||
enum rid rid_code = (enum rid)(ident->rid_code);
|
||
if (cpp_macro_p (ident))
|
||
{
|
||
(void) cpp_get_token (pfile);
|
||
tok = cpp_peek_token (pfile, 0);
|
||
ident = spu_categorize_keyword (tok);
|
||
if (ident)
|
||
rid_code = (enum rid)(ident->rid_code);
|
||
}
|
||
|
||
if (rid_code == RID_UNSIGNED || rid_code == RID_LONG
|
||
|| rid_code == RID_SHORT || rid_code == RID_SIGNED
|
||
|| rid_code == RID_INT || rid_code == RID_CHAR
|
||
|| rid_code == RID_FLOAT || rid_code == RID_DOUBLE)
|
||
expand_this = C_CPP_HASHNODE (__vector_keyword);
|
||
}
|
||
}
|
||
return expand_this;
|
||
}
|
||
|
||
/* target hook for resolve_overloaded_builtin(). Returns a function call
|
||
RTX if we can resolve the overloaded builtin */
|
||
tree
|
||
spu_resolve_overloaded_builtin (location_t loc, tree fndecl, void *passed_args)
|
||
{
|
||
#define SCALAR_TYPE_P(t) (INTEGRAL_TYPE_P (t) \
|
||
|| SCALAR_FLOAT_TYPE_P (t) \
|
||
|| POINTER_TYPE_P (t))
|
||
vec<tree, va_gc> *fnargs = static_cast <vec<tree, va_gc> *> (passed_args);
|
||
unsigned int nargs = vec_safe_length (fnargs);
|
||
int new_fcode, fcode = DECL_MD_FUNCTION_CODE (fndecl);
|
||
struct spu_builtin_description *desc;
|
||
tree match = NULL_TREE;
|
||
|
||
/* The vector types are not available if the backend is not initialized. */
|
||
gcc_assert (!flag_preprocess_only);
|
||
|
||
desc = &spu_builtins[fcode];
|
||
if (desc->type != B_OVERLOAD)
|
||
return NULL_TREE;
|
||
|
||
/* Compare the signature of each internal builtin function with the
|
||
function arguments until a match is found. */
|
||
|
||
for (new_fcode = fcode + 1; spu_builtins[new_fcode].type == B_INTERNAL;
|
||
new_fcode++)
|
||
{
|
||
tree decl = targetm.builtin_decl (new_fcode, true);
|
||
tree params = TYPE_ARG_TYPES (TREE_TYPE (decl));
|
||
tree param;
|
||
bool all_scalar;
|
||
unsigned int p;
|
||
|
||
/* Check whether all parameters are scalar. */
|
||
all_scalar = true;
|
||
for (param = params; param != void_list_node; param = TREE_CHAIN (param))
|
||
if (!SCALAR_TYPE_P (TREE_VALUE (param)))
|
||
all_scalar = false;
|
||
|
||
for (param = params, p = 0;
|
||
param != void_list_node;
|
||
param = TREE_CHAIN (param), p++)
|
||
{
|
||
tree var, arg_type, param_type = TREE_VALUE (param);
|
||
|
||
if (p >= nargs)
|
||
{
|
||
error ("insufficient arguments to overloaded function %s",
|
||
desc->name);
|
||
return error_mark_node;
|
||
}
|
||
|
||
var = (*fnargs)[p];
|
||
|
||
if (TREE_CODE (var) == NON_LVALUE_EXPR)
|
||
var = TREE_OPERAND (var, 0);
|
||
|
||
if (TREE_CODE (var) == ERROR_MARK)
|
||
return NULL_TREE; /* Let somebody else deal with the problem. */
|
||
|
||
arg_type = TREE_TYPE (var);
|
||
|
||
/* The intrinsics spec does not specify precisely how to
|
||
resolve generic intrinsics. We require an exact match
|
||
for vector types and let C do it's usual parameter type
|
||
checking/promotions for scalar arguments, except for the
|
||
first argument of intrinsics which don't have a vector
|
||
parameter. */
|
||
if ((!SCALAR_TYPE_P (param_type)
|
||
|| !SCALAR_TYPE_P (arg_type)
|
||
|| (all_scalar && p == 0))
|
||
&& !lang_hooks.types_compatible_p (param_type, arg_type))
|
||
break;
|
||
}
|
||
if (param == void_list_node)
|
||
{
|
||
if (p != nargs)
|
||
{
|
||
error ("too many arguments to overloaded function %s",
|
||
desc->name);
|
||
return error_mark_node;
|
||
}
|
||
|
||
match = decl;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (match == NULL_TREE)
|
||
{
|
||
error ("parameter list does not match a valid signature for %s()",
|
||
desc->name);
|
||
return error_mark_node;
|
||
}
|
||
|
||
return build_function_call_vec (loc, vNULL, match, fnargs, NULL);
|
||
#undef SCALAR_TYPE_P
|
||
}
|
||
|
||
|
||
void
|
||
spu_cpu_cpp_builtins (struct cpp_reader *pfile)
|
||
{
|
||
cpp_define (pfile, "__SPU__");
|
||
cpp_assert (pfile, "cpu=spu");
|
||
cpp_assert (pfile, "machine=spu");
|
||
if (spu_arch == PROCESSOR_CELLEDP)
|
||
cpp_define (pfile, "__SPU_EDP__");
|
||
if (cpp_get_options (pfile)->lang != CLK_ASM)
|
||
cpp_define (pfile, "__vector=__attribute__((__spu_vector__))");
|
||
switch (spu_ea_model)
|
||
{
|
||
case 32:
|
||
cpp_define (pfile, "__EA32__");
|
||
break;
|
||
case 64:
|
||
cpp_define (pfile, "__EA64__");
|
||
break;
|
||
default:
|
||
gcc_unreachable ();
|
||
}
|
||
|
||
if (!flag_iso && cpp_get_options (pfile)->lang != CLK_ASM)
|
||
{
|
||
/* Define this when supporting context-sensitive keywords. */
|
||
cpp_define (pfile, "__VECTOR_KEYWORD_SUPPORTED__");
|
||
cpp_define (pfile, "vector=vector");
|
||
|
||
/* Initialize vector keywords. */
|
||
__vector_keyword = get_identifier ("__vector");
|
||
C_CPP_HASHNODE (__vector_keyword)->flags |= NODE_CONDITIONAL;
|
||
vector_keyword = get_identifier ("vector");
|
||
C_CPP_HASHNODE (vector_keyword)->flags |= NODE_CONDITIONAL;
|
||
|
||
/* Enable context-sensitive macros. */
|
||
cpp_get_callbacks (pfile)->macro_to_expand = spu_macro_to_expand;
|
||
}
|
||
}
|
||
|
||
void
|
||
spu_c_common_override_options (void)
|
||
{
|
||
if (!TARGET_STD_MAIN)
|
||
{
|
||
/* Don't give warnings about the main() function. */
|
||
warn_main = 0;
|
||
}
|
||
}
|