targhooks.c: New file.
* 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. From-SVN: r71048
This commit is contained in:
parent
b885908b11
commit
61f71b3447
132
gcc/ChangeLog
132
gcc/ChangeLog
@ -1,3 +1,135 @@
|
||||
2003-09-03 DJ Delorie <dj@redhat.com>
|
||||
|
||||
* 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 <mustafa@il.ibm.com>
|
||||
|
||||
* gcse.c (replace_one_set): New function.
|
||||
|
@ -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)
|
||||
|
@ -1,3 +1,8 @@
|
||||
2003-09-03 DJ Delorie <dj@redhat.com>
|
||||
|
||||
* misc.c (default_pass_by_ref): Convert to calls.return_in_memory
|
||||
hook.
|
||||
|
||||
2003-08-30 Zack Weinberg <zack@codesourcery.com>
|
||||
|
||||
* Makefile.in: Update substitutions to match changes to
|
||||
|
@ -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),
|
||||
|
@ -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 ();
|
||||
|
39
gcc/c-decl.c
39
gcc/c-decl.c
@ -2672,6 +2672,26 @@ start_decl (tree declarator, tree declspecs, int initialized, tree attributes)
|
||||
/* Set attributes here so if duplicate decl, will have proper 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)
|
||||
@ -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. */
|
||||
|
@ -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);
|
||||
|
61
gcc/calls.c
61
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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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));
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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 */
|
||||
|
@ -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));
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -1,3 +1,7 @@
|
||||
2003-09-03 DJ Delorie <dj@redhat.com>
|
||||
|
||||
* decl.c (finish_function): Pass fndecl to aggregate_value_p.
|
||||
|
||||
2003-09-03 Mark Mitchell <mark@codesourcery.com>
|
||||
|
||||
PR c++/12053
|
||||
|
@ -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
|
||||
|
186
gcc/doc/tm.texi
186
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
|
||||
@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
|
||||
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
|
||||
|
||||
@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
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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)
|
||||
|
23
gcc/expr.h
23
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. */
|
||||
|
||||
|
29
gcc/final.c
29
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
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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. */
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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));
|
||||
|
@ -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;
|
||||
|
20
gcc/stmt.c
20
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 (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);
|
||||
#endif
|
||||
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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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"
|
||||
|
17
gcc/target.h
17
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;
|
||||
|
158
gcc/targhooks.c
Normal file
158
gcc/targhooks.c
Normal file
@ -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
|
||||
}
|
31
gcc/targhooks.h
Normal file
31
gcc/targhooks.h
Normal file
@ -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 *);
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user