/* Pass computing data for optimizing stdarg functions.
- Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc.
+ Copyright (C) 2004, 2005, 2007, 2008, 2009, 2010
+ Free Software Foundation, Inc.
Contributed by Jakub Jelinek <jakub@redhat.com>
This file is part of GCC.
#include "tree.h"
#include "function.h"
#include "langhooks.h"
-#include "diagnostic.h"
+#include "gimple-pretty-print.h"
#include "target.h"
#include "tree-flow.h"
#include "tree-pass.h"
va_list_counter_bump (struct stdarg_info *si, tree counter, tree rhs,
bool gpr_p)
{
- tree stmt, lhs, orig_lhs;
+ tree lhs, orig_lhs;
+ gimple stmt;
unsigned HOST_WIDE_INT ret = 0, val, counter_val;
unsigned int max_size;
orig_lhs = lhs = rhs;
while (lhs)
{
+ enum tree_code rhs_code;
+
if (si->offsets[SSA_NAME_VERSION (lhs)] != -1)
{
if (counter_val >= max_size)
stmt = SSA_NAME_DEF_STMT (lhs);
- if (TREE_CODE (stmt) != GIMPLE_MODIFY_STMT
- || GIMPLE_STMT_OPERAND (stmt, 0) != lhs)
+ if (!is_gimple_assign (stmt) || gimple_assign_lhs (stmt) != lhs)
return (unsigned HOST_WIDE_INT) -1;
- rhs = GIMPLE_STMT_OPERAND (stmt, 1);
- if (TREE_CODE (rhs) == WITH_SIZE_EXPR)
- rhs = TREE_OPERAND (rhs, 0);
-
- if (TREE_CODE (rhs) == SSA_NAME)
+ rhs_code = gimple_assign_rhs_code (stmt);
+ if ((get_gimple_rhs_class (rhs_code) == GIMPLE_SINGLE_RHS
+ || gimple_assign_cast_p (stmt))
+ && TREE_CODE (gimple_assign_rhs1 (stmt)) == SSA_NAME)
{
- lhs = rhs;
+ lhs = gimple_assign_rhs1 (stmt);
continue;
}
- if (CONVERT_EXPR_P (rhs)
- && TREE_CODE (TREE_OPERAND (rhs, 0)) == SSA_NAME)
+ if ((rhs_code == POINTER_PLUS_EXPR
+ || rhs_code == PLUS_EXPR)
+ && TREE_CODE (gimple_assign_rhs1 (stmt)) == SSA_NAME
+ && host_integerp (gimple_assign_rhs2 (stmt), 1))
{
- lhs = TREE_OPERAND (rhs, 0);
+ ret += tree_low_cst (gimple_assign_rhs2 (stmt), 1);
+ lhs = gimple_assign_rhs1 (stmt);
continue;
}
- if ((TREE_CODE (rhs) == POINTER_PLUS_EXPR
- || TREE_CODE (rhs) == PLUS_EXPR)
- && TREE_CODE (TREE_OPERAND (rhs, 0)) == SSA_NAME
- && TREE_CODE (TREE_OPERAND (rhs, 1)) == INTEGER_CST
- && host_integerp (TREE_OPERAND (rhs, 1), 1))
- {
- ret += tree_low_cst (TREE_OPERAND (rhs, 1), 1);
- lhs = TREE_OPERAND (rhs, 0);
- continue;
- }
+ if (get_gimple_rhs_class (rhs_code) != GIMPLE_SINGLE_RHS)
+ return (unsigned HOST_WIDE_INT) -1;
+ rhs = gimple_assign_rhs1 (stmt);
if (TREE_CODE (counter) != TREE_CODE (rhs))
return (unsigned HOST_WIDE_INT) -1;
val = ret + counter_val;
while (lhs)
{
+ enum tree_code rhs_code;
+
if (si->offsets[SSA_NAME_VERSION (lhs)] != -1)
break;
stmt = SSA_NAME_DEF_STMT (lhs);
- rhs = GIMPLE_STMT_OPERAND (stmt, 1);
- if (TREE_CODE (rhs) == WITH_SIZE_EXPR)
- rhs = TREE_OPERAND (rhs, 0);
-
- if (TREE_CODE (rhs) == SSA_NAME)
- {
- lhs = rhs;
- continue;
- }
-
- if (CONVERT_EXPR_P (rhs)
- && TREE_CODE (TREE_OPERAND (rhs, 0)) == SSA_NAME)
+ rhs_code = gimple_assign_rhs_code (stmt);
+ if ((get_gimple_rhs_class (rhs_code) == GIMPLE_SINGLE_RHS
+ || gimple_assign_cast_p (stmt))
+ && TREE_CODE (gimple_assign_rhs1 (stmt)) == SSA_NAME)
{
- lhs = TREE_OPERAND (rhs, 0);
+ lhs = gimple_assign_rhs1 (stmt);
continue;
}
- if ((TREE_CODE (rhs) == POINTER_PLUS_EXPR
- || TREE_CODE (rhs) == PLUS_EXPR)
- && TREE_CODE (TREE_OPERAND (rhs, 0)) == SSA_NAME
- && TREE_CODE (TREE_OPERAND (rhs, 1)) == INTEGER_CST
- && host_integerp (TREE_OPERAND (rhs, 1), 1))
+ if ((rhs_code == POINTER_PLUS_EXPR
+ || rhs_code == PLUS_EXPR)
+ && TREE_CODE (gimple_assign_rhs1 (stmt)) == SSA_NAME
+ && host_integerp (gimple_assign_rhs2 (stmt), 1))
{
- val -= tree_low_cst (TREE_OPERAND (rhs, 1), 1);
- lhs = TREE_OPERAND (rhs, 0);
+ val -= tree_low_cst (gimple_assign_rhs2 (stmt), 1);
+ lhs = gimple_assign_rhs1 (stmt);
continue;
}
find_va_list_reference (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED,
void *data)
{
- bitmap va_list_vars = (bitmap) data;
+ bitmap va_list_vars = (bitmap) ((struct walk_stmt_info *) data)->info;
tree var = *tp;
if (TREE_CODE (var) == SSA_NAME)
if (! POINTER_TYPE_P (TREE_TYPE (rhs)))
return;
- if (((TREE_CODE (rhs) == POINTER_PLUS_EXPR
- || TREE_CODE (rhs) == PLUS_EXPR)
- && TREE_CODE (TREE_OPERAND (rhs, 1)) == INTEGER_CST)
- || CONVERT_EXPR_P (rhs))
- rhs = TREE_OPERAND (rhs, 0);
-
if (TREE_CODE (rhs) != SSA_NAME
|| ! bitmap_bit_p (si->va_list_escape_vars,
DECL_UID (SSA_NAME_VAR (rhs))))
FOR_EACH_BB (bb)
{
- block_stmt_iterator i;
+ gimple_stmt_iterator i;
- for (i = bsi_start (bb); !bsi_end_p (i); bsi_next (&i))
+ for (i = gsi_start_bb (bb); !gsi_end_p (i); gsi_next (&i))
{
- tree stmt = bsi_stmt (i), use;
+ gimple stmt = gsi_stmt (i);
+ tree use;
ssa_op_iter iter;
+ if (is_gimple_debug (stmt))
+ continue;
+
FOR_EACH_SSA_TREE_OPERAND (use, stmt, iter, SSA_OP_ALL_USES)
{
if (! bitmap_bit_p (si->va_list_escape_vars,
DECL_UID (SSA_NAME_VAR (use))))
continue;
- if (TREE_CODE (stmt) == GIMPLE_MODIFY_STMT)
+ if (is_gimple_assign (stmt))
{
- tree lhs = GIMPLE_STMT_OPERAND (stmt, 0);
- tree rhs = GIMPLE_STMT_OPERAND (stmt, 1);
-
- if (TREE_CODE (rhs) == WITH_SIZE_EXPR)
- rhs = TREE_OPERAND (rhs, 0);
+ tree rhs = gimple_assign_rhs1 (stmt);
+ enum tree_code rhs_code = gimple_assign_rhs_code (stmt);
/* x = *ap_temp; */
- if (TREE_CODE (rhs) == INDIRECT_REF
+ if (gimple_assign_rhs_code (stmt) == MEM_REF
&& TREE_OPERAND (rhs, 0) == use
&& TYPE_SIZE_UNIT (TREE_TYPE (rhs))
&& host_integerp (TYPE_SIZE_UNIT (TREE_TYPE (rhs)), 1)
tree access_size = TYPE_SIZE_UNIT (TREE_TYPE (rhs));
gpr_size = si->offsets[SSA_NAME_VERSION (use)]
+ + tree_low_cst (TREE_OPERAND (rhs, 1), 0)
+ tree_low_cst (access_size, 1);
if (gpr_size >= VA_LIST_MAX_GPR_SIZE)
cfun->va_list_gpr_size = VA_LIST_MAX_GPR_SIZE;
other_ap_temp = (some_type *) ap_temp;
ap = ap_temp;
statements. */
- if ((TREE_CODE (rhs) == POINTER_PLUS_EXPR
- && TREE_CODE (TREE_OPERAND (rhs, 1)) == INTEGER_CST)
- || CONVERT_EXPR_P (rhs))
- rhs = TREE_OPERAND (rhs, 0);
-
- if (rhs == use)
+ if (rhs == use
+ && ((rhs_code == POINTER_PLUS_EXPR
+ && (TREE_CODE (gimple_assign_rhs2 (stmt))
+ == INTEGER_CST))
+ || gimple_assign_cast_p (stmt)
+ || (get_gimple_rhs_class (rhs_code)
+ == GIMPLE_SINGLE_RHS)))
{
+ tree lhs = gimple_assign_lhs (stmt);
+
if (TREE_CODE (lhs) == SSA_NAME
&& bitmap_bit_p (si->va_list_escape_vars,
DECL_UID (SSA_NAME_VAR (lhs))))
if (dump_file && (dump_flags & TDF_DETAILS))
{
fputs ("va_list escapes in ", dump_file);
- print_generic_expr (dump_file, stmt, dump_flags);
+ print_gimple_stmt (dump_file, stmt, 0, dump_flags);
fputc ('\n', dump_file);
}
return true;
bool va_list_escapes = false;
bool va_list_simple_ptr;
struct stdarg_info si;
+ struct walk_stmt_info wi;
const char *funcname = NULL;
+ tree cfun_va_list;
cfun->va_list_gpr_size = 0;
cfun->va_list_fpr_size = 0;
if (dump_file)
funcname = lang_hooks.decl_printable_name (current_function_decl, 2);
- va_list_simple_ptr = POINTER_TYPE_P (va_list_type_node)
- && (TREE_TYPE (va_list_type_node) == void_type_node
- || TREE_TYPE (va_list_type_node) == char_type_node);
- gcc_assert (is_gimple_reg_type (va_list_type_node) == va_list_simple_ptr);
+ cfun_va_list = targetm.fn_abi_va_list (cfun->decl);
+ va_list_simple_ptr = POINTER_TYPE_P (cfun_va_list)
+ && (TREE_TYPE (cfun_va_list) == void_type_node
+ || TREE_TYPE (cfun_va_list) == char_type_node);
+ gcc_assert (is_gimple_reg_type (cfun_va_list) == va_list_simple_ptr);
FOR_EACH_BB (bb)
{
- block_stmt_iterator i;
+ gimple_stmt_iterator i;
- for (i = bsi_start (bb); !bsi_end_p (i); bsi_next (&i))
+ for (i = gsi_start_bb (bb); !gsi_end_p (i); gsi_next (&i))
{
- tree stmt = bsi_stmt (i);
- tree call = get_call_expr_in (stmt), callee;
- tree ap;
+ gimple stmt = gsi_stmt (i);
+ tree callee, ap;
- if (!call)
+ if (!is_gimple_call (stmt))
continue;
- callee = get_callee_fndecl (call);
+ callee = gimple_call_fndecl (stmt);
if (!callee
|| DECL_BUILT_IN_CLASS (callee) != BUILT_IN_NORMAL)
continue;
}
si.va_start_count++;
- ap = CALL_EXPR_ARG (call, 0);
+ ap = gimple_call_arg (stmt, 0);
if (TREE_CODE (ap) != ADDR_EXPR)
{
ap = TREE_OPERAND (ap, 0);
}
if (TYPE_MAIN_VARIANT (TREE_TYPE (ap))
- != TYPE_MAIN_VARIANT (va_list_type_node)
+ != TYPE_MAIN_VARIANT (targetm.fn_abi_va_list (cfun->decl))
|| TREE_CODE (ap) != VAR_DECL)
{
va_list_escapes = true;
cfun->va_list_fpr_size = VA_LIST_MAX_FPR_SIZE;
calculate_dominance_info (CDI_DOMINATORS);
+ memset (&wi, 0, sizeof (wi));
+ wi.info = si.va_list_vars;
FOR_EACH_BB (bb)
{
- block_stmt_iterator i;
+ gimple_stmt_iterator i;
si.compute_sizes = -1;
si.bb = bb;
any real data movement. */
if (va_list_simple_ptr)
{
- tree phi, lhs, rhs;
+ tree lhs, rhs;
use_operand_p uop;
ssa_op_iter soi;
- for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi))
+ for (i = gsi_start_phis (bb); !gsi_end_p (i); gsi_next (&i))
{
+ gimple phi = gsi_stmt (i);
lhs = PHI_RESULT (phi);
if (!is_gimple_reg (lhs))
else
check_va_list_escapes (&si, lhs, rhs);
- if (si.va_list_escapes
- || walk_tree (&phi, find_va_list_reference,
- si.va_list_vars, NULL))
+ if (si.va_list_escapes)
{
if (dump_file && (dump_flags & TDF_DETAILS))
{
fputs ("va_list escapes in ", dump_file);
- print_generic_expr (dump_file, phi, dump_flags);
+ print_gimple_stmt (dump_file, phi, 0, dump_flags);
fputc ('\n', dump_file);
}
va_list_escapes = true;
}
}
- for (i = bsi_start (bb);
- !bsi_end_p (i) && !va_list_escapes;
- bsi_next (&i))
+ for (i = gsi_start_bb (bb);
+ !gsi_end_p (i) && !va_list_escapes;
+ gsi_next (&i))
{
- tree stmt = bsi_stmt (i);
- tree call;
+ gimple stmt = gsi_stmt (i);
/* Don't look at __builtin_va_{start,end}, they are ok. */
- call = get_call_expr_in (stmt);
- if (call)
+ if (is_gimple_call (stmt))
{
- tree callee = get_callee_fndecl (call);
+ tree callee = gimple_call_fndecl (stmt);
if (callee
&& DECL_BUILT_IN_CLASS (callee) == BUILT_IN_NORMAL
continue;
}
- if (TREE_CODE (stmt) == GIMPLE_MODIFY_STMT)
+ if (is_gimple_assign (stmt))
{
- tree lhs = GIMPLE_STMT_OPERAND (stmt, 0);
- tree rhs = GIMPLE_STMT_OPERAND (stmt, 1);
-
- if (TREE_CODE (rhs) == WITH_SIZE_EXPR)
- rhs = TREE_OPERAND (rhs, 0);
+ tree lhs = gimple_assign_lhs (stmt);
+ tree rhs = gimple_assign_rhs1 (stmt);
if (va_list_simple_ptr)
{
- /* Check for tem = ap. */
- if (va_list_ptr_read (&si, rhs, lhs))
- continue;
+ if (get_gimple_rhs_class (gimple_assign_rhs_code (stmt))
+ == GIMPLE_SINGLE_RHS)
+ {
+ /* Check for tem = ap. */
+ if (va_list_ptr_read (&si, rhs, lhs))
+ continue;
- /* Check for the last insn in:
- tem1 = ap;
- tem2 = tem1 + CST;
- ap = tem2;
- sequence. */
- else if (va_list_ptr_write (&si, lhs, rhs))
- continue;
+ /* Check for the last insn in:
+ tem1 = ap;
+ tem2 = tem1 + CST;
+ ap = tem2;
+ sequence. */
+ else if (va_list_ptr_write (&si, lhs, rhs))
+ continue;
+ }
- else
+ if ((gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR
+ && TREE_CODE (gimple_assign_rhs2 (stmt)) == INTEGER_CST)
+ || CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (stmt))
+ || (get_gimple_rhs_class (gimple_assign_rhs_code (stmt))
+ == GIMPLE_SINGLE_RHS))
check_va_list_escapes (&si, lhs, rhs);
}
else
{
- /* Check for ap[0].field = temp. */
- if (va_list_counter_struct_op (&si, lhs, rhs, true))
- continue;
+ if (get_gimple_rhs_class (gimple_assign_rhs_code (stmt))
+ == GIMPLE_SINGLE_RHS)
+ {
+ /* Check for ap[0].field = temp. */
+ if (va_list_counter_struct_op (&si, lhs, rhs, true))
+ continue;
- /* Check for temp = ap[0].field. */
- else if (va_list_counter_struct_op (&si, rhs, lhs, false))
- continue;
+ /* Check for temp = ap[0].field. */
+ else if (va_list_counter_struct_op (&si, rhs, lhs,
+ false))
+ continue;
+ }
/* Do any architecture specific checking. */
- else if (targetm.stdarg_optimize_hook
- && targetm.stdarg_optimize_hook (&si, lhs, rhs))
+ if (targetm.stdarg_optimize_hook
+ && targetm.stdarg_optimize_hook (&si, stmt))
continue;
}
}
+ else if (is_gimple_debug (stmt))
+ continue;
/* All other uses of va_list are either va_copy (that is not handled
in this optimization), taking address of va_list variable or
fully), or some unexpected use of va_list. None of these should
happen in a gimplified VA_ARG_EXPR. */
if (si.va_list_escapes
- || walk_tree (&stmt, find_va_list_reference,
- si.va_list_vars, NULL))
+ || walk_gimple_op (stmt, find_va_list_reference, &wi))
{
if (dump_file && (dump_flags & TDF_DETAILS))
{
fputs ("va_list escapes in ", dump_file);
- print_generic_expr (dump_file, stmt, dump_flags);
+ print_gimple_stmt (dump_file, stmt, 0, dump_flags);
fputc ('\n', dump_file);
}
va_list_escapes = true;
NULL, /* sub */
NULL, /* next */
0, /* static_pass_number */
- 0, /* tv_id */
- PROP_cfg | PROP_ssa | PROP_alias, /* properties_required */
+ TV_NONE, /* tv_id */
+ PROP_cfg | PROP_ssa, /* properties_required */
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */