/* Preliminarily mark non-addressed complex variables as eligible
for promotion to gimple registers. We'll transform their uses
- as we find them. */
- if ((TREE_CODE (TREE_TYPE (t)) == COMPLEX_TYPE
- || TREE_CODE (TREE_TYPE (t)) == VECTOR_TYPE)
+ as we find them.
+ We 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). */
+ if (optimize
+ && (TREE_CODE (TREE_TYPE (t)) == COMPLEX_TYPE
+ || TREE_CODE (TREE_TYPE (t)) == VECTOR_TYPE)
&& !TREE_THIS_VOLATILE (t)
&& (TREE_CODE (t) == VAR_DECL && !DECL_HARD_REGISTER (t))
&& !needs_to_live_in_memory (t))
}
len = i;
+ if (!VEC_empty (tree, labels))
+ sort_case_labels (labels);
+
if (!default_case)
{
- gimple new_default;
+ tree type = TREE_TYPE (switch_expr);
/* If the switch has no default label, add one, so that we jump
- around the switch body. */
- default_case = build3 (CASE_LABEL_EXPR, void_type_node, NULL_TREE,
- NULL_TREE, create_artificial_label ());
- new_default = gimple_build_label (CASE_LABEL (default_case));
- gimplify_seq_add_stmt (&switch_body_seq, new_default);
- }
+ around the switch body. If the labels already cover the whole
+ range of type, add the default label pointing to one of the
+ existing labels. */
+ if (type == void_type_node)
+ type = TREE_TYPE (SWITCH_COND (switch_expr));
+ if (len
+ && INTEGRAL_TYPE_P (type)
+ && TYPE_MIN_VALUE (type)
+ && TYPE_MAX_VALUE (type)
+ && tree_int_cst_equal (CASE_LOW (VEC_index (tree, labels, 0)),
+ TYPE_MIN_VALUE (type)))
+ {
+ tree low, high = CASE_HIGH (VEC_index (tree, labels, len - 1));
+ if (!high)
+ high = CASE_LOW (VEC_index (tree, labels, len - 1));
+ if (tree_int_cst_equal (high, TYPE_MAX_VALUE (type)))
+ {
+ for (i = 1; i < len; i++)
+ {
+ high = CASE_LOW (VEC_index (tree, labels, i));
+ low = CASE_HIGH (VEC_index (tree, labels, i - 1));
+ if (!low)
+ low = CASE_LOW (VEC_index (tree, labels, i - 1));
+ if ((TREE_INT_CST_LOW (low) + 1
+ != TREE_INT_CST_LOW (high))
+ || (TREE_INT_CST_HIGH (low)
+ + (TREE_INT_CST_LOW (high) == 0)
+ != TREE_INT_CST_HIGH (high)))
+ break;
+ }
+ if (i == len)
+ default_case = build3 (CASE_LABEL_EXPR, void_type_node,
+ NULL_TREE, NULL_TREE,
+ CASE_LABEL (VEC_index (tree,
+ labels, 0)));
+ }
+ }
- if (!VEC_empty (tree, labels))
- sort_case_labels (labels);
+ if (!default_case)
+ {
+ gimple new_default;
+
+ default_case = build3 (CASE_LABEL_EXPR, void_type_node,
+ NULL_TREE, NULL_TREE,
+ create_artificial_label ());
+ new_default = gimple_build_label (CASE_LABEL (default_case));
+ gimplify_seq_add_stmt (&switch_body_seq, new_default);
+ }
+ }
gimple_switch = gimple_build_switch_vec (SWITCH_COND (switch_expr),
default_case, labels);
return GS_OK;
}
+/* Nonlocal VLAs seen in the current function. */
+static struct pointer_set_t *nonlocal_vlas;
+
/* Gimplify a VAR_DECL or PARM_DECL. Returns GS_OK if we expanded a
DECL_VALUE_EXPR, and it's worth re-examining things. */
/* If the decl is an alias for another expression, substitute it now. */
if (DECL_HAS_VALUE_EXPR_P (decl))
{
- *expr_p = unshare_expr (DECL_VALUE_EXPR (decl));
+ tree value_expr = DECL_VALUE_EXPR (decl);
+
+ /* For referenced nonlocal VLAs add a decl for debugging purposes
+ to the current function. */
+ if (TREE_CODE (decl) == VAR_DECL
+ && TREE_CODE (DECL_SIZE_UNIT (decl)) != INTEGER_CST
+ && nonlocal_vlas != NULL
+ && TREE_CODE (value_expr) == INDIRECT_REF
+ && TREE_CODE (TREE_OPERAND (value_expr, 0)) == VAR_DECL
+ && decl_function_context (decl) != current_function_decl)
+ {
+ struct gimplify_omp_ctx *ctx = gimplify_omp_ctxp;
+ while (ctx && ctx->region_type == ORT_WORKSHARE)
+ ctx = ctx->outer_context;
+ if (!ctx && !pointer_set_insert (nonlocal_vlas, decl))
+ {
+ tree copy = copy_node (decl), block;
+
+ lang_hooks.dup_lang_specific_decl (copy);
+ SET_DECL_RTL (copy, NULL_RTX);
+ TREE_USED (copy) = 1;
+ block = DECL_INITIAL (current_function_decl);
+ TREE_CHAIN (copy) = BLOCK_VARS (block);
+ BLOCK_VARS (block) = copy;
+ SET_DECL_VALUE_EXPR (copy, unshare_expr (value_expr));
+ DECL_HAS_VALUE_EXPR_P (copy) = 1;
+ }
+ }
+
+ *expr_p = unshare_expr (value_expr);
return GS_OK;
}
switch (TREE_CODE (*from_p))
{
case VAR_DECL:
- /* If we're assigning from a constant constructor, move the
- constructor expression to the RHS of the MODIFY_EXPR. */
+ /* If we're assigning from a read-only variable initialized with
+ a constructor, do the direct assignment from the constructor,
+ but only if neither source nor target are volatile since this
+ latter assignment might end up being done on a per-field basis. */
if (DECL_INITIAL (*from_p)
&& TREE_READONLY (*from_p)
&& !TREE_THIS_VOLATILE (*from_p)
+ && !TREE_THIS_VOLATILE (*to_p)
&& TREE_CODE (DECL_INITIAL (*from_p)) == CONSTRUCTOR)
{
tree old_from = *from_p;
switch (default_kind)
{
case OMP_CLAUSE_DEFAULT_NONE:
- error ("%qs not specified in enclosing parallel",
- IDENTIFIER_POINTER (DECL_NAME (decl)));
+ error ("%qE not specified in enclosing parallel",
+ DECL_NAME (decl));
error ("%Henclosing parallel", &ctx->location);
/* FALLTHRU */
case OMP_CLAUSE_DEFAULT_SHARED:
{
if (ctx == gimplify_omp_ctxp)
{
- error ("iteration variable %qs should be private",
- IDENTIFIER_POINTER (DECL_NAME (decl)));
+ error ("iteration variable %qE should be private",
+ DECL_NAME (decl));
n->value = GOVD_PRIVATE;
return true;
}
&& 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)));
+ error ("iteration variable %qE should not be firstprivate",
+ DECL_NAME (decl));
else if ((n->value & GOVD_REDUCTION) != 0)
- error ("iteration variable %qs should not be reduction",
- IDENTIFIER_POINTER (DECL_NAME (decl)));
+ error ("iteration variable %qE should not be reduction",
+ DECL_NAME (decl));
}
return (ctx == gimplify_omp_ctxp
|| (ctx->region_type == ORT_COMBINED_PARALLEL
&& region_type == ORT_WORKSHARE
&& omp_check_private (ctx, decl))
{
- error ("%s variable %qs is private in outer context",
- check_non_private, IDENTIFIER_POINTER (DECL_NAME (decl)));
+ error ("%s variable %qE is private in outer context",
+ check_non_private, DECL_NAME (decl));
remove = true;
}
break;
gimplify_omp_for (tree *expr_p, gimple_seq *pre_p)
{
tree for_stmt, decl, var, t;
- enum gimplify_status ret = GS_OK;
+ enum gimplify_status ret = GS_ALL_DONE;
+ enum gimplify_status tret;
gimple gfor;
gimple_seq for_body, for_pre_body;
int i;
else
var = decl;
- ret |= gimplify_expr (&TREE_OPERAND (t, 1), &for_pre_body, NULL,
+ tret = gimplify_expr (&TREE_OPERAND (t, 1), &for_pre_body, NULL,
is_gimple_val, fb_rvalue);
+ ret = MIN (ret, tret);
if (ret == GS_ERROR)
return ret;
gcc_assert (COMPARISON_CLASS_P (t));
gcc_assert (TREE_OPERAND (t, 0) == decl);
- ret |= gimplify_expr (&TREE_OPERAND (t, 1), &for_pre_body, NULL,
+ tret = gimplify_expr (&TREE_OPERAND (t, 1), &for_pre_body, NULL,
is_gimple_val, fb_rvalue);
+ ret = MIN (ret, tret);
/* Handle OMP_FOR_INCR. */
t = TREE_VEC_ELT (OMP_FOR_INCR (for_stmt), i);
gcc_unreachable ();
}
- ret |= gimplify_expr (&TREE_OPERAND (t, 1), &for_pre_body, NULL,
+ tret = gimplify_expr (&TREE_OPERAND (t, 1), &for_pre_body, NULL,
is_gimple_val, fb_rvalue);
+ ret = MIN (ret, tret);
break;
default:
}
/* Do any language-specific gimplification. */
- ret = lang_hooks.gimplify_expr (expr_p, pre_p, post_p);
+ ret = ((enum gimplify_status)
+ lang_hooks.gimplify_expr (expr_p, pre_p, post_p));
if (ret == GS_OK)
{
if (*expr_p == NULL_TREE)
/* The postqueue might change the value of the expression between
the initialization and use of the temporary, so we can't use a
formal temp. FIXME do we care? */
- *expr_p = get_initialized_tmp_var (*expr_p, pre_p, post_p);
+ {
+ *expr_p = get_initialized_tmp_var (*expr_p, pre_p, post_p);
+ if (TREE_CODE (TREE_TYPE (*expr_p)) == COMPLEX_TYPE
+ || TREE_CODE (TREE_TYPE (*expr_p)) == VECTOR_TYPE)
+ DECL_GIMPLE_REG_P (*expr_p) = 1;
+ }
else
*expr_p = get_formal_tmp_var (*expr_p, pre_p);
}
unshare_body (body_p, fndecl);
unvisit_body (body_p, fndecl);
+ if (cgraph_node (fndecl)->origin)
+ nonlocal_vlas = pointer_set_create ();
+
/* Make sure input_location isn't set to something weird. */
input_location = DECL_SOURCE_LOCATION (fndecl);
gimple_bind_set_body (outer_bind, parm_stmts);
}
+ if (nonlocal_vlas)
+ {
+ pointer_set_destroy (nonlocal_vlas);
+ nonlocal_vlas = NULL;
+ }
+
pop_gimplify_context (outer_bind);
gcc_assert (gimplify_ctxp == NULL);