From 455507905e358525176b45e9c2c49e0d35e79927 Mon Sep 17 00:00:00 2001 From: dj Date: Thu, 4 Sep 2003 03:18:05 +0000 Subject: [PATCH] * targhooks.c: New file. * targhooks.h: New file. * Makefile.in: Add targhooks.o support. (function.o): Depend on$(TARGET_H). (stmt.o): Likewise. (combine.o): Depend on $(TREE_H) and $(TARGET_H). * builtins.c (apply_args_size, expand_builtin_apply_args_1, expand_builtin_apply): Convert to calls.struct_value_rtx hook. (expand_builtin_saveregs): Convert to calls.expand_builtin_saveregs hook. * c-decl.c (start_decl): Handle new calls.promote_prototypes hook here, instead of ... (get_parm_info) ... here. (store_parm_decls_oldstyle): Convert to calls.promote_prototypes hook. (finish_function): Handle calls.promote_prototypes hook here too. * c-typeck.c (convert_arguments): Convert to calls.promote_prototypes hook. (c_convert_parm_for_inlining): Likewise. * calls.c (initialize_argument_information): Convert to calls.promote_function_args hook. (expand_call): Convert to calls.struct_value_rtx, calls.strict_argument_naming, calls.pretend_outgoing_varargs_named, and calls.promote_function_return hooks. Pass fndecl to aggregate_value_p. Initialize CUMULATIVE_ARGS before calling hooks, so they can use that. (emit_library_call_value_1): Likewise. * combine.c (setup_incoming_promotions): Convert to calls.promote_function_args hook. * emit-rtl.c: Convert to calls.struct_value_rtx hook. * expr.c (expand_assignment): Pass call to aggregate_value_p. (expand_expr): Likewise. * expr.h: Remove support for SETUP_INCOMING_VARARGS, STRICT_ARGUMENT_NAMING, PRETEND_OUTGOING_VARARGS_NAMED, RETURN_IN_MEMORY macro defaults. * final.c (profile_function): Convert to calls.struct_value_rtx hook. * function.c (aggregate_value_p): Accept function type tree as second parameter; try to deduce fntype from it. Convert to calls.return_in_memory hook. (assign_parms): Convert to calls.setup_incoming_varargs, calls.strict_argument_naming, calls.promote_function_args, calls.pretend_outgoing_varargs_named hooks. Pass fndecl to aggregate_value_p. (expand_function_start): Likewise. Convert to calls.struct_value_rtx hook. (expand_function_end): Convert to calls.promote_function_return hook. (allocate_struct_function): Pass fndecl to aggregate_value_p. * hard-reg-set.h: Update comments to new hook names. * integrate.c (expand_inline_function): Pass fndecl to aggregate_value_p. * reg-stack.c (stack_result): Likewise. * rtl.h (struct_value_rtx, struct_value_incoming_rtx): Delete. * stmt.c (expand_value_return): Convert to calls.promote_function_return hook. * target-def.h: Add TARGET_PROMOTE_FUNCTION_ARGS, TARGET_PROMOTE_FUNCTION_RETURN, TARGET_PROMOTE_PROTOTYPES, TARGET_STRUCT_VALUE_RTX, TARGET_RETURN_IN_MEMORY, TARGET_EXPAND_BUILTIN_SAVEREGS, TARGET_SETUP_INCOMING_VARARGS, TARGET_STRICT_ARGUMENT_NAMING, TARGET_PRETEND_OUTGOING_VARARGS_NAMED, and TARGET_CALLS. * target.h: Likewise. * tree.h (aggregate_value_p): Also takes a tree to deduce function attributes from (for target hooks). * doc/tm.texi (PROMOTE_FUNCTION_ARGS, PROMOTE_FUNCTION_RETURN, PROMOTE_PROTOTYPES, RETURN_IN_MEMORY, STRUCT_VALUE_REGNUM, STRUCT_VALUE, STRUCT_VALUE_INCOMING_REGNUM, STRUCT_VALUE_INCOMING, EXPAND_BUILTIN_SAVEREGS, SETUP_INCOMING_VARARGS, STRICT_ARGUMENT_NAMING, PRETEND_OUTGOING_VARARGS_NAMED): Convert to hooks. * config/alpha/alpha.c (alpha_output_mi_thunk_osf): Pass function to aggregate_value_p. * config/arm/arm.c (arm_init_cumulative_args, arm_output_mi_thunk): Likewise. * config/i386/i386.c (ix86_return_pops_args, x86_this_parameter): Likewise. * config/mips/mips.c (mips_save_reg_p, mips_expand_prologue, mips_can_use_return_insn): Likewise. * config/rs6000/rs6000.c (rs6000_output_mi_thunk): Likewise. * config/s390/s390.c (s390_output_mi_thunk): Likewise. * config/sparc/sparc.c (sparc_output_mi_thunk): Pass function to aggregate_value_p. * config/story16/stormy16.c (xstormy16_asm_output_mi_thunk): Pass function to aggregate_value_p. * objc/objc-act.c (generate_struct_by_value_array): Pass NULL to aggregate_value_p. * config/sh/sh-protos.h (sh_builtin_saveregs): Remove. (sh_attr_renesas_p, sh_cfun_attr_renesas_p, sh_function_arg, sh_function_arg_advance, sh_pass_in_reg_p): New. * config/sh/sh.c (sh_handle_renesas_attribute, sh_promote_prototypes, sh_struct_value_rtx, sh_return_in_memory, sh_builtin_saveregs, sh_setup_incoming_varargs, sh_strict_argument_naming, sh_pretend_outgoing_varargs_named): New decls. (targetm): Add new hooks. (calc_live_regs): Save MACL and MACH if the function has the renesas attribute. (sh_expand_prologue): Support renesas attribute. (sh_builtin_saveregs): Make static. (sh_build_va_list): Support renesas attribute. (sh_va_start): Likewise. (sh_va_arg): Likewise. (sh_promote_prototypes): New. (sh_function_arg): New, moved from sh.h. Support renesas attribute. (sh_function_arg_advance): Likewise. (sh_return_in_memory): Likewise. (sh_strict_argument_naming): Likewise. (sh_pretend_outgoing_varargs_named): Likewise. (sh_struct_value_rtx): New. (sh_attribute): Add renesas attribute. (sh_handle_renesas_attribute): New. (sh_attr_renesas_p, sh_cfun_attr_renesas_p): New. (sh_ms_bitfield_layout_p): Support renesas attribute also. (sh_output_mi_thunk): Pass function to aggregate_value_p. * config/sh/sh.h (TARGET_SWITCHES): Add -mrenesas as an alias for -mhitachi. (STRUCT_VALUE_REGNUM, STRUCT_VALUE, RETURN_IN_MEMORY): Moved to target hooks. (sh_args): Add renesas_abi flag. (INIT_CUMULATIVE_ARGS): Set it. Pass fndecl to aggregate_value_p. (FUNCTION_ARG_ADVANCE, FUNCTION_ARG): Move to sh.c. (PASS_IN_REG_P): Support renesas attribute. Pass DF and TF on the stack for the renesas abi. (STRICT_ARGUMENT_NAMING, PRETEND_OUTGOING_VARARGS_NAMED, SETUP_INCOMING_VARARGS, EXPAND_BUILTIN_SAVEREGS, PROMOTE_PROTOTYPES): Moved to sh.c. * config/sh/sh.md (call): Set call cookie to indicate renesas calls. * decl.c (finish_function): Pass fndecl to aggregate_value_p. * misc.c (default_pass_by_ref): Convert to calls.return_in_memory hook. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@71048 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog | 132 +++++++++++++ gcc/Makefile.in | 11 +- gcc/ada/ChangeLog | 5 + gcc/ada/misc.c | 4 +- gcc/builtins.c | 35 ++-- gcc/c-decl.c | 39 +++- gcc/c-typeck.c | 4 +- gcc/calls.c | 61 +++--- gcc/combine.c | 33 ++-- gcc/config/alpha/alpha.c | 2 +- gcc/config/arm/arm.c | 4 +- gcc/config/i386/i386.c | 6 +- gcc/config/i960/i960.c | 2 +- gcc/config/m68hc11/m68hc11.c | 2 +- gcc/config/mips/mips.c | 6 +- gcc/config/rs6000/rs6000.c | 2 +- gcc/config/s390/s390.c | 2 +- gcc/config/sh/sh-protos.h | 7 +- gcc/config/sh/sh.c | 436 ++++++++++++++++++++++++++++++++++++++++- gcc/config/sh/sh.h | 255 ++---------------------- gcc/config/sh/sh.md | 3 + gcc/config/sparc/sparc.c | 2 +- gcc/config/stormy16/stormy16.c | 2 +- gcc/cp/ChangeLog | 4 + gcc/cp/decl.c | 2 +- gcc/doc/tm.texi | 186 ++++++++---------- gcc/emit-rtl.c | 19 -- gcc/expr.c | 4 +- gcc/expr.h | 23 --- gcc/final.c | 29 +-- gcc/function.c | 74 ++++--- gcc/hard-reg-set.h | 4 +- gcc/integrate.c | 4 +- gcc/objc/objc-act.c | 2 +- gcc/reg-stack.c | 2 +- gcc/rtl.h | 2 - gcc/stmt.c | 22 ++- gcc/stor-layout.c | 1 + gcc/target-def.h | 26 +++ gcc/target.h | 17 ++ gcc/targhooks.c | 158 +++++++++++++++ gcc/targhooks.h | 31 +++ gcc/tree.h | 2 +- 43 files changed, 1112 insertions(+), 555 deletions(-) create mode 100644 gcc/targhooks.c create mode 100644 gcc/targhooks.h diff --git a/gcc/ChangeLog b/gcc/ChangeLog index bd7880186cf..62e9d65b6ce 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,135 @@ +2003-09-03 DJ Delorie + + * targhooks.c: New file. + * targhooks.h: New file. + * Makefile.in: Add targhooks.o support. + (function.o): Depend on$(TARGET_H). + (stmt.o): Likewise. + (combine.o): Depend on $(TREE_H) and $(TARGET_H). + * builtins.c (apply_args_size, expand_builtin_apply_args_1, + expand_builtin_apply): Convert to calls.struct_value_rtx hook. + (expand_builtin_saveregs): Convert to + calls.expand_builtin_saveregs hook. + * c-decl.c (start_decl): Handle new calls.promote_prototypes hook + here, instead of ... + (get_parm_info) ... here. + (store_parm_decls_oldstyle): Convert to calls.promote_prototypes + hook. + (finish_function): Handle calls.promote_prototypes hook here too. + * c-typeck.c (convert_arguments): Convert to + calls.promote_prototypes hook. + (c_convert_parm_for_inlining): Likewise. + * calls.c (initialize_argument_information): Convert to + calls.promote_function_args hook. + (expand_call): Convert to calls.struct_value_rtx, + calls.strict_argument_naming, + calls.pretend_outgoing_varargs_named, and + calls.promote_function_return hooks. Pass fndecl to + aggregate_value_p. Initialize CUMULATIVE_ARGS before calling + hooks, so they can use that. + (emit_library_call_value_1): Likewise. + * combine.c (setup_incoming_promotions): Convert to + calls.promote_function_args hook. + * emit-rtl.c: Convert to calls.struct_value_rtx hook. + * expr.c (expand_assignment): Pass call to aggregate_value_p. + (expand_expr): Likewise. + * expr.h: Remove support for SETUP_INCOMING_VARARGS, + STRICT_ARGUMENT_NAMING, PRETEND_OUTGOING_VARARGS_NAMED, + RETURN_IN_MEMORY macro defaults. + * final.c (profile_function): Convert to calls.struct_value_rtx + hook. + * function.c (aggregate_value_p): Accept function type tree as + second parameter; try to deduce fntype from it. Convert to + calls.return_in_memory hook. + (assign_parms): Convert to calls.setup_incoming_varargs, + calls.strict_argument_naming, calls.promote_function_args, + calls.pretend_outgoing_varargs_named hooks. Pass fndecl to + aggregate_value_p. + (expand_function_start): Likewise. Convert to + calls.struct_value_rtx hook. + (expand_function_end): Convert to calls.promote_function_return hook. + (allocate_struct_function): Pass fndecl to aggregate_value_p. + * hard-reg-set.h: Update comments to new hook names. + * integrate.c (expand_inline_function): Pass fndecl to aggregate_value_p. + * reg-stack.c (stack_result): Likewise. + * rtl.h (struct_value_rtx, struct_value_incoming_rtx): Delete. + * stmt.c (expand_value_return): Convert to + calls.promote_function_return hook. + * target-def.h: Add TARGET_PROMOTE_FUNCTION_ARGS, + TARGET_PROMOTE_FUNCTION_RETURN, TARGET_PROMOTE_PROTOTYPES, + TARGET_STRUCT_VALUE_RTX, TARGET_RETURN_IN_MEMORY, + TARGET_EXPAND_BUILTIN_SAVEREGS, TARGET_SETUP_INCOMING_VARARGS, + TARGET_STRICT_ARGUMENT_NAMING, + TARGET_PRETEND_OUTGOING_VARARGS_NAMED, and TARGET_CALLS. + * target.h: Likewise. + * tree.h (aggregate_value_p): Also takes a tree to deduce function + attributes from (for target hooks). + * doc/tm.texi (PROMOTE_FUNCTION_ARGS, PROMOTE_FUNCTION_RETURN, + PROMOTE_PROTOTYPES, RETURN_IN_MEMORY, STRUCT_VALUE_REGNUM, + STRUCT_VALUE, STRUCT_VALUE_INCOMING_REGNUM, STRUCT_VALUE_INCOMING, + EXPAND_BUILTIN_SAVEREGS, SETUP_INCOMING_VARARGS, + STRICT_ARGUMENT_NAMING, PRETEND_OUTGOING_VARARGS_NAMED): Convert + to hooks. + + * config/alpha/alpha.c (alpha_output_mi_thunk_osf): Pass function + to aggregate_value_p. + * config/arm/arm.c (arm_init_cumulative_args, + arm_output_mi_thunk): Likewise. + * config/i386/i386.c (ix86_return_pops_args, x86_this_parameter): + Likewise. + * config/mips/mips.c (mips_save_reg_p, mips_expand_prologue, + mips_can_use_return_insn): Likewise. + * config/rs6000/rs6000.c (rs6000_output_mi_thunk): Likewise. + * config/s390/s390.c (s390_output_mi_thunk): Likewise. + * config/sparc/sparc.c (sparc_output_mi_thunk): Pass function to + aggregate_value_p. + * config/story16/stormy16.c (xstormy16_asm_output_mi_thunk): Pass + function to aggregate_value_p. + * objc/objc-act.c (generate_struct_by_value_array): Pass NULL to + aggregate_value_p. + + * config/sh/sh-protos.h (sh_builtin_saveregs): Remove. + (sh_attr_renesas_p, sh_cfun_attr_renesas_p, sh_function_arg, + sh_function_arg_advance, sh_pass_in_reg_p): New. * config/sh/sh.c + (sh_handle_renesas_attribute, sh_promote_prototypes, + sh_struct_value_rtx, sh_return_in_memory, sh_builtin_saveregs, + sh_setup_incoming_varargs, sh_strict_argument_naming, + sh_pretend_outgoing_varargs_named): New decls. + (targetm): Add new hooks. + (calc_live_regs): Save MACL and MACH if the function has the + renesas attribute. + (sh_expand_prologue): Support renesas attribute. + (sh_builtin_saveregs): Make static. + (sh_build_va_list): Support renesas attribute. + (sh_va_start): Likewise. + (sh_va_arg): Likewise. + (sh_promote_prototypes): New. + (sh_function_arg): New, moved from sh.h. Support renesas + attribute. + (sh_function_arg_advance): Likewise. + (sh_return_in_memory): Likewise. + (sh_strict_argument_naming): Likewise. + (sh_pretend_outgoing_varargs_named): Likewise. + (sh_struct_value_rtx): New. + (sh_attribute): Add renesas attribute. + (sh_handle_renesas_attribute): New. + (sh_attr_renesas_p, sh_cfun_attr_renesas_p): New. + (sh_ms_bitfield_layout_p): Support renesas attribute also. + (sh_output_mi_thunk): Pass function to aggregate_value_p. * + config/sh/sh.h (TARGET_SWITCHES): Add -mrenesas as an alias for + -mhitachi. + (STRUCT_VALUE_REGNUM, STRUCT_VALUE, RETURN_IN_MEMORY): Moved to + target hooks. + (sh_args): Add renesas_abi flag. + (INIT_CUMULATIVE_ARGS): Set it. Pass fndecl to aggregate_value_p. + (FUNCTION_ARG_ADVANCE, FUNCTION_ARG): Move to sh.c. + (PASS_IN_REG_P): Support renesas attribute. Pass DF and TF on the + stack for the renesas abi. + (STRICT_ARGUMENT_NAMING, PRETEND_OUTGOING_VARARGS_NAMED, + SETUP_INCOMING_VARARGS, EXPAND_BUILTIN_SAVEREGS, + PROMOTE_PROTOTYPES): Moved to sh.c. * config/sh/sh.md (call): Set + call cookie to indicate renesas calls. + 2003-09-03 Mostafa Hagog * gcse.c (replace_one_set): New function. diff --git a/gcc/Makefile.in b/gcc/Makefile.in index b6dd4eedf2e..672e09ac0f0 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -844,7 +844,7 @@ OBJS-common = \ reload.o reload1.o reorg.o resource.o rtl.o rtlanal.o rtl-error.o \ sbitmap.o sched-deps.o sched-ebb.o sched-rgn.o sched-vis.o sdbout.o \ sibcall.o simplify-rtx.o sreal.o ssa.o ssa-ccp.o ssa-dce.o stmt.o \ - stor-layout.o stringpool.o timevar.o toplev.o tracer.o tree.o tree-dump.o \ + stor-layout.o stringpool.o targhooks.o timevar.o toplev.o tracer.o tree.o tree-dump.o \ unroll.o varasm.o varray.o version.o vmsdbgout.o xcoffout.o \ alloc-pool.o et-forest.o cfghooks.o bt-load.o pretty-print.o $(GGC) @@ -1488,6 +1488,9 @@ diagnostic.o : diagnostic.c $(DIAGNOSTIC_H) real.h \ opts.o : opts.c opts.h options.h toplev.h $(CONFIG_H) $(SYSTEM_H) \ coretypes.h $(TREE_H) $(TM_H) $(LANGHOOKS_H) $(GGC_H) $(RTL_H) \ output.h $(DIAGNOSTIC_H) $(TM_P_H) $(INSN_ATTR_H) intl.h +targhooks.o : targhooks.c targhooks.h $(CONFIG_H) $(SYSTEM_H) \ + coretypes.h $(TREE_H) $(TM_H) $(RTL_H) $(TM_P_H) function.h toplev.h + toplev.o : toplev.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) $(RTL_H) \ function.h flags.h xcoffout.h input.h $(INSN_ATTR_H) output.h $(DIAGNOSTIC_H) \ debug.h insn-config.h intl.h $(RECOG_H) Makefile toplev.h \ @@ -1526,11 +1529,11 @@ varasm.o : varasm.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) $(RTL_ function.o : function.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(TREE_H) \ flags.h function.h $(EXPR_H) $(OPTABS_H) libfuncs.h $(REGS_H) hard-reg-set.h \ insn-config.h $(RECOG_H) output.h toplev.h except.h $(HASHTAB_H) $(GGC_H) \ - $(TM_P_H) langhooks.h gt-function.h + $(TM_P_H) langhooks.h gt-function.h $(TARGET_H) stmt.o : stmt.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(TREE_H) flags.h \ function.h insn-config.h hard-reg-set.h $(EXPR_H) libfuncs.h except.h \ $(LOOP_H) $(RECOG_H) toplev.h output.h varray.h $(GGC_H) $(TM_P_H) \ - langhooks.h $(PREDICT_H) gt-stmt.h $(OPTABS_H) + langhooks.h $(PREDICT_H) gt-stmt.h $(OPTABS_H) $(TARGET_H) except.o : except.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(TREE_H) \ flags.h except.h function.h $(EXPR_H) libfuncs.h $(INTEGRATE_H) langhooks.h \ insn-config.h hard-reg-set.h $(BASIC_BLOCK_H) output.h \ @@ -1696,7 +1699,7 @@ dominance.o : dominance.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ et-forest.o : et-forest.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) et-forest.h alloc-pool.h combine.o : combine.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) flags.h \ function.h insn-config.h $(INSN_ATTR_H) $(REGS_H) $(EXPR_H) \ - $(BASIC_BLOCK_H) $(RECOG_H) real.h hard-reg-set.h toplev.h $(TM_P_H) + $(BASIC_BLOCK_H) $(RECOG_H) real.h hard-reg-set.h toplev.h $(TM_P_H) $(TREE_H) $(TARGET_H) regclass.o : regclass.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ hard-reg-set.h flags.h $(BASIC_BLOCK_H) $(REGS_H) insn-config.h $(RECOG_H) reload.h \ real.h toplev.h function.h output.h $(GGC_H) $(TM_P_H) $(EXPR_H) $(TIMEVAR_H) diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog index 9efeeb85ffb..ae7a1de3aea 100644 --- a/gcc/ada/ChangeLog +++ b/gcc/ada/ChangeLog @@ -1,3 +1,8 @@ +2003-09-03 DJ Delorie + + * misc.c (default_pass_by_ref): Convert to calls.return_in_memory + hook. + 2003-08-30 Zack Weinberg * Makefile.in: Update substitutions to match changes to diff --git a/gcc/ada/misc.c b/gcc/ada/misc.c index 60232bf5997..f4407e5a35d 100644 --- a/gcc/ada/misc.c +++ b/gcc/ada/misc.c @@ -7,7 +7,7 @@ * C Implementation File * * * * * - * Copyright (C) 1992-2002 Free Software Foundation, Inc. * + * Copyright (C) 1992-2003 Free Software Foundation, Inc. * * * * GNAT is free software; you can redistribute it and/or modify it under * * terms of the GNU General Public License as published by the Free Soft- * @@ -796,7 +796,7 @@ default_pass_by_ref (gnu_type) || FUNCTION_ARG_PASS_BY_REFERENCE (cum, TYPE_MODE (gnu_type), gnu_type, 1) #endif - || RETURN_IN_MEMORY (gnu_type) + || targetm.calls.return_in_memory (gnu_type, NULL_TREE) || (AGGREGATE_TYPE_P (gnu_type) && (! host_integerp (TYPE_SIZE (gnu_type), 1) || 0 < compare_tree_int (TYPE_SIZE (gnu_type), diff --git a/gcc/builtins.c b/gcc/builtins.c index c63d812d90f..6fa03503a9e 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -941,7 +941,7 @@ apply_args_size (void) /* The second value is the structure value address unless this is passed as an "invisible" first argument. */ - if (struct_value_rtx) + if (targetm.calls.struct_value_rtx (TREE_TYPE (cfun->decl), 0)) size += GET_MODE_SIZE (Pmode); for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) @@ -1116,6 +1116,7 @@ expand_builtin_apply_args_1 (void) rtx registers; int size, align, regno; enum machine_mode mode; + rtx struct_incoming_value = targetm.calls.struct_value_rtx (TREE_TYPE (cfun->decl), 1); /* Create a block where the arg-pointer, structure value address, and argument registers can be saved. */ @@ -1123,7 +1124,7 @@ expand_builtin_apply_args_1 (void) /* Walk past the arg-pointer and structure value address. */ size = GET_MODE_SIZE (Pmode); - if (struct_value_rtx) + if (targetm.calls.struct_value_rtx (TREE_TYPE (cfun->decl), 0)) size += GET_MODE_SIZE (Pmode); /* Save each register used in calling a function to the block. */ @@ -1149,10 +1150,10 @@ expand_builtin_apply_args_1 (void) /* Save the structure value address unless this is passed as an "invisible" first argument. */ - if (struct_value_incoming_rtx) + if (struct_incoming_value) { emit_move_insn (adjust_address (registers, Pmode, size), - copy_to_reg (struct_value_incoming_rtx)); + copy_to_reg (struct_incoming_value)); size += GET_MODE_SIZE (Pmode); } @@ -1210,6 +1211,7 @@ expand_builtin_apply (rtx function, rtx arguments, rtx argsize) rtx incoming_args, result, reg, dest, src, call_insn; rtx old_stack_level = 0; rtx call_fusage = 0; + rtx struct_value = targetm.calls.struct_value_rtx (TREE_TYPE (cfun->decl), 0); #ifdef POINTERS_EXTEND_UNSIGNED if (GET_MODE (arguments) != Pmode) @@ -1263,7 +1265,7 @@ expand_builtin_apply (rtx function, rtx arguments, rtx argsize) /* Walk past the arg-pointer and structure value address. */ size = GET_MODE_SIZE (Pmode); - if (struct_value_rtx) + if (struct_value) size += GET_MODE_SIZE (Pmode); /* Restore each of the registers previously saved. Make USE insns @@ -1283,13 +1285,13 @@ expand_builtin_apply (rtx function, rtx arguments, rtx argsize) /* Restore the structure value address unless this is passed as an "invisible" first argument. */ size = GET_MODE_SIZE (Pmode); - if (struct_value_rtx) + if (struct_value) { rtx value = gen_reg_rtx (Pmode); emit_move_insn (value, adjust_address (arguments, Pmode, size)); - emit_move_insn (struct_value_rtx, value); - if (GET_CODE (struct_value_rtx) == REG) - use_reg (&call_fusage, struct_value_rtx); + emit_move_insn (struct_value, value); + if (GET_CODE (struct_value) == REG) + use_reg (&call_fusage, struct_value); size += GET_MODE_SIZE (Pmode); } @@ -3728,21 +3730,8 @@ expand_builtin_saveregs (void) start_sequence (); -#ifdef EXPAND_BUILTIN_SAVEREGS /* Do whatever the machine needs done in this case. */ - val = EXPAND_BUILTIN_SAVEREGS (); -#else - /* ??? We used to try and build up a call to the out of line function, - guessing about what registers needed saving etc. This became much - harder with __builtin_va_start, since we don't have a tree for a - call to __builtin_saveregs to fall back on. There was exactly one - port (i860) that used this code, and I'm unconvinced it could actually - handle the general case. So we no longer try to handle anything - weird and make the backend absorb the evil. */ - - error ("__builtin_saveregs not supported by this target"); - val = const0_rtx; -#endif + val = targetm.calls.expand_builtin_saveregs (); seq = get_insns (); end_sequence (); diff --git a/gcc/c-decl.c b/gcc/c-decl.c index 31212ff42c5..f16fe7cd2f6 100644 --- a/gcc/c-decl.c +++ b/gcc/c-decl.c @@ -2673,6 +2673,26 @@ start_decl (tree declarator, tree declspecs, int initialized, tree attributes) decl_attributes (&decl, attributes, 0); if (TREE_CODE (decl) == FUNCTION_DECL + && targetm.calls.promote_prototypes (TREE_TYPE (decl))) + { + tree ce = declarator; + + if (TREE_CODE (ce) == INDIRECT_REF) + ce = TREE_OPERAND (declarator, 0); + if (TREE_CODE (ce) == CALL_EXPR) + { + tree args = TREE_PURPOSE (TREE_OPERAND (ce, 1)); + for (; args; args = TREE_CHAIN (args)) + { + tree type = TREE_TYPE (args); + if (INTEGRAL_TYPE_P (type) + && TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node)) + DECL_ARG_TYPE (args) = integer_type_node; + } + } + } + + if (TREE_CODE (decl) == FUNCTION_DECL && DECL_DECLARED_INLINE_P (decl) && DECL_UNINLINABLE (decl) && lookup_attribute ("noinline", DECL_ATTRIBUTES (decl))) @@ -4574,10 +4594,6 @@ get_parm_info (int void_at_end) declared types. The back end may override this. */ type = TREE_TYPE (decl); DECL_ARG_TYPE (decl) = type; - if (PROMOTE_PROTOTYPES - && INTEGRAL_TYPE_P (type) - && TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node)) - DECL_ARG_TYPE (decl) = integer_type_node; /* Check for (..., void, ...) and issue an error. */ if (VOID_TYPE_P (type) && !DECL_NAME (decl) && !gave_void_only_once_err) @@ -5899,7 +5915,7 @@ store_parm_decls_oldstyle (void) useful for argument types like uid_t. */ DECL_ARG_TYPE (parm) = TREE_TYPE (parm); - if (PROMOTE_PROTOTYPES + if (targetm.calls.promote_prototypes (TREE_TYPE (current_function_decl)) && INTEGRAL_TYPE_P (TREE_TYPE (parm)) && TYPE_PRECISION (TREE_TYPE (parm)) < TYPE_PRECISION (integer_type_node)) @@ -6051,6 +6067,19 @@ finish_function () poplevel (0, 0, 0); } + if (TREE_CODE (fndecl) == FUNCTION_DECL + && targetm.calls.promote_prototypes (TREE_TYPE (fndecl))) + { + tree args = DECL_ARGUMENTS (fndecl); + for (; args; args = TREE_CHAIN (args)) + { + tree type = TREE_TYPE (args); + if (INTEGRAL_TYPE_P (type) + && TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node)) + DECL_ARG_TYPE (args) = integer_type_node; + } + } + BLOCK_SUPERCONTEXT (DECL_INITIAL (fndecl)) = fndecl; /* Must mark the RESULT_DECL as being in this function. */ diff --git a/gcc/c-typeck.c b/gcc/c-typeck.c index 1d5823c131f..23e73e87982 100644 --- a/gcc/c-typeck.c +++ b/gcc/c-typeck.c @@ -1866,7 +1866,7 @@ convert_arguments (tree typelist, tree values, tree name, tree fundecl) (char *) 0, /* arg passing */ fundecl, name, parmnum + 1); - if (PROMOTE_PROTOTYPES + if (targetm.calls.promote_prototypes (fundecl ? TREE_TYPE (fundecl) : 0) && INTEGRAL_TYPE_P (type) && (TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node))) parmval = default_conversion (parmval); @@ -3615,7 +3615,7 @@ c_convert_parm_for_inlining (tree parm, tree value, tree fn) ret = convert_for_assignment (type, value, (char *) 0 /* arg passing */, fn, DECL_NAME (fn), 0); - if (PROMOTE_PROTOTYPES + if (targetm.calls.promote_prototypes (TREE_TYPE (fn)) && INTEGRAL_TYPE_P (type) && (TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node))) ret = default_conversion (ret); diff --git a/gcc/calls.c b/gcc/calls.c index 50fa592972a..dc3da0a9174 100644 --- a/gcc/calls.c +++ b/gcc/calls.c @@ -1,5 +1,5 @@ /* Convert function calls to rtl insns, for GNU C compiler. - Copyright (C) 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998 + Copyright (C) 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. This file is part of GCC. @@ -1177,9 +1177,8 @@ initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED, mode = TYPE_MODE (type); unsignedp = TREE_UNSIGNED (type); -#ifdef PROMOTE_FUNCTION_ARGS - mode = promote_mode (type, mode, &unsignedp, 1); -#endif + if (targetm.calls.promote_function_args (fndecl ? TREE_TYPE (fndecl) : 0)) + mode = promote_mode (type, mode, &unsignedp, 1); args[i].unsignedp = unsignedp; args[i].mode = mode; @@ -2060,6 +2059,7 @@ expand_call (tree exp, rtx target, int ignore) /* Nonzero if called function returns an aggregate in memory PCC style, by returning the address of where to find it. */ int pcc_struct_value = 0; + rtx struct_value = 0; /* Number of actual parameters in this call, including struct value addr. */ int num_actuals; @@ -2175,6 +2175,8 @@ expand_call (tree exp, rtx target, int ignore) else flags |= flags_from_decl_or_type (TREE_TYPE (TREE_TYPE (p))); + struct_value = targetm.calls.struct_value_rtx (fndecl ? TREE_TYPE (fndecl) : 0, 0); + /* Warn if this value is an aggregate type, regardless of which calling convention we are using for it. */ if (warn_aggregate_return && AGGREGATE_TYPE_P (TREE_TYPE (exp))) @@ -2222,7 +2224,7 @@ expand_call (tree exp, rtx target, int ignore) /* Set up a place to return a structure. */ /* Cater to broken compilers. */ - if (aggregate_value_p (exp)) + if (aggregate_value_p (exp, fndecl)) { /* This call returns a big structure. */ flags &= ~(ECF_CONST | ECF_PURE | ECF_LIBCALL_BLOCK); @@ -2316,7 +2318,7 @@ expand_call (tree exp, rtx target, int ignore) /* If struct_value_rtx is 0, it means pass the address as if it were an extra parameter. */ - if (structure_value_addr && struct_value_rtx == 0) + if (structure_value_addr && struct_value == 0) { /* If structure_value_addr is a REG other than virtual_outgoing_args_rtx, we can use always use it. If it @@ -2342,6 +2344,14 @@ expand_call (tree exp, rtx target, int ignore) for (p = actparms, num_actuals = 0; p; p = TREE_CHAIN (p)) num_actuals++; + /* Start updating where the next arg would go. + + On some machines (such as the PA) indirect calls have a difuferent + calling convention than normal calls. The last argument in + INIT_CUMULATIVE_ARGS tells the backend if this is an indirect call + or not. */ + INIT_CUMULATIVE_ARGS (args_so_far, funtype, NULL_RTX, fndecl); + /* Compute number of named args. Normally, don't include the last named arg if anonymous args follow. We do include the last named arg if STRICT_ARGUMENT_NAMING is nonzero. @@ -2358,27 +2368,19 @@ expand_call (tree exp, rtx target, int ignore) reliable way to pass unnamed args in registers, so we must force them into memory. */ - if ((STRICT_ARGUMENT_NAMING - || ! PRETEND_OUTGOING_VARARGS_NAMED) + if ((targetm.calls.strict_argument_naming (&args_so_far) + || ! targetm.calls.pretend_outgoing_varargs_named (&args_so_far)) && type_arg_types != 0) n_named_args = (list_length (type_arg_types) /* Don't include the last named arg. */ - - (STRICT_ARGUMENT_NAMING ? 0 : 1) + - (targetm.calls.strict_argument_naming (&args_so_far) ? 0 : 1) /* Count the struct value address, if it is passed as a parm. */ + structure_value_addr_parm); else /* If we know nothing, treat all args as named. */ n_named_args = num_actuals; - /* Start updating where the next arg would go. - - On some machines (such as the PA) indirect calls have a different - calling convention than normal calls. The last argument in - INIT_CUMULATIVE_ARGS tells the backend if this is an indirect call - or not. */ - INIT_CUMULATIVE_ARGS (args_so_far, funtype, NULL_RTX, fndecl); - /* Make a vector to hold all the information about each arg. */ args = alloca (num_actuals * sizeof (struct arg_data)); memset (args, 0, num_actuals * sizeof (struct arg_data)); @@ -3016,13 +3018,13 @@ expand_call (tree exp, rtx target, int ignore) structure_value_addr = convert_memory_address (Pmode, structure_value_addr); #endif - emit_move_insn (struct_value_rtx, + emit_move_insn (struct_value, force_reg (Pmode, force_operand (structure_value_addr, NULL_RTX))); - if (GET_CODE (struct_value_rtx) == REG) - use_reg (&call_fusage, struct_value_rtx); + if (GET_CODE (struct_value) == REG) + use_reg (&call_fusage, struct_value); } funexp = prepare_call_address (funexp, fndecl, &call_fusage, @@ -3246,7 +3248,8 @@ expand_call (tree exp, rtx target, int ignore) else target = copy_to_reg (valreg); -#ifdef PROMOTE_FUNCTION_RETURN + if (targetm.calls.promote_function_return(funtype)) + { /* If we promoted this return value, make the proper SUBREG. TARGET might be const0_rtx here, so be careful. */ if (GET_CODE (target) == REG @@ -3277,7 +3280,7 @@ expand_call (tree exp, rtx target, int ignore) SUBREG_PROMOTED_VAR_P (target) = 1; SUBREG_PROMOTED_UNSIGNED_SET (target, unsignedp); } -#endif + } /* If size of args is variable or this was a constructor call for a stack argument, restore saved stack-pointer value. */ @@ -3586,6 +3589,8 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value, int initial_highest_arg_in_use = highest_outgoing_arg_in_use; char *initial_stack_usage_map = stack_usage_map; + rtx struct_value = targetm.calls.struct_value_rtx (0, 0); + #ifdef REG_PARM_STACK_SPACE #ifdef MAYBE_REG_PARM_STACK_SPACE reg_parm_stack_space = MAYBE_REG_PARM_STACK_SPACE; @@ -3638,7 +3643,7 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value, if (outmode != VOIDmode) { tfom = (*lang_hooks.types.type_for_mode) (outmode, 0); - if (aggregate_value_p (tfom)) + if (aggregate_value_p (tfom, 0)) { #ifdef PCC_STATIC_STRUCT_RETURN rtx pointer_reg @@ -3693,7 +3698,7 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value, /* If there's a structure value address to be passed, either pass it in the special place, or pass it as an extra argument. */ - if (mem_value && struct_value_rtx == 0 && ! pcc_struct_value) + if (mem_value && struct_value == 0 && ! pcc_struct_value) { rtx addr = XEXP (mem_value, 0); nargs++; @@ -4068,14 +4073,14 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value, } /* Pass the function the address in which to return a structure value. */ - if (mem_value != 0 && struct_value_rtx != 0 && ! pcc_struct_value) + if (mem_value != 0 && struct_value != 0 && ! pcc_struct_value) { - emit_move_insn (struct_value_rtx, + emit_move_insn (struct_value, force_reg (Pmode, force_operand (XEXP (mem_value, 0), NULL_RTX))); - if (GET_CODE (struct_value_rtx) == REG) - use_reg (&call_fusage, struct_value_rtx); + if (GET_CODE (struct_value) == REG) + use_reg (&call_fusage, struct_value); } /* Don't allow popping to be deferred, since then diff --git a/gcc/combine.c b/gcc/combine.c index cc7c7de156e..26cdf49dc78 100644 --- a/gcc/combine.c +++ b/gcc/combine.c @@ -75,6 +75,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "coretypes.h" #include "tm.h" #include "rtl.h" +#include "tree.h" #include "tm_p.h" #include "flags.h" #include "regs.h" @@ -88,6 +89,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "recog.h" #include "real.h" #include "toplev.h" +#include "target.h" /* It is not safe to use ordinary gen_lowpart in combine. Use gen_lowpart_for_combine instead. See comments there. */ @@ -799,30 +801,31 @@ init_reg_last_arrays (void) static void setup_incoming_promotions (void) { -#ifdef PROMOTE_FUNCTION_ARGS unsigned int regno; rtx reg; enum machine_mode mode; int unsignedp; rtx first = get_insns (); + if (targetm.calls.promote_function_args (TREE_TYPE (cfun->decl))) + { #ifndef OUTGOING_REGNO #define OUTGOING_REGNO(N) N #endif - for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) - /* Check whether this register can hold an incoming pointer - argument. FUNCTION_ARG_REGNO_P tests outgoing register - numbers, so translate if necessary due to register windows. */ - if (FUNCTION_ARG_REGNO_P (OUTGOING_REGNO (regno)) - && (reg = promoted_input_arg (regno, &mode, &unsignedp)) != 0) - { - record_value_for_reg - (reg, first, gen_rtx_fmt_e ((unsignedp ? ZERO_EXTEND - : SIGN_EXTEND), - GET_MODE (reg), - gen_rtx_CLOBBER (mode, const0_rtx))); - } -#endif + for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) + /* Check whether this register can hold an incoming pointer + argument. FUNCTION_ARG_REGNO_P tests outgoing register + numbers, so translate if necessary due to register windows. */ + if (FUNCTION_ARG_REGNO_P (OUTGOING_REGNO (regno)) + && (reg = promoted_input_arg (regno, &mode, &unsignedp)) != 0) + { + record_value_for_reg + (reg, first, gen_rtx_fmt_e ((unsignedp ? ZERO_EXTEND + : SIGN_EXTEND), + GET_MODE (reg), + gen_rtx_CLOBBER (mode, const0_rtx))); + } + } } /* Called via note_stores. If X is a pseudo that is narrower than diff --git a/gcc/config/alpha/alpha.c b/gcc/config/alpha/alpha.c index 92fe830b2d1..72d01af2f15 100644 --- a/gcc/config/alpha/alpha.c +++ b/gcc/config/alpha/alpha.c @@ -7799,7 +7799,7 @@ alpha_output_mi_thunk_osf (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED, /* Find the "this" pointer. If the function returns a structure, the structure return pointer is in $16. */ - if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)))) + if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function)) this = gen_rtx_REG (Pmode, 17); else this = gen_rtx_REG (Pmode, 16); diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c index 747b93115df..5e92b28b79b 100644 --- a/gcc/config/arm/arm.c +++ b/gcc/config/arm/arm.c @@ -1968,7 +1968,7 @@ arm_init_cumulative_args (CUMULATIVE_ARGS *pcum, tree fntype, tree fndecl ATTRIBUTE_UNUSED) { /* On the ARM, the offset starts at 0. */ - pcum->nregs = ((fntype && aggregate_value_p (TREE_TYPE (fntype))) ? 1 : 0); + pcum->nregs = ((fntype && aggregate_value_p (TREE_TYPE (fntype), fntype)) ? 1 : 0); pcum->iwmmxt_nregs = 0; pcum->call_cookie = CALL_NORMAL; @@ -12962,7 +12962,7 @@ arm_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED, int mi_delta = delta; const char *const mi_op = mi_delta < 0 ? "sub" : "add"; int shift = 0; - int this_regno = (aggregate_value_p (TREE_TYPE (TREE_TYPE (function))) + int this_regno = (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function) ? 1 : 0); if (mi_delta < 0) mi_delta = - mi_delta; diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index 4984fc4f9cf..bccbae9bb3c 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -1748,7 +1748,7 @@ ix86_return_pops_args (tree fundecl, tree funtype, int size) } /* Lose any fake structure return argument if it is passed on the stack. */ - if (aggregate_value_p (TREE_TYPE (funtype)) + if (aggregate_value_p (TREE_TYPE (funtype), fundecl) && !TARGET_64BIT) { int nregs = ix86_function_regparm (funtype, fundecl); @@ -15150,7 +15150,7 @@ x86_this_parameter (tree function) if (TARGET_64BIT) { - int n = aggregate_value_p (TREE_TYPE (type)) != 0; + int n = aggregate_value_p (TREE_TYPE (type), type) != 0; return gen_rtx_REG (DImode, x86_64_int_parameter_registers[n]); } @@ -15174,7 +15174,7 @@ x86_this_parameter (tree function) } } - if (aggregate_value_p (TREE_TYPE (type))) + if (aggregate_value_p (TREE_TYPE (type), type)) return gen_rtx_MEM (SImode, plus_constant (stack_pointer_rtx, 8)); else return gen_rtx_MEM (SImode, plus_constant (stack_pointer_rtx, 4)); diff --git a/gcc/config/i960/i960.c b/gcc/config/i960/i960.c index cb44ee3efe7..26443223ddc 100644 --- a/gcc/config/i960/i960.c +++ b/gcc/config/i960/i960.c @@ -1086,7 +1086,7 @@ i960_function_name_declare (file, name, fndecl) /* See if caller passes in an address to return value. */ - if (aggregate_value_p (DECL_RESULT (fndecl))) + if (aggregate_value_p (DECL_RESULT (fndecl), fndecl)) { tail_call_ok = 0; leaf_proc_ok = 0; diff --git a/gcc/config/m68hc11/m68hc11.c b/gcc/config/m68hc11/m68hc11.c index 38690ee7319..2787ce11649 100644 --- a/gcc/config/m68hc11/m68hc11.c +++ b/gcc/config/m68hc11/m68hc11.c @@ -1490,7 +1490,7 @@ m68hc11_init_cumulative_args (cum, fntype, libname) ret_type = TREE_TYPE (fntype); - if (ret_type && aggregate_value_p (ret_type)) + if (ret_type && aggregate_value_p (ret_type, fntype)) { cum->words = 1; cum->nregs = 1; diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c index 74539249fab..7fa4ad80ebd 100644 --- a/gcc/config/mips/mips.c +++ b/gcc/config/mips/mips.c @@ -5933,7 +5933,7 @@ mips_save_reg_p (unsigned int regno) if (regno == GP_REG_FIRST + 31 && mips16_hard_float && !mips_entry - && !aggregate_value_p (return_type) + && !aggregate_value_p (return_type, current_function_decl) && GET_MODE_CLASS (DECL_MODE (return_type)) == MODE_FLOAT && GET_MODE_SIZE (DECL_MODE (return_type)) <= UNITS_PER_FPVALUE) return true; @@ -6712,7 +6712,7 @@ mips_expand_prologue (void) REGNO (pic_offset_table_rtx) = cfun->machine->global_pointer; /* If struct value address is treated as the first argument, make it so. */ - if (aggregate_value_p (DECL_RESULT (fndecl)) + if (aggregate_value_p (DECL_RESULT (fndecl), fndecl) && ! current_function_returns_pcc_struct && struct_value_incoming_rtx == 0) { @@ -7179,7 +7179,7 @@ mips_can_use_return_insn (void) registers. */ if (TARGET_MIPS16 && mips16_hard_float - && ! aggregate_value_p (return_type) + && ! aggregate_value_p (return_type, current_function_decl) && GET_MODE_CLASS (DECL_MODE (return_type)) == MODE_FLOAT && GET_MODE_SIZE (DECL_MODE (return_type)) <= UNITS_PER_FPVALUE) return 0; diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c index 6807511c3c8..378170ca79d 100644 --- a/gcc/config/rs6000/rs6000.c +++ b/gcc/config/rs6000/rs6000.c @@ -12430,7 +12430,7 @@ rs6000_output_mi_thunk (file, thunk_fndecl, delta, vcall_offset, function) /* Find the "this" pointer. If the function returns a structure, the structure return pointer is in r3. */ - if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)))) + if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function)) this = gen_rtx_REG (Pmode, 4); else this = gen_rtx_REG (Pmode, 3); diff --git a/gcc/config/s390/s390.c b/gcc/config/s390/s390.c index 4bdb40584ac..7086d5b6932 100644 --- a/gcc/config/s390/s390.c +++ b/gcc/config/s390/s390.c @@ -6629,7 +6629,7 @@ s390_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED, } /* Operand 1 is the 'this' pointer. */ - if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)))) + if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function)) op[1] = gen_rtx_REG (Pmode, 3); else op[1] = gen_rtx_REG (Pmode, 2); diff --git a/gcc/config/sh/sh-protos.h b/gcc/config/sh/sh-protos.h index e046206dc39..b87aecd0181 100644 --- a/gcc/config/sh/sh-protos.h +++ b/gcc/config/sh/sh-protos.h @@ -25,7 +25,6 @@ Boston, MA 02111-1307, USA. */ #define GCC_SH_PROTOS_H #ifdef RTX_CODE -extern struct rtx_def *sh_builtin_saveregs PARAMS ((void)); extern struct rtx_def *prepare_scc_operands PARAMS ((enum rtx_code)); /* Declare functions defined in sh.c and used in templates. */ @@ -121,6 +120,8 @@ extern int fldi_ok PARAMS ((void)); extern int sh_pr_n_sets PARAMS ((void)); extern int sh_hard_regno_rename_ok PARAMS ((unsigned int, unsigned int)); extern int sh_cfun_interrupt_handler_p PARAMS ((void)); +extern int sh_attr_renesas_p PARAMS ((tree)); +extern int sh_cfun_attr_renesas_p PARAMS ((void)); extern void sh_initialize_trampoline PARAMS ((rtx, rtx, rtx)); extern bool sh_cannot_change_mode_class PARAMS ((enum machine_mode, enum machine_mode, enum reg_class)); @@ -138,4 +139,8 @@ extern void sh_pr_nosave_low_regs PARAMS ((struct cpp_reader *)); extern rtx function_symbol (const char *); extern rtx sh_get_pr_initial_val (void); +extern rtx sh_function_arg (CUMULATIVE_ARGS *, enum machine_mode, tree, int); +extern void sh_function_arg_advance (CUMULATIVE_ARGS *, enum machine_mode, tree, int); +extern int sh_pass_in_reg_p (CUMULATIVE_ARGS *, enum machine_mode, tree); + #endif /* ! GCC_SH_PROTOS_H */ diff --git a/gcc/config/sh/sh.c b/gcc/config/sh/sh.c index 15d1d1a57dd..a266471b063 100644 --- a/gcc/config/sh/sh.c +++ b/gcc/config/sh/sh.c @@ -203,6 +203,7 @@ const struct attribute_spec sh_attribute_table[]; static tree sh_handle_interrupt_handler_attribute PARAMS ((tree *, tree, tree, int, bool *)); static tree sh_handle_sp_switch_attribute PARAMS ((tree *, tree, tree, int, bool *)); static tree sh_handle_trap_exit_attribute PARAMS ((tree *, tree, tree, int, bool *)); +static tree sh_handle_renesas_attribute PARAMS ((tree *, tree, tree, int, bool *)); static void sh_output_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT)); static void sh_insert_attributes PARAMS ((tree, tree *)); static int sh_adjust_cost PARAMS ((rtx, rtx, rtx, int)); @@ -238,6 +239,15 @@ static int scavenge_reg (HARD_REG_SET *s); struct save_schedule_s; static struct save_entry_s *sh5_schedule_saves (HARD_REG_SET *, struct save_schedule_s *, int); + +static bool sh_promote_prototypes PARAMS ((tree)); +static rtx sh_struct_value_rtx PARAMS ((tree, int)); +static bool sh_return_in_memory PARAMS ((tree, tree)); +static rtx sh_builtin_saveregs PARAMS ((void)); +static void sh_setup_incoming_varargs PARAMS ((CUMULATIVE_ARGS *, enum machine_mode, tree, int *, int)); +static bool sh_strict_argument_naming PARAMS ((CUMULATIVE_ARGS *)); +static bool sh_pretend_outgoing_varargs_named PARAMS ((CUMULATIVE_ARGS *)); + /* Initialize the GCC target structure. */ #undef TARGET_ATTRIBUTE_TABLE @@ -315,6 +325,27 @@ static struct save_entry_s *sh5_schedule_saves (HARD_REG_SET *, #define TARGET_HAVE_TLS true #endif +#undef TARGET_PROMOTE_PROTOTYPES +#define TARGET_PROMOTE_PROTOTYPES sh_promote_prototypes +#undef TARGET_PROMOTE_FUNCTION_ARGS +#define TARGET_PROMOTE_FUNCTION_ARGS sh_promote_prototypes +#undef TARGET_PROMOTE_FUNCTION_RETURN +#define TARGET_PROMOTE_FUNCTION_RETURN sh_promote_prototypes + +#undef TARGET_STRUCT_VALUE_RTX +#define TARGET_STRUCT_VALUE_RTX sh_struct_value_rtx +#undef TARGET_RETURN_IN_MEMORY +#define TARGET_RETURN_IN_MEMORY sh_return_in_memory + +#undef TARGET_EXPAND_BUILTIN_SAVEREGS +#define TARGET_EXPAND_BUILTIN_SAVEREGS sh_builtin_saveregs +#undef TARGET_SETUP_INCOMING_VARARGS +#define TARGET_SETUP_INCOMING_VARARGS sh_setup_incoming_varargs +#undef TARGET_STRICT_ARGUMENT_NAMING +#define TARGET_STRICT_ARGUMENT_NAMING sh_strict_argument_naming +#undef TARGET_PRETEND_OUTGOING_VARARGS_NAMED +#define TARGET_PRETEND_OUTGOING_VARARGS_NAMED sh_pretend_outgoing_varargs_named + struct gcc_target targetm = TARGET_INITIALIZER; /* Print the operand address in x to the stream. */ @@ -4898,7 +4929,11 @@ calc_live_regs (live_regs_mask) && (reg == (int) EH_RETURN_DATA_REGNO (0) || reg == (int) EH_RETURN_DATA_REGNO (1) || reg == (int) EH_RETURN_DATA_REGNO (2) - || reg == (int) EH_RETURN_DATA_REGNO (3))))) + || reg == (int) EH_RETURN_DATA_REGNO (3))) + || ((reg == MACL_REG || reg == MACH_REG) + && regs_ever_live[reg] + && sh_cfun_attr_renesas_p ()) + )) { SET_HARD_REG_BIT (*live_regs_mask, reg); count += GET_MODE_SIZE (REGISTER_NATURAL_MODE (reg)); @@ -5190,7 +5225,8 @@ sh_expand_prologue () if (current_function_stdarg) { /* This is not used by the SH2E calling convention */ - if (TARGET_SH1 && ! TARGET_SH2E && ! TARGET_SH5 && ! TARGET_HITACHI) + if (TARGET_SH1 && ! TARGET_SH2E && ! TARGET_SH5 + && ! (TARGET_HITACHI || sh_cfun_attr_renesas_p ())) { /* Push arg regs as if they'd been provided by caller in stack. */ for (i = 0; i < NPARM_REGS(SImode); i++) @@ -5822,7 +5858,7 @@ sh_output_function_epilogue (file, size) sp_switch = NULL_RTX; } -rtx +static rtx sh_builtin_saveregs () { /* First unnamed integer register. */ @@ -5972,7 +6008,8 @@ sh_build_va_list () tree f_next_o, f_next_o_limit, f_next_fp, f_next_fp_limit, f_next_stack; tree record; - if (TARGET_SH5 || (! TARGET_SH2E && ! TARGET_SH4) || TARGET_HITACHI) + if (TARGET_SH5 || (! TARGET_SH2E && ! TARGET_SH4) + || TARGET_HITACHI || sh_cfun_attr_renesas_p ()) return ptr_type_node; record = make_node (RECORD_TYPE); @@ -6026,7 +6063,8 @@ sh_va_start (valist, nextarg) return; } - if ((! TARGET_SH2E && ! TARGET_SH4) || TARGET_HITACHI) + if ((! TARGET_SH2E && ! TARGET_SH4) + || TARGET_HITACHI || sh_cfun_attr_renesas_p ()) { std_expand_builtin_va_start (valist, nextarg); return; @@ -6105,7 +6143,8 @@ sh_va_arg (valist, type) if (pass_by_ref) type = build_pointer_type (type); - if (! TARGET_SH5 && (TARGET_SH2E || TARGET_SH4) && ! TARGET_HITACHI) + if (! TARGET_SH5 && (TARGET_SH2E || TARGET_SH4) + && ! (TARGET_HITACHI || sh_cfun_attr_renesas_p ())) { tree f_next_o, f_next_o_limit, f_next_fp, f_next_fp_limit, f_next_stack; tree next_o, next_o_limit, next_fp, next_fp_limit, next_stack; @@ -6289,6 +6328,343 @@ sh_va_arg (valist, type) return result; } +static bool +sh_promote_prototypes (type) + tree type; +{ + if (TARGET_HITACHI) + return 0; + if (! type) + return 1; + return ! sh_attr_renesas_p (type); +} + +/* Define where to put the arguments to a function. + Value is zero to push the argument on the stack, + or a hard register in which to store the argument. + + MODE is the argument's machine mode. + TYPE is the data type of the argument (as a tree). + This is null for libcalls where that information may + not be available. + CUM is a variable of type CUMULATIVE_ARGS which gives info about + the preceding args and about the function being called. + NAMED is nonzero if this argument is a named parameter + (otherwise it is an extra parameter matching an ellipsis). + + On SH the first args are normally in registers + and the rest are pushed. Any arg that starts within the first + NPARM_REGS words is at least partially passed in a register unless + its data type forbids. */ + + +rtx +sh_function_arg (ca, mode, type, named) + CUMULATIVE_ARGS *ca; + enum machine_mode mode; + tree type; + int named; +{ + if (! TARGET_SH5 && mode == VOIDmode) + return GEN_INT (ca->renesas_abi ? 1 : 0); + + if (! TARGET_SH5 + && PASS_IN_REG_P (*ca, mode, type) + && (named || ! (TARGET_HITACHI || ca->renesas_abi))) + { + int regno; + + if (mode == SCmode && TARGET_SH4 && TARGET_LITTLE_ENDIAN + && (! FUNCTION_ARG_SCmode_WART || (ROUND_REG (*ca, mode) & 1))) + { + rtx r1 = gen_rtx_EXPR_LIST (VOIDmode, + gen_rtx_REG (SFmode, + BASE_ARG_REG (mode) + + (ROUND_REG (*ca, mode) ^ 1)), + const0_rtx); + rtx r2 = gen_rtx_EXPR_LIST(VOIDmode, + gen_rtx_REG (SFmode, + BASE_ARG_REG (mode) + + ((ROUND_REG (*ca, mode) + 1) ^ 1)), + GEN_INT (4)); + return gen_rtx_PARALLEL(SCmode, gen_rtvec(2, r1, r2)); + } + + /* If the alignment of a DF value causes an SF register to be + skipped, we will use that skipped register for the next SF + value. */ + if ((TARGET_HITACHI || ca->renesas_abi) + && ca->free_single_fp_reg + && mode == SFmode) + return gen_rtx_REG (mode, ca->free_single_fp_reg); + + regno = (BASE_ARG_REG (mode) + ROUND_REG (*ca, mode)) + ^ (mode == SFmode && TARGET_SH4 + && TARGET_LITTLE_ENDIAN != 0 + && ! TARGET_HITACHI && ! ca->renesas_abi); + return gen_rtx_REG (mode, regno); + + } + + if (TARGET_SH5) + { + if (mode == VOIDmode && TARGET_SHCOMPACT) + return GEN_INT (ca->call_cookie); + + /* The following test assumes unnamed arguments are promoted to + DFmode. */ + if (mode == SFmode && ca->free_single_fp_reg) + return SH5_PROTOTYPED_FLOAT_ARG (*ca, mode, ca->free_single_fp_reg); + + if ((GET_SH_ARG_CLASS (mode) == SH_ARG_FLOAT) + && (named || ! ca->prototype_p) + && ca->arg_count[(int) SH_ARG_FLOAT] < NPARM_REGS (SFmode)) + { + if (! ca->prototype_p && TARGET_SHMEDIA) + return SH5_PROTOTYPELESS_FLOAT_ARG (*ca, mode); + + return SH5_PROTOTYPED_FLOAT_ARG (*ca, mode, + FIRST_FP_PARM_REG + + ca->arg_count[(int) SH_ARG_FLOAT]); + } + + if (ca->arg_count[(int) SH_ARG_INT] < NPARM_REGS (SImode) + && (! TARGET_SHCOMPACT + || (! SHCOMPACT_FORCE_ON_STACK (mode, type) + && ! SH5_WOULD_BE_PARTIAL_NREGS (*ca, mode, + type, named)))) + { + return gen_rtx_REG (mode, (FIRST_PARM_REG + + ca->arg_count[(int) SH_ARG_INT])); + } + + return 0; + } + + return 0; +} + +/* Update the data in CUM to advance over an argument + of mode MODE and data type TYPE. + (TYPE is null for libcalls where that information may not be + available.) */ + +void +sh_function_arg_advance (ca, mode, type, named) + CUMULATIVE_ARGS *ca; + enum machine_mode mode; + tree type; + int named; +{ + if (ca->force_mem) + ca->force_mem = 0; + else if (TARGET_SH5) + { + tree type2 = (ca->byref && type + ? TREE_TYPE (type) + : type); + enum machine_mode mode2 = (ca->byref && type + ? TYPE_MODE (type2) + : mode); + int dwords = ((ca->byref + ? ca->byref + : mode2 == BLKmode + ? int_size_in_bytes (type2) + : GET_MODE_SIZE (mode2)) + 7) / 8; + int numregs = MIN (dwords, NPARM_REGS (SImode) + - ca->arg_count[(int) SH_ARG_INT]); + + if (numregs) + { + ca->arg_count[(int) SH_ARG_INT] += numregs; + if (TARGET_SHCOMPACT + && SHCOMPACT_FORCE_ON_STACK (mode2, type2)) + { + ca->call_cookie + |= CALL_COOKIE_INT_REG (ca->arg_count[(int) SH_ARG_INT] + - numregs, 1); + /* N.B. We want this also for outgoing. */ + ca->stack_regs += numregs; + } + else if (ca->byref) + { + if (! ca->outgoing) + ca->stack_regs += numregs; + ca->byref_regs += numregs; + ca->byref = 0; + do + ca->call_cookie + |= CALL_COOKIE_INT_REG (ca->arg_count[(int) SH_ARG_INT] + - numregs, 2); + while (--numregs); + ca->call_cookie + |= CALL_COOKIE_INT_REG (ca->arg_count[(int) SH_ARG_INT] + - 1, 1); + } + else if (dwords > numregs) + { + int pushregs = numregs; + + if (TARGET_SHCOMPACT) + ca->stack_regs += numregs; + while (pushregs < NPARM_REGS (SImode) - 1 + && (CALL_COOKIE_INT_REG_GET + (ca->call_cookie, + NPARM_REGS (SImode) - pushregs) + == 1)) + { + ca->call_cookie + &= ~ CALL_COOKIE_INT_REG (NPARM_REGS (SImode) + - pushregs, 1); + pushregs++; + } + if (numregs == NPARM_REGS (SImode)) + ca->call_cookie + |= CALL_COOKIE_INT_REG (0, 1) + | CALL_COOKIE_STACKSEQ (numregs - 1); + else + ca->call_cookie + |= CALL_COOKIE_STACKSEQ (numregs); + } + } + if (GET_SH_ARG_CLASS (mode2) == SH_ARG_FLOAT + && (named || ! ca->prototype_p)) + { + if (mode2 == SFmode && ca->free_single_fp_reg) + ca->free_single_fp_reg = 0; + else if (ca->arg_count[(int) SH_ARG_FLOAT] + < NPARM_REGS (SFmode)) + { + int numfpregs + = MIN ((GET_MODE_SIZE (mode2) + 7) / 8 * 2, + NPARM_REGS (SFmode) + - ca->arg_count[(int) SH_ARG_FLOAT]); + + ca->arg_count[(int) SH_ARG_FLOAT] += numfpregs; + + if (TARGET_SHCOMPACT && ! ca->prototype_p) + { + if (ca->outgoing && numregs > 0) + do + { + ca->call_cookie + |= (CALL_COOKIE_INT_REG + (ca->arg_count[(int) SH_ARG_INT] + - numregs + ((numfpregs - 2) / 2), + 4 + (ca->arg_count[(int) SH_ARG_FLOAT] + - numfpregs) / 2)); + } + while (numfpregs -= 2); + } + else if (mode2 == SFmode && (named) + && (ca->arg_count[(int) SH_ARG_FLOAT] + < NPARM_REGS (SFmode))) + ca->free_single_fp_reg + = FIRST_FP_PARM_REG - numfpregs + + ca->arg_count[(int) SH_ARG_FLOAT] + 1; + } + } + return; + } + + if ((TARGET_HITACHI || ca->renesas_abi) && TARGET_FPU_DOUBLE) + { + /* Note that we've used the skipped register. */ + if (mode == SFmode && ca->free_single_fp_reg) + { + ca->free_single_fp_reg = 0; + return; + } + /* When we have a DF after an SF, there's an SF register that get + skipped in order to align the DF value. We note this skipped + register, because the next SF value will use it, and not the + SF that follows the DF. */ + if (mode == DFmode + && ROUND_REG (*ca, DFmode) != ROUND_REG (*ca, SFmode)) + { + ca->free_single_fp_reg = (ROUND_REG (*ca, SFmode) + + BASE_ARG_REG (mode)); + } + } + + if (! (TARGET_SH4 || ca->renesas_abi) + || PASS_IN_REG_P (*ca, mode, type)) + (ca->arg_count[(int) GET_SH_ARG_CLASS (mode)] + = (ROUND_REG (*ca, mode) + + (mode == BLKmode + ? ROUND_ADVANCE (int_size_in_bytes (type)) + : ROUND_ADVANCE (GET_MODE_SIZE (mode))))); +} + +/* If the structure value address is not passed in a register, define + `STRUCT_VALUE' as an expression returning an RTX for the place + where the address is passed. If it returns 0, the address is + passed as an "invisible" first argument. */ +/* The Renesas calling convention doesn't quite fit into this scheme since + the address is passed like an invisible argument, but one that is always + passed in memory. */ +static rtx +sh_struct_value_rtx (fndecl, incoming) + tree fndecl; + int incoming ATTRIBUTE_UNUSED; +{ + if (TARGET_HITACHI || sh_attr_renesas_p (fndecl)) + return 0; + return gen_rtx_REG (Pmode, 2); +} + +static bool +sh_return_in_memory (type, fndecl) + tree type; + tree fndecl; +{ + if (TARGET_SH5) + { + if (TYPE_MODE (type) == BLKmode) + return ((unsigned HOST_WIDE_INT) int_size_in_bytes (type)) > 8; + else + return GET_MODE_SIZE (TYPE_MODE (type)) > 8; + } + else + { + return (TYPE_MODE (type) == BLKmode + || ((TARGET_HITACHI || sh_attr_renesas_p (fndecl)) + && TREE_CODE (type) == RECORD_TYPE)); + } +} + +/* We actually emit the code in sh_expand_prologue. We used to use + a static variable to flag that we need to emit this code, but that + doesn't when inlining, when functions are deferred and then emitted + later. Fortunately, we already have two flags that are part of struct + function that tell if a function uses varargs or stdarg. */ +static void +sh_setup_incoming_varargs (ca, mode, type, pretend_arg_size, second_time) + CUMULATIVE_ARGS *ca ATTRIBUTE_UNUSED; + enum machine_mode mode ATTRIBUTE_UNUSED; + tree type ATTRIBUTE_UNUSED; + int *pretend_arg_size ATTRIBUTE_UNUSED; + int second_time ATTRIBUTE_UNUSED; +{ + if (! current_function_stdarg) + abort (); +} + +static bool +sh_strict_argument_naming (ca) + CUMULATIVE_ARGS *ca ATTRIBUTE_UNUSED; +{ + return TARGET_SH5; +} + +static bool +sh_pretend_outgoing_varargs_named (ca) + CUMULATIVE_ARGS *ca; +{ + return ! (TARGET_HITACHI || ca->renesas_abi) && ! TARGET_SH5; +} + + /* Define the offset between two registers, one to be eliminated, and the other its replacement, at the start of a routine. */ @@ -6424,7 +6800,12 @@ sh_insert_attributes (node, attributes) to run on. trap_exit -- use a trapa to exit an interrupt function instead of - an rte instruction. */ + an rte instruction. + + renesas -- use Renesas calling/layout conventions (functions and + structures). + +*/ const struct attribute_spec sh_attribute_table[] = { @@ -6432,6 +6813,7 @@ const struct attribute_spec sh_attribute_table[] = { "interrupt_handler", 0, 0, true, false, false, sh_handle_interrupt_handler_attribute }, { "sp_switch", 1, 1, true, false, false, sh_handle_sp_switch_attribute }, { "trap_exit", 1, 1, true, false, false, sh_handle_trap_exit_attribute }, + { "renesas", 0, 0, false, true, false, sh_handle_renesas_attribute }, { NULL, 0, 0, false, false, false, NULL } }; @@ -6537,6 +6919,40 @@ sh_handle_trap_exit_attribute (node, name, args, flags, no_add_attrs) return NULL_TREE; } +static tree +sh_handle_renesas_attribute (node, name, args, flags, no_add_attrs) + tree *node ATTRIBUTE_UNUSED; + tree name ATTRIBUTE_UNUSED; + tree args ATTRIBUTE_UNUSED; + int flags ATTRIBUTE_UNUSED; + bool *no_add_attrs ATTRIBUTE_UNUSED; +{ + return NULL_TREE; +} + +/* True if __attribute__((renesas)) or -mrenesas. */ +int +sh_attr_renesas_p (td) + tree td; +{ + if (TARGET_HITACHI) + return 1; + if (td == 0) + return 0; + if (DECL_P (td)) + td = TREE_TYPE (td); + return (lookup_attribute ("renesas", TYPE_ATTRIBUTES (td)) + != NULL_TREE); +} + +/* True if __attribute__((renesas)) or -mrenesas, for the current + function. */ +int +sh_cfun_attr_renesas_p () +{ + return sh_attr_renesas_p (current_function_decl); +} + int sh_cfun_interrupt_handler_p () { @@ -8000,7 +8416,7 @@ static bool sh_ms_bitfield_layout_p (record_type) tree record_type ATTRIBUTE_UNUSED; { - return TARGET_SH5; + return (TARGET_SH5 || TARGET_HITACHI || sh_attr_renesas_p (record_type)); } /* @@ -8683,10 +9099,10 @@ sh_output_mi_thunk (file, thunk_fndecl, delta, vcall_offset, function) comes first, in which case "this" comes second. */ INIT_CUMULATIVE_ARGS (cum, funtype, NULL_RTX, 0); #ifndef PCC_STATIC_STRUCT_RETURN - if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)))) + if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function)) structure_value_byref = 1; #endif /* not PCC_STATIC_STRUCT_RETURN */ - if (structure_value_byref && struct_value_rtx == 0) + if (structure_value_byref && sh_struct_value_rtx (function, 0) == 0) { tree ptype = build_pointer_type (TREE_TYPE (funtype)); diff --git a/gcc/config/sh/sh.h b/gcc/config/sh/sh.h index 3ab2120e9a5..a3aa1dd29ae 100644 --- a/gcc/config/sh/sh.h +++ b/gcc/config/sh/sh.h @@ -319,6 +319,7 @@ extern int target_flags; {"dalign", DALIGN_BIT, "Aligns doubles at 64-bit boundaries" }, \ {"fmovd", FMOVD_BIT, "" }, \ {"hitachi", HITACHI_BIT, "Follow Renesas (formerly Hitachi) / SuperH calling conventions" }, \ + {"renesas", HITACHI_BIT, "Follow Renesas (formerly Hitachi) / SuperH calling conventions" }, \ {"nomacsave", NOMACSAVE_BIT, "Mark MAC register as call-clobbered" }, \ {"ieee", IEEE_BIT, "Increase the IEEE compliance for floating-point code" }, \ {"isize", ISIZE_BIT, "" }, \ @@ -1126,29 +1127,6 @@ extern char sh_additional_register_names[ADDREGNAMES_SIZE] \ /* Register in which the static-chain is passed to a function. */ #define STATIC_CHAIN_REGNUM (TARGET_SH5 ? 1 : 3) -/* The register in which a struct value address is passed. */ - -#define STRUCT_VALUE_REGNUM 2 - -/* If the structure value address is not passed in a register, define - `STRUCT_VALUE' as an expression returning an RTX for the place - where the address is passed. If it returns 0, the address is - passed as an "invisible" first argument. */ - -/* The Renesas calling convention doesn't quite fit into this scheme since - the address is passed like an invisible argument, but one that is always - passed in memory. */ -#define STRUCT_VALUE \ - (TARGET_HITACHI ? 0 : gen_rtx_REG (Pmode, STRUCT_VALUE_REGNUM)) - -#define RETURN_IN_MEMORY(TYPE) \ - (TARGET_SH5 \ - ? ((TYPE_MODE (TYPE) == BLKmode \ - ? (unsigned HOST_WIDE_INT) int_size_in_bytes (TYPE) \ - : GET_MODE_SIZE (TYPE_MODE (TYPE))) > 8) \ - : (TYPE_MODE (TYPE) == BLKmode \ - || (TARGET_HITACHI && TREE_CODE (TYPE) == RECORD_TYPE))) - /* Don't default to pcc-struct-return, because we have already specified exactly how to return structures in the RETURN_IN_MEMORY macro. */ @@ -1797,6 +1775,10 @@ struct sh_args { #define CALL_COOKIE_INT_REG_GET(COOKIE, REG) \ (((COOKIE) >> CALL_COOKIE_INT_REG_SHIFT (REG)) & ((REG) < 4 ? 7 : 15)) long call_cookie; + + /* This is set to non-zero when the call in question must use the Renesas ABI, + even without the -mrenesas option. */ + int renesas_abi; }; #define CUMULATIVE_ARGS struct sh_args @@ -1839,17 +1821,18 @@ struct sh_args { For TARGET_HITACHI, the structure value pointer is passed in memory. */ -#define INIT_CUMULATIVE_ARGS(CUM, FNTYPE, LIBNAME, INDIRECT) \ +#define INIT_CUMULATIVE_ARGS(CUM, FNTYPE, LIBNAME, FNDECL) \ do { \ (CUM).arg_count[(int) SH_ARG_INT] = 0; \ (CUM).arg_count[(int) SH_ARG_FLOAT] = 0; \ + (CUM).renesas_abi = sh_attr_renesas_p (FNTYPE) ? 1 : 0; \ (CUM).force_mem \ - = (TARGET_HITACHI && FNTYPE \ - && aggregate_value_p (TREE_TYPE (FNTYPE))); \ + = ((TARGET_HITACHI || (CUM).renesas_abi) && (FNTYPE) \ + && aggregate_value_p (TREE_TYPE (FNTYPE), (FNDECL))); \ (CUM).prototype_p = (FNTYPE) && TYPE_ARG_TYPES (FNTYPE); \ (CUM).arg_count[(int) SH_ARG_INT] \ = (TARGET_SH5 && (FNTYPE) \ - && aggregate_value_p (TREE_TYPE (FNTYPE))); \ + && aggregate_value_p (TREE_TYPE (FNTYPE), (FNDECL))); \ (CUM).free_single_fp_reg = 0; \ (CUM).outgoing = 1; \ (CUM).stack_regs = 0; \ @@ -1881,128 +1864,11 @@ struct sh_args { INIT_CUMULATIVE_ARGS ((CUM), (FNTYPE), (LIBNAME), 0); \ (CUM).outgoing = 0; \ } while (0) - -/* Update the data in CUM to advance over an argument - of mode MODE and data type TYPE. - (TYPE is null for libcalls where that information may not be - available.) */ #define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \ - if ((CUM).force_mem) \ - (CUM).force_mem = 0; \ - else if (TARGET_SH5) \ - { \ - tree TYPE_ = ((CUM).byref && (TYPE) \ - ? TREE_TYPE (TYPE) \ - : (TYPE)); \ - enum machine_mode MODE_ = ((CUM).byref && (TYPE) \ - ? TYPE_MODE (TYPE_) \ - : (MODE)); \ - int dwords = (((CUM).byref \ - ? (CUM).byref \ - : (MODE_) == BLKmode \ - ? int_size_in_bytes (TYPE_) \ - : GET_MODE_SIZE (MODE_)) + 7) / 8; \ - int numregs = MIN (dwords, NPARM_REGS (SImode) \ - - (CUM).arg_count[(int) SH_ARG_INT]); \ - \ - if (numregs) \ - { \ - (CUM).arg_count[(int) SH_ARG_INT] += numregs; \ - if (TARGET_SHCOMPACT \ - && SHCOMPACT_FORCE_ON_STACK (MODE_, TYPE_)) \ - { \ - (CUM).call_cookie \ - |= CALL_COOKIE_INT_REG (((CUM).arg_count[(int) SH_ARG_INT] \ - - numregs), 1); \ - /* N.B. We want this also for outgoing. */\ - (CUM).stack_regs += numregs; \ - } \ - else if ((CUM).byref) \ - { \ - if (! (CUM).outgoing) \ - (CUM).stack_regs += numregs; \ - (CUM).byref_regs += numregs; \ - (CUM).byref = 0; \ - do \ - (CUM).call_cookie \ - |= CALL_COOKIE_INT_REG (((CUM).arg_count[(int) SH_ARG_INT] \ - - numregs), 2); \ - while (--numregs); \ - (CUM).call_cookie \ - |= CALL_COOKIE_INT_REG (((CUM).arg_count[(int) SH_ARG_INT] \ - - 1), 1); \ - } \ - else if (dwords > numregs) \ - { \ - int pushregs = numregs; \ - \ - if (TARGET_SHCOMPACT) \ - (CUM).stack_regs += numregs; \ - while (pushregs < NPARM_REGS (SImode) - 1 \ - && (CALL_COOKIE_INT_REG_GET \ - ((CUM).call_cookie, \ - NPARM_REGS (SImode) - pushregs) \ - == 1)) \ - { \ - (CUM).call_cookie \ - &= ~ CALL_COOKIE_INT_REG (NPARM_REGS (SImode) \ - - pushregs, 1); \ - pushregs++; \ - } \ - if (numregs == NPARM_REGS (SImode)) \ - (CUM).call_cookie \ - |= CALL_COOKIE_INT_REG (0, 1) \ - | CALL_COOKIE_STACKSEQ (numregs - 1); \ - else \ - (CUM).call_cookie \ - |= CALL_COOKIE_STACKSEQ (numregs); \ - } \ - } \ - if (GET_SH_ARG_CLASS (MODE_) == SH_ARG_FLOAT \ - && ((NAMED) || ! (CUM).prototype_p)) \ - { \ - if ((MODE_) == SFmode && (CUM).free_single_fp_reg) \ - (CUM).free_single_fp_reg = 0; \ - else if ((CUM).arg_count[(int) SH_ARG_FLOAT] \ - < NPARM_REGS (SFmode)) \ - { \ - int numfpregs \ - = MIN ((GET_MODE_SIZE (MODE_) + 7) / 8 * 2, \ - NPARM_REGS (SFmode) \ - - (CUM).arg_count[(int) SH_ARG_FLOAT]); \ - \ - (CUM).arg_count[(int) SH_ARG_FLOAT] += numfpregs; \ - \ - if (TARGET_SHCOMPACT && ! (CUM).prototype_p) \ - { \ - if ((CUM).outgoing && numregs > 0) \ - do \ - { \ - (CUM).call_cookie \ - |= (CALL_COOKIE_INT_REG \ - ((CUM).arg_count[(int) SH_ARG_INT] \ - - numregs + ((numfpregs - 2) / 2), \ - 4 + ((CUM).arg_count[(int) SH_ARG_FLOAT] \ - - numfpregs) / 2)); \ - } \ - while (numfpregs -= 2); \ - } \ - else if ((MODE_) == SFmode && (NAMED) \ - && ((CUM).arg_count[(int) SH_ARG_FLOAT] \ - < NPARM_REGS (SFmode))) \ - (CUM).free_single_fp_reg \ - = FIRST_FP_PARM_REG - numfpregs \ - + (CUM).arg_count[(int) SH_ARG_FLOAT] + 1; \ - } \ - } \ - } \ - else if (! TARGET_SH4 || PASS_IN_REG_P ((CUM), (MODE), (TYPE))) \ - ((CUM).arg_count[(int) GET_SH_ARG_CLASS (MODE)] \ - = (ROUND_REG ((CUM), (MODE)) \ - + ((MODE) == BLKmode \ - ? ROUND_ADVANCE (int_size_in_bytes (TYPE)) \ - : ROUND_ADVANCE (GET_MODE_SIZE (MODE))))) + sh_function_arg_advance (&(CUM), (MODE), (TYPE), (NAMED)) +#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \ + sh_function_arg (&(CUM), (MODE), (TYPE), (NAMED)) /* Return boolean indicating arg of mode MODE will be passed in a reg. This macro is only used in this file. */ @@ -2010,7 +1876,11 @@ struct sh_args { #define PASS_IN_REG_P(CUM, MODE, TYPE) \ (((TYPE) == 0 \ || (! TREE_ADDRESSABLE ((tree)(TYPE)) \ - && (! TARGET_HITACHI || ! AGGREGATE_TYPE_P (TYPE)))) \ + && (! (TARGET_HITACHI || (CUM).renesas_abi) \ + || ! (AGGREGATE_TYPE_P (TYPE) \ + || (!TARGET_FPU_ANY \ + && (GET_MODE_CLASS (MODE) == MODE_FLOAT \ + && GET_MODE_SIZE (MODE) > GET_MODE_SIZE (SFmode))))))) \ && ! (CUM).force_mem \ && (TARGET_SH2E \ ? ((MODE) == BLKmode \ @@ -2040,75 +1910,6 @@ struct sh_args { foo (float a, __complex float b); a: fr5 b.real: fr4 b.imag: fr7 */ #define FUNCTION_ARG_SCmode_WART 1 -/* Define where to put the arguments to a function. - Value is zero to push the argument on the stack, - or a hard register in which to store the argument. - - MODE is the argument's machine mode. - TYPE is the data type of the argument (as a tree). - This is null for libcalls where that information may - not be available. - CUM is a variable of type CUMULATIVE_ARGS which gives info about - the preceding args and about the function being called. - NAMED is nonzero if this argument is a named parameter - (otherwise it is an extra parameter matching an ellipsis). - - On SH the first args are normally in registers - and the rest are pushed. Any arg that starts within the first - NPARM_REGS words is at least partially passed in a register unless - its data type forbids. */ - -#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \ - ((! TARGET_SH5 \ - && PASS_IN_REG_P ((CUM), (MODE), (TYPE)) \ - && ((NAMED) || !TARGET_HITACHI)) \ - ? (((MODE) == SCmode && TARGET_SH4 && TARGET_LITTLE_ENDIAN \ - && (! FUNCTION_ARG_SCmode_WART || (ROUND_REG ((CUM), (MODE)) & 1)))\ - ? (gen_rtx_PARALLEL \ - (SCmode, \ - (gen_rtvec \ - (2, \ - (gen_rtx_EXPR_LIST \ - (VOIDmode, \ - gen_rtx_REG (SFmode, \ - BASE_ARG_REG (MODE) \ - + (ROUND_REG ((CUM), (MODE)) ^ 1)), \ - const0_rtx)), \ - (gen_rtx_EXPR_LIST \ - (VOIDmode, \ - gen_rtx_REG (SFmode, \ - BASE_ARG_REG (MODE) \ - + ((ROUND_REG ((CUM), (MODE)) + 1) ^ 1)), \ - GEN_INT (4))))))) \ - : gen_rtx_REG ((MODE), \ - ((BASE_ARG_REG (MODE) + ROUND_REG ((CUM), (MODE))) \ - ^ ((MODE) == SFmode && TARGET_SH4 \ - && TARGET_LITTLE_ENDIAN != 0)))) \ - : TARGET_SH5 \ - ? ((MODE) == VOIDmode && TARGET_SHCOMPACT \ - ? GEN_INT ((CUM).call_cookie) \ - /* The following test assumes unnamed arguments are promoted to \ - DFmode. */ \ - : (MODE) == SFmode && (CUM).free_single_fp_reg \ - ? SH5_PROTOTYPED_FLOAT_ARG ((CUM), (MODE), (CUM).free_single_fp_reg) \ - : (GET_SH_ARG_CLASS (MODE) == SH_ARG_FLOAT \ - && ((NAMED) || ! (CUM).prototype_p) \ - && (CUM).arg_count[(int) SH_ARG_FLOAT] < NPARM_REGS (SFmode)) \ - ? ((! (CUM).prototype_p && TARGET_SHMEDIA) \ - ? SH5_PROTOTYPELESS_FLOAT_ARG ((CUM), (MODE)) \ - : SH5_PROTOTYPED_FLOAT_ARG ((CUM), (MODE), \ - FIRST_FP_PARM_REG \ - + (CUM).arg_count[(int) SH_ARG_FLOAT])) \ - : ((CUM).arg_count[(int) SH_ARG_INT] < NPARM_REGS (SImode) \ - && (! TARGET_SHCOMPACT \ - || (! SHCOMPACT_FORCE_ON_STACK ((MODE), (TYPE)) \ - && ! SH5_WOULD_BE_PARTIAL_NREGS ((CUM), (MODE), \ - (TYPE), (NAMED))))) \ - ? gen_rtx_REG ((MODE), (FIRST_PARM_REG \ - + (CUM).arg_count[(int) SH_ARG_INT])) \ - : 0) \ - : 0) - /* Whether an argument must be passed by reference. On SHcompact, we pretend arguments wider than 32-bits that would have been passed in registers are passed by reference, so that an SHmedia trampoline @@ -2203,10 +2004,6 @@ struct sh_args { (REG)), \ const0_rtx)))) -#define STRICT_ARGUMENT_NAMING TARGET_SH5 - -#define PRETEND_OUTGOING_VARARGS_NAMED (! TARGET_HITACHI && ! TARGET_SH5) - /* For an arg passed partly in registers and partly in memory, this is the number of registers used. For args passed entirely in registers or entirely in memory, zero. @@ -2238,16 +2035,6 @@ struct sh_args { /* Perform any needed actions needed for a function that is receiving a variable number of arguments. */ -/* We actually emit the code in sh_expand_prologue. We used to use - a static variable to flag that we need to emit this code, but that - doesn't when inlining, when functions are deferred and then emitted - later. Fortunately, we already have two flags that are part of struct - function that tell if a function uses varargs or stdarg. */ -#define SETUP_INCOMING_VARARGS(ASF, MODE, TYPE, PAS, ST) do \ - if (! current_function_stdarg) \ - abort (); \ -while (0) - /* Define the `__builtin_va_list' type for the ABI. */ #define BUILD_VA_LIST_TYPE(VALIST) \ (VALIST) = sh_build_va_list () @@ -2336,9 +2123,6 @@ while (0) #define INCOMING_RETURN_ADDR_RTX \ gen_rtx_REG (Pmode, TARGET_SHMEDIA ? PR_MEDIA_REG : PR_REG) -/* Generate necessary RTL for __builtin_saveregs(). */ -#define EXPAND_BUILTIN_SAVEREGS() sh_builtin_saveregs () - /* Addressing modes, and classification of registers for them. */ #define HAVE_POST_INCREMENT TARGET_SH1 #define HAVE_PRE_DECREMENT TARGET_SH1 @@ -2919,9 +2703,6 @@ while (0) but a CALL with constant address is cheap. */ /*#define NO_FUNCTION_CSE 1*/ -/* Chars and shorts should be passed as ints. */ -#define PROMOTE_PROTOTYPES 1 - /* The machine modes of pointers and functions. */ #define Pmode (TARGET_SHMEDIA64 ? DImode : SImode) #define FUNCTION_MODE Pmode diff --git a/gcc/config/sh/sh.md b/gcc/config/sh/sh.md index bd341a0b2df..c5c55c76bf2 100644 --- a/gcc/config/sh/sh.md +++ b/gcc/config/sh/sh.md @@ -5869,7 +5869,10 @@ DONE; } else + { operands[0] = force_reg (SImode, XEXP (operands[0], 0)); + operands[1] = operands[2]; + } emit_call_insn (gen_calli (operands[0], operands[1])); DONE; diff --git a/gcc/config/sparc/sparc.c b/gcc/config/sparc/sparc.c index b095a007bb8..84d27d26a34 100644 --- a/gcc/config/sparc/sparc.c +++ b/gcc/config/sparc/sparc.c @@ -8301,7 +8301,7 @@ sparc_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED, /* Find the "this" pointer. Normally in %o0, but in ARCH64 if the function returns a structure, the structure return pointer is there instead. */ - if (TARGET_ARCH64 && aggregate_value_p (TREE_TYPE (TREE_TYPE (function)))) + if (TARGET_ARCH64 && aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function)) this = gen_rtx_REG (Pmode, SPARC_INCOMING_INT_ARG_FIRST + 1); else this = gen_rtx_REG (Pmode, SPARC_INCOMING_INT_ARG_FIRST); diff --git a/gcc/config/stormy16/stormy16.c b/gcc/config/stormy16/stormy16.c index 8ce526f90d2..d493b7ce797 100644 --- a/gcc/config/stormy16/stormy16.c +++ b/gcc/config/stormy16/stormy16.c @@ -1562,7 +1562,7 @@ xstormy16_asm_output_mi_thunk (file, thunk_fndecl, delta, int regnum = FIRST_ARGUMENT_REGISTER; /* There might be a hidden first argument for a returned structure. */ - if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)))) + if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function)) regnum += 1; fprintf (file, "\tadd %s,#0x%x\n", reg_names[regnum], (int) delta & 0xFFFF); diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index b64cf992998..dafa9c545a2 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,7 @@ +2003-09-03 DJ Delorie + + * decl.c (finish_function): Pass fndecl to aggregate_value_p. + 2003-09-03 Mark Mitchell PR c++/12053 diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 4c287ea7158..1575ec4dbf1 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -14118,7 +14118,7 @@ finish_function (int flags) if (r != error_mark_node /* This is only worth doing for fns that return in memory--and simpler, since we don't have to worry about promoted modes. */ - && aggregate_value_p (TREE_TYPE (TREE_TYPE (fndecl))) + && aggregate_value_p (TREE_TYPE (TREE_TYPE (fndecl)), fndecl) /* Only allow this for variables declared in the outer scope of the function so we know that their lifetime always ends with a return; see g++.dg/opt/nrv6.C. We could be more flexible if diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi index c501aacdbe7..ef49a688033 100644 --- a/gcc/doc/tm.texi +++ b/gcc/doc/tm.texi @@ -1058,24 +1058,25 @@ sign-extend the result to 64 bits. On such machines, set Do not define this macro if it would never modify @var{m}. @end defmac -@defmac PROMOTE_FUNCTION_ARGS -Define this macro if the promotion described by @code{PROMOTE_MODE} -should also be done for outgoing function arguments. -@end defmac +@deftypefn {Target Hook} bool TARGET_PROMOTE_FUNCTION_ARGS (tree @var{fntype}) +This target hook should return @code{true} if the promotion described by +@code{PROMOTE_MODE} should also be done for outgoing function arguments. +@end deftypefn -@defmac PROMOTE_FUNCTION_RETURN -Define this macro if the promotion described by @code{PROMOTE_MODE} -should also be done for the return value of functions. +@deftypefn {Target Hook} bool TARGET_PROMOTE_FUNCTION_RETURN (tree @var{fntype}) +This target hook should return @code{true} if the promotion described by +@code{PROMOTE_MODE} should also be done for the return value of +functions. -If this macro is defined, @code{FUNCTION_VALUE} must perform the same -promotions done by @code{PROMOTE_MODE}. -@end defmac +If this target hook returns @code{true}, @code{FUNCTION_VALUE} must +perform the same promotions done by @code{PROMOTE_MODE}. +@end deftypefn @defmac PROMOTE_FOR_CALL_ONLY Define this macro if the promotion described by @code{PROMOTE_MODE} should @emph{only} be performed for outgoing function arguments or -function return values, as specified by @code{PROMOTE_FUNCTION_ARGS} -and @code{PROMOTE_FUNCTION_RETURN}, respectively. +function return values, as specified by @code{TARGET_PROMOTE_FUNCTION_ARGS} +and @code{TARGET_PROMOTE_FUNCTION_RETURN}, respectively. @end defmac @defmac PARM_BOUNDARY @@ -3353,14 +3354,13 @@ The macros in this section control how arguments are passed on the stack. See the following section for other macros that control passing certain arguments in registers. -@defmac PROMOTE_PROTOTYPES -A C expression whose value is nonzero if an argument declared in -a prototype as an integral type smaller than @code{int} should -actually be passed as an @code{int}. In addition to avoiding -errors in certain cases of mismatch, it also makes for better -code on certain machines. If the macro is not defined in target -header files, it defaults to 0. -@end defmac +@deftypefn {Target Hook} bool TARGET_PROMOTE_PROTOTYPES (tree @var{fntype}) +This target hook returns @code{true} if an argument declared in a +prototype as an integral type smaller than @code{int} should actually be +passed as an @code{int}. In addition to avoiding errors in certain +cases of mismatch, it also makes for better code on certain machines. +The default is to not promote prototypes. +@end deftypefn @defmac PUSH_ARGS A C expression. If nonzero, push insns will be used to pass @@ -3819,7 +3819,7 @@ register where the return value is stored. The value can also be a @code{parallel} RTX, if the return value is in multiple places. See @code{FUNCTION_ARG} for an explanation of the @code{parallel} form. -If @code{PROMOTE_FUNCTION_RETURN} is defined, you must apply the same +If @code{TARGET_PROMOTE_FUNCTION_RETURN} is defined, you must apply the same promotion rules specified in @code{PROMOTE_MODE} if @var{valtype} is a scalar type. @@ -3910,24 +3910,24 @@ is called the @dfn{structure value address}. This section describes how to control returning structure values in memory. -@defmac RETURN_IN_MEMORY (@var{type}) -A C expression which can inhibit the returning of certain function -values in registers, based on the type of value. A nonzero value says -to return the function value in memory, just as large structures are -always returned. Here @var{type} will be a C expression of type -@code{tree}, representing the data type of the value. +@deftypefn {Target Hook} bool RETURN_IN_MEMORY (tree @var{type}, tree @var{fntype}) +This target hook should return a nonzero value to say to return the +function value in memory, just as large structures are always returned. +Here @var{type} will be the data type of the value, and @var{fntype} +will be the type of the function doing the returning, or @code{NULL} for +libcalls. Note that values of mode @code{BLKmode} must be explicitly handled -by this macro. Also, the option @option{-fpcc-struct-return} +by this function. Also, the option @option{-fpcc-struct-return} takes effect regardless of this macro. On most systems, it is -possible to leave the macro undefined; this causes a default +possible to leave the hook undefined; this causes a default definition to be used, whose value is the constant 1 for @code{BLKmode} values, and 0 otherwise. -Do not use this macro to indicate that structures and unions should always +Do not use this hook to indicate that structures and unions should always be returned in memory. You should instead use @code{DEFAULT_PCC_STRUCT_RETURN} to indicate this. -@end defmac +@end deftypefn @defmac DEFAULT_PCC_STRUCT_RETURN Define this macro to be 1 if all structure and union return values must be @@ -3939,36 +3939,23 @@ and union return values are decided by the @code{RETURN_IN_MEMORY} macro. If not defined, this defaults to the value 1. @end defmac -@defmac STRUCT_VALUE_REGNUM -If the structure value address is passed in a register, then -@code{STRUCT_VALUE_REGNUM} should be the number of that register. -@end defmac - -@defmac STRUCT_VALUE -If the structure value address is not passed in a register, define -@code{STRUCT_VALUE} as an expression returning an RTX for the place -where the address is passed. If it returns 0, the address is passed as -an ``invisible'' first argument. -@end defmac +@deftypefn {Target Hook} rtx TARGET_STRUCT_VALUE_RTX (tree @var{fndecl}, int @var{incoming}) +This target hook should return the location of the structure value +address (normally a @code{mem} or @code{reg}), or 0 if the address is +passed as an ``invisible'' first argument. Note that @var{fndecl} may +be @code{NULL}, for libcalls. -@defmac STRUCT_VALUE_INCOMING_REGNUM On some architectures the place where the structure value address is found by the called function is not the same place that the caller put it. This can be due to register windows, or it could be because the function prologue moves it to a different place. +@var{incoming} is @code{true} when the location is needed in +the context of the called function, and @code{false} in the context of +the caller. -If the incoming location of the structure value address is in a -register, define this macro as the register number. -@end defmac - -@defmac STRUCT_VALUE_INCOMING -If the incoming location is not a register, then you should define -@code{STRUCT_VALUE_INCOMING} as an expression for an RTX for where the -called function should find the value. If it should find the value on -the stack, define this to create a @code{mem} which refers to the frame -pointer. A definition of 0 means that the address is passed as an -``invisible'' first argument. -@end defmac +If @var{incoming} is @code{true} and the address is to be found on the +stack, return a @code{mem} which refers to the frame pointer. +@end deftypefn @defmac PCC_STATIC_STRUCT_RETURN Define this macro if the usual system convention on the target machine @@ -4428,70 +4415,71 @@ interpret the values of @code{__builtin_classify_type}. These machine description macros help implement varargs: -@defmac EXPAND_BUILTIN_SAVEREGS () -If defined, is a C expression that produces the machine-specific code -for a call to @code{__builtin_saveregs}. This code will be moved to the -very beginning of the function, before any parameter access are made. -The return value of this function should be an RTX that contains the -value to use as the return of @code{__builtin_saveregs}. -@end defmac +@deftypefn {Target Hook} rtx TARGET_EXPAND_BUILTIN_SAVEREGS (void) +If defined, this hook produces the machine-specific code for a call to +@code{__builtin_saveregs}. This code will be moved to the very +beginning of the function, before any parameter access are made. The +return value of this function should be an RTX that contains the value +to use as the return of @code{__builtin_saveregs}. +@end deftypefn -@defmac SETUP_INCOMING_VARARGS (@var{args_so_far}, @var{mode}, @var{type}, @var{pretend_args_size}, @var{second_time}) -This macro offers an alternative to using @code{__builtin_saveregs} and -defining the macro @code{EXPAND_BUILTIN_SAVEREGS}. Use it to store the -anonymous register arguments into the stack so that all the arguments -appear to have been passed consecutively on the stack. Once this is -done, you can use the standard implementation of varargs that works for -machines that pass all their arguments on the stack. +@deftypefn {Target Hook} void TARGET_SETUP_INCOMING_VARARGS (CUMULATIVE_ARGS *@var{args_so_far}, enum machine_mode @var{mode}, tree @var{type}, int *@var{pretend_args_size}, int @var{second_time}) +This target hook offers an alternative to using +@code{__builtin_saveregs} and defining the hook +@code{TARGET_EXPAND_BUILTIN_SAVEREGS}. Use it to store the anonymous +register arguments into the stack so that all the arguments appear to +have been passed consecutively on the stack. Once this is done, you can +use the standard implementation of varargs that works for machines that +pass all their arguments on the stack. -The argument @var{args_so_far} is the @code{CUMULATIVE_ARGS} data +The argument @var{args_so_far} points to the @code{CUMULATIVE_ARGS} data structure, containing the values that are obtained after processing the named arguments. The arguments @var{mode} and @var{type} describe the last named argument---its machine mode and its data type as a tree node. -The macro implementation should do two things: first, push onto the -stack all the argument registers @emph{not} used for the named -arguments, and second, store the size of the data thus pushed into the -@code{int}-valued variable whose name is supplied as the argument -@var{pretend_args_size}. The value that you store here will serve as -additional offset for setting up the stack frame. +The target hook should do two things: first, push onto the stack all the +argument registers @emph{not} used for the named arguments, and second, +store the size of the data thus pushed into the @code{int}-valued +variable pointed to by @var{pretend_args_size}. The value that you +store here will serve as additional offset for setting up the stack +frame. Because you must generate code to push the anonymous arguments at compile time without knowing their data types, -@code{SETUP_INCOMING_VARARGS} is only useful on machines that have just -a single category of argument register and use it uniformly for all data -types. +@code{TARGET_SETUP_INCOMING_VARARGS} is only useful on machines that +have just a single category of argument register and use it uniformly +for all data types. If the argument @var{second_time} is nonzero, it means that the arguments of the function are being analyzed for the second time. This happens for an inline function, which is not actually compiled until the -end of the source file. The macro @code{SETUP_INCOMING_VARARGS} should +end of the source file. The hook @code{TARGET_SETUP_INCOMING_VARARGS} should not generate any instructions in this case. -@end defmac +@end deftypefn -@defmac STRICT_ARGUMENT_NAMING -Define this macro to be a nonzero value if the location where a function +@deftypefn {Target Hook} bool TARGET_STRICT_ARGUMENT_NAMING (CUMULATIVE_ARGS *@var{ca}) +Define this hook to return @code{true} if the location where a function argument is passed depends on whether or not it is a named argument. -This macro controls how the @var{named} argument to @code{FUNCTION_ARG} -is set for varargs and stdarg functions. If this macro returns a -nonzero value, the @var{named} argument is always true for named -arguments, and false for unnamed arguments. If it returns a value of -zero, but @code{SETUP_INCOMING_VARARGS} is defined, then all arguments -are treated as named. Otherwise, all named arguments except the last -are treated as named. +This hook controls how the @var{named} argument to @code{FUNCTION_ARG} +is set for varargs and stdarg functions. If this hook returns +@code{true}, the @var{named} argument is always true for named +arguments, and false for unnamed arguments. If it returns @code{false}, +but @code{TARGET_PRETEND_OUTOGOING_VARARGS_NAMED} returns @code{true}, +then all arguments are treated as named. Otherwise, all named arguments +except the last are treated as named. -You need not define this macro if it always returns zero. -@end defmac +You need not define this hook if it always returns zero. +@end deftypefn -@defmac PRETEND_OUTGOING_VARARGS_NAMED +@deftypefn {Target Hook} bool TARGET_PRETEND_OUTGOING_VARARGS_NAMED If you need to conditionally change ABIs so that one works with -@code{SETUP_INCOMING_VARARGS}, but the other works like neither -@code{SETUP_INCOMING_VARARGS} nor @code{STRICT_ARGUMENT_NAMING} was -defined, then define this macro to return nonzero if -@code{SETUP_INCOMING_VARARGS} is used, zero otherwise. -Otherwise, you should not define this macro. -@end defmac +@code{TARGET_SETUP_INCOMING_VARARGS}, but the other works like neither +@code{TARGET_SETUP_INCOMING_VARARGS} nor @code{TARGET_STRICT_ARGUMENT_NAMING} was +defined, then define this hook to return @code{true} if +@code{SETUP_INCOMING_VARARGS} is used, @code{false} otherwise. +Otherwise, you should not define this hook. +@end deftypefn @node Trampolines @section Trampolines for Nested Functions diff --git a/gcc/emit-rtl.c b/gcc/emit-rtl.c index 4140abc15d0..0668cfb20e4 100644 --- a/gcc/emit-rtl.c +++ b/gcc/emit-rtl.c @@ -132,8 +132,6 @@ REAL_VALUE_TYPE dconsthalf; In an inline procedure, the stack and frame pointer rtxs may not be used for anything else. */ -rtx struct_value_rtx; /* (REG:Pmode STRUCT_VALUE_REGNUM) */ -rtx struct_value_incoming_rtx; /* (REG:Pmode STRUCT_VALUE_INCOMING_REGNUM) */ rtx static_chain_rtx; /* (REG:Pmode STATIC_CHAIN_REGNUM) */ rtx static_chain_incoming_rtx; /* (REG:Pmode STATIC_CHAIN_INCOMING_REGNUM) */ rtx pic_offset_table_rtx; /* (REG:Pmode PIC_OFFSET_TABLE_REGNUM) */ @@ -5467,23 +5465,6 @@ init_emit_once (int line_numbers) = gen_raw_REG (Pmode, RETURN_ADDRESS_POINTER_REGNUM); #endif -#ifdef STRUCT_VALUE - struct_value_rtx = STRUCT_VALUE; -#else - struct_value_rtx = gen_rtx_REG (Pmode, STRUCT_VALUE_REGNUM); -#endif - -#ifdef STRUCT_VALUE_INCOMING - struct_value_incoming_rtx = STRUCT_VALUE_INCOMING; -#else -#ifdef STRUCT_VALUE_INCOMING_REGNUM - struct_value_incoming_rtx - = gen_rtx_REG (Pmode, STRUCT_VALUE_INCOMING_REGNUM); -#else - struct_value_incoming_rtx = struct_value_rtx; -#endif -#endif - #ifdef STATIC_CHAIN_REGNUM static_chain_rtx = gen_rtx_REG (Pmode, STATIC_CHAIN_REGNUM); diff --git a/gcc/expr.c b/gcc/expr.c index 489aba4b496..eb25fed8a4a 100644 --- a/gcc/expr.c +++ b/gcc/expr.c @@ -4273,7 +4273,7 @@ expand_assignment (tree to, tree from, int want_value) since it might be a promoted variable where the zero- or sign- extension needs to be done. Handling this in the normal way is safe because no computation is done before the call. */ - if (TREE_CODE (from) == CALL_EXPR && ! aggregate_value_p (from) + if (TREE_CODE (from) == CALL_EXPR && ! aggregate_value_p (from, from) && TREE_CODE (TYPE_SIZE (TREE_TYPE (from))) == INTEGER_CST && ! ((TREE_CODE (to) == VAR_DECL || TREE_CODE (to) == PARM_DECL) && GET_CODE (DECL_RTL (to)) == REG)) @@ -6704,7 +6704,7 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier if (! cse_not_expected && mode != BLKmode && target && (GET_CODE (target) != REG || REGNO (target) < FIRST_PSEUDO_REGISTER) && ! (code == CONSTRUCTOR && GET_MODE_SIZE (mode) > UNITS_PER_WORD) - && ! (code == CALL_EXPR && aggregate_value_p (exp))) + && ! (code == CALL_EXPR && aggregate_value_p (exp, exp))) target = 0; switch (code) diff --git a/gcc/expr.h b/gcc/expr.h index 9abea77872b..aa9936e1555 100644 --- a/gcc/expr.h +++ b/gcc/expr.h @@ -169,35 +169,12 @@ do { \ tree split_complex_types (tree); tree split_complex_values (tree); -/* Provide a default value for STRICT_ARGUMENT_NAMING. */ -#ifndef STRICT_ARGUMENT_NAMING -#define STRICT_ARGUMENT_NAMING 0 -#endif - -/* Provide a default value for PRETEND_OUTGOING_VARARGS_NAMED. */ -#ifdef SETUP_INCOMING_VARARGS -#ifndef PRETEND_OUTGOING_VARARGS_NAMED -#define PRETEND_OUTGOING_VARARGS_NAMED 1 -#endif -#else -/* It is an error to define PRETEND_OUTGOING_VARARGS_NAMED without - defining SETUP_INCOMING_VARARGS. */ -#define PRETEND_OUTGOING_VARARGS_NAMED 0 -#endif - /* Nonzero if we do not know how to pass TYPE solely in registers. */ extern bool default_must_pass_in_stack (enum machine_mode, tree); #ifndef MUST_PASS_IN_STACK #define MUST_PASS_IN_STACK(MODE,TYPE) default_must_pass_in_stack(MODE, TYPE) #endif -/* Nonzero if type TYPE should be returned in memory. - Most machines can use the following default definition. */ - -#ifndef RETURN_IN_MEMORY -#define RETURN_IN_MEMORY(TYPE) (TYPE_MODE (TYPE) == BLKmode) -#endif - /* Supply a default definition of STACK_SAVEAREA_MODE for emit_stack_save. Normally move_insn, so Pmode stack pointer. */ diff --git a/gcc/final.c b/gcc/final.c index f43f9d92b6e..6ee13a604f8 100644 --- a/gcc/final.c +++ b/gcc/final.c @@ -1418,9 +1418,8 @@ profile_function (FILE *file ATTRIBUTE_UNUSED) # define NO_PROFILE_COUNTERS 0 #endif #if defined(ASM_OUTPUT_REG_PUSH) -#if defined(STRUCT_VALUE_INCOMING_REGNUM) || defined(STRUCT_VALUE_REGNUM) int sval = current_function_returns_struct; -#endif + rtx svrtx = targetm.calls.struct_value_rtx (TREE_TYPE (current_function_decl), 1); #if defined(STATIC_CHAIN_INCOMING_REGNUM) || defined(STATIC_CHAIN_REGNUM) int cxt = current_function_needs_context; #endif @@ -1437,16 +1436,9 @@ profile_function (FILE *file ATTRIBUTE_UNUSED) function_section (current_function_decl); -#if defined(STRUCT_VALUE_INCOMING_REGNUM) && defined(ASM_OUTPUT_REG_PUSH) - if (sval) - ASM_OUTPUT_REG_PUSH (file, STRUCT_VALUE_INCOMING_REGNUM); -#else -#if defined(STRUCT_VALUE_REGNUM) && defined(ASM_OUTPUT_REG_PUSH) - if (sval) - { - ASM_OUTPUT_REG_PUSH (file, STRUCT_VALUE_REGNUM); - } -#endif +#if defined(ASM_OUTPUT_REG_PUSH) + if (sval && GET_CODE (svrtx) == REG) + ASM_OUTPUT_REG_PUSH (file, REGNO (svrtx)); #endif #if defined(STATIC_CHAIN_INCOMING_REGNUM) && defined(ASM_OUTPUT_REG_PUSH) @@ -1475,16 +1467,9 @@ profile_function (FILE *file ATTRIBUTE_UNUSED) #endif #endif -#if defined(STRUCT_VALUE_INCOMING_REGNUM) && defined(ASM_OUTPUT_REG_PUSH) - if (sval) - ASM_OUTPUT_REG_POP (file, STRUCT_VALUE_INCOMING_REGNUM); -#else -#if defined(STRUCT_VALUE_REGNUM) && defined(ASM_OUTPUT_REG_PUSH) - if (sval) - { - ASM_OUTPUT_REG_POP (file, STRUCT_VALUE_REGNUM); - } -#endif +#if defined(ASM_OUTPUT_REG_PUSH) + if (sval && GET_CODE (svrtx) == REG) + ASM_OUTPUT_REG_POP (file, REGNO (svrtx)); #endif } diff --git a/gcc/function.c b/gcc/function.c index 6decfdf232d..8227139d256 100644 --- a/gcc/function.c +++ b/gcc/function.c @@ -62,6 +62,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "tm_p.h" #include "integrate.h" #include "langhooks.h" +#include "target.h" #ifndef TRAMPOLINE_ALIGNMENT #define TRAMPOLINE_ALIGNMENT FUNCTION_BOUNDARY @@ -4177,16 +4178,37 @@ get_first_nonparm_insn (void) EXP may be a type node or an expression (whose type is tested). */ int -aggregate_value_p (tree exp) +aggregate_value_p (tree exp, tree fntype) { int i, regno, nregs; rtx reg; tree type = (TYPE_P (exp)) ? exp : TREE_TYPE (exp); + if (fntype) + switch (TREE_CODE (fntype)) + { + case CALL_EXPR: + fntype = get_callee_fndecl (fntype); + fntype = fntype ? TREE_TYPE (fntype) : 0; + break; + case FUNCTION_DECL: + fntype = TREE_TYPE (fntype); + break; + case FUNCTION_TYPE: + case METHOD_TYPE: + break; + case IDENTIFIER_NODE: + fntype = 0; + break; + default: + /* We don't expect other rtl types here. */ + abort(); + } + if (TREE_CODE (type) == VOID_TYPE) return 0; - if (RETURN_IN_MEMORY (type)) + if (targetm.calls.return_in_memory (type, fntype)) return 1; /* Types that are TREE_ADDRESSABLE must be constructed in memory, and thus can't be returned in registers. */ @@ -4230,9 +4252,7 @@ assign_parms (tree fndecl) /* This is a dummy PARM_DECL that we used for the function result if the function returns a structure. */ tree function_result_decl = 0; -#ifdef SETUP_INCOMING_VARARGS int varargs_setup = 0; -#endif int reg_parm_stack_space = 0; rtx conversion_insns = 0; @@ -4265,9 +4285,9 @@ assign_parms (tree fndecl) stack_args_size.var = 0; /* If struct value address is treated as the first argument, make it so. */ - if (aggregate_value_p (DECL_RESULT (fndecl)) + if (aggregate_value_p (DECL_RESULT (fndecl), fndecl) && ! current_function_returns_pcc_struct - && struct_value_incoming_rtx == 0) + && targetm.calls.struct_value_rtx (TREE_TYPE (fndecl), 1) == 0) { tree type = build_pointer_type (TREE_TYPE (fntype)); @@ -4336,7 +4356,7 @@ assign_parms (tree fndecl) /* Set NAMED_ARG if this arg should be treated as a named arg. For most machines, if this is a varargs/stdarg function, then we treat the last named arg as if it were anonymous too. */ - named_arg = STRICT_ARGUMENT_NAMING ? 1 : ! last_named; + named_arg = targetm.calls.strict_argument_naming (&args_so_far) ? 1 : ! last_named; if (TREE_TYPE (parm) == error_mark_node /* This can happen after weird syntax errors @@ -4401,11 +4421,12 @@ assign_parms (tree fndecl) promoted_mode = passed_mode; -#ifdef PROMOTE_FUNCTION_ARGS - /* Compute the mode in which the arg is actually extended to. */ - unsignedp = TREE_UNSIGNED (passed_type); - promoted_mode = promote_mode (passed_type, promoted_mode, &unsignedp, 1); -#endif + if (targetm.calls.promote_function_args (TREE_TYPE (fndecl))) + { + /* Compute the mode in which the arg is actually extended to. */ + unsignedp = TREE_UNSIGNED (passed_type); + promoted_mode = promote_mode (passed_type, promoted_mode, &unsignedp, 1); + } /* Let machine desc say which reg (if any) the parm arrives in. 0 means it arrives on the stack. */ @@ -4420,7 +4441,6 @@ assign_parms (tree fndecl) if (entry_parm == 0) promoted_mode = passed_mode; -#ifdef SETUP_INCOMING_VARARGS /* If this is the last named parameter, do any required setup for varargs or stdargs. We need to know about the case of this being an addressable type, in which case we skip the registers it @@ -4433,11 +4453,11 @@ assign_parms (tree fndecl) Also, indicate when RTL generation is to be suppressed. */ if (last_named && !varargs_setup) { - SETUP_INCOMING_VARARGS (args_so_far, promoted_mode, passed_type, - current_function_pretend_args_size, 0); + targetm.calls.setup_incoming_varargs (&args_so_far, promoted_mode, + passed_type, + ¤t_function_pretend_args_size, 0); varargs_setup = 1; } -#endif /* Determine parm's home in the stack, in case it arrives in the stack or we should pretend it did. @@ -4457,7 +4477,8 @@ assign_parms (tree fndecl) #endif if (!in_regs && !named_arg) { - int pretend_named = PRETEND_OUTGOING_VARARGS_NAMED; + int pretend_named = + targetm.calls.pretend_outgoing_varargs_named (&args_so_far); if (pretend_named) { #ifdef FUNCTION_INCOMING_ARG @@ -5275,8 +5296,6 @@ split_complex_args (tree args) that REGNO is promoted from and whether the promotion was signed or unsigned. */ -#ifdef PROMOTE_FUNCTION_ARGS - rtx promoted_input_arg (unsigned int regno, enum machine_mode *pmode, int *punsignedp) { @@ -5304,7 +5323,6 @@ promoted_input_arg (unsigned int regno, enum machine_mode *pmode, int *punsigned return 0; } -#endif /* Compute the size and offset from the start of the stacked arguments for a parm passed in mode PASSED_MODE and with type TYPE. @@ -6284,7 +6302,7 @@ allocate_struct_function (tree fndecl) current_function_name = (*lang_hooks.decl_printable_name) (fndecl, 2); result = DECL_RESULT (fndecl); - if (aggregate_value_p (result)) + if (aggregate_value_p (result, fndecl)) { #ifdef PCC_STATIC_STRUCT_RETURN current_function_returns_pcc_struct = 1; @@ -6515,7 +6533,7 @@ expand_function_start (tree subr, int parms_have_cleanups) before any library calls that assign parms might generate. */ /* Decide whether to return the value in memory or in a register. */ - if (aggregate_value_p (DECL_RESULT (subr))) + if (aggregate_value_p (DECL_RESULT (subr), subr)) { /* Returning something that won't go in a register. */ rtx value_address = 0; @@ -6529,13 +6547,14 @@ expand_function_start (tree subr, int parms_have_cleanups) else #endif { + rtx sv = targetm.calls.struct_value_rtx (TREE_TYPE (subr), 1); /* Expect to be passed the address of a place to store the value. If it is passed as an argument, assign_parms will take care of it. */ - if (struct_value_incoming_rtx) + if (sv) { value_address = gen_reg_rtx (Pmode); - emit_move_insn (value_address, struct_value_incoming_rtx); + emit_move_insn (value_address, sv); } } if (value_address) @@ -6973,10 +6992,9 @@ expand_function_end (void) { int unsignedp = TREE_UNSIGNED (TREE_TYPE (decl_result)); -#ifdef PROMOTE_FUNCTION_RETURN - promote_mode (TREE_TYPE (decl_result), GET_MODE (decl_rtl), - &unsignedp, 1); -#endif + if (targetm.calls.promote_function_return (TREE_TYPE (current_function_decl))) + promote_mode (TREE_TYPE (decl_result), GET_MODE (decl_rtl), + &unsignedp, 1); convert_move (real_decl_rtl, decl_rtl, unsignedp); } diff --git a/gcc/hard-reg-set.h b/gcc/hard-reg-set.h index 53330cf28b7..a770180e386 100644 --- a/gcc/hard-reg-set.h +++ b/gcc/hard-reg-set.h @@ -1,5 +1,5 @@ /* Sets (bit vectors) of hard registers, and operations on them. - Copyright (C) 1987, 1992, 1994, 2000 Free Software Foundation, Inc. + Copyright (C) 1987, 1992, 1994, 2000, 2003 Free Software Foundation, Inc. This file is part of GCC @@ -418,7 +418,7 @@ extern HARD_REG_SET losing_caller_save_reg_set; /* Indexed by hard register number, contains 1 for registers that are fixed use -- i.e. in fixed_regs -- or a function value return register - or STRUCT_VALUE_REGNUM or STATIC_CHAIN_REGNUM. These are the + or TARGET_STRUCT_VALUE_RTX or STATIC_CHAIN_REGNUM. These are the registers that cannot hold quantities across calls even if we are willing to save and restore them. */ diff --git a/gcc/integrate.c b/gcc/integrate.c index 15474ba3f24..f0abe89f3e2 100644 --- a/gcc/integrate.c +++ b/gcc/integrate.c @@ -1028,7 +1028,7 @@ expand_inline_function (tree fndecl, tree parms, rtx target, int ignore, else { if (! structure_value_addr - || ! aggregate_value_p (DECL_RESULT (fndecl))) + || ! aggregate_value_p (DECL_RESULT (fndecl), fndecl)) abort (); /* Pass the function the address in which to return a structure @@ -1283,7 +1283,7 @@ expand_inline_function (tree fndecl, tree parms, rtx target, int ignore, out of the temp register into a BLKmode memory object. */ if (target && TYPE_MODE (TREE_TYPE (TREE_TYPE (fndecl))) == BLKmode - && ! aggregate_value_p (TREE_TYPE (TREE_TYPE (fndecl)))) + && ! aggregate_value_p (TREE_TYPE (TREE_TYPE (fndecl)), fndecl)) target = copy_blkmode_from_reg (0, target, TREE_TYPE (TREE_TYPE (fndecl))); if (structure_value_addr) diff --git a/gcc/objc/objc-act.c b/gcc/objc/objc-act.c index 8350cb9e986..10cc88912fc 100644 --- a/gcc/objc/objc-act.c +++ b/gcc/objc/objc-act.c @@ -406,7 +406,7 @@ generate_struct_by_value_array () } finish_struct (type, field_decl_chain, NULL_TREE); - aggregate_in_mem[i] = aggregate_value_p (type); + aggregate_in_mem[i] = aggregate_value_p (type, 0); if (!aggregate_in_mem[i]) found = 1; } diff --git a/gcc/reg-stack.c b/gcc/reg-stack.c index 016c5c7c2c6..fd707e21e83 100644 --- a/gcc/reg-stack.c +++ b/gcc/reg-stack.c @@ -802,7 +802,7 @@ stack_result (tree decl) /* If the value is supposed to be returned in memory, then clearly it is not returned in a stack register. */ - if (aggregate_value_p (DECL_RESULT (decl))) + if (aggregate_value_p (DECL_RESULT (decl), decl)) return 0; result = DECL_RTL_IF_SET (DECL_RESULT (decl)); diff --git a/gcc/rtl.h b/gcc/rtl.h index 82dddc74fa0..b7db32adeed 100644 --- a/gcc/rtl.h +++ b/gcc/rtl.h @@ -1816,8 +1816,6 @@ extern GTY(()) rtx global_rtl[GR_MAX]; #define arg_pointer_rtx (global_rtl[GR_ARG_POINTER]) extern GTY(()) rtx pic_offset_table_rtx; -extern GTY(()) rtx struct_value_rtx; -extern GTY(()) rtx struct_value_incoming_rtx; extern GTY(()) rtx static_chain_rtx; extern GTY(()) rtx static_chain_incoming_rtx; extern GTY(()) rtx return_address_pointer_rtx; diff --git a/gcc/stmt.c b/gcc/stmt.c index 9a8c0bc6cb9..b62f83eccb3 100644 --- a/gcc/stmt.c +++ b/gcc/stmt.c @@ -57,6 +57,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "langhooks.h" #include "predict.h" #include "optabs.h" +#include "target.h" /* Assume that case vectors are not pc-relative. */ #ifndef CASE_VECTOR_PC_RELATIVE @@ -2937,16 +2938,17 @@ expand_value_return (rtx val) if (return_reg != val) { tree type = TREE_TYPE (DECL_RESULT (current_function_decl)); -#ifdef PROMOTE_FUNCTION_RETURN - int unsignedp = TREE_UNSIGNED (type); - enum machine_mode old_mode - = DECL_MODE (DECL_RESULT (current_function_decl)); - enum machine_mode mode - = promote_mode (type, old_mode, &unsignedp, 1); - - if (mode != old_mode) - val = convert_modes (mode, old_mode, val, unsignedp); -#endif + if (targetm.calls.promote_function_return (TREE_TYPE (current_function_decl))) + { + int unsignedp = TREE_UNSIGNED (type); + enum machine_mode old_mode + = DECL_MODE (DECL_RESULT (current_function_decl)); + enum machine_mode mode + = promote_mode (type, old_mode, &unsignedp, 1); + + if (mode != old_mode) + val = convert_modes (mode, old_mode, val, unsignedp); + } if (GET_CODE (return_reg) == PARALLEL) emit_group_load (return_reg, val, type, int_size_in_bytes (type)); else diff --git a/gcc/stor-layout.c b/gcc/stor-layout.c index afd830d20e8..d1a856983a5 100644 --- a/gcc/stor-layout.c +++ b/gcc/stor-layout.c @@ -1093,6 +1093,7 @@ place_field (record_layout_info rli, tree field) rli->prev_field = NULL; } + rli->offset_align = tree_low_cst (TYPE_SIZE (type), 0); normalize_rli (rli); } diff --git a/gcc/target-def.h b/gcc/target-def.h index e3c4df1d670..da6003eff5c 100644 --- a/gcc/target-def.h +++ b/gcc/target-def.h @@ -305,6 +305,30 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define TARGET_MACHINE_DEPENDENT_REORG 0 +#define TARGET_PROMOTE_FUNCTION_ARGS default_promote_function_args +#define TARGET_PROMOTE_FUNCTION_RETURN default_promote_function_return +#define TARGET_PROMOTE_PROTOTYPES default_promote_prototypes + +#define TARGET_STRUCT_VALUE_RTX default_struct_value_rtx +#define TARGET_RETURN_IN_MEMORY default_return_in_memory + +#define TARGET_EXPAND_BUILTIN_SAVEREGS default_expand_builtin_saveregs +#define TARGET_SETUP_INCOMING_VARARGS default_setup_incoming_varargs +#define TARGET_STRICT_ARGUMENT_NAMING default_strict_argument_naming +#define TARGET_PRETEND_OUTGOING_VARARGS_NAMED default_pretend_outgoing_varargs_named + +#define TARGET_CALLS { \ + TARGET_PROMOTE_FUNCTION_ARGS, \ + TARGET_PROMOTE_FUNCTION_RETURN, \ + TARGET_PROMOTE_PROTOTYPES, \ + TARGET_STRUCT_VALUE_RTX, \ + TARGET_RETURN_IN_MEMORY, \ + TARGET_EXPAND_BUILTIN_SAVEREGS, \ + TARGET_SETUP_INCOMING_VARARGS, \ + TARGET_STRICT_ARGUMENT_NAMING, \ + TARGET_PRETEND_OUTGOING_VARARGS_NAMED, \ + } + /* The whole shebang. */ #define TARGET_INITIALIZER \ { \ @@ -345,6 +369,8 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. TARGET_TERMINATE_DW2_EH_FRAME_INFO, \ TARGET_ASM_FILE_START_APP_OFF, \ TARGET_ASM_FILE_START_FILE_DIRECTIVE, \ + TARGET_CALLS, \ } #include "hooks.h" +#include "targhooks.h" diff --git a/gcc/target.h b/gcc/target.h index 8acfb7ab26f..3a7ea78af38 100644 --- a/gcc/target.h +++ b/gcc/target.h @@ -386,6 +386,23 @@ struct gcc_target /* True if output_file_directive should be called for main_input_filename at the beginning of assembly output. */ bool file_start_file_directive; + + /* Functions relating to calls - argument passing, returns, etc. */ + struct calls { + bool (*promote_function_args) (tree fntype); + bool (*promote_function_return) (tree fntype); + bool (*promote_prototypes) (tree fntype); + rtx (*struct_value_rtx) (tree fndecl, int incoming); + bool (*return_in_memory) (tree type, tree fndecl); + rtx (*expand_builtin_saveregs) (void); + /* Returns pretend_argument_size. */ + void (*setup_incoming_varargs) (CUMULATIVE_ARGS *ca, enum machine_mode mode, + tree type, int *pretend_arg_size, int second_time); + bool (*strict_argument_naming) (CUMULATIVE_ARGS *ca); + /* Returns true if we should use SETUP_INCOMING_VARARGS and/or + STRICT_ARGUMENT_NAMING. */ + bool (*pretend_outgoing_varargs_named) (CUMULATIVE_ARGS *ca); + } calls; }; extern struct gcc_target targetm; diff --git a/gcc/targhooks.c b/gcc/targhooks.c new file mode 100644 index 00000000000..943c5bd55c0 --- /dev/null +++ b/gcc/targhooks.c @@ -0,0 +1,158 @@ +/* Default target hook functions. + Copyright (C) 2003 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to the Free +Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "machmode.h" +#include "rtl.h" +#include "tree.h" +#include "expr.h" +#include "toplev.h" +#include "function.h" +#include "target.h" +#include "tm_p.h" +#include "target-def.h" + +bool +default_promote_function_args (fntype) + tree fntype ATTRIBUTE_UNUSED; +{ +#ifdef PROMOTE_FUNCTION_ARGS + return true; +#else + return false; +#endif +} + +bool +default_promote_function_return (fntype) + tree fntype ATTRIBUTE_UNUSED; +{ +#ifdef PROMOTE_FUNCTION_RETURN + return true; +#else + return false; +#endif +} + +bool +default_promote_prototypes (fntype) + tree fntype ATTRIBUTE_UNUSED; +{ + if (PROMOTE_PROTOTYPES) + return true; + else + return false; +} + +rtx +default_struct_value_rtx (tree fntype ATTRIBUTE_UNUSED, int incoming) +{ + rtx rv = 0; + if (incoming) + { +#ifdef STRUCT_VALUE_INCOMING + rv = STRUCT_VALUE_INCOMING; +#else +#ifdef STRUCT_VALUE_INCOMING_REGNUM + rv = gen_rtx_REG (Pmode, STRUCT_VALUE_INCOMING_REGNUM); +#else +#ifdef STRUCT_VALUE + rv = STRUCT_VALUE; +#else +#ifndef STRUCT_VALUE_REGNUM + abort(); +#else + rv = gen_rtx_REG (Pmode, STRUCT_VALUE_REGNUM); +#endif +#endif +#endif +#endif + } + else + { +#ifdef STRUCT_VALUE + rv = STRUCT_VALUE; +#else +#ifndef STRUCT_VALUE_REGNUM + abort(); +#else + rv = gen_rtx_REG (Pmode, STRUCT_VALUE_REGNUM); +#endif +#endif + } + return rv; +} + +bool +default_return_in_memory (tree type, + tree fntype ATTRIBUTE_UNUSED) +{ + return RETURN_IN_MEMORY (type); +} + +rtx +default_expand_builtin_saveregs (void) +{ +#ifdef EXPAND_BUILTIN_SAVEREGS + return EXPAND_BUILTIN_SAVEREGS (); +#else + error ("__builtin_saveregs not supported by this target"); + return const0_rtx; +#endif +} + +void +default_setup_incoming_varargs (CUMULATIVE_ARGS *ca ATTRIBUTE_UNUSED, + enum machine_mode mode ATTRIBUTE_UNUSED, + tree type ATTRIBUTE_UNUSED, + int *pretend_arg_size ATTRIBUTE_UNUSED, + int second_time ATTRIBUTE_UNUSED) +{ +#ifdef SETUP_INCOMING_VARARGS + SETUP_INCOMING_VARARGS ((*ca), mode, type, (*pretend_arg_size), second_time); +#endif +} + +bool +default_strict_argument_naming (CUMULATIVE_ARGS *ca ATTRIBUTE_UNUSED) +{ +#ifdef STRICT_ARGUMENT_NAMING + return STRICT_ARGUMENT_NAMING; +#else + return 0; +#endif +} + +bool +default_pretend_outgoing_varargs_named(CUMULATIVE_ARGS *ca ATTRIBUTE_UNUSED) +{ +#ifdef PRETEND_OUTGOING_VARARGS_NAMED + return PRETEND_OUTGOING_VARARGS_NAMED; +#else +#ifdef SETUP_INCOMING_VARARGS + return 1; +#else + return (targetm.calls.setup_incoming_varargs != default_setup_incoming_varargs); +#endif +#endif +} diff --git a/gcc/targhooks.h b/gcc/targhooks.h new file mode 100644 index 00000000000..335134b81b1 --- /dev/null +++ b/gcc/targhooks.h @@ -0,0 +1,31 @@ +/* Default target hook functions. + Copyright (C) 2003 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to the Free +Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +extern bool default_promote_function_args (tree); +extern bool default_promote_function_return (tree); +extern bool default_promote_prototypes (tree); + +extern rtx default_struct_value_rtx (tree, int); +extern bool default_return_in_memory (tree, tree); + +extern rtx default_expand_builtin_saveregs (void); +extern void default_setup_incoming_varargs (CUMULATIVE_ARGS *, enum machine_mode, tree, int *, int); +extern bool default_strict_argument_naming (CUMULATIVE_ARGS *); +extern bool default_pretend_outgoing_varargs_named (CUMULATIVE_ARGS *); diff --git a/gcc/tree.h b/gcc/tree.h index ec60935542b..d742bc3d95b 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -2871,7 +2871,7 @@ extern void pop_temp_slots (void); extern void push_temp_slots (void); extern void preserve_temp_slots (rtx); extern void preserve_rtl_expr_temps (tree); -extern int aggregate_value_p (tree); +extern int aggregate_value_p (tree, tree); extern void free_temps_for_rtl_expr (tree); extern void instantiate_virtual_regs (tree, rtx); extern void unshare_all_rtl (tree, rtx); -- 2.11.4.GIT