/* Gimple IR support functions.
- Copyright 2007, 2008, 2009 Free Software Foundation, Inc.
+ Copyright 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
Contributed by Aldy Hernandez <aldyh@redhat.com>
This file is part of GCC.
/* Build a tuple with operands. CODE is the statement to build (which
must be one of the GIMPLE_WITH_OPS tuples). SUBCODE is the sub-code
- for the new tuple. NUM_OPS is the number of operands to allocate. */
+ for the new tuple. NUM_OPS is the number of operands to allocate. */
#define gimple_build_with_ops(c, s, n) \
gimple_build_with_ops_stat (c, s, n MEM_STAT_INFO)
return s;
}
+/* Reset alias information on call S. */
+
+void
+gimple_call_reset_alias_info (gimple s)
+{
+ if (gimple_call_flags (s) & ECF_CONST)
+ memset (gimple_call_use_set (s), 0, sizeof (struct pt_solution));
+ else
+ pt_solution_reset (gimple_call_use_set (s));
+ if (gimple_call_flags (s) & (ECF_CONST|ECF_PURE|ECF_NOVOPS))
+ memset (gimple_call_clobber_set (s), 0, sizeof (struct pt_solution));
+ else
+ pt_solution_reset (gimple_call_clobber_set (s));
+}
+
/* Helper for gimple_build_call, gimple_build_call_vec and
gimple_build_call_from_tree. Build the basic components of a
GIMPLE_CALL statement to function FN with NARGS arguments. */
if (TREE_CODE (fn) == FUNCTION_DECL)
fn = build_fold_addr_expr (fn);
gimple_set_op (s, 1, fn);
+ gimple_call_reset_alias_info (s);
return s;
}
gimple_call_set_return_slot_opt (call, CALL_EXPR_RETURN_SLOT_OPT (t));
gimple_call_set_from_thunk (call, CALL_FROM_THUNK_P (t));
gimple_call_set_va_arg_pack (call, CALL_EXPR_VA_ARG_PACK (t));
+ gimple_call_set_nothrow (call, TREE_NOTHROW (t));
gimple_set_no_warning (call, TREE_NO_WARNING (t));
return call;
/* Need 1 operand for LHS and 1 or 2 for the RHS (depending on the
code). */
num_ops = get_gimple_rhs_num_ops (subcode) + 1;
-
+
p = gimple_build_with_ops_stat (GIMPLE_ASSIGN, (unsigned)subcode, num_ops
PASS_MEM_STAT);
gimple_assign_set_lhs (p, lhs);
gimple
gimplify_assign (tree dst, tree src, gimple_seq *seq_p)
-{
+{
tree t = build2 (MODIFY_EXPR, TREE_TYPE (dst), dst, src);
gimplify_and_add (t, seq_p);
ggc_free (t);
/* Build a GIMPLE_NOP statement. */
-gimple
+gimple
gimple_build_nop (void)
{
return gimple_alloc (GIMPLE_NOP, 0);
*/
static inline gimple
-gimple_build_asm_1 (const char *string, unsigned ninputs, unsigned noutputs,
+gimple_build_asm_1 (const char *string, unsigned ninputs, unsigned noutputs,
unsigned nclobbers, unsigned nlabels)
{
gimple p;
#ifdef GATHER_STATISTICS
gimple_alloc_sizes[(int) gimple_alloc_kind (GIMPLE_ASM)] += size;
#endif
-
+
return p;
}
LABELS is a vector of destination labels. */
gimple
-gimple_build_asm_vec (const char *string, VEC(tree,gc)* inputs,
+gimple_build_asm_vec (const char *string, VEC(tree,gc)* inputs,
VEC(tree,gc)* outputs, VEC(tree,gc)* clobbers,
VEC(tree,gc)* labels)
{
p = gimple_build_asm_1 (string,
VEC_length (tree, inputs),
- VEC_length (tree, outputs),
+ VEC_length (tree, outputs),
VEC_length (tree, clobbers),
VEC_length (tree, labels));
-
+
for (i = 0; i < VEC_length (tree, inputs); i++)
gimple_asm_set_input_op (p, i, VEC_index (tree, inputs, i));
for (i = 0; i < VEC_length (tree, clobbers); i++)
gimple_asm_set_clobber_op (p, i, VEC_index (tree, clobbers, i));
-
+
for (i = 0; i < VEC_length (tree, labels); i++)
gimple_asm_set_label_op (p, i, VEC_index (tree, labels, i));
-
+
return p;
}
gimple
gimple_build_eh_must_not_throw (tree decl)
{
- gimple p = gimple_alloc (GIMPLE_EH_MUST_NOT_THROW, 1);
+ gimple p = gimple_alloc (GIMPLE_EH_MUST_NOT_THROW, 0);
gcc_assert (TREE_CODE (decl) == FUNCTION_DECL);
gcc_assert (flags_from_decl_or_type (decl) & ECF_NORETURN);
NLABELS is the number of labels in the switch excluding the default.
DEFAULT_LABEL is the default label for the switch statement. */
-gimple
+gimple
gimple_build_switch_nlabels (unsigned nlabels, tree index, tree default_label)
{
/* nlabels + 1 default label + 1 index. */
/* Build a GIMPLE_SWITCH statement.
INDEX is the switch's index.
- NLABELS is the number of labels in the switch excluding the DEFAULT_LABEL.
+ NLABELS is the number of labels in the switch excluding the DEFAULT_LABEL.
... are the labels excluding the default. */
-gimple
+gimple
gimple_build_switch (unsigned nlabels, tree index, tree default_label, ...)
{
va_list al;
BODY is the sequence of statements for which only one thread can execute.
NAME is optional identifier for this critical block. */
-gimple
+gimple
gimple_build_omp_critical (gimple_seq body, tree name)
{
gimple p = gimple_alloc (GIMPLE_OMP_CRITICAL, 0);
/* Build a GIMPLE_OMP_FOR statement.
BODY is sequence of statements inside the for loop.
- CLAUSES, are any of the OMP loop construct's clauses: private, firstprivate,
+ CLAUSES, are any of the OMP loop construct's clauses: private, firstprivate,
lastprivate, reductions, ordered, schedule, and nowait.
COLLAPSE is the collapse count.
PRE_BODY is the sequence of statements that are loop invariant. */
CHILD_FN is the function created for the parallel threads to execute.
DATA_ARG are the shared data argument(s). */
-gimple
-gimple_build_omp_parallel (gimple_seq body, tree clauses, tree child_fn,
+gimple
+gimple_build_omp_parallel (gimple_seq body, tree clauses, tree child_fn,
tree data_arg)
{
gimple p = gimple_alloc (GIMPLE_OMP_PARALLEL, 0);
COPY_FN is the optional function for firstprivate initialization.
ARG_SIZE and ARG_ALIGN are size and alignment of the data block. */
-gimple
+gimple
gimple_build_omp_task (gimple_seq body, tree clauses, tree child_fn,
tree data_arg, tree copy_fn, tree arg_size,
tree arg_align)
BODY is the sequence of statements to be executed by just the master. */
-gimple
+gimple
gimple_build_omp_master (gimple_seq body)
{
gimple p = gimple_alloc (GIMPLE_OMP_MASTER, 0);
CONTROL_DEF is the definition of the control variable.
CONTROL_USE is the use of the control variable. */
-gimple
+gimple
gimple_build_omp_continue (tree control_def, tree control_use)
{
gimple p = gimple_alloc (GIMPLE_OMP_CONTINUE, 0);
BODY is the sequence of statements inside a loop that will executed in
sequence. */
-gimple
+gimple
gimple_build_omp_ordered (gimple_seq body)
{
gimple p = gimple_alloc (GIMPLE_OMP_ORDERED, 0);
/* Build a GIMPLE_OMP_RETURN statement.
WAIT_P is true if this is a non-waiting return. */
-gimple
+gimple
gimple_build_omp_return (bool wait_p)
{
gimple p = gimple_alloc (GIMPLE_OMP_RETURN, 0);
CLAUSES are any of the OMP sections contsruct's clauses: private,
firstprivate, lastprivate, reduction, and nowait. */
-gimple
+gimple
gimple_build_omp_sections (gimple_seq body, tree clauses)
{
gimple p = gimple_alloc (GIMPLE_OMP_SECTIONS, 0);
CLAUSES are any of the OMP single construct's clauses: private, firstprivate,
copyprivate, nowait. */
-gimple
+gimple
gimple_build_omp_single (gimple_seq body, tree clauses)
{
gimple p = gimple_alloc (GIMPLE_OMP_SINGLE, 0);
/* If this triggers, it's a sign that the same list is being freed
twice. */
gcc_assert (seq != gimple_seq_cache || gimple_seq_cache == NULL);
-
+
/* Add SEQ to the pool of free sequences. */
seq->next_free = gimple_seq_cache;
gimple_seq_cache = seq;
/* Walk all the statements in the sequence SEQ calling walk_gimple_stmt
on each one. WI is as in walk_gimple_stmt.
-
+
If walk_gimple_stmt returns non-NULL, the walk is stopped, the
value is stored in WI->CALLBACK_RESULT and the statement that
produced the value is returned.
The return value is that returned by the last call to walk_tree, or
NULL_TREE if no CALLBACK_OP is specified. */
-inline tree
+tree
walk_gimple_op (gimple stmt, walk_tree_fn callback_op,
struct walk_stmt_info *wi)
{
switch (gimple_code (stmt))
{
case GIMPLE_ASSIGN:
- /* Walk the RHS operands. A formal temporary LHS may use a
- COMPONENT_REF RHS. */
+ /* Walk the RHS operands. If the LHS is of a non-renamable type or
+ is a register variable, we may use a COMPONENT_REF on the RHS. */
if (wi)
- wi->val_only = !is_gimple_reg (gimple_assign_lhs (stmt))
- || !gimple_assign_single_p (stmt);
+ {
+ tree lhs = gimple_assign_lhs (stmt);
+ wi->val_only
+ = (is_gimple_reg_type (TREE_TYPE (lhs)) && !is_gimple_reg (lhs))
+ || !gimple_assign_single_p (stmt);
+ }
for (i = 1; i < gimple_num_ops (stmt); i++)
{
flags = 0;
}
+ if (stmt->gsbase.subcode & GF_CALL_NOTHROW)
+ flags |= ECF_NOTHROW;
+
return flags;
}
+/* Detects argument flags for argument number ARG on call STMT. */
+
+int
+gimple_call_arg_flags (const_gimple stmt, unsigned arg)
+{
+ tree type = TREE_TYPE (TREE_TYPE (gimple_call_fn (stmt)));
+ tree attr = lookup_attribute ("fn spec", TYPE_ATTRIBUTES (type));
+ if (!attr)
+ return 0;
+
+ attr = TREE_VALUE (TREE_VALUE (attr));
+ if (1 + arg >= (unsigned) TREE_STRING_LENGTH (attr))
+ return 0;
+
+ switch (TREE_STRING_POINTER (attr)[1 + arg])
+ {
+ case 'x':
+ case 'X':
+ return EAF_UNUSED;
+
+ case 'R':
+ return EAF_DIRECT | EAF_NOCLOBBER | EAF_NOESCAPE;
+
+ case 'r':
+ return EAF_NOCLOBBER | EAF_NOESCAPE;
+
+ case 'W':
+ return EAF_DIRECT | EAF_NOESCAPE;
+
+ case 'w':
+ return EAF_NOESCAPE;
+
+ case '.':
+ default:
+ return 0;
+ }
+}
+
+/* Detects return flags for the call STMT. */
+
+int
+gimple_call_return_flags (const_gimple stmt)
+{
+ tree type;
+ tree attr = NULL_TREE;
+
+ if (gimple_call_flags (stmt) & ECF_MALLOC)
+ return ERF_NOALIAS;
+
+ type = TREE_TYPE (TREE_TYPE (gimple_call_fn (stmt)));
+ attr = lookup_attribute ("fn spec", TYPE_ATTRIBUTES (type));
+ if (!attr)
+ return 0;
+
+ attr = TREE_VALUE (TREE_VALUE (attr));
+ if (TREE_STRING_LENGTH (attr) < 1)
+ return 0;
+
+ switch (TREE_STRING_POINTER (attr)[0])
+ {
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ return ERF_RETURNS_ARG | (TREE_STRING_POINTER (attr)[0] - '1');
+
+ case 'm':
+ return ERF_NOALIAS;
+
+ case '.':
+ default:
+ return 0;
+ }
+}
/* Return true if GS is a copy assignment. */
assignment. I suspect there may be cases where gimple_assign_copy_p,
gimple_assign_single_p, or equivalent logic is used where a similar
treatment of unary NOPs is appropriate. */
-
+
bool
gimple_assign_unary_nop_p (gimple gs)
{
}
-/* Fold the expression computed by STMT. If the expression can be
- folded, return the folded result, otherwise return NULL. STMT is
- not modified. */
-
-tree
-gimple_fold (const_gimple stmt)
-{
- location_t loc = gimple_location (stmt);
- switch (gimple_code (stmt))
- {
- case GIMPLE_COND:
- return fold_binary_loc (loc, gimple_cond_code (stmt),
- boolean_type_node,
- gimple_cond_lhs (stmt),
- gimple_cond_rhs (stmt));
-
- case GIMPLE_ASSIGN:
- switch (get_gimple_rhs_class (gimple_assign_rhs_code (stmt)))
- {
- case GIMPLE_UNARY_RHS:
- return fold_unary_loc (loc, gimple_assign_rhs_code (stmt),
- TREE_TYPE (gimple_assign_lhs (stmt)),
- gimple_assign_rhs1 (stmt));
- case GIMPLE_BINARY_RHS:
- return fold_binary_loc (loc, gimple_assign_rhs_code (stmt),
- TREE_TYPE (gimple_assign_lhs (stmt)),
- gimple_assign_rhs1 (stmt),
- gimple_assign_rhs2 (stmt));
- case GIMPLE_SINGLE_RHS:
- return fold (gimple_assign_rhs1 (stmt));
- default:;
- }
- break;
-
- case GIMPLE_SWITCH:
- return gimple_switch_index (stmt);
-
- case GIMPLE_CALL:
- return NULL_TREE;
-
- default:
- break;
- }
-
- gcc_unreachable ();
-}
-
-
/* Modify the RHS of the assignment pointed-to by GSI using the
operands in the expression tree EXPR.
gcc_unreachable();
}
+/* Replace the LHS of STMT, an assignment, either a GIMPLE_ASSIGN or a
+ GIMPLE_CALL, with NLHS, in preparation for modifying the RHS to an
+ expression with a different value.
+
+ This will update any annotations (say debug bind stmts) referring
+ to the original LHS, so that they use the RHS instead. This is
+ done even if NLHS and LHS are the same, for it is understood that
+ the RHS will be modified afterwards, and NLHS will not be assigned
+ an equivalent value.
+
+ Adjusting any non-annotation uses of the LHS, if needed, is a
+ responsibility of the caller.
+
+ The effect of this call should be pretty much the same as that of
+ inserting a copy of STMT before STMT, and then removing the
+ original stmt, at which time gsi_remove() would have update
+ annotations, but using this function saves all the inserting,
+ copying and removing. */
+
+void
+gimple_replace_lhs (gimple stmt, tree nlhs)
+{
+ if (MAY_HAVE_DEBUG_STMTS)
+ {
+ tree lhs = gimple_get_lhs (stmt);
+
+ gcc_assert (SSA_NAME_DEF_STMT (lhs) == stmt);
+
+ insert_debug_temp_for_var_def (NULL, lhs);
+ }
+
+ gimple_set_lhs (stmt, nlhs);
+}
/* Return a deep copy of statement STMT. All the operands from STMT
are reallocated and copied using unshare_expr. The DEF, USE, VDEF
{
while (handled_component_p (t))
t = TREE_OPERAND (t, 0);
-
+
if (SSA_VAR_P (t)
|| TREE_CODE (t) == STRING_CST
|| TREE_CODE (t) == CONSTRUCTOR
tree
canonicalize_cond_expr_cond (tree t)
{
+ /* Strip conversions around boolean operations. */
+ if (CONVERT_EXPR_P (t)
+ && truth_value_p (TREE_CODE (TREE_OPERAND (t, 0))))
+ t = TREE_OPERAND (t, 0);
+
/* For (bool)x use x != 0. */
- if (TREE_CODE (t) == NOP_EXPR
- && TREE_TYPE (t) == boolean_type_node)
+ if (CONVERT_EXPR_P (t)
+ && TREE_CODE (TREE_TYPE (t)) == BOOLEAN_TYPE)
{
tree top0 = TREE_OPERAND (t, 0);
t = build2 (NE_EXPR, TREE_TYPE (t),
return false;
}
-/* Return true if the field decls F1 and F2 are at the same offset. */
+/* Return true if the field decls F1 and F2 are at the same offset.
-static bool
-compare_field_offset (tree f1, tree f2)
+ This is intended to be used on GIMPLE types only. In order to
+ compare GENERIC types, use fields_compatible_p instead. */
+
+bool
+gimple_compare_field_offset (tree f1, tree f2)
{
if (DECL_OFFSET_ALIGN (f1) == DECL_OFFSET_ALIGN (f2))
- return (operand_equal_p (DECL_FIELD_OFFSET (f1),
- DECL_FIELD_OFFSET (f2), 0)
- && tree_int_cst_equal (DECL_FIELD_BIT_OFFSET (f1),
- DECL_FIELD_BIT_OFFSET (f2)));
+ {
+ tree offset1 = DECL_FIELD_OFFSET (f1);
+ tree offset2 = DECL_FIELD_OFFSET (f2);
+ return ((offset1 == offset2
+ /* Once gimplification is done, self-referential offsets are
+ instantiated as operand #2 of the COMPONENT_REF built for
+ each access and reset. Therefore, they are not relevant
+ anymore and fields are interchangeable provided that they
+ represent the same access. */
+ || (TREE_CODE (offset1) == PLACEHOLDER_EXPR
+ && TREE_CODE (offset2) == PLACEHOLDER_EXPR
+ && (DECL_SIZE (f1) == DECL_SIZE (f2)
+ || (TREE_CODE (DECL_SIZE (f1)) == PLACEHOLDER_EXPR
+ && TREE_CODE (DECL_SIZE (f2)) == PLACEHOLDER_EXPR)
+ || operand_equal_p (DECL_SIZE (f1), DECL_SIZE (f2), 0))
+ && DECL_ALIGN (f1) == DECL_ALIGN (f2))
+ || operand_equal_p (offset1, offset2, 0))
+ && tree_int_cst_equal (DECL_FIELD_BIT_OFFSET (f1),
+ DECL_FIELD_BIT_OFFSET (f2)));
+ }
/* Fortran and C do not always agree on what DECL_OFFSET_ALIGN
should be, so handle differing ones specially by decomposing
/* Check first for the obvious case of pointer identity. */
if (t1 == t2)
- goto same_types;
+ return 1;
/* Check that we have two types to compare. */
if (t1 == NULL_TREE || t2 == NULL_TREE)
- goto different_types;
+ return 0;
/* Can't be the same type if the types don't have the same code. */
if (TREE_CODE (t1) != TREE_CODE (t2))
- goto different_types;
+ return 0;
+
+ /* Can't be the same type if they have different CV qualifiers. */
+ if (TYPE_QUALS (t1) != TYPE_QUALS (t2))
+ return 0;
/* Void types are always the same. */
if (TREE_CODE (t1) == VOID_TYPE)
- goto same_types;
+ return 1;
- /* Can't be the same type if they have different CV qualifiers. */
- if (TYPE_QUALS (t1) != TYPE_QUALS (t2))
- goto different_types;
+ /* For numerical types do some simple checks before doing three
+ hashtable queries. */
+ if (INTEGRAL_TYPE_P (t1)
+ || SCALAR_FLOAT_TYPE_P (t1)
+ || FIXED_POINT_TYPE_P (t1)
+ || TREE_CODE (t1) == VECTOR_TYPE
+ || TREE_CODE (t1) == COMPLEX_TYPE
+ || TREE_CODE (t1) == OFFSET_TYPE)
+ {
+ /* Can't be the same type if they have different alignment,
+ sign, precision or mode. */
+ if (TYPE_ALIGN (t1) != TYPE_ALIGN (t2)
+ || TYPE_PRECISION (t1) != TYPE_PRECISION (t2)
+ || TYPE_MODE (t1) != TYPE_MODE (t2)
+ || TYPE_UNSIGNED (t1) != TYPE_UNSIGNED (t2))
+ return 0;
+
+ if (TREE_CODE (t1) == INTEGER_TYPE
+ && (TYPE_IS_SIZETYPE (t1) != TYPE_IS_SIZETYPE (t2)
+ || TYPE_STRING_FLAG (t1) != TYPE_STRING_FLAG (t2)))
+ return 0;
+
+ /* That's all we need to check for float and fixed-point types. */
+ if (SCALAR_FLOAT_TYPE_P (t1)
+ || FIXED_POINT_TYPE_P (t1))
+ return 1;
+
+ /* Perform cheap tail-recursion for vector and complex types. */
+ if (TREE_CODE (t1) == VECTOR_TYPE
+ || TREE_CODE (t1) == COMPLEX_TYPE)
+ return gimple_types_compatible_p (TREE_TYPE (t1), TREE_TYPE (t2));
+
+ /* For integral types fall thru to more complex checks. */
+ }
/* If the hash values of t1 and t2 are different the types can't
possibly be the same. This helps keeping the type-pair hashtable
if (!attribute_list_equal (TYPE_ATTRIBUTES (t1), TYPE_ATTRIBUTES (t2)))
goto different_types;
- /* For numerical types, the bounds must coincide. */
- if (INTEGRAL_TYPE_P (t1)
- || SCALAR_FLOAT_TYPE_P (t1)
- || FIXED_POINT_TYPE_P (t1))
- {
- /* Can't be the same type if they have different size, alignment,
- sign, precision or mode. Note that from now on, comparisons
- between *_CST nodes must be done using tree_int_cst_equal because
- we cannot assume that constants from T1 and T2 will be shared
- since T1 and T2 are distinct pointers. */
- if (!tree_int_cst_equal (TYPE_SIZE (t1), TYPE_SIZE (t2))
- || !tree_int_cst_equal (TYPE_SIZE_UNIT (t1), TYPE_SIZE_UNIT (t2))
- || TYPE_ALIGN (t1) != TYPE_ALIGN (t2)
- || TYPE_PRECISION (t1) != TYPE_PRECISION (t2)
- || TYPE_MODE (t1) != TYPE_MODE (t2)
- || TYPE_UNSIGNED (t1) != TYPE_UNSIGNED (t2))
- goto different_types;
-
- /* For non-enumeral types, check type bounds. FIXME lto, we
- cannot check bounds on enumeral types because different front
- ends will produce different values. In C, enumeral types are
- integers, while in C++ each element will have its own
- symbolic value. We should decide how enums are to be
- represented in GIMPLE and have each front end lower to that. */
- if (TREE_CODE (t1) != ENUMERAL_TYPE)
- {
- tree min1 = TYPE_MIN_VALUE (t1);
- tree max1 = TYPE_MAX_VALUE (t1);
- tree min2 = TYPE_MIN_VALUE (t2);
- tree max2 = TYPE_MAX_VALUE (t2);
- bool min_equal_p = false;
- bool max_equal_p = false;
-
- /* If either type has a minimum value, the other type must
- have the same. */
- if (min1 == NULL_TREE && min2 == NULL_TREE)
- min_equal_p = true;
- else if (min1 && min2 && operand_equal_p (min1, min2, 0))
- min_equal_p = true;
-
- /* Likewise, if either type has a maximum value, the other
- type must have the same. */
- if (max1 == NULL_TREE && max2 == NULL_TREE)
- max_equal_p = true;
- else if (max1 && max2 && operand_equal_p (max1, max2, 0))
- max_equal_p = true;
-
- if (!min_equal_p || !max_equal_p)
- goto different_types;
- }
-
- if (TREE_CODE (t1) == INTEGER_TYPE)
- {
- if (TYPE_IS_SIZETYPE (t1) == TYPE_IS_SIZETYPE (t2)
- && TYPE_STRING_FLAG (t1) == TYPE_STRING_FLAG (t2))
- goto same_types;
- else
- goto different_types;
- }
- else if (TREE_CODE (t1) == BOOLEAN_TYPE)
- goto same_types;
- else if (TREE_CODE (t1) == REAL_TYPE)
- goto same_types;
- }
-
/* Do type-specific comparisons. */
switch (TREE_CODE (t1))
{
/* Array types are the same if the element types are the same and
the number of elements are the same. */
if (!gimple_types_compatible_p (TREE_TYPE (t1), TREE_TYPE (t2))
- || TYPE_STRING_FLAG (t1) != TYPE_STRING_FLAG (t2))
+ || TYPE_STRING_FLAG (t1) != TYPE_STRING_FLAG (t2)
+ || TYPE_NONALIASED_COMPONENT (t1) != TYPE_NONALIASED_COMPONENT (t2))
goto different_types;
else
{
/* The minimum/maximum values have to be the same. */
if ((min1 == min2
- || (min1 && min2 && operand_equal_p (min1, min2, 0)))
+ || (min1 && min2
+ && ((TREE_CODE (min1) == PLACEHOLDER_EXPR
+ && TREE_CODE (min2) == PLACEHOLDER_EXPR)
+ || operand_equal_p (min1, min2, 0))))
&& (max1 == max2
- || (max1 && max2 && operand_equal_p (max1, max2, 0))))
+ || (max1 && max2
+ && ((TREE_CODE (max1) == PLACEHOLDER_EXPR
+ && TREE_CODE (max2) == PLACEHOLDER_EXPR)
+ || operand_equal_p (max1, max2, 0)))))
goto same_types;
else
goto different_types;
}
}
+ case OFFSET_TYPE:
+ {
+ if (!gimple_types_compatible_p (TREE_TYPE (t1), TREE_TYPE (t2))
+ || !gimple_types_compatible_p (TYPE_OFFSET_BASETYPE (t1),
+ TYPE_OFFSET_BASETYPE (t2)))
+ goto different_types;
+
+ goto same_types;
+ }
+
case POINTER_TYPE:
case REFERENCE_TYPE:
{
&& RECORD_OR_UNION_TYPE_P (TREE_TYPE (t1))
&& (!COMPLETE_TYPE_P (TREE_TYPE (t1))
|| !COMPLETE_TYPE_P (TREE_TYPE (t2)))
- && compare_type_names_p (TREE_TYPE (t1), TREE_TYPE (t2), true))
+ && TYPE_QUALS (TREE_TYPE (t1)) == TYPE_QUALS (TREE_TYPE (t2))
+ && compare_type_names_p (TYPE_MAIN_VARIANT (TREE_TYPE (t1)),
+ TYPE_MAIN_VARIANT (TREE_TYPE (t2)), true))
{
/* Replace the pointed-to incomplete type with the
- complete one. */
+ complete one.
+ ??? This simple name-based merging causes at least some
+ of the ICEs in canonicalizing FIELD_DECLs during stmt
+ read. For example in GCC we have two different struct deps
+ and we mismatch the use in struct cpp_reader in sched-int.h
+ vs. mkdeps.c. Of course the whole exercise is for TBAA
+ with structs which contain pointers to incomplete types
+ in one unit and to complete ones in another. So we
+ probably should merge these types only with more context. */
if (COMPLETE_TYPE_P (TREE_TYPE (t2)))
TREE_TYPE (t1) = TREE_TYPE (t2);
else
goto different_types;
}
+ case INTEGER_TYPE:
+ case BOOLEAN_TYPE:
+ {
+ tree min1 = TYPE_MIN_VALUE (t1);
+ tree max1 = TYPE_MAX_VALUE (t1);
+ tree min2 = TYPE_MIN_VALUE (t2);
+ tree max2 = TYPE_MAX_VALUE (t2);
+ bool min_equal_p = false;
+ bool max_equal_p = false;
+
+ /* If either type has a minimum value, the other type must
+ have the same. */
+ if (min1 == NULL_TREE && min2 == NULL_TREE)
+ min_equal_p = true;
+ else if (min1 && min2 && operand_equal_p (min1, min2, 0))
+ min_equal_p = true;
+
+ /* Likewise, if either type has a maximum value, the other
+ type must have the same. */
+ if (max1 == NULL_TREE && max2 == NULL_TREE)
+ max_equal_p = true;
+ else if (max1 && max2 && operand_equal_p (max1, max2, 0))
+ max_equal_p = true;
+
+ if (!min_equal_p || !max_equal_p)
+ goto different_types;
+
+ goto same_types;
+ }
+
case ENUMERAL_TYPE:
{
- /* For enumeral types, all the values must be the same. */
+ /* FIXME lto, we cannot check bounds on enumeral types because
+ different front ends will produce different values.
+ In C, enumeral types are integers, while in C++ each element
+ will have its own symbolic value. We should decide how enums
+ are to be represented in GIMPLE and have each front end lower
+ to that. */
tree v1, v2;
+ /* For enumeral types, all the values must be the same. */
if (TYPE_VALUES (t1) == TYPE_VALUES (t2))
goto same_types;
{
/* The fields must have the same name, offset and type. */
if (DECL_NAME (f1) != DECL_NAME (f2)
- || !compare_field_offset (f1, f2)
+ || DECL_NONADDRESSABLE_P (f1) != DECL_NONADDRESSABLE_P (f2)
+ || !gimple_compare_field_offset (f1, f2)
|| !gimple_types_compatible_p (TREE_TYPE (f1),
TREE_TYPE (f2)))
goto different_types;
goto same_types;
}
- case VECTOR_TYPE:
- if (TYPE_VECTOR_SUBPARTS (t1) != TYPE_VECTOR_SUBPARTS (t2))
- goto different_types;
-
- /* Fallthru */
- case COMPLEX_TYPE:
- if (!gimple_types_compatible_p (TREE_TYPE (t1), TREE_TYPE (t2)))
- goto different_types;
- goto same_types;
-
default:
- goto different_types;
+ gcc_unreachable ();
}
/* Common exit path for types that are not compatible. */
different_types:
- if (p)
- p->same_p = 0;
+ p->same_p = 0;
return 0;
/* Common exit path for types that are compatible. */
same_types:
- if (p)
- p->same_p = 1;
+ p->same_p = 1;
return 1;
}
/* For integer types hash the types min/max values and the string flag. */
if (TREE_CODE (type) == INTEGER_TYPE)
{
- v = iterative_hash_expr (TYPE_MIN_VALUE (type), v);
- v = iterative_hash_expr (TYPE_MAX_VALUE (type), v);
+ /* OMP lowering can introduce error_mark_node in place of
+ random local decls in types. */
+ if (TYPE_MIN_VALUE (type) != error_mark_node)
+ v = iterative_hash_expr (TYPE_MIN_VALUE (type), v);
+ if (TYPE_MAX_VALUE (type) != error_mark_node)
+ v = iterative_hash_expr (TYPE_MAX_VALUE (type), v);
v = iterative_hash_hashval_t (TYPE_STRING_FLAG (type), v);
}
gcc_assert (TYPE_P (t));
+ /* Always register the main variant first. This is important so we
+ pick up the non-typedef variants as canonical, otherwise we'll end
+ up taking typedef ids for structure tags during comparison. */
+ if (TYPE_MAIN_VARIANT (t) != t)
+ gimple_register_type (TYPE_MAIN_VARIANT (t));
+
if (gimple_types == NULL)
gimple_types = htab_create (16381, gimple_type_hash, gimple_type_eq, 0);
alias_set_type
gimple_get_alias_set (tree t)
{
- static bool recursing_p;
tree u;
/* Permit type-punning when accessing a union, provided the access
}
else if (POINTER_TYPE_P (t))
{
- tree t1;
-
- /* ??? We can end up creating cycles with TYPE_MAIN_VARIANT
- and TYPE_CANONICAL. Avoid recursing endlessly between
- this langhook and get_alias_set. */
- if (recursing_p)
- return -1;
+ /* From the common C and C++ langhook implementation:
- /* Unfortunately, there is no canonical form of a pointer type.
+ Unfortunately, there is no canonical form of a pointer type.
In particular, if we have `typedef int I', then `int *', and
`I *' are different types. So, we have to pick a canonical
representative. We do this below.
can dereference IPP and CIPP. So, we ignore cv-qualifiers on
the pointed-to types. This issue has been reported to the
C++ committee. */
- t1 = build_type_no_quals (t);
- if (t1 != t)
- {
- alias_set_type set;
- recursing_p = true;
- set = get_alias_set (t1);
- recursing_p = false;
- return set;
- }
+
+ /* In addition to the above canonicalization issue with LTO
+ we should also canonicalize `T (*)[]' to `T *' avoiding
+ alias issues with pointer-to element types and pointer-to
+ array types.
+
+ Likewise we need to deal with the situation of incomplete
+ pointed-to types and make `*(struct X **)&a' and
+ `*(struct X {} **)&a' alias. Otherwise we will have to
+ guarantee that all pointer-to incomplete type variants
+ will be replaced by pointer-to complete type variants if
+ they are available.
+
+ With LTO the convenient situation of using `void *' to
+ access and store any pointer type will also become
+ more apparent (and `void *' is just another pointer-to
+ incomplete type). Assigning alias-set zero to `void *'
+ and all pointer-to incomplete types is a not appealing
+ solution. Assigning an effective alias-set zero only
+ affecting pointers might be - by recording proper subset
+ relationships of all pointer alias-sets.
+
+ Pointer-to function types are another grey area which
+ needs caution. Globbing them all into one alias-set
+ or the above effective zero set would work. */
+
+ /* For now just assign the same alias-set to all pointers.
+ That's simple and avoids all the above problems. */
+ if (t != ptr_type_node)
+ return get_alias_set (ptr_type_node);
}
return -1;
tree addr, void *data)
{
bitmap addresses_taken = (bitmap)data;
- while (handled_component_p (addr))
- addr = TREE_OPERAND (addr, 0);
- if (DECL_P (addr))
+ addr = get_base_address (addr);
+ if (addr
+ && DECL_P (addr))
{
bitmap_set_bit (addresses_taken, DECL_UID (addr));
return true;
const char *
gimple_decl_printable_name (tree decl, int verbosity)
{
- gcc_assert (decl && DECL_NAME (decl));
+ if (!DECL_NAME (decl))
+ return NULL;
if (DECL_ASSEMBLER_NAME_SET_P (decl))
{
return IDENTIFIER_POINTER (DECL_NAME (decl));
}
-
-/* Fold a OBJ_TYPE_REF expression to the address of a function.
- KNOWN_TYPE carries the true type of OBJ_TYPE_REF_OBJECT(REF). Adapted
- from cp_fold_obj_type_ref, but it tolerates types with no binfo
- data. */
-
-tree
-gimple_fold_obj_type_ref (tree ref, tree known_type)
-{
- HOST_WIDE_INT index;
- HOST_WIDE_INT i;
- tree v;
- tree fndecl;
-
- if (TYPE_BINFO (known_type) == NULL_TREE)
- return NULL_TREE;
-
- v = BINFO_VIRTUALS (TYPE_BINFO (known_type));
- index = tree_low_cst (OBJ_TYPE_REF_TOKEN (ref), 1);
- i = 0;
- while (i != index)
- {
- i += (TARGET_VTABLE_USES_DESCRIPTORS
- ? TARGET_VTABLE_USES_DESCRIPTORS : 1);
- v = TREE_CHAIN (v);
- }
-
- fndecl = TREE_VALUE (v);
-
-#ifdef ENABLE_CHECKING
- gcc_assert (tree_int_cst_equal (OBJ_TYPE_REF_TOKEN (ref),
- DECL_VINDEX (fndecl)));
-#endif
-
- cgraph_node (fndecl)->local.vtable_method = true;
-
- return build_fold_addr_expr (fndecl);
-}
-
#include "gt-gimple.h"