#include "tree-inline.h"
#include "tree-pretty-print.h"
#include "langhooks.h"
-#include "tree-ssa.h"
+#include "bitmap.h"
+#include "gimple-ssa.h"
#include "cgraph.h"
+#include "tree-cfg.h"
+#include "tree-ssanames.h"
+#include "tree-ssa.h"
#include "timevar.h"
#include "hashtab.h"
#include "flags.h"
#include "vec.h"
#include "omp-low.h"
#include "gimple-low.h"
+#include "cilk.h"
#include "langhooks-def.h" /* FIXME: for lhd_set_decl_assembler_name */
#include "tree-pass.h" /* FIXME: only for PROP_gimple_any */
-#include "tree-mudflap.h"
#include "expr.h"
#include "tm_p.h"
if (cgn)
for (cgn = cgn->nested; cgn; cgn = cgn->next_nested)
- unshare_body (cgn->symbol.decl);
+ unshare_body (cgn->decl);
}
/* Callback for walk_tree to unmark the visited trees rooted at *TP.
if (cgn)
for (cgn = cgn->nested; cgn; cgn = cgn->next_nested)
- unvisit_body (cgn->symbol.decl);
+ unvisit_body (cgn->decl);
}
/* Unconditionally make an unshared copy of EXPR. This is used when using
gimple stack_restore;
/* Save stack on entry and restore it on exit. Add a try_finally
- block to achieve this. Note that mudflap depends on the
- format of the emitted code: see mx_register_decls(). */
+ block to achieve this. */
build_stack_save_restore (&stack_save, &stack_restore);
gimplify_seq_add_stmt (&cleanup, stack_restore);
if (ret_expr == error_mark_node)
return GS_ERROR;
+ /* Implicit _Cilk_sync must be inserted right before any return statement
+ if there is a _Cilk_spawn in the function. If the user has provided a
+ _Cilk_sync, the optimizer should remove this duplicate one. */
+ if (fn_contains_cilk_spawn_p (cfun))
+ {
+ tree impl_sync = build0 (CILK_SYNC_STMT, void_type_node);
+ gimplify_and_add (impl_sync, pre_p);
+ }
+
if (!ret_expr
|| TREE_CODE (ret_expr) == RESULT_DECL
|| ret_expr == error_mark_node)
gimplify_vla_decl (tree decl, gimple_seq *seq_p)
{
/* This is a variable-sized decl. Simplify its size and mark it
- for deferred expansion. Note that mudflap depends on the format
- of the emitted code: see mx_register_decls(). */
+ for deferred expansion. */
tree t, addr, ptr_type;
gimplify_one_sizepos (&DECL_SIZE (decl), seq_p);
fallback_t fallback)
{
tree *p;
- vec<tree> expr_stack;
enum gimplify_status ret = GS_ALL_DONE, tret;
int i;
location_t loc = EXPR_LOCATION (*expr_p);
/* Create a stack of the subexpressions so later we can walk them in
order from inner to outer. */
- expr_stack.create (10);
+ stack_vec<tree, 10> expr_stack;
/* We can handle anything that get_inner_reference can deal with. */
for (p = expr_p; ; p = &TREE_OPERAND (*p, 0))
if (! EXPR_HAS_LOCATION (*expr_p))
SET_EXPR_LOCATION (*expr_p, input_location);
+ if (fn_contains_cilk_spawn_p (cfun)
+ && lang_hooks.cilkplus.cilk_detect_spawn_and_unwrap (expr_p)
+ && !seen_error ())
+ return (enum gimplify_status)
+ lang_hooks.cilkplus.gimplify_cilk_spawn (expr_p, pre_p, NULL);
+
/* This may be a call to a builtin function.
Builtin function calls may be transformed into different
TREE_TYPE (expr) = boolean_type_node;
return expr;
+ case ANNOTATE_EXPR:
+ if ((enum annot_expr_kind) tree_to_uhwi (TREE_OPERAND (expr, 1))
+ == annot_expr_ivdep_kind)
+ {
+ TREE_OPERAND (expr, 0) = gimple_boolify (TREE_OPERAND (expr, 0));
+ if (TREE_CODE (type) != BOOLEAN_TYPE)
+ TREE_TYPE (expr) = boolean_type_node;
+ return expr;
+ }
+ /* FALLTHRU */
+
default:
if (COMPARISON_CLASS_P (expr))
{
individual element initialization. Also don't do this for small
all-zero initializers (which aren't big enough to merit
clearing), and don't try to make bitwise copies of
- TREE_ADDRESSABLE types. */
+ TREE_ADDRESSABLE types.
+
+ We cannot apply such transformation when compiling chkp static
+ initializer because creation of initializer image in the memory
+ will require static initialization of bounds for it. It should
+ result in another gimplification of similar initializer and we
+ may fall into infinite loop. */
if (valid_const_initializer
&& !(cleared || num_nonzero_elements == 0)
- && !TREE_ADDRESSABLE (type))
+ && !TREE_ADDRESSABLE (type)
+ && (!current_function_decl
+ || !lookup_attribute ("chkp ctor",
+ DECL_ATTRIBUTES (current_function_decl))))
{
HOST_WIDE_INT size = int_size_in_bytes (type);
unsigned int align;
gcc_assert (TREE_CODE (*expr_p) == MODIFY_EXPR
|| TREE_CODE (*expr_p) == INIT_EXPR);
+
+ if (fn_contains_cilk_spawn_p (cfun)
+ && lang_hooks.cilkplus.cilk_detect_spawn_and_unwrap (expr_p)
+ && !seen_error ())
+ return (enum gimplify_status)
+ lang_hooks.cilkplus.gimplify_cilk_spawn (expr_p, pre_p, post_p);
/* Trying to simplify a clobber using normal logic doesn't work,
so handle it here. */
}
break;
+ case CILK_SPAWN_STMT:
+ gcc_assert
+ (fn_contains_cilk_spawn_p (cfun)
+ && lang_hooks.cilkplus.cilk_detect_spawn_and_unwrap (expr_p));
+ if (!seen_error ())
+ {
+ ret = (enum gimplify_status)
+ lang_hooks.cilkplus.gimplify_cilk_spawn (expr_p, pre_p,
+ post_p);
+ break;
+ }
+ /* If errors are seen, then just process it as a CALL_EXPR. */
+
case CALL_EXPR:
ret = gimplify_call_expr (expr_p, pre_p, fallback != fb_none);
ret = gimplify_addr_expr (expr_p, pre_p, post_p);
break;
+ case ANNOTATE_EXPR:
+ {
+ tree cond = TREE_OPERAND (*expr_p, 0);
+ tree id = TREE_OPERAND (*expr_p, 1);
+ tree tmp = create_tmp_var_raw (TREE_TYPE(cond), NULL);
+ gimplify_arg (&cond, pre_p, EXPR_LOCATION (*expr_p));
+ gimple call = gimple_build_call_internal (IFN_ANNOTATE, 2,
+ cond, id);
+ gimple_call_set_lhs (call, tmp);
+ gimplify_seq_add_stmt (pre_p, call);
+ *expr_p = tmp;
+ ret = GS_ALL_DONE;
+ break;
+ }
+
case VA_ARG_EXPR:
ret = gimplify_va_arg_expr (expr_p, pre_p, post_p);
break;
break;
}
+ case CILK_SYNC_STMT:
+ {
+ if (!fn_contains_cilk_spawn_p (cfun))
+ {
+ error_at (EXPR_LOCATION (*expr_p),
+ "expected %<_Cilk_spawn%> before %<_Cilk_sync%>");
+ ret = GS_ERROR;
+ }
+ else
+ {
+ gimplify_cilk_sync (expr_p, pre_p);
+ ret = GS_ALL_DONE;
+ }
+ break;
+ }
+
default:
switch (TREE_CODE_CLASS (TREE_CODE (*expr_p)))
{
var, before, m);
}
-#ifndef PAD_VARARGS_DOWN
-#define PAD_VARARGS_DOWN BYTES_BIG_ENDIAN
-#endif
+/* Return a dummy expression of type TYPE in order to keep going after an
+ error. */
-/* Build an indirect-ref expression over the given TREE, which represents a
- piece of a va_arg() expansion. */
-tree
-build_va_arg_indirect_ref (tree addr)
+static tree
+dummy_object (tree type)
{
- addr = build_simple_mem_ref_loc (EXPR_LOCATION (addr), addr);
-
- if (flag_mudflap) /* Don't instrument va_arg INDIRECT_REF. */
- mf_mark (addr);
-
- return addr;
+ tree t = build_int_cst (build_pointer_type (type), 0);
+ return build2 (MEM_REF, type, t, t);
}
-/* The "standard" implementation of va_arg: read the value from the
- current (padded) address and increment by the (padded) size. */
+/* Gimplify __builtin_va_arg, aka VA_ARG_EXPR, which is not really a
+ builtin function, but a very special sort of operator. */
-tree
-std_gimplify_va_arg_expr (tree valist, tree type, gimple_seq *pre_p,
- gimple_seq *post_p)
-{
- tree addr, t, type_size, rounded_size, valist_tmp;
- unsigned HOST_WIDE_INT align, boundary;
- bool indirect;
-
-#ifdef ARGS_GROW_DOWNWARD
- /* All of the alignment and movement below is for args-grow-up machines.
- As of 2004, there are only 3 ARGS_GROW_DOWNWARD targets, and they all
- implement their own specialized gimplify_va_arg_expr routines. */
- gcc_unreachable ();
-#endif
-
- indirect = pass_by_reference (NULL, TYPE_MODE (type), type, false);
- if (indirect)
- type = build_pointer_type (type);
+enum gimplify_status
+gimplify_va_arg_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p)
+{
+ tree promoted_type, have_va_type;
+ tree valist = TREE_OPERAND (*expr_p, 0);
+ tree type = TREE_TYPE (*expr_p);
+ tree t;
+ location_t loc = EXPR_LOCATION (*expr_p);
- align = PARM_BOUNDARY / BITS_PER_UNIT;
- boundary = targetm.calls.function_arg_boundary (TYPE_MODE (type), type);
+ /* Verify that valist is of the proper type. */
+ have_va_type = TREE_TYPE (valist);
+ if (have_va_type == error_mark_node)
+ return GS_ERROR;
+ have_va_type = targetm.canonical_va_list_type (have_va_type);
- /* When we align parameter on stack for caller, if the parameter
- alignment is beyond MAX_SUPPORTED_STACK_ALIGNMENT, it will be
- aligned at MAX_SUPPORTED_STACK_ALIGNMENT. We will match callee
- here with caller. */
- if (boundary > MAX_SUPPORTED_STACK_ALIGNMENT)
- boundary = MAX_SUPPORTED_STACK_ALIGNMENT;
+ if (have_va_type == NULL_TREE)
+ {
+ error_at (loc, "first argument to %<va_arg%> not of type %<va_list%>");
+ return GS_ERROR;
+ }
- boundary /= BITS_PER_UNIT;
+ /* Generate a diagnostic for requesting data of a type that cannot
+ be passed through `...' due to type promotion at the call site. */
+ if ((promoted_type = lang_hooks.types.type_promotes_to (type))
+ != type)
+ {
+ static bool gave_help;
+ bool warned;
- /* Hoist the valist value into a temporary for the moment. */
- valist_tmp = get_initialized_tmp_var (valist, pre_p, NULL);
+ /* Unfortunately, this is merely undefined, rather than a constraint
+ violation, so we cannot make this an error. If this call is never
+ executed, the program is still strictly conforming. */
+ warned = warning_at (loc, 0,
+ "%qT is promoted to %qT when passed through %<...%>",
+ type, promoted_type);
+ if (!gave_help && warned)
+ {
+ gave_help = true;
+ inform (loc, "(so you should pass %qT not %qT to %<va_arg%>)",
+ promoted_type, type);
+ }
- /* va_list pointer is aligned to PARM_BOUNDARY. If argument actually
- requires greater alignment, we must perform dynamic alignment. */
- if (boundary > align
- && !integer_zerop (TYPE_SIZE (type)))
- {
- t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist_tmp,
- fold_build_pointer_plus_hwi (valist_tmp, boundary - 1));
+ /* We can, however, treat "undefined" any way we please.
+ Call abort to encourage the user to fix the program. */
+ if (warned)
+ inform (loc, "if this code is reached, the program will abort");
+ /* Before the abort, allow the evaluation of the va_list
+ expression to exit or longjmp. */
+ gimplify_and_add (valist, pre_p);
+ t = build_call_expr_loc (loc,
+ builtin_decl_implicit (BUILT_IN_TRAP), 0);
gimplify_and_add (t, pre_p);
- t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist_tmp,
- fold_build2 (BIT_AND_EXPR, TREE_TYPE (valist),
- valist_tmp,
- build_int_cst (TREE_TYPE (valist), -boundary)));
- gimplify_and_add (t, pre_p);
+ /* This is dead code, but go ahead and finish so that the
+ mode of the result comes out right. */
+ *expr_p = dummy_object (type);
+ return GS_ALL_DONE;
}
else
- boundary = align;
-
- /* If the actual alignment is less than the alignment of the type,
- adjust the type accordingly so that we don't assume strict alignment
- when dereferencing the pointer. */
- boundary *= BITS_PER_UNIT;
- if (boundary < TYPE_ALIGN (type))
{
- type = build_variant_type_copy (type);
- TYPE_ALIGN (type) = boundary;
- }
+ /* Make it easier for the backends by protecting the valist argument
+ from multiple evaluations. */
+ if (TREE_CODE (have_va_type) == ARRAY_TYPE)
+ {
+ /* For this case, the backends will be expecting a pointer to
+ TREE_TYPE (abi), but it's possible we've
+ actually been given an array (an actual TARGET_FN_ABI_VA_LIST).
+ So fix it. */
+ if (TREE_CODE (TREE_TYPE (valist)) == ARRAY_TYPE)
+ {
+ tree p1 = build_pointer_type (TREE_TYPE (have_va_type));
+ valist = fold_convert_loc (loc, p1,
+ build_fold_addr_expr_loc (loc, valist));
+ }
- /* Compute the rounded size of the type. */
- type_size = size_in_bytes (type);
- rounded_size = round_up (type_size, align);
+ gimplify_expr (&valist, pre_p, post_p, is_gimple_val, fb_rvalue);
+ }
+ else
+ gimplify_expr (&valist, pre_p, post_p, is_gimple_min_lval, fb_lvalue);
- /* Reduce rounded_size so it's sharable with the postqueue. */
- gimplify_expr (&rounded_size, pre_p, post_p, is_gimple_val, fb_rvalue);
+ if (!targetm.gimplify_va_arg_expr)
+ /* FIXME: Once most targets are converted we should merely
+ assert this is non-null. */
+ return GS_ALL_DONE;
- /* Get AP. */
- addr = valist_tmp;
- if (PAD_VARARGS_DOWN && !integer_zerop (rounded_size))
- {
- /* Small args are padded downward. */
- t = fold_build2_loc (input_location, GT_EXPR, sizetype,
- rounded_size, size_int (align));
- t = fold_build3 (COND_EXPR, sizetype, t, size_zero_node,
- size_binop (MINUS_EXPR, rounded_size, type_size));
- addr = fold_build_pointer_plus (addr, t);
+ *expr_p = targetm.gimplify_va_arg_expr (valist, type, pre_p, post_p);
+ return GS_OK;
}
-
- /* Compute new value for AP. */
- t = fold_build_pointer_plus (valist_tmp, rounded_size);
- t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist, t);
- gimplify_and_add (t, pre_p);
-
- addr = fold_convert (build_pointer_type (type), addr);
-
- if (indirect)
- addr = build_va_arg_indirect_ref (addr);
-
- return build_va_arg_indirect_ref (addr);
}
#include "gt-gimplify.h"