*** ./alias.c.~1~ 2004-06-03 16:26:18.000000000 -0400 --- ./alias.c 2004-06-03 16:25:19.000000000 -0400 *************** static GTY(()) HOST_WIDE_INT varargs_set *** 737,746 **** --- 737,754 ---- HOST_WIDE_INT get_varargs_alias_set (void) { + #if 1 + /* We now lower VA_ARG_EXPR, and there's currently no way to attach the + varargs alias set to an INDIRECT_REF (FIXME!), so we can't + consistently use the varargs alias set for loads from the varargs + area. So don't use it anywhere. */ + return 0; + #else if (varargs_set == -1) varargs_set = new_alias_set (); return varargs_set; + #endif } /* Likewise, but used for the fixed portions of the frame, e.g., register *** ./config/i386/i386.c.~1~ 2004-06-03 16:26:18.000000000 -0400 --- ./config/i386/i386.c 2004-06-08 16:29:35.000000000 -0400 *************** Boston, MA 02111-1307, USA. */ *** 46,51 **** --- 46,52 ---- #include "target-def.h" #include "langhooks.h" #include "cgraph.h" + #include "tree-gimple.h" #ifndef CHECK_STACK_LIMIT #define CHECK_STACK_LIMIT (-1) *************** static bool ix86_expand_carry_flag_compa *** 877,882 **** --- 878,884 ---- static tree ix86_build_builtin_va_list (void); static void ix86_setup_incoming_varargs (CUMULATIVE_ARGS *, enum machine_mode, tree, int *, int); + static void ix86_gimplify_va_arg (tree *expr_p, tree *pre_p, tree *post_p); struct ix86_address { *************** static void init_ext_80387_constants (vo *** 1069,1074 **** --- 1071,1079 ---- #undef TARGET_SETUP_INCOMING_VARARGS #define TARGET_SETUP_INCOMING_VARARGS ix86_setup_incoming_varargs + #undef TARGET_GIMPLIFY_VA_ARG_EXPR + #define TARGET_GIMPLIFY_VA_ARG_EXPR ix86_gimplify_va_arg + struct gcc_target targetm = TARGET_INITIALIZER; *************** ix86_va_arg (tree valist, tree type) *** 3410,3415 **** --- 3415,3672 ---- return addr_rtx; } + + /* Lower VA_ARG_EXPR at gimplification time. */ + + void + ix86_gimplify_va_arg (tree *expr_p, tree *pre_p, tree *post_p) + { + tree valist = TREE_OPERAND (*expr_p, 0); + tree type = TREE_TYPE (*expr_p); + static const int intreg[6] = { 0, 1, 2, 3, 4, 5 }; + tree f_gpr, f_fpr, f_ovf, f_sav; + tree gpr, fpr, ovf, sav, t; + int size, rsize; + tree lab_false, lab_over = NULL_TREE; + tree addr, t2; + rtx container; + int indirect_p = 0; + tree ptrtype; + + /* Only 64bit target needs something special. */ + if (!TARGET_64BIT) + { + std_gimplify_va_arg_expr (expr_p, pre_p, post_p); + return; + } + + f_gpr = TYPE_FIELDS (TREE_TYPE (va_list_type_node)); + f_fpr = TREE_CHAIN (f_gpr); + f_ovf = TREE_CHAIN (f_fpr); + 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); + + size = int_size_in_bytes (type); + if (size == -1) + { + /* Variable-size types are passed by reference. */ + indirect_p = 1; + type = build_pointer_type (type); + size = int_size_in_bytes (type); + } + rsize = (size + UNITS_PER_WORD - 1) / UNITS_PER_WORD; + + container = construct_container (TYPE_MODE (type), type, 0, + REGPARM_MAX, SSE_REGPARM_MAX, intreg, 0); + /* + * Pull the value out of the saved registers ... + */ + + addr = create_tmp_var (ptr_type_node, "addr"); + DECL_POINTER_ALIAS_SET (addr) = get_varargs_alias_set (); + + if (container) + { + int needed_intregs, needed_sseregs; + int need_temp; + tree int_addr, sse_addr; + + lab_false = create_artificial_label (); + lab_over = create_artificial_label (); + + examine_argument (TYPE_MODE (type), type, 0, + &needed_intregs, &needed_sseregs); + + + need_temp = ((needed_intregs && TYPE_ALIGN (type) > 64) + || TYPE_ALIGN (type) > 128); + + /* In case we are passing structure, verify that it is consecutive block + on the register save area. If not we need to do moves. */ + if (!need_temp && !REG_P (container)) + { + /* Verify that all registers are strictly consecutive */ + if (SSE_REGNO_P (REGNO (XEXP (XVECEXP (container, 0, 0), 0)))) + { + int i; + + for (i = 0; i < XVECLEN (container, 0) && !need_temp; i++) + { + rtx slot = XVECEXP (container, 0, i); + if (REGNO (XEXP (slot, 0)) != FIRST_SSE_REG + (unsigned int) i + || INTVAL (XEXP (slot, 1)) != i * 16) + need_temp = 1; + } + } + else + { + int i; + + for (i = 0; i < XVECLEN (container, 0) && !need_temp; i++) + { + rtx slot = XVECEXP (container, 0, i); + if (REGNO (XEXP (slot, 0)) != (unsigned int) i + || INTVAL (XEXP (slot, 1)) != i * 8) + need_temp = 1; + } + } + } + if (!need_temp) + { + int_addr = addr; + sse_addr = addr; + } + else + { + int_addr = create_tmp_var (ptr_type_node, "int_addr"); + DECL_POINTER_ALIAS_SET (int_addr) = get_varargs_alias_set (); + sse_addr = create_tmp_var (ptr_type_node, "sse_addr"); + DECL_POINTER_ALIAS_SET (sse_addr) = get_varargs_alias_set (); + } + /* First ensure that we fit completely in registers. */ + if (needed_intregs) + { + t = build_int_2 ((REGPARM_MAX - needed_intregs + 1) * 8, 0); + TREE_TYPE (t) = TREE_TYPE (gpr); + t = build2 (GE_EXPR, boolean_type_node, gpr, t); + t2 = build1 (GOTO_EXPR, void_type_node, lab_false); + t = build (COND_EXPR, void_type_node, t, t2, NULL_TREE); + gimplify_and_add (t, pre_p); + } + if (needed_sseregs) + { + t = build_int_2 ((SSE_REGPARM_MAX - needed_sseregs + 1) * 16 + + REGPARM_MAX * 8, 0); + TREE_TYPE (t) = TREE_TYPE (fpr); + t = build2 (GE_EXPR, boolean_type_node, fpr, t); + t2 = build1 (GOTO_EXPR, void_type_node, lab_false); + t = build (COND_EXPR, void_type_node, t, t2, NULL_TREE); + gimplify_and_add (t, pre_p); + } + + /* Compute index to start of area used for integer regs. */ + if (needed_intregs) + { + /* int_addr = gpr + sav; */ + t = build2 (PLUS_EXPR, ptr_type_node, sav, gpr); + t = build2 (MODIFY_EXPR, void_type_node, int_addr, t); + gimplify_and_add (t, pre_p); + } + if (needed_sseregs) + { + /* sse_addr = fpr + sav; */ + t = build2 (PLUS_EXPR, ptr_type_node, sav, fpr); + t = build2 (MODIFY_EXPR, void_type_node, sse_addr, t); + gimplify_and_add (t, pre_p); + } + if (need_temp) + { + int i; + tree temp = create_tmp_var (type, "va_arg_tmp"); + + /* addr = &temp; */ + t = build1 (ADDR_EXPR, build_pointer_type (type), temp); + t = build2 (MODIFY_EXPR, void_type_node, addr, t); + gimplify_and_add (t, pre_p); + + for (i = 0; i < XVECLEN (container, 0); i++) + { + rtx slot = XVECEXP (container, 0, i); + rtx reg = XEXP (slot, 0); + enum machine_mode mode = GET_MODE (reg); + tree piece_type = lang_hooks.types.type_for_mode (mode, 1); + tree addr_type = build_pointer_type (piece_type); + tree src_addr, src; + int src_offset; + tree dest_addr, dest; + + if (SSE_REGNO_P (REGNO (reg))) + { + src_addr = sse_addr; + src_offset = (REGNO (reg) - FIRST_SSE_REG) * 16; + } + else + { + src_addr = int_addr; + src_offset = REGNO (reg) * 8; + } + src_addr = convert (addr_type, src_addr); + src_addr = fold (build2 (PLUS_EXPR, addr_type, src_addr, + size_int (src_offset))); + src = build_fold_indirect_ref (src_addr); + + dest_addr = convert (addr_type, addr); + dest_addr = fold (build2 (PLUS_EXPR, addr_type, dest_addr, + size_int (INTVAL (XEXP (slot, 1))))); + dest = build_fold_indirect_ref (dest_addr); + + t = build2 (MODIFY_EXPR, void_type_node, dest, src); + gimplify_and_add (t, pre_p); + } + } + + if (needed_intregs) + { + t = build2 (PLUS_EXPR, TREE_TYPE (gpr), gpr, + build_int_2 (needed_intregs * 8, 0)); + t = build2 (MODIFY_EXPR, TREE_TYPE (gpr), gpr, t); + gimplify_and_add (t, pre_p); + } + if (needed_sseregs) + { + t = + build2 (PLUS_EXPR, TREE_TYPE (fpr), fpr, + build_int_2 (needed_sseregs * 16, 0)); + t = build2 (MODIFY_EXPR, TREE_TYPE (fpr), fpr, t); + gimplify_and_add (t, pre_p); + } + + t = build1 (GOTO_EXPR, void_type_node, lab_over); + gimplify_and_add (t, pre_p); + + t = build1 (LABEL_EXPR, void_type_node, lab_false); + append_to_statement_list (t, pre_p); + } + + /* ... otherwise out of the overflow area. */ + + /* Care for on-stack alignment if needed. */ + if (FUNCTION_ARG_BOUNDARY (VOIDmode, type) <= 64) + t = ovf; + else + { + HOST_WIDE_INT align = FUNCTION_ARG_BOUNDARY (VOIDmode, type) / 8; + t = build (PLUS_EXPR, TREE_TYPE (ovf), ovf, build_int_2 (align - 1, 0)); + t = build (BIT_AND_EXPR, TREE_TYPE (t), t, build_int_2 (-align, -1)); + } + gimplify_expr (&t, pre_p, NULL, is_gimple_val, fb_rvalue); + + t2 = build2 (MODIFY_EXPR, void_type_node, addr, t); + gimplify_and_add (t2, pre_p); + + t = build2 (PLUS_EXPR, TREE_TYPE (t), t, + build_int_2 (rsize * UNITS_PER_WORD, 0)); + t = build2 (MODIFY_EXPR, TREE_TYPE (ovf), ovf, t); + gimplify_and_add (t, pre_p); + + if (container) + { + t = build1 (LABEL_EXPR, void_type_node, lab_over); + append_to_statement_list (t, pre_p); + } + + ptrtype = build_pointer_type (type); + addr = convert (ptrtype, addr); + + if (indirect_p) + addr = build_fold_indirect_ref (addr); + *expr_p = build_fold_indirect_ref (addr); + } /* Return nonzero if OP is either a i387 or SSE fp register. */ int *** ./config/ia64/ia64.c.~1~ 2004-06-03 16:26:18.000000000 -0400 --- ./config/ia64/ia64.c 2004-06-08 16:36:59.000000000 -0400 *************** Boston, MA 02111-1307, USA. */ *** 51,56 **** --- 51,57 ---- #include "hashtab.h" #include "langhooks.h" #include "cfglayout.h" + #include "tree-gimple.h" /* This is used for communication between ASM_OUTPUT_LABEL and ASM_OUTPUT_LABELREF. */ *************** static void ia64_vms_init_libfuncs (void *** 273,278 **** --- 274,280 ---- static tree ia64_handle_model_attribute (tree *, tree, tree, int, bool *); static void ia64_encode_section_info (tree, rtx, int); static rtx ia64_struct_value_rtx (tree, int); + static void ia64_gimplify_va_arg (tree *, tree *, tree *); /* Table of valid machine attributes. */ *************** static const struct attribute_spec ia64_ *** 407,412 **** --- 409,417 ---- #undef TARGET_STRICT_ARGUMENT_NAMING #define TARGET_STRICT_ARGUMENT_NAMING hook_bool_CUMULATIVE_ARGS_true + #undef TARGET_GIMPLIFY_VA_ARG_EXPR + #define TARGET_GIMPLIFY_VA_ARG_EXPR ia64_gimplify_va_arg + struct gcc_target targetm = TARGET_INITIALIZER; /* Return 1 if OP is a valid operand for the MEM of a CALL insn. */ *************** ia64_va_arg (tree valist, tree type) *** 3987,3992 **** --- 3992,4030 ---- return std_expand_builtin_va_arg (valist, type); } + + static void + ia64_gimplify_va_arg (tree *expr_p, tree *pre_p, tree *post_p) + { + tree valist = TREE_OPERAND (*expr_p, 0); + tree type = TREE_TYPE (*expr_p); + + /* Variable sized types are passed by reference. */ + if (TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST) + { + TREE_TYPE (*expr_p) = build_pointer_type (type); + std_gimplify_va_arg_expr (expr_p, pre_p, post_p); + *expr_p = build_fold_indirect_ref (*expr_p); + return; + } + + /* Aggregate arguments with alignment larger than 8 bytes start at + the next even boundary. Integer and floating point arguments + do so if they are larger than 8 bytes, whether or not they are + also aligned larger than 8 bytes. */ + if ((TREE_CODE (type) == REAL_TYPE || TREE_CODE (type) == INTEGER_TYPE) + ? int_size_in_bytes (type) > 8 : TYPE_ALIGN (type) > 8 * BITS_PER_UNIT) + { + tree t = build (PLUS_EXPR, TREE_TYPE (valist), valist, + build_int_2 (2 * UNITS_PER_WORD - 1, 0)); + t = build (BIT_AND_EXPR, TREE_TYPE (t), t, + build_int_2 (-2 * UNITS_PER_WORD, -1)); + t = build (MODIFY_EXPR, TREE_TYPE (valist), valist, t); + gimplify_and_add (t, pre_p); + } + + std_gimplify_va_arg_expr (expr_p, pre_p, post_p); + } /* Return 1 if function return value returned in memory. Return 0 if it is in a register. */ *** ./config/rs6000/rs6000.c.~1~ 2004-06-03 16:26:18.000000000 -0400 --- ./config/rs6000/rs6000.c 2004-06-09 00:41:59.000000000 -0400 *************** *** 52,57 **** --- 52,58 ---- #include "reload.h" #include "cfglayout.h" #include "sched-int.h" + #include "tree-gimple.h" #if TARGET_XCOFF #include "xcoffout.h" /* get declarations of xcoff_*_section_name */ #endif *************** static tree get_prev_label (tree functio *** 439,444 **** --- 440,446 ---- #endif static tree rs6000_build_builtin_va_list (void); + static void rs6000_gimplify_va_arg (tree *, tree *, tree *); /* Hash table stuff for keeping track of TOC entries. */ *************** static const char alt_reg_names[][8] = *** 647,652 **** --- 649,657 ---- #undef TARGET_BUILD_BUILTIN_VA_LIST #define TARGET_BUILD_BUILTIN_VA_LIST rs6000_build_builtin_va_list + #undef TARGET_GIMPLIFY_VA_ARG_EXPR + #define TARGET_GIMPLIFY_VA_ARG_EXPR rs6000_gimplify_va_arg + struct gcc_target targetm = TARGET_INITIALIZER; *************** rs6000_va_arg (tree valist, tree type) *** 5287,5292 **** --- 5292,5534 ---- return addr_rtx; } + void + rs6000_gimplify_va_arg (tree *expr_p, tree *pre_p, tree *post_p) + { + tree valist = TREE_OPERAND (*expr_p, 0); + tree type = TREE_TYPE (*expr_p); + tree f_gpr, f_fpr, f_res, f_ovf, f_sav; + tree gpr, fpr, ovf, sav, reg, t, u; + int indirect_p, size, rsize, n_reg, sav_ofs, sav_scale; + tree lab_false, lab_over, addr; + int align; + tree ptrtype = build_pointer_type (type); + + if (DEFAULT_ABI != ABI_V4) + { + /* Variable sized types are passed by reference, as are AltiVec + vectors when 32-bit and not using the AltiVec ABI extension. */ + if (int_size_in_bytes (type) < 0 + || (TARGET_32BIT + && !TARGET_ALTIVEC_ABI + && ALTIVEC_VECTOR_MODE (TYPE_MODE (type)))) + { + /* Args grow upward. */ + t = build2 (POSTINCREMENT_EXPR, TREE_TYPE (valist), valist, + build_int_2 (POINTER_SIZE / BITS_PER_UNIT, 0)); + t = build1 (NOP_EXPR, build_pointer_type (ptrtype), t); + t = build_fold_indirect_ref (t); + t = build_fold_indirect_ref (t); + + *expr_p = t; + return; + } + if (targetm.calls.split_complex_arg + && TREE_CODE (type) == COMPLEX_TYPE) + { + tree elem_type = TREE_TYPE (type); + enum machine_mode elem_mode = TYPE_MODE (elem_type); + int elem_size = GET_MODE_SIZE (elem_mode); + + if (elem_size < UNITS_PER_WORD) + { + tree real_part, imag_addr, dest_real, rr; + tree post = NULL_TREE; + + /* This is a bit tricky because we can't just feed the + VA_ARG_EXPRs back into gimplify_expr; if we did, + gimplify_va_arg_expr would complain about trying to pass a + float. */ + real_part = build1 (VA_ARG_EXPR, elem_type, valist); + rs6000_gimplify_va_arg (&real_part, pre_p, &post); + gimplify_expr (&real_part, pre_p, &post, is_gimple_val, + fb_rvalue); + append_to_statement_list (post, pre_p); + + imag_addr = build1 (VA_ARG_EXPR, elem_type, valist); + rs6000_gimplify_va_arg (&imag_addr, pre_p, post_p); + imag_addr = build_fold_addr_expr (imag_addr); + gimplify_expr (&imag_addr, pre_p, post_p, is_gimple_val, + fb_rvalue); + + /* We're not returning the value here, but the address. + real_part and imag_part are not contiguous, and we know + there is space available to pack real_part next to + imag_part. float _Complex is not promoted to + double _Complex by the default promotion rules that + promote float to double. */ + if (2 * elem_size > UNITS_PER_WORD) + abort (); + + dest_real = fold (build2 (MINUS_EXPR, TREE_TYPE (imag_addr), + imag_addr, ssize_int (elem_size))); + gimplify_expr (&dest_real, pre_p, post_p, is_gimple_val, + fb_rvalue); + + rr = build_fold_indirect_ref (dest_real); + rr = build2 (MODIFY_EXPR, void_type_node, rr, real_part); + gimplify_and_add (rr, pre_p); + + dest_real = convert (build_pointer_type (type), dest_real); + *expr_p = build_fold_indirect_ref (dest_real); + + return; + } + } + + std_gimplify_va_arg_expr (expr_p, pre_p, post_p); + return; + } + + f_gpr = TYPE_FIELDS (TREE_TYPE (va_list_type_node)); + f_fpr = TREE_CHAIN (f_gpr); + f_res = TREE_CHAIN (f_fpr); + f_ovf = TREE_CHAIN (f_res); + 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); + + size = int_size_in_bytes (type); + rsize = (size + 3) / 4; + align = 1; + + if (AGGREGATE_TYPE_P (type) + || TYPE_MODE (type) == TFmode + || (!TARGET_ALTIVEC_ABI && ALTIVEC_VECTOR_MODE (TYPE_MODE (type)))) + { + /* Aggregates, long doubles, and AltiVec vectors are passed by + reference. */ + indirect_p = 1; + reg = gpr; + n_reg = 1; + sav_ofs = 0; + sav_scale = 4; + size = 4; + rsize = 1; + } + else if (TARGET_HARD_FLOAT && TARGET_FPRS + && (TYPE_MODE (type) == SFmode || TYPE_MODE (type) == DFmode)) + { + /* FP args go in FP registers, if present. */ + indirect_p = 0; + reg = fpr; + n_reg = 1; + sav_ofs = 8*4; + sav_scale = 8; + if (TYPE_MODE (type) == DFmode) + align = 8; + } + else + { + /* Otherwise into GP registers. */ + indirect_p = 0; + reg = gpr; + n_reg = rsize; + sav_ofs = 0; + sav_scale = 4; + if (n_reg == 2) + align = 8; + } + + /* Pull the value out of the saved registers.... */ + + lab_over = NULL; + addr = create_tmp_var (ptr_type_node, "addr"); + DECL_POINTER_ALIAS_SET (addr) = get_varargs_alias_set (); + + /* AltiVec vectors never go in registers when -mabi=altivec. */ + if (TARGET_ALTIVEC_ABI && ALTIVEC_VECTOR_MODE (TYPE_MODE (type))) + align = 16; + else + { + lab_false = create_artificial_label (); + lab_over = create_artificial_label (); + + /* Long long and SPE vectors are aligned in the registers. + As are any other 2 gpr item such as complex int due to a + historical mistake. */ + u = reg; + if (n_reg == 2) + { + u = build2 (BIT_AND_EXPR, TREE_TYPE (reg), reg, + build_int_2 (n_reg - 1, 0)); + u = build2 (POSTINCREMENT_EXPR, TREE_TYPE (reg), reg, u); + } + + t = build_int_2 (8 - n_reg + 1, 0); + TREE_TYPE (t) = TREE_TYPE (reg); + t = build2 (GE_EXPR, boolean_type_node, u, t); + u = build1 (GOTO_EXPR, void_type_node, lab_false); + t = build3 (COND_EXPR, void_type_node, t, u, NULL_TREE); + gimplify_and_add (t, pre_p); + + t = sav; + if (sav_ofs) + t = build2 (PLUS_EXPR, ptr_type_node, sav, build_int_2 (sav_ofs, 0)); + + u = build2 (POSTINCREMENT_EXPR, TREE_TYPE (reg), reg, + build_int_2 (n_reg, 0)); + u = build1 (CONVERT_EXPR, integer_type_node, u); + u = build2 (MULT_EXPR, integer_type_node, u, build_int_2 (sav_scale, 0)); + t = build2 (PLUS_EXPR, ptr_type_node, t, u); + + t = build2 (MODIFY_EXPR, void_type_node, addr, t); + gimplify_and_add (t, pre_p); + + t = build1 (GOTO_EXPR, void_type_node, lab_over); + gimplify_and_add (t, pre_p); + + t = build1 (LABEL_EXPR, void_type_node, lab_false); + append_to_statement_list (t, pre_p); + + if (n_reg > 2) + { + /* Ensure that we don't find any more args in regs. + Alignment has taken care of the n_reg == 2 case. */ + t = build (MODIFY_EXPR, TREE_TYPE (reg), reg, build_int_2 (8, 0)); + gimplify_and_add (t, pre_p); + } + } + + /* ... otherwise out of the overflow area. */ + + /* Care for on-stack alignment if needed. */ + t = ovf; + if (align != 1) + { + t = build2 (PLUS_EXPR, TREE_TYPE (t), t, build_int_2 (align - 1, 0)); + t = build2 (BIT_AND_EXPR, TREE_TYPE (t), t, build_int_2 (-align, -1)); + } + gimplify_expr (&t, pre_p, NULL, is_gimple_val, fb_rvalue); + + u = build2 (MODIFY_EXPR, void_type_node, addr, t); + gimplify_and_add (u, pre_p); + + t = build2 (PLUS_EXPR, TREE_TYPE (t), t, build_int_2 (size, 0)); + t = build2 (MODIFY_EXPR, TREE_TYPE (ovf), ovf, t); + gimplify_and_add (t, pre_p); + + if (lab_over) + { + t = build1 (LABEL_EXPR, void_type_node, lab_over); + append_to_statement_list (t, pre_p); + } + + if (indirect_p) + { + addr = convert (build_pointer_type (ptrtype), addr); + addr = build_fold_indirect_ref (addr); + } + else + addr = convert (ptrtype, addr); + + *expr_p = build_fold_indirect_ref (addr); + } + /* Builtins. */ #define def_builtin(MASK, NAME, TYPE, CODE) \ *** ./config/sparc/sparc.c.~1~ 2004-06-03 16:26:18.000000000 -0400 --- ./config/sparc/sparc.c 2004-06-09 00:52:36.000000000 -0400 *************** Boston, MA 02111-1307, USA. */ *** 47,52 **** --- 47,53 ---- #include "target.h" #include "target-def.h" #include "cfglayout.h" + #include "tree-gimple.h" /* Global variables for machine-dependent things. */ *************** static bool sparc_promote_prototypes (tr *** 181,186 **** --- 182,190 ---- static rtx sparc_struct_value_rtx (tree, int); static bool sparc_return_in_memory (tree, tree); static bool sparc_strict_argument_naming (CUMULATIVE_ARGS *); + #if 0 + static void sparc_gimplify_va_arg (tree *, tree *, tree *); + #endif /* Option handling. */ *************** enum processor_type sparc_cpu; *** 289,294 **** --- 293,303 ---- #undef TARGET_STRICT_ARGUMENT_NAMING #define TARGET_STRICT_ARGUMENT_NAMING sparc_strict_argument_naming + #if 0 + #undef TARGET_GIMPLIFY_VA_ARG_EXPR + #define TARGET_GIMPLIFY_VA_ARG_EXPR sparc_gimplify_va_arg + #endif + struct gcc_target targetm = TARGET_INITIALIZER; /* Validate and override various options, and do some machine dependent *************** sparc_va_arg (tree valist, tree type) *** 6042,6047 **** --- 6051,6155 ---- return addr_rtx; } + + #if 0 + void + sparc_gimplify_va_arg (tree *expr_p, tree *pre_p, tree *post_p) + { + tree valist = TREE_OPERAND (*expr_p, 0); + tree type = TREE_TYPE (*expr_p); + HOST_WIDE_INT size, rsize, align; + tree addr, incr; + bool indirect; + tree ptrtype = build_pointer_type (type); + + if (function_arg_pass_by_reference (0, TYPE_MODE (type), type, 0)) + { + indirect = true; + size = rsize = UNITS_PER_WORD; + align = 0; + } + else + { + indirect = false; + size = int_size_in_bytes (type); + rsize = (size + UNITS_PER_WORD - 1) & -UNITS_PER_WORD; + align = 0; + + if (TARGET_ARCH64) + { + /* For SPARC64, objects requiring 16-byte alignment get it. */ + if (TYPE_ALIGN (type) >= 2 * (unsigned) BITS_PER_WORD) + align = 2 * UNITS_PER_WORD; + + /* SPARC-V9 ABI states that structures up to 16 bytes in size + are given whole slots as needed. */ + if (AGGREGATE_TYPE_P (type)) + { + if (size == 0) + size = rsize = UNITS_PER_WORD; + else + size = rsize; + } + } + } + + incr = valist; + if (align) + { + incr = fold (build2 (PLUS_EXPR, ptr_type_node, incr, + build_int_2 (align - 1, 0))); + incr = fold (build2 (BIT_AND_EXPR, ptr_type_node, incr, + build_int_2 (-align, -1))); + } + + gimplify_expr (&incr, pre_p, post_p, is_gimple_val, fb_rvalue); + addr = incr; + + if (BYTES_BIG_ENDIAN && size < rsize) + { + addr = fold (build2 (PLUS_EXPR, ptr_type_node, incr, + build_int_2 (rsize - size, 0))); + } + incr = fold (build2 (PLUS_EXPR, ptr_type_node, incr, + build_int_2 (rsize, 0))); + + incr = build2 (MODIFY_EXPR, ptr_type_node, valist, incr); + gimplify_and_add (incr, pre_p); + + if (indirect) + { + addr = convert (build_pointer_type (ptrtype), addr); + addr = build_fold_indirect_ref (addr); + } + /* If the address isn't aligned properly for the type, + we may need to copy to a temporary. + FIXME: This is inefficient. Usually we can do this + in registers. */ + else if (align == 0 + && TYPE_ALIGN (type) > BITS_PER_WORD) + { + tree tmp = create_tmp_var (type, "va_arg_tmp"); + tree dest_addr = build1 (ADDR_EXPR, build_pointer_type (type), tmp); + + incr = build_function_call_expr + (implicit_built_in_decls[BUILT_IN_MEMCPY], + tree_cons (NULL_TREE, dest_addr, + tree_cons (NULL_TREE, addr, + tree_cons (NULL_TREE, size_int (rsize), + NULL_TREE)))); + gimplify_and_add (incr, pre_p); + *expr_p = tmp; + return GS_ALL_DONE; + } + + if (!indirect) + addr = convert (build_pointer_type (type), addr); + *expr_p = build_fold_indirect_ref (addr); + + return false; + } + #endif /* Return the string to output a conditional branch to LABEL, which is the operand number of the label. OP is the conditional expression. *** ./doc/tm.texi.~1~ 2004-05-25 16:03:40.000000000 -0400 --- ./doc/tm.texi 2004-06-08 17:04:12.000000000 -0400 *************** The default value of this hook is @code{ *** 3864,3869 **** --- 3864,3881 ---- false. @end deftypefn + @deftypefn {Target Hook} bool TARGET_GIMPLIFY_VA_ARG_EXPR (tree *@var{expr_p}, tree *@var{pre_p}, tree *@var{post_p}) + This hook performs target-specific gimplification of + @code{VA_ARG_EXPR}. The arguments are as for + @code{gimplify.c:gimplify_expr}. + + You only need to define this hook if you also define + @code{EXPAND_BUILTIN_VA_ARG}; it is pretty easy to reuse the same code + for both. One significant difference is that + @code{EXPAND_BUILTIN_VA_ARG} returns an address, whereas this hook + produces a reference, usually an @code{INDIRECT_REF}. + @end deftypefn + @node Scalar Return @subsection How Scalar Function Values Are Returned @cindex return values in registers *** ./builtins.c.~1~ 2004-06-03 16:26:18.000000000 -0400 --- ./builtins.c 2004-06-08 16:37:12.000000000 -0400 *************** stabilize_va_list (tree valist, int need *** 4102,4111 **** if (TREE_CODE (TREE_TYPE (valist)) == ARRAY_TYPE) { tree p1 = build_pointer_type (TREE_TYPE (va_list_type_node)); ! tree p2 = build_pointer_type (va_list_type_node); ! ! valist = build1 (ADDR_EXPR, p2, valist); ! valist = fold_convert (p1, valist); } } else --- 4102,4108 ---- if (TREE_CODE (TREE_TYPE (valist)) == ARRAY_TYPE) { tree p1 = build_pointer_type (TREE_TYPE (va_list_type_node)); ! valist = build_fold_addr_expr_with_type (valist, p1); } } else *************** stabilize_va_list (tree valist, int need *** 4124,4131 **** if (TREE_SIDE_EFFECTS (valist)) valist = save_expr (valist); ! valist = fold (build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (valist)), ! valist)); } return valist; --- 4121,4127 ---- if (TREE_SIDE_EFFECTS (valist)) valist = save_expr (valist); ! valist = build_fold_indirect_ref (valist); } return valist; *************** expand_builtin_va_arg (tree valist, tree *** 4360,4365 **** --- 4356,4539 ---- return result; } + /* Like std_expand_builtin_va_arg, but gimplify instead of expanding. */ + + void + std_gimplify_va_arg_expr (tree *expr_p, tree *pre_p, tree *post_p) + { + tree addr, t, type_size = NULL; + tree align, alignm1; + tree rounded_size; + HOST_WIDE_INT boundary; + tree valist = TREE_OPERAND (*expr_p, 0); + tree type = TREE_TYPE (*expr_p); + + /* Compute the rounded size of the type. */ + align = size_int (PARM_BOUNDARY / BITS_PER_UNIT); + alignm1 = size_int (PARM_BOUNDARY / BITS_PER_UNIT - 1); + boundary = FUNCTION_ARG_BOUNDARY (TYPE_MODE (type), type); + + /* Reduce valist it so it's sharable with the postqueue. */ + gimplify_expr (&valist, pre_p, post_p, is_gimple_min_lval, fb_lvalue); + + /* va_list pointer is aligned to PARM_BOUNDARY. If argument actually + requires greater alignment, we must perform dynamic alignment. */ + + if (boundary > PARM_BOUNDARY) + { + if (!PAD_VARARGS_DOWN) + { + t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist, + build2 (PLUS_EXPR, TREE_TYPE (valist), valist, + build_int_2 (boundary / BITS_PER_UNIT - 1, 0))); + gimplify_stmt (&t); + append_to_statement_list (t, pre_p); + } + t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist, + build2 (BIT_AND_EXPR, TREE_TYPE (valist), valist, + build_int_2 (~(boundary / BITS_PER_UNIT - 1), -1))); + gimplify_stmt (&t); + append_to_statement_list (t, pre_p); + } + if (type == error_mark_node + || (type_size = TYPE_SIZE_UNIT (TYPE_MAIN_VARIANT (type))) == NULL + || TREE_OVERFLOW (type_size)) + rounded_size = size_zero_node; + else + { + rounded_size = fold (build2 (PLUS_EXPR, sizetype, type_size, alignm1)); + rounded_size = fold (build2 (TRUNC_DIV_EXPR, sizetype, + rounded_size, align)); + rounded_size = fold (build2 (MULT_EXPR, sizetype, + rounded_size, align)); + } + + /* Reduce rounded_size so it's sharable with the postqueue. */ + gimplify_expr (&rounded_size, pre_p, post_p, is_gimple_val, fb_rvalue); + + /* Get AP. */ + addr = valist; + if (PAD_VARARGS_DOWN && ! integer_zerop (rounded_size)) + { + /* Small args are padded downward. */ + addr = fold (build2 (PLUS_EXPR, TREE_TYPE (addr), addr, + fold (build3 (COND_EXPR, sizetype, + fold (build2 (GT_EXPR, sizetype, + rounded_size, + align)), + size_zero_node, + fold (build2 (MINUS_EXPR, + sizetype, + rounded_size, + type_size)))))); + } + + addr = convert (build_pointer_type (type), addr); + *expr_p = build1 (INDIRECT_REF, type, addr); + + /* Compute new value for AP. */ + if (! integer_zerop (rounded_size)) + { + t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist, + build2 (PLUS_EXPR, TREE_TYPE (valist), valist, + rounded_size)); + gimplify_stmt (&t); + append_to_statement_list (t, post_p); + } + } + + /* Return a dummy expression of type TYPE in order to keep going after an + error. */ + + static tree + dummy_object (tree type) + { + tree t = convert (build_pointer_type (type), null_pointer_node); + return build1 (INDIRECT_REF, type, t); + } + + /* Like expand_builtin_va_arg, but gimplify instead of expanding. */ + + enum gimplify_status + gimplify_va_arg_expr (tree *expr_p, tree *pre_p, tree *post_p) + { + tree promoted_type, want_va_type, have_va_type; + tree valist = TREE_OPERAND (*expr_p, 0); + tree type = TREE_TYPE (*expr_p); + tree t; + + /* Verify that valist is of the proper type. */ + + want_va_type = va_list_type_node; + have_va_type = TREE_TYPE (valist); + if (TREE_CODE (want_va_type) == ARRAY_TYPE) + { + /* If va_list is an array type, the argument may have decayed + to a pointer type, e.g. by being passed to another function. + In that case, unwrap both types so that we can compare the + underlying records. */ + if (TREE_CODE (have_va_type) == ARRAY_TYPE + || TREE_CODE (have_va_type) == POINTER_TYPE) + { + want_va_type = TREE_TYPE (want_va_type); + have_va_type = TREE_TYPE (have_va_type); + } + } + + if (TYPE_MAIN_VARIANT (want_va_type) != TYPE_MAIN_VARIANT (have_va_type)) + { + error ("first argument to `va_arg' not of type `va_list'"); + *expr_p = dummy_object (type); + return GS_ALL_DONE; + } + + /* Generate a diagnostic for requesting data of a type that cannot + be passed through `...' due to type promotion at the call site. */ + else if ((promoted_type = lang_hooks.types.type_promotes_to (type)) + != type) + { + static bool gave_help; + + /* Unfortunately, this is merely undefined, rather than a constraint + violation, so we cannot make this an error. If this call is never + executed, the program is still strictly conforming. */ + warning ("`%T' is promoted to `%T' when passed through `...'", + type, promoted_type); + if (! gave_help) + { + gave_help = true; + warning ("(so you should pass `%T' not `%T' to `va_arg')", + promoted_type, type); + } + + /* We can, however, treat "undefined" any way we please. + Call abort to encourage the user to fix the program. */ + inform ("if this code is reached, the program will abort"); + t = build_function_call_expr (implicit_built_in_decls[BUILT_IN_TRAP], + NULL); + append_to_statement_list (t, pre_p); + + /* This is dead code, but go ahead and finish so that the + mode of the result comes out right. */ + *expr_p = dummy_object (type); + return GS_ALL_DONE; + } + else + { + /* Make it easier for the backends by protecting the valist argument + from multiple evaluations. */ + valist = stabilize_va_list (valist, 0); + TREE_OPERAND (*expr_p, 0) = valist; + + if (!targetm.calls.gimplify_va_arg_expr) + /* Once most targets are converted this should abort. */ + return GS_ALL_DONE; + + targetm.calls.gimplify_va_arg_expr (expr_p, pre_p, post_p); + return GS_OK; + } + } + /* Expand ARGLIST, from a call to __builtin_va_end. */ static rtx *** ./gimplify.c.~1~ 2004-06-03 16:26:18.000000000 -0400 --- ./gimplify.c 2004-06-08 11:55:20.000000000 -0400 *************** Software Foundation, 59 Temple Place - S *** 45,50 **** --- 45,51 ---- #include "output.h" #include "expr.h" #include "ggc.h" + #include "target.h" static struct gimplify_ctx { *************** append_to_statement_list_force (tree t, *** 236,241 **** --- 237,251 ---- append_to_statement_list_1 (t, list_p, t != NULL); } + /* Both gimplify the statement T and append it to LIST_P. */ + + void + gimplify_and_add (tree t, tree *list_p) + { + gimplify_stmt (&t); + append_to_statement_list (t, list_p); + } + /* Add T to the end of a COMPOUND_EXPR pointed by LIST_P. The type of the result is the type of T. */ *************** copy_if_shared_r (tree *tp, int *walk_su *** 665,671 **** /* Otherwise, mark the tree as visited and keep looking. */ else ! TREE_VISITED (t) = 1; return NULL_TREE; } --- 675,697 ---- /* Otherwise, mark the tree as visited and keep looking. */ else ! { ! TREE_VISITED (t) = 1; ! if (TREE_CODE (*tp) == VA_ARG_EXPR ! && targetm.calls.gimplify_va_arg_expr == NULL) ! { ! /* Mark any _DECL inside the operand as volatile to avoid ! the optimizers messing around with it. We have to do this ! early, otherwise we might mark a variable as volatile ! after we gimplify other statements that use the variable ! assuming it's not volatile. */ ! ! /* FIXME once most targets define the above hook, this should ! go away (perhaps along with the #include "target.h"). */ ! walk_tree (&TREE_OPERAND (*tp, 0), mark_decls_volatile_r, ! NULL, NULL); ! } ! } return NULL_TREE; } *************** gimplify_minimax_expr (tree *expr_p, tre *** 1636,1674 **** 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; - while (TREE_CODE (base) == COMPONENT_REF - || TREE_CODE (base) == ARRAY_REF) - 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))); - } - /* Subroutine of gimplify_compound_lval and gimplify_array_ref. Converts an ARRAY_REF to the equivalent *(&array + offset) form. */ --- 1662,1667 ---- *************** gimplify_array_ref_to_plus (tree *expr_p *** 1719,1725 **** if (ret == GS_ERROR) return ret; ! addr = build_addr_expr_with_type (array, ptrtype); result = fold (build (add_code, ptrtype, addr, offset)); *expr_p = build1 (INDIRECT_REF, elttype, result); --- 1712,1718 ---- if (ret == GS_ERROR) return ret; ! addr = build_fold_addr_expr_with_type (array, ptrtype); result = fold (build (add_code, ptrtype, addr, offset)); *expr_p = build1 (INDIRECT_REF, elttype, result); *************** gimplify_modify_expr (tree *expr_p, tree *** 2536,2544 **** t = TYPE_SIZE_UNIT (TREE_TYPE (*to_p)); t = unshare_expr (t); args = tree_cons (NULL, t, NULL); ! t = build_addr_expr (*from_p); args = tree_cons (NULL, t, args); ! dest = build_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); --- 2529,2537 ---- 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); *************** gimplify_expr (tree *expr_p, tree *pre_p *** 3242,3255 **** break; case VA_ARG_EXPR: ! /* Mark any _DECL inside the operand as volatile to avoid the ! optimizers messing around with it. FIXME: Remove this once ! VA_ARG_EXPRs are properly lowered. */ ! walk_tree (&TREE_OPERAND (*expr_p, 0), mark_decls_volatile_r, ! NULL, NULL); ! ! /* va_arg expressions are in GIMPLE form already. */ ! ret = GS_ALL_DONE; break; case CONVERT_EXPR: --- 3235,3241 ---- break; case VA_ARG_EXPR: ! ret = gimplify_va_arg_expr (expr_p, pre_p, post_p); break; case CONVERT_EXPR: *************** gimplify_expr (tree *expr_p, tree *pre_p *** 3589,3595 **** /* An lvalue will do. Take the address of the expression, store it in a temporary, and replace the expression with an INDIRECT_REF of that temporary. */ ! tmp = build_addr_expr (*expr_p); gimplify_expr (&tmp, pre_p, post_p, is_gimple_reg, fb_rvalue); *expr_p = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (tmp)), tmp); } --- 3575,3581 ---- /* An lvalue will do. Take the address of the expression, store it in a temporary, and replace the expression with an INDIRECT_REF of that temporary. */ ! tmp = build_fold_addr_expr (*expr_p); gimplify_expr (&tmp, pre_p, post_p, is_gimple_reg, fb_rvalue); *expr_p = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (tmp)), tmp); } *** ./target-def.h.~1~ 2004-06-03 16:26:18.000000000 -0400 --- ./target-def.h 2004-06-07 15:54:38.000000000 -0400 *************** Foundation, 59 Temple Place - Suite 330, *** 358,363 **** --- 358,371 ---- default_pretend_outgoing_varargs_named #define TARGET_SPLIT_COMPLEX_ARG NULL + #ifdef EXPAND_BUILTIN_VA_ARG + /* If there's a target-specific va_arg expander, there needs to be a + target-specific gimplifier. */ + #define TARGET_GIMPLIFY_VA_ARG_EXPR NULL + #else + #define TARGET_GIMPLIFY_VA_ARG_EXPR std_gimplify_va_arg_expr + #endif + #define TARGET_CALLS { \ TARGET_PROMOTE_FUNCTION_ARGS, \ TARGET_PROMOTE_FUNCTION_RETURN, \ *************** Foundation, 59 Temple Place - Suite 330, *** 370,375 **** --- 378,384 ---- TARGET_STRICT_ARGUMENT_NAMING, \ TARGET_PRETEND_OUTGOING_VARARGS_NAMED, \ TARGET_SPLIT_COMPLEX_ARG, \ + TARGET_GIMPLIFY_VA_ARG_EXPR, \ } /* The whole shebang. */ *** ./c-objc-common.c.~1~ 2004-06-03 16:26:18.000000000 -0400 --- ./c-objc-common.c 2004-06-03 16:25:21.000000000 -0400 *************** c_tree_printer (pretty_printer *pp, text *** 270,286 **** break; case 'T': ! if (TREE_CODE (t) == TYPE_DECL) { if (DECL_NAME (t)) n = lang_hooks.decl_printable_name (t, 2); } ! else ! { ! t = TYPE_NAME (t); ! if (t) ! n = IDENTIFIER_POINTER (t); ! } break; case 'E': --- 270,284 ---- break; case 'T': ! if (TYPE_P (t)) ! t = TYPE_NAME (t); ! if (t && TREE_CODE (t) == TYPE_DECL) { if (DECL_NAME (t)) n = lang_hooks.decl_printable_name (t, 2); } ! else if (t) ! n = IDENTIFIER_POINTER (t); break; case 'E': *** ./target.h.~1~ 2004-06-03 16:26:18.000000000 -0400 --- ./target.h 2004-06-08 16:28:49.000000000 -0400 *************** struct gcc_target *** 470,475 **** --- 470,479 ---- /* Given a complex type T, return true if a parameter of type T should be passed as two scalars. */ bool (* split_complex_arg) (tree type); + + /* Gimplifies a VA_ARG_EXPR. */ + void (* gimplify_va_arg_expr) (tree *expr_p, tree *pre_p, + tree *post_p); } calls; /* Leave the boolean fields at the end. */ *** ./tree.h.~1~ 2004-06-03 16:26:18.000000000 -0400 --- ./tree.h 2004-06-04 14:47:31.000000000 -0400 *************** struct tree_block GTY(()) *** 1602,1608 **** #define TYPE_VECTOR_SUBPARTS(VECTOR_TYPE) \ GET_MODE_NUNITS (VECTOR_TYPE_CHECK (VECTOR_TYPE)->type.mode) ! /* Indicates that objects of this type must be initialized by calling a function when they are created. */ #define TYPE_NEEDS_CONSTRUCTING(NODE) \ (TYPE_CHECK (NODE)->type.needs_constructing_flag) --- 1602,1608 ---- #define TYPE_VECTOR_SUBPARTS(VECTOR_TYPE) \ GET_MODE_NUNITS (VECTOR_TYPE_CHECK (VECTOR_TYPE)->type.mode) ! /* Indicates that objects of this type must be initialized by calling a function when they are created. */ #define TYPE_NEEDS_CONSTRUCTING(NODE) \ (TYPE_CHECK (NODE)->type.needs_constructing_flag) *************** extern tree nondestructive_fold_unary_to *** 3473,3478 **** --- 3473,3481 ---- extern tree nondestructive_fold_binary_to_constant (enum tree_code, tree, tree, tree); extern tree fold_read_from_constant_string (tree); extern tree int_const_binop (enum tree_code, tree, tree, int); + extern tree build_fold_addr_expr (tree); + extern tree build_fold_addr_expr_with_type (tree, tree); + extern tree build_fold_indirect_ref (tree); /* In builtins.c */ extern tree fold_builtin (tree); *** ./tree-gimple.h.~1~ 2004-06-03 16:26:18.000000000 -0400 --- ./tree-gimple.h 2004-06-08 17:05:19.000000000 -0400 *************** void gimplify_to_stmt_list (tree *); *** 107,112 **** --- 107,113 ---- void gimplify_body (tree *, tree); void push_gimplify_context (void); void pop_gimplify_context (tree); + void gimplify_and_add (tree, tree *); /* Miscellaneous helpers. */ tree get_base_address (tree t); *************** tree build_and_jump (tree *); *** 121,126 **** --- 122,129 ---- 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 *); + void std_gimplify_va_arg_expr (tree *, tree *, tree *); /* In tree-nested.c. */ extern void lower_nested_functions (tree); *** ./fold-const.c.~1~ 2004-06-01 10:57:37.000000000 -0400 --- ./fold-const.c 2004-06-07 15:23:16.000000000 -0400 *************** fold_relational_const (enum tree_code co *** 9994,9997 **** --- 9994,10066 ---- return tem; } + /* Build an expression for the address of T. Folds away INDIRECT_REF to + avoid confusing the gimplify process. */ + + tree + build_fold_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; + while (TREE_CODE (base) == COMPONENT_REF + || TREE_CODE (base) == ARRAY_REF) + base = TREE_OPERAND (base, 0); + if (DECL_P (base)) + TREE_ADDRESSABLE (base) = 1; + + t = build1 (ADDR_EXPR, ptrtype, t); + } + + return t; + } + + tree + build_fold_addr_expr (tree t) + { + return build_fold_addr_expr_with_type (t, build_pointer_type (TREE_TYPE (t))); + } + + /* Builds an expression for an indirection through T, simplifying some + cases. */ + + tree + build_fold_indirect_ref (tree t) + { + tree type = TREE_TYPE (TREE_TYPE (t)); + tree sub = t; + tree subtype; + + STRIP_NOPS (sub); + if (TREE_CODE (sub) == ADDR_EXPR) + { + tree op = TREE_OPERAND (sub, 0); + tree optype = TREE_TYPE (op); + /* *&p => p */ + if (lang_hooks.types_compatible_p (type, optype)) + return op; + /* *(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); + } + + /* *(foo *)fooarrptr => (*fooarrptr)[0] */ + subtype = TREE_TYPE (sub); + if (TREE_CODE (TREE_TYPE (subtype)) == ARRAY_TYPE + && 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 build1 (INDIRECT_REF, type, t); + } + #include "gt-fold-const.h"