/* 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.
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;
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);
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. */
}
-/* 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.
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.
+
+ This is intended to be used on GIMPLE types only. In order to
+ compare GENERIC types, use fields_compatible_p instead. */
bool
-compare_field_offset (tree f1, tree f2)
+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
/* 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;
&& RECORD_OR_UNION_TYPE_P (TREE_TYPE (t1))
&& (!COMPLETE_TYPE_P (TREE_TYPE (t1))
|| !COMPLETE_TYPE_P (TREE_TYPE (t2)))
+ && 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
/* The fields must have the same name, offset and type. */
if (DECL_NAME (f1) != DECL_NAME (f2)
|| DECL_NONADDRESSABLE_P (f1) != DECL_NONADDRESSABLE_P (f2)
- || !compare_field_offset (f1, f2)
+ || !gimple_compare_field_offset (f1, f2)
|| !gimple_types_compatible_p (TREE_TYPE (f1),
TREE_TYPE (f2)))
goto different_types;
/* 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);
}
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"