-
-/* Visit the conditional statement STMT. Return SSA_PROP_INTERESTING
- if it can determine which edge will be taken. Otherwise, return
- SSA_PROP_VARYING. */
-
-static enum ssa_prop_result
-visit_cond_stmt (gimple stmt, edge *taken_edge_p)
-{
- prop_value_t val;
- basic_block block;
-
- block = gimple_bb (stmt);
- val = evaluate_stmt (stmt);
-
- /* Find which edge out of the conditional block will be taken and add it
- to the worklist. If no single edge can be determined statically,
- return SSA_PROP_VARYING to feed all the outgoing edges to the
- propagation engine. */
- *taken_edge_p = val.value ? find_taken_edge (block, val.value) : 0;
- if (*taken_edge_p)
- return SSA_PROP_INTERESTING;
- else
- return SSA_PROP_VARYING;
-}
-
-
-/* Evaluate statement STMT. If the statement produces an output value and
- its evaluation changes the lattice value of its output, return
- SSA_PROP_INTERESTING and set *OUTPUT_P to the SSA_NAME holding the
- output value.
-
- If STMT is a conditional branch and we can determine its truth
- value, set *TAKEN_EDGE_P accordingly. If STMT produces a varying
- value, return SSA_PROP_VARYING. */
-
-static enum ssa_prop_result
-ccp_visit_stmt (gimple stmt, edge *taken_edge_p, tree *output_p)
-{
- tree def;
- ssa_op_iter iter;
-
- if (dump_file && (dump_flags & TDF_DETAILS))
- {
- fprintf (dump_file, "\nVisiting statement:\n");
- print_gimple_stmt (dump_file, stmt, 0, dump_flags);
- }
-
- switch (gimple_code (stmt))
- {
- case GIMPLE_ASSIGN:
- /* If the statement is an assignment that produces a single
- output value, evaluate its RHS to see if the lattice value of
- its output has changed. */
- return visit_assignment (stmt, output_p);
-
- case GIMPLE_CALL:
- /* A value-returning call also performs an assignment. */
- if (gimple_call_lhs (stmt) != NULL_TREE)
- return visit_assignment (stmt, output_p);
- break;
-
- case GIMPLE_COND:
- case GIMPLE_SWITCH:
- /* If STMT is a conditional branch, see if we can determine
- which branch will be taken. */
- /* FIXME. It appears that we should be able to optimize
- computed GOTOs here as well. */
- return visit_cond_stmt (stmt, taken_edge_p);
-
- default:
- break;
- }
-
- /* Any other kind of statement is not interesting for constant
- propagation and, therefore, not worth simulating. */
- if (dump_file && (dump_flags & TDF_DETAILS))
- fprintf (dump_file, "No interesting values produced. Marked VARYING.\n");
-
- /* Definitions made by statements other than assignments to
- SSA_NAMEs represent unknown modifications to their outputs.
- Mark them VARYING. */
- FOR_EACH_SSA_TREE_OPERAND (def, stmt, iter, SSA_OP_ALL_DEFS)
- {
- prop_value_t v = { VARYING, NULL_TREE };
- set_lattice_value (def, v);
- }
-
- return SSA_PROP_VARYING;
-}
-
-
-/* Main entry point for SSA Conditional Constant Propagation. */
-
-static unsigned int
-do_ssa_ccp (void)
-{
- ccp_initialize ();
- ssa_propagate (ccp_visit_stmt, ccp_visit_phi_node);
- if (ccp_finalize ())
- return (TODO_cleanup_cfg | TODO_update_ssa | TODO_remove_unused_locals);
- else
- return 0;
-}
-
-
-static bool
-gate_ccp (void)
-{
- return flag_tree_ccp != 0;
-}
-
-
-struct gimple_opt_pass pass_ccp =
-{
- {
- GIMPLE_PASS,
- "ccp", /* name */
- gate_ccp, /* gate */
- do_ssa_ccp, /* execute */
- NULL, /* sub */
- NULL, /* next */
- 0, /* static_pass_number */
- TV_TREE_CCP, /* tv_id */
- PROP_cfg | PROP_ssa, /* properties_required */
- 0, /* properties_provided */
- 0, /* properties_destroyed */
- 0, /* todo_flags_start */
- TODO_dump_func | TODO_verify_ssa
- | TODO_verify_stmts | TODO_ggc_collect/* todo_flags_finish */
- }
-};
-
-
-/* A subroutine of fold_stmt_r. Attempts to fold *(A+O) to A[X].
- BASE is an array type. OFFSET is a byte displacement. ORIG_TYPE
- is the desired result type. */
-
-static tree
-maybe_fold_offset_to_array_ref (tree base, tree offset, tree orig_type,
- bool allow_negative_idx)
-{
- tree min_idx, idx, idx_type, elt_offset = integer_zero_node;
- tree array_type, elt_type, elt_size;
- tree domain_type;
-
- /* If BASE is an ARRAY_REF, we can pick up another offset (this time
- measured in units of the size of elements type) from that ARRAY_REF).
- We can't do anything if either is variable.
-
- The case we handle here is *(&A[N]+O). */
- if (TREE_CODE (base) == ARRAY_REF)
- {
- tree low_bound = array_ref_low_bound (base);
-
- elt_offset = TREE_OPERAND (base, 1);
- if (TREE_CODE (low_bound) != INTEGER_CST
- || TREE_CODE (elt_offset) != INTEGER_CST)
- return NULL_TREE;
-
- elt_offset = int_const_binop (MINUS_EXPR, elt_offset, low_bound, 0);
- base = TREE_OPERAND (base, 0);
- }
-
- /* Ignore stupid user tricks of indexing non-array variables. */
- array_type = TREE_TYPE (base);
- if (TREE_CODE (array_type) != ARRAY_TYPE)
- return NULL_TREE;
- elt_type = TREE_TYPE (array_type);
- if (!useless_type_conversion_p (orig_type, elt_type))
- return NULL_TREE;
-
- /* Use signed size type for intermediate computation on the index. */
- idx_type = signed_type_for (size_type_node);
-
- /* If OFFSET and ELT_OFFSET are zero, we don't care about the size of the
- element type (so we can use the alignment if it's not constant).
- Otherwise, compute the offset as an index by using a division. If the
- division isn't exact, then don't do anything. */
- elt_size = TYPE_SIZE_UNIT (elt_type);
- if (!elt_size)
- return NULL;
- if (integer_zerop (offset))
- {
- if (TREE_CODE (elt_size) != INTEGER_CST)
- elt_size = size_int (TYPE_ALIGN (elt_type));
-
- idx = build_int_cst (idx_type, 0);
- }
- else
- {
- unsigned HOST_WIDE_INT lquo, lrem;
- HOST_WIDE_INT hquo, hrem;
- double_int soffset;
-
- /* The final array offset should be signed, so we need
- to sign-extend the (possibly pointer) offset here
- and use signed division. */
- soffset = double_int_sext (tree_to_double_int (offset),
- TYPE_PRECISION (TREE_TYPE (offset)));
- if (TREE_CODE (elt_size) != INTEGER_CST
- || div_and_round_double (TRUNC_DIV_EXPR, 0,
- soffset.low, soffset.high,
- TREE_INT_CST_LOW (elt_size),
- TREE_INT_CST_HIGH (elt_size),
- &lquo, &hquo, &lrem, &hrem)
- || lrem || hrem)
- return NULL_TREE;
-
- idx = build_int_cst_wide (idx_type, lquo, hquo);
- }
-
- /* Assume the low bound is zero. If there is a domain type, get the
- low bound, if any, convert the index into that type, and add the
- low bound. */
- min_idx = build_int_cst (idx_type, 0);
- domain_type = TYPE_DOMAIN (array_type);
- if (domain_type)
- {
- idx_type = domain_type;
- if (TYPE_MIN_VALUE (idx_type))
- min_idx = TYPE_MIN_VALUE (idx_type);
- else
- min_idx = fold_convert (idx_type, min_idx);
-
- if (TREE_CODE (min_idx) != INTEGER_CST)
- return NULL_TREE;
-
- elt_offset = fold_convert (idx_type, elt_offset);
- }
-
- if (!integer_zerop (min_idx))
- idx = int_const_binop (PLUS_EXPR, idx, min_idx, 0);
- if (!integer_zerop (elt_offset))
- idx = int_const_binop (PLUS_EXPR, idx, elt_offset, 0);
-
- /* Make sure to possibly truncate late after offsetting. */
- idx = fold_convert (idx_type, idx);
-
- /* We don't want to construct access past array bounds. For example
- char *(c[4]);
- c[3][2];
- should not be simplified into (*c)[14] or tree-vrp will
- give false warnings. The same is true for
- struct A { long x; char d[0]; } *a;
- (char *)a - 4;
- which should be not folded to &a->d[-8]. */
- if (domain_type
- && TYPE_MAX_VALUE (domain_type)
- && TREE_CODE (TYPE_MAX_VALUE (domain_type)) == INTEGER_CST)
- {
- tree up_bound = TYPE_MAX_VALUE (domain_type);
-
- if (tree_int_cst_lt (up_bound, idx)
- /* Accesses after the end of arrays of size 0 (gcc
- extension) and 1 are likely intentional ("struct
- hack"). */
- && compare_tree_int (up_bound, 1) > 0)
- return NULL_TREE;
- }
- if (domain_type
- && TYPE_MIN_VALUE (domain_type))
- {
- if (!allow_negative_idx
- && TREE_CODE (TYPE_MIN_VALUE (domain_type)) == INTEGER_CST
- && tree_int_cst_lt (idx, TYPE_MIN_VALUE (domain_type)))
- return NULL_TREE;
- }
- else if (!allow_negative_idx
- && compare_tree_int (idx, 0) < 0)
- return NULL_TREE;
-
- return build4 (ARRAY_REF, elt_type, base, idx, NULL_TREE, NULL_TREE);
-}
-
-
-/* Attempt to fold *(S+O) to S.X.
- BASE is a record type. OFFSET is a byte displacement. ORIG_TYPE
- is the desired result type. */
-
-static tree
-maybe_fold_offset_to_component_ref (tree record_type, tree base, tree offset,
- tree orig_type, bool base_is_ptr)
-{
- tree f, t, field_type, tail_array_field, field_offset;
- tree ret;
- tree new_base;
-
- if (TREE_CODE (record_type) != RECORD_TYPE
- && TREE_CODE (record_type) != UNION_TYPE
- && TREE_CODE (record_type) != QUAL_UNION_TYPE)
- return NULL_TREE;
-
- /* Short-circuit silly cases. */
- if (useless_type_conversion_p (record_type, orig_type))
- return NULL_TREE;
-
- tail_array_field = NULL_TREE;
- for (f = TYPE_FIELDS (record_type); f ; f = TREE_CHAIN (f))
- {
- int cmp;
-
- if (TREE_CODE (f) != FIELD_DECL)
- continue;
- if (DECL_BIT_FIELD (f))
- continue;
-
- if (!DECL_FIELD_OFFSET (f))
- continue;
- field_offset = byte_position (f);
- if (TREE_CODE (field_offset) != INTEGER_CST)
- continue;
-
- /* ??? Java creates "interesting" fields for representing base classes.
- They have no name, and have no context. With no context, we get into
- trouble with nonoverlapping_component_refs_p. Skip them. */
- if (!DECL_FIELD_CONTEXT (f))
- continue;
-
- /* The previous array field isn't at the end. */
- tail_array_field = NULL_TREE;
-
- /* Check to see if this offset overlaps with the field. */
- cmp = tree_int_cst_compare (field_offset, offset);
- if (cmp > 0)
- continue;
-
- field_type = TREE_TYPE (f);
-
- /* Here we exactly match the offset being checked. If the types match,
- then we can return that field. */
- if (cmp == 0
- && useless_type_conversion_p (orig_type, field_type))
- {
- if (base_is_ptr)
- base = build1 (INDIRECT_REF, record_type, base);
- t = build3 (COMPONENT_REF, field_type, base, f, NULL_TREE);
- return t;
- }
-
- /* Don't care about offsets into the middle of scalars. */
- if (!AGGREGATE_TYPE_P (field_type))
- continue;
-
- /* Check for array at the end of the struct. This is often
- used as for flexible array members. We should be able to
- turn this into an array access anyway. */
- if (TREE_CODE (field_type) == ARRAY_TYPE)
- tail_array_field = f;
-
- /* Check the end of the field against the offset. */
- if (!DECL_SIZE_UNIT (f)
- || TREE_CODE (DECL_SIZE_UNIT (f)) != INTEGER_CST)
- continue;
- t = int_const_binop (MINUS_EXPR, offset, field_offset, 1);
- if (!tree_int_cst_lt (t, DECL_SIZE_UNIT (f)))
- continue;
-
- /* If we matched, then set offset to the displacement into
- this field. */
- if (base_is_ptr)
- new_base = build1 (INDIRECT_REF, record_type, base);
- else
- new_base = base;
- new_base = build3 (COMPONENT_REF, field_type, new_base, f, NULL_TREE);
-
- /* Recurse to possibly find the match. */
- ret = maybe_fold_offset_to_array_ref (new_base, t, orig_type,
- f == TYPE_FIELDS (record_type));
- if (ret)
- return ret;
- ret = maybe_fold_offset_to_component_ref (field_type, new_base, t,
- orig_type, false);
- if (ret)
- return ret;
- }
-
- if (!tail_array_field)
- return NULL_TREE;
-
- f = tail_array_field;
- field_type = TREE_TYPE (f);
- offset = int_const_binop (MINUS_EXPR, offset, byte_position (f), 1);
-
- /* If we get here, we've got an aggregate field, and a possibly
- nonzero offset into them. Recurse and hope for a valid match. */
- if (base_is_ptr)
- base = build1 (INDIRECT_REF, record_type, base);
- base = build3 (COMPONENT_REF, field_type, base, f, NULL_TREE);
-
- t = maybe_fold_offset_to_array_ref (base, offset, orig_type,
- f == TYPE_FIELDS (record_type));
- if (t)
- return t;
- return maybe_fold_offset_to_component_ref (field_type, base, offset,
- orig_type, false);
-}
-
-/* Attempt to express (ORIG_TYPE)BASE+OFFSET as BASE->field_of_orig_type
- or BASE[index] or by combination of those.
-
- Before attempting the conversion strip off existing ADDR_EXPRs and
- handled component refs. */
-
-tree
-maybe_fold_offset_to_reference (tree base, tree offset, tree orig_type)
-{
- tree ret;
- tree type;
- bool base_is_ptr = true;
-
- STRIP_NOPS (base);
- if (TREE_CODE (base) == ADDR_EXPR)
- {
- base_is_ptr = false;
-
- base = TREE_OPERAND (base, 0);
-
- /* Handle case where existing COMPONENT_REF pick e.g. wrong field of union,
- so it needs to be removed and new COMPONENT_REF constructed.
- The wrong COMPONENT_REF are often constructed by folding the
- (type *)&object within the expression (type *)&object+offset */
- if (handled_component_p (base))
- {
- HOST_WIDE_INT sub_offset, size, maxsize;
- tree newbase;
- newbase = get_ref_base_and_extent (base, &sub_offset,
- &size, &maxsize);
- gcc_assert (newbase);
- if (size == maxsize
- && size != -1
- && !(sub_offset & (BITS_PER_UNIT - 1)))
- {
- base = newbase;
- if (sub_offset)
- offset = int_const_binop (PLUS_EXPR, offset,
- build_int_cst (TREE_TYPE (offset),
- sub_offset / BITS_PER_UNIT), 1);
- }
- }
- if (useless_type_conversion_p (orig_type, TREE_TYPE (base))
- && integer_zerop (offset))
- return base;
- type = TREE_TYPE (base);
- }
- else
- {
- base_is_ptr = true;
- if (!POINTER_TYPE_P (TREE_TYPE (base)))
- return NULL_TREE;
- type = TREE_TYPE (TREE_TYPE (base));
- }
- ret = maybe_fold_offset_to_component_ref (type, base, offset,
- orig_type, base_is_ptr);
- if (!ret)
- {
- if (base_is_ptr)
- base = build1 (INDIRECT_REF, type, base);
- ret = maybe_fold_offset_to_array_ref (base, offset, orig_type, true);
- }
- return ret;
-}
-
-/* Attempt to express (ORIG_TYPE)&BASE+OFFSET as &BASE->field_of_orig_type
- or &BASE[index] or by combination of those.
-
- Before attempting the conversion strip off existing component refs. */
-
-tree
-maybe_fold_offset_to_address (tree addr, tree offset, tree orig_type)
-{
- tree t;
-
- gcc_assert (POINTER_TYPE_P (TREE_TYPE (addr))
- && POINTER_TYPE_P (orig_type));
-
- t = maybe_fold_offset_to_reference (addr, offset, TREE_TYPE (orig_type));
- if (t != NULL_TREE)
- {
- tree orig = addr;
- tree ptr_type;
-
- /* For __builtin_object_size to function correctly we need to
- make sure not to fold address arithmetic so that we change
- reference from one array to another. This would happen for
- example for
-
- struct X { char s1[10]; char s2[10] } s;
- char *foo (void) { return &s.s2[-4]; }
-
- where we need to avoid generating &s.s1[6]. As the C and
- C++ frontends create different initial trees
- (char *) &s.s1 + -4 vs. &s.s1[-4] we have to do some
- sophisticated comparisons here. Note that checking for the
- condition after the fact is easier than trying to avoid doing
- the folding. */
- STRIP_NOPS (orig);
- if (TREE_CODE (orig) == ADDR_EXPR)
- orig = TREE_OPERAND (orig, 0);
- if ((TREE_CODE (orig) == ARRAY_REF
- || (TREE_CODE (orig) == COMPONENT_REF
- && TREE_CODE (TREE_TYPE (TREE_OPERAND (orig, 1))) == ARRAY_TYPE))
- && (TREE_CODE (t) == ARRAY_REF
- || TREE_CODE (t) == COMPONENT_REF)
- && !operand_equal_p (TREE_CODE (orig) == ARRAY_REF
- ? TREE_OPERAND (orig, 0) : orig,
- TREE_CODE (t) == ARRAY_REF
- ? TREE_OPERAND (t, 0) : t, 0))
- return NULL_TREE;
-
- ptr_type = build_pointer_type (TREE_TYPE (t));
- if (!useless_type_conversion_p (orig_type, ptr_type))
- return NULL_TREE;
- return build_fold_addr_expr_with_type (t, ptr_type);
- }
-
- return NULL_TREE;
-}
-
-/* A subroutine of fold_stmt_r. Attempt to simplify *(BASE+OFFSET).
- Return the simplified expression, or NULL if nothing could be done. */
-
-static tree
-maybe_fold_stmt_indirect (tree expr, tree base, tree offset)
-{
- tree t;
- bool volatile_p = TREE_THIS_VOLATILE (expr);
-
- /* We may well have constructed a double-nested PLUS_EXPR via multiple
- substitutions. Fold that down to one. Remove NON_LVALUE_EXPRs that
- are sometimes added. */
- base = fold (base);
- STRIP_TYPE_NOPS (base);
- TREE_OPERAND (expr, 0) = base;
-
- /* One possibility is that the address reduces to a string constant. */
- t = fold_read_from_constant_string (expr);
- if (t)
- return t;
-
- /* Add in any offset from a POINTER_PLUS_EXPR. */
- if (TREE_CODE (base) == POINTER_PLUS_EXPR)
- {
- tree offset2;
-
- offset2 = TREE_OPERAND (base, 1);
- if (TREE_CODE (offset2) != INTEGER_CST)
- return NULL_TREE;
- base = TREE_OPERAND (base, 0);
-
- offset = fold_convert (sizetype,
- int_const_binop (PLUS_EXPR, offset, offset2, 1));
- }
-
- if (TREE_CODE (base) == ADDR_EXPR)
- {
- tree base_addr = base;
-
- /* Strip the ADDR_EXPR. */
- base = TREE_OPERAND (base, 0);
-
- /* Fold away CONST_DECL to its value, if the type is scalar. */
- if (TREE_CODE (base) == CONST_DECL
- && is_gimple_min_invariant (DECL_INITIAL (base)))
- return DECL_INITIAL (base);
-
- /* Try folding *(&B+O) to B.X. */
- t = maybe_fold_offset_to_reference (base_addr, offset,
- TREE_TYPE (expr));
- if (t)
- {
- /* Preserve volatileness of the original expression.
- We can end up with a plain decl here which is shared
- and we shouldn't mess with its flags. */
- if (!SSA_VAR_P (t))
- TREE_THIS_VOLATILE (t) = volatile_p;
- return t;
- }
- }
- else
- {
- /* We can get here for out-of-range string constant accesses,
- such as "_"[3]. Bail out of the entire substitution search
- and arrange for the entire statement to be replaced by a
- call to __builtin_trap. In all likelihood this will all be
- constant-folded away, but in the meantime we can't leave with
- something that get_expr_operands can't understand. */
-
- t = base;
- STRIP_NOPS (t);
- if (TREE_CODE (t) == ADDR_EXPR
- && TREE_CODE (TREE_OPERAND (t, 0)) == STRING_CST)
- {
- /* FIXME: Except that this causes problems elsewhere with dead
- code not being deleted, and we die in the rtl expanders
- because we failed to remove some ssa_name. In the meantime,
- just return zero. */
- /* FIXME2: This condition should be signaled by
- fold_read_from_constant_string directly, rather than
- re-checking for it here. */
- return integer_zero_node;
- }
-
- /* Try folding *(B+O) to B->X. Still an improvement. */
- if (POINTER_TYPE_P (TREE_TYPE (base)))
- {
- t = maybe_fold_offset_to_reference (base, offset,
- TREE_TYPE (expr));
- if (t)
- return t;
- }
- }
-
- /* Otherwise we had an offset that we could not simplify. */
- return NULL_TREE;
-}
-
-
-/* A quaint feature extant in our address arithmetic is that there
- can be hidden type changes here. The type of the result need
- not be the same as the type of the input pointer.
-
- What we're after here is an expression of the form
- (T *)(&array + const)
- where array is OP0, const is OP1, RES_TYPE is T and
- the cast doesn't actually exist, but is implicit in the
- type of the POINTER_PLUS_EXPR. We'd like to turn this into
- &array[x]
- which may be able to propagate further. */
-
-tree
-maybe_fold_stmt_addition (tree res_type, tree op0, tree op1)
-{
- tree ptd_type;
- tree t;
-
- /* It had better be a constant. */
- if (TREE_CODE (op1) != INTEGER_CST)
- return NULL_TREE;
- /* The first operand should be an ADDR_EXPR. */
- if (TREE_CODE (op0) != ADDR_EXPR)
- return NULL_TREE;
- op0 = TREE_OPERAND (op0, 0);
-
- /* If the first operand is an ARRAY_REF, expand it so that we can fold
- the offset into it. */
- while (TREE_CODE (op0) == ARRAY_REF)
- {
- tree array_obj = TREE_OPERAND (op0, 0);
- tree array_idx = TREE_OPERAND (op0, 1);
- tree elt_type = TREE_TYPE (op0);
- tree elt_size = TYPE_SIZE_UNIT (elt_type);
- tree min_idx;
-
- if (TREE_CODE (array_idx) != INTEGER_CST)
- break;
- if (TREE_CODE (elt_size) != INTEGER_CST)
- break;
-
- /* Un-bias the index by the min index of the array type. */
- min_idx = TYPE_DOMAIN (TREE_TYPE (array_obj));
- if (min_idx)
- {
- min_idx = TYPE_MIN_VALUE (min_idx);
- if (min_idx)
- {
- if (TREE_CODE (min_idx) != INTEGER_CST)
- break;
-
- array_idx = fold_convert (TREE_TYPE (min_idx), array_idx);
- if (!integer_zerop (min_idx))
- array_idx = int_const_binop (MINUS_EXPR, array_idx,
- min_idx, 0);
- }
- }
-
- /* Convert the index to a byte offset. */
- array_idx = fold_convert (sizetype, array_idx);
- array_idx = int_const_binop (MULT_EXPR, array_idx, elt_size, 0);
-
- /* Update the operands for the next round, or for folding. */
- op1 = int_const_binop (PLUS_EXPR,
- array_idx, op1, 0);
- op0 = array_obj;
- }
-
- ptd_type = TREE_TYPE (res_type);
- /* If we want a pointer to void, reconstruct the reference from the
- array element type. A pointer to that can be trivially converted
- to void *. This happens as we fold (void *)(ptr p+ off). */
- if (VOID_TYPE_P (ptd_type)
- && TREE_CODE (TREE_TYPE (op0)) == ARRAY_TYPE)
- ptd_type = TREE_TYPE (TREE_TYPE (op0));
-
- /* At which point we can try some of the same things as for indirects. */
- t = maybe_fold_offset_to_array_ref (op0, op1, ptd_type, true);
- if (!t)
- t = maybe_fold_offset_to_component_ref (TREE_TYPE (op0), op0, op1,
- ptd_type, false);
- if (t)
- t = build1 (ADDR_EXPR, res_type, t);
-
- return t;
-}
-
-/* For passing state through walk_tree into fold_stmt_r and its
- children. */
-
-struct fold_stmt_r_data
-{
- gimple stmt;
- bool *changed_p;
- bool *inside_addr_expr_p;
-};
-
-/* Subroutine of fold_stmt called via walk_tree. We perform several
- simplifications of EXPR_P, mostly having to do with pointer arithmetic. */
-
-static tree
-fold_stmt_r (tree *expr_p, int *walk_subtrees, void *data)
-{
- struct walk_stmt_info *wi = (struct walk_stmt_info *) data;
- struct fold_stmt_r_data *fold_stmt_r_data;
- bool *inside_addr_expr_p;
- bool *changed_p;
- tree expr = *expr_p, t;
- bool volatile_p = TREE_THIS_VOLATILE (expr);
-
- fold_stmt_r_data = (struct fold_stmt_r_data *) wi->info;
- inside_addr_expr_p = fold_stmt_r_data->inside_addr_expr_p;
- changed_p = fold_stmt_r_data->changed_p;
-
- /* ??? It'd be nice if walk_tree had a pre-order option. */
- switch (TREE_CODE (expr))
- {
- case INDIRECT_REF:
- t = walk_tree (&TREE_OPERAND (expr, 0), fold_stmt_r, data, NULL);
- if (t)
- return t;
- *walk_subtrees = 0;
-
- t = maybe_fold_stmt_indirect (expr, TREE_OPERAND (expr, 0),
- integer_zero_node);
- /* Avoid folding *"abc" = 5 into 'a' = 5. */
- if (wi->is_lhs && t && TREE_CODE (t) == INTEGER_CST)
- t = NULL_TREE;
- if (!t
- && TREE_CODE (TREE_OPERAND (expr, 0)) == ADDR_EXPR)
- /* If we had a good reason for propagating the address here,
- make sure we end up with valid gimple. See PR34989. */
- t = TREE_OPERAND (TREE_OPERAND (expr, 0), 0);
- break;
-
- case NOP_EXPR:
- t = walk_tree (&TREE_OPERAND (expr, 0), fold_stmt_r, data, NULL);
- if (t)
- return t;
- *walk_subtrees = 0;
-
- if (POINTER_TYPE_P (TREE_TYPE (expr))
- && POINTER_TYPE_P (TREE_TYPE (TREE_TYPE (expr)))
- && POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (expr, 0)))
- && (t = maybe_fold_offset_to_address (TREE_OPERAND (expr, 0),
- integer_zero_node,
- TREE_TYPE (TREE_TYPE (expr)))))
- return t;
- break;
-
- /* ??? Could handle more ARRAY_REFs here, as a variant of INDIRECT_REF.
- We'd only want to bother decomposing an existing ARRAY_REF if
- the base array is found to have another offset contained within.
- Otherwise we'd be wasting time. */
- case ARRAY_REF:
- /* If we are not processing expressions found within an
- ADDR_EXPR, then we can fold constant array references.
- Don't fold on LHS either, to avoid folding "abc"[0] = 5
- into 'a' = 5. */
- if (!*inside_addr_expr_p && !wi->is_lhs)
- t = fold_read_from_constant_string (expr);
- else
- t = NULL;