/* Gimple IR support functions.
- Copyright 2007, 2008 Free Software Foundation, Inc.
+ Copyright 2007, 2008, 2009 Free Software Foundation, Inc.
Contributed by Aldy Hernandez <aldyh@redhat.com>
This file is part of GCC.
#include "tm.h"
#include "tree.h"
#include "ggc.h"
-#include "errors.h"
#include "hard-reg-set.h"
#include "basic-block.h"
#include "gimple.h"
+#include "toplev.h"
#include "diagnostic.h"
#include "tree-flow.h"
#include "value-prof.h"
#include "flags.h"
+#include "demangle.h"
#define DEFGSCODE(SYM, NAME, STRUCT) NAME,
const char *const gimple_code_name[] = {
operands vector the size of the structure minus the size of the 1
element tree array at the end (see gimple_ops). */
#define DEFGSCODE(SYM, NAME, STRUCT) (sizeof (STRUCT) - sizeof (tree)),
-const size_t gimple_ops_offset_[] = {
+EXPORTED_CONST size_t gimple_ops_offset_[] = {
#include "gimple.def"
};
#undef DEFGSCODE
case GIMPLE_COND:
case GIMPLE_GOTO:
case GIMPLE_LABEL:
- case GIMPLE_CHANGE_DYNAMIC_TYPE:
+ case GIMPLE_DEBUG:
case GIMPLE_SWITCH: return GSS_WITH_OPS;
case GIMPLE_ASM: return GSS_ASM;
case GIMPLE_BIND: return GSS_BIND;
return sizeof (struct gimple_statement_omp_atomic_store);
case GIMPLE_WITH_CLEANUP_EXPR:
return sizeof (struct gimple_statement_wce);
- case GIMPLE_CHANGE_DYNAMIC_TYPE:
- return sizeof (struct gimple_statement_with_ops);
case GIMPLE_PREDICT:
return sizeof (struct gimple_statement_base);
default:
gimple_build_with_ops_stat (c, s, n MEM_STAT_INFO)
static gimple
-gimple_build_with_ops_stat (enum gimple_code code, enum tree_code subcode,
+gimple_build_with_ops_stat (enum gimple_code code, unsigned subcode,
unsigned num_ops MEM_STAT_DECL)
{
gimple s = gimple_alloc_stat (code, num_ops PASS_MEM_STAT);
gimple
gimple_build_return (tree retval)
{
- gimple s = gimple_build_with_ops (GIMPLE_RETURN, 0, 1);
+ gimple s = gimple_build_with_ops (GIMPLE_RETURN, ERROR_MARK, 1);
if (retval)
gimple_return_set_retval (s, retval);
return s;
static inline gimple
gimple_build_call_1 (tree fn, unsigned nargs)
{
- gimple s = gimple_build_with_ops (GIMPLE_CALL, 0, nargs + 3);
+ gimple s = gimple_build_with_ops (GIMPLE_CALL, ERROR_MARK, nargs + 3);
if (TREE_CODE (fn) == FUNCTION_DECL)
fn = build_fold_addr_expr (fn);
gimple_set_op (s, 1, fn);
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_set_no_warning (call, TREE_NO_WARNING (t));
return call;
}
code). */
num_ops = get_gimple_rhs_num_ops (subcode) + 1;
- p = gimple_build_with_ops_stat (GIMPLE_ASSIGN, subcode, num_ops
+ p = gimple_build_with_ops_stat (GIMPLE_ASSIGN, (unsigned)subcode, num_ops
PASS_MEM_STAT);
gimple_assign_set_lhs (p, lhs);
gimple_assign_set_rhs1 (p, op1);
This function returns the newly created GIMPLE_ASSIGN tuple. */
-inline gimple
+gimple
gimplify_assign (tree dst, tree src, gimple_seq *seq_p)
{
tree t = build2 (MODIFY_EXPR, TREE_TYPE (dst), dst, src);
gimple_cond_get_ops_from_tree (tree cond, enum tree_code *code_p,
tree *lhs_p, tree *rhs_p)
{
+ location_t loc = EXPR_LOCATION (cond);
gcc_assert (TREE_CODE_CLASS (TREE_CODE (cond)) == tcc_comparison
|| TREE_CODE (cond) == TRUTH_NOT_EXPR
|| is_gimple_min_invariant (cond)
{
*code_p = EQ_EXPR;
gcc_assert (*lhs_p && *rhs_p == NULL_TREE);
- *rhs_p = fold_convert (TREE_TYPE (*lhs_p), integer_zero_node);
+ *rhs_p = fold_convert_loc (loc, TREE_TYPE (*lhs_p), integer_zero_node);
}
/* Canonicalize conditionals of the form 'if (VAL)' */
else if (TREE_CODE_CLASS (*code_p) != tcc_comparison)
{
*code_p = NE_EXPR;
gcc_assert (*lhs_p && *rhs_p == NULL_TREE);
- *rhs_p = fold_convert (TREE_TYPE (*lhs_p), integer_zero_node);
+ *rhs_p = fold_convert_loc (loc, TREE_TYPE (*lhs_p), integer_zero_node);
}
}
gimple
gimple_build_label (tree label)
{
- gimple p = gimple_build_with_ops (GIMPLE_LABEL, 0, 1);
+ gimple p = gimple_build_with_ops (GIMPLE_LABEL, ERROR_MARK, 1);
gimple_label_set_label (p, label);
return p;
}
gimple
gimple_build_goto (tree dest)
{
- gimple p = gimple_build_with_ops (GIMPLE_GOTO, 0, 1);
+ gimple p = gimple_build_with_ops (GIMPLE_GOTO, ERROR_MARK, 1);
gimple_goto_set_dest (p, dest);
return p;
}
gimple p;
int size = strlen (string);
- p = gimple_build_with_ops (GIMPLE_ASM, 0, ninputs + noutputs + nclobbers);
+ p = gimple_build_with_ops (GIMPLE_ASM, ERROR_MARK,
+ ninputs + noutputs + nclobbers);
p->gimple_asm.ni = ninputs;
p->gimple_asm.no = noutputs;
gimple_build_switch_1 (unsigned nlabels, tree index, tree default_label)
{
/* nlabels + 1 default label + 1 index. */
- gimple p = gimple_build_with_ops (GIMPLE_SWITCH, 0, nlabels + 1 + 1);
+ gimple p = gimple_build_with_ops (GIMPLE_SWITCH, ERROR_MARK,
+ nlabels + 1 + 1);
gimple_switch_set_index (p, index);
gimple_switch_set_default_label (p, default_label);
return p;
}
+/* Build a new GIMPLE_DEBUG_BIND statement.
+
+ VAR is bound to VALUE; block and location are taken from STMT. */
+
+gimple
+gimple_build_debug_bind_stat (tree var, tree value, gimple stmt MEM_STAT_DECL)
+{
+ gimple p = gimple_build_with_ops_stat (GIMPLE_DEBUG,
+ (unsigned)GIMPLE_DEBUG_BIND, 2
+ PASS_MEM_STAT);
+
+ gimple_debug_bind_set_var (p, var);
+ gimple_debug_bind_set_value (p, value);
+ if (stmt)
+ {
+ gimple_set_block (p, gimple_block (stmt));
+ gimple_set_location (p, gimple_location (stmt));
+ }
+
+ return p;
+}
+
+
/* Build a GIMPLE_OMP_CRITICAL statement.
BODY is the sequence of statements for which only one thread can execute.
}
-/* Build a GIMPLE_CHANGE_DYNAMIC_TYPE statement. TYPE is the new type
- for the location PTR. */
-
-gimple
-gimple_build_cdt (tree type, tree ptr)
-{
- gimple p = gimple_build_with_ops (GIMPLE_CHANGE_DYNAMIC_TYPE, 0, 2);
- gimple_cdt_set_new_type (p, type);
- gimple_cdt_set_location (p, ptr);
-
- return p;
-}
-
-
/* Build a GIMPLE_OMP_ATOMIC_LOAD statement. */
gimple
{
gimple_stmt_iterator i;
-
if (gimple_seq_empty_p (body))
return true;
for (i = gsi_start (body); !gsi_end_p (i); gsi_next (&i))
- if (!empty_stmt_p (gsi_stmt (i)))
+ if (!empty_stmt_p (gsi_stmt (i))
+ && !is_gimple_debug (gsi_stmt (i)))
return false;
return true;
return ret;
break;
- case GIMPLE_CHANGE_DYNAMIC_TYPE:
- ret = walk_tree (gimple_cdt_location_ptr (stmt), callback_op, wi, pset);
- if (ret)
- return ret;
-
- ret = walk_tree (gimple_cdt_new_type_ptr (stmt), callback_op, wi, pset);
- if (ret)
- return ret;
- break;
-
case GIMPLE_ASM:
ret = walk_gimple_asm (stmt, callback_op, wi);
if (ret)
tree
gimple_fold (const_gimple stmt)
{
+ location_t loc = gimple_location (stmt);
switch (gimple_code (stmt))
{
case GIMPLE_COND:
- return fold_binary (gimple_cond_code (stmt),
+ return fold_binary_loc (loc, gimple_cond_code (stmt),
boolean_type_node,
gimple_cond_lhs (stmt),
gimple_cond_rhs (stmt));
switch (get_gimple_rhs_class (gimple_assign_rhs_code (stmt)))
{
case GIMPLE_UNARY_RHS:
- return fold_unary (gimple_assign_rhs_code (stmt),
+ 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 (gimple_assign_rhs_code (stmt),
+ return fold_binary_loc (loc, gimple_assign_rhs_code (stmt),
TREE_TYPE (gimple_assign_lhs (stmt)),
gimple_assign_rhs1 (stmt),
gimple_assign_rhs2 (stmt));
{
unsigned i;
+ if (is_gimple_debug (s))
+ return false;
+
/* We don't have to scan the arguments to check for
volatile arguments, though, at present, we still
do a scan to check for TREE_SIDE_EFFECTS. */
return true;
}
}
+ else if (is_gimple_debug (s))
+ return false;
else
{
/* For statements without an LHS, examine all arguments. */
case TRY_FINALLY_EXPR:
case EH_FILTER_EXPR:
case CATCH_EXPR:
- case CHANGE_DYNAMIC_TYPE_EXPR:
case ASM_EXPR:
case RESX_EXPR:
case STATEMENT_LIST:
bool
is_gimple_reg_type (tree type)
{
- /* In addition to aggregate types, we also exclude complex types if not
- optimizing because they can be subject to partial stores in GNU C by
- means of the __real__ and __imag__ operators and we cannot promote
- them to total stores (see gimplify_modify_expr_complex_part). */
- return !(AGGREGATE_TYPE_P (type)
- || (TREE_CODE (type) == COMPLEX_TYPE && !optimize));
-
+ return !AGGREGATE_TYPE_P (type);
}
/* Return true if T is a non-aggregate register variable. */
if (!is_gimple_variable (t))
return false;
- /* Complex and vector values must have been put into SSA-like form.
- That is, no assignments to the individual components. */
- if (TREE_CODE (TREE_TYPE (t)) == COMPLEX_TYPE
- || TREE_CODE (TREE_TYPE (t)) == VECTOR_TYPE)
- return DECL_GIMPLE_REG_P (t);
-
if (!is_gimple_reg_type (TREE_TYPE (t)))
return false;
if (TREE_CODE (t) == VAR_DECL && DECL_HARD_REGISTER (t))
return false;
+ /* Complex and vector values must have been put into SSA-like form.
+ That is, no assignments to the individual components. */
+ if (TREE_CODE (TREE_TYPE (t)) == COMPLEX_TYPE
+ || TREE_CODE (TREE_TYPE (t)) == VECTOR_TYPE)
+ return DECL_GIMPLE_REG_P (t);
+
return true;
}
ret |= visit_store (stmt, lhs, data);
}
rhs = gimple_assign_rhs1 (stmt);
+ while (handled_component_p (rhs))
+ rhs = TREE_OPERAND (rhs, 0);
if (visit_addr)
{
if (TREE_CODE (rhs) == ADDR_EXPR)
ret |= visit_addr (stmt, TREE_OPERAND (rhs, 0), data);
else if (TREE_CODE (rhs) == TARGET_MEM_REF
+ && TMR_BASE (rhs) != NULL_TREE
&& TREE_CODE (TMR_BASE (rhs)) == ADDR_EXPR)
ret |= visit_addr (stmt, TREE_OPERAND (TMR_BASE (rhs), 0), data);
else if (TREE_CODE (rhs) == OBJ_TYPE_REF
&& TREE_CODE (OBJ_TYPE_REF_OBJECT (rhs)) == ADDR_EXPR)
ret |= visit_addr (stmt, TREE_OPERAND (OBJ_TYPE_REF_OBJECT (rhs),
0), data);
+ lhs = gimple_assign_lhs (stmt);
+ if (TREE_CODE (lhs) == TARGET_MEM_REF
+ && TMR_BASE (lhs) != NULL_TREE
+ && TREE_CODE (TMR_BASE (lhs)) == ADDR_EXPR)
+ ret |= visit_addr (stmt, TREE_OPERAND (TMR_BASE (lhs), 0), data);
}
if (visit_load)
{
}
else if (visit_addr
&& (is_gimple_assign (stmt)
- || gimple_code (stmt) == GIMPLE_COND
- || gimple_code (stmt) == GIMPLE_CHANGE_DYNAMIC_TYPE))
+ || gimple_code (stmt) == GIMPLE_COND))
{
for (i = 0; i < gimple_num_ops (stmt); ++i)
if (gimple_op (stmt, i)
&& TREE_CODE (gimple_call_chain (stmt)) == ADDR_EXPR)
ret |= visit_addr (stmt, TREE_OPERAND (gimple_call_chain (stmt), 0),
data);
+ if (visit_addr
+ && gimple_call_return_slot_opt_p (stmt)
+ && gimple_call_lhs (stmt) != NULL_TREE
+ && TREE_ADDRESSABLE (TREE_TYPE (gimple_call_lhs (stmt))))
+ ret |= visit_addr (stmt, gimple_call_lhs (stmt), data);
}
else if (gimple_code (stmt) == GIMPLE_ASM)
{
gimple_ior_addresses_taken_1);
}
+
+/* Return a printable name for symbol DECL. */
+
+const char *
+gimple_decl_printable_name (tree decl, int verbosity)
+{
+ gcc_assert (decl && DECL_NAME (decl));
+
+ if (DECL_ASSEMBLER_NAME_SET_P (decl))
+ {
+ const char *str, *mangled_str;
+ int dmgl_opts = DMGL_NO_OPTS;
+
+ if (verbosity >= 2)
+ {
+ dmgl_opts = DMGL_VERBOSE
+ | DMGL_TYPES
+ | DMGL_ANSI
+ | DMGL_GNU_V3
+ | DMGL_RET_POSTFIX;
+ if (TREE_CODE (decl) == FUNCTION_DECL)
+ dmgl_opts |= DMGL_PARAMS;
+ }
+
+ mangled_str = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
+ str = cplus_demangle_v3 (mangled_str, dmgl_opts);
+ return (str) ? str : mangled_str;
+ }
+
+ 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"