/* GIMPLE lowering pass. Converts High GIMPLE into Low GIMPLE.
- Copyright (C) 2003-2014 Free Software Foundation, Inc.
+ Copyright (C) 2003-2016 Free Software Foundation, Inc.
This file is part of GCC.
#include "config.h"
#include "system.h"
#include "coretypes.h"
-#include "tm.h"
+#include "backend.h"
#include "tree.h"
+#include "gimple.h"
+#include "tree-pass.h"
+#include "fold-const.h"
#include "tree-nested.h"
#include "calls.h"
-#include "basic-block.h"
-#include "tree-ssa-alias.h"
-#include "internal-fn.h"
-#include "gimple-expr.h"
-#include "is-a.h"
-#include "gimple.h"
#include "gimple-iterator.h"
-#include "tree-iterator.h"
-#include "tree-inline.h"
-#include "flags.h"
-#include "function.h"
-#include "diagnostic-core.h"
-#include "tree-pass.h"
-#include "langhooks.h"
#include "gimple-low.h"
-#include "tree-nested.h"
/* The differences between High GIMPLE and Low GIMPLE are the
following:
struct return_statements_t
{
tree label;
- gimple stmt;
+ greturn *stmt;
};
typedef struct return_statements_t return_statements_t;
gimple_seq body = gimple_body (current_function_decl);
gimple_seq lowered_body;
gimple_stmt_iterator i;
- gimple bind;
- gimple x;
+ gimple *bind;
+ gimple *x;
/* The gimplifier should've left a body of exactly one statement,
namely a GIMPLE_BIND. */
/* If the function falls off the end, we need a null return statement.
If we've already got one in the return_statements vector, we don't
need to do anything special. Otherwise build one by hand. */
- if (gimple_seq_may_fallthru (lowered_body)
+ bool may_fallthru = gimple_seq_may_fallthru (lowered_body);
+ if (may_fallthru
&& (data.return_statements.is_empty ()
|| (gimple_return_retval (data.return_statements.last().stmt)
!= NULL)))
gimple_set_location (x, cfun->function_end_locus);
gimple_set_block (x, DECL_INITIAL (current_function_decl));
gsi_insert_after (&i, x, GSI_CONTINUE_LINKING);
+ may_fallthru = false;
}
/* If we lowered any return statements, emit the representative
x = gimple_build_label (t.label);
gsi_insert_after (&i, x, GSI_CONTINUE_LINKING);
gsi_insert_after (&i, t.stmt, GSI_CONTINUE_LINKING);
+ if (may_fallthru)
+ {
+ /* Remove the line number from the representative return statement.
+ It now fills in for the fallthru too. Failure to remove this
+ will result in incorrect results for coverage analysis. */
+ gimple_set_location (t.stmt, UNKNOWN_LOCATION);
+ may_fallthru = false;
+ }
}
/* Once the old body has been lowered, replace it with the new
GIMPLE_PASS, /* type */
"lower", /* name */
OPTGROUP_NONE, /* optinfo_flags */
- false, /* has_gate */
- true, /* has_execute */
TV_NONE, /* tv_id */
PROP_gimple_any, /* properties_required */
PROP_gimple_lcf, /* properties_provided */
{}
/* opt_pass methods: */
- unsigned int execute () { return lower_function_body (); }
+ virtual unsigned int execute (function *) { return lower_function_body (); }
}; // class pass_lower_cf
static void
lower_omp_directive (gimple_stmt_iterator *gsi, struct lower_data *data)
{
- gimple stmt;
+ gimple *stmt;
stmt = gsi_stmt (*gsi);
static void
lower_stmt (gimple_stmt_iterator *gsi, struct lower_data *data)
{
- gimple stmt = gsi_stmt (*gsi);
+ gimple *stmt = gsi_stmt (*gsi);
gimple_set_block (stmt, data->block);
return;
case GIMPLE_EH_ELSE:
- lower_sequence (gimple_eh_else_n_body_ptr (stmt), data);
- lower_sequence (gimple_eh_else_e_body_ptr (stmt), data);
+ {
+ geh_else *eh_else_stmt = as_a <geh_else *> (stmt);
+ lower_sequence (gimple_eh_else_n_body_ptr (eh_else_stmt), data);
+ lower_sequence (gimple_eh_else_e_body_ptr (eh_else_stmt), data);
+ }
break;
case GIMPLE_NOP:
return;
}
else if (DECL_FUNCTION_CODE (decl) == BUILT_IN_POSIX_MEMALIGN
- && flag_tree_bit_ccp)
+ && flag_tree_bit_ccp
+ && gimple_builtin_call_types_compatible_p (stmt, decl))
{
lower_builtin_posix_memalign (gsi);
return;
return;
case GIMPLE_TRANSACTION:
- lower_sequence (gimple_transaction_body_ptr (stmt), data);
+ lower_sequence (gimple_transaction_body_ptr (
+ as_a <gtransaction *> (stmt)),
+ data);
break;
default:
lower_gimple_bind (gimple_stmt_iterator *gsi, struct lower_data *data)
{
tree old_block = data->block;
- gimple stmt = gsi_stmt (*gsi);
+ gbind *stmt = as_a <gbind *> (gsi_stmt (*gsi));
tree new_block = gimple_bind_block (stmt);
if (new_block)
lower_try_catch (gimple_stmt_iterator *gsi, struct lower_data *data)
{
bool cannot_fallthru;
- gimple stmt = gsi_stmt (*gsi);
+ gimple *stmt = gsi_stmt (*gsi);
gimple_stmt_iterator i;
/* We don't handle GIMPLE_TRY_FINALLY. */
for (; !gsi_end_p (i); gsi_next (&i))
{
data->cannot_fallthru = false;
- lower_sequence (gimple_catch_handler_ptr (gsi_stmt (i)), data);
+ lower_sequence (gimple_catch_handler_ptr (
+ as_a <gcatch *> (gsi_stmt (i))),
+ data);
if (!data->cannot_fallthru)
cannot_fallthru = false;
}
This is a subroutine of gimple_stmt_may_fallthru. */
static bool
-gimple_try_catch_may_fallthru (gimple stmt)
+gimple_try_catch_may_fallthru (gtry *stmt)
{
gimple_stmt_iterator i;
through iff any of the catch bodies falls through. */
for (; !gsi_end_p (i); gsi_next (&i))
{
- if (gimple_seq_may_fallthru (gimple_catch_handler (gsi_stmt (i))))
+ if (gimple_seq_may_fallthru (gimple_catch_handler (
+ as_a <gcatch *> (gsi_stmt (i)))))
return true;
}
return false;
we'll just delete the extra code later. */
bool
-gimple_stmt_may_fallthru (gimple stmt)
+gimple_stmt_may_fallthru (gimple *stmt)
{
if (!stmt)
return true;
return false;
case GIMPLE_BIND:
- return gimple_seq_may_fallthru (gimple_bind_body (stmt));
+ return gimple_seq_may_fallthru (
+ gimple_bind_body (as_a <gbind *> (stmt)));
case GIMPLE_TRY:
if (gimple_try_kind (stmt) == GIMPLE_TRY_CATCH)
- return gimple_try_catch_may_fallthru (stmt);
+ return gimple_try_catch_may_fallthru (as_a <gtry *> (stmt));
/* It must be a GIMPLE_TRY_FINALLY. */
&& gimple_seq_may_fallthru (gimple_try_cleanup (stmt)));
case GIMPLE_EH_ELSE:
- return (gimple_seq_may_fallthru (gimple_eh_else_n_body (stmt))
- || gimple_seq_may_fallthru (gimple_eh_else_e_body (stmt)));
+ {
+ geh_else *eh_else_stmt = as_a <geh_else *> (stmt);
+ return (gimple_seq_may_fallthru (gimple_eh_else_n_body (eh_else_stmt))
+ || gimple_seq_may_fallthru (gimple_eh_else_e_body (
+ eh_else_stmt)));
+ }
case GIMPLE_CALL:
/* Functions that do not return do not fall through. */
static void
lower_gimple_return (gimple_stmt_iterator *gsi, struct lower_data *data)
{
- gimple stmt = gsi_stmt (*gsi);
- gimple t;
+ greturn *stmt = as_a <greturn *> (gsi_stmt (*gsi));
+ gimple *t;
int i;
return_statements_t tmp_rs;
static void
lower_builtin_setjmp (gimple_stmt_iterator *gsi)
{
- gimple stmt = gsi_stmt (*gsi);
+ gimple *stmt = gsi_stmt (*gsi);
location_t loc = gimple_location (stmt);
tree cont_label = create_artificial_label (loc);
tree next_label = create_artificial_label (loc);
tree dest, t, arg;
- gimple g;
+ gimple *g;
/* __builtin_setjmp_{setup,receiver} aren't ECF_RETURNS_TWICE and for RTL
these builtins are modelled as non-local label jumps to the label
that is passed to these two builtins, so pretend we have a non-local
label during GIMPLE passes too. See PR60003. */
- cfun->has_nonlocal_label = true;
+ cfun->has_nonlocal_label = 1;
/* NEXT_LABEL is the label __builtin_longjmp will jump to. Its address is
passed to both __builtin_setjmp_setup and __builtin_setjmp_receiver. */
dest = gimple_call_lhs (stmt);
/* Build '__builtin_setjmp_setup (BUF, NEXT_LABEL)' and insert. */
- arg = build_addr (next_label, current_function_decl);
+ arg = build_addr (next_label);
t = builtin_decl_implicit (BUILT_IN_SETJMP_SETUP);
g = gimple_build_call (t, 2, gimple_call_arg (stmt, 0), arg);
gimple_set_location (g, loc);
gsi_insert_before (gsi, g, GSI_SAME_STMT);
/* Build '__builtin_setjmp_receiver (NEXT_LABEL)' and insert. */
- arg = build_addr (next_label, current_function_decl);
+ arg = build_addr (next_label);
t = builtin_decl_implicit (BUILT_IN_SETJMP_RECEIVER);
g = gimple_build_call (t, 1, arg);
gimple_set_location (g, loc);
static void
lower_builtin_posix_memalign (gimple_stmt_iterator *gsi)
{
- gimple stmt, call = gsi_stmt (*gsi);
+ gimple *stmt, *call = gsi_stmt (*gsi);
tree pptr = gimple_call_arg (call, 0);
tree align = gimple_call_arg (call, 1);
tree res = gimple_call_lhs (call);
- tree ptr = create_tmp_reg (ptr_type_node, NULL);
+ tree ptr = create_tmp_reg (ptr_type_node);
if (TREE_CODE (pptr) == ADDR_EXPR)
{
- tree tem = create_tmp_var (ptr_type_node, NULL);
+ tree tem = create_tmp_var (ptr_type_node);
TREE_ADDRESSABLE (tem) = 1;
gimple_call_set_arg (call, 0, build_fold_addr_expr (tem));
stmt = gimple_build_assign (ptr, tem);
build_int_cst (ptr_type_node, 0)));
if (res == NULL_TREE)
{
- res = create_tmp_reg (integer_type_node, NULL);
+ res = create_tmp_reg (integer_type_node);
gimple_call_set_lhs (call, res);
}
tree align_label = create_artificial_label (UNKNOWN_LOCATION);
tree noalign_label = create_artificial_label (UNKNOWN_LOCATION);
- gimple cond = gimple_build_cond (EQ_EXPR, res, integer_zero_node,
+ gimple *cond = gimple_build_cond (EQ_EXPR, res, integer_zero_node,
align_label, noalign_label);
gsi_insert_after (gsi, cond, GSI_NEW_STMT);
gsi_insert_after (gsi, gimple_build_label (align_label), GSI_NEW_STMT);
void
record_vars_into (tree vars, tree fn)
{
- bool change_cfun = fn != current_function_decl;
-
- if (change_cfun)
- push_cfun (DECL_STRUCT_FUNCTION (fn));
-
for (; vars; vars = DECL_CHAIN (vars))
{
tree var = vars;
continue;
/* Record the variable. */
- add_local_decl (cfun, var);
+ add_local_decl (DECL_STRUCT_FUNCTION (fn), var);
}
-
- if (change_cfun)
- pop_cfun ();
}