#include "gimple-iterator.h"
#include "gimplify.h"
#include "tree-dfa.h"
-#include "params.h"
#include "langhooks-def.h"
#include "tree-diagnostic.h"
#include "except.h"
#include "rtl.h"
#include "regs.h"
#include "tree-vector-builder.h"
+#include "gimple-fold.h"
+#include "escaped_string.h"
/* Tree code classes. */
2, /* OMP_CLAUSE_TO */
2, /* OMP_CLAUSE_MAP */
1, /* OMP_CLAUSE_USE_DEVICE_PTR */
+ 1, /* OMP_CLAUSE_USE_DEVICE_ADDR */
1, /* OMP_CLAUSE_IS_DEVICE_PTR */
1, /* OMP_CLAUSE_INCLUSIVE */
1, /* OMP_CLAUSE_EXCLUSIVE */
0, /* OMP_CLAUSE_PROC_BIND */
1, /* OMP_CLAUSE_SAFELEN */
1, /* OMP_CLAUSE_SIMDLEN */
+ 0, /* OMP_CLAUSE_DEVICE_TYPE */
0, /* OMP_CLAUSE_FOR */
0, /* OMP_CLAUSE_PARALLEL */
0, /* OMP_CLAUSE_SECTIONS */
0, /* OMP_CLAUSE_THREADS */
0, /* OMP_CLAUSE_SIMD */
1, /* OMP_CLAUSE_HINT */
- 0, /* OMP_CLAUSE_DEFALTMAP */
+ 0, /* OMP_CLAUSE_DEFAULTMAP */
+ 0, /* OMP_CLAUSE_ORDER */
+ 0, /* OMP_CLAUSE_BIND */
1, /* OMP_CLAUSE__SIMDUID_ */
0, /* OMP_CLAUSE__SIMT_ */
0, /* OMP_CLAUSE_INDEPENDENT */
"to",
"map",
"use_device_ptr",
+ "use_device_addr",
"is_device_ptr",
"inclusive",
"exclusive",
"proc_bind",
"safelen",
"simdlen",
+ "device_type",
"for",
"parallel",
"sections",
"simd",
"hint",
"defaultmap",
+ "order",
+ "bind",
"_simduid_",
"_simt_",
"independent",
switch (TREE_CODE_CLASS (code))
{
case tcc_declaration:
- {
- switch (code)
- {
- case FIELD_DECL:
- return TS_FIELD_DECL;
- case PARM_DECL:
- return TS_PARM_DECL;
- case VAR_DECL:
- return TS_VAR_DECL;
- case LABEL_DECL:
- return TS_LABEL_DECL;
- case RESULT_DECL:
- return TS_RESULT_DECL;
- case DEBUG_EXPR_DECL:
- return TS_DECL_WRTL;
- case CONST_DECL:
- return TS_CONST_DECL;
- case TYPE_DECL:
- return TS_TYPE_DECL;
- case FUNCTION_DECL:
- return TS_FUNCTION_DECL;
- case TRANSLATION_UNIT_DECL:
- return TS_TRANSLATION_UNIT_DECL;
- default:
- return TS_DECL_NON_COMMON;
- }
- }
- case tcc_type:
- return TS_TYPE_NON_COMMON;
- case tcc_reference:
- case tcc_comparison:
- case tcc_unary:
+ switch (code)
+ {
+ case CONST_DECL: return TS_CONST_DECL;
+ case DEBUG_EXPR_DECL: return TS_DECL_WRTL;
+ case FIELD_DECL: return TS_FIELD_DECL;
+ case FUNCTION_DECL: return TS_FUNCTION_DECL;
+ case LABEL_DECL: return TS_LABEL_DECL;
+ case PARM_DECL: return TS_PARM_DECL;
+ case RESULT_DECL: return TS_RESULT_DECL;
+ case TRANSLATION_UNIT_DECL: return TS_TRANSLATION_UNIT_DECL;
+ case TYPE_DECL: return TS_TYPE_DECL;
+ case VAR_DECL: return TS_VAR_DECL;
+ default: return TS_DECL_NON_COMMON;
+ }
+
+ case tcc_type: return TS_TYPE_NON_COMMON;
+
case tcc_binary:
+ case tcc_comparison:
case tcc_expression:
+ case tcc_reference:
case tcc_statement:
- case tcc_vl_exp:
- return TS_EXP;
+ case tcc_unary:
+ case tcc_vl_exp: return TS_EXP;
+
default: /* tcc_constant and tcc_exceptional */
break;
}
+
switch (code)
{
/* tcc_constant cases. */
- case VOID_CST: return TS_TYPED;
+ case COMPLEX_CST: return TS_COMPLEX;
+ case FIXED_CST: return TS_FIXED_CST;
case INTEGER_CST: return TS_INT_CST;
case POLY_INT_CST: return TS_POLY_INT_CST;
case REAL_CST: return TS_REAL_CST;
- case FIXED_CST: return TS_FIXED_CST;
- case COMPLEX_CST: return TS_COMPLEX;
- case VECTOR_CST: return TS_VECTOR;
case STRING_CST: return TS_STRING;
+ case VECTOR_CST: return TS_VECTOR;
+ case VOID_CST: return TS_TYPED;
+
/* tcc_exceptional cases. */
- case ERROR_MARK: return TS_COMMON;
- case IDENTIFIER_NODE: return TS_IDENTIFIER;
- case TREE_LIST: return TS_LIST;
- case TREE_VEC: return TS_VEC;
- case SSA_NAME: return TS_SSA_NAME;
- case PLACEHOLDER_EXPR: return TS_COMMON;
- case STATEMENT_LIST: return TS_STATEMENT_LIST;
case BLOCK: return TS_BLOCK;
case CONSTRUCTOR: return TS_CONSTRUCTOR;
- case TREE_BINFO: return TS_BINFO;
+ case ERROR_MARK: return TS_COMMON;
+ case IDENTIFIER_NODE: return TS_IDENTIFIER;
case OMP_CLAUSE: return TS_OMP_CLAUSE;
case OPTIMIZATION_NODE: return TS_OPTIMIZATION;
+ case PLACEHOLDER_EXPR: return TS_COMMON;
+ case SSA_NAME: return TS_SSA_NAME;
+ case STATEMENT_LIST: return TS_STATEMENT_LIST;
case TARGET_OPTION_NODE: return TS_TARGET_OPTION;
+ case TREE_BINFO: return TS_BINFO;
+ case TREE_LIST: return TS_LIST;
+ case TREE_VEC: return TS_VEC;
default:
gcc_unreachable ();
vec_free (BLOCK_NONLOCALIZED_VARS (node));
else if (code == TREE_BINFO)
vec_free (BINFO_BASE_ACCESSES (node));
+ else if (code == OPTIMIZATION_NODE)
+ cl_optimization_option_free (TREE_OPTIMIZATION (node));
+ else if (code == TARGET_OPTION_NODE)
+ cl_target_option_free (TREE_TARGET_OPTION (node));
ggc_free (node);
}
\f
if (TYPE_SIGN (type) == UNSIGNED)
{
/* Cache [0, N). */
- limit = INTEGER_SHARE_LIMIT;
- if (IN_RANGE (hwi, 0, INTEGER_SHARE_LIMIT - 1))
+ limit = param_integer_share_limit;
+ if (IN_RANGE (hwi, 0, param_integer_share_limit - 1))
ix = hwi;
}
else
{
/* Cache [-1, N). */
- limit = INTEGER_SHARE_LIMIT + 1;
- if (IN_RANGE (hwi, -1, INTEGER_SHARE_LIMIT - 1))
+ limit = param_integer_share_limit + 1;
+ if (IN_RANGE (hwi, -1, param_integer_share_limit - 1))
ix = hwi + 1;
}
break;
if (TYPE_UNSIGNED (type))
{
/* Cache 0..N */
- limit = INTEGER_SHARE_LIMIT;
+ limit = param_integer_share_limit;
/* This is a little hokie, but if the prec is smaller than
- what is necessary to hold INTEGER_SHARE_LIMIT, then the
+ what is necessary to hold param_integer_share_limit, then the
obvious test will not get the correct answer. */
if (prec < HOST_BITS_PER_WIDE_INT)
{
- if (tree_to_uhwi (t) < (unsigned HOST_WIDE_INT) INTEGER_SHARE_LIMIT)
+ if (tree_to_uhwi (t)
+ < (unsigned HOST_WIDE_INT) param_integer_share_limit)
ix = tree_to_uhwi (t);
}
- else if (wi::ltu_p (wi::to_wide (t), INTEGER_SHARE_LIMIT))
+ else if (wi::ltu_p (wi::to_wide (t), param_integer_share_limit))
ix = tree_to_uhwi (t);
}
else
{
/* Cache -1..N */
- limit = INTEGER_SHARE_LIMIT + 1;
+ limit = param_integer_share_limit + 1;
if (integer_minus_onep (t))
ix = 0;
{
if (prec < HOST_BITS_PER_WIDE_INT)
{
- if (tree_to_shwi (t) < INTEGER_SHARE_LIMIT)
+ if (tree_to_shwi (t) < param_integer_share_limit)
ix = tree_to_shwi (t) + 1;
}
- else if (wi::ltu_p (wi::to_wide (t), INTEGER_SHARE_LIMIT))
+ else if (wi::ltu_p (wi::to_wide (t), param_integer_share_limit))
ix = tree_to_shwi (t) + 1;
}
}
tree
build_vector_from_ctor (tree type, vec<constructor_elt, va_gc> *v)
{
+ if (vec_safe_length (v) == 0)
+ return build_zero_cst (type);
+
unsigned HOST_WIDE_INT idx, nelts;
tree value;
return v.build ();
}
+/* Return a VECTOR_CST of type VEC_TYPE in which the first NUM_A
+ elements are A and the rest are B. */
+
+tree
+build_vector_a_then_b (tree vec_type, unsigned int num_a, tree a, tree b)
+{
+ gcc_assert (known_le (num_a, TYPE_VECTOR_SUBPARTS (vec_type)));
+ unsigned int count = constant_lower_bound (TYPE_VECTOR_SUBPARTS (vec_type));
+ /* Optimize the constant case. */
+ if ((count & 1) == 0 && TYPE_VECTOR_SUBPARTS (vec_type).is_constant ())
+ count /= 2;
+ tree_vector_builder builder (vec_type, count, 2);
+ for (unsigned int i = 0; i < count * 2; ++i)
+ builder.quick_push (i < num_a ? a : b);
+ return builder.build ();
+}
+
/* Something has messed with the elements of CONSTRUCTOR C after it was built;
calculate TREE_CONSTANT and TREE_SIDE_EFFECTS. */
return t;
}
+/* Returns the last FIELD_DECL in the TYPE_FIELDS of the RECORD_TYPE or
+ UNION_TYPE TYPE, or NULL_TREE if none. */
+
+tree
+last_field (const_tree type)
+{
+ tree last = NULL_TREE;
+
+ for (tree fld = TYPE_FIELDS (type); fld; fld = TREE_CHAIN (fld))
+ {
+ if (TREE_CODE (fld) != FIELD_DECL)
+ continue;
+
+ last = fld;
+ }
+
+ return last;
+}
+
/* Concatenate two chains of nodes (chained through TREE_CHAIN)
by modifying the last node in chain 1 to point to chain 2.
This is the Lisp primitive `nconc'. */
TYPE_TYPELESS_STORAGE (copy) = 0;
TYPE_FIELDS (copy) = NULL;
TYPE_BINFO (copy) = NULL;
+ TYPE_FINAL_P (copy) = 0;
+ TYPE_EMPTY_P (copy) = 0;
}
else
- TYPE_VALUES (copy) = NULL;
+ {
+ TYPE_VALUES (copy) = NULL;
+ ENUM_IS_OPAQUE (copy) = 0;
+ ENUM_IS_SCOPED (copy) = 0;
+ }
/* Build copy of TYPE_DECL in TYPE_NAME if necessary.
This is needed for ODR violation warnings to come out right (we
BINFO_INHERITANCE_CHAIN (binfo) = NULL_TREE;
BINFO_SUBVTT_INDEX (binfo) = NULL_TREE;
BINFO_VPTR_FIELD (binfo) = NULL_TREE;
+ TREE_PUBLIC (binfo) = 0;
FOR_EACH_VEC_ELT (*BINFO_BASE_BINFOS (binfo), i, t)
free_lang_data_in_binfo (t);
free_lang_data_in_binfo (TYPE_BINFO (type));
/* We need to preserve link to bases and virtual table for all
polymorphic types to make devirtualization machinery working. */
- if (!BINFO_VTABLE (TYPE_BINFO (type))
- || !flag_devirtualize)
+ if (!BINFO_VTABLE (TYPE_BINFO (type)))
TYPE_BINFO (type) = NULL;
}
}
{
if (TREE_CODE (type) == ENUMERAL_TYPE)
{
+ ENUM_IS_OPAQUE (type) = 0;
+ ENUM_IS_SCOPED (type) = 0;
/* Type values are used only for C++ ODR checking. Drop them
for all type variants and non-ODR types.
For ODR types the data is freed in free_odr_warning_data. */
while (*nextp)
{
tree var = *nextp;
- if (fndecl_built_in_p (var))
+ if (TREE_CODE (var) == FUNCTION_DECL
+ && fndecl_built_in_p (var))
*nextp = TREE_CHAIN (var);
else
nextp = &TREE_CHAIN (var);
{
for (tree *tem = &BLOCK_VARS (t); *tem; )
{
- if (TREE_CODE (*tem) != VAR_DECL
- || !auto_var_in_fn_p (*tem, DECL_CONTEXT (*tem)))
+ if (TREE_CODE (*tem) != LABEL_DECL
+ && (TREE_CODE (*tem) != VAR_DECL
+ || !auto_var_in_fn_p (*tem, DECL_CONTEXT (*tem))))
{
gcc_assert (TREE_CODE (*tem) != RESULT_DECL
&& TREE_CODE (*tem) != PARM_DECL);
{
tree arg = gimple_op (stmt, i);
find_decls_types (arg, fld);
+ /* find_decls_types doesn't walk TREE_PURPOSE of TREE_LISTs,
+ which we need for asm stmts. */
+ if (arg
+ && TREE_CODE (arg) == TREE_LIST
+ && TREE_PURPOSE (arg)
+ && gimple_code (stmt) == GIMPLE_ASM)
+ find_decls_types (TREE_PURPOSE (arg), fld);
}
}
}
}
}
-namespace inchash
-{
-
-/* Generate a hash value for an expression. This can be used iteratively
- by passing a previous result as the HSTATE argument.
-
- This function is intended to produce the same hash for expressions which
- would compare equal using operand_equal_p. */
-void
-add_expr (const_tree t, inchash::hash &hstate, unsigned int flags)
-{
- int i;
- enum tree_code code;
- enum tree_code_class tclass;
-
- if (t == NULL_TREE || t == error_mark_node)
- {
- hstate.merge_hash (0);
- return;
- }
-
- STRIP_ANY_LOCATION_WRAPPER (t);
-
- if (!(flags & OEP_ADDRESS_OF))
- STRIP_NOPS (t);
-
- code = TREE_CODE (t);
-
- switch (code)
- {
- /* Alas, constants aren't shared, so we can't rely on pointer
- identity. */
- case VOID_CST:
- hstate.merge_hash (0);
- return;
- case INTEGER_CST:
- gcc_checking_assert (!(flags & OEP_ADDRESS_OF));
- for (i = 0; i < TREE_INT_CST_EXT_NUNITS (t); i++)
- hstate.add_hwi (TREE_INT_CST_ELT (t, i));
- return;
- case REAL_CST:
- {
- unsigned int val2;
- if (!HONOR_SIGNED_ZEROS (t) && real_zerop (t))
- val2 = rvc_zero;
- else
- val2 = real_hash (TREE_REAL_CST_PTR (t));
- hstate.merge_hash (val2);
- return;
- }
- case FIXED_CST:
- {
- unsigned int val2 = fixed_hash (TREE_FIXED_CST_PTR (t));
- hstate.merge_hash (val2);
- return;
- }
- case STRING_CST:
- hstate.add ((const void *) TREE_STRING_POINTER (t),
- TREE_STRING_LENGTH (t));
- return;
- case COMPLEX_CST:
- inchash::add_expr (TREE_REALPART (t), hstate, flags);
- inchash::add_expr (TREE_IMAGPART (t), hstate, flags);
- return;
- case VECTOR_CST:
- {
- hstate.add_int (VECTOR_CST_NPATTERNS (t));
- hstate.add_int (VECTOR_CST_NELTS_PER_PATTERN (t));
- unsigned int count = vector_cst_encoded_nelts (t);
- for (unsigned int i = 0; i < count; ++i)
- inchash::add_expr (VECTOR_CST_ENCODED_ELT (t, i), hstate, flags);
- return;
- }
- case SSA_NAME:
- /* We can just compare by pointer. */
- hstate.add_hwi (SSA_NAME_VERSION (t));
- return;
- case PLACEHOLDER_EXPR:
- /* The node itself doesn't matter. */
- return;
- case BLOCK:
- case OMP_CLAUSE:
- /* Ignore. */
- return;
- case TREE_LIST:
- /* A list of expressions, for a CALL_EXPR or as the elements of a
- VECTOR_CST. */
- for (; t; t = TREE_CHAIN (t))
- inchash::add_expr (TREE_VALUE (t), hstate, flags);
- return;
- case CONSTRUCTOR:
- {
- unsigned HOST_WIDE_INT idx;
- tree field, value;
- flags &= ~OEP_ADDRESS_OF;
- FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (t), idx, field, value)
- {
- inchash::add_expr (field, hstate, flags);
- inchash::add_expr (value, hstate, flags);
- }
- return;
- }
- case STATEMENT_LIST:
- {
- tree_stmt_iterator i;
- for (i = tsi_start (CONST_CAST_TREE (t));
- !tsi_end_p (i); tsi_next (&i))
- inchash::add_expr (tsi_stmt (i), hstate, flags);
- return;
- }
- case TREE_VEC:
- for (i = 0; i < TREE_VEC_LENGTH (t); ++i)
- inchash::add_expr (TREE_VEC_ELT (t, i), hstate, flags);
- return;
- case IDENTIFIER_NODE:
- hstate.add_object (IDENTIFIER_HASH_VALUE (t));
- return;
- case FUNCTION_DECL:
- /* When referring to a built-in FUNCTION_DECL, use the __builtin__ form.
- Otherwise nodes that compare equal according to operand_equal_p might
- get different hash codes. However, don't do this for machine specific
- or front end builtins, since the function code is overloaded in those
- cases. */
- if (DECL_BUILT_IN_CLASS (t) == BUILT_IN_NORMAL
- && builtin_decl_explicit_p (DECL_FUNCTION_CODE (t)))
- {
- t = builtin_decl_explicit (DECL_FUNCTION_CODE (t));
- code = TREE_CODE (t);
- }
- /* FALL THROUGH */
- default:
- if (POLY_INT_CST_P (t))
- {
- for (unsigned int i = 0; i < NUM_POLY_INT_COEFFS; ++i)
- hstate.add_wide_int (wi::to_wide (POLY_INT_CST_COEFF (t, i)));
- return;
- }
- tclass = TREE_CODE_CLASS (code);
-
- if (tclass == tcc_declaration)
- {
- /* DECL's have a unique ID */
- hstate.add_hwi (DECL_UID (t));
- }
- else if (tclass == tcc_comparison && !commutative_tree_code (code))
- {
- /* For comparisons that can be swapped, use the lower
- tree code. */
- enum tree_code ccode = swap_tree_comparison (code);
- if (code < ccode)
- ccode = code;
- hstate.add_object (ccode);
- inchash::add_expr (TREE_OPERAND (t, ccode != code), hstate, flags);
- inchash::add_expr (TREE_OPERAND (t, ccode == code), hstate, flags);
- }
- else if (CONVERT_EXPR_CODE_P (code))
- {
- /* NOP_EXPR and CONVERT_EXPR are considered equal by
- operand_equal_p. */
- enum tree_code ccode = NOP_EXPR;
- hstate.add_object (ccode);
-
- /* Don't hash the type, that can lead to having nodes which
- compare equal according to operand_equal_p, but which
- have different hash codes. Make sure to include signedness
- in the hash computation. */
- hstate.add_int (TYPE_UNSIGNED (TREE_TYPE (t)));
- inchash::add_expr (TREE_OPERAND (t, 0), hstate, flags);
- }
- /* For OEP_ADDRESS_OF, hash MEM_EXPR[&decl, 0] the same as decl. */
- else if (code == MEM_REF
- && (flags & OEP_ADDRESS_OF) != 0
- && TREE_CODE (TREE_OPERAND (t, 0)) == ADDR_EXPR
- && DECL_P (TREE_OPERAND (TREE_OPERAND (t, 0), 0))
- && integer_zerop (TREE_OPERAND (t, 1)))
- inchash::add_expr (TREE_OPERAND (TREE_OPERAND (t, 0), 0),
- hstate, flags);
- /* Don't ICE on FE specific trees, or their arguments etc.
- during operand_equal_p hash verification. */
- else if (!IS_EXPR_CODE_CLASS (tclass))
- gcc_assert (flags & OEP_HASH_CHECK);
- else
- {
- unsigned int sflags = flags;
-
- hstate.add_object (code);
-
- switch (code)
- {
- case ADDR_EXPR:
- gcc_checking_assert (!(flags & OEP_ADDRESS_OF));
- flags |= OEP_ADDRESS_OF;
- sflags = flags;
- break;
-
- case INDIRECT_REF:
- case MEM_REF:
- case TARGET_MEM_REF:
- flags &= ~OEP_ADDRESS_OF;
- sflags = flags;
- break;
-
- case ARRAY_REF:
- case ARRAY_RANGE_REF:
- case COMPONENT_REF:
- case BIT_FIELD_REF:
- sflags &= ~OEP_ADDRESS_OF;
- break;
-
- case COND_EXPR:
- flags &= ~OEP_ADDRESS_OF;
- break;
-
- case WIDEN_MULT_PLUS_EXPR:
- case WIDEN_MULT_MINUS_EXPR:
- {
- /* The multiplication operands are commutative. */
- inchash::hash one, two;
- inchash::add_expr (TREE_OPERAND (t, 0), one, flags);
- inchash::add_expr (TREE_OPERAND (t, 1), two, flags);
- hstate.add_commutative (one, two);
- inchash::add_expr (TREE_OPERAND (t, 2), two, flags);
- return;
- }
-
- case CALL_EXPR:
- if (CALL_EXPR_FN (t) == NULL_TREE)
- hstate.add_int (CALL_EXPR_IFN (t));
- break;
-
- case TARGET_EXPR:
- /* For TARGET_EXPR, just hash on the TARGET_EXPR_SLOT.
- Usually different TARGET_EXPRs just should use
- different temporaries in their slots. */
- inchash::add_expr (TARGET_EXPR_SLOT (t), hstate, flags);
- return;
-
- default:
- break;
- }
-
- /* Don't hash the type, that can lead to having nodes which
- compare equal according to operand_equal_p, but which
- have different hash codes. */
- if (code == NON_LVALUE_EXPR)
- {
- /* Make sure to include signness in the hash computation. */
- hstate.add_int (TYPE_UNSIGNED (TREE_TYPE (t)));
- inchash::add_expr (TREE_OPERAND (t, 0), hstate, flags);
- }
-
- else if (commutative_tree_code (code))
- {
- /* It's a commutative expression. We want to hash it the same
- however it appears. We do this by first hashing both operands
- and then rehashing based on the order of their independent
- hashes. */
- inchash::hash one, two;
- inchash::add_expr (TREE_OPERAND (t, 0), one, flags);
- inchash::add_expr (TREE_OPERAND (t, 1), two, flags);
- hstate.add_commutative (one, two);
- }
- else
- for (i = TREE_OPERAND_LENGTH (t) - 1; i >= 0; --i)
- inchash::add_expr (TREE_OPERAND (t, i), hstate,
- i == 0 ? flags : sflags);
- }
- return;
- }
-}
-
-}
-
/* Constructors for pointer, array and function types.
(RECORD_TYPE, UNION_TYPE and ENUMERAL_TYPE nodes are
constructed by language-dependent code, not here.) */
{
unsigned j = indices[i];
fprintf (stderr, "%-20s %6" PRIu64 "%c %9" PRIu64 "%c\n",
- tree_node_kind_names[i], SIZE_AMOUNT (tree_node_counts[j]),
+ tree_node_kind_names[j], SIZE_AMOUNT (tree_node_counts[j]),
SIZE_AMOUNT (tree_node_sizes[j]));
total_nodes += tree_node_counts[j];
total_bytes += tree_node_sizes[j];
uint64_type_node = make_or_reuse_type (64, 1);
/* Decimal float types. */
- dfloat32_type_node = make_node (REAL_TYPE);
- TYPE_PRECISION (dfloat32_type_node) = DECIMAL32_TYPE_SIZE;
- SET_TYPE_MODE (dfloat32_type_node, SDmode);
- layout_type (dfloat32_type_node);
- dfloat32_ptr_type_node = build_pointer_type (dfloat32_type_node);
-
- dfloat64_type_node = make_node (REAL_TYPE);
- TYPE_PRECISION (dfloat64_type_node) = DECIMAL64_TYPE_SIZE;
- SET_TYPE_MODE (dfloat64_type_node, DDmode);
- layout_type (dfloat64_type_node);
- dfloat64_ptr_type_node = build_pointer_type (dfloat64_type_node);
-
- dfloat128_type_node = make_node (REAL_TYPE);
- TYPE_PRECISION (dfloat128_type_node) = DECIMAL128_TYPE_SIZE;
- SET_TYPE_MODE (dfloat128_type_node, TDmode);
- layout_type (dfloat128_type_node);
- dfloat128_ptr_type_node = build_pointer_type (dfloat128_type_node);
+ if (targetm.decimal_float_supported_p ())
+ {
+ dfloat32_type_node = make_node (REAL_TYPE);
+ TYPE_PRECISION (dfloat32_type_node) = DECIMAL32_TYPE_SIZE;
+ SET_TYPE_MODE (dfloat32_type_node, SDmode);
+ layout_type (dfloat32_type_node);
+
+ dfloat64_type_node = make_node (REAL_TYPE);
+ TYPE_PRECISION (dfloat64_type_node) = DECIMAL64_TYPE_SIZE;
+ SET_TYPE_MODE (dfloat64_type_node, DDmode);
+ layout_type (dfloat64_type_node);
+
+ dfloat128_type_node = make_node (REAL_TYPE);
+ TYPE_PRECISION (dfloat128_type_node) = DECIMAL128_TYPE_SIZE;
+ SET_TYPE_MODE (dfloat128_type_node, TDmode);
+ layout_type (dfloat128_type_node);
+ }
complex_integer_type_node = build_complex_type (integer_type_node, true);
complex_float_type_node = build_complex_type (float_type_node, true);
return make_vector_type (innertype, nunits, VOIDmode);
}
-/* Build truth vector with specified length and number of units. */
+/* Build a truth vector with NUNITS units, giving it mode MASK_MODE. */
tree
-build_truth_vector_type (poly_uint64 nunits, poly_uint64 vector_size)
+build_truth_vector_type_for_mode (poly_uint64 nunits, machine_mode mask_mode)
{
- machine_mode mask_mode
- = targetm.vectorize.get_mask_mode (nunits, vector_size).else_blk ();
-
- poly_uint64 vsize;
- if (mask_mode == BLKmode)
- vsize = vector_size * BITS_PER_UNIT;
- else
- vsize = GET_MODE_BITSIZE (mask_mode);
+ gcc_assert (mask_mode != BLKmode);
+ poly_uint64 vsize = GET_MODE_BITSIZE (mask_mode);
unsigned HOST_WIDE_INT esize = vector_element_size (vsize, nunits);
-
tree bool_type = build_nonstandard_boolean_type (esize);
return make_vector_type (bool_type, nunits, mask_mode);
}
-/* Returns a vector type corresponding to a comparison of VECTYPE. */
+/* Build a vector type that holds one boolean result for each element of
+ vector type VECTYPE. The public interface for this operation is
+ truth_type_for. */
-tree
-build_same_sized_truth_vector_type (tree vectype)
+static tree
+build_truth_vector_type_for (tree vectype)
{
- if (VECTOR_BOOLEAN_TYPE_P (vectype))
- return vectype;
+ machine_mode vector_mode = TYPE_MODE (vectype);
+ poly_uint64 nunits = TYPE_VECTOR_SUBPARTS (vectype);
- poly_uint64 size = GET_MODE_SIZE (TYPE_MODE (vectype));
+ machine_mode mask_mode;
+ if (VECTOR_MODE_P (vector_mode)
+ && targetm.vectorize.get_mask_mode (vector_mode).exists (&mask_mode))
+ return build_truth_vector_type_for_mode (nunits, mask_mode);
- if (known_eq (size, 0U))
- size = tree_to_uhwi (TYPE_SIZE_UNIT (vectype));
+ poly_uint64 vsize = tree_to_poly_uint64 (TYPE_SIZE (vectype));
+ unsigned HOST_WIDE_INT esize = vector_element_size (vsize, nunits);
+ tree bool_type = build_nonstandard_boolean_type (esize);
- return build_truth_vector_type (TYPE_VECTOR_SUBPARTS (vectype), size);
+ return make_vector_type (bool_type, nunits, BLKmode);
}
-/* Similarly, but builds a variant type with TYPE_VECTOR_OPAQUE set. */
+/* Like build_vector_type, but builds a variant type with TYPE_VECTOR_OPAQUE
+ set. */
tree
build_opaque_vector_type (tree innertype, poly_int64 nunits)
}
}
-/* Create a new constant string literal consisting of elements of type
- ELTYPE and return a tree node representing char* pointer to it as
- an ADDR_EXPR (ARRAY_REF (ELTYPE, ...)). The STRING_CST value is
- the LEN bytes at STR (the representation of the string, which may
+/* Create a new constant string literal of type ELTYPE[SIZE] (or LEN
+ if SIZE == -1) and return a tree node representing char* pointer to
+ it as an ADDR_EXPR (ARRAY_REF (ELTYPE, ...)). The STRING_CST value
+ is the LEN bytes at STR (the representation of the string, which may
be wide). */
tree
build_string_literal (int len, const char *str,
- tree eltype /* = char_type_node */)
+ tree eltype /* = char_type_node */,
+ unsigned HOST_WIDE_INT size /* = -1 */)
{
tree t = build_string (len, str);
- tree index = build_index_type (size_int (len - 1));
+ /* Set the maximum valid index based on the string length or SIZE. */
+ unsigned HOST_WIDE_INT maxidx
+ = (size == HOST_WIDE_INT_M1U ? len : size) - 1;
+
+ tree index = build_index_type (size_int (maxidx));
eltype = build_type_variant (eltype, 1, 0);
tree type = build_array_type (eltype, index);
TREE_TYPE (t) = type;
{
if (VECTOR_BOOLEAN_TYPE_P (type))
return type;
- return build_truth_vector_type (TYPE_VECTOR_SUBPARTS (type),
- GET_MODE_SIZE (TYPE_MODE (type)));
+ return build_truth_vector_type_for (type);
}
else
return boolean_type_node;
case OMP_CLAUSE_TO_DECLARE:
case OMP_CLAUSE_LINK:
case OMP_CLAUSE_USE_DEVICE_PTR:
+ case OMP_CLAUSE_USE_DEVICE_ADDR:
case OMP_CLAUSE_IS_DEVICE_PTR:
case OMP_CLAUSE_INCLUSIVE:
case OMP_CLAUSE_EXCLUSIVE:
case OMP_CLAUSE_UNTIED:
case OMP_CLAUSE_MERGEABLE:
case OMP_CLAUSE_PROC_BIND:
+ case OMP_CLAUSE_DEVICE_TYPE:
case OMP_CLAUSE_INBRANCH:
case OMP_CLAUSE_NOTINBRANCH:
case OMP_CLAUSE_FOR:
case OMP_CLAUSE_THREADS:
case OMP_CLAUSE_SIMD:
case OMP_CLAUSE_DEFAULTMAP:
+ case OMP_CLAUSE_ORDER:
+ case OMP_CLAUSE_BIND:
case OMP_CLAUSE_AUTO:
case OMP_CLAUSE_SEQ:
case OMP_CLAUSE_TILE:
return is_typedef_decl (TYPE_NAME (type));
}
-/* A class to handle converting a string that might contain
- control characters, (eg newline, form-feed, etc), into one
- in which contains escape sequences instead. */
-
-class escaped_string
-{
- public:
- escaped_string () { m_owned = false; m_str = NULL; };
- ~escaped_string () { if (m_owned) free (m_str); }
- operator const char *() const { return (const char *) m_str; }
- void escape (const char *);
- private:
- char *m_str;
- bool m_owned;
-};
-
/* PR 84195: Replace control characters in "unescaped" with their
escaped equivalents. Allow newlines if -fmessage-length has
been set to a non-zero value. This is done here, rather than
return NULL_TREE;
}
-/* Returns true if REF is an array reference or a component reference
- to an array at the end of a structure.
+/* Returns true if REF is an array reference, component reference,
+ or memory reference to an array at the end of a structure.
If this is the case, the array may be allocated larger
than its upper bound implies. */
else if (TREE_CODE (ref) == COMPONENT_REF
&& TREE_CODE (TREE_TYPE (TREE_OPERAND (ref, 1))) == ARRAY_TYPE)
atype = TREE_TYPE (TREE_OPERAND (ref, 1));
+ else if (TREE_CODE (ref) == MEM_REF)
+ {
+ tree arg = TREE_OPERAND (ref, 0);
+ if (TREE_CODE (arg) == ADDR_EXPR)
+ arg = TREE_OPERAND (arg, 0);
+ tree argtype = TREE_TYPE (arg);
+ if (TREE_CODE (argtype) == RECORD_TYPE)
+ {
+ if (tree fld = last_field (argtype))
+ {
+ atype = TREE_TYPE (fld);
+ if (TREE_CODE (atype) != ARRAY_TYPE)
+ return false;
+ if (VAR_P (arg) && DECL_SIZE (fld))
+ return false;
+ }
+ else
+ return false;
+ }
+ else
+ return false;
+ }
else
return false;
return SUBSTITUTE_PLACEHOLDER_IN_EXPR (DECL_FIELD_OFFSET (field), exp);
}
+/* Given the initializer INIT, return the initializer for the field
+ DECL if it exists, otherwise null. Used to obtain the initializer
+ for a flexible array member and determine its size. */
+
+static tree
+get_initializer_for (tree init, tree decl)
+{
+ STRIP_NOPS (init);
+
+ tree fld, fld_init;
+ unsigned HOST_WIDE_INT i;
+ FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (init), i, fld, fld_init)
+ {
+ if (decl == fld)
+ return fld_init;
+
+ if (TREE_CODE (fld) == CONSTRUCTOR)
+ {
+ fld_init = get_initializer_for (fld_init, decl);
+ if (fld_init)
+ return fld_init;
+ }
+ }
+
+ return NULL_TREE;
+}
+
+/* Determines the size of the member referenced by the COMPONENT_REF
+ REF, using its initializer expression if necessary in order to
+ determine the size of an initialized flexible array member.
+ If non-null, *INTERIOR_ZERO_LENGTH is set when REF refers to
+ an interior zero-length array.
+ Returns the size (which might be zero for an object with
+ an uninitialized flexible array member) or null if the size
+ cannot be determined. */
+
+tree
+component_ref_size (tree ref, bool *interior_zero_length /* = NULL */)
+{
+ gcc_assert (TREE_CODE (ref) == COMPONENT_REF);
+
+ bool int_0_len = false;
+ if (!interior_zero_length)
+ interior_zero_length = &int_0_len;
+
+ tree member = TREE_OPERAND (ref, 1);
+
+ tree memsize = DECL_SIZE_UNIT (member);
+ if (memsize)
+ {
+ tree memtype = TREE_TYPE (member);
+ if (TREE_CODE (memtype) != ARRAY_TYPE)
+ return memsize;
+
+ bool trailing = array_at_struct_end_p (ref);
+ bool zero_length = integer_zerop (memsize);
+ if (!trailing && (!interior_zero_length || !zero_length))
+ /* MEMBER is either an interior array or is an array with
+ more than one element. */
+ return memsize;
+
+ *interior_zero_length = zero_length && !trailing;
+ if (*interior_zero_length)
+ memsize = NULL_TREE;
+
+ if (!zero_length)
+ if (tree dom = TYPE_DOMAIN (memtype))
+ if (tree min = TYPE_MIN_VALUE (dom))
+ if (tree max = TYPE_MAX_VALUE (dom))
+ if (TREE_CODE (min) == INTEGER_CST
+ && TREE_CODE (max) == INTEGER_CST)
+ {
+ offset_int minidx = wi::to_offset (min);
+ offset_int maxidx = wi::to_offset (max);
+ if (maxidx - minidx > 0)
+ /* MEMBER is an array with more than 1 element. */
+ return memsize;
+ }
+ }
+
+ /* MEMBER is either a bona fide flexible array member, or a zero-length
+ array member, or an array of length one treated as such. */
+
+ /* If the reference is to a declared object and the member a true
+ flexible array, try to determine its size from its initializer. */
+ poly_int64 baseoff = 0;
+ tree base = get_addr_base_and_unit_offset (ref, &baseoff);
+ if (!base || !VAR_P (base))
+ {
+ if (!*interior_zero_length)
+ return NULL_TREE;
+
+ if (TREE_CODE (TREE_OPERAND (ref, 0)) != COMPONENT_REF)
+ return NULL_TREE;
+
+ base = TREE_OPERAND (ref, 0);
+ while (TREE_CODE (base) == COMPONENT_REF)
+ base = TREE_OPERAND (base, 0);
+ baseoff = tree_to_poly_int64 (byte_position (TREE_OPERAND (ref, 1)));
+ }
+
+ /* BASE is the declared object of which MEMBER is either a member
+ or that is is cast to REFTYPE (e.g., a char buffer used to store
+ a REFTYPE object). */
+ tree reftype = TREE_TYPE (TREE_OPERAND (ref, 0));
+ tree basetype = TREE_TYPE (base);
+
+ /* Determine the base type of the referenced object. If it's
+ the same as REFTYPE and MEMBER has a known size, return it. */
+ tree bt = basetype;
+ if (!*interior_zero_length)
+ while (TREE_CODE (bt) == ARRAY_TYPE)
+ bt = TREE_TYPE (bt);
+ bool typematch = useless_type_conversion_p (reftype, bt);
+ if (memsize && typematch)
+ return memsize;
+
+ memsize = NULL_TREE;
+
+ if (typematch)
+ /* MEMBER is a true flexible array member. Compute its size from
+ the initializer of the BASE object if it has one. */
+ if (tree init = DECL_P (base) ? DECL_INITIAL (base) : NULL_TREE)
+ {
+ init = get_initializer_for (init, member);
+ if (init)
+ {
+ memsize = TYPE_SIZE_UNIT (TREE_TYPE (init));
+ if (tree refsize = TYPE_SIZE_UNIT (reftype))
+ {
+ /* Use the larger of the initializer size and the tail
+ padding in the enclosing struct. */
+ poly_int64 rsz = tree_to_poly_int64 (refsize);
+ rsz -= baseoff;
+ if (known_lt (tree_to_poly_int64 (memsize), rsz))
+ memsize = wide_int_to_tree (TREE_TYPE (memsize), rsz);
+ }
+
+ baseoff = 0;
+ }
+ }
+
+ if (!memsize)
+ {
+ if (typematch)
+ {
+ if (DECL_P (base)
+ && DECL_EXTERNAL (base)
+ && bt == basetype
+ && !*interior_zero_length)
+ /* The size of a flexible array member of an extern struct
+ with no initializer cannot be determined (it's defined
+ in another translation unit and can have an initializer
+ with an arbitrary number of elements). */
+ return NULL_TREE;
+
+ /* Use the size of the base struct or, for interior zero-length
+ arrays, the size of the enclosing type. */
+ memsize = TYPE_SIZE_UNIT (bt);
+ }
+ else if (DECL_P (base))
+ /* Use the size of the BASE object (possibly an array of some
+ other type such as char used to store the struct). */
+ memsize = DECL_SIZE_UNIT (base);
+ else
+ return NULL_TREE;
+ }
+
+ /* If the flexible array member has a known size use the greater
+ of it and the tail padding in the enclosing struct.
+ Otherwise, when the size of the flexible array member is unknown
+ and the referenced object is not a struct, use the size of its
+ type when known. This detects sizes of array buffers when cast
+ to struct types with flexible array members. */
+ if (memsize)
+ {
+ poly_int64 memsz64 = memsize ? tree_to_poly_int64 (memsize) : 0;
+ if (known_lt (baseoff, memsz64))
+ {
+ memsz64 -= baseoff;
+ return wide_int_to_tree (TREE_TYPE (memsize), memsz64);
+ }
+ return integer_zero_node;
+ }
+
+ /* Return "don't know" for an external non-array object since its
+ flexible array member can be initialized to have any number of
+ elements. Otherwise, return zero because the flexible array
+ member has no elements. */
+ return (DECL_P (base)
+ && DECL_EXTERNAL (base)
+ && (!typematch
+ || TREE_CODE (basetype) != ARRAY_TYPE)
+ ? NULL_TREE : integer_zero_node);
+}
+
/* Return the machine mode of T. For vectors, returns the mode of the
inner type. The main use case is to feed the result to HONOR_NANS,
avoiding the BLKmode that a direct TYPE_MODE (T) might return. */
return default_is_empty_type (TYPE_MAIN_VARIANT (type));
}
+/* Determine whether TYPE is a structure with a flexible array member,
+ or a union containing such a structure (possibly recursively). */
+
+bool
+flexible_array_type_p (const_tree type)
+{
+ tree x, last;
+ switch (TREE_CODE (type))
+ {
+ case RECORD_TYPE:
+ last = NULL_TREE;
+ for (x = TYPE_FIELDS (type); x != NULL_TREE; x = DECL_CHAIN (x))
+ if (TREE_CODE (x) == FIELD_DECL)
+ last = x;
+ if (last == NULL_TREE)
+ return false;
+ if (TREE_CODE (TREE_TYPE (last)) == ARRAY_TYPE
+ && TYPE_SIZE (TREE_TYPE (last)) == NULL_TREE
+ && TYPE_DOMAIN (TREE_TYPE (last)) != NULL_TREE
+ && TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (last))) == NULL_TREE)
+ return true;
+ return false;
+ case UNION_TYPE:
+ for (x = TYPE_FIELDS (type); x != NULL_TREE; x = DECL_CHAIN (x))
+ {
+ if (TREE_CODE (x) == FIELD_DECL
+ && flexible_array_type_p (TREE_TYPE (x)))
+ return true;
+ }
+ return false;
+ default:
+ return false;
+ }
+}
+
/* Like int_size_in_bytes, but handle empty records specially. */
HOST_WIDE_INT
return TYPE_MAX_VALUE (ptrdiff_type_node);
}
+/* A wrapper around TARGET_VERIFY_TYPE_CONTEXT that makes the silent_p
+ parameter default to false and that weeds out error_mark_node. */
+
+bool
+verify_type_context (location_t loc, type_context_kind context,
+ const_tree type, bool silent_p)
+{
+ if (type == error_mark_node)
+ return true;
+
+ gcc_assert (TYPE_P (type));
+ return (!targetm.verify_type_context
+ || targetm.verify_type_context (loc, context, type, silent_p));
+}
+
#if CHECKING_P
namespace selftest {