+2004-06-21 Richard Kenner <kenner@vlsi1.ultra.nyu.edu>
+
+ * alias.c (adjust_offset_for_component_ref): Use
+ component_ref_field_offset.
+ * c-decl.c (build_array_declarator): Add news args for ARRAY_REF.
+ * c-gimplify.c (gimplify_expr_stmt): Use alloc_stmt_list.
+ (gimplify_decl_stmt): Call gimplify_type_sizes for type.
+ For decl, call gimplify_one_sizepos and use statement list.
+ (gimplify_compound_literal_expr): New arg PRE_P.
+ Add statement to PRE_P list and return DECL.
+ (c_gimplify_expr, case COMPOUND_LITERAL_EXPR): Add arg to
+ gimplify_compound_literal_expr.
+ * c-tree.h (getdecls): Deleted.
+ * c-typeck.c (build_component_ref): Add operand for COMPONENT_REF.
+ (build_array_ref): Add two operands for ARRAY_REF.
+ (build_unary_op): Set TREE_INVARIANT and TREE_CONSTANT for
+ COMPOUND_LITERAL_EXPR.
+ * coverage.c (tree_coverage_counter_ref): Add new operands
+ for ARRAY_REF.
+ * emit-rtl.c (component_ref_for_mem_expr): Add new operand
+ for COMPONENT_REF.
+ (set_mem_attributes_minus_bitpos): Use array_ref_low_bound
+ and array_ref_element_size.
+ (widen_memory_access):Use component_ref_field_offset.
+ * explow.c (update_nonlocal_goto_save_area): Add two operands
+ for ARRAY_REF.
+ * expr.c (array_ref_element_size, array_ref_low_bound): New functions.
+ (component_ref_field_offset): Likewise.
+ (get_inner_reference): Use them.
+ (expand_expr_real_1, case ARRAY_REF): Use array_ref_low_bound.
+ * fold-const.c (fold, case EQ_EXPR): Properly handle DECL_SIZE.
+ (fold_read_from_constant_string): Use array_ref_low_bound.
+ Verify that result is a character type.
+ (build_fold_indirect_ref): Add two operands for ARRAY_REF.
+ * function.c (expand_function_start): Likewise.
+ * gimple-low.c (expand_var_p): Delete duplicated line.
+ * gimplify.c: Add static decls for local functions.
+ (cgraph.h): Now included.
+ (create_tmp_var): Remove check for ARRAY_TYPE.
+ (copy_if_shared_r): Look at bounds and sizes of types.
+ (build_and_jump): Return alloc_stmt_list instead of build_empty_stmt.
+ (gimplify_exit_expr, shortcut_cond_expr): Likewise.
+ (gimplify_save_expr, gimple_push_cleanup): Likewise.
+ (gimplify_init_constructor): Likewise.
+ WANT_VALUE now bool.
+ If empty list with no result wanted, return GS_UNHANDLED.
+ Add additional operands for ARRAY_REF and COMPONENT_REF.
+ (canonicalize_component_ref): Convert to &array[L].
+ (gimplify_array_ref_to_plus): Use array_ref_element_size and
+ array_ref_lower_bound.
+ (build_addr_expr_with_type, build_addr_expr): New functions.
+ (gimplify_compound_lval): WANT_LVALUE now bool.
+ Major rework to allow handle_component_p and initialize and
+ gimplify new operands for ARRAY_REF, ARRAY_RANGE_REF, and
+ COMPONENT_REF.
+ (gimplify_array_ref): Deleted.
+ (gimplify_self_mod_expr): WANT_VALUE now bool.
+ (gimplify_modify_expr): Gimplify to_p and from_p later.
+ Factor out code into gimplify_modify_expr_rhs and call twice.
+ Move variable-size code earlier and handle PLACEHOLDER_EXPR.
+ (gimplify_modify_expr_rhs, gimplify_variable_sized_compare): New fns.
+ (gimplify_addr_expr, case VIEW_CONVERT_EXPR): New case.
+ (gimplify_expr, case ARRAY_REF): Delete special case.
+ Instead handle like COMPONENT_REF; also do ARRAY_RANGE_REF,
+ IMAGPART, and REALPART the same way.
+ (gimplify_expr, case VIEW_CONVERT_EXPR): New case.
+ (gimplify_expr): Call gimplify_variable_sized_compare if applicable.
+ Call alloc_stmt_list instead of build_empty_stmt.
+ Deal with _REF that's volatile.
+ (gimplify_type_sizes, gimplify_one_sizepos): New functions.
+ (unshare_body, unvisit_body): New functions.
+ (gimplify_body): Call them.
+ * stmt.c (expand_stack_alloc): Don't expand TYPE_MAX_VALUE.
+ * stor-layout.c (get_pending_sizes): Don't change SAVE_EXPR_CONTEXT.
+ * tree-alias-common.c (get_alias_var): Also skip ARRAY_RANGE_REF.
+ * tree-cfg.c (tree_node_can_be_shared): Treat ARRAY_RANGE_REF
+ like ARRAY_REF.
+ (verify_expr, case ADDR_EXPR): Use handled_component_p.
+ * tree-dfa.c (get_virtual_var): Likewise.
+ * tree-dump.c (dequeue_and_dump, case COMPONENT_REF, ARRAY_REF):
+ New cases to dump new operands; likewise for ARRAY_RANGE_REF.
+ * tree-eh.c (tree_could_trap, case ARRAY_RANGE_REF): Like ARRAY_REF.
+ * tree-gimple.c (is_gimple_addr_expr_arg): Add ARRAY_RANGE_REF
+ and INDIRECT_REF.
+ (get_base_address): Use handled_component_p.
+ * tree-gimple.h (gimplify_type_sizes, gimplify_one_sizepos): New.
+ * tree-inline.c (walk_tree): Walk more things for types and decls.
+ * tree-mudflap.c (mf_build_check_statement_for): Add new operands
+ for ARRAY_REF and COMPONENT_REF.
+ (mx_xform_derefs_1): Clean up usage of decl sizes.
+ * tree-nested.c (build_addr): Use handled_component_p.
+ (walk_stmts, case CATCH_EXPR): Add missing "break".
+ (get_static_chain, get_frame_field): Add new operand for COMPONENT_REF.
+ (finalize_nesting_tree_1): Likewise.
+ (convert_nonlocal_reference, case ARRAY_RANGE_REF): Like ARRAY_REF
+ and process additional operands.
+ (convert_local_reference): Likewise.
+ * tree-outof-ssa.c (discover_nonconstant_array_refs_r): Treat
+ ARRAY_RANGE_REF similarly to ARRAY_REF.
+ * tree-pretty-print.c (dump_generic_node, case QUAL_UNION_TYPE): Handle
+ like RECORD_TYPE.
+ (dump_generic_node, case COMPONENT_REF): Print offset operand.
+ (dump_generic_node, case ARRAY_RANGE_REF): Treat like ARRAY_REF
+ and print lower bound and element size for both.
+ (op_prio, case ARRAY_RANGE_REF): Like ARRAY_REF.
+ * tree-sra.c (csc_build_component_ref): Add new operand.
+ (scalarize_call_expr): Use get_base_address.
+ * tree-ssa-ccp.c (widen_bitfield): Clean up size handling.
+ (maybe_fold_offset_to_array_ref): Rework to handle input having an
+ ARRAY_REF, refine handling of lower bound, and add new operands
+ for ARRAY_REF.
+ (maybe_fold_to_component_ref): Add new operand for COMPONENT_REF.
+ (maybe_fold_stmt_indirect): Only fold *&B to B if types match.
+ (maybe_fold_stmt_addition): Only handle constant lower bound.
+ * tree-ssa-operands.c (get_expr_operands): Minor rearrangements.
+ Treat ARRAY_REF and ARRAY_RANGE_REF the same; look at extra operands.
+ Look at new offset operand of COMPONENT_REF.
+ * tree-ssa.c (set_is_used): Use handled_component_p.
+ * tree.c (substitute_in_expr, case COMPONENT_REF): Add new operand.
+ (stabilize_reference, case COMPONENT_REF): Likewise.
+ (stabilize_reference, case ARRAY_RANGE_REF, ARRAY_REF): Similarly.
+ (recompute_tree_invariant_for_addr_expr): Completely rework to
+ be more precise. Also set TREE_SIDE_EFFECTS.
+ (build1_stat, case ARRAY_EXPR): Don't handle TREE_SIDE_EFFECTS here.
+ (build2_stat, build3_stat, build4_stat): For references,
+ propagate TREE_THIS_VOLATILE.
+ (get_unwidened): Add new operand for COMPONENT_REF.
+ (get_narrower): Likewise; use host_integerp for DECL_SIZE.
+ * tree.def (COMPONENT_REF): Add new operand.
+ (ARRAY_REF, ARRAY_RANGE_REF): Add two new operands.
+ * tree.h (array_ref_element_size, array_ref_low_bound): New decls.
+ (component_ref_field_offset): Likewise.
+ * config/alpha/alpha.c (alpha_va_start): Add new op for COMPONENT_REF.
+ (alpha_gimplify_va_arg): Likewise.
+ * config/i386/i386.c (ix86_va_start, ix86_gimplify_va_arg): Likewise.
+ * config/i860/i860.c (i860_va_start, i860_va_arg): Likewise.
+ * config/iq2000/iq2000.c (iq2000_va_arg): Likewise.
+ * config/mips/mips.c (mips_va_start, mips_va_arg): Likewise.
+ * config/rs6000/rs6000.c (rs6000_va_start, rs6000_gimplify_va_arg):
+ Likewise.
+ * config/s390/s390.c (s390_va_start, s390_gimplify_va_arg): Likewise.
+ * config/sh/sh.c (sh_va_start, sh_va_arg): Likewise.
+ * config/stormy16/stormy16.c (xstormy1_expand_builin_va_start):
+ Likewise.
+ (xstormy16_expand_builtin_va_arg): Likewise.
+ * config/xtensa/xtensa.c (xtensa_va_start, xtensa_va_arg): Likewise.
+ * objc/objc-act.c (generate_static_references): Likewise.
+ (generate_strings, build_method_prototype_list_template): Likewise.
+ (generate_protocol_list): Likewise.
+
2004-06-21 John David Anglin <dave.anglin@nrc-cnrc.gc.ca>
PR rtl-optimization/14782
ioffset = INTVAL (offset);
do
{
+ tree offset = component_ref_field_offset (x);
tree field = TREE_OPERAND (x, 1);
- if (! host_integerp (DECL_FIELD_OFFSET (field), 1))
+ if (! host_integerp (offset, 1))
return NULL_RTX;
- ioffset += (tree_low_cst (DECL_FIELD_OFFSET (field), 1)
+ ioffset += (tree_low_cst (offset, 1)
+ (tree_low_cst (DECL_FIELD_BIT_OFFSET (field), 1)
/ BITS_PER_UNIT));
build_array_declarator (tree expr, tree quals, int static_p, int vla_unspec_p)
{
tree decl;
- decl = build_nt (ARRAY_REF, NULL_TREE, expr);
+ decl = build_nt (ARRAY_REF, NULL_TREE, expr, NULL_TREE, NULL_TREE);
TREE_TYPE (decl) = quals;
TREE_STATIC (decl) = (static_p ? 1 : 0);
if (pedantic && !flag_isoc99)
}
if (stmt == NULL_TREE)
- stmt = build_empty_stmt ();
+ stmt = alloc_stmt_list ();
*stmt_p = stmt;
{
tree stmt = *stmt_p;
tree decl = DECL_STMT_DECL (stmt);
- tree pre = NULL_TREE;
- tree post = NULL_TREE;
if (TREE_TYPE (decl) == error_mark_node)
{
}
if (TREE_CODE (decl) == TYPE_DECL)
- {
- tree type = TREE_TYPE (decl);
- if (TYPE_SIZE_UNIT (type)
- && !TREE_CONSTANT (TYPE_SIZE_UNIT (type)))
- {
- /* This is a variable-sized array type. Simplify its size. */
- tree temp = TYPE_SIZE_UNIT (type);
- gimplify_expr (&temp, &pre, &post, is_gimple_val, fb_rvalue);
- }
- }
+ *stmt_p = gimplify_type_sizes (TREE_TYPE (decl));
- if (TREE_CODE (decl) == VAR_DECL && !DECL_EXTERNAL (decl))
+ else if (TREE_CODE (decl) == VAR_DECL && !DECL_EXTERNAL (decl))
{
tree init = DECL_INITIAL (decl);
+ *stmt_p = NULL_TREE;
+ gimplify_one_sizepos (&DECL_SIZE (decl), stmt_p);
+ gimplify_one_sizepos (&DECL_SIZE_UNIT (decl), stmt_p);
+
if (!TREE_CONSTANT (DECL_SIZE (decl)))
{
- tree pt_type = build_pointer_type (TREE_TYPE (decl));
- tree alloc, size;
-
/* 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(). */
- size = get_initialized_tmp_var (DECL_SIZE_UNIT (decl), &pre, &post);
+ tree pt_type = build_pointer_type (TREE_TYPE (decl));
+ tree alloc_stmt
+ = (build_function_call_expr
+ (implicit_built_in_decls[BUILT_IN_STACK_ALLOC],
+ tree_cons (NULL_TREE,
+ build1 (ADDR_EXPR, pt_type, decl),
+ tree_cons (NULL_TREE, DECL_SIZE_UNIT (decl),
+ NULL_TREE))));
+
+ gimplify_stmt (&alloc_stmt);
+ append_to_statement_list(alloc_stmt, stmt_p);
DECL_DEFER_OUTPUT (decl) = 1;
- alloc = build_function_call_expr
- (implicit_built_in_decls[BUILT_IN_STACK_ALLOC],
- tree_cons (NULL_TREE,
- build1 (ADDR_EXPR, pt_type, decl),
- tree_cons (NULL_TREE, size, NULL_TREE)));
- append_to_compound_expr (alloc, &pre);
}
if (init && init != error_mark_node)
DECL_INITIAL (decl) = NULL_TREE;
init = build (MODIFY_EXPR, void_type_node, decl, init);
- append_to_compound_expr (init, &pre);
+ gimplify_stmt (&init);
+ append_to_statement_list (init, stmt_p);
}
else
- {
- /* We must still examine initializers for static variables
- as they may contain a label address. */
- walk_tree (&init, force_labels_r, NULL, NULL);
- }
+ /* We must still examine initializers for static variables
+ as they may contain a label address. */
+ walk_tree (&init, force_labels_r, NULL, NULL);
}
/* This decl isn't mentioned in the enclosing block, so add it to the
if (DECL_ARTIFICIAL (decl) && DECL_NAME (decl) == NULL_TREE)
gimple_add_tmp_var (decl);
}
+ else
+ *stmt_p = alloc_stmt_list ();
- append_to_compound_expr (post, &pre);
- *stmt_p = pre;
- return GS_OK;
+ return GS_ALL_DONE;
}
/* Gimplification of expression trees. */
instead. */
static enum gimplify_status
-gimplify_compound_literal_expr (tree *expr_p)
+gimplify_compound_literal_expr (tree *expr_p, tree *pre_p)
{
tree decl_s = COMPOUND_LITERAL_EXPR_DECL_STMT (*expr_p);
tree decl = DECL_STMT_DECL (decl_s);
gimple_add_tmp_var (decl);
gimplify_decl_stmt (&decl_s);
- *expr_p = decl_s ? decl_s : decl;
+ append_to_statement_list (decl_s, pre_p);
+ *expr_p = decl;
return GS_OK;
}
switch (code)
{
case COMPOUND_LITERAL_EXPR:
- return gimplify_compound_literal_expr (expr_p);
+ return gimplify_compound_literal_expr (expr_p, pre_p);
case FOR_STMT:
return gimplify_for_stmt (expr_p, pre_p);
extern int c_in_case_stmt;
extern int global_bindings_p (void);
-extern tree getdecls (void);
extern void push_scope (void);
extern tree pop_scope (void);
extern void insert_block (tree);
if (TREE_CODE (exp) == VAR_DECL)
{
- /* ??? This is not really quite correct
- in that the type of the operand of ADDR_EXPR
- is not the target type of the type of the ADDR_EXPR itself.
- Question is, can this lossage be avoided? */
+ /* We are making an ADDR_EXPR of ptrtype. This is a valid
+ ADDR_EXPR because it's the best way of representing what
+ happens in C when we take the address of an array and place
+ it in a pointer to the element type. */
adr = build1 (ADDR_EXPR, ptrtype, exp);
if (!c_mark_addressable (exp))
return error_mark_node;
if (TREE_TYPE (subdatum) == error_mark_node)
return error_mark_node;
- ref = build (COMPONENT_REF, TREE_TYPE (subdatum), datum, subdatum);
+ ref = build (COMPONENT_REF, TREE_TYPE (subdatum), datum, subdatum,
+ NULL_TREE);
if (TREE_READONLY (datum) || TREE_READONLY (subdatum))
TREE_READONLY (ref) = 1;
if (TREE_THIS_VOLATILE (datum) || TREE_THIS_VOLATILE (subdatum))
}
type = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (array)));
- rval = build (ARRAY_REF, type, array, index);
+ rval = build (ARRAY_REF, type, array, index, NULL_TREE, NULL_TREE);
/* Array ref is const/volatile if the array elements are
or if the array is. */
TREE_READONLY (rval)
else
addr = build1 (code, argtype, arg);
+ if (TREE_CODE (arg) == COMPOUND_LITERAL_EXPR)
+ TREE_INVARIANT (addr) = TREE_CONSTANT (addr) = 1;
+
return addr;
}
offset_field = TREE_CHAIN (base_field);
base_field = build (COMPONENT_REF, TREE_TYPE (base_field),
- valist, base_field);
+ valist, base_field, NULL_TREE);
offset_field = build (COMPONENT_REF, TREE_TYPE (offset_field),
- valist, offset_field);
+ valist, offset_field, NULL_TREE);
t = make_tree (ptr_type_node, virtual_incoming_args_rtx);
t = build (PLUS_EXPR, ptr_type_node, t, build_int_2 (offset, 0));
base_field = TYPE_FIELDS (va_list_type_node);
offset_field = TREE_CHAIN (base_field);
base_field = build (COMPONENT_REF, TREE_TYPE (base_field),
- valist, base_field);
+ valist, base_field, NULL_TREE);
offset_field = build (COMPONENT_REF, TREE_TYPE (offset_field),
- valist, offset_field);
+ valist, offset_field, NULL_TREE);
/* Pull the fields of the structure out into temporaries. Since we never
modify the base field, we can use a formal temporary. Sign-extend the
f_sav = TREE_CHAIN (f_ovf);
valist = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (valist)), valist);
- gpr = build (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr);
- fpr = build (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr);
- ovf = build (COMPONENT_REF, TREE_TYPE (f_ovf), valist, f_ovf);
- sav = build (COMPONENT_REF, TREE_TYPE (f_sav), valist, f_sav);
+ gpr = build (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr, NULL_TREE);
+ fpr = build (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr, NULL_TREE);
+ ovf = build (COMPONENT_REF, TREE_TYPE (f_ovf), valist, f_ovf, NULL_TREE);
+ sav = build (COMPONENT_REF, TREE_TYPE (f_sav), valist, f_sav, NULL_TREE);
/* Count number of gp and fp argument registers used. */
words = current_function_args_info.words;
f_sav = TREE_CHAIN (f_ovf);
valist = build_fold_indirect_ref (valist);
- gpr = build (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr);
- fpr = build (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr);
- ovf = build (COMPONENT_REF, TREE_TYPE (f_ovf), valist, f_ovf);
- sav = build (COMPONENT_REF, TREE_TYPE (f_sav), valist, f_sav);
+ gpr = build (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr, NULL_TREE);
+ fpr = build (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr, NULL_TREE);
+ ovf = build (COMPONENT_REF, TREE_TYPE (f_ovf), valist, f_ovf, NULL_TREE);
+ sav = build (COMPONENT_REF, TREE_TYPE (f_sav), valist, f_sav, NULL_TREE);
size = int_size_in_bytes (type);
if (size == -1)
f_fpr = TREE_CHAIN (f_gpr);
#endif
- gpr = build (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr);
- fpr = build (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr);
- sav = build (COMPONENT_REF, TREE_TYPE (f_sav), valist, f_sav);
- mem = build (COMPONENT_REF, TREE_TYPE (f_mem), valist, f_mem);
+ gpr = build (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr, NULL_TREE);
+ fpr = build (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr, NULL_TREE);
+ sav = build (COMPONENT_REF, TREE_TYPE (f_sav), valist, f_sav, NULL_TREE);
+ mem = build (COMPONENT_REF, TREE_TYPE (f_mem), valist, f_mem, NULL_TREE);
/* Initialize the `mem_ptr' field to the address of the first anonymous
stack argument. */
f_fpr = TREE_CHAIN (f_gpr);
#endif
- gpr = build (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr);
- fpr = build (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr);
- mem = build (COMPONENT_REF, TREE_TYPE (f_mem), valist, f_mem);
- sav = build (COMPONENT_REF, TREE_TYPE (f_sav), valist, f_sav);
+ gpr = build (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr, NULL_TREE);
+ fpr = build (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr, NULL_TREE);
+ mem = build (COMPONENT_REF, TREE_TYPE (f_mem), valist, f_mem, NULL_TREE);
+ sav = build (COMPONENT_REF, TREE_TYPE (f_sav), valist, f_sav, NULL_TREE);
size = int_size_in_bytes (type);
f_goff = TREE_CHAIN (f_ftop);
f_foff = TREE_CHAIN (f_goff);
- ovfl = build (COMPONENT_REF, TREE_TYPE (f_ovfl), valist, f_ovfl);
- gtop = build (COMPONENT_REF, TREE_TYPE (f_gtop), valist, f_gtop);
- ftop = build (COMPONENT_REF, TREE_TYPE (f_ftop), valist, f_ftop);
- goff = build (COMPONENT_REF, TREE_TYPE (f_goff), valist, f_goff);
- foff = build (COMPONENT_REF, TREE_TYPE (f_foff), valist, f_foff);
+ ovfl = build (COMPONENT_REF, TREE_TYPE (f_ovfl), valist, f_ovfl, NULL_TREE);
+ gtop = build (COMPONENT_REF, TREE_TYPE (f_gtop), valist, f_gtop, NULL_TREE);
+ ftop = build (COMPONENT_REF, TREE_TYPE (f_ftop), valist, f_ftop, NULL_TREE);
+ goff = build (COMPONENT_REF, TREE_TYPE (f_goff), valist, f_goff, NULL_TREE);
+ foff = build (COMPONENT_REF, TREE_TYPE (f_foff), valist, f_foff, NULL_TREE);
lab_false = gen_label_rtx ();
lab_over = gen_label_rtx ();
f_goff = TREE_CHAIN (f_ftop);
f_foff = TREE_CHAIN (f_goff);
- ovfl = build (COMPONENT_REF, TREE_TYPE (f_ovfl), valist, f_ovfl);
- gtop = build (COMPONENT_REF, TREE_TYPE (f_gtop), valist, f_gtop);
- ftop = build (COMPONENT_REF, TREE_TYPE (f_ftop), valist, f_ftop);
- goff = build (COMPONENT_REF, TREE_TYPE (f_goff), valist, f_goff);
- foff = build (COMPONENT_REF, TREE_TYPE (f_foff), valist, f_foff);
+ ovfl = build (COMPONENT_REF, TREE_TYPE (f_ovfl), valist, f_ovfl,
+ NULL_TREE);
+ gtop = build (COMPONENT_REF, TREE_TYPE (f_gtop), valist, f_gtop,
+ NULL_TREE);
+ ftop = build (COMPONENT_REF, TREE_TYPE (f_ftop), valist, f_ftop,
+ NULL_TREE);
+ goff = build (COMPONENT_REF, TREE_TYPE (f_goff), valist, f_goff,
+ NULL_TREE);
+ foff = build (COMPONENT_REF, TREE_TYPE (f_foff), valist, f_foff,
+ NULL_TREE);
/* Emit code to initialize OVFL, which points to the next varargs
stack argument. CUM->STACK_WORDS gives the number of stack
lab_false = gen_label_rtx ();
lab_over = gen_label_rtx ();
- ovfl = build (COMPONENT_REF, TREE_TYPE (f_ovfl), valist, f_ovfl);
+ ovfl = build (COMPONENT_REF, TREE_TYPE (f_ovfl), valist, f_ovfl,
+ NULL_TREE);
if (GET_MODE_CLASS (TYPE_MODE (type)) == MODE_FLOAT
&& GET_MODE_SIZE (TYPE_MODE (type)) <= UNITS_PER_FPVALUE)
{
- top = build (COMPONENT_REF, TREE_TYPE (f_ftop), valist, f_ftop);
- off = build (COMPONENT_REF, TREE_TYPE (f_foff), valist, f_foff);
+ top = build (COMPONENT_REF, TREE_TYPE (f_ftop), valist, f_ftop,
+ NULL_TREE);
+ off = build (COMPONENT_REF, TREE_TYPE (f_foff), valist, f_foff,
+ NULL_TREE);
/* When floating-point registers are saved to the stack,
each one will take up UNITS_PER_HWFPVALUE bytes, regardless
}
else
{
- top = build (COMPONENT_REF, TREE_TYPE (f_gtop), valist, f_gtop);
- off = build (COMPONENT_REF, TREE_TYPE (f_goff), valist, f_goff);
+ top = build (COMPONENT_REF, TREE_TYPE (f_gtop), valist, f_gtop,
+ NULL_TREE);
+ off = build (COMPONENT_REF, TREE_TYPE (f_goff), valist, f_goff,
+ NULL_TREE);
if (rsize > UNITS_PER_WORD)
{
/* [1] Emit code for: off &= -rsize. */
f_sav = TREE_CHAIN (f_ovf);
valist = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (valist)), valist);
- gpr = build (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr);
- fpr = build (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr);
- ovf = build (COMPONENT_REF, TREE_TYPE (f_ovf), valist, f_ovf);
- sav = build (COMPONENT_REF, TREE_TYPE (f_sav), valist, f_sav);
+ gpr = build (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr, NULL_TREE);
+ fpr = build (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr, NULL_TREE);
+ ovf = build (COMPONENT_REF, TREE_TYPE (f_ovf), valist, f_ovf, NULL_TREE);
+ sav = build (COMPONENT_REF, TREE_TYPE (f_sav), valist, f_sav, NULL_TREE);
/* Count number of gp and fp argument registers used. */
words = current_function_args_info.words;
f_sav = TREE_CHAIN (f_ovf);
valist = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (valist)), valist);
- gpr = build (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr);
- fpr = build (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr);
- ovf = build (COMPONENT_REF, TREE_TYPE (f_ovf), valist, f_ovf);
- sav = build (COMPONENT_REF, TREE_TYPE (f_sav), valist, f_sav);
+ gpr = build (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr, NULL_TREE);
+ fpr = build (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr, NULL_TREE);
+ ovf = build (COMPONENT_REF, TREE_TYPE (f_ovf), valist, f_ovf, NULL_TREE);
+ sav = build (COMPONENT_REF, TREE_TYPE (f_sav), valist, f_sav, NULL_TREE);
size = int_size_in_bytes (type);
rsize = (size + 3) / 4;
f_sav = TREE_CHAIN (f_ovf);
valist = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (valist)), valist);
- gpr = build (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr);
- fpr = build (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr);
- ovf = build (COMPONENT_REF, TREE_TYPE (f_ovf), valist, f_ovf);
- sav = build (COMPONENT_REF, TREE_TYPE (f_sav), valist, f_sav);
+ gpr = build (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr, NULL_TREE);
+ fpr = build (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr, NULL_TREE);
+ ovf = build (COMPONENT_REF, TREE_TYPE (f_ovf), valist, f_ovf, NULL_TREE);
+ sav = build (COMPONENT_REF, TREE_TYPE (f_sav), valist, f_sav, NULL_TREE);
/* Count number of gp and fp argument registers used. */
f_sav = TREE_CHAIN (f_ovf);
valist = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (valist)), valist);
- gpr = build (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr);
- fpr = build (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr);
- ovf = build (COMPONENT_REF, TREE_TYPE (f_ovf), valist, f_ovf);
- sav = build (COMPONENT_REF, TREE_TYPE (f_sav), valist, f_sav);
+ gpr = build (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr, NULL_TREE);
+ fpr = build (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr, NULL_TREE);
+ ovf = build (COMPONENT_REF, TREE_TYPE (f_ovf), valist, f_ovf, NULL_TREE);
+ sav = build (COMPONENT_REF, TREE_TYPE (f_sav), valist, f_sav, NULL_TREE);
size = int_size_in_bytes (type);
f_next_fp_limit = TREE_CHAIN (f_next_fp);
f_next_stack = TREE_CHAIN (f_next_fp_limit);
- next_o = build (COMPONENT_REF, TREE_TYPE (f_next_o), valist, f_next_o);
+ next_o = build (COMPONENT_REF, TREE_TYPE (f_next_o), valist, f_next_o,
+ NULL_TREE);
next_o_limit = build (COMPONENT_REF, TREE_TYPE (f_next_o_limit),
- valist, f_next_o_limit);
- next_fp = build (COMPONENT_REF, TREE_TYPE (f_next_fp), valist, f_next_fp);
+ valist, f_next_o_limit, NULL_TREE);
+ next_fp = build (COMPONENT_REF, TREE_TYPE (f_next_fp), valist, f_next_fp,
+ NULL_TREE);
next_fp_limit = build (COMPONENT_REF, TREE_TYPE (f_next_fp_limit),
- valist, f_next_fp_limit);
+ valist, f_next_fp_limit, NULL_TREE);
next_stack = build (COMPONENT_REF, TREE_TYPE (f_next_stack),
- valist, f_next_stack);
+ valist, f_next_stack, NULL_TREE);
/* Call __builtin_saveregs. */
u = make_tree (ptr_type_node, expand_builtin_saveregs ());
f_next_fp_limit = TREE_CHAIN (f_next_fp);
f_next_stack = TREE_CHAIN (f_next_fp_limit);
- next_o = build (COMPONENT_REF, TREE_TYPE (f_next_o), valist, f_next_o);
+ next_o = build (COMPONENT_REF, TREE_TYPE (f_next_o), valist, f_next_o,
+ NULL_TREE);
next_o_limit = build (COMPONENT_REF, TREE_TYPE (f_next_o_limit),
- valist, f_next_o_limit);
+ valist, f_next_o_limit, NULL_TREE);
next_fp = build (COMPONENT_REF, TREE_TYPE (f_next_fp),
- valist, f_next_fp);
+ valist, f_next_fp, NULL_TREE);
next_fp_limit = build (COMPONENT_REF, TREE_TYPE (f_next_fp_limit),
- valist, f_next_fp_limit);
+ valist, f_next_fp_limit, NULL_TREE);
next_stack = build (COMPONENT_REF, TREE_TYPE (f_next_stack),
- valist, f_next_stack);
+ valist, f_next_stack, NULL_TREE);
/* Structures with a single member with a distinct mode are passed
like their member. This is relevant if the latter has a REAL_TYPE
f_base = TYPE_FIELDS (va_list_type_node);
f_count = TREE_CHAIN (f_base);
- base = build (COMPONENT_REF, TREE_TYPE (f_base), valist, f_base);
- count = build (COMPONENT_REF, TREE_TYPE (f_count), valist, f_count);
+ base = build (COMPONENT_REF, TREE_TYPE (f_base), valist, f_base, NULL_TREE);
+ count = build (COMPONENT_REF, TREE_TYPE (f_count), valist, f_count,
+ NULL_TREE);
t = make_tree (TREE_TYPE (base), virtual_incoming_args_rtx);
t = build (PLUS_EXPR, TREE_TYPE (base), t,
f_base = TYPE_FIELDS (va_list_type_node);
f_count = TREE_CHAIN (f_base);
- base = build (COMPONENT_REF, TREE_TYPE (f_base), valist, f_base);
- count = build (COMPONENT_REF, TREE_TYPE (f_count), valist, f_count);
+ base = build (COMPONENT_REF, TREE_TYPE (f_base), valist, f_base, NULL_TREE);
+ count = build (COMPONENT_REF, TREE_TYPE (f_count), valist, f_count,
+ NULL_TREE);
must_stack = MUST_PASS_IN_STACK (TYPE_MODE (type), type);
size_tree = round_up (size_in_bytes (type), UNITS_PER_WORD);
f_reg = TREE_CHAIN (f_stk);
f_ndx = TREE_CHAIN (f_reg);
- stk = build (COMPONENT_REF, TREE_TYPE (f_stk), valist, f_stk);
- reg = build (COMPONENT_REF, TREE_TYPE (f_reg), valist, f_reg);
- ndx = build (COMPONENT_REF, TREE_TYPE (f_ndx), valist, f_ndx);
+ stk = build (COMPONENT_REF, TREE_TYPE (f_stk), valist, f_stk, NULL_TREE);
+ reg = build (COMPONENT_REF, TREE_TYPE (f_reg), valist, f_reg, NULL_TREE);
+ ndx = build (COMPONENT_REF, TREE_TYPE (f_ndx), valist, f_ndx, NULL_TREE);
/* Call __builtin_saveregs; save the result in __va_reg */
u = make_tree (ptr_type_node, expand_builtin_saveregs ());
f_reg = TREE_CHAIN (f_stk);
f_ndx = TREE_CHAIN (f_reg);
- stk = build (COMPONENT_REF, TREE_TYPE (f_stk), valist, f_stk);
- reg = build (COMPONENT_REF, TREE_TYPE (f_reg), valist, f_reg);
- ndx = build (COMPONENT_REF, TREE_TYPE (f_ndx), valist, f_ndx);
+ stk = build (COMPONENT_REF, TREE_TYPE (f_stk), valist, f_stk, NULL_TREE);
+ reg = build (COMPONENT_REF, TREE_TYPE (f_reg), valist, f_reg, NULL_TREE);
+ ndx = build (COMPONENT_REF, TREE_TYPE (f_ndx), valist, f_ndx, NULL_TREE);
type_size = TYPE_SIZE_UNIT (TYPE_MAIN_VARIANT (type));
tree
tree_coverage_counter_ref (unsigned counter, unsigned no)
{
- tree t;
+ tree domain_type = TYPE_DOMAIN (TREE_TYPE (tree_ctr_tables[counter]));
if (no >= fn_n_ctrs[counter] - fn_b_ctrs[counter])
abort ();
no += prg_n_ctrs[counter] + fn_b_ctrs[counter];
/* "no" here is an array index, scaled to bytes later. */
- t = build (ARRAY_REF, GCOV_TYPE_NODE, tree_ctr_tables[counter],
- build_int_2 (no, 0));
- return t;
+ return build (ARRAY_REF, GCOV_TYPE_NODE, tree_ctr_tables[counter],
+ fold_convert (domain_type, build_int_2 (no, 0)),
+ TYPE_MIN_VALUE (domain_type),
+ size_binop (EXACT_DIV_EXPR, TYPE_SIZE_UNIT (GCOV_TYPE_NODE),
+ size_int (TYPE_ALIGN (GCOV_TYPE_NODE))));
}
\f
/* Generate a checksum for a string. CHKSUM is the current
+2004-06-21 Richard Kenner <kenner@vlsi1.ultra.nyu.edu>
+
+ * call.c (build_vfield_ref): Add new operand for COMPONENT_REF.
+ (build_new_method_call): Likewise.
+ * decl.c (local_variable_p_walkfn): Don't walk into types.
+ * decl2.c (grok_array_decl): Add new operands for ARRAY_REF.
+ (build_anon_union_vars): Add new operand for COMPONENT_REF.
+ * init.c (buld_new): Add new operand for ARRAY_REF.
+ * method.c (do_build_copy_constructor): New op for COMPONENT_REF.
+ (do_build_assign_ref): Likewise.
+ * parser.c (cp_parser_direct_new_declarator): Add new operands
+ for ARRAY_REF.
+ (cp_parser_direct_declarator): Likewise.
+ * pt.c (tsubst): Likewise.
+ (tsubst_copy, tsubst_copy_and_build): Likewise; also add new operand
+ for COMPONENT_REF.
+ * semantics.c (finish_non_static_data_member): Add new operand
+ for COMPONENT_REF.
+ * typeck.c (build_class_member_access_expr): Likewise.
+ (build_class_member_access_expr, finish_class_member_access_expr):
+ Likewise.
+ (build_ptrmemfunc_access_expr): Likewise.
+ (build_array_ref): Add new operands for ARRAY_REF.
+ * typeck2.c (split_nonconstant_init_1): Likewise; COMPONENT_REF too.
+ * tree.c (count_trees_r, no_linkage_helper): Don't walk in types.
+
2004-06-21 Richard Henderson <rth@redhat.com>
* dump.c (cp_dump_tree): Don't use dump_next_stmt.
datum = convert_to_base (datum, type, /*check_access=*/false);
return build (COMPONENT_REF, TREE_TYPE (TYPE_VFIELD (type)),
- datum, TYPE_VFIELD (type));
+ datum, TYPE_VFIELD (type), NULL_TREE);
}
/* Returns nonzero iff the destructor name specified in NAME
return build_conditional_expr (arg1, arg2, arg3);
case MEMBER_REF:
- return build_m_component_ref
- (build_indirect_ref (arg1, NULL), arg2);
+ return build_m_component_ref (build_indirect_ref (arg1, NULL), arg2);
/* The caller will deal with these. */
case ADDR_EXPR:
if (processing_template_decl && call != error_mark_node)
call = (build_min_non_dep
(CALL_EXPR, call,
- build_min_nt (COMPONENT_REF, orig_instance, orig_fns),
+ build_min_nt (COMPONENT_REF, orig_instance, orig_fns, NULL_TREE),
orig_args, NULL_TREE));
/* Free all the conversions we allocated. */
function. */
static tree
-local_variable_p_walkfn (tree* tp,
- int* walk_subtrees ATTRIBUTE_UNUSED ,
- void* data ATTRIBUTE_UNUSED )
+local_variable_p_walkfn (tree *tp, int *walk_subtrees,
+ void *data ATTRIBUTE_UNUSED)
{
- return ((local_variable_p (*tp) && !DECL_ARTIFICIAL (*tp))
- ? *tp : NULL_TREE);
+ if (local_variable_p (*tp) && !DECL_ARTIFICIAL (*tp))
+ return *tp;
+ else if (TYPE_P (*tp))
+ *walk_subtrees = 0;
+
+ return NULL_TREE;
}
+
/* Check that ARG, which is a default-argument expression for a
parameter DECL, is valid. Returns ARG, or ERROR_MARK_NODE, if
something goes wrong. DECL may also be a _TYPE node, rather than a
{
if (type_dependent_expression_p (array_expr)
|| type_dependent_expression_p (index_exp))
- return build_min_nt (ARRAY_REF, array_expr, index_exp);
+ return build_min_nt (ARRAY_REF, array_expr, index_exp,
+ NULL_TREE, NULL_TREE);
array_expr = build_non_dependent_expr (array_expr);
index_exp = build_non_dependent_expr (index_exp);
}
expr = build_array_ref (array_expr, index_exp);
}
if (processing_template_decl && expr != error_mark_node)
- return build_min_non_dep (ARRAY_REF, expr,
- orig_array_expr, orig_index_exp);
+ return build_min_non_dep (ARRAY_REF, expr, orig_array_expr, orig_index_exp,
+ NULL_TREE, NULL_TREE);
return expr;
}
cp_pedwarn_at ("protected member `%#D' in anonymous union", field);
if (processing_template_decl)
- ref = build_min_nt (COMPONENT_REF, object, DECL_NAME (field));
+ ref = build_min_nt (COMPONENT_REF, object,
+ DECL_NAME (field), NULL_TREE);
else
ref = build_class_member_access_expr (object, field, NULL_TREE,
false);
{
if (has_array)
t = tree_cons (tree_cons (NULL_TREE, type, NULL_TREE),
- build_min_nt (ARRAY_REF, NULL_TREE, nelts),
+ build_min_nt (ARRAY_REF, NULL_TREE, nelts,
+ NULL_TREE, NULL_TREE),
NULL_TREE);
else
t = type;
}
if (has_array)
- t = build_nt (ARRAY_REF, type, nelts);
+ t = build_nt (ARRAY_REF, type, nelts, NULL_TREE, NULL_TREE);
else
t = type;
expr_type = TREE_TYPE (field);
if (TREE_CODE (expr_type) != REFERENCE_TYPE)
expr_type = cp_build_qualified_type (expr_type, cvquals);
- init = build (COMPONENT_REF, expr_type, init, field);
+ init = build (COMPONENT_REF, expr_type, init, field, NULL_TREE);
init = build_tree_list (NULL_TREE, init);
member_init_list
else
continue;
- comp = build (COMPONENT_REF, TREE_TYPE (field), comp, field);
+ comp = build (COMPONENT_REF, TREE_TYPE (field), comp, field,
+ NULL_TREE);
init = build (COMPONENT_REF,
cp_build_qualified_type (TREE_TYPE (field), cvquals),
- init, field);
+ init, field, NULL_TREE);
if (DECL_NAME (field))
finish_expr_stmt (build_modify_expr (comp, NOP_EXPR, init));
cp_parser_require (parser, CPP_CLOSE_SQUARE, "`]'");
/* Add this bound to the declarator. */
- declarator = build_nt (ARRAY_REF, declarator, expression);
+ declarator = build_nt (ARRAY_REF, declarator, expression,
+ NULL_TREE, NULL_TREE);
/* If the next token is not a `[', then there are no more
bounds. */
break;
}
- declarator = build_nt (ARRAY_REF, declarator, bounds);
+ declarator = build_nt (ARRAY_REF, declarator, bounds,
+ NULL_TREE, NULL_TREE);
}
else if (first && dcl_kind != CP_PARSER_DECLARATOR_ABSTRACT)
{
if (e1 == error_mark_node || e2 == error_mark_node)
return error_mark_node;
- return build_nt (ARRAY_REF, e1, e2);
+ return build_nt (ARRAY_REF, e1, e2, NULL_TREE, NULL_TREE);
}
case CALL_EXPR:
in_decl);
else
name = tsubst_copy (name, args, complain, in_decl);
- return build_nt (COMPONENT_REF, object, name);
+ return build_nt (COMPONENT_REF, object, name, NULL_TREE);
}
case PLUS_EXPR:
if (object)
return build (COMPONENT_REF, TREE_TYPE (template),
- object, template);
+ object, template, NULL_TREE);
else
return template;
}
if (tsubst_copy (TREE_OPERAND (t, 0), args, complain, in_decl)
== NULL_TREE)
/* new-type-id */
- return build_nt (ARRAY_REF, NULL_TREE, RECUR (TREE_OPERAND (t, 1)));
+ return build_nt (ARRAY_REF, NULL_TREE, RECUR (TREE_OPERAND (t, 1)),
+ NULL_TREE, NULL_TREE);
op1 = tsubst_non_call_postfix_expression (TREE_OPERAND (t, 0),
args, complain, in_decl);
type = cp_build_qualified_type (type, quals);
}
- return build_min (COMPONENT_REF, type, object, decl);
+ return build_min (COMPONENT_REF, type, object, decl, NULL_TREE);
}
else
{
/* Called from count_trees via walk_tree. */
static tree
-count_trees_r (tree* tp ATTRIBUTE_UNUSED ,
- int* walk_subtrees ATTRIBUTE_UNUSED ,
- void* data)
+count_trees_r (tree *tp, int *walk_subtrees, void *data)
{
- ++ *((int*) data);
+ ++*((int *) data);
+
+ if (TYPE_P (*tp))
+ *walk_subtrees = 0;
+
return NULL_TREE;
}
/* Passed to walk_tree. Checks for the use of types with no linkage. */
static tree
-no_linkage_helper (tree* tp,
- int* walk_subtrees ATTRIBUTE_UNUSED ,
- void* data ATTRIBUTE_UNUSED )
+no_linkage_helper (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED,
+ void *data ATTRIBUTE_UNUSED)
{
tree t = *tp;
&& (decl_function_context (TYPE_MAIN_DECL (t))
|| TYPE_ANONYMOUS_P (t)))
return t;
+
return NULL_TREE;
}
member_type = cp_build_qualified_type (member_type, type_quals);
}
- result = fold (build (COMPONENT_REF, member_type, object, member));
+ result = fold (build (COMPONENT_REF, member_type, object, member,
+ NULL_TREE));
/* Mark the expression const or volatile, as appropriate. Even
though we've dealt with the type above, we still have to mark the
type = unknown_type_node;
/* Note that we do not convert OBJECT to the BASELINK_BINFO
base. That will happen when the function is called. */
- result = build (COMPONENT_REF, type, object, member);
+ result = build (COMPONENT_REF, type, object, member, NULL_TREE);
}
else if (TREE_CODE (member) == CONST_DECL)
{
|| (TREE_CODE (name) == SCOPE_REF
&& TYPE_P (TREE_OPERAND (name, 0))
&& dependent_type_p (TREE_OPERAND (name, 0))))
- return build_min_nt (COMPONENT_REF, object, name);
+ return build_min_nt (COMPONENT_REF, object, name, NULL_TREE);
object = build_non_dependent_expr (object);
}
/*preserve_reference=*/false);
if (processing_template_decl && expr != error_mark_node)
return build_min_non_dep (COMPONENT_REF, expr,
- orig_object, orig_name);
+ orig_object, orig_name, NULL_TREE);
return expr;
}
/*want_type=*/false);
member_type = cp_build_qualified_type (TREE_TYPE (member),
cp_type_quals (ptrmem_type));
- return fold (build (COMPONENT_REF, member_type, ptrmem, member));
+ return fold (build (COMPONENT_REF, member_type, ptrmem, member, NULL_TREE));
}
/* Given an expression PTR for a pointer, return an expression
}
type = TREE_TYPE (TREE_TYPE (array));
- rval = build (ARRAY_REF, type, array, idx);
+ rval = build (ARRAY_REF, type, array, idx, NULL_TREE, NULL_TREE);
/* Array ref is const/volatile if the array elements are
or if the array is.. */
TREE_READONLY (rval)
if (TREE_CODE (value) == CONSTRUCTOR)
{
if (array_type_p)
- sub = build (ARRAY_REF, inner_type, dest, field_index);
+ sub = build (ARRAY_REF, inner_type, dest, field_index,
+ NULL_TREE, NULL_TREE);
else
- sub = build (COMPONENT_REF, inner_type, dest, field_index);
+ sub = build (COMPONENT_REF, inner_type, dest, field_index,
+ NULL_TREE);
split_nonconstant_init_1 (sub, value);
}
*pelt = TREE_CHAIN (elt);
if (array_type_p)
- sub = build (ARRAY_REF, inner_type, dest, field_index);
+ sub = build (ARRAY_REF, inner_type, dest, field_index,
+ NULL_TREE, NULL_TREE);
else
- sub = build (COMPONENT_REF, inner_type, dest, field_index);
+ sub = build (COMPONENT_REF, inner_type, dest, field_index,
+ NULL_TREE);
code = build (MODIFY_EXPR, inner_type, sub, value);
code = build_stmt (EXPR_STMT, code);
if (inner == TREE_OPERAND (ref, 0))
return ref;
else
- return build (COMPONENT_REF, TREE_TYPE (ref), inner,
- TREE_OPERAND (ref, 1));
+ return build (COMPONENT_REF, TREE_TYPE (ref), inner, TREE_OPERAND (ref, 1),
+ NULL_TREE);
}
/* Returns 1 if both MEM_EXPR can be considered equal
do
{
tree index = TREE_OPERAND (t2, 1);
- tree array = TREE_OPERAND (t2, 0);
- tree domain = TYPE_DOMAIN (TREE_TYPE (array));
- tree low_bound = (domain ? TYPE_MIN_VALUE (domain) : 0);
- tree unit_size = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (array)));
+ tree low_bound = array_ref_low_bound (t2);
+ tree unit_size = array_ref_element_size (t2);
/* We assume all arrays have sizes that are a multiple of a byte.
First subtract the lower bound, if any, in the type of the
- index, then convert to sizetype and multiply by the size of the
- array element. */
- if (low_bound != 0 && ! integer_zerop (low_bound))
+ index, then convert to sizetype and multiply by the size of
+ the array element. */
+ if (! integer_zerop (low_bound))
index = fold (build (MINUS_EXPR, TREE_TYPE (index),
index, low_bound));
- /* If the index has a self-referential type, instantiate it;
- likewise for the component size. */
- index = SUBSTITUTE_PLACEHOLDER_IN_EXPR (index, t2);
- unit_size = SUBSTITUTE_PLACEHOLDER_IN_EXPR (unit_size, array);
- off_tree
- = fold (build (PLUS_EXPR, sizetype,
- fold (build (MULT_EXPR, sizetype,
- index, unit_size)),
- off_tree));
+ off_tree = size_binop (PLUS_EXPR,
+ size_binop (MULT_EXPR, convert (sizetype,
+ index),
+ unit_size),
+ off_tree);
t2 = TREE_OPERAND (t2, 0);
}
while (TREE_CODE (t2) == ARRAY_REF);
if (TREE_CODE (expr) == COMPONENT_REF)
{
tree field = TREE_OPERAND (expr, 1);
+ tree offset = component_ref_field_offset (expr);
if (! DECL_SIZE_UNIT (field))
{
&& INTVAL (memoffset) >= 0)
break;
- if (! host_integerp (DECL_FIELD_OFFSET (field), 1))
+ if (! host_integerp (offset, 1))
{
expr = NULL_TREE;
break;
}
expr = TREE_OPERAND (expr, 0);
- memoffset = (GEN_INT (INTVAL (memoffset)
- + tree_low_cst (DECL_FIELD_OFFSET (field), 1)
- + (tree_low_cst (DECL_FIELD_BIT_OFFSET (field), 1)
- / BITS_PER_UNIT)));
+ memoffset
+ = (GEN_INT (INTVAL (memoffset)
+ + tree_low_cst (offset, 1)
+ + (tree_low_cst (DECL_FIELD_BIT_OFFSET (field), 1)
+ / BITS_PER_UNIT)));
}
/* Similarly for the decl. */
else if (DECL_P (expr)
STACK_SAVEAREA_MODE. Create a reference to array index 1, the first
of the stack save area slots. */
t_save = build (ARRAY_REF, ptr_type_node, cfun->nonlocal_goto_save_area,
- integer_one_node);
+ integer_one_node, NULL_TREE, NULL_TREE);
r_save = expand_expr (t_save, NULL_RTX, VOIDmode, EXPAND_WRITE);
emit_stack_save (SAVE_NONLOCAL, &r_save, NULL_RTX);
else if (TREE_CODE (exp) == COMPONENT_REF)
{
tree field = TREE_OPERAND (exp, 1);
- tree this_offset = DECL_FIELD_OFFSET (field);
+ tree this_offset = component_ref_field_offset (exp);
/* If this field hasn't been filled in yet, don't go
past it. This should only happen when folding expressions
made during type construction. */
if (this_offset == 0)
break;
- else
- this_offset = SUBSTITUTE_PLACEHOLDER_IN_EXPR (this_offset, exp);
offset = size_binop (PLUS_EXPR, offset, this_offset);
bit_offset = size_binop (PLUS_EXPR, bit_offset,
|| TREE_CODE (exp) == ARRAY_RANGE_REF)
{
tree index = TREE_OPERAND (exp, 1);
- tree array = TREE_OPERAND (exp, 0);
- tree domain = TYPE_DOMAIN (TREE_TYPE (array));
- tree low_bound = (domain ? TYPE_MIN_VALUE (domain) : 0);
- tree unit_size = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (array)));
+ tree low_bound = array_ref_low_bound (exp);
+ tree unit_size = array_ref_element_size (exp);
/* We assume all arrays have sizes that are a multiple of a byte.
First subtract the lower bound, if any, in the type of the
index, then convert to sizetype and multiply by the size of the
array element. */
- if (low_bound != 0 && ! integer_zerop (low_bound))
+ if (! integer_zerop (low_bound))
index = fold (build (MINUS_EXPR, TREE_TYPE (index),
index, low_bound));
- /* If the index has a self-referential type, instantiate it with
- the object; likewise for the component size. */
- index = SUBSTITUTE_PLACEHOLDER_IN_EXPR (index, exp);
- unit_size = SUBSTITUTE_PLACEHOLDER_IN_EXPR (unit_size, array);
offset = size_binop (PLUS_EXPR, offset,
size_binop (MULT_EXPR,
convert (sizetype, index),
return exp;
}
+/* Return a tree of sizetype representing the size, in bytes, of the element
+ of EXP, an ARRAY_REF. */
+
+tree
+array_ref_element_size (tree exp)
+{
+ tree aligned_size = TREE_OPERAND (exp, 3);
+ tree elmt_type = TREE_TYPE (TREE_TYPE (TREE_OPERAND (exp, 0)));
+
+ /* If a size was specified in the ARRAY_REF, it's the size measured
+ in alignment units of the element type. So multiply by that value. */
+ if (aligned_size)
+ return size_binop (MULT_EXPR, aligned_size,
+ size_int (TYPE_ALIGN (elmt_type) / BITS_PER_UNIT));
+
+ /* Otherwise, take the size from that of the element type. Substitute
+ any PLACEHOLDER_EXPR that we have. */
+ else
+ return SUBSTITUTE_PLACEHOLDER_IN_EXPR (TYPE_SIZE_UNIT (elmt_type), exp);
+}
+
+/* Return a tree representing the lower bound of the array mentioned in
+ EXP, an ARRAY_REF. */
+
+tree
+array_ref_low_bound (tree exp)
+{
+ tree domain_type = TYPE_DOMAIN (TREE_TYPE (TREE_OPERAND (exp, 0)));
+
+ /* If a lower bound is specified in EXP, use it. */
+ if (TREE_OPERAND (exp, 2))
+ return TREE_OPERAND (exp, 2);
+
+ /* Otherwise, if there is a domain type and it has a lower bound, use it,
+ substituting for a PLACEHOLDER_EXPR as needed. */
+ if (domain_type && TYPE_MIN_VALUE (domain_type))
+ return SUBSTITUTE_PLACEHOLDER_IN_EXPR (TYPE_MIN_VALUE (domain_type), exp);
+
+ /* Otherwise, return a zero of the appropriate type. */
+ return fold_convert (TREE_TYPE (TREE_OPERAND (exp, 1)), integer_zero_node);
+}
+
+/* Return a tree representing the offset, in bytes, of the field referenced
+ by EXP. This does not include any offset in DECL_FIELD_BIT_OFFSET. */
+
+tree
+component_ref_field_offset (tree exp)
+{
+ tree aligned_offset = TREE_OPERAND (exp, 2);
+ tree field = TREE_OPERAND (exp, 1);
+
+ /* If an offset was specified in the COMPONENT_REF, it's the offset measured
+ in units of DECL_OFFSET_ALIGN / BITS_PER_UNIT. So multiply by that
+ value. */
+ if (aligned_offset)
+ return size_binop (MULT_EXPR, aligned_offset,
+ size_int (DECL_OFFSET_ALIGN (field) / BITS_PER_UNIT));
+
+ /* Otherwise, take the offset from that of the field. Substitute
+ any PLACEHOLDER_EXPR that we have. */
+ else
+ return SUBSTITUTE_PLACEHOLDER_IN_EXPR (DECL_FIELD_OFFSET (field), exp);
+}
+
/* Return 1 if T is an expression that get_inner_reference handles. */
int
{
tree array = TREE_OPERAND (exp, 0);
- tree domain = TYPE_DOMAIN (TREE_TYPE (array));
- tree low_bound = domain ? TYPE_MIN_VALUE (domain) : integer_zero_node;
+ tree low_bound = array_ref_low_bound (exp);
tree index = convert (sizetype, TREE_OPERAND (exp, 1));
HOST_WIDE_INT i;
case COMPONENT_REF:
case INDIRECT_REF:
case ARRAY_REF:
+ case ARRAY_RANGE_REF:
case BIT_FIELD_REF:
case BUFFER_REF:
- case ARRAY_RANGE_REF:
case VTABLE_REF:
case REALPART_EXPR:
/* If VAROP is a reference to a bitfield, we must mask
the constant by the width of the field. */
if (TREE_CODE (TREE_OPERAND (varop, 0)) == COMPONENT_REF
- && DECL_BIT_FIELD (TREE_OPERAND (TREE_OPERAND (varop, 0), 1)))
+ && DECL_BIT_FIELD (TREE_OPERAND (TREE_OPERAND (varop, 0), 1))
+ && host_integerp (DECL_SIZE (TREE_OPERAND
+ (TREE_OPERAND (varop, 0), 1)), 1))
{
tree fielddecl = TREE_OPERAND (TREE_OPERAND (varop, 0), 1);
- int size = TREE_INT_CST_LOW (DECL_SIZE (fielddecl));
+ HOST_WIDE_INT size = tree_low_cst (DECL_SIZE (fielddecl), 1);
tree folded_compare, shift;
/* First check whether the comparison would come out
always the same. If we don't do that we would
change the meaning with the masking. */
folded_compare = fold (build2 (code, type,
- TREE_OPERAND (varop, 0),
- arg1));
+ TREE_OPERAND (varop, 0), arg1));
if (integer_zerop (folded_compare)
|| integer_onep (folded_compare))
return omit_one_operand (type, folded_compare, varop);
shift = build_int_2 (TYPE_PRECISION (TREE_TYPE (varop)) - size,
0);
+ shift = fold_convert (TREE_TYPE (varop), shift);
newconst = fold (build2 (LSHIFT_EXPR, TREE_TYPE (varop),
newconst, shift));
newconst = fold (build2 (RSHIFT_EXPR, TREE_TYPE (varop),
tree string;
if (TREE_CODE (exp) == INDIRECT_REF)
- {
- string = string_constant (exp1, &index);
- }
+ string = string_constant (exp1, &index);
else
{
- tree domain = TYPE_DOMAIN (TREE_TYPE (exp1));
- tree low_bound = domain ? TYPE_MIN_VALUE (domain) : integer_zero_node;
+ tree low_bound = array_ref_low_bound (exp);
index = fold_convert (sizetype, TREE_OPERAND (exp, 1));
/* Optimize the special-case of a zero lower bound.
}
if (string
+ && TREE_TYPE (exp) == TREE_TYPE (TREE_TYPE (string))
&& TREE_CODE (string) == STRING_CST
&& TREE_CODE (index) == INTEGER_CST
&& compare_tree_int (index, TREE_STRING_LENGTH (string)) < 0
/* *(foo *)&fooarray => fooarray[0] */
else if (TREE_CODE (optype) == ARRAY_TYPE
&& lang_hooks.types_compatible_p (type, TREE_TYPE (optype)))
- return build2 (ARRAY_REF, type, op, size_zero_node);
+ return build4 (ARRAY_REF, type, op, size_zero_node, NULL_TREE, NULL_TREE);
}
/* *(foo *)fooarrptr => (*fooarrptr)[0] */
&& lang_hooks.types_compatible_p (type, TREE_TYPE (TREE_TYPE (subtype))))
{
sub = build_fold_indirect_ref (sub);
- return build2 (ARRAY_REF, type, sub, size_zero_node);
+ return build4 (ARRAY_REF, type, sub, size_zero_node, NULL_TREE, NULL_TREE);
}
return build1 (INDIRECT_REF, type, t);
+2004-06-21 Richard Kenner <kenner@vlsi1.ultra.nyu.edu>
+
+ * f95-lang.c (LANG_HOOKS_GIMPLE_BEFORE_INLINING): Deleted.
+ * trans-array.c (gfc_conv_descriptor_data): Add operand
+ for COMPONENT_REF.
+ (gfc_conv_descriptor_offset, gfc_conv_descriptor_dtype): Likewise.
+ (gfc_conv_descriptor_dimension, gfc_conv_descriptor_stride): Likewise.
+ (gfc_conv_descriptor_lbound, gfc_conv_descriptor_ubound): Likewise.
+ * trans-common.c (create_common): Likewise.
+ * trans-expr.c (gfc_conv_component_ref): Likewise.
+ * trans-io.c (set_parameter_value): Likewise.
+ (set_parameter_ref, set_string, set_flag, io_result): Likewise.
+ (transfer_expr): Likewise.
+ * trans-decl.c (gfc_trans_auto_character_variable):
+ Set up to get DECL_SIZE and DECL_SIZE_UNIT gimplified.
+ (gfc_simplify_function): New function.
+ (gfc_generate_function-code): Properly handle nested functions.
+ * trans.c (gfc_build_array_ref): Add two new operands for ARRAY_REF.
+
2004-06-22 Janne Blomqvist <jblomqvi@cc.hut.fi>
PR fortran/15750
#undef LANG_HOOKS_UNSIGNED_TYPE
#undef LANG_HOOKS_SIGNED_TYPE
#undef LANG_HOOKS_SIGNED_OR_UNSIGNED_TYPE
-#undef LANG_HOOKS_GIMPLE_BEFORE_INLINING
#undef LANG_HOOKS_CALLGRAPH_EXPAND_FUNCTION
/* Define lang hooks. */
#define LANG_HOOKS_UNSIGNED_TYPE gfc_unsigned_type
#define LANG_HOOKS_SIGNED_TYPE gfc_signed_type
#define LANG_HOOKS_SIGNED_OR_UNSIGNED_TYPE gfc_signed_or_unsigned_type
-#define LANG_HOOKS_GIMPLE_BEFORE_INLINING false
#define LANG_HOOKS_CALLGRAPH_EXPAND_FUNCTION gfc_expand_function
const struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER;
&& TREE_CODE (TREE_TYPE (field)) == POINTER_TYPE
&& TREE_CODE (TREE_TYPE (TREE_TYPE (field))) == ARRAY_TYPE);
- return build (COMPONENT_REF, TREE_TYPE (field), desc, field);
+ return build (COMPONENT_REF, TREE_TYPE (field), desc, field, NULL_TREE);
}
tree
field = gfc_advance_chain (TYPE_FIELDS (type), OFFSET_FIELD);
assert (field != NULL_TREE && TREE_TYPE (field) == gfc_array_index_type);
- return build (COMPONENT_REF, TREE_TYPE (field), desc, field);
+ return build (COMPONENT_REF, TREE_TYPE (field), desc, field, NULL_TREE);
}
tree
field = gfc_advance_chain (TYPE_FIELDS (type), DTYPE_FIELD);
assert (field != NULL_TREE && TREE_TYPE (field) == gfc_array_index_type);
- return build (COMPONENT_REF, TREE_TYPE (field), desc, field);
+ return build (COMPONENT_REF, TREE_TYPE (field), desc, field, NULL_TREE);
}
static tree
&& TREE_CODE (TREE_TYPE (field)) == ARRAY_TYPE
&& TREE_CODE (TREE_TYPE (TREE_TYPE (field))) == RECORD_TYPE);
- tmp = build (COMPONENT_REF, TREE_TYPE (field), desc, field);
+ tmp = build (COMPONENT_REF, TREE_TYPE (field), desc, field, NULL_TREE);
tmp = gfc_build_array_ref (tmp, dim);
return tmp;
}
field = gfc_advance_chain (field, STRIDE_SUBFIELD);
assert (field != NULL_TREE && TREE_TYPE (field) == gfc_array_index_type);
- tmp = build (COMPONENT_REF, TREE_TYPE (field), tmp, field);
+ tmp = build (COMPONENT_REF, TREE_TYPE (field), tmp, field, NULL_TREE);
return tmp;
}
field = gfc_advance_chain (field, LBOUND_SUBFIELD);
assert (field != NULL_TREE && TREE_TYPE (field) == gfc_array_index_type);
- tmp = build (COMPONENT_REF, TREE_TYPE (field), tmp, field);
+ tmp = build (COMPONENT_REF, TREE_TYPE (field), tmp, field, NULL_TREE);
return tmp;
}
field = gfc_advance_chain (field, UBOUND_SUBFIELD);
assert (field != NULL_TREE && TREE_TYPE (field) == gfc_array_index_type);
- tmp = build (COMPONENT_REF, TREE_TYPE (field), tmp, field);
+ tmp = build (COMPONENT_REF, TREE_TYPE (field), tmp, field, NULL_TREE);
return tmp;
}
for (h = current_common; h; h = next_s)
{
h->sym->backend_decl = build (COMPONENT_REF, TREE_TYPE (h->field),
- decl, h->field);
+ decl, h->field, NULL_TREE);
next_s = h->next;
gfc_free (h);
DECL_DEFER_OUTPUT (decl) = 1;
+ /* Since we don't use a DECL_STMT or equivalent, we have to deal
+ with getting these gimplified. But we can't gimplify it yet since
+ we're still generating statements.
+
+ ??? This should be cleaned up and handled like other front ends. */
+ gfc_add_expr_to_block (&body, save_expr (DECL_SIZE (decl)));
+ gfc_add_expr_to_block (&body, save_expr (DECL_SIZE_UNIT (decl)));
+
/* Generate code to allocate the automatic variable. It will be freed
automatically. */
tmp = gfc_build_addr_expr (NULL, decl);
cgraph_finalize_function (decl, false);
}
+/* Convert FNDECL's code to GIMPLE and handle any nested functions. */
+
+static void
+gfc_gimplify_function (tree fndecl)
+{
+ struct cgraph_node *cgn;
+
+ gimplify_function_tree (fndecl);
+ dump_function (TDI_generic, fndecl);
+
+ /* Convert all nested functions to GIMPLE now. We do things in this order
+ so that items like VLA sizes are expanded properly in the context of the
+ correct function. */
+ cgn = cgraph_node (fndecl);
+ for (cgn = cgn->nested; cgn; cgn = cgn->next_nested)
+ gfc_gimplify_function (cgn->decl);
+}
+
/* Generate code for a function. */
void
current_function_decl = old_context;
if (decl_function_context (fndecl))
- {
- /* Register this function with cgraph just far enough to get it
- added to our parent's nested function list. */
- (void) cgraph_node (fndecl);
-
- /* Lowering nested functions requires gimple input. */
- gimplify_function_tree (fndecl);
- }
+ /* Register this function with cgraph just far enough to get it
+ added to our parent's nested function list. */
+ (void) cgraph_node (fndecl);
else
{
- if (cgraph_node (fndecl)->nested)
- {
- gimplify_function_tree (fndecl);
- lower_nested_functions (fndecl);
- }
+ gfc_gimplify_function (fndecl);
+ lower_nested_functions (fndecl);
gfc_finalize (fndecl);
}
}
-
void
gfc_generate_constructors (void)
{
field = c->backend_decl;
assert (TREE_CODE (field) == FIELD_DECL);
decl = se->expr;
- tmp = build (COMPONENT_REF, TREE_TYPE (field), decl, field);
+ tmp = build (COMPONENT_REF, TREE_TYPE (field), decl, field, NULL_TREE);
se->expr = tmp;
gfc_conv_expr_type (&se, e, TREE_TYPE (var));
gfc_add_block_to_block (block, &se.pre);
- tmp = build (COMPONENT_REF, TREE_TYPE (var), ioparm_var, var);
+ tmp = build (COMPONENT_REF, TREE_TYPE (var), ioparm_var, var, NULL_TREE);
gfc_add_modify_expr (block, tmp, se.expr);
}
gfc_conv_expr_type (&se, e, TREE_TYPE (var));
gfc_add_block_to_block (block, &se.pre);
- tmp = build (COMPONENT_REF, TREE_TYPE (var), ioparm_var, var);
+ tmp = build (COMPONENT_REF, TREE_TYPE (var), ioparm_var, var, NULL_TREE);
gfc_add_modify_expr (block, tmp, se.expr);
}
gfc_init_se (&se, NULL);
gfc_conv_expr (&se, e);
- io = build (COMPONENT_REF, TREE_TYPE (var), ioparm_var, var);
- len = build (COMPONENT_REF, TREE_TYPE (var_len), ioparm_var, var_len);
+ io = build (COMPONENT_REF, TREE_TYPE (var), ioparm_var, var, NULL_TREE);
+ len = build (COMPONENT_REF, TREE_TYPE (var_len), ioparm_var, var_len,
+ NULL_TREE);
/* Integer variable assigned a format label. */
if (e->ts.type == BT_INTEGER && e->symtree->n.sym->attr.assign == 1)
{
tree tmp;
- tmp = build (COMPONENT_REF, TREE_TYPE(var), ioparm_var, var);
+ tmp = build (COMPONENT_REF, TREE_TYPE(var), ioparm_var, var, NULL_TREE);
gfc_add_modify_expr (block, tmp, integer_one_node);
}
tmp = gfc_finish_block (&body);
rc = build (COMPONENT_REF, TREE_TYPE (ioparm_library_return), ioparm_var,
- ioparm_library_return);
+ ioparm_library_return, NULL_TREE);
tmp = build_v (SWITCH_EXPR, rc, tmp, NULL_TREE);
field = c->backend_decl;
assert (field && TREE_CODE (field) == FIELD_DECL);
- tmp = build (COMPONENT_REF, TREE_TYPE (field), expr, field);
+ tmp = build (COMPONENT_REF, TREE_TYPE (field), expr, field,
+ NULL_TREE);
if (c->ts.type == BT_CHARACTER)
{
if (DECL_P (base))
TREE_ADDRESSABLE (base) = 1;
- return build (ARRAY_REF, type, base, offset);
+ return build (ARRAY_REF, type, base, offset, NULL_TREE, NULL_TREE);
}
expand_var (TREE_OPERAND (cfun->nonlocal_goto_save_area, 0));
t_save = build (ARRAY_REF, ptr_type_node, cfun->nonlocal_goto_save_area,
- integer_zero_node);
+ integer_zero_node, NULL_TREE, NULL_TREE);
r_save = expand_expr (t_save, NULL_RTX, VOIDmode, EXPAND_WRITE);
emit_move_insn (r_save, virtual_stack_vars_rtx);
if (TREE_CODE (var) != VAR_DECL)
return true;
- ann = var_ann (var);
-
/* Remove all unused, unaliased temporaries. Also remove unused, unaliased
local variables during highly optimizing compilations. */
ann = var_ann (var);
/* Tree lowering pass. This pass converts the GENERIC functions-as-trees
tree representation into the GIMPLE form.
-
Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
Major work done by Sebastian Pop <s.pop@laposte.net>,
Diego Novillo <dnovillo@redhat.com> and Jason Merrill <jason@redhat.com>.
#include "langhooks.h"
#include "langhooks-def.h"
#include "tree-flow.h"
+#include "cgraph.h"
#include "timevar.h"
#include "except.h"
#include "hashtab.h"
tree temp; /* Value */
} elt_t;
+/* Forward declarations. */
+static hashval_t gimple_tree_hash (const void *);
+static int gimple_tree_eq (const void *, const void *);
+static bool gimple_conditional_context (void);
+static void gimple_push_condition (void);
+static void gimple_pop_condition (tree *);
+static void append_to_statement_list_1 (tree, tree *, bool);
+static inline void remove_suffix (char *, int);
+static inline tree create_tmp_from_val (tree);
+static tree lookup_tmp_var (tree, bool);
+static tree internal_get_tmp_var (tree, tree *, tree *, bool);
+static bool should_carry_locus_p (tree);
+static tree mostly_copy_tree_r (tree *, int *, void *);
+static tree mark_decls_volatile_r (tree *, int *, void *);
+static tree copy_if_shared_r (tree *, int *, void *);
+static tree unmark_visited_r (tree *, int *, void *);
+static void unshare_body (tree *, tree);
+static void unvisit_body (tree *, tree);
+static void build_stack_save_restore (tree *, tree *);
+static enum gimplify_status gimplify_bind_expr (tree *, tree, tree *);
+static enum gimplify_status gimplify_return_expr (tree, tree *);
+static enum gimplify_status gimplify_loop_expr (tree *, tree *);
+static int compare_case_labels (const void *, const void *);
+static enum gimplify_status gimplify_switch_expr (tree *, tree *);
+static enum gimplify_status gimplify_case_label_expr (tree *);
+static enum gimplify_status gimplify_labeled_block_expr (tree *);
+static enum gimplify_status gimplify_exit_block_expr (tree *);
+static enum gimplify_status gimplify_exit_expr (tree *);
+static enum gimplify_status gimplify_init_constructor (tree *, tree *, tree *,
+ bool);
+static void canonicalize_component_ref (tree *);
+static void canonicalize_addr_expr (tree *);
+static enum gimplify_status gimplify_conversion (tree *);
+static enum gimplify_status gimplify_minimax_expr (tree *, tree *, tree *);
+static enum gimplify_status gimplify_array_ref_to_plus (tree *, tree *,
+ tree *);
+static tree build_addr_expr_with_type (tree, tree);
+static tree build_addr_expr (tree);
+static enum gimplify_status gimplify_compound_lval (tree *, tree *, tree *,
+ bool);
+static enum gimplify_status gimplify_self_mod_expr (tree *, tree *, tree *,
+ bool);
+static enum gimplify_status gimplify_call_expr (tree *, tree *,
+ bool (*) (tree));
+static tree shortcut_cond_r (tree, tree *, tree *);
+static tree shortcut_cond_expr (tree);
+static tree gimple_boolify (tree);
+static enum gimplify_status gimplify_cond_expr (tree *, tree *, tree);
+static enum gimplify_status gimplify_modify_expr (tree *, tree *, tree *,
+ bool);
+static enum gimplify_status gimplify_modify_expr_rhs (tree *, tree *, tree *,
+ tree *, tree *, bool);
+static enum gimplify_status gimplify_variable_sized_compare (tree *);
+static enum gimplify_status gimplify_boolean_expr (tree *);
+static enum gimplify_status gimplify_compound_expr (tree *, tree *, bool);
+static enum gimplify_status gimplify_statement_list (tree *);
+static enum gimplify_status gimplify_save_expr (tree *, tree *, tree *);
+static enum gimplify_status gimplify_addr_expr (tree *, tree *, tree *);
+static enum gimplify_status gimplify_asm_expr (tree *, tree *, tree *);
+static enum gimplify_status gimplify_cleanup_point_expr (tree *, tree *);
+static void gimple_push_cleanup (tree, tree, tree *);
+static enum gimplify_status gimplify_target_expr (tree *, tree *, tree *);
+#ifdef ENABLE_CHECKING
+static bool cpt_same_type (tree, tree);
+static tree check_pointer_types_r (tree *, int *, void *);
+#endif
+
/* Return a hash value for a formal temporary table entry. */
static hashval_t
tree tmp_var;
#if defined ENABLE_CHECKING
- /* If the type is an array or a type which must be created by the
- frontend, something is wrong. */
- if (TREE_CODE (type) == ARRAY_TYPE || TREE_ADDRESSABLE (type))
- abort ();
- if (!COMPLETE_TYPE_P (type))
- abort ();
- /* Variable sized types require lots of machinery to create; the
- optimizers shouldn't be doing anything of the sort. */
- if (TREE_CODE (TYPE_SIZE_UNIT (type)) != INTEGER_CST)
+ /* We don't allow types that are addressable (meaning we can't make copies),
+ incomplete, or of variable size. */
+ if (TREE_ADDRESSABLE (type)
+ || !COMPLETE_TYPE_P (type)
+ || TREE_CODE (TYPE_SIZE_UNIT (type)) != INTEGER_CST)
abort ();
#endif
tree t = *tp;
enum tree_code code = TREE_CODE (t);
- /* Skip types, decls, and constants. */
+ /* Skip types, decls, and constants. But we do want to look at their
+ types and the bounds of types. Mark them as visited so we properly
+ unmark their subtrees on the unmark pass. If we've already seen them,
+ don't look down further. */
if (TREE_CODE_CLASS (code) == 't'
|| TREE_CODE_CLASS (code) == 'd'
|| TREE_CODE_CLASS (code) == 'c')
- *walk_subtrees = 0;
+ {
+ if (TREE_VISITED (t))
+ *walk_subtrees = 0;
+ else
+ TREE_VISITED (t) = 1;
+ }
/* Special-case BIND_EXPR. We should never be copying these, therefore
we can omit examining BIND_EXPR_VARS. Which also avoids problems with
return NULL_TREE;
}
+/* Unshare all the trees in BODY_P, a pointer to the body of FNDECL, and the
+ bodies of any nested functions. */
+
+static void
+unshare_body (tree *body_p, tree fndecl)
+{
+ struct cgraph_node *cgn = cgraph_node (fndecl);
+
+ walk_tree (body_p, copy_if_shared_r, NULL, NULL);
+ for (cgn = cgn->nested; cgn; cgn = cgn->next_nested)
+ unshare_body (&DECL_SAVED_TREE (cgn->decl), cgn->decl);
+}
+
+/* Likewise, but mark all trees as not visited. */
+
+static void
+unvisit_body (tree *body_p, tree fndecl)
+{
+ struct cgraph_node *cgn = cgraph_node (fndecl);
+
+ walk_tree (body_p, unmark_visited_r, NULL, NULL);
+ for (cgn = cgn->nested; cgn; cgn = cgn->next_nested)
+ unvisit_body (&DECL_SAVED_TREE (cgn->decl), cgn->decl);
+}
+
/* Unshare T and all the trees reached from T via TREE_CHAIN. */
void
{
if (label_p == NULL)
/* If there's nowhere to jump, just fall through. */
- return build_empty_stmt ();
+ return alloc_stmt_list ();
if (*label_p == NULL_TREE)
{
tree expr;
expr = build_and_jump (&gimplify_ctxp->exit_label);
- expr = build (COND_EXPR, void_type_node, cond, expr, build_empty_stmt ());
+ expr = build (COND_EXPR, void_type_node, cond, expr, alloc_stmt_list ());
*expr_p = expr;
return GS_OK;
static enum gimplify_status
gimplify_init_constructor (tree *expr_p, tree *pre_p,
- tree *post_p, int want_value)
+ tree *post_p, bool want_value)
{
tree object = TREE_OPERAND (*expr_p, 0);
tree ctor = TREE_OPERAND (*expr_p, 1);
return GS_OK;
}
else
- return GS_ALL_DONE;
+ return GS_UNHANDLED;
}
categorize_ctor_elements (ctor, &num_nonzero_elements,
TU-local symbol, we must invoke the lhd version now. */
lhd_set_decl_assembler_name (object);
- *expr_p = build_empty_stmt ();
+ *expr_p = alloc_stmt_list ();
break;
}
if (TREE_CODE (purpose) == RANGE_EXPR)
abort ();
- cref = build (ARRAY_REF, t, object, purpose);
+ cref = build (ARRAY_REF, t, object, purpose, NULL_TREE, NULL_TREE);
}
else
- {
- cref = build (COMPONENT_REF, TREE_TYPE (purpose),
- object, purpose);
- }
+ cref = build (COMPONENT_REF, TREE_TYPE (purpose), object,
+ purpose, NULL_TREE);
init = build (MODIFY_EXPR, TREE_TYPE (purpose), cref, value);
/* Each member initialization is a full-expression. */
append_to_statement_list (init, pre_p);
}
- *expr_p = build_empty_stmt ();
+ *expr_p = alloc_stmt_list ();
}
break;
}
/* If a NOP conversion is changing a pointer to array of foo to a pointer
- to foo, embed that change in the ADDR_EXPR. Lest we perturb the type
- system too badly, we must take extra steps to ensure that the ADDR_EXPR
- and the addressed object continue to agree on types. */
-/* ??? We might could do better if we recognize
- T array[N][M];
- (T *)&array
+ to foo, embed that change in the ADDR_EXPR by converting
+ T array[U];
+ (T *)&array
==>
- &array[0][0];
-*/
+ &array[L]
+ where L is the lower bound. Only do this for constant lower bound since
+ we have no place to put any statements made during gimplification of
+ the lower bound. */
static void
-canonicalize_addr_expr (tree* expr_p)
+canonicalize_addr_expr (tree *expr_p)
{
tree expr = *expr_p;
tree ctype = TREE_TYPE (expr);
if (!lang_hooks.types_compatible_p (otype, datype))
return;
+ /* The lower bound and element sizes must be constant. */
+ if (TREE_CODE (TYPE_SIZE_UNIT (dctype)) != INTEGER_CST
+ || !TYPE_DOMAIN (datype) || !TYPE_MIN_VALUE (TYPE_DOMAIN (datype))
+ || TREE_CODE (TYPE_MIN_VALUE (TYPE_DOMAIN (datype))) != INTEGER_CST)
+ return;
+
/* All checks succeeded. Build a new node to merge the cast. */
- *expr_p = build1 (ADDR_EXPR, ctype, obj_expr);
+ *expr_p = build4 (ARRAY_REF, dctype, obj_expr,
+ TYPE_MIN_VALUE (TYPE_DOMAIN (datype)),
+ TYPE_MIN_VALUE (TYPE_DOMAIN (datype)),
+ size_binop (EXACT_DIV_EXPR, TYPE_SIZE_UNIT (dctype),
+ size_int (TYPE_ALIGN (dctype)
+ / BITS_PER_UNIT)));
+ *expr_p = build1 (ADDR_EXPR, ctype, *expr_p);
}
/* *EXPR_P is a NOP_EXPR or CONVERT_EXPR. Remove it and/or other conversions
return GS_OK;
}
-/* Subroutine of gimplify_compound_lval and gimplify_array_ref.
+/* Subroutine of gimplify_compound_lval.
Converts an ARRAY_REF to the equivalent *(&array + offset) form. */
static enum gimplify_status
tree array = TREE_OPERAND (*expr_p, 0);
tree arrtype = TREE_TYPE (array);
tree elttype = TREE_TYPE (arrtype);
- tree size = size_in_bytes (elttype);
+ tree size = array_ref_element_size (*expr_p);
tree ptrtype = build_pointer_type (elttype);
enum tree_code add_code = PLUS_EXPR;
tree idx = TREE_OPERAND (*expr_p, 1);
- tree minidx, offset, addr, result;
+ tree minidx = unshare_expr (array_ref_low_bound (*expr_p));
+ tree offset, addr, result;
enum gimplify_status ret;
/* If the array domain does not start at zero, apply the offset. */
- minidx = TYPE_DOMAIN (arrtype);
- if (minidx)
+ if (!integer_zerop (minidx))
{
- minidx = TYPE_MIN_VALUE (minidx);
- if (minidx && !integer_zerop (minidx))
- {
- idx = convert (TREE_TYPE (minidx), idx);
- idx = fold (build (MINUS_EXPR, TREE_TYPE (minidx), idx, minidx));
- }
+ idx = convert (TREE_TYPE (minidx), idx);
+ idx = fold (build (MINUS_EXPR, TREE_TYPE (minidx), idx, minidx));
}
-
+
/* If the index is negative -- a technically invalid situation now
that we've biased the index back to zero -- then casting it to
unsigned has ill effects. In particular, -1*4U/4U != -1.
}
/* Pointer arithmetic must be done in sizetype. */
- idx = convert (sizetype, idx);
+ idx = fold_convert (sizetype, idx);
/* Convert the index to a byte offset. */
offset = size_binop (MULT_EXPR, size, idx);
return GS_OK;
}
+/* Build an expression for the address of T. Folds away INDIRECT_REF to
+ avoid confusing the gimplify process. */
+
+static tree
+build_addr_expr_with_type (tree t, tree ptrtype)
+{
+ if (TREE_CODE (t) == INDIRECT_REF)
+ {
+ t = TREE_OPERAND (t, 0);
+ if (TREE_TYPE (t) != ptrtype)
+ t = build1 (NOP_EXPR, ptrtype, t);
+ }
+ else
+ {
+ tree base = t;
+
+ if (TREE_CODE (base) == REALPART_EXPR
+ || TREE_CODE (base) == IMAGPART_EXPR)
+ base = TREE_OPERAND (base, 0);
+ else
+ while (handled_component_p (base))
+ base = TREE_OPERAND (base, 0);
+
+ if (DECL_P (base))
+ TREE_ADDRESSABLE (base) = 1;
+
+ t = build1 (ADDR_EXPR, ptrtype, t);
+ }
+
+ return t;
+}
+
+static tree
+build_addr_expr (tree t)
+{
+ return build_addr_expr_with_type (t, build_pointer_type (TREE_TYPE (t)));
+}
+
/* Gimplify the COMPONENT_REF, ARRAY_REF, REALPART_EXPR or IMAGPART_EXPR
node pointed by EXPR_P.
static enum gimplify_status
gimplify_compound_lval (tree *expr_p, tree *pre_p,
- tree *post_p, int want_lvalue)
+ tree *post_p, bool want_lvalue)
{
tree *p;
- enum tree_code code;
varray_type stack;
- enum gimplify_status ret;
+ enum gimplify_status ret = GS_OK, tret;
#if defined ENABLE_CHECKING
if (TREE_CODE (*expr_p) != ARRAY_REF
+ && TREE_CODE (*expr_p) != ARRAY_RANGE_REF
&& TREE_CODE (*expr_p) != COMPONENT_REF
+ && TREE_CODE (*expr_p) != BIT_FIELD_REF
&& TREE_CODE (*expr_p) != REALPART_EXPR
&& TREE_CODE (*expr_p) != IMAGPART_EXPR)
abort ();
#endif
- code = ERROR_MARK; /* [GIMPLE] Avoid uninitialized use warning. */
-
/* Create a stack of the subexpressions so later we can walk them in
order from inner to outer. */
VARRAY_TREE_INIT (stack, 10, "stack");
- for (p = expr_p;
- TREE_CODE (*p) == ARRAY_REF
- || TREE_CODE (*p) == COMPONENT_REF
- || TREE_CODE (*p) == REALPART_EXPR
- || TREE_CODE (*p) == IMAGPART_EXPR;
- p = &TREE_OPERAND (*p, 0))
- {
- code = TREE_CODE (*p);
- if (code == ARRAY_REF)
- {
- tree elttype = TREE_TYPE (TREE_TYPE (TREE_OPERAND (*p, 0)));
- if (!TREE_CONSTANT (TYPE_SIZE_UNIT (elttype)))
- /* If the size of the array elements is not constant,
- computing the offset is non-trivial, so expose it. */
- break;
- }
+ /* We can either handle one REALPART_EXPR or IMAGEPART_EXPR or
+ nest of handled components. */
+ if (TREE_CODE (*expr_p) == REALPART_EXPR
+ || TREE_CODE (*expr_p) == IMAGPART_EXPR)
+ p = &TREE_OPERAND (*expr_p, 0);
+ else
+ for (p = expr_p; handled_component_p (*p); p = &TREE_OPERAND (*p, 0))
VARRAY_PUSH_TREE (stack, *p);
- }
-
- /* Now 'p' points to the first bit that isn't a ref, 'code' is the
- TREE_CODE of the last bit that was, and 'stack' is a stack of pointers
- to all the refs we've walked through.
- Gimplify the base, and then process each of the outer nodes from left
- to right. */
- ret = gimplify_expr (p, pre_p, post_p, is_gimple_min_lval,
- code != ARRAY_REF ? fb_either : fb_lvalue);
+ /* Now STACK is a stack of pointers to all the refs we've walked through
+ and P points to the innermost expression.
+ Process each of the outer nodes from left to right, then gimplify the
+ base. We need to do it in this order so that PLACEHOLDER_EXPRs
+ can be resolved. */
for (; VARRAY_ACTIVE_SIZE (stack) > 0; )
{
tree t = VARRAY_TOP_TREE (stack);
- if (TREE_CODE (t) == ARRAY_REF)
+
+ if (TREE_CODE (t) == ARRAY_REF || TREE_CODE (t) == ARRAY_RANGE_REF)
{
- /* Gimplify the dimension. */
- enum gimplify_status tret;
- /* Temporary fix for gcc.c-torture/execute/20040313-1.c.
+ /* Gimplify the dimension.
+ Temporary fix for gcc.c-torture/execute/20040313-1.c.
Gimplify non-constant array indices into a temporary
variable.
FIXME - The real fix is to gimplify post-modify
{
tret = gimplify_expr (&TREE_OPERAND (t, 1), pre_p, post_p,
is_gimple_tmp_var, fb_rvalue);
- if (tret == GS_ERROR)
- ret = GS_ERROR;
+ ret = MIN (ret, tret);
+ }
+
+ /* Gimplify the low bound and element type size and put them into
+ the ARRAY_REF. If these values are set, they have already been
+ gimplified. */
+ if (!TREE_OPERAND (t, 2))
+ {
+ TREE_OPERAND (t, 2) = unshare_expr (array_ref_low_bound (t));
+ if (!is_gimple_min_invariant (TREE_OPERAND (t, 2)))
+ {
+ tret = gimplify_expr (&TREE_OPERAND (t, 2), pre_p, post_p,
+ is_gimple_tmp_var, fb_rvalue);
+ ret = MIN (ret, tret);
+ }
+ }
+
+ if (!TREE_OPERAND (t, 3))
+ {
+ tree elmt_type = TREE_TYPE (TREE_TYPE (TREE_OPERAND (t, 0)));
+ tree elmt_size = unshare_expr (array_ref_element_size (t));
+ tree factor = size_int (TYPE_ALIGN (elmt_type) / BITS_PER_UNIT);
+
+ /* Divide the element size by the alignment of the element
+ type (above). */
+ elmt_size = size_binop (EXACT_DIV_EXPR, elmt_size, factor);
+
+ TREE_OPERAND (t, 3) = elmt_size;
+ if (!is_gimple_min_invariant (TREE_OPERAND (t, 3)))
+ {
+ tret = gimplify_expr (&TREE_OPERAND (t, 3), pre_p, post_p,
+ is_gimple_tmp_var, 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))
+ {
+ tree offset = unshare_expr (component_ref_field_offset (t));
+ tree field = TREE_OPERAND (t, 1);
+ tree factor
+ = size_int (DECL_OFFSET_ALIGN (field) / BITS_PER_UNIT);
+
+ /* Divide the offset by its alignment. */
+ offset = size_binop (EXACT_DIV_EXPR, offset, factor);
+
+ TREE_OPERAND (t, 2) = offset;
+ if (!is_gimple_min_invariant (TREE_OPERAND (t, 2)))
+ {
+ tret = gimplify_expr (&TREE_OPERAND (t, 2), pre_p, post_p,
+ is_gimple_tmp_var, fb_rvalue);
+ ret = MIN (ret, tret);
+ }
+ }
+ }
+ else if (TREE_CODE (t) == BIT_FIELD_REF)
+ {
+ tret = gimplify_expr (&TREE_OPERAND (t, 1), pre_p, post_p,
+ is_gimple_val, fb_rvalue);
+ ret = MIN (ret, tret);
+ tret = gimplify_expr (&TREE_OPERAND (t, 2), pre_p, post_p,
+ is_gimple_val, fb_rvalue);
+ ret = MIN (ret, tret);
+ }
+
recalculate_side_effects (t);
VARRAY_POP (stack);
}
+ tret = gimplify_expr (p, pre_p, post_p, is_gimple_min_lval,
+ want_lvalue ? fb_lvalue : fb_rvalue);
+ ret = MIN (ret, tret);
+
/* If the outermost expression is a COMPONENT_REF, canonicalize its type. */
if (!want_lvalue && TREE_CODE (*expr_p) == COMPONENT_REF)
{
return ret;
}
-/* Re-write the ARRAY_REF node pointed by EXPR_P.
-
- PRE_P points to the list where side effects that must happen before
- *EXPR_P should be stored.
-
- POST_P points to the list where side effects that must happen after
- *EXPR_P should be stored.
-
- FIXME: ARRAY_REF currently doesn't accept a pointer as the array
- argument, so this gimplification uses an INDIRECT_REF of ARRAY_TYPE.
- ARRAY_REF should be extended. */
-
-static enum gimplify_status
-gimplify_array_ref (tree *expr_p, tree *pre_p,
- tree *post_p, int want_lvalue)
-{
- tree elttype = TREE_TYPE (TREE_TYPE (TREE_OPERAND (*expr_p, 0)));
- if (!TREE_CONSTANT (TYPE_SIZE_UNIT (elttype)))
- /* If the size of the array elements is not constant,
- computing the offset is non-trivial, so expose it. */
- return gimplify_array_ref_to_plus (expr_p, pre_p, post_p);
- else
- /* Handle array and member refs together for now. When alias analysis
- improves, we may want to go back to handling them separately. */
- return gimplify_compound_lval (expr_p, pre_p, post_p, want_lvalue);
-}
-
/* Gimplify the self modifying expression pointed by EXPR_P (++, --, +=, -=).
PRE_P points to the list where side effects that must happen before
static enum gimplify_status
gimplify_self_mod_expr (tree *expr_p, tree *pre_p, tree *post_p,
- int want_value)
+ bool want_value)
{
enum tree_code code;
tree lhs, lvalue, rhs, t1;
then_ = shortcut_cond_expr (expr);
pred = TREE_OPERAND (pred, 0);
expr = build (COND_EXPR, void_type_node, pred, then_,
- build_empty_stmt ());
+ alloc_stmt_list ());
}
}
if (!TREE_SIDE_EFFECTS (then_))
else_ = shortcut_cond_expr (expr);
pred = TREE_OPERAND (pred, 0);
expr = build (COND_EXPR, void_type_node, pred,
- build_empty_stmt (), else_);
+ alloc_stmt_list (), else_);
}
}
&& TREE_CODE (GOTO_DESTINATION (then_)) == LABEL_DECL)
{
true_label = GOTO_DESTINATION (then_);
- then_ = build_empty_stmt ();
+ then_ = alloc_stmt_list ();
}
if (TREE_CODE (else_) == GOTO_EXPR
&& TREE_CODE (GOTO_DESTINATION (else_)) == LABEL_DECL)
{
false_label = GOTO_DESTINATION (else_);
- else_ = build_empty_stmt ();
+ else_ = alloc_stmt_list ();
}
/* If we aren't hijacking a label for the 'then' branch, it falls through. */
The second form is used when *EXPR_P is of type void.
+ TARGET is the tree for T1 above.
+
PRE_P points to the list where side effects that must happen before
*EXPR_P should be stored. */
{
tree *from_p = &TREE_OPERAND (*expr_p, 1);
tree *to_p = &TREE_OPERAND (*expr_p, 0);
- enum gimplify_status ret;
+ enum gimplify_status ret = GS_UNHANDLED;
#if defined ENABLE_CHECKING
if (TREE_CODE (*expr_p) != MODIFY_EXPR && TREE_CODE (*expr_p) != INIT_EXPR)
if (TREE_CODE (*expr_p) == INIT_EXPR)
TREE_SET_CODE (*expr_p, MODIFY_EXPR);
- ret = gimplify_expr (to_p, pre_p, post_p, is_gimple_lvalue, fb_lvalue);
- if (ret == GS_ERROR)
+ /* See if any simplifications can be done based on what the RHS is. */
+ ret = gimplify_modify_expr_rhs (expr_p, from_p, to_p, pre_p, post_p,
+ want_value);
+ if (ret != GS_UNHANDLED)
return ret;
- /* If we are initializing something from a TARGET_EXPR, strip the
- TARGET_EXPR and initialize it directly, if possible. This can't
- be done if the initializer is void, since that implies that the
- temporary is set in some non-trivial way. */
- /* What about code that pulls out the temp and uses it elsewhere? I
- think that such code never uses the TARGET_EXPR as an initializer. If
- I'm wrong, we'll abort because the temp won't have any RTL. In that
- case, I guess we'll need to replace references somehow. */
- if (TREE_CODE (*from_p) == TARGET_EXPR)
+ /* If the value being copied is of variable width, expose the length
+ if the copy by converting the whole thing to a memcpy. Note that
+ we need to do this before gimplifying any of the operands
+ so that we can resolve any PLACEHOLDER_EXPRs in the size. */
+ if (TREE_CODE (TYPE_SIZE_UNIT (TREE_TYPE (*to_p))) != INTEGER_CST)
{
- tree init = TARGET_EXPR_INITIAL (*from_p);
- if (!VOID_TYPE_P (TREE_TYPE (init)))
- *from_p = init;
+ tree args, t, dest;
+
+ t = TYPE_SIZE_UNIT (TREE_TYPE (*to_p));
+ t = SUBSTITUTE_PLACEHOLDER_IN_EXPR (t, *to_p);
+ t = SUBSTITUTE_PLACEHOLDER_IN_EXPR (t, *from_p);
+ t = unshare_expr (t);
+ args = tree_cons (NULL, t, NULL);
+ t = build_fold_addr_expr (*from_p);
+ args = tree_cons (NULL, t, args);
+ dest = build_fold_addr_expr (*to_p);
+ args = tree_cons (NULL, dest, args);
+ t = implicit_built_in_decls[BUILT_IN_MEMCPY];
+ t = build_function_call_expr (t, args);
+ if (want_value)
+ {
+ t = build1 (NOP_EXPR, TREE_TYPE (dest), t);
+ t = build1 (INDIRECT_REF, TREE_TYPE (*to_p), t);
+ }
+ *expr_p = t;
+ return GS_OK;
}
- /* If we're assigning from a ?: expression with ADDRESSABLE type, push
- the assignment down into the branches, since we can't generate a
- temporary of such a type. */
- if (TREE_CODE (*from_p) == COND_EXPR
- && TREE_ADDRESSABLE (TREE_TYPE (*from_p)))
- {
- *expr_p = *from_p;
- return gimplify_cond_expr (expr_p, pre_p, *to_p);
- }
+ ret = gimplify_expr (to_p, pre_p, post_p, is_gimple_lvalue, fb_lvalue);
+ if (ret == GS_ERROR)
+ return ret;
ret = gimplify_expr (from_p, pre_p, post_p, is_gimple_rhs, fb_rvalue);
if (ret == GS_ERROR)
return ret;
- ret = gimplify_init_constructor (expr_p, pre_p, post_p, want_value);
+ /* Now see if the above changed *from_p to something we handle specially. */
+ ret = gimplify_modify_expr_rhs (expr_p, from_p, to_p, pre_p, post_p,
+ want_value);
if (ret != GS_UNHANDLED)
return ret;
&& !is_gimple_reg (*to_p)))
gimplify_expr (from_p, pre_p, post_p, is_gimple_val, fb_rvalue);
- /* If the value being copied is of variable width, expose the length
- if the copy by converting the whole thing to a memcpy. */
- /* ??? Except that we can't manage this with VA_ARG_EXPR. Yes, this
- does leave us with an edge condition that doesn't work. The only
- way out is to rearrange how VA_ARG_EXPR works. */
- if (TREE_CODE (TYPE_SIZE_UNIT (TREE_TYPE (*to_p))) != INTEGER_CST
- && TREE_CODE (*from_p) != VA_ARG_EXPR)
- {
- tree args, t, dest;
-
- t = TYPE_SIZE_UNIT (TREE_TYPE (*to_p));
- t = unshare_expr (t);
- args = tree_cons (NULL, t, NULL);
- t = build_fold_addr_expr (*from_p);
- args = tree_cons (NULL, t, args);
- dest = build_fold_addr_expr (*to_p);
- args = tree_cons (NULL, dest, args);
- t = implicit_built_in_decls[BUILT_IN_MEMCPY];
- t = build_function_call_expr (t, args);
- if (want_value)
- {
- t = build1 (NOP_EXPR, TREE_TYPE (dest), t);
- t = build1 (INDIRECT_REF, TREE_TYPE (*to_p), t);
- }
- *expr_p = t;
-
- return GS_OK;
- }
-
ret = want_value ? GS_OK : GS_ALL_DONE;
}
return ret;
}
+/* Subroutine of above to do simplications of MODIFY_EXPRs based on
+ the code of the RHS. We loop for as long as we can do something. */
+
+static enum gimplify_status
+gimplify_modify_expr_rhs (tree *expr_p, tree *from_p, tree *to_p, tree *pre_p,
+ tree *post_p, bool want_value)
+{
+ enum gimplify_status ret = GS_OK;
+
+ while (ret != GS_UNHANDLED)
+ switch (TREE_CODE (*from_p))
+ {
+ case TARGET_EXPR:
+ {
+ /* If we are initializing something from a TARGET_EXPR, strip the
+ TARGET_EXPR and initialize it directly, if possible. This can't
+ be done if the initializer is void, since that implies that the
+ temporary is set in some non-trivial way.
+
+ ??? What about code that pulls out the temp and uses it
+ elsewhere? I think that such code never uses the TARGET_EXPR as
+ an initializer. If I'm wrong, we'll abort because the temp won't
+ have any RTL. In that case, I guess we'll need to replace
+ references somehow. */
+ tree init = TARGET_EXPR_INITIAL (*from_p);
+
+ if (!VOID_TYPE_P (TREE_TYPE (init)))
+ {
+ *from_p = init;
+ ret = GS_OK;
+ }
+ else
+ ret = GS_UNHANDLED;
+ }
+ break;
+
+ case COMPOUND_EXPR:
+ /* Remove any COMPOUND_EXPR in the RHS so the following cases will be
+ caught. */
+ gimplify_compound_expr (from_p, pre_p, true);
+ ret = GS_OK;
+ break;
+
+ case CONSTRUCTOR:
+ /* If we're initializing from a CONSTRUCTOR, break this into
+ individual MODIFY_EXPRs. */
+ return gimplify_init_constructor (expr_p, pre_p, post_p, want_value);
+
+ case COND_EXPR:
+ /* If we're assigning from a ?: expression with ADDRESSABLE type, push
+ the assignment down into the branches, since we can't generate a
+ temporary of such a type. */
+ if (TREE_ADDRESSABLE (TREE_TYPE (*from_p)))
+ {
+ *expr_p = *from_p;
+ return gimplify_cond_expr (expr_p, pre_p, *to_p);
+ }
+ else
+ ret = GS_UNHANDLED;
+ break;
+
+ default:
+ ret = GS_UNHANDLED;
+ break;
+ }
+
+ return ret;
+}
+
+/* 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)
+{
+ tree op0 = TREE_OPERAND (*expr_p, 0);
+ tree op1 = TREE_OPERAND (*expr_p, 1);
+ tree args, t, dest;
+
+ t = TYPE_SIZE_UNIT (TREE_TYPE (op0));
+ t = SUBSTITUTE_PLACEHOLDER_IN_EXPR (t, op0);
+ t = unshare_expr (t);
+ args = tree_cons (NULL, t, NULL);
+ t = build_addr_expr (op1);
+ args = tree_cons (NULL, t, args);
+ dest = build_addr_expr (op0);
+ args = tree_cons (NULL, dest, args);
+ t = implicit_built_in_decls[BUILT_IN_MEMCMP];
+ t = build_function_call_expr (t, args);
+ *expr_p
+ = build (TREE_CODE (*expr_p), TREE_TYPE (*expr_p), t, integer_zero_node);
+
+ return GS_OK;
+}
+
/* Gimplify TRUTH_ANDIF_EXPR and TRUTH_ORIF_EXPR expressions. EXPR_P
points to the expression to gimplify.
tree body = TREE_OPERAND (*expr_p, 0);
ret = gimplify_expr (& body, pre_p, post_p, is_gimple_stmt, fb_none);
append_to_statement_list (body, pre_p);
- *expr_p = build_empty_stmt ();
+ *expr_p = alloc_stmt_list ();
}
else
*expr_p = TREE_OPERAND (*expr_p, 0)
pre_p, post_p);
/* This added an INDIRECT_REF. Fold it away. */
- op0 = TREE_OPERAND (TREE_OPERAND (expr, 0), 0);
+ *expr_p = TREE_OPERAND (TREE_OPERAND (expr, 0), 0);
+ break;
- *expr_p = op0;
+ case VIEW_CONVERT_EXPR:
+ /* Take the address of our operand and then convert it to the type of
+ this ADDR_EXPR. */
+ *expr_p = fold_convert (TREE_TYPE (expr),
+ build_addr_expr (TREE_OPERAND (op0, 0)));
+ ret = GS_OK;
break;
default:
tree ftrue = build (MODIFY_EXPR, void_type_node, flag,
boolean_true_node);
cleanup = build (COND_EXPR, void_type_node, flag, cleanup,
- build_empty_stmt ());
+ alloc_stmt_list ());
wce = build (WITH_CLEANUP_EXPR, void_type_node, NULL_TREE,
cleanup, NULL_TREE);
append_to_statement_list (ffalse, &gimplify_ctxp->conditional_cleanups);
break;
case ARRAY_REF:
- ret = gimplify_array_ref (expr_p, pre_p, post_p,
- fallback & fb_lvalue);
- break;
-
+ case ARRAY_RANGE_REF:
+ case REALPART_EXPR:
+ case IMAGPART_EXPR:
case COMPONENT_REF:
ret = gimplify_compound_lval (expr_p, pre_p, post_p,
fallback & fb_lvalue);
ret = gimplify_compound_expr (expr_p, pre_p, fallback != fb_none);
break;
- case REALPART_EXPR:
- case IMAGPART_EXPR:
- ret = gimplify_compound_lval (expr_p, pre_p, post_p,
- fallback & fb_lvalue);
- break;
-
case MODIFY_EXPR:
case INIT_EXPR:
ret = gimplify_modify_expr (expr_p, pre_p, post_p,
ret = gimplify_va_arg_expr (expr_p, pre_p, post_p);
break;
+ case VIEW_CONVERT_EXPR:
+ if (VOID_TYPE_P (TREE_TYPE (*expr_p))
+ || fallback == fb_none)
+ {
+ /* Just strip a conversion to void (or in void context) and
+ try again. */
+ *expr_p = TREE_OPERAND (*expr_p, 0);
+ break;
+ }
+
+ /* If both types are BLKmode or if one type is of variable size,
+ convert this into a pointer punning operation. This avoids
+ copies of large data or making a variable-size temporary. */
+ if ((TYPE_MODE (TREE_TYPE (*expr_p)) == BLKmode
+ && TYPE_MODE (TREE_TYPE (TREE_OPERAND (*expr_p, 0))) == BLKmode)
+ || !TREE_CONSTANT (TYPE_SIZE (TREE_TYPE (*expr_p)))
+ || !TREE_CONSTANT (TYPE_SIZE (TREE_TYPE
+ (TREE_OPERAND (*expr_p,0)))))
+ {
+ tree restype = TREE_TYPE (*expr_p);
+ *expr_p = build1 (INDIRECT_REF, TREE_TYPE (*expr_p),
+ fold_convert (build_pointer_type (restype),
+ build_addr_expr
+ (TREE_OPERAND (*expr_p, 0))));
+ break;
+ }
+ goto unary;
+
case CONVERT_EXPR:
case NOP_EXPR:
if (IS_EMPTY_STMT (*expr_p))
case FIX_CEIL_EXPR:
case FIX_FLOOR_EXPR:
case FIX_ROUND_EXPR:
+ unary:
/* unary_expr: ... | '(' cast ')' val | ... */
ret = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p,
is_gimple_val, fb_rvalue);
break;
default:
+ /* If this is a comparison of objects of aggregate type, handle
+ it specially (by converting to a call to memcmp). It would be
+ nice to only have to do this for variable-sized objects, but
+ then we'd have to allow the same nest of reference nodes we
+ allow for MODIFY_EXPR and that's too complex. */
+ if (TREE_CODE_CLASS (TREE_CODE (*expr_p)) == '<'
+ && (AGGREGATE_TYPE_P (TREE_TYPE (TREE_OPERAND (*expr_p, 1)))))
+ ret = gimplify_variable_sized_compare (expr_p);
+
/* If *EXPR_P does not need to be special-cased, handle it
according to its class. */
- if (TREE_CODE_CLASS (TREE_CODE (*expr_p)) == '1')
+ else if (TREE_CODE_CLASS (TREE_CODE (*expr_p)) == '1')
ret = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p,
post_p, is_gimple_val, fb_rvalue);
else if (TREE_CODE_CLASS (TREE_CODE (*expr_p)) == '2'
if (ret == GS_ERROR)
{
if (is_statement)
- *expr_p = build_empty_stmt ();
+ *expr_p = alloc_stmt_list ();
goto out;
}
#endif
if (!*expr_p)
- *expr_p = build_empty_stmt ();
+ *expr_p = alloc_stmt_list ();
if (fallback == fb_none && !is_gimple_stmt (*expr_p))
{
/* We aren't looking for a value, and we don't have a valid
statement. If it doesn't have side-effects, throw it away. */
if (!TREE_SIDE_EFFECTS (*expr_p))
- *expr_p = build_empty_stmt ();
+ *expr_p = alloc_stmt_list ();
else if (!TREE_THIS_VOLATILE (*expr_p))
- /* We only handle volatiles here; anything else with side-effects
- must be converted to a valid statement before we get here. */
- abort ();
+ {
+ /* This is probably a _REF that contains something nested that
+ has side effects. Recurse through the operands to find it. */
+ enum tree_code code = TREE_CODE (*expr_p);
+
+ if (code == COMPONENT_REF
+ || code == REALPART_EXPR || code == IMAGPART_EXPR)
+ gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p,
+ gimple_test_f, fallback);
+ else if (code == ARRAY_REF || code == ARRAY_RANGE_REF)
+ {
+ gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p,
+ gimple_test_f, fallback);
+ gimplify_expr (&TREE_OPERAND (*expr_p, 1), pre_p, post_p,
+ gimple_test_f, fallback);
+ }
+ else
+ /* Anything else with side-effects
+ must be converted to a valid statement before we get here. */
+ abort ();
+
+ *expr_p = alloc_stmt_list ();
+ }
else if (COMPLETE_TYPE_P (TREE_TYPE (*expr_p)))
{
/* Historically, the compiler has treated a bare
else
/* We can't do anything useful with a volatile reference to
incomplete type, so just throw it away. */
- *expr_p = build_empty_stmt ();
+ *expr_p = alloc_stmt_list ();
}
/* If we are gimplifying at the statement level, we're done. Tack
return ret;
}
+/* Look through TYPE for variable-sized objects and gimplify each such
+ size that we find. Return a STATEMENT_LIST containing the result. */
+
+tree
+gimplify_type_sizes (tree type)
+{
+ tree stmts = NULL_TREE;
+ tree field;
+
+ switch (TREE_CODE (type))
+ {
+ case ERROR_MARK:
+ return alloc_stmt_list ();
+
+ case INTEGER_TYPE:
+ case ENUMERAL_TYPE:
+ case BOOLEAN_TYPE:
+ case CHAR_TYPE:
+ case REAL_TYPE:
+ gimplify_one_sizepos (&TYPE_MIN_VALUE (type), &stmts);
+ gimplify_one_sizepos (&TYPE_MAX_VALUE (type), &stmts);
+ break;
+
+ case ARRAY_TYPE:
+ /* These anonymous types don't have declarations, so handle them here. */
+ append_to_statement_list (gimplify_type_sizes (TYPE_DOMAIN (type)),
+ &stmts);
+ break;
+
+ case RECORD_TYPE:
+ case UNION_TYPE:
+ case QUAL_UNION_TYPE:
+ for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
+ if (TREE_CODE (field) == FIELD_DECL)
+ gimplify_one_sizepos (&DECL_FIELD_OFFSET (field), &stmts);
+ break;
+
+ default:
+ break;
+ }
+
+ gimplify_one_sizepos (&TYPE_SIZE (type), &stmts);
+ gimplify_one_sizepos (&TYPE_SIZE_UNIT (type), &stmts);
+
+ if (!stmts)
+ stmts = alloc_stmt_list ();
+
+ return stmts;
+}
+
+/* Subroutine of the above to gimplify one size or position, *EXPR_P.
+ We add any required statements to STMT_P. */
+
+void
+gimplify_one_sizepos (tree *expr_p, tree *stmt_p)
+{
+ tree pre = NULL_TREE, post = NULL_TREE;
+
+ /* We don't do anything if the value isn't there, is constant, or contains
+ A PLACEHOLDER_EXPR. */
+ if (*expr_p == NULL_TREE || TREE_CONSTANT (*expr_p)
+ || CONTAINS_PLACEHOLDER_P (*expr_p))
+ return;
+
+ gimplify_expr (expr_p, &pre, &post, is_gimple_val, fb_rvalue);
+
+ if (pre)
+ append_to_statement_list (pre, stmt_p);
+ if (post)
+ append_to_statement_list (post, stmt_p);
+}
+\f
#ifdef ENABLE_CHECKING
/* Compare types A and B for a "close enough" match. */
dtype = TREE_TYPE (ptype);
if (!cpt_same_type (otype, dtype))
{
- /* &array is allowed to produce a pointer to the element,
- rather than a pointer to the array type. */
+ /* &array is allowed to produce a pointer to the element, rather than
+ a pointer to the array type. We must allow this in order to
+ properly represent assigning the address of an array in C into
+ pointer to the element type. */
if (TREE_CODE (otype) == ARRAY_TYPE
&& POINTER_TYPE_P (ptype)
&& cpt_same_type (TREE_TYPE (otype), dtype))
timevar_push (TV_TREE_GIMPLIFY);
push_gimplify_context ();
- /* Unshare most shared trees in the body. */
- unshare_all_trees (*body_p);
+ /* Unshare most shared trees in the body and in that of any nested functions.
+ It would seem we don't have to do this for nested functions because
+ they are supposed to be output and then the outer function gimplified
+ first, but the g++ front end doesn't always do it that way. */
+ unshare_body (body_p, fndecl);
+ unvisit_body (body_p, fndecl);
/* Make sure input_location isn't set to something wierd. */
input_location = DECL_SOURCE_LOCATION (fndecl);
/* Unshare again, in case gimplification was sloppy. */
unshare_all_trees (body);
- /* If there isn't an outer BIND_EXPR, add one. */
if (TREE_CODE (body) == STATEMENT_LIST)
{
tree t = expr_only (*body_p);
if (t)
body = t;
}
+
+ /* If there isn't an outer BIND_EXPR, add one. */
if (TREE_CODE (body) != BIND_EXPR)
{
tree b = build (BIND_EXPR, void_type_node, NULL_TREE,
+2004-06-21 Richard Kenner <kenner@vlsi1.ultra.nyu.edu>
+
+ * class.c (build_class_ref): Add new operand for COMPONENT_REF.
+ (build_static_field_ref): Likewise and add new operands for ARRAY_REF.
+ * constants.c (build_ref_from_constant_pool): Likewise.
+ * expr.c (build_java_array_length_access): Likewise.
+ (build_get_class, build_field_ref, build_known_method_ref): Likewise.
+ (invoke_build_dtable, build_invokevirtual): Likewise.
+ (build_invokeinterface, java_expand_expr): Likewise.
+ (emit_init_test_initialization): Likewise.
+ * java-gimplify.c (java_gimplify_new_array_init): Likewise.
+ * parse.y (make_qualifed_name, build_array_ref): Likewise.
+
2004-06-21 Andrew Haley <aph@redhat.com>
* java-gimplify.c (java_gimplify_block): set TREE_USED on the new
prim_class = lookup_class (get_identifier (prim_class_name));
return build (COMPONENT_REF, NULL_TREE,
- prim_class, TYPE_identifier_node);
+ prim_class, TYPE_identifier_node, NULL_TREE);
}
decl_name = TYPE_NAME (type);
if (TREE_CODE (decl_name) == TYPE_DECL)
(fdecl, &TYPE_ATABLE_METHODS (output_class)), 0);
tree field_address
= build (ARRAY_REF, build_pointer_type (TREE_TYPE (fdecl)),
- TYPE_ATABLE_DECL (output_class), table_index);
+ TYPE_ATABLE_DECL (output_class), table_index,
+ NULL_TREE, NULL_TREE);
return fold (build1 (INDIRECT_REF, TREE_TYPE (fdecl),
field_address));
}
int field_index = 0;
ref = build1 (INDIRECT_REF, class_type_node, ref);
ref = build (COMPONENT_REF, field_ptr_type_node, ref,
- lookup_field (&class_type_node, fields_ident));
+ lookup_field (&class_type_node, fields_ident),
+ NULL_TREE);
for (fld = TYPE_FIELDS (fclass); ; fld = TREE_CHAIN (fld))
{
ref, build_int_2 (field_index, 0)));
ref = build1 (INDIRECT_REF, field_type_node, ref);
ref = build (COMPONENT_REF, field_info_union_node,
- ref, lookup_field (&field_type_node, info_ident));
+ ref, lookup_field (&field_type_node, info_ident),
+ NULL_TREE);
ref = build (COMPONENT_REF, ptr_type_node,
- ref, TREE_CHAIN (TYPE_FIELDS (field_info_union_node)));
+ ref, TREE_CHAIN (TYPE_FIELDS (field_info_union_node)),
+ NULL_TREE);
return fold (build1 (INDIRECT_REF, TREE_TYPE(fdecl), ref));
}
}
{
tree d = build_constant_data_ref ();
tree i = build_int_2 (index, 0);
- return build (ARRAY_REF, TREE_TYPE (TREE_TYPE (d)), d, i);
+ return build (ARRAY_REF, TREE_TYPE (TREE_TYPE (d)), d, i,
+ NULL_TREE, NULL_TREE);
}
/* Build an initializer for the constants field of the current constant pool.
node = build (COMPONENT_REF, int_type_node,
build_java_indirect_ref (array_type, node,
flag_check_references),
- lookup_field (&array_type, get_identifier ("length")));
+ lookup_field (&array_type, get_identifier ("length")),
+ NULL_TREE);
IS_ARRAY_LENGTH_ACCESS (node) = 1;
return node;
}
ref = build (COMPONENT_REF, TREE_TYPE (data_field),
build_java_indirect_ref (array_type, array,
flag_check_references),
- data_field);
+ data_field, NULL_TREE);
- node = build (ARRAY_REF, type, ref, index);
+ node = build (ARRAY_REF, type, ref, index, NULL_TREE, NULL_TREE);
return node;
}
build (COMPONENT_REF, dtable_ptr_type,
build_java_indirect_ref (object_type_node, value,
flag_check_references),
- vtable_field)),
- class_field);
+ vtable_field, NULL_TREE)),
+ class_field, NULL_TREE);
}
/* This builds the tree representation of the `instanceof' operator.
in the same translation unit as output_class. If it is,
we can make a direct reference. */
{
- tree otable_index =
- build_int_2 (get_symbol_table_index
- (field_decl, &TYPE_OTABLE_METHODS (output_class)), 0);
- tree field_offset =
- build (ARRAY_REF, integer_type_node, TYPE_OTABLE_DECL (output_class),
- otable_index);
+ tree otable_index
+ = build_int_2 (get_symbol_table_index
+ (field_decl, &TYPE_OTABLE_METHODS (output_class)),
+ 0);
+ tree field_offset
+ = build (ARRAY_REF, integer_type_node,
+ TYPE_OTABLE_DECL (output_class), otable_index,
+ NULL_TREE, NULL_TREE);
tree address;
+
field_offset = fold (convert (sizetype, field_offset));
address
= fold (build (PLUS_EXPR,
self_value = build_java_indirect_ref (TREE_TYPE (TREE_TYPE (self_value)),
self_value, check);
return fold (build (COMPONENT_REF, TREE_TYPE (field_decl),
- self_value, field_decl));
+ self_value, field_decl, NULL_TREE));
}
}
}
else
{
- tree table_index =
- build_int_2 (get_symbol_table_index
- (method, &TYPE_ATABLE_METHODS (output_class)), 0);
- func =
- build (ARRAY_REF, method_ptr_type_node,
- TYPE_ATABLE_DECL (output_class), table_index);
+ tree table_index
+ = build_int_2 (get_symbol_table_index
+ (method, &TYPE_ATABLE_METHODS (output_class)), 0);
+ func = build (ARRAY_REF, method_ptr_type_node,
+ TYPE_ATABLE_DECL (output_class), table_index,
+ NULL_TREE, NULL_TREE);
}
func = convert (method_ptr_type_node, func);
}
if (methods_ident == NULL_TREE)
methods_ident = get_identifier ("methods");
ref = build (COMPONENT_REF, method_ptr_type_node, ref,
- lookup_field (&class_type_node, methods_ident));
+ lookup_field (&class_type_node, methods_ident), NULL_TREE);
for (meth = TYPE_METHODS (self_type);
; meth = TREE_CHAIN (meth))
{
ref, build_int_2 (method_index, 0)));
ref = build1 (INDIRECT_REF, method_type_node, ref);
func = build (COMPONENT_REF, nativecode_ptr_type_node,
- ref,
- lookup_field (&method_type_node, ncode_ident));
+ ref, lookup_field (&method_type_node, ncode_ident),
+ NULL_TREE);
}
return func;
}
dtable = build_java_indirect_ref (object_type_node, objectref,
flag_check_references);
dtable = build (COMPONENT_REF, dtable_ptr_type, dtable,
- lookup_field (&object_type_node, dtable_ident));
+ lookup_field (&object_type_node, dtable_ident), NULL_TREE);
return dtable;
}
(method, &TYPE_OTABLE_METHODS (output_class)), 0);
method_index = build (ARRAY_REF, integer_type_node,
TYPE_OTABLE_DECL (output_class),
- otable_index);
+ otable_index, NULL_TREE, NULL_TREE);
}
else
{
dtable = build_java_indirect_ref (dtable_type, dtable,
flag_check_references);
dtable = build (COMPONENT_REF, class_ptr_type, dtable,
- lookup_field (&dtable_type, class_ident));
+ lookup_field (&dtable_type, class_ident), NULL_TREE);
interface = DECL_CONTEXT (method);
if (! CLASS_INTERFACE (TYPE_NAME (interface)))
if (flag_indirect_dispatch)
{
- otable_index =
- build_int_2 (get_symbol_table_index
- (method, &TYPE_OTABLE_METHODS (output_class)), 0);
- idx =
- build (ARRAY_REF, integer_type_node, TYPE_OTABLE_DECL (output_class),
- otable_index);
+ otable_index
+ = build_int_2 (get_symbol_table_index
+ (method, &TYPE_OTABLE_METHODS (output_class)), 0);
+ idx = build (ARRAY_REF, integer_type_node,
+ TYPE_OTABLE_DECL (output_class), otable_index,
+ NULL_TREE, NULL_TREE);
}
else
- {
- idx = build_int_2 (get_interface_method_index (method, interface), 0);
- }
+ idx = build_int_2 (get_interface_method_index (method, interface), 0);
lookup_arg = tree_cons (NULL_TREE, dtable,
tree_cons (NULL_TREE, build_class_ref (interface),
expand_assignment (build (COMPONENT_REF, TREE_TYPE (data_fld),
build_java_indirect_ref (array_type,
array_decl, flag_check_references),
- data_fld), init, 0);
+ data_fld, NULL_TREE),
+ init, 0);
return tmp;
}
case BLOCK:
build (COMPONENT_REF, byte_type_node,
build1 (INDIRECT_REF, class_type_node, klass),
lookup_field (&class_type_node,
- get_identifier ("state"))),
+ get_identifier ("state")),
+ NULL_TREE),
build_int_2 (JV_STATE_DONE, 0));
expand_expr_stmt (build (MODIFY_EXPR, boolean_type_node,
/* Java(TM) language-specific gimplification routines.
-
Copyright (C) 2003, 2004 Free Software Foundation, Inc.
This file is part of GCC.
bounds checking. */
tree lhs = build (COMPONENT_REF, TREE_TYPE (data_field),
build_java_indirect_ref (array_type, tmp, 0),
- data_field);
+ data_field, NULL_TREE);
tree assignment = build (MODIFY_EXPR, element_type,
build (ARRAY_REF, element_type, lhs,
- build_int_2 (index++, 0)),
+ build_int_2 (index++, 0),
+ NULL_TREE, NULL_TREE),
TREE_VALUE (values));
body = build (COMPOUND_EXPR, element_type, body, assignment);
values = TREE_CHAIN (values);
make_qualified_name (tree left, tree right, int location)
{
#ifdef USE_COMPONENT_REF
- tree node = build (COMPONENT_REF, NULL_TREE, left, right);
+ tree node = build (COMPONENT_REF, NULL_TREE, left, right, NULL_TREE);
EXPR_WFL_LINECOL (node) = location;
return node;
#else
static tree
build_array_ref (int location, tree array, tree index)
{
- tree node = build (ARRAY_REF, NULL_TREE, array, index);
+ tree node = build (ARRAY_REF, NULL_TREE, array, index, NULL_TREE, NULL_TREE);
EXPR_WFL_LINECOL (node) = location;
return node;
}
sprintf (buf, "_OBJC_STATIC_INSTANCES_%d", num_class);
ident = get_identifier (buf);
- expr_decl = build_nt (ARRAY_REF, ident, NULL_TREE);
+ expr_decl = build_nt (ARRAY_REF, ident, NULL_TREE, NULL_TREE, NULL_TREE);
decl_spec = tree_cons (NULL_TREE, build_pointer_type (void_type_node),
build_tree_list (NULL_TREE,
ridpointers[(int) RID_STATIC]));
decls = tree_cons (NULL_TREE, build_int_2 (0, 0), decls);
ident = get_identifier ("_OBJC_STATIC_INSTANCES");
- expr_decl = build_nt (ARRAY_REF, ident, NULL_TREE);
+ expr_decl = build_nt (ARRAY_REF, ident, NULL_TREE, NULL_TREE, NULL_TREE);
decl_spec = tree_cons (NULL_TREE, build_pointer_type (void_type_node),
build_tree_list (NULL_TREE,
ridpointers[(int) RID_STATIC]));
sc_spec
= tree_cons (NULL_TREE, ridpointers[(int) RID_STATIC], NULL_TREE);
decl_specs = tree_cons (NULL_TREE, ridpointers[(int) RID_CHAR], sc_spec);
- expr_decl = build_nt (ARRAY_REF, DECL_NAME (decl), NULL_TREE);
+ expr_decl = build_nt (ARRAY_REF, DECL_NAME (decl), NULL_TREE,
+ NULL_TREE, NULL_TREE);
decl = start_decl (expr_decl, decl_specs, 1, NULL_TREE);
DECL_CONTEXT (decl) = NULL_TREE;
string_expr = my_build_string (IDENTIFIER_LENGTH (string) + 1,
sc_spec
= tree_cons (NULL_TREE, ridpointers[(int) RID_STATIC], NULL_TREE);
decl_specs = tree_cons (NULL_TREE, ridpointers[(int) RID_CHAR], sc_spec);
- expr_decl = build_nt (ARRAY_REF, DECL_NAME (decl), NULL_TREE);
+ expr_decl = build_nt (ARRAY_REF, DECL_NAME (decl), NULL_TREE,
+ NULL_TREE, NULL_TREE);
decl = start_decl (expr_decl, decl_specs, 1, NULL_TREE);
DECL_CONTEXT (decl) = NULL_TREE;
string_expr = my_build_string (IDENTIFIER_LENGTH (string) + 1,
sc_spec
= tree_cons (NULL_TREE, ridpointers[(int) RID_STATIC], NULL_TREE);
decl_specs = tree_cons (NULL_TREE, ridpointers[(int) RID_CHAR], sc_spec);
- expr_decl = build_nt (ARRAY_REF, DECL_NAME (decl), NULL_TREE);
+ expr_decl = build_nt (ARRAY_REF, DECL_NAME (decl), NULL_TREE,
+ NULL_TREE, NULL_TREE);
decl = start_decl (expr_decl, decl_specs, 1, NULL_TREE);
DECL_CONTEXT (decl) = NULL_TREE;
string_expr = my_build_string (IDENTIFIER_LENGTH (string) + 1,
decl_specs = build_tree_list (NULL_TREE, list_type);
field_decl = build_nt (ARRAY_REF, get_identifier ("method_list"),
- build_int_2 (size, 0));
+ build_int_2 (size, 0), NULL_TREE, NULL_TREE);
field_decl = grokfield (field_decl, decl_specs, NULL_TREE);
chainon (field_decl_chain, field_decl);
decl_specs = build_tree_list (NULL_TREE, list_type);
field_decl = build_nt (ARRAY_REF, get_identifier ("ivar_list"),
- build_int_2 (size, 0));
+ build_int_2 (size, 0), NULL_TREE, NULL_TREE);
field_decl = grokfield (field_decl, decl_specs, NULL_TREE);
chainon (field_decl_chain, field_decl);
decl_specs = build_tree_list (NULL_TREE, list_type);
field_decl = build_nt (ARRAY_REF, get_identifier ("method_list"),
- build_int_2 (size, 0));
+ build_int_2 (size, 0), NULL_TREE, NULL_TREE);
field_decl = grokfield (field_decl, decl_specs, NULL_TREE);
chainon (field_decl_chain, field_decl);
expr_decl = build_nt (ARRAY_REF,
synth_id_with_class_suffix ("_OBJC_PROTOCOL_REFS",
i_or_p),
- build_int_2 (size + 2, 0));
+ build_int_2 (size + 2, 0), NULL_TREE, NULL_TREE);
else if (TREE_CODE (i_or_p) == CLASS_INTERFACE_TYPE)
expr_decl = build_nt (ARRAY_REF,
synth_id_with_class_suffix ("_OBJC_CLASS_PROTOCOLS",
i_or_p),
- build_int_2 (size + 2, 0));
+ build_int_2 (size + 2, 0), NULL_TREE, NULL_TREE);
else if (TREE_CODE (i_or_p) == CATEGORY_INTERFACE_TYPE)
expr_decl
= build_nt (ARRAY_REF,
synth_id_with_class_suffix ("_OBJC_CATEGORY_PROTOCOLS",
i_or_p),
- build_int_2 (size + 2, 0));
+ build_int_2 (size + 2, 0), NULL_TREE, NULL_TREE);
else
abort ();
type = TREE_TYPE (var);
- /* In function-at-a-time mode, variable_size doesn't expand this,
- so do it now. */
- if (TREE_CODE (type) == ARRAY_TYPE && TYPE_DOMAIN (type))
- expand_expr (TYPE_MAX_VALUE (TYPE_DOMAIN (type)),
- const0_rtx, VOIDmode, 0);
-
/* Compute the variable's size, in bytes. */
size = expand_expr (t_size, NULL_RTX, VOIDmode, 0);
free_temp_slots ();
get_pending_sizes (void)
{
tree chain = pending_sizes;
- tree t;
-
- /* Put each SAVE_EXPR into the current function. */
- for (t = chain; t; t = TREE_CHAIN (t))
- SAVE_EXPR_CONTEXT (TREE_VALUE (t)) = current_function_decl;
pending_sizes = 0;
return chain;
switch (TREE_CODE (expr))
{
case ARRAY_REF:
+ case ARRAY_RANGE_REF:
{
- /* Find the first non-array ref, and return it's alias
- variable */
+ /* Find the first non-array ref, and return its alias variable. */
tree p;
- for (p = expr; TREE_CODE (p) == ARRAY_REF;
- p = TREE_OPERAND (p, 0));
+
+ for (p = expr;
+ TREE_CODE (p) == ARRAY_REF || TREE_CODE (p) == ARRAY_RANGE_REF;
+ p = TREE_OPERAND (p, 0))
+ ;
return get_alias_var (p);
}
break;
break;
case ADDR_EXPR:
- x = TREE_OPERAND (t, 0);
- while (TREE_CODE (x) == ARRAY_REF
- || TREE_CODE (x) == COMPONENT_REF
- || TREE_CODE (x) == REALPART_EXPR
- || TREE_CODE (x) == IMAGPART_EXPR)
- x = TREE_OPERAND (x, 0);
+ for (x = TREE_OPERAND (t, 0); handled_component_p (x);
+ x = TREE_OPERAND (x, 0))
+ ;
+
if (TREE_CODE (x) != VAR_DECL && TREE_CODE (x) != PARM_DECL)
return NULL;
if (!TREE_ADDRESSABLE (x))
|| TREE_CODE (t) == SSA_NAME)
return true;
- while ((TREE_CODE (t) == ARRAY_REF
+ while (((TREE_CODE (t) == ARRAY_REF || TREE_CODE (t) == ARRAY_RANGE_REF)
/* We check for constants explicitly since they are not considered
gimple invariants if they overflowed. */
&& (TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (t, 1))) == 'c'
tree
get_virtual_var (tree var)
{
- enum tree_code code;
-
STRIP_NOPS (var);
if (TREE_CODE (var) == SSA_NAME)
var = SSA_NAME_VAR (var);
- code = TREE_CODE (var);
-
- while (code == ARRAY_REF
- || code == COMPONENT_REF
- || code == REALPART_EXPR
- || code == IMAGPART_EXPR)
- {
+ if (TREE_CODE (var) == REALPART_EXPR || TREE_CODE (var) == IMAGPART_EXPR)
+ var = TREE_OPERAND (var, 0);
+ else
+ while (handled_component_p (var))
var = TREE_OPERAND (var, 0);
- code = TREE_CODE (var);
- }
-
+
#ifdef ENABLE_CHECKING
/* Treating GIMPLE registers as virtual variables makes no sense.
Also complain if we couldn't extract a _DECL out of the original
case TRUTH_ORIF_EXPR:
case INIT_EXPR:
case MODIFY_EXPR:
- case COMPONENT_REF:
case COMPOUND_EXPR:
- case ARRAY_REF:
case PREDECREMENT_EXPR:
case PREINCREMENT_EXPR:
case POSTDECREMENT_EXPR:
dump_child ("op 1", TREE_OPERAND (t, 1));
break;
+ case COMPONENT_REF:
+ dump_child ("op 0", TREE_OPERAND (t, 0));
+ dump_child ("op 1", TREE_OPERAND (t, 1));
+ dump_child ("op 2", TREE_OPERAND (t, 2));
+ break;
+
+ case ARRAY_REF:
+ case ARRAY_RANGE_REF:
+ dump_child ("op 0", TREE_OPERAND (t, 0));
+ dump_child ("op 1", TREE_OPERAND (t, 1));
+ dump_child ("op 2", TREE_OPERAND (t, 2));
+ dump_child ("op 3", TREE_OPERAND (t, 3));
+ break;
+
case COND_EXPR:
dump_child ("op 0", TREE_OPERAND (t, 0));
dump_child ("op 1", TREE_OPERAND (t, 1));
switch (code)
{
case ARRAY_REF:
+ case ARRAY_RANGE_REF:
case COMPONENT_REF:
case REALPART_EXPR:
case IMAGPART_EXPR:
min-lval: ID | '*' ID
bitfieldref :
BIT_FIELD_REF
- op0 -> compref | min-lval
+ op0 -> inner_compref
op1 -> CONST
- op2 -> CONST
+ op2 -> var
compref :
COMPONENT_REF
- op0 -> compref | min-lval
+ op0 -> inner_compref
| ARRAY_REF
- op0 -> compref | min-lval
+ op0 -> inner_compref
op1 -> val
+ op2 -> val
+ op3 -> val
+ | ARRAY_RANGE_REF
+ op0 -> inner_compref
+ op1 -> val
+ op2 -> val
+ op3 -> val
| REALPART_EXPR
+ op0 -> inner_compref
| IMAGPART_EXPR
+ op0 -> inner_compref
+
+ inner_compref : compref | min_lval
+ | VIEW_CONVERT_EXPR
+ op0 -> inner_compref
+ | NOP_EXPR
+ op0 -> inner_compref
+ | CONVERT_EXPR
+ op0 -> inner_compref
condition : val | val relop val
val : ID | CONST
{
return (is_gimple_id (t)
|| TREE_CODE (t) == ARRAY_REF
+ || TREE_CODE (t) == ARRAY_RANGE_REF
|| TREE_CODE (t) == COMPONENT_REF
|| TREE_CODE (t) == REALPART_EXPR
- || TREE_CODE (t) == IMAGPART_EXPR);
+ || TREE_CODE (t) == IMAGPART_EXPR
+ || TREE_CODE (t) == INDIRECT_REF);
}
/* Return nonzero if T is function invariant. Or rather a restricted
|| TREE_CODE (t) == INDIRECT_REF)
return t;
- switch (TREE_CODE (t))
- {
- case ARRAY_REF:
- case COMPONENT_REF:
- case REALPART_EXPR:
- case IMAGPART_EXPR:
- case BIT_FIELD_REF:
- t = TREE_OPERAND (t, 0);
- break;
-
- default:
- return NULL_TREE;
- }
+ if (TREE_CODE (t) == REALPART_EXPR || TREE_CODE (t) == IMAGPART_EXPR)
+ t = TREE_OPERAND (t, 0);
+ else if (handled_component_p (t))
+ t = get_base_address (TREE_OPERAND (t, 0));
+ else
+ return NULL_TREE;
}
while (t);
underlying nodes are also of the right form. */
/* Returns true iff T is a valid GIMPLE statement. */
-bool is_gimple_stmt (tree);
+extern bool is_gimple_stmt (tree);
/* Returns true iff TYPE is a valid type for a scalar register variable. */
-bool is_gimple_reg_type (tree);
+extern bool is_gimple_reg_type (tree);
/* Returns true iff T is a scalar register variable. */
-bool is_gimple_reg (tree);
+extern bool is_gimple_reg (tree);
/* Returns true iff T is any sort of variable. */
-bool is_gimple_variable (tree);
+extern bool is_gimple_variable (tree);
/* Returns true iff T is a variable or an INDIRECT_REF (of a variable). */
-bool is_gimple_min_lval (tree);
+extern bool is_gimple_min_lval (tree);
/* Returns true iff T is an lvalue other than an INDIRECT_REF. */
-bool is_gimple_addr_expr_arg (tree);
+extern bool is_gimple_addr_expr_arg (tree);
/* Returns true iff T is any valid GIMPLE lvalue. */
-bool is_gimple_lvalue (tree);
+extern bool is_gimple_lvalue (tree);
/* Returns true iff T is a GIMPLE restricted function invariant. */
-bool is_gimple_min_invariant (tree);
+extern bool is_gimple_min_invariant (tree);
/* Returns true iff T is a GIMPLE rvalue. */
-bool is_gimple_val (tree);
+extern bool is_gimple_val (tree);
/* Returns true iff T is a valid rhs for a MODIFY_EXPR. */
-bool is_gimple_rhs (tree);
+extern bool is_gimple_rhs (tree);
/* Returns true iff T is a valid if-statement condition. */
-bool is_gimple_condexpr (tree);
+extern bool is_gimple_condexpr (tree);
/* Returns true iff T is a type conversion. */
-bool is_gimple_cast (tree);
+extern bool is_gimple_cast (tree);
/* Returns true iff T is a valid CONSTRUCTOR element (either an rvalue or
another CONSTRUCTOR). */
-bool is_gimple_constructor_elt (tree);
+extern bool is_gimple_constructor_elt (tree);
/* Returns true iff T is a variable that does not need to live in memory. */
-bool is_gimple_non_addressable (tree t);
+extern bool is_gimple_non_addressable (tree t);
/* If T makes a function call, returns the CALL_EXPR operand. */
-tree get_call_expr_in (tree t);
+extern tree get_call_expr_in (tree t);
-void recalculate_side_effects (tree);
+extern void recalculate_side_effects (tree);
-void append_to_compound_expr (tree, tree *);
+extern void append_to_compound_expr (tree, tree *);
/* FIXME we should deduce this from the predicate. */
typedef enum fallback_t {
GS_ALL_DONE = 1 /* The expression is fully gimplified. */
};
-enum gimplify_status gimplify_expr (tree *, tree *, tree *,
- bool (*) (tree), fallback_t);
-void gimplify_stmt (tree *);
-void gimplify_to_stmt_list (tree *);
-void gimplify_body (tree *, tree);
-void push_gimplify_context (void);
-void pop_gimplify_context (tree);
-void gimplify_and_add (tree, tree *);
+extern enum gimplify_status gimplify_expr (tree *, tree *, tree *,
+ bool (*) (tree), fallback_t);
+extern tree gimplify_type_sizes (tree);
+extern void gimplify_one_sizepos (tree *, tree *);
+extern void gimplify_stmt (tree *);
+extern void gimplify_to_stmt_list (tree *);
+extern void gimplify_body (tree *, tree);
+extern void push_gimplify_context (void);
+extern void pop_gimplify_context (tree);
+extern void gimplify_and_add (tree, tree *);
/* Miscellaneous helpers. */
-tree get_base_address (tree t);
-void gimple_add_tmp_var (tree);
-tree gimple_current_bind_expr (void);
-void gimple_push_bind_expr (tree);
-void gimple_pop_bind_expr (void);
-void unshare_all_trees (tree);
-tree voidify_wrapper_expr (tree, tree);
-tree gimple_build_eh_filter (tree, tree, tree);
-tree build_and_jump (tree *);
-tree alloc_stmt_list (void);
-void free_stmt_list (tree);
-tree force_labels_r (tree *, int *, void *);
-enum gimplify_status gimplify_va_arg_expr (tree *, tree *, tree *);
+extern tree get_base_address (tree t);
+extern void gimple_add_tmp_var (tree);
+extern tree gimple_current_bind_expr (void);
+extern void gimple_push_bind_expr (tree);
+extern void gimple_pop_bind_expr (void);
+extern void unshare_all_trees (tree);
+extern tree voidify_wrapper_expr (tree, tree);
+extern tree gimple_build_eh_filter (tree, tree, tree);
+extern tree build_and_jump (tree *);
+extern tree alloc_stmt_list (void);
+extern void free_stmt_list (tree);
+extern tree force_labels_r (tree *, int *, void *);
+extern enum gimplify_status gimplify_va_arg_expr (tree *, tree *, tree *);
/* In tree-nested.c. */
extern void lower_nested_functions (tree);
}
#endif
}
- else if (TREE_CODE_CLASS (code) == 'd')
+
+ /* Look inside the sizes of decls, but we don't ever use the values for
+ FIELD_DECL and RESULT_DECL, so ignore them. */
+ else if (TREE_CODE_CLASS (code) == 'd'
+ && code != FIELD_DECL && code != RESULT_DECL)
{
+ WALK_SUBTREE (DECL_SIZE (*tp));
+ WALK_SUBTREE (DECL_SIZE_UNIT (*tp));
WALK_SUBTREE_TAIL (TREE_TYPE (*tp));
}
else
case REAL_CST:
case VECTOR_CST:
case STRING_CST:
- case REAL_TYPE:
- case COMPLEX_TYPE:
case VECTOR_TYPE:
case VOID_TYPE:
- case BOOLEAN_TYPE:
- case UNION_TYPE:
- case ENUMERAL_TYPE:
case BLOCK:
- case RECORD_TYPE:
case PLACEHOLDER_EXPR:
case SSA_NAME:
+ case FIELD_DECL:
+ case RESULT_DECL:
/* None of thse have subtrees other than those already walked
above. */
break;
case POINTER_TYPE:
case REFERENCE_TYPE:
+ case COMPLEX_TYPE:
WALK_SUBTREE_TAIL (TREE_TYPE (*tp));
break;
case METHOD_TYPE:
WALK_SUBTREE (TYPE_METHOD_BASETYPE (*tp));
+
/* Fall through. */
case FUNCTION_TYPE:
}
break;
+ case RECORD_TYPE:
+ case UNION_TYPE:
+ case QUAL_UNION_TYPE:
+ {
+ tree field;
+
+ for (field = TYPE_FIELDS (*tp); field; field = TREE_CHAIN (field))
+ {
+ /* We would like to look at the type of the field, but we
+ can easily get infinite recursion. So assume it's
+ pointed to elsewhere in the tree. Also, ignore things that
+ aren't fields. */
+ if (TREE_CODE (field) != FIELD_DECL)
+ continue;
+
+ WALK_SUBTREE (DECL_FIELD_OFFSET (field));
+ WALK_SUBTREE (DECL_SIZE (field));
+ WALK_SUBTREE (DECL_SIZE_UNIT (field));
+ if (code == QUAL_UNION_TYPE)
+ WALK_SUBTREE (DECL_QUALIFIER (field));
+ }
+ }
+ break;
+
case ARRAY_TYPE:
- WALK_SUBTREE (TREE_TYPE (*tp));
+ /* Don't follow this nodes's type if a pointer for fear that we'll
+ have infinite recursion. Those types are uninteresting anyway. */
+ if (!POINTER_TYPE_P (TREE_TYPE (*tp))
+ && TREE_CODE (TREE_TYPE (*tp)) != OFFSET_TYPE)
+ WALK_SUBTREE (TREE_TYPE (*tp));
WALK_SUBTREE_TAIL (TYPE_DOMAIN (*tp));
+ case BOOLEAN_TYPE:
+ case ENUMERAL_TYPE:
case INTEGER_TYPE:
case CHAR_TYPE:
+ case REAL_TYPE:
WALK_SUBTREE (TYPE_MIN_VALUE (*tp));
WALK_SUBTREE_TAIL (TYPE_MAX_VALUE (*tp));
/* Walk the DECL_INITIAL and DECL_SIZE. We don't want to walk
into declarations that are just mentioned, rather than
declared; they don't really belong to this part of the tree.
- And, we can see cycles: the initializer for a declaration can
- refer to the declaration itself. */
+ And, we can see cycles: the initializer for a declaration
+ can refer to the declaration itself. */
WALK_SUBTREE (DECL_INITIAL (decl));
WALK_SUBTREE (DECL_SIZE (decl));
WALK_SUBTREE (DECL_SIZE_UNIT (decl));
break;
default:
- abort ();
+ /* ??? This could be a language-defined node. We really should make
+ a hook for it, but right now just ignore it. */
+ break;
}
}
(flag_mudflap_threads ? mf_cache_mask_decl : mf_cache_mask_decl_l));
t = build (ARRAY_REF,
TREE_TYPE (TREE_TYPE (mf_cache_array_decl)),
- mf_cache_array_decl, t);
+ mf_cache_array_decl, t, NULL_TREE, NULL_TREE);
t = build1 (ADDR_EXPR, mf_cache_structptr_type, t);
t = build (MODIFY_EXPR, void_type_node, mf_elem, t);
SET_EXPR_LOCUS (t, locus);
/* Construct t <-- '__mf_elem->low > __mf_base'. */
t = build (COMPONENT_REF, mf_uintptr_type,
build1 (INDIRECT_REF, mf_cache_struct_type, mf_elem),
- TYPE_FIELDS (mf_cache_struct_type));
+ TYPE_FIELDS (mf_cache_struct_type), NULL_TREE);
t = build (GT_EXPR, boolean_type_node, t, mf_base);
/* Construct '__mf_elem->high < __mf_base + sizeof(T) - 1'.
u = build (COMPONENT_REF, mf_uintptr_type,
build1 (INDIRECT_REF, mf_cache_struct_type, mf_elem),
- TREE_CHAIN (TYPE_FIELDS (mf_cache_struct_type)));
+ TREE_CHAIN (TYPE_FIELDS (mf_cache_struct_type)), NULL_TREE);
v = convert (mf_uintptr_type,
size_binop (MINUS_EXPR, size, size_one_node));
things the hard way with PLUS. */
if (DECL_BIT_FIELD_TYPE (field))
{
- size = bitsize_int (BITS_PER_UNIT);
- size = size_binop (CEIL_DIV_EXPR, DECL_SIZE (field), size);
- size = convert (sizetype, size);
+ if (TREE_CODE (DECL_SIZE_UNIT (field)) == INTEGER_CST)
+ size = DECL_SIZE_UNIT (field);
addr = TREE_OPERAND (TREE_OPERAND (t, 0), 0);
- addr = convert (ptr_type_node, addr);
+ addr = fold_convert (ptr_type_node, addr);
addr = fold (build (PLUS_EXPR, ptr_type_node,
- addr, byte_position (field)));
+ addr, fold_convert (ptr_type_node,
+ byte_position (field))));
}
else
{
build_addr (tree exp)
{
tree base = exp;
- while (TREE_CODE (base) == COMPONENT_REF || TREE_CODE (base) == ARRAY_REF)
+
+ if (TREE_CODE (base) == REALPART_EXPR || TREE_CODE (base) == IMAGPART_EXPR)
base = TREE_OPERAND (base, 0);
+ else
+ while (handled_component_p (base))
+ base = TREE_OPERAND (base, 0);
+
if (DECL_P (base))
TREE_ADDRESSABLE (base) = 1;
break;
case CATCH_EXPR:
walk_stmts (wi, &CATCH_BODY (t));
+ break;
case EH_FILTER_EXPR:
walk_stmts (wi, &EH_FILTER_FAILURE (t));
break;
tree field = get_chain_field (i);
x = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (x)), x);
- x = build (COMPONENT_REF, TREE_TYPE (field), x, field);
+ x = build (COMPONENT_REF, TREE_TYPE (field), x, field, NULL_TREE);
x = init_tmp_var (info, x, tsi);
}
}
tree field = get_chain_field (i);
x = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (x)), x);
- x = build (COMPONENT_REF, TREE_TYPE (field), x, field);
+ x = build (COMPONENT_REF, TREE_TYPE (field), x, field, NULL_TREE);
x = init_tmp_var (info, x, tsi);
}
x = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (x)), x);
}
- x = build (COMPONENT_REF, TREE_TYPE (field), x, field);
+ x = build (COMPONENT_REF, TREE_TYPE (field), x, field, NULL_TREE);
return x;
}
break;
case ARRAY_REF:
+ case ARRAY_RANGE_REF:
wi->val_only = false;
walk_tree (&TREE_OPERAND (t, 0), convert_nonlocal_reference, wi, NULL);
wi->val_only = true;
walk_tree (&TREE_OPERAND (t, 1), convert_nonlocal_reference, wi, NULL);
+ walk_tree (&TREE_OPERAND (t, 2), convert_nonlocal_reference, wi, NULL);
+ walk_tree (&TREE_OPERAND (t, 3), convert_nonlocal_reference, wi, NULL);
break;
case BIT_FIELD_REF:
break;
case ARRAY_REF:
+ case ARRAY_RANGE_REF:
wi->val_only = false;
walk_tree (&TREE_OPERAND (t, 0), convert_local_reference, wi, NULL);
wi->val_only = true;
walk_tree (&TREE_OPERAND (t, 1), convert_local_reference, wi, NULL);
+ walk_tree (&TREE_OPERAND (t, 2), convert_local_reference, wi, NULL);
+ walk_tree (&TREE_OPERAND (t, 3), convert_local_reference, wi, NULL);
break;
case BIT_FIELD_REF:
x = p;
y = build (COMPONENT_REF, TREE_TYPE (field),
- root->frame_decl, field);
+ root->frame_decl, field, NULL_TREE);
x = build (MODIFY_EXPR, TREE_TYPE (field), y, x);
append_to_statement_list (x, &stmt_list);
}
from chain_decl. */
if (root->chain_field)
{
- tree x;
- x = build (COMPONENT_REF, TREE_TYPE (root->chain_field),
- root->frame_decl, root->chain_field);
+ tree x = build (COMPONENT_REF, TREE_TYPE (root->chain_field),
+ root->frame_decl, root->chain_field, NULL_TREE);
x = build (MODIFY_EXPR, TREE_TYPE (x), x, get_chain_decl (root));
append_to_statement_list (x, &stmt_list);
}
arg = tree_cons (NULL, x, arg);
x = build (COMPONENT_REF, TREE_TYPE (field),
- root->frame_decl, field);
+ root->frame_decl, field, NULL_TREE);
x = build_addr (x);
arg = tree_cons (NULL, x, arg);
if (TYPE_P (t) || DECL_P (t))
*walk_subtrees = 0;
- else if (TREE_CODE (t) == ARRAY_REF)
+ else if (TREE_CODE (t) == ARRAY_REF || TREE_CODE (t) == ARRAY_RANGE_REF)
{
- while ((TREE_CODE (t) == ARRAY_REF
+ while (((TREE_CODE (t) == ARRAY_REF || TREE_CODE (t) == ARRAY_RANGE_REF)
&& is_gimple_min_invariant (TREE_OPERAND (t, 1)))
|| (TREE_CODE (t) == COMPONENT_REF
|| TREE_CODE (t) == BIT_FIELD_REF
|| TREE_CODE (t) == REALPART_EXPR
- || TREE_CODE (t) == IMAGPART_EXPR))
+ || TREE_CODE (t) == IMAGPART_EXPR
+ || TREE_CODE (t) == VIEW_CONVERT_EXPR
+ || TREE_CODE (t) == NOP_EXPR
+ || TREE_CODE (t) == CONVERT_EXPR))
t = TREE_OPERAND (t, 0);
- if (TREE_CODE (t) == ARRAY_REF)
+ if (TREE_CODE (t) == ARRAY_REF || TREE_CODE (t) == ARRAY_RANGE_REF)
{
t = get_base_address (t);
if (t && DECL_P (t))
case RECORD_TYPE:
case UNION_TYPE:
+ case QUAL_UNION_TYPE:
/* Print the name of the structure. */
if (TREE_CODE (node) == RECORD_TYPE)
pp_string (buffer, "struct ");
print_struct_decl (buffer, node, spc, flags);
break;
- case QUAL_UNION_TYPE:
- NIY;
- break;
-
-
case LANG_TYPE:
NIY;
break;
pp_character (buffer, ')');
pp_string (buffer, str);
dump_generic_node (buffer, TREE_OPERAND (node, 1), spc, flags, false);
+ if (TREE_OPERAND (node, 2)
+ && TREE_CODE (TREE_OPERAND (node, 2)) != INTEGER_CST)
+ {
+ pp_string (buffer, "{off: ");
+ dump_generic_node (buffer, TREE_OPERAND (node, 2),
+ spc, flags, false);
+ pp_character (buffer, '}');
+ }
break;
case BIT_FIELD_REF:
break;
case ARRAY_REF:
+ case ARRAY_RANGE_REF:
op0 = TREE_OPERAND (node, 0);
if (op_prio (op0) < op_prio (node))
pp_character (buffer, '(');
pp_character (buffer, ')');
pp_character (buffer, '[');
dump_generic_node (buffer, TREE_OPERAND (node, 1), spc, flags, false);
+ if (TREE_CODE (node) == ARRAY_RANGE_REF)
+ pp_string (buffer, " ...");
pp_character (buffer, ']');
- break;
- case ARRAY_RANGE_REF:
- NIY;
+ if ((TREE_OPERAND (node, 2)
+ && TREE_CODE (TREE_OPERAND (node, 2)) != INTEGER_CST)
+ || (TREE_OPERAND (node, 3)
+ && TREE_CODE (TREE_OPERAND (node, 3)) != INTEGER_CST))
+ {
+ pp_string (buffer, "{lb: ");
+ dump_generic_node (buffer, TREE_OPERAND (node, 2),
+ spc, flags, false);
+ pp_string (buffer, " sz: ");
+ dump_generic_node (buffer, TREE_OPERAND (node, 3),
+ spc, flags, false);
+ pp_character (buffer, '}');
+ }
break;
case CONSTRUCTOR:
INDENT (spc);
if (TREE_CODE (node) == RECORD_TYPE)
pp_string (buffer, "struct ");
- else if (TREE_CODE (node) == UNION_TYPE)
+ else if ((TREE_CODE (node) == UNION_TYPE
+ || TREE_CODE (node) == QUAL_UNION_TYPE))
pp_string (buffer, "union ");
- else
- NIY;
+
dump_generic_node (buffer, TYPE_NAME (node), spc, 0, false);
}
Maybe this could be solved by looking at the scope in which the
structure was declared. */
if (TREE_TYPE (tmp) != node
- || (TREE_CODE (TREE_TYPE (tmp)) == POINTER_TYPE &&
- TREE_TYPE (TREE_TYPE (tmp)) != node))
+ || (TREE_CODE (TREE_TYPE (tmp)) == POINTER_TYPE
+ && TREE_TYPE (TREE_TYPE (tmp)) != node))
{
print_declaration (buffer, tmp, spc+2, flags);
pp_newline (buffer);
case CALL_EXPR:
case ARRAY_REF:
+ case ARRAY_RANGE_REF:
case COMPONENT_REF:
return 15;
break;
}
- return build (COMPONENT_REF, TREE_TYPE (field), base, field);
+ return build (COMPONENT_REF, TREE_TYPE (field), base, field, NULL_TREE);
}
/* Similarly for REALPART_EXPR and IMAGPART_EXPR for complex types. */
/* Scalarize the return value, if any. */
if (TREE_CODE (stmt) == MODIFY_EXPR)
{
- tree var = TREE_OPERAND (stmt, 0);
+ tree var = get_base_address (TREE_OPERAND (stmt, 0));
/* If the LHS of the assignment is a scalarizable structure, insert
copies into the scalar replacements after the call. */
tree
widen_bitfield (tree val, tree field, tree var)
{
- unsigned var_size, field_size;
+ unsigned HOST_WIDE_INT var_size, field_size;
tree wide_val;
unsigned HOST_WIDE_INT mask;
- unsigned i;
+ unsigned int i;
- var_size = TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE ((var))));
- field_size = TREE_INT_CST_LOW (DECL_SIZE (field));
+ /* We can only do this if the size of the type and field and VAL are
+ all constants representable in HOST_WIDE_INT. */
+ if (!host_integerp (TYPE_SIZE (TREE_TYPE (var)), 1)
+ || !host_integerp (DECL_SIZE (field), 1)
+ || !host_integerp (val, 0))
+ return NULL_TREE;
+
+ var_size = tree_low_cst (TYPE_SIZE (TREE_TYPE (var)), 1);
+ field_size = tree_low_cst (DECL_SIZE (field), 1);
/* Give up if either the bitfield or the variable are too wide. */
if (field_size > HOST_BITS_PER_WIDE_INT || var_size > HOST_BITS_PER_WIDE_INT)
- return NULL;
+ return NULL_TREE;
#if defined ENABLE_CHECKING
if (var_size < field_size)
abort ();
#endif
- /* If VAL is not an integer constant, then give up. */
- if (TREE_CODE (val) != INTEGER_CST)
- return NULL;
-
- /* If the sign bit of the value is not set, or the field's type is
- unsigned, then just mask off the high order bits of the value. */
- if ((TREE_INT_CST_LOW (val) & (1 << (field_size - 1))) == 0
- || DECL_UNSIGNED (field))
+ /* If the sign bit of the value is not set or the field's type is unsigned,
+ just mask off the high order bits of the value. */
+ if (DECL_UNSIGNED (field)
+ || !(tree_low_cst (val, 0) & (((HOST_WIDE_INT)1) << (field_size - 1))))
{
/* Zero extension. Build a mask with the lower 'field_size' bits
set and a BIT_AND_EXPR node to clear the high order bits of
the value. */
for (i = 0, mask = 0; i < field_size; i++)
- mask |= 1 << i;
+ mask |= ((HOST_WIDE_INT) 1) << i;
wide_val = build (BIT_AND_EXPR, TREE_TYPE (var), val,
- build_int_2 (mask, 0));
+ fold_convert (TREE_TYPE (var), build_int_2 (mask, 0)));
}
else
{
bits set and a BIT_IOR_EXPR to set the high order bits of the
value. */
for (i = 0, mask = 0; i < (var_size - field_size); i++)
- mask |= 1 << (var_size - i - 1);
+ mask |= ((HOST_WIDE_INT) 1) << (var_size - i - 1);
wide_val = build (BIT_IOR_EXPR, TREE_TYPE (var), val,
- build_int_2 (mask, 0));
+ fold_convert (TREE_TYPE (var), build_int_2 (mask, 0)));
}
return fold (wide_val);
static tree
maybe_fold_offset_to_array_ref (tree base, tree offset, tree orig_type)
{
- unsigned HOST_WIDE_INT lquo, lrem;
- HOST_WIDE_INT hquo, hrem;
- tree elt_size, min_idx, idx;
- tree array_type, elt_type;
+ tree min_idx, idx, elt_offset = integer_zero_node;
+ tree array_type, elt_type, elt_size;
+
+ /* 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 (!lang_hooks.types_compatible_p (orig_type, elt_type))
return NULL_TREE;
- /* Whee. Ignore indexing of variable sized types. */
+ /* 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 (TREE_CODE (elt_size) != INTEGER_CST)
- return NULL_TREE;
+ if (integer_zerop (offset))
+ {
+ if (TREE_CODE (elt_size) != INTEGER_CST)
+ elt_size = size_int (TYPE_ALIGN (elt_type));
- /* If the division isn't exact, then don't do anything. Equally
- invalid as the above indexing of non-array variables. */
- if (div_and_round_double (TRUNC_DIV_EXPR, 1,
- TREE_INT_CST_LOW (offset),
- TREE_INT_CST_HIGH (offset),
- TREE_INT_CST_LOW (elt_size),
- TREE_INT_CST_HIGH (elt_size),
- &lquo, &hquo, &lrem, &hrem)
- || lrem || hrem)
- return NULL_TREE;
- idx = build_int_2_wide (lquo, hquo);
+ idx = integer_zero_node;
+ }
+ else
+ {
+ unsigned HOST_WIDE_INT lquo, lrem;
+ HOST_WIDE_INT hquo, hrem;
+
+ if (TREE_CODE (elt_size) != INTEGER_CST
+ || div_and_round_double (TRUNC_DIV_EXPR, 1,
+ TREE_INT_CST_LOW (offset),
+ TREE_INT_CST_HIGH (offset),
+ TREE_INT_CST_LOW (elt_size),
+ TREE_INT_CST_HIGH (elt_size),
+ &lquo, &hquo, &lrem, &hrem)
+ || lrem || hrem)
+ return NULL_TREE;
- /* Re-bias the index by the min index of the array type. */
- min_idx = TYPE_DOMAIN (TREE_TYPE (base));
- if (min_idx)
+ idx = build_int_2_wide (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 = integer_zero_node;
+ if (TYPE_DOMAIN (array_type))
{
- min_idx = TYPE_MIN_VALUE (min_idx);
- if (min_idx)
- {
- idx = convert (TREE_TYPE (min_idx), idx);
- if (!integer_zerop (min_idx))
- idx = int_const_binop (PLUS_EXPR, idx, min_idx, 1);
- }
+ if (TYPE_MIN_VALUE (TYPE_DOMAIN (array_type)))
+ min_idx = TYPE_MIN_VALUE (TYPE_DOMAIN (array_type));
+ else
+ min_idx = fold_convert (TYPE_DOMAIN (array_type), min_idx);
+
+ if (TREE_CODE (min_idx) != INTEGER_CST)
+ return NULL_TREE;
+
+ idx = fold_convert (TYPE_DOMAIN (array_type), idx);
+ elt_offset = fold_convert (TYPE_DOMAIN (array_type), elt_offset);
}
- return build (ARRAY_REF, orig_type, base, idx);
+ 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);
+
+ return build (ARRAY_REF, orig_type, base, idx, min_idx,
+ size_int (tree_low_cst (elt_size, 1)
+ / (TYPE_ALIGN (elt_type) / BITS_PER_UNIT)));
}
/* A subroutine of fold_stmt_r. Attempts to fold *(S+O) to S.X.
{
if (base_is_ptr)
base = build1 (INDIRECT_REF, record_type, base);
- t = build (COMPONENT_REF, field_type, base, f);
+ t = build (COMPONENT_REF, field_type, base, f, NULL_TREE);
return t;
}
nonzero offset into them. Recurse and hope for a valid match. */
if (base_is_ptr)
base = build1 (INDIRECT_REF, record_type, base);
- base = build (COMPONENT_REF, field_type, base, f);
+ base = build (COMPONENT_REF, field_type, base, f, NULL_TREE);
t = maybe_fold_offset_to_array_ref (base, offset, orig_type);
if (t)
if (t)
return t;
- /* Fold *&B to B. */
- if (integer_zerop (offset))
+ /* Fold *&B to B. We can only do this if EXPR is the same type
+ as BASE. We can't do this if EXPR is the element type of an array
+ and BASE is the array. */
+ if (integer_zerop (offset)
+ && lang_hooks.types_compatible_p (TREE_TYPE (base),
+ TREE_TYPE (expr)))
return base;
}
else
min_idx = TYPE_MIN_VALUE (min_idx);
if (min_idx)
{
+ if (TREE_CODE (min_idx) != INTEGER_CST)
+ break;
+
array_idx = convert (TREE_TYPE (min_idx), array_idx);
if (!integer_zerop (min_idx))
array_idx = int_const_binop (MINUS_EXPR, array_idx,
code = TREE_CODE (expr);
class = TREE_CODE_CLASS (code);
- /* Expressions that make no memory references. */
- if (class == 'c'
- || class == 't'
- || code == BLOCK
- || code == FUNCTION_DECL
- || code == EXC_PTR_EXPR
- || code == FILTER_EXPR
- || code == LABEL_DECL)
- return;
-
/* We could have the address of a component, array member, etc which
has interesting variable references. */
if (code == ADDR_EXPR)
{
- enum tree_code subcode = TREE_CODE (TREE_OPERAND (expr, 0));
-
/* Taking the address of a variable does not represent a
reference to it, but the fact that STMT takes its address will be
of interest to some passes (e.g. alias resolution). */
add_stmt_operand (expr_p, stmt, 0, NULL);
- /* If the address is invariant, there may be no interesting variable
- references inside. */
- if (is_gimple_min_invariant (expr))
+ /* If the address is constant (invariant is not sufficient), there will
+ be no interesting variable references inside. */
+ if (TREE_CONSTANT (expr))
return;
/* There should be no VUSEs created, since the referenced objects are
flags |= opf_no_vops;
/* Avoid recursion. */
- code = subcode;
- class = TREE_CODE_CLASS (code);
expr_p = &TREE_OPERAND (expr, 0);
expr = *expr_p;
+ code = TREE_CODE (expr);
+ class = TREE_CODE_CLASS (code);
}
+ /* Expressions that make no memory references. */
+ if (class == 'c'
+ || class == 't'
+ || code == BLOCK
+ || code == FUNCTION_DECL
+ || code == EXC_PTR_EXPR
+ || code == FILTER_EXPR
+ || code == LABEL_DECL)
+ return;
+
/* If we found a variable, add it to DEFS or USES depending on the
operand flags. */
if (SSA_VAR_P (expr))
/* Treat array references as references to the virtual variable
representing the array. The virtual variable for an ARRAY_REF
is the VAR_DECL for the array. */
- if (code == ARRAY_REF)
+ if (code == ARRAY_REF || code == ARRAY_RANGE_REF)
{
/* Add the virtual variable for the ARRAY_REF to VDEFS or VUSES
according to the value of IS_DEF. Recurse if the LHS of the
get_expr_operands (stmt, &TREE_OPERAND (expr, 0), flags, prev_vops);
get_expr_operands (stmt, &TREE_OPERAND (expr, 1), opf_none, prev_vops);
+ get_expr_operands (stmt, &TREE_OPERAND (expr, 2), opf_none, prev_vops);
+ get_expr_operands (stmt, &TREE_OPERAND (expr, 3), opf_none, prev_vops);
return;
}
else
get_expr_operands (stmt, &TREE_OPERAND (expr, 0), flags, prev_vops);
+ if (code == COMPONENT_REF)
+ get_expr_operands (stmt, &TREE_OPERAND (expr, 2), opf_none, prev_vops);
return;
}
if (SSA_VAR_P (t))
break;
- switch (TREE_CODE (t))
- {
- case ARRAY_REF:
- case COMPONENT_REF:
- case REALPART_EXPR:
- case IMAGPART_EXPR:
- case BIT_FIELD_REF:
- case INDIRECT_REF:
+ if (TREE_CODE (t) == REALPART_EXPR || TREE_CODE (t) == IMAGPART_EXPR)
+ t = TREE_OPERAND (t, 0);
+ else
+ while (handled_component_p (t))
t = TREE_OPERAND (t, 0);
- break;
-
- default:
- return;
- }
}
if (TREE_CODE (t) == SSA_NAME)
if (op0 == TREE_OPERAND (exp, 0))
return exp;
- new = fold (build2 (code, TREE_TYPE (exp), op0, TREE_OPERAND (exp, 1)));
+ new = fold (build (code, TREE_TYPE (exp), op0, TREE_OPERAND (exp, 1),
+ NULL_TREE));
}
else
switch (TREE_CODE_CLASS (code))
case COMPONENT_REF:
result = build_nt (COMPONENT_REF,
stabilize_reference (TREE_OPERAND (ref, 0)),
- TREE_OPERAND (ref, 1));
+ TREE_OPERAND (ref, 1), NULL_TREE);
break;
case BIT_FIELD_REF:
case ARRAY_REF:
result = build_nt (ARRAY_REF,
stabilize_reference (TREE_OPERAND (ref, 0)),
- stabilize_reference_1 (TREE_OPERAND (ref, 1)));
+ stabilize_reference_1 (TREE_OPERAND (ref, 1)),
+ TREE_OPERAND (ref, 2), TREE_OPERAND (ref, 3));
break;
case ARRAY_RANGE_REF:
result = build_nt (ARRAY_RANGE_REF,
stabilize_reference (TREE_OPERAND (ref, 0)),
- stabilize_reference_1 (TREE_OPERAND (ref, 1)));
+ stabilize_reference_1 (TREE_OPERAND (ref, 1)),
+ TREE_OPERAND (ref, 2), TREE_OPERAND (ref, 3));
break;
case COMPOUND_EXPR:
\f
/* Low-level constructors for expressions. */
-/* A helper function for build1 and constant folders.
- Set TREE_CONSTANT and TREE_INVARIANT for an ADDR_EXPR. */
+/* A helper function for build1 and constant folders. Set TREE_CONSTANT,
+ TREE_INVARIANT, and TREE_SIDE_EFFECTS for an ADDR_EXPR. */
void
recompute_tree_invarant_for_addr_expr (tree t)
{
- tree node = TREE_OPERAND (t, 0);
- bool tc = false, ti = false;
+ tree node;
+ bool tc = true, ti = true, se = false;
- /* Addresses of constants and static variables are constant;
- all other decl addresses are invariant. */
- if (staticp (node))
- tc = ti = true;
- else
+ /* We started out assuming this address is both invariant and constant, but
+ does not have side effects. Now go down any handled components and see if
+ any of them involve offsets that are either non-constant or non-invariant.
+ Also check for side-effects.
+
+ ??? Note that this code makes no attempt to deal with the case where
+ taking the address of something causes a copy due to misalignment. */
+
+#define UPDATE_TITCSE(NODE) \
+do { tree _node = (NODE); \
+ if (_node && !TREE_INVARIANT (_node)) ti = false; \
+ if (_node && !TREE_CONSTANT (_node)) tc = false; \
+ if (_node && TREE_SIDE_EFFECTS (_node)) se = true; } while (0)
+
+ for (node = TREE_OPERAND (t, 0); handled_component_p (node);
+ node = TREE_OPERAND (node, 0))
{
- /* Step past constant offsets. */
- while (1)
+ /* If the first operand doesn't have an ARRAY_TYPE, this is a bogus
+ array reference (probably made temporarily by the G++ front end),
+ so ignore all the operands. */
+ if ((TREE_CODE (node) == ARRAY_REF
+ || TREE_CODE (node) == ARRAY_RANGE_REF)
+ && TREE_CODE (TREE_TYPE (TREE_OPERAND (node, 0))) == ARRAY_TYPE)
{
- if (TREE_CODE (node) == COMPONENT_REF
- && TREE_CODE (TREE_OPERAND (node, 1)) == FIELD_DECL
- && ! DECL_BIT_FIELD (TREE_OPERAND (node, 1)))
- ;
- else if (TREE_CODE (node) == ARRAY_REF
- && TREE_CONSTANT (TREE_OPERAND (node, 1)))
- ;
- else
- break;
- node = TREE_OPERAND (node, 0);
+ UPDATE_TITCSE (TREE_OPERAND (node, 1));
+ UPDATE_TITCSE (array_ref_low_bound (node));
+ UPDATE_TITCSE (array_ref_element_size (node));
}
- if (DECL_P (node))
- ti = true;
+ /* Likewise, just because this is a COMPONENT_REF doesn't mean we have a
+ FIELD_DECL, apparently. The G++ front end can put something else
+ there, at least temporarily. */
+ else if (TREE_CODE (node) == COMPONENT_REF
+ && TREE_CODE (TREE_OPERAND (node, 1)) == FIELD_DECL)
+ UPDATE_TITCSE (component_ref_field_offset (node));
+ else if (TREE_CODE (node) == BIT_FIELD_REF)
+ UPDATE_TITCSE (TREE_OPERAND (node, 2));
+ }
+
+ /* Now see what's inside. If it's an INDIRECT_REF, copy our properties from
+ it. If it's a decl, it's definitely invariant and it's constant if the
+ decl is static. (Taking the address of a volatile variable is not
+ volatile.) If it's a constant, the address is both invariant and
+ constant. Otherwise it's neither. */
+ if (TREE_CODE (node) == INDIRECT_REF)
+ UPDATE_TITCSE (node);
+ else if (DECL_P (node))
+ {
+ if (!staticp (node))
+ tc = false;
+ }
+ else if (TREE_CODE_CLASS (TREE_CODE (node)) == 'c')
+ ;
+ else
+ {
+ ti = tc = false;
+ se |= TREE_SIDE_EFFECTS (node);
}
TREE_CONSTANT (t) = tc;
TREE_INVARIANT (t) = ti;
+ TREE_SIDE_EFFECTS (t) = se;
+#undef UPDATE_TITCSE
}
/* Build an expression of code CODE, data type TYPE, and operands as
case ADDR_EXPR:
if (node)
- {
- recompute_tree_invarant_for_addr_expr (t);
-
- /* The address of a volatile decl or reference does not have
- side-effects. But be careful not to ignore side-effects from
- other sources deeper in the expression--if node is a _REF and
- one of its operands has side-effects, so do we. */
- if (TREE_THIS_VOLATILE (node))
- {
- TREE_SIDE_EFFECTS (t) = 0;
- if (!DECL_P (node))
- {
- int i = first_rtl_op (TREE_CODE (node)) - 1;
- for (; i >= 0; --i)
- {
- if (TREE_SIDE_EFFECTS (TREE_OPERAND (node, i)))
- TREE_SIDE_EFFECTS (t) = 1;
- }
- }
- }
- }
+ recompute_tree_invarant_for_addr_expr (t);
break;
default:
TREE_CONSTANT (t) = constant;
TREE_INVARIANT (t) = invariant;
TREE_SIDE_EFFECTS (t) = side_effects;
+ TREE_THIS_VOLATILE (t)
+ = TREE_CODE_CLASS (code) == 'r' && arg0 && TREE_THIS_VOLATILE (arg0);
return t;
}
}
TREE_SIDE_EFFECTS (t) = side_effects;
+ TREE_THIS_VOLATILE (t)
+ = TREE_CODE_CLASS (code) == 'r' && arg0 && TREE_THIS_VOLATILE (arg0);
return t;
}
PROCESS_ARG(3);
TREE_SIDE_EFFECTS (t) = side_effects;
+ TREE_THIS_VOLATILE (t)
+ = TREE_CODE_CLASS (code) == 'r' && arg0 && TREE_THIS_VOLATILE (arg0);
return t;
}
&& (for_type || ! DECL_BIT_FIELD (TREE_OPERAND (op, 1)))
&& (! uns || final_prec <= innerprec || unsignedp))
{
- win = build2 (COMPONENT_REF, type, TREE_OPERAND (op, 0),
- TREE_OPERAND (op, 1));
+ win = build3 (COMPONENT_REF, type, TREE_OPERAND (op, 0),
+ TREE_OPERAND (op, 1), NULL_TREE);
TREE_SIDE_EFFECTS (win) = TREE_SIDE_EFFECTS (op);
TREE_THIS_VOLATILE (win) = TREE_THIS_VOLATILE (op);
}
/* Since type_for_size always gives an integer type. */
&& TREE_CODE (TREE_TYPE (op)) != REAL_TYPE
/* Ensure field is laid out already. */
- && DECL_SIZE (TREE_OPERAND (op, 1)) != 0)
+ && DECL_SIZE (TREE_OPERAND (op, 1)) != 0
+ && host_integerp (DECL_SIZE (TREE_OPERAND (op, 1)), 1))
{
unsigned HOST_WIDE_INT innerprec
= tree_low_cst (DECL_SIZE (TREE_OPERAND (op, 1)), 1);
{
if (first)
uns = DECL_UNSIGNED (TREE_OPERAND (op, 1));
- win = build2 (COMPONENT_REF, type, TREE_OPERAND (op, 0),
- TREE_OPERAND (op, 1));
+ win = build3 (COMPONENT_REF, type, TREE_OPERAND (op, 0),
+ TREE_OPERAND (op, 1), NULL_TREE);
TREE_SIDE_EFFECTS (win) = TREE_SIDE_EFFECTS (op);
TREE_THIS_VOLATILE (win) = TREE_THIS_VOLATILE (op);
}
/* References to storage. */
/* Value is structure or union component.
- Operand 0 is the structure or union (an expression);
- operand 1 is the field (a node of type FIELD_DECL). */
-DEFTREECODE (COMPONENT_REF, "component_ref", 'r', 2)
+ Operand 0 is the structure or union (an expression).
+ Operand 1 is the field (a node of type FIELD_DECL).
+ Operand 2, if present, is the value of DECL_FIELD_OFFSET, measured
+ in units of DECL_OFFSET_ALIGN / BITS_PER_UNIT. */
+DEFTREECODE (COMPONENT_REF, "component_ref", 'r', 3)
/* Reference to a group of bits within an object. Similar to COMPONENT_REF
except the position is given explicitly rather than via a FIELD_DECL.
DEFTREECODE (BUFFER_REF, "buffer_ref", 'r', 1)
/* Array indexing.
- Operand 0 is the array; operand 1 is a (single) array index. */
-DEFTREECODE (ARRAY_REF, "array_ref", 'r', 2)
+ Operand 0 is the array; operand 1 is a (single) array index.
+ Operand 2, if present, is a copy of TYPE_MIN_VALUE of the index.
+ Operand 3, if present, is the element size, measured in units of
+ the alignment of the element type. */
+DEFTREECODE (ARRAY_REF, "array_ref", 'r', 4)
/* Likewise, except that the result is a range ("slice") of the array. The
starting index of the resulting array is taken from operand 1 and the size
of the range is taken from the type of the expression. */
-DEFTREECODE (ARRAY_RANGE_REF, "array_range_ref", 'r', 2)
+DEFTREECODE (ARRAY_RANGE_REF, "array_range_ref", 'r', 4)
/* Vtable indexing. Carries data useful for emitting information
for vtable garbage collection.
extern int handled_component_p (tree);
+/* Return a tree of sizetype representing the size, in bytes, of the element
+ of EXP, an ARRAY_REF. */
+
+extern tree array_ref_element_size (tree);
+
+/* Return a tree representing the lower bound of the array mentioned in
+ EXP, an ARRAY_REF. */
+
+extern tree array_ref_low_bound (tree);
+
+/* Return a tree representing the offset, in bytes, of the field referenced
+ by EXP. This does not include any offset in DECL_FIELD_BIT_OFFSET. */
+
+extern tree component_ref_field_offset (tree);
+
/* Given a DECL or TYPE, return the scope in which it was declared, or
NUL_TREE if there is no containing scope. */