static struct gimplify_omp_ctx *gimplify_omp_ctxp;
-/* Formal (expression) temporary table handling: Multiple occurrences of
+/* Formal (expression) temporary table handling: multiple occurrences of
the same scalar expression are evaluated into the same temporary. */
typedef struct gimple_temp_hash_elt
tree temp; /* Value */
} elt_t;
-/* Forward declarations. */
+/* Forward declaration. */
static enum gimplify_status gimplify_compound_expr (tree *, gimple_seq *, bool);
/* Mark X addressable. Unlike the langhook we expect X to be in gimple
form and we don't do any syntax checking. */
+
void
mark_addressable (tree x)
{
htab_delete (c->temp_htab);
}
+/* Push a GIMPLE_BIND tuple onto the stack of bindings. */
+
static void
gimple_push_bind_expr (gimple gimple_bind)
{
VEC_safe_push (gimple, heap, gimplify_ctxp->bind_expr_stack, gimple_bind);
}
+/* Pop the first element off the stack of bindings. */
+
static void
gimple_pop_bind_expr (void)
{
VEC_pop (gimple, gimplify_ctxp->bind_expr_stack);
}
+/* Return the first element of the stack of bindings. */
+
gimple
gimple_current_bind_expr (void)
{
return VEC_last (gimple, gimplify_ctxp->bind_expr_stack);
}
-/* Return the stack GIMPLE_BINDs created during gimplification. */
+/* Return the stack of bindings created during gimplification. */
VEC(gimple, heap) *
gimple_bind_expr_stack (void)
return gimplify_ctxp->bind_expr_stack;
}
-/* Returns true iff there is a COND_EXPR between us and the innermost
+/* Return true iff there is a COND_EXPR between us and the innermost
CLEANUP_POINT_EXPR. This info is used by gimple_push_cleanup. */
static bool
}
}
-/* Create a new temporary name with PREFIX. Returns an identifier. */
+/* Create a new temporary name with PREFIX. Return an identifier. */
static GTY(()) unsigned int tmp_var_id_num;
return get_identifier (tmp_name);
}
-
/* Create a new temporary variable declaration of type TYPE.
- Does NOT push it into the current binding. */
+ Do NOT push it into the current binding. */
tree
create_tmp_var_raw (tree type, const char *prefix)
{
tree tmp_var;
- tree new_type;
-
- /* Make the type of the variable writable. */
- new_type = build_type_variant (type, 0, 0);
- TYPE_ATTRIBUTES (new_type) = TYPE_ATTRIBUTES (type);
tmp_var = build_decl (input_location,
VAR_DECL, prefix ? create_tmp_var_name (prefix) : NULL,
return tmp_var;
}
-/* Create a new temporary variable declaration of type TYPE. DOES push the
+/* Create a new temporary variable declaration of type TYPE. DO push the
variable into the current binding. Further, assume that this is called
only from gimplification or optimization, at which point the creation of
certain types are bugs. */
return ret;
}
-
/* Return true if T is a CALL_EXPR or an expression that can be
assigned to a temporary. Note that this predicate should only be
used during gimplification. See the rationale for this in
return t;
}
-/* Returns a formal temporary variable initialized with VAL. PRE_P is as
+/* Return a formal temporary variable initialized with VAL. PRE_P is as
in gimplify_expr. Only use this function if:
1) The value of the unfactored expression represented by VAL will not
return internal_get_tmp_var (val, pre_p, NULL, true);
}
-/* Returns a temporary variable initialized with VAL. PRE_P and POST_P
+/* Return a temporary variable initialized with VAL. PRE_P and POST_P
are as in gimplify_expr. */
tree
return internal_get_tmp_var (val, pre_p, post_p, false);
}
-/* Declares all the variables in VARS in SCOPE. If DEBUG_INFO is
- true, generate debug info for them; otherwise don't. */
+/* Declare all the variables in VARS in SCOPE. If DEBUG_INFO is true,
+ generate debug info for them; otherwise don't. */
void
declare_vars (tree vars, gimple scope, bool debug_info)
= build_int_cst (TREE_TYPE (DECL_SIZE (var)), max_size * BITS_PER_UNIT);
}
+/* Push the temporary variable TMP into the current binding. */
+
void
gimple_add_tmp_var (tree tmp)
{
}
}
-/* Determines whether to assign a location to the statement GS. */
+/* Determine whether to assign a location to the statement GS. */
static bool
should_carry_location_p (gimple gs)
return true;
}
-
/* Return true if a location should not be emitted for this statement
by annotate_one_with_location. */
gimple_set_location (gs, location);
}
-
/* Set LOCATION for all the statements after iterator GSI in sequence
SEQ. If GSI is pointing to the end of the sequence, start with the
first statement in SEQ. */
annotate_one_with_location (gsi_stmt (gsi), location);
}
-
/* Set the location for all the statements in a sequence STMT_P to LOCATION. */
void
\f
/* WRAPPER is a code such as BIND_EXPR or CLEANUP_POINT_EXPR which can both
contain statements and have a value. Assign its value to a temporary
- and give it void_type_node. Returns the temporary, or NULL_TREE if
+ and give it void_type_node. Return the temporary, or NULL_TREE if
WRAPPER was already void. */
tree
break;
case COMPOUND_EXPR:
- /* Advance to the last statement. Set all container types to void. */
+ /* Advance to the last statement. Set all container types to
+ void. */
for (; TREE_CODE (*p) == COMPOUND_EXPR; p = &TREE_OPERAND (*p, 1))
{
TREE_SIDE_EFFECTS (*p) = 1;
{
tree tmp_var;
- *save = gimple_build_call (implicit_built_in_decls[BUILT_IN_STACK_SAVE], 0);
+ *save = gimple_build_call (builtin_decl_implicit (BUILT_IN_STACK_SAVE), 0);
tmp_var = create_tmp_var (ptr_type_node, "saved_stack");
gimple_call_set_lhs (*save, tmp_var);
- *restore = gimple_build_call (implicit_built_in_decls[BUILT_IN_STACK_RESTORE],
- 1, tmp_var);
+ *restore
+ = gimple_build_call (builtin_decl_implicit (BUILT_IN_STACK_RESTORE),
+ 1, tmp_var);
}
/* Gimplify a BIND_EXPR. Just voidify and recurse. */
struct gimplify_omp_ctx *ctx = gimplify_omp_ctxp;
/* Mark variable as local. */
- if (ctx && !is_global_var (t)
+ if (ctx && !DECL_EXTERNAL (t)
&& (! DECL_SEEN_IN_BIND_EXPR_P (t)
|| splay_tree_lookup (ctx->variables,
(splay_tree_key) t) == NULL))
return GS_ALL_DONE;
}
+/* Gimplify a variable-length array DECL. */
+
static void
gimplify_vla_decl (tree decl, gimple_seq *seq_p)
{
SET_DECL_VALUE_EXPR (decl, t);
DECL_HAS_VALUE_EXPR_P (decl) = 1;
- t = built_in_decls[BUILT_IN_ALLOCA];
- t = build_call_expr (t, 1, DECL_SIZE_UNIT (decl));
+ t = builtin_decl_explicit (BUILT_IN_ALLOCA_WITH_ALIGN);
+ t = build_call_expr (t, 2, DECL_SIZE_UNIT (decl),
+ size_int (DECL_ALIGN (decl)));
/* The call has been built for a variable-sized object. */
- ALLOCA_FOR_VAR_P (t) = 1;
+ CALL_ALLOCA_FOR_VAR_P (t) = 1;
t = fold_convert (ptr_type, t);
t = build2 (MODIFY_EXPR, TREE_TYPE (addr), addr, t);
gimplify_ctxp->save_stack = true;
}
-
-/* Gimplifies a DECL_EXPR node *STMT_P by making any necessary allocation
+/* Gimplify a DECL_EXPR node *STMT_P by making any necessary allocation
and initialization explicit. */
static enum gimplify_status
gimplify_seq_add_stmt (pre_p, gimple_build_goto (start_label));
if (gimplify_ctxp->exit_label)
- gimplify_seq_add_stmt (pre_p, gimple_build_label (gimplify_ctxp->exit_label));
+ gimplify_seq_add_stmt (pre_p,
+ gimple_build_label (gimplify_ctxp->exit_label));
gimplify_ctxp->exit_label = saved_label;
return GS_ALL_DONE;
}
-/* Gimplifies a statement list onto a sequence. These may be created either
+/* Gimplify a statement list onto a sequence. These may be created either
by an enlightened front-end, or by shortcut_cond_expr. */
static enum gimplify_status
return tree_int_cst_compare (CASE_LOW (case1), CASE_LOW (case2));
}
-
/* Sort the case labels in LABEL_VEC in place in ascending order. */
void
VEC_qsort (tree, label_vec, compare_case_labels);
}
-
/* Gimplify a SWITCH_EXPR, and collect a TREE_VEC of the labels it can
branch to. */
break;
}
if (i == len)
- default_case = build3 (CASE_LABEL_EXPR, void_type_node,
- NULL_TREE, NULL_TREE,
- CASE_LABEL (VEC_index (tree,
- labels, 0)));
+ {
+ tree label = CASE_LABEL (VEC_index (tree, labels, 0));
+ default_case = build_case_label (NULL_TREE, NULL_TREE,
+ label);
+ }
}
}
gimple new_default;
default_case
- = build3 (CASE_LABEL_EXPR, void_type_node,
- NULL_TREE, NULL_TREE,
- create_artificial_label (UNKNOWN_LOCATION));
+ = build_case_label (NULL_TREE, NULL_TREE,
+ create_artificial_label (UNKNOWN_LOCATION));
new_default = gimple_build_label (CASE_LABEL (default_case));
gimplify_seq_add_stmt (&switch_body_seq, new_default);
}
return GS_ALL_DONE;
}
+/* Gimplify the CASE_LABEL_EXPR pointed to by EXPR_P. */
static enum gimplify_status
gimplify_case_label_expr (tree *expr_p, gimple_seq *pre_p)
static enum gimplify_status
gimplify_conversion (tree *expr_p)
{
- tree tem;
location_t loc = EXPR_LOCATION (*expr_p);
gcc_assert (CONVERT_EXPR_P (*expr_p));
if (tree_ssa_useless_type_conversion (*expr_p))
*expr_p = TREE_OPERAND (*expr_p, 0);
- /* Attempt to avoid NOP_EXPR by producing reference to a subtype.
- For example this fold (subclass *)&A into &A->subclass avoiding
- a need for statement. */
- if (CONVERT_EXPR_P (*expr_p)
- && POINTER_TYPE_P (TREE_TYPE (*expr_p))
- && POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (*expr_p, 0)))
- && (tem = maybe_fold_offset_to_address
- (EXPR_LOCATION (*expr_p), TREE_OPERAND (*expr_p, 0),
- integer_zero_node, TREE_TYPE (*expr_p))) != NULL_TREE)
- *expr_p = tem;
-
/* If we still have a conversion at the toplevel,
then canonicalize some constructs. */
if (CONVERT_EXPR_P (*expr_p))
/* 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
+/* Gimplify a VAR_DECL or PARM_DECL. Return GS_OK if we expanded a
DECL_VALUE_EXPR, and it's worth re-examining things. */
static enum gimplify_status
return GS_ALL_DONE;
}
-
/* Gimplify the COMPONENT_REF, ARRAY_REF, REALPART_EXPR or IMAGPART_EXPR
node *EXPR_P.
ret = MIN (ret, tret);
}
}
+ else
+ {
+ tret = gimplify_expr (&TREE_OPERAND (t, 2), pre_p, post_p,
+ is_gimple_reg, fb_rvalue);
+ ret = MIN (ret, tret);
+ }
- if (!TREE_OPERAND (t, 3))
+ if (TREE_OPERAND (t, 3) == NULL_TREE)
{
tree elmt_type = TREE_TYPE (TREE_TYPE (TREE_OPERAND (t, 0)));
tree elmt_size = unshare_expr (array_ref_element_size (t));
/* Divide the element size by the alignment of the element
type (above). */
- elmt_size = size_binop_loc (loc, EXACT_DIV_EXPR, elmt_size, factor);
+ elmt_size
+ = size_binop_loc (loc, EXACT_DIV_EXPR, elmt_size, factor);
if (!is_gimple_min_invariant (elmt_size))
{
ret = MIN (ret, tret);
}
}
+ else
+ {
+ tret = gimplify_expr (&TREE_OPERAND (t, 3), pre_p, post_p,
+ is_gimple_reg, fb_rvalue);
+ ret = MIN (ret, tret);
+ }
}
else if (TREE_CODE (t) == COMPONENT_REF)
{
/* Set the field offset into T and gimplify it. */
- if (!TREE_OPERAND (t, 2))
+ if (TREE_OPERAND (t, 2) == NULL_TREE)
{
tree offset = unshare_expr (component_ref_field_offset (t));
tree field = TREE_OPERAND (t, 1);
ret = MIN (ret, tret);
}
}
+ else
+ {
+ tret = gimplify_expr (&TREE_OPERAND (t, 2), pre_p, post_p,
+ is_gimple_reg, fb_rvalue);
+ ret = MIN (ret, tret);
+ }
}
}
/* For POINTERs increment, use POINTER_PLUS_EXPR. */
if (POINTER_TYPE_P (TREE_TYPE (lhs)))
{
- rhs = fold_convert_loc (loc, sizetype, rhs);
+ rhs = convert_to_ptrofftype_loc (loc, rhs);
if (arith_code == MINUS_EXPR)
rhs = fold_build1_loc (loc, NEGATE_EXPR, TREE_TYPE (rhs), rhs);
arith_code = POINTER_PLUS_EXPR;
}
}
-
/* If *EXPR_P has a variable sized type, wrap it in a WITH_SIZE_EXPR. */
static void
*expr_p = build2 (WITH_SIZE_EXPR, type, expr, size);
}
-
/* Helper for gimplify_call_expr. Gimplify a single argument *ARG_P
Store any side-effects in PRE_P. CALL_LOCATION is the location of
the CALL_EXPR. */
return gimplify_expr (arg_p, pre_p, NULL, test, fb);
}
-
/* Gimplify the CALL_EXPR node *EXPR_P into the GIMPLE sequence PRE_P.
WANT_VALUE is true if the result of the call is desired. */
new_locus);
append_to_statement_list (t, &expr);
}
- else if (TREE_CODE (pred) == COND_EXPR)
+ else if (TREE_CODE (pred) == COND_EXPR
+ && !VOID_TYPE_P (TREE_TYPE (TREE_OPERAND (pred, 1)))
+ && !VOID_TYPE_P (TREE_TYPE (TREE_OPERAND (pred, 2))))
{
location_t new_locus;
if (a)
if (b) goto yes; else goto no;
else
- if (c) goto yes; else goto no; */
+ if (c) goto yes; else goto no;
+
+ Don't do this if one of the arms has void type, which can happen
+ in C++ when the arm is throw. */
/* Keep the original source location on the first 'if'. Set the source
location of the ? on the second 'if'. */
}
}
- if (TREE_CODE (type) == BOOLEAN_TYPE)
- return expr;
-
switch (TREE_CODE (expr))
{
case TRUTH_AND_EXPR:
case TRUTH_NOT_EXPR:
TREE_OPERAND (expr, 0) = gimple_boolify (TREE_OPERAND (expr, 0));
- /* FALLTHRU */
- case EQ_EXPR: case NE_EXPR:
- case LE_EXPR: case GE_EXPR: case LT_EXPR: case GT_EXPR:
/* These expressions always produce boolean results. */
- TREE_TYPE (expr) = boolean_type_node;
+ if (TREE_CODE (type) != BOOLEAN_TYPE)
+ TREE_TYPE (expr) = boolean_type_node;
return expr;
default:
+ if (COMPARISON_CLASS_P (expr))
+ {
+ /* There expressions always prduce boolean results. */
+ if (TREE_CODE (type) != BOOLEAN_TYPE)
+ TREE_TYPE (expr) = boolean_type_node;
+ return expr;
+ }
/* Other expressions that get here must have boolean values, but
might need to be converted to the appropriate mode. */
+ if (TREE_CODE (type) == BOOLEAN_TYPE)
+ return expr;
return fold_convert_loc (loc, boolean_type_node, expr);
}
}
return MIN (ret, tret);
}
-/* Returns true if evaluating EXPR could trap.
+/* Return true if evaluating EXPR could trap.
EXPR is GENERIC, while tree_could_trap_p can be called
only on GIMPLE. */
to_ptr = build_fold_addr_expr_loc (loc, to);
gimplify_arg (&to_ptr, seq_p, loc);
- t = implicit_built_in_decls[BUILT_IN_MEMCPY];
+ t = builtin_decl_implicit (BUILT_IN_MEMCPY);
gs = gimple_build_call (t, 3, to_ptr, from_ptr, size);
to_ptr = build_fold_addr_expr_loc (loc, to);
gimplify_arg (&to_ptr, seq_p, loc);
- t = implicit_built_in_decls[BUILT_IN_MEMSET];
+ t = builtin_decl_implicit (BUILT_IN_MEMSET);
gs = gimple_build_call (t, 3, to_ptr, integer_zero_node, size);
/* A subroutine of gimplify_init_ctor_preeval. Called via walk_tree,
determine, cautiously, if a CONSTRUCTOR overlaps the lhs of an
- assignment. Returns non-null if we detect a potential overlap. */
+ assignment. Return non-null if we detect a potential overlap. */
struct gimplify_init_ctor_preeval_data
{
{
/* Do not use bitsizetype for ARRAY_REF indices. */
if (TYPE_DOMAIN (TREE_TYPE (object)))
- purpose = fold_convert (TREE_TYPE (TYPE_DOMAIN (TREE_TYPE (object))),
- purpose);
+ purpose
+ = fold_convert (TREE_TYPE (TYPE_DOMAIN (TREE_TYPE (object))),
+ purpose);
cref = build4 (ARRAY_REF, array_elt_type, unshare_expr (object),
purpose, NULL_TREE, NULL_TREE);
}
}
}
-
-/* Returns the appropriate RHS predicate for this LHS. */
+/* Return the appropriate RHS predicate for this LHS. */
gimple_predicate
rhs_predicate_for (tree lhs)
return ctor;
}
-
-
/* A subroutine of gimplify_modify_expr. Break out elements of a
CONSTRUCTOR used as an initializer into separate MODIFY_EXPRs.
case ARRAY_TYPE:
{
struct gimplify_init_ctor_preeval_data preeval_data;
- HOST_WIDE_INT num_type_elements, num_ctor_elements;
- HOST_WIDE_INT num_nonzero_elements;
- bool cleared, valid_const_initializer;
+ HOST_WIDE_INT num_ctor_elements, num_nonzero_elements;
+ bool cleared, complete_p, valid_const_initializer;
/* Aggregate types must lower constructors to initialization of
individual elements. The exception is that a CONSTRUCTOR node
can only do so if it known to be a valid constant initializer. */
valid_const_initializer
= categorize_ctor_elements (ctor, &num_nonzero_elements,
- &num_ctor_elements, &cleared);
+ &num_ctor_elements, &complete_p);
/* If a const aggregate variable is being initialized, then it
should never be a lose to promote the variable to be static. */
parts in, then generate code for the non-constant parts. */
/* TODO. There's code in cp/typeck.c to do this. */
- num_type_elements = count_type_elements (type, true);
-
- /* If count_type_elements could not determine number of type elements
- for a constant-sized object, assume clearing is needed.
- Don't do this for variable-sized objects, as store_constructor
- will ignore the clearing of variable-sized objects. */
- if (num_type_elements < 0 && int_size_in_bytes (type) >= 0)
+ if (int_size_in_bytes (TREE_TYPE (ctor)) < 0)
+ /* store_constructor will ignore the clearing of variable-sized
+ objects. Initializers for such objects must explicitly set
+ every field that needs to be set. */
+ cleared = false;
+ else if (!complete_p)
+ /* If the constructor isn't complete, clear the whole object
+ beforehand.
+
+ ??? This ought not to be needed. For any element not present
+ in the initializer, we should simply set them to zero. Except
+ we'd need to *find* the elements that are not present, and that
+ requires trickery to avoid quadratic compile-time behavior in
+ large cases or excessive memory use in small cases. */
cleared = true;
- /* If there are "lots" of zeros, then block clear the object first. */
- else if (num_type_elements - num_nonzero_elements
+ else if (num_ctor_elements - num_nonzero_elements
> CLEAR_RATIO (optimize_function_for_speed_p (cfun))
- && num_nonzero_elements < num_type_elements/4)
- cleared = true;
- /* ??? This bit ought not be needed. For any element not present
- in the initializer, we should simply set them to zero. Except
- we'd need to *find* the elements that are not present, and that
- requires trickery to avoid quadratic compile-time behavior in
- large cases or excessive memory use in small cases. */
- else if (num_ctor_elements < num_type_elements)
+ && num_nonzero_elements < num_ctor_elements / 4)
+ /* If there are "lots" of zeros, it's more efficient to clear
+ the memory and then set the nonzero elements. */
cleared = true;
+ else
+ cleared = false;
/* If there are "lots" of initialized elements, and all of them
are valid address constants, then the entire initializer can
if (!(rhs_predicate_for (*to_p))(*from_p))
/* If we need a temporary, *to_p isn't accurate. */
use_target = false;
+ /* It's OK to use the return slot directly unless it's an NRV. */
else if (TREE_CODE (*to_p) == RESULT_DECL
&& DECL_NAME (*to_p) == NULL_TREE
&& 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))
|| (DECL_P (*to_p) && DECL_REGISTER (*to_p)))
return ret;
}
-
/* Promote partial stores to COMPLEX variables to total stores. *EXPR_P is
a MODIFY_EXPR with a lhs of a REAL/IMAGPART_EXPR of a variable with
DECL_GIMPLE_REG_P set.
ocode = code == REALPART_EXPR ? IMAGPART_EXPR : REALPART_EXPR;
other = build1 (ocode, TREE_TYPE (rhs), lhs);
+ TREE_NO_WARNING (other) = 1;
other = get_formal_tmp_var (other, pre_p);
realpart = code == REALPART_EXPR ? rhs : other;
return GS_ALL_DONE;
}
-
/* Gimplify the MODIFY_EXPR node pointed to by EXPR_P.
modify_expr
return GS_ALL_DONE;
}
-/* Gimplify a comparison between two variable-sized objects. Do this
- with a call to BUILT_IN_MEMCMP. */
+/* Gimplify a comparison between two variable-sized objects. Do this
+ with a call to BUILT_IN_MEMCMP. */
static enum gimplify_status
gimplify_variable_sized_compare (tree *expr_p)
arg = SUBSTITUTE_PLACEHOLDER_IN_EXPR (arg, op0);
src = build_fold_addr_expr_loc (loc, op1);
dest = build_fold_addr_expr_loc (loc, op0);
- t = implicit_built_in_decls[BUILT_IN_MEMCMP];
+ t = builtin_decl_implicit (BUILT_IN_MEMCMP);
t = build_call_expr_loc (loc, t, 3, dest, src, arg);
expr
return GS_OK;
}
-/* Gimplify a comparison between two aggregate objects of integral scalar
- mode as a comparison between the bitwise equivalent scalar values. */
+/* Gimplify a comparison between two aggregate objects of integral scalar
+ mode as a comparison between the bitwise equivalent scalar values. */
static enum gimplify_status
gimplify_scalar_mode_aggregate_compare (tree *expr_p)
return GS_OK;
}
-/* Gimplify TRUTH_ANDIF_EXPR and TRUTH_ORIF_EXPR expressions. EXPR_P
- points to the expression to gimplify.
-
- Expressions of the form 'a && b' are gimplified to:
-
- a && b ? true : false
-
- LOCUS is the source location to be put on the generated COND_EXPR.
- gimplify_cond_expr will do the rest. */
-
-static enum gimplify_status
-gimplify_boolean_expr (tree *expr_p, location_t locus)
-{
- /* Preserve the original type of the expression. */
- tree type = TREE_TYPE (*expr_p);
-
- *expr_p = build3 (COND_EXPR, type, *expr_p,
- fold_convert_loc (locus, type, boolean_true_node),
- fold_convert_loc (locus, type, boolean_false_node));
-
- SET_EXPR_LOCATION (*expr_p, locus);
-
- return GS_OK;
-}
-
-/* Gimplifies an expression sequence. This function gimplifies each
- expression and re-writes the original expression with the last
+/* Gimplify an expression sequence. This function gimplifies each
+ expression and rewrites the original expression with the last
expression of the sequence in GIMPLE form.
PRE_P points to the list where the side effects for all the
}
}
-
/* Gimplify a SAVE_EXPR node. EXPR_P points to the expression to
gimplify. After gimplification, EXPR_P will point to a new temporary
that holds the original value of the SAVE_EXPR node.
PRE_P points to the list where side effects that must happen before
- *EXPR_P should be stored. */
+ *EXPR_P should be stored. */
static enum gimplify_status
gimplify_save_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p)
return ret;
}
-/* Re-write the ADDR_EXPR node pointed to by EXPR_P
+/* Rewrite the ADDR_EXPR node pointed to by EXPR_P
unary_expr
: ...
return last != gimple_seq_last (*seq_p);
}
-
/* Add FIRSTPRIVATE entries for DECL in the OpenMP the surrounding parallels
to CTX. If entries already exist, force them to be some flavor of private.
If there is no enclosing parallel, do nothing. */
unsigned int nflags;
tree t;
- if (decl == error_mark_node || TREE_TYPE (decl) == error_mark_node)
+ if (error_operand_p (decl))
return;
/* Never elide decls whose type has TREE_ADDRESSABLE set. This means
n = splay_tree_lookup (ctx->variables, (splay_tree_key)decl);
if (n == NULL)
{
- error ("threadprivate variable %qE used in untied task", DECL_NAME (decl));
+ error ("threadprivate variable %qE used in untied task",
+ DECL_NAME (decl));
error_at (ctx->location, "enclosing task");
splay_tree_insert (ctx->variables, (splay_tree_key)decl, 0);
}
unsigned flags = in_code ? GOVD_SEEN : 0;
bool ret = false, shared;
- if (decl == error_mark_node || TREE_TYPE (decl) == error_mark_node)
+ if (error_operand_p (decl))
return false;
/* Threadprivate variables are predetermined. */
do_add:
decl = OMP_CLAUSE_DECL (c);
- if (decl == error_mark_node || TREE_TYPE (decl) == error_mark_node)
+ if (error_operand_p (decl))
{
remove = true;
break;
case OMP_CLAUSE_COPYIN:
case OMP_CLAUSE_COPYPRIVATE:
decl = OMP_CLAUSE_DECL (c);
- if (decl == error_mark_node || TREE_TYPE (decl) == error_mark_node)
+ if (error_operand_p (decl))
{
remove = true;
break;
}
break;
+ case OMP_CLAUSE_FINAL:
case OMP_CLAUSE_IF:
OMP_CLAUSE_OPERAND (c, 0)
= gimple_boolify (OMP_CLAUSE_OPERAND (c, 0));
case OMP_CLAUSE_ORDERED:
case OMP_CLAUSE_UNTIED:
case OMP_CLAUSE_COLLAPSE:
+ case OMP_CLAUSE_MERGEABLE:
break;
case OMP_CLAUSE_DEFAULT:
case OMP_CLAUSE_DEFAULT:
case OMP_CLAUSE_UNTIED:
case OMP_CLAUSE_COLLAPSE:
+ case OMP_CLAUSE_FINAL:
+ case OMP_CLAUSE_MERGEABLE:
break;
default:
return false;
}
-/* Walk *EXPR_P and replace
- appearances of *LHS_ADDR with LHS_VAR. If an expression does not involve
- the lhs, evaluate it into a temporary. Return 1 if the lhs appeared as
- a subexpression, 0 if it did not, or -1 if an error was encountered. */
+/* Walk *EXPR_P and replace appearances of *LHS_ADDR with LHS_VAR. If an
+ expression does not involve the lhs, evaluate it into a temporary.
+ Return 1 if the lhs appeared as a subexpression, 0 if it did not,
+ or -1 if an error was encountered. */
static int
goa_stabilize_expr (tree *expr_p, gimple_seq *pre_p, tree lhs_addr,
saw_lhs |= goa_stabilize_expr (&TREE_OPERAND (expr, 0), pre_p,
lhs_addr, lhs_var);
break;
+ case COMPOUND_EXPR:
+ /* Break out any preevaluations from cp_build_modify_expr. */
+ for (; TREE_CODE (expr) == COMPOUND_EXPR;
+ expr = TREE_OPERAND (expr, 1))
+ gimplify_stmt (&TREE_OPERAND (expr, 0), pre_p);
+ *expr_p = expr;
+ return goa_stabilize_expr (expr_p, pre_p, lhs_addr, lhs_var);
default:
break;
}
return saw_lhs;
}
-
/* Gimplify an OMP_ATOMIC statement. */
static enum gimplify_status
gimplify_omp_atomic (tree *expr_p, gimple_seq *pre_p)
{
tree addr = TREE_OPERAND (*expr_p, 0);
- tree rhs = TREE_OPERAND (*expr_p, 1);
+ tree rhs = TREE_CODE (*expr_p) == OMP_ATOMIC_READ
+ ? NULL : TREE_OPERAND (*expr_p, 1);
tree type = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (addr)));
tree tmp_load;
+ gimple loadstmt, storestmt;
- tmp_load = create_tmp_reg (type, NULL);
- if (goa_stabilize_expr (&rhs, pre_p, addr, tmp_load) < 0)
- return GS_ERROR;
+ tmp_load = create_tmp_reg (type, NULL);
+ if (rhs && goa_stabilize_expr (&rhs, pre_p, addr, tmp_load) < 0)
+ return GS_ERROR;
- if (gimplify_expr (&addr, pre_p, NULL, is_gimple_val, fb_rvalue)
- != GS_ALL_DONE)
- return GS_ERROR;
+ if (gimplify_expr (&addr, pre_p, NULL, is_gimple_val, fb_rvalue)
+ != GS_ALL_DONE)
+ return GS_ERROR;
- gimplify_seq_add_stmt (pre_p, gimple_build_omp_atomic_load (tmp_load, addr));
- if (gimplify_expr (&rhs, pre_p, NULL, is_gimple_val, fb_rvalue)
- != GS_ALL_DONE)
- return GS_ERROR;
- gimplify_seq_add_stmt (pre_p, gimple_build_omp_atomic_store (rhs));
- *expr_p = NULL;
+ loadstmt = gimple_build_omp_atomic_load (tmp_load, addr);
+ gimplify_seq_add_stmt (pre_p, loadstmt);
+ if (rhs && gimplify_expr (&rhs, pre_p, NULL, is_gimple_val, fb_rvalue)
+ != GS_ALL_DONE)
+ return GS_ERROR;
+
+ if (TREE_CODE (*expr_p) == OMP_ATOMIC_READ)
+ rhs = tmp_load;
+ storestmt = gimple_build_omp_atomic_store (rhs);
+ gimplify_seq_add_stmt (pre_p, storestmt);
+ switch (TREE_CODE (*expr_p))
+ {
+ case OMP_ATOMIC_READ:
+ case OMP_ATOMIC_CAPTURE_OLD:
+ *expr_p = tmp_load;
+ gimple_omp_atomic_set_need_value (loadstmt);
+ break;
+ case OMP_ATOMIC_CAPTURE_NEW:
+ *expr_p = rhs;
+ gimple_omp_atomic_set_need_value (storestmt);
+ break;
+ default:
+ *expr_p = NULL;
+ break;
+ }
return GS_ALL_DONE;
}
-
-/* Converts the GENERIC expression tree *EXPR_P to GIMPLE. If the
+/* Convert the GENERIC expression tree *EXPR_P to GIMPLE. If the
expression produces a value to be used as an operand inside a GIMPLE
statement, the value will be stored back in *EXPR_P. This value will
be a tree of class tcc_declaration, tcc_constant, tcc_reference or
case TRUTH_ANDIF_EXPR:
case TRUTH_ORIF_EXPR:
- /* Pass the source location of the outer expression. */
- ret = gimplify_boolean_expr (expr_p, saved_location);
- break;
+ {
+ /* Preserve the original type of the expression and the
+ source location of the outer expression. */
+ tree org_type = TREE_TYPE (*expr_p);
+ *expr_p = gimple_boolify (*expr_p);
+ *expr_p = build3_loc (input_location, COND_EXPR,
+ org_type, *expr_p,
+ fold_convert_loc
+ (input_location,
+ org_type, boolean_true_node),
+ fold_convert_loc
+ (input_location,
+ org_type, boolean_false_node));
+ ret = GS_OK;
+ break;
+ }
case TRUTH_NOT_EXPR:
- if (TREE_CODE (TREE_TYPE (*expr_p)) != BOOLEAN_TYPE)
- {
- tree type = TREE_TYPE (*expr_p);
- *expr_p = fold_convert (type, gimple_boolify (*expr_p));
- ret = GS_OK;
- break;
- }
-
- ret = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p,
- is_gimple_val, fb_rvalue);
- recalculate_side_effects (*expr_p);
- break;
+ {
+ tree type = TREE_TYPE (*expr_p);
+ /* The parsers are careful to generate TRUTH_NOT_EXPR
+ only with operands that are always zero or one.
+ We do not fold here but handle the only interesting case
+ manually, as fold may re-introduce the TRUTH_NOT_EXPR. */
+ *expr_p = gimple_boolify (*expr_p);
+ if (TYPE_PRECISION (TREE_TYPE (*expr_p)) == 1)
+ *expr_p = build1_loc (input_location, BIT_NOT_EXPR,
+ TREE_TYPE (*expr_p),
+ TREE_OPERAND (*expr_p, 0));
+ else
+ *expr_p = build2_loc (input_location, BIT_XOR_EXPR,
+ TREE_TYPE (*expr_p),
+ TREE_OPERAND (*expr_p, 0),
+ build_int_cst (TREE_TYPE (*expr_p), 1));
+ if (!useless_type_conversion_p (type, TREE_TYPE (*expr_p)))
+ *expr_p = fold_convert_loc (input_location, type, *expr_p);
+ ret = GS_OK;
+ break;
+ }
case ADDR_EXPR:
ret = gimplify_addr_expr (expr_p, pre_p, post_p);
}
case OMP_ATOMIC:
+ case OMP_ATOMIC_READ:
+ case OMP_ATOMIC_CAPTURE_OLD:
+ case OMP_ATOMIC_CAPTURE_NEW:
ret = gimplify_omp_atomic (expr_p, pre_p);
break;
case TRUTH_AND_EXPR:
case TRUTH_OR_EXPR:
case TRUTH_XOR_EXPR:
- /* Classified as tcc_expression. */
- goto expr_2;
+ {
+ tree orig_type = TREE_TYPE (*expr_p);
+ tree new_type, xop0, xop1;
+ *expr_p = gimple_boolify (*expr_p);
+ new_type = TREE_TYPE (*expr_p);
+ if (!useless_type_conversion_p (orig_type, new_type))
+ {
+ *expr_p = fold_convert_loc (input_location, orig_type, *expr_p);
+ ret = GS_OK;
+ break;
+ }
+
+ /* Boolified binary truth expressions are semantically equivalent
+ to bitwise binary expressions. Canonicalize them to the
+ bitwise variant. */
+ switch (TREE_CODE (*expr_p))
+ {
+ case TRUTH_AND_EXPR:
+ TREE_SET_CODE (*expr_p, BIT_AND_EXPR);
+ break;
+ case TRUTH_OR_EXPR:
+ TREE_SET_CODE (*expr_p, BIT_IOR_EXPR);
+ break;
+ case TRUTH_XOR_EXPR:
+ TREE_SET_CODE (*expr_p, BIT_XOR_EXPR);
+ break;
+ default:
+ break;
+ }
+ /* Now make sure that operands have compatible type to
+ expression's new_type. */
+ xop0 = TREE_OPERAND (*expr_p, 0);
+ xop1 = TREE_OPERAND (*expr_p, 1);
+ if (!useless_type_conversion_p (new_type, TREE_TYPE (xop0)))
+ TREE_OPERAND (*expr_p, 0) = fold_convert_loc (input_location,
+ new_type,
+ xop0);
+ if (!useless_type_conversion_p (new_type, TREE_TYPE (xop1)))
+ TREE_OPERAND (*expr_p, 1) = fold_convert_loc (input_location,
+ new_type,
+ xop1);
+ /* Continue classified as tcc_binary. */
+ goto expr_2;
+ }
case FMA_EXPR:
+ case VEC_PERM_EXPR:
/* Classified as tcc_expression. */
goto expr_3;
case POINTER_PLUS_EXPR:
- /* Convert ((type *)A)+offset into &A->field_of_type_and_offset.
- The second is gimple immediate saving a need for extra statement.
- */
- if (TREE_CODE (TREE_OPERAND (*expr_p, 1)) == INTEGER_CST
- && (tmp = maybe_fold_offset_to_address
- (EXPR_LOCATION (*expr_p),
- TREE_OPERAND (*expr_p, 0), TREE_OPERAND (*expr_p, 1),
- TREE_TYPE (*expr_p))))
- {
- *expr_p = tmp;
- ret = GS_OK;
- break;
- }
- /* Convert (void *)&a + 4 into (void *)&a[1]. */
- if (TREE_CODE (TREE_OPERAND (*expr_p, 0)) == NOP_EXPR
- && TREE_CODE (TREE_OPERAND (*expr_p, 1)) == INTEGER_CST
- && POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (*expr_p,
- 0),0)))
- && (tmp = maybe_fold_offset_to_address
- (EXPR_LOCATION (*expr_p),
- TREE_OPERAND (TREE_OPERAND (*expr_p, 0), 0),
- TREE_OPERAND (*expr_p, 1),
- TREE_TYPE (TREE_OPERAND (TREE_OPERAND (*expr_p, 0),
- 0)))))
- {
- *expr_p = fold_convert (TREE_TYPE (*expr_p), tmp);
- ret = GS_OK;
- break;
- }
- /* FALLTHRU */
+ {
+ enum gimplify_status r0, r1;
+ r0 = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p,
+ post_p, is_gimple_val, fb_rvalue);
+ r1 = gimplify_expr (&TREE_OPERAND (*expr_p, 1), pre_p,
+ post_p, is_gimple_val, fb_rvalue);
+ recalculate_side_effects (*expr_p);
+ ret = MIN (r0, r1);
+ /* Convert &X + CST to invariant &MEM[&X, CST]. Do this
+ after gimplifying operands - this is similar to how
+ it would be folding all gimplified stmts on creation
+ to have them canonicalized, which is what we eventually
+ should do anyway. */
+ if (TREE_CODE (TREE_OPERAND (*expr_p, 1)) == INTEGER_CST
+ && is_gimple_min_invariant (TREE_OPERAND (*expr_p, 0)))
+ {
+ *expr_p = build_fold_addr_expr_with_type_loc
+ (input_location,
+ fold_build2 (MEM_REF, TREE_TYPE (TREE_TYPE (*expr_p)),
+ TREE_OPERAND (*expr_p, 0),
+ fold_convert (ptr_type_node,
+ TREE_OPERAND (*expr_p, 1))),
+ TREE_TYPE (*expr_p));
+ ret = MIN (ret, GS_OK);
+ }
+ break;
+ }
default:
switch (TREE_CODE_CLASS (TREE_CODE (*expr_p)))
{
tree type = TREE_TYPE (TREE_OPERAND (*expr_p, 1));
- if (!AGGREGATE_TYPE_P (type))
+ /* Vector comparisons need no boolification. */
+ if (TREE_CODE (type) == VECTOR_TYPE)
goto expr_2;
+ else if (!AGGREGATE_TYPE_P (type))
+ {
+ tree org_type = TREE_TYPE (*expr_p);
+ *expr_p = gimple_boolify (*expr_p);
+ if (!useless_type_conversion_p (org_type,
+ TREE_TYPE (*expr_p)))
+ {
+ *expr_p = fold_convert_loc (input_location,
+ org_type, *expr_p);
+ ret = GS_OK;
+ }
+ else
+ goto expr_2;
+ }
else if (TYPE_MODE (type) != BLKmode)
ret = gimplify_scalar_mode_aggregate_compare (expr_p);
else
}
}
-
/* Gimplify the body of statements pointed to by BODY_P and return a
GIMPLE_BIND containing the sequence of GIMPLE statements
corresponding to BODY_P. FNDECL is the function decl containing
/* Entry point to the gimplification pass. FNDECL is the FUNCTION_DECL
node for the function we want to gimplify.
- Returns the sequence of GIMPLE statements corresponding to the body
+ Return the sequence of GIMPLE statements corresponding to the body
of FNDECL. */
void
tree tmp_var;
gimple call;
- x = implicit_built_in_decls[BUILT_IN_RETURN_ADDRESS];
+ x = builtin_decl_implicit (BUILT_IN_RETURN_ADDRESS);
call = gimple_build_call (x, 1, integer_zero_node);
tmp_var = create_tmp_var (ptr_type_node, "return_addr");
gimple_call_set_lhs (call, tmp_var);
gimplify_seq_add_stmt (&cleanup, call);
- x = implicit_built_in_decls[BUILT_IN_PROFILE_FUNC_EXIT];
+ x = builtin_decl_implicit (BUILT_IN_PROFILE_FUNC_EXIT);
call = gimple_build_call (x, 2,
build_fold_addr_expr (current_function_decl),
tmp_var);
gimplify_seq_add_stmt (&cleanup, call);
tf = gimple_build_try (seq, cleanup, GIMPLE_TRY_FINALLY);
- x = implicit_built_in_decls[BUILT_IN_RETURN_ADDRESS];
+ x = builtin_decl_implicit (BUILT_IN_RETURN_ADDRESS);
call = gimple_build_call (x, 1, integer_zero_node);
tmp_var = create_tmp_var (ptr_type_node, "return_addr");
gimple_call_set_lhs (call, tmp_var);
gimplify_seq_add_stmt (&body, call);
- x = implicit_built_in_decls[BUILT_IN_PROFILE_FUNC_ENTER];
+ x = builtin_decl_implicit (BUILT_IN_PROFILE_FUNC_ENTER);
call = gimple_build_call (x, 2,
build_fold_addr_expr (current_function_decl),
tmp_var);
pop_cfun ();
}
-
/* Some transformations like inlining may invalidate the GIMPLE form
for operands. This function traverses all the operands in STMT and
gimplifies anything that is not a valid gimple operand. Any new
pop_gimplify_context (NULL);
}
-
-/* Expands EXPR to list of gimple statements STMTS. GIMPLE_TEST_F specifies
+/* Expand EXPR to list of gimple statements STMTS. GIMPLE_TEST_F specifies
the predicate that will hold for the result. If VAR is not NULL, make the
base variable of the final destination be VAR if suitable. */
return expr;
}
-/* Expands EXPR to list of gimple statements STMTS. If SIMPLE is true,
+/* Expand EXPR to list of gimple statements STMTS. If SIMPLE is true,
force the result to be either ssa_name or an invariant, otherwise
just force it to be a rhs expression. If VAR is not NULL, make the
base variable of the final destination be VAR if suitable. */
var);
}
-/* Invokes force_gimple_operand_1 for EXPR with parameters GIMPLE_TEST_F
+/* Invoke force_gimple_operand_1 for EXPR with parameters GIMPLE_TEST_F
and VAR. If some statements are produced, emits them at GSI.
If BEFORE is true. the statements are appended before GSI, otherwise
they are appended after it. M specifies the way GSI moves after
return expr;
}
-/* Invokes force_gimple_operand_1 for EXPR with parameter VAR.
+/* Invoke force_gimple_operand_1 for EXPR with parameter VAR.
If SIMPLE is true, force the result to be either ssa_name or an invariant,
otherwise just force it to be a rhs expression. If some statements are
produced, emits them at GSI. If BEFORE is true, the statements are