diff options
author | Richard Kenner <kenner@vlsi1.ultra.nyu.edu> | 2004-06-22 03:07:05 +0000 |
---|---|---|
committer | Richard Kenner <kenner@gcc.gnu.org> | 2004-06-21 23:07:05 -0400 |
commit | 44de5aeb00a66307236cb5b7ccfca1a21aaca080 (patch) | |
tree | 0f08ba8e2fff4040497202121f17db146e774840 /gcc/gimplify.c | |
parent | 6264b0a68d820604c6b85a4c093de22bef6382cf (diff) | |
download | gcc-44de5aeb00a66307236cb5b7ccfca1a21aaca080.zip gcc-44de5aeb00a66307236cb5b7ccfca1a21aaca080.tar.gz gcc-44de5aeb00a66307236cb5b7ccfca1a21aaca080.tar.bz2 |
alias.c (adjust_offset_for_component_ref): Use component_ref_field_offset.
* 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-line.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.
* cp/call.c (build_vfield_ref): Add new operand for COMPONENT_REF.
(build_new_method_call): Likewise.
* cp/decl.c (local_variable_p_walkfn): Don't walk into types.
* cp/decl2.c (grok_array_decl): Add new operands for ARRAY_REF.
(build_anon_union_vars): Add new operand for COMPONENT_REF.
* cp/init.c (buld_new): Add new operand for ARRAY_REF.
* cp/method.c (do_build_copy_constructor): New op for COMPONENT_REF.
(do_build_assign_ref): Likewise.
* cp/parser.c (cp_parser_direct_new_declarator): Add new operands
for ARRAY_REF.
(cp_parser_direct_declarator): Likewise.
* cp/pt.c (tsubst): Likewise.
(tsubst_copy, tsubst_copy_and_build): Likewise; also add new operand
for COMPONENT_REF.
* cp/semantics.c (finish_non_static_data_member): Add new operand
for COMPONENT_REF.
* cp/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.
* cp/typeck2.c (split_nonconstant_init_1): Likewise; COMPONENT_REF too.
* cp/tree.c (count_trees_r, no_linkage_helper): Don't walk in types.
* fortran/f95-lang.c (LANG_HOOKS_GIMPLE_BEFORE_INLINING): Deleted.
* fortran/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.
* fortran/trans-common.c (create_common): Likewise.
* fortran/trans-expr.c (gfc_conv_component_ref): Likewise.
* fortran/trans-io.c (set_parameter_value): Likewise.
(set_parameter_ref, set_string, set_flag, io_result): Likewise.
(transfer_expr): Likewise.
* fortran/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.
* fortran/trans.c (gfc_build_array_ref): Add two new operands
for ARRAY_REF.
* java/class.c (build_class_ref): Add new operand for COMPONENT_REF.
(build_static_field_ref): Likewise and add new operands for ARRAY_REF.
* java/constants.c (build_ref_from_constant_pool): Likewise.
* java/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/java-gimplify.c (java_gimplify_new_array_init): Likewise.
* java/parse.y (make_qualifed_name, build_array_ref): Likewise.
* objc/ojbc-act.c (generate_static_references): Add additional
operands to ARRAY_REF.
(generate_strings, build_method_prototype_list_template): Likewise.
(generate_protocol_list): Likewise.
From-SVN: r83474
Diffstat (limited to 'gcc/gimplify.c')
-rw-r--r-- | gcc/gimplify.c | 771 |
1 files changed, 576 insertions, 195 deletions
diff --git a/gcc/gimplify.c b/gcc/gimplify.c index f6e4a04..3649272 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -1,6 +1,5 @@ /* 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>. @@ -36,6 +35,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "langhooks.h" #include "langhooks-def.h" #include "tree-flow.h" +#include "cgraph.h" #include "timevar.h" #include "except.h" #include "hashtab.h" @@ -71,6 +71,73 @@ typedef struct gimple_temp_hash_elt 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 @@ -355,15 +422,11 @@ create_tmp_var (tree type, const char *prefix) 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 @@ -653,11 +716,19 @@ copy_if_shared_r (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED, 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 @@ -715,6 +786,31 @@ unmark_visited_r (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED, 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 @@ -1192,7 +1288,7 @@ build_and_jump (tree *label_p) { 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) { @@ -1214,7 +1310,7 @@ gimplify_exit_expr (tree *expr_p) 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; @@ -1243,7 +1339,7 @@ force_labels_r (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED) 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); @@ -1279,7 +1375,7 @@ gimplify_init_constructor (tree *expr_p, tree *pre_p, return GS_OK; } else - return GS_ALL_DONE; + return GS_UNHANDLED; } categorize_ctor_elements (ctor, &num_nonzero_elements, @@ -1307,7 +1403,7 @@ gimplify_init_constructor (tree *expr_p, tree *pre_p, 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; } @@ -1416,13 +1512,11 @@ gimplify_init_constructor (tree *expr_p, tree *pre_p, 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. */ @@ -1430,7 +1524,7 @@ gimplify_init_constructor (tree *expr_p, tree *pre_p, append_to_statement_list (init, pre_p); } - *expr_p = build_empty_stmt (); + *expr_p = alloc_stmt_list (); } break; @@ -1552,18 +1646,17 @@ canonicalize_component_ref (tree *expr_p) } /* 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); @@ -1592,8 +1685,20 @@ canonicalize_addr_expr (tree* expr_p) 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 @@ -1666,7 +1771,7 @@ gimplify_minimax_expr (tree *expr_p, tree *pre_p, tree *post_p) 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 @@ -1675,25 +1780,21 @@ gimplify_array_ref_to_plus (tree *expr_p, tree *pre_p, tree *post_p) 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. @@ -1707,7 +1808,7 @@ gimplify_array_ref_to_plus (tree *expr_p, tree *pre_p, tree *post_p) } /* 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); @@ -1723,6 +1824,44 @@ gimplify_array_ref_to_plus (tree *expr_p, tree *pre_p, tree *post_p) 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. @@ -1747,63 +1886,49 @@ gimplify_array_ref_to_plus (tree *expr_p, tree *pre_p, tree *post_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 @@ -1815,14 +1940,82 @@ gimplify_compound_lval (tree *expr_p, tree *pre_p, { 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) { @@ -1833,33 +2026,6 @@ gimplify_compound_lval (tree *expr_p, tree *pre_p, 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 @@ -1873,7 +2039,7 @@ gimplify_array_ref (tree *expr_p, tree *pre_p, 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; @@ -2166,7 +2332,7 @@ shortcut_cond_expr (tree expr) 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_)) @@ -2181,7 +2347,7 @@ shortcut_cond_expr (tree expr) 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_); } } @@ -2207,14 +2373,14 @@ shortcut_cond_expr (tree expr) && 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. */ @@ -2329,6 +2495,8 @@ gimple_boolify (tree expr) 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. */ @@ -2456,7 +2624,7 @@ gimplify_modify_expr (tree *expr_p, tree *pre_p, tree *post_p, bool want_value) { 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) @@ -2467,40 +2635,51 @@ gimplify_modify_expr (tree *expr_p, tree *pre_p, tree *post_p, bool want_value) 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; @@ -2530,35 +2709,6 @@ gimplify_modify_expr (tree *expr_p, tree *pre_p, tree *post_p, bool want_value) && !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; } @@ -2571,6 +2721,101 @@ gimplify_modify_expr (tree *expr_p, tree *pre_p, tree *post_p, bool want_value) 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. @@ -2696,7 +2941,7 @@ gimplify_save_expr (tree *expr_p, tree *pre_p, tree *post_p) 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) @@ -2742,9 +2987,15 @@ gimplify_addr_expr (tree *expr_p, tree *pre_p, tree *post_p) 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: @@ -2993,7 +3244,7 @@ gimple_push_cleanup (tree var, tree cleanup, tree *pre_p) 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); @@ -3208,10 +3459,9 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p, 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); @@ -3232,12 +3482,6 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p, 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, @@ -3265,6 +3509,34 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *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)) @@ -3293,6 +3565,7 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_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); @@ -3484,9 +3757,18 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p, 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' @@ -3529,7 +3811,7 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p, if (ret == GS_ERROR) { if (is_statement) - *expr_p = build_empty_stmt (); + *expr_p = alloc_stmt_list (); goto out; } @@ -3541,17 +3823,37 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p, #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 @@ -3562,7 +3864,7 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p, 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 @@ -3660,6 +3962,78 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p, 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); +} + #ifdef ENABLE_CHECKING /* Compare types A and B for a "close enough" match. */ @@ -3720,8 +4094,10 @@ check_pointer_types_r (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED, 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)) @@ -3751,8 +4127,12 @@ gimplify_body (tree *body_p, tree fndecl) 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); @@ -3764,13 +4144,14 @@ gimplify_body (tree *body_p, tree 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, |