location_t location;
enum omp_clause_default_kind default_kind;
bool is_parallel;
+ bool is_combined_parallel;
};
struct gimplify_ctx
DECL_GIMPLE_FORMAL_TEMP_P (t) = 0;
if (body)
- declare_tmp_vars (c->temps, body);
+ declare_vars (c->temps, body, false);
else
record_vars (c->temps);
/* Create a new omp construct that deals with variable remapping. */
static struct gimplify_omp_ctx *
-new_omp_context (bool is_parallel)
+new_omp_context (bool is_parallel, bool is_combined_parallel)
{
struct gimplify_omp_ctx *c;
c->privatized_types = pointer_set_create ();
c->location = input_location;
c->is_parallel = is_parallel;
+ c->is_combined_parallel = is_combined_parallel;
c->default_kind = OMP_CLAUSE_DEFAULT_SHARED;
return c;
tree tmp_var;
/* We don't allow types that are addressable (meaning we can't make copies),
- incomplete, or of variable size. */
- gcc_assert (!TREE_ADDRESSABLE (type)
- && COMPLETE_TYPE_P (type)
- && TREE_CODE (TYPE_SIZE_UNIT (type)) == INTEGER_CST);
+ or incomplete. We also used to reject every variable size objects here,
+ but now support those for which a constant upper bound can be obtained.
+ The processing for variable sizes is performed in gimple_add_tmp_var,
+ point at which it really matters and possibly reached via paths not going
+ through this function, e.g. after direct calls to create_tmp_var_raw. */
+ gcc_assert (!TREE_ADDRESSABLE (type) && COMPLETE_TYPE_P (type));
tmp_var = create_tmp_var_raw (type, prefix);
gimple_add_tmp_var (tmp_var);
return internal_get_tmp_var (val, pre_p, post_p, false);
}
-/* Declares all the variables in VARS in SCOPE. */
+/* Declares all the variables in VARS in SCOPE. If DEBUG_INFO is
+ true, generate debug info for them; otherwise don't. */
void
-declare_tmp_vars (tree vars, tree scope)
+declare_vars (tree vars, tree scope, bool debug_info)
{
tree last = vars;
if (last)
{
- tree temps;
+ tree temps, block;
/* C99 mode puts the default 'return 0;' for main outside the outer
braces. So drill down until we find an actual scope. */
gcc_assert (TREE_CODE (scope) == BIND_EXPR);
temps = nreverse (last);
- TREE_CHAIN (last) = BIND_EXPR_VARS (scope);
- BIND_EXPR_VARS (scope) = temps;
+
+ block = BIND_EXPR_BLOCK (scope);
+ if (!block || !debug_info)
+ {
+ TREE_CHAIN (last) = BIND_EXPR_VARS (scope);
+ BIND_EXPR_VARS (scope) = temps;
+ }
+ else
+ {
+ /* We need to attach the nodes both to the BIND_EXPR and to its
+ associated BLOCK for debugging purposes. The key point here
+ is that the BLOCK_VARS of the BIND_EXPR_BLOCK of a BIND_EXPR
+ is a subchain of the BIND_EXPR_VARS of the BIND_EXPR. */
+ if (BLOCK_VARS (block))
+ BLOCK_VARS (block) = chainon (BLOCK_VARS (block), temps);
+ else
+ {
+ BIND_EXPR_VARS (scope) = chainon (BIND_EXPR_VARS (scope), temps);
+ BLOCK_VARS (block) = temps;
+ }
+ }
}
}
+/* For VAR a VAR_DECL of variable size, try to find a constant upper bound
+ for the size and adjust DECL_SIZE/DECL_SIZE_UNIT accordingly. Abort if
+ no such upper bound can be obtained. */
+
+static void
+force_constant_size (tree var)
+{
+ /* The only attempt we make is by querying the maximum size of objects
+ of the variable's type. */
+
+ HOST_WIDE_INT max_size;
+
+ gcc_assert (TREE_CODE (var) == VAR_DECL);
+
+ max_size = max_int_size_in_bytes (TREE_TYPE (var));
+
+ gcc_assert (max_size >= 0);
+
+ DECL_SIZE_UNIT (var)
+ = build_int_cst (TREE_TYPE (DECL_SIZE_UNIT (var)), max_size);
+ DECL_SIZE (var)
+ = build_int_cst (TREE_TYPE (DECL_SIZE (var)), max_size * BITS_PER_UNIT);
+}
+
void
gimple_add_tmp_var (tree tmp)
{
gcc_assert (!TREE_CHAIN (tmp) && !DECL_SEEN_IN_BIND_EXPR_P (tmp));
+ /* Later processing assumes that the object size is constant, which might
+ not be true at this point. Force the use of a constant upper bound in
+ this case. */
+ if (!host_integerp (DECL_SIZE_UNIT (tmp), 1))
+ force_constant_size (tmp);
+
DECL_CONTEXT (tmp) = current_function_decl;
DECL_SEEN_IN_BIND_EXPR_P (tmp) = 1;
else if (cfun)
record_vars (tmp);
else
- declare_tmp_vars (tmp, DECL_SAVED_TREE (current_function_decl));
+ declare_vars (tmp, DECL_SAVED_TREE (current_function_decl), false);
}
/* Determines whether to assign a locus to the statement STMT. */
for (t = BIND_EXPR_VARS (bind_expr); t ; t = TREE_CHAIN (t))
{
if (TREE_CODE (t) == VAR_DECL)
- DECL_SEEN_IN_BIND_EXPR_P (t) = 1;
+ {
+ struct gimplify_omp_ctx *ctx = gimplify_omp_ctxp;
+
+ /* Mark variable as local. */
+ if (ctx && !is_global_var (t)
+ && (! DECL_SEEN_IN_BIND_EXPR_P (t)
+ || splay_tree_lookup (ctx->variables,
+ (splay_tree_key) t) == NULL))
+ omp_add_variable (gimplify_omp_ctxp, t, GOVD_LOCAL | GOVD_SEEN);
+
+ DECL_SEEN_IN_BIND_EXPR_P (t) = 1;
+ }
/* Preliminarily mark non-addressed complex variables as eligible
for promotion to gimple registers. We'll transform their uses
DECL_COMPLEX_GIMPLE_REG_P (t) = 1;
}
- /* Mark variables seen in this bind expr as locals. */
- if (gimplify_omp_ctxp)
- {
- struct gimplify_omp_ctx *ctx = gimplify_omp_ctxp;
-
- for (t = BIND_EXPR_VARS (bind_expr); t ; t = TREE_CHAIN (t))
- if (TREE_CODE (t) == VAR_DECL && !is_global_var (t))
- omp_add_variable (ctx, t, GOVD_LOCAL | GOVD_SEEN);
- }
-
gimple_push_bind_expr (bind_expr);
gimplify_ctxp->save_stack = false;
walk_tree (&init, force_labels_r, NULL, NULL);
}
- /* This decl isn't mentioned in the enclosing block, so add it to the
- list of temps. FIXME it seems a bit of a kludge to say that
- anonymous artificial vars aren't pushed, but everything else is. */
- if (DECL_ARTIFICIAL (decl) && DECL_NAME (decl) == NULL_TREE)
+ /* Some front ends do not explicitly declare all anonymous
+ artificial variables. We compensate here by declaring the
+ variables, though it would be better if the front ends would
+ explicitly declare them. */
+ if (!DECL_SEEN_IN_BIND_EXPR_P (decl)
+ && DECL_ARTIFICIAL (decl) && DECL_NAME (decl) == NULL_TREE)
gimple_add_tmp_var (decl);
}
labels = gimplify_ctxp->case_labels;
gimplify_ctxp->case_labels = saved_labels;
- len = VEC_length (tree, labels);
-
- for (i = 0; i < len; ++i)
+ i = 0;
+ while (i < VEC_length (tree, labels))
{
- tree t = VEC_index (tree, labels, i);
- if (!CASE_LOW (t))
+ tree elt = VEC_index (tree, labels, i);
+ tree low = CASE_LOW (elt);
+ bool remove_element = FALSE;
+
+ if (low)
+ {
+ /* Discard empty ranges. */
+ tree high = CASE_HIGH (elt);
+ if (high && INT_CST_LT (high, low))
+ remove_element = TRUE;
+ }
+ else
{
/* The default case must be the last label in the list. */
- default_case = t;
- VEC_replace (tree, labels, i, VEC_index (tree, labels, len - 1));
- len--;
- break;
+ gcc_assert (!default_case);
+ default_case = elt;
+ remove_element = TRUE;
}
+
+ if (remove_element)
+ VEC_ordered_remove (tree, labels, i);
+ else
+ i++;
}
+ len = i;
label_vec = make_tree_vec (len + 1);
SWITCH_LABELS (*expr_p) = label_vec;
default:
/* Other expressions that get here must have boolean values, but
might need to be converted to the appropriate mode. */
- return convert (boolean_type_node, expr);
+ return fold_convert (boolean_type_node, expr);
}
}
i = VEC_index (constructor_elt, elts, 1)->value;
if (r == NULL || i == NULL)
{
- tree zero = convert (TREE_TYPE (type), integer_zero_node);
+ tree zero = fold_convert (TREE_TYPE (type), integer_zero_node);
if (r == NULL)
r = zero;
if (i == NULL)
&& needs_to_live_in_memory (*to_p))
/* It's OK to use the return slot directly unless it's an NRV. */
use_target = true;
- else if (is_gimple_reg_type (TREE_TYPE (*to_p)))
+ else if (is_gimple_reg_type (TREE_TYPE (*to_p))
+ || (DECL_P (*to_p) && DECL_REGISTER (*to_p)))
/* Don't force regs into memory. */
use_target = false;
else if (TREE_CODE (*to_p) == VAR_DECL
tree type = TREE_TYPE (*expr_p);
*expr_p = build3 (COND_EXPR, type, *expr_p,
- convert (type, boolean_true_node),
- convert (type, boolean_false_node));
+ fold_convert (type, boolean_true_node),
+ fold_convert (type, boolean_false_node));
return GS_OK;
}
if (n->value & GOVD_SHARED)
{
if (ctx == gimplify_omp_ctxp)
- error ("iteration variable %qs should be private",
+ {
+ error ("iteration variable %qs should be private",
+ IDENTIFIER_POINTER (DECL_NAME (decl)));
+ n->value = GOVD_PRIVATE;
+ return true;
+ }
+ else
+ return false;
+ }
+ else if ((n->value & GOVD_EXPLICIT) != 0
+ && (ctx == gimplify_omp_ctxp
+ || (ctx->is_combined_parallel
+ && gimplify_omp_ctxp->outer_context == ctx)))
+ {
+ if ((n->value & GOVD_FIRSTPRIVATE) != 0)
+ error ("iteration variable %qs should not be firstprivate",
+ IDENTIFIER_POINTER (DECL_NAME (decl)));
+ else if ((n->value & GOVD_REDUCTION) != 0)
+ error ("iteration variable %qs should not be reduction",
IDENTIFIER_POINTER (DECL_NAME (decl)));
- n->value = GOVD_PRIVATE;
}
return true;
}
- if (ctx->outer_context)
- return omp_is_private (ctx->outer_context, decl);
- else if (ctx->is_parallel)
+ if (ctx->is_parallel)
return false;
+ else if (ctx->outer_context)
+ return omp_is_private (ctx->outer_context, decl);
else
return !is_global_var (decl);
}
and previous omp contexts. */
static void
-gimplify_scan_omp_clauses (tree *list_p, tree *pre_p, bool in_parallel)
+gimplify_scan_omp_clauses (tree *list_p, tree *pre_p, bool in_parallel,
+ bool in_combined_parallel)
{
struct gimplify_omp_ctx *ctx, *outer_ctx;
tree c;
- ctx = new_omp_context (in_parallel);
+ ctx = new_omp_context (in_parallel, in_combined_parallel);
outer_ctx = ctx->outer_context;
while ((c = *list_p) != NULL)
remove = true;
break;
}
+ /* Handle NRV results passed by reference. */
+ if (TREE_CODE (decl) == INDIRECT_REF
+ && TREE_CODE (TREE_OPERAND (decl, 0)) == RESULT_DECL
+ && DECL_BY_REFERENCE (TREE_OPERAND (decl, 0)))
+ OMP_CLAUSE_DECL (c) = decl = TREE_OPERAND (decl, 0);
omp_add_variable (ctx, decl, flags);
- if (TREE_CODE (c) == OMP_CLAUSE_REDUCTION
+ if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION
&& OMP_CLAUSE_REDUCTION_PLACEHOLDER (c))
{
omp_add_variable (ctx, OMP_CLAUSE_REDUCTION_PLACEHOLDER (c),
- GOVD_LOCAL);
+ GOVD_LOCAL | GOVD_SEEN);
gimplify_omp_ctxp = ctx;
push_gimplify_context ();
gimplify_stmt (&OMP_CLAUSE_REDUCTION_INIT (c));
remove = true;
break;
}
+ /* Handle NRV results passed by reference. */
+ if (TREE_CODE (decl) == INDIRECT_REF
+ && TREE_CODE (TREE_OPERAND (decl, 0)) == RESULT_DECL
+ && DECL_BY_REFERENCE (TREE_OPERAND (decl, 0)))
+ OMP_CLAUSE_DECL (c) = decl = TREE_OPERAND (decl, 0);
do_notice:
if (outer_ctx)
omp_notice_variable (outer_ctx, decl, true);
break;
- case OMP_CLAUSE_SCHEDULE:
case OMP_CLAUSE_IF:
+ OMP_CLAUSE_OPERAND (c, 0)
+ = gimple_boolify (OMP_CLAUSE_OPERAND (c, 0));
+ /* Fall through. */
+
+ case OMP_CLAUSE_SCHEDULE:
case OMP_CLAUSE_NUM_THREADS:
gs = gimplify_expr (&OMP_CLAUSE_OPERAND (c, 0), pre_p, NULL,
is_gimple_val, fb_rvalue);
{
tree expr = *expr_p;
- gimplify_scan_omp_clauses (&OMP_PARALLEL_CLAUSES (expr), pre_p, true);
+ gimplify_scan_omp_clauses (&OMP_PARALLEL_CLAUSES (expr), pre_p, true,
+ OMP_PARALLEL_COMBINED (expr));
push_gimplify_context ();
for_stmt = *expr_p;
- gimplify_scan_omp_clauses (&OMP_FOR_CLAUSES (for_stmt), pre_p, false);
+ gimplify_scan_omp_clauses (&OMP_FOR_CLAUSES (for_stmt), pre_p, false, false);
t = OMP_FOR_INIT (for_stmt);
gcc_assert (TREE_CODE (t) == MODIFY_EXPR);
decl = TREE_OPERAND (t, 0);
gcc_assert (DECL_P (decl));
gcc_assert (INTEGRAL_TYPE_P (TREE_TYPE (decl)));
- gcc_assert (!TYPE_UNSIGNED (TREE_TYPE (decl)));
/* Make sure the iteration variable is private. */
if (omp_is_private (gimplify_omp_ctxp, decl))
{
tree stmt = *expr_p;
- gimplify_scan_omp_clauses (&OMP_CLAUSES (stmt), pre_p, false);
+ gimplify_scan_omp_clauses (&OMP_CLAUSES (stmt), pre_p, false, false);
gimplify_to_stmt_list (&OMP_BODY (stmt));
gimplify_adjust_omp_clauses (&OMP_CLAUSES (stmt));
ret = gimplify_var_or_parm_decl (expr_p);
break;
+ case RESULT_DECL:
+ /* When within an OpenMP context, notice uses of variables. */
+ if (gimplify_omp_ctxp)
+ omp_notice_variable (gimplify_omp_ctxp, *expr_p, true);
+ ret = GS_ALL_DONE;
+ break;
+
case SSA_NAME:
/* Allow callbacks into the gimplifier during optimization. */
ret = GS_ALL_DONE;
ret = gimplify_omp_atomic (expr_p, pre_p);
break;
- case OMP_RETURN_EXPR:
+ case OMP_RETURN:
+ case OMP_CONTINUE:
ret = GS_ALL_DONE;
break;
switch (code)
{
case COMPONENT_REF:
- case REALPART_EXPR: case IMAGPART_EXPR:
+ case REALPART_EXPR:
+ case IMAGPART_EXPR:
+ case VIEW_CONVERT_EXPR:
gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p,
gimple_test_f, fallback);
break;
/* Historically, the compiler has treated a bare
reference to a volatile lvalue as forcing a load. */
tree type = TYPE_MAIN_VARIANT (TREE_TYPE (*expr_p));
- /* Normally, we do want to create a temporary for a
+ /* Normally, we do not want to create a temporary for a
TREE_ADDRESSABLE type because such a type should not be
copied by bitwise-assignment. However, we make an
exception here, as all we are doing here is ensuring that
if (referenced_vars)
{
for (t = gimplify_ctxp->temps; t ; t = TREE_CHAIN (t))
- add_referenced_tmp_var (t);
+ add_referenced_var (t);
}
pop_gimplify_context (NULL);