From 483ab821df8b418706ca1763088b1f2f9171fc16 Mon Sep 17 00:00:00 2001 From: Mark Mitchell Date: Fri, 18 Oct 2002 23:35:40 +0000 Subject: [PATCH] target-def.h (TARGET_ASM_OUTPUT_MI_THUNK): Default to NULL. * target-def.h (TARGET_ASM_OUTPUT_MI_THUNK): Default to NULL. (TARGET_ASM_OUTPUT_MI_VCALL_THUNK): Likewise. (TARGET_ASM_OUT): Add them. * target.h (asm_out): Add output_mi_thunk and output_mi_vcall_thunk. * config/alpha/alpha.h (ASM_OUTPUT_MI_THUNK): Rename to ... (TARGET_ASM_OUTPUT_MI_THUNK): ... this. * config/arm/arm-protos.h (arm_output_mi_thunk): Declare. * config/arm/arm.c (arm_output_mi_thunk): Define. * config/arm/arm.h (ASM_OUTPUT_MI_THUNK): Rename to ... (TARGET_ASM_OUTPUT_MI_THUNK): ... this. * config/cris/cris.h (ASM_OUTPUT_MI_THUNK): Rename to ... (TARGET_ASM_OUTPUT_MI_THUNK): ... this. * config/frv/frv.h (ASM_OUTPUT_MI_THUNK): Rename to ... (TARGET_ASM_OUTPUT_MI_THUNK): ... this. * config/i386/i386-protos.h (x86_output_mi_thunk): Adjust prototype. (x86_output_mi_vcall_thunk): Declare. * config/i386/i386.c (override_options): Clear output_mi_vcall_thunk in 64-bit mode. (ix86_fntype_regparm): New function. (ix86_return_pops_args): Use it. (ia32_this_parameter): New function. (x86_output_mi_vcall_thunk): New function. (x86_output_mi_thunk): Use it * config/i386/unix.h (TARGET_ASM_OUTPUT_MI_THUNK): Adjust. (TARGET_ASM_OUTPUT_MI_VCALL_THUNK): Define. * config/i960/i960-protos.h (i960_output_mi_thunk): Declare. * config/i960/i960.c (i960_output_mi_thunk): New function. * config/i960/i960.h (ASM_OUTPUT_MI_THUNK): Adjust. * config/ia64/ia64-protos.h (ia64_output_mi_thunk): Declare. * config/ia64/ia64.c (ia64_output_mi_thunk): Define. * config/ia64/ia64.h (ASM_OUTPUT_MI_THUNK): Rename to ... (TARGET_ASM_OUTPUT_MI_THUNK): ... this. * config/m68k/m68k-protos.h (m68k_output_mi_thunk): New function. * config/m68k/linux.h (ASM_OUTPUT_MI_THUNK): Rename to ... (TARGET_ASM_OUTPUT_MI_THUNK): ... this. * config/m68k/netbsd-elf.h (ASM_OUTPUT_MI_THUNK): Rename to ... (TARGET_ASM_OUTPUT_MI_THUNK): ... this. * config/mmix/mmix.h (ASM_OUTPUT_MI_THUNK): Rename to ... (TARGET_ASM_OUTPUT_MI_THUNK): ... this. * config/pa/pa.h (ASM_OUTPUT_MI_THUNK): Rename to ... (TARGET_ASM_OUTPUT_MI_THUNK): ... this. * config/rs6000/sysv4.h (ASM_OUTPUT_MI_THUNK): Rename to ... (TARGET_ASM_OUTPUT_MI_THUNK): ... this. * config/s390/s390-protos.h (s390_output_mi_thunk): Declare. * config/s390/s390.c (s390_output_mi_thunk): Define. * config/s390/s390.h (ASM_OUTPUT_MI_THUNK): Rename to ... (TARGET_ASM_OUTPUT_MI_THUNK): ... this. * config/sparc/sparc.h (ASM_OUTPUT_MI_THUNK): Rename to ... (TARGET_ASM_OUTPUT_MI_THUNK): ... this. * config/stormy16/stormy16.h (ASM_OUTPUT_MI_THUNK): Rename to ... (TARGET_ASM_OUTPUT_MI_THUNK): ... this. * config/vax/vax-protos.h (vax_output_mi_thunk): Declare. * config/vax/vax.c (vax_output_mi_thunk): Define. * config/vax/vax.h (ASM_OUTPUT_MI_THUNK): Rename to ... (TARGET_ASM_OUTPUT_MI_THUNK): ... this. * doc/tm.texi: Adjust documentation. From-SVN: r58293 --- gcc/ChangeLog | 61 +++++++++++ gcc/config/alpha/alpha.h | 3 +- gcc/config/arm/arm-protos.h | 3 +- gcc/config/arm/arm.c | 35 ++++++ gcc/config/arm/arm.h | 31 +----- gcc/config/cris/cris.h | 3 +- gcc/config/frv/frv.h | 3 +- gcc/config/i386/i386-protos.h | 3 +- gcc/config/i386/i386.c | 146 ++++++++++++++++++++------ gcc/config/i386/unix.h | 6 +- gcc/config/i960/i960-protos.h | 1 + gcc/config/i960/i960.c | 22 ++++ gcc/config/i960/i960.h | 17 +-- gcc/config/ia64/ia64-protos.h | 3 +- gcc/config/ia64/ia64.c | 35 ++++++ gcc/config/ia64/ia64.h | 30 +----- gcc/config/m68k/linux.h | 23 +--- gcc/config/m68k/m68k-protos.h | 6 +- gcc/config/m68k/m68k.c | 28 +++++ gcc/config/m68k/netbsd-elf.h | 26 +---- gcc/config/mmix/mmix.h | 3 +- gcc/config/pa/pa.h | 3 +- gcc/config/rs6000/sysv4.h | 3 +- gcc/config/s390/s390-protos.h | 3 +- gcc/config/s390/s390.c | 75 +++++++++++++ gcc/config/s390/s390.h | 71 +------------ gcc/config/sparc/sparc.h | 3 +- gcc/config/stormy16/stormy16.h | 3 +- gcc/config/vax/vax-protos.h | 3 +- gcc/config/vax/vax.c | 14 +++ gcc/config/vax/vax.h | 9 +- gcc/cp/ChangeLog | 6 ++ gcc/cp/Make-lang.in | 2 +- gcc/cp/method.c | 26 +++-- gcc/doc/tm.texi | 27 ++++- gcc/target-def.h | 12 ++- gcc/target.h | 7 ++ gcc/testsuite/g++.dg/inherit/thunk1.C | 41 ++++++++ 38 files changed, 527 insertions(+), 269 deletions(-) create mode 100644 gcc/testsuite/g++.dg/inherit/thunk1.C diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 5ca6ddd6bf0..1fb2af10072 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,64 @@ +2002-10-18 Mark Mitchell + + * target-def.h (TARGET_ASM_OUTPUT_MI_THUNK): Default to NULL. + (TARGET_ASM_OUTPUT_MI_VCALL_THUNK): Likewise. + (TARGET_ASM_OUT): Add them. + * target.h (asm_out): Add output_mi_thunk and + output_mi_vcall_thunk. + * config/alpha/alpha.h (ASM_OUTPUT_MI_THUNK): Rename to ... + (TARGET_ASM_OUTPUT_MI_THUNK): ... this. + * config/arm/arm-protos.h (arm_output_mi_thunk): Declare. + * config/arm/arm.c (arm_output_mi_thunk): Define. + * config/arm/arm.h (ASM_OUTPUT_MI_THUNK): Rename to ... + (TARGET_ASM_OUTPUT_MI_THUNK): ... this. + * config/cris/cris.h (ASM_OUTPUT_MI_THUNK): Rename to ... + (TARGET_ASM_OUTPUT_MI_THUNK): ... this. + * config/frv/frv.h (ASM_OUTPUT_MI_THUNK): Rename to ... + (TARGET_ASM_OUTPUT_MI_THUNK): ... this. + * config/i386/i386-protos.h (x86_output_mi_thunk): Adjust + prototype. + (x86_output_mi_vcall_thunk): Declare. + * config/i386/i386.c (override_options): Clear + output_mi_vcall_thunk in 64-bit mode. + (ix86_fntype_regparm): New function. + (ix86_return_pops_args): Use it. + (ia32_this_parameter): New function. + (x86_output_mi_vcall_thunk): New function. + (x86_output_mi_thunk): Use it + * config/i386/unix.h (TARGET_ASM_OUTPUT_MI_THUNK): Adjust. + (TARGET_ASM_OUTPUT_MI_VCALL_THUNK): Define. + * config/i960/i960-protos.h (i960_output_mi_thunk): Declare. + * config/i960/i960.c (i960_output_mi_thunk): New function. + * config/i960/i960.h (ASM_OUTPUT_MI_THUNK): Adjust. + * config/ia64/ia64-protos.h (ia64_output_mi_thunk): Declare. + * config/ia64/ia64.c (ia64_output_mi_thunk): Define. + * config/ia64/ia64.h (ASM_OUTPUT_MI_THUNK): Rename to ... + (TARGET_ASM_OUTPUT_MI_THUNK): ... this. + * config/m68k/m68k-protos.h (m68k_output_mi_thunk): New function. + * config/m68k/linux.h (ASM_OUTPUT_MI_THUNK): Rename to ... + (TARGET_ASM_OUTPUT_MI_THUNK): ... this. + * config/m68k/netbsd-elf.h (ASM_OUTPUT_MI_THUNK): Rename to ... + (TARGET_ASM_OUTPUT_MI_THUNK): ... this. + * config/mmix/mmix.h (ASM_OUTPUT_MI_THUNK): Rename to ... + (TARGET_ASM_OUTPUT_MI_THUNK): ... this. + * config/pa/pa.h (ASM_OUTPUT_MI_THUNK): Rename to ... + (TARGET_ASM_OUTPUT_MI_THUNK): ... this. + * config/rs6000/sysv4.h (ASM_OUTPUT_MI_THUNK): Rename to ... + (TARGET_ASM_OUTPUT_MI_THUNK): ... this. + * config/s390/s390-protos.h (s390_output_mi_thunk): Declare. + * config/s390/s390.c (s390_output_mi_thunk): Define. + * config/s390/s390.h (ASM_OUTPUT_MI_THUNK): Rename to ... + (TARGET_ASM_OUTPUT_MI_THUNK): ... this. + * config/sparc/sparc.h (ASM_OUTPUT_MI_THUNK): Rename to ... + (TARGET_ASM_OUTPUT_MI_THUNK): ... this. + * config/stormy16/stormy16.h (ASM_OUTPUT_MI_THUNK): Rename to ... + (TARGET_ASM_OUTPUT_MI_THUNK): ... this. + * config/vax/vax-protos.h (vax_output_mi_thunk): Declare. + * config/vax/vax.c (vax_output_mi_thunk): Define. + * config/vax/vax.h (ASM_OUTPUT_MI_THUNK): Rename to ... + (TARGET_ASM_OUTPUT_MI_THUNK): ... this. + * doc/tm.texi: Adjust documentation. + 2002-10-18 Jason Thorpe * config/netbsd.h (NETBSD_ENABLE_EXECUTE_STACK): Define diff --git a/gcc/config/alpha/alpha.h b/gcc/config/alpha/alpha.h index 0b70284d599..461dc959c8e 100644 --- a/gcc/config/alpha/alpha.h +++ b/gcc/config/alpha/alpha.h @@ -2141,5 +2141,4 @@ do { \ /* Output code to add DELTA to the first argument, and then jump to FUNCTION. Used for C++ multiple inheritance. */ -#define ASM_OUTPUT_MI_THUNK(FILE, THUNK_FNDECL, DELTA, FUNCTION) \ - alpha_output_mi_thunk_osf (FILE, THUNK_FNDECL, DELTA, FUNCTION) +#define TARGET_ASM_OUTPUT_MI_THUNK alpha_output_mi_thunk_osf diff --git a/gcc/config/arm/arm-protos.h b/gcc/config/arm/arm-protos.h index b4e65c24d93..eac8dbbbb41 100644 --- a/gcc/config/arm/arm-protos.h +++ b/gcc/config/arm/arm-protos.h @@ -1,5 +1,5 @@ /* Prototypes for exported functions defined in arm.c and pe.c - Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc. + Copyright (C) 1999, 2000, 2001, 2002 Free Software Foundation, Inc. Contributed by Richard Earnshaw (rearnsha@arm.com) Minor hacks by Nick Clifton (nickc@cygnus.com) @@ -194,6 +194,7 @@ extern int arm_dllexport_p PARAMS ((tree)); extern int arm_dllimport_p PARAMS ((tree)); extern void arm_mark_dllexport PARAMS ((tree)); extern void arm_mark_dllimport PARAMS ((tree)); +extern void arm_output_mi_thunk PARAMS ((FILE *, tree, int, tree)); #endif extern void arm_init_builtins PARAMS ((void)); diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c index 23b90432149..6971a53b2d9 100644 --- a/gcc/config/arm/arm.c +++ b/gcc/config/arm/arm.c @@ -11130,3 +11130,38 @@ arm_encode_section_info (decl, first) } } #endif /* !ARM_PE */ + +void +arm_output_mi_thunk (file, thunk, delta, function) + FILE *file; + tree thunk ATTRIBUTE_UNUSED; + int delta; + tree function; +{ + 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))) + ? 1 : 0); + if (mi_delta < 0) + mi_delta = - mi_delta; + while (mi_delta != 0) + { + if ((mi_delta & (3 << shift)) == 0) + shift += 2; + else + { + asm_fprintf (file, "\t%s\t%r, %r, #%d\n", + mi_op, this_regno, this_regno, + mi_delta & (0xff << shift)); + mi_delta &= ~(0xff << shift); + shift += 8; + } + } + fputs ("\tb\t", file); + assemble_name (file, XSTR (XEXP (DECL_RTL (function), 0), 0)); + if (NEED_PLT_RELOC) + fputs ("(PLT)", file); + fputc ('\n', file); +} + diff --git a/gcc/config/arm/arm.h b/gcc/config/arm/arm.h index 3b3e38a629b..b4f6e705aa6 100644 --- a/gcc/config/arm/arm.h +++ b/gcc/config/arm/arm.h @@ -2697,36 +2697,7 @@ extern int making_const_table; /* Output code to add DELTA to the first argument, and then jump to FUNCTION. Used for C++ multiple inheritance. */ -#define ASM_OUTPUT_MI_THUNK(FILE, THUNK_FNDECL, DELTA, FUNCTION) \ - do \ - { \ - 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))) \ - ? 1 : 0); \ - if (mi_delta < 0) \ - mi_delta = - mi_delta; \ - while (mi_delta != 0) \ - { \ - if ((mi_delta & (3 << shift)) == 0) \ - shift += 2; \ - else \ - { \ - asm_fprintf (FILE, "\t%s\t%r, %r, #%d\n", \ - mi_op, this_regno, this_regno, \ - mi_delta & (0xff << shift)); \ - mi_delta &= ~(0xff << shift); \ - shift += 8; \ - } \ - } \ - fputs ("\tb\t", FILE); \ - assemble_name (FILE, XSTR (XEXP (DECL_RTL (FUNCTION), 0), 0)); \ - if (NEED_PLT_RELOC) \ - fputs ("(PLT)", FILE); \ - fputc ('\n', FILE); \ - } \ - while (0) +#define TARGET_ASM_OUTPUT_MI_THUNK arm_output_mi_thunk /* A C expression whose value is RTL representing the value of the return address for the frame COUNT steps up from the current frame. */ diff --git a/gcc/config/cris/cris.h b/gcc/config/cris/cris.h index ddf84e53c7f..717f2497928 100644 --- a/gcc/config/cris/cris.h +++ b/gcc/config/cris/cris.h @@ -1013,8 +1013,7 @@ struct cum_args {int regs;}; #define ELIGIBLE_FOR_EPILOGUE_DELAY(INSN, N) \ cris_eligible_for_epilogue_delay (INSN) -#define ASM_OUTPUT_MI_THUNK(FILE, THUNK_FNDECL, DELTA, FUNCTION) \ - cris_asm_output_mi_thunk(FILE, THUNK_FNDECL, DELTA, FUNCTION) +#define TARGET_ASM_OUTPUT_MI_THUNK cris_asm_output_mi_thunk /* Node: Profiling */ diff --git a/gcc/config/frv/frv.h b/gcc/config/frv/frv.h index f5fe93ee0b6..8fc43a46879 100644 --- a/gcc/config/frv/frv.h +++ b/gcc/config/frv/frv.h @@ -2110,8 +2110,7 @@ struct machine_function GTY(()) frontend will generate a less efficient heavyweight thunk that calls FUNCTION instead of jumping to it. The generic approach does not support varargs. */ -#define ASM_OUTPUT_MI_THUNK(FILE, THUNK_FNDECL, DELTA, FUNCTION) \ -frv_asm_output_mi_thunk (FILE, THUNK_FNDECL, (long)DELTA, FUNCTION) +#define TARGET_ASM_OUTPUT_MI_THUNK frv_asm_output_mi_thunk /* Generating Code for Profiling. */ diff --git a/gcc/config/i386/i386-protos.h b/gcc/config/i386/i386-protos.h index f0bdf22cf6a..c3b7c308349 100644 --- a/gcc/config/i386/i386-protos.h +++ b/gcc/config/i386/i386-protos.h @@ -211,7 +211,8 @@ extern tree ix86_handle_shared_attribute PARAMS ((tree *, tree, tree, int, bool extern unsigned int i386_pe_section_type_flags PARAMS ((tree, const char *, int)); extern void i386_pe_asm_named_section PARAMS ((const char *, unsigned int)); -extern void x86_output_mi_thunk PARAMS ((FILE *, int, tree)); +extern void x86_output_mi_thunk PARAMS ((FILE *, tree, int, tree)); +extern void x86_output_mi_vcall_thunk PARAMS ((FILE *, tree, int, int, tree)); extern int x86_field_alignment PARAMS ((tree, int)); #endif diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index 1ea90ee860f..c96270241d1 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -750,6 +750,7 @@ static int ix86_variable_issue PARAMS ((FILE *, int, rtx, int)); static int ia32_use_dfa_pipeline_interface PARAMS ((void)); static int ia32_multipass_dfa_lookahead PARAMS ((void)); static void ix86_init_mmx_sse_builtins PARAMS ((void)); +static rtx ia32_this_parameter PARAMS ((tree)); struct ix86_address { @@ -788,6 +789,7 @@ static unsigned int ix86_select_alt_pic_regnum PARAMS ((void)); static int ix86_save_reg PARAMS ((unsigned int, int)); static void ix86_compute_frame_layout PARAMS ((struct ix86_frame *)); static int ix86_comp_type_attributes PARAMS ((tree, tree)); +static int ix86_fntype_regparm PARAMS ((tree)); const struct attribute_spec ix86_attribute_table[]; static tree ix86_handle_cdecl_attribute PARAMS ((tree *, tree, tree, int, bool *)); static tree ix86_handle_regparm_attribute PARAMS ((tree *, tree, tree, int, bool *)); @@ -1295,6 +1297,10 @@ override_options () internal_label_prefix_len = p - internal_label_prefix; *p = '\0'; } + + /* In 64-bit mode, we do not have support for vcall thunks. */ + if (TARGET_64BIT) + targetm.asm_out.output_mi_vcall_thunk = NULL; } void @@ -1431,6 +1437,21 @@ ix86_comp_type_attributes (type1, type2) return 1; } +/* Return the regparm value for a fuctio with the indicated TYPE. */ + +static int +ix86_fntype_regparm (type) + tree type; +{ + tree attr; + + attr = lookup_attribute ("regparm", TYPE_ATTRIBUTES (type)); + if (attr) + return TREE_INT_CST_LOW (TREE_VALUE (TREE_VALUE (attr))); + else + return ix86_regparm; +} + /* Value is the number of bytes of arguments automatically popped when returning from a subroutine call. FUNDECL is the declaration node of the function (as a tree), @@ -1474,15 +1495,7 @@ ix86_return_pops_args (fundecl, funtype, size) if (aggregate_value_p (TREE_TYPE (funtype)) && !TARGET_64BIT) { - int nregs = ix86_regparm; - - if (funtype) - { - tree attr = lookup_attribute ("regparm", TYPE_ATTRIBUTES (funtype)); - - if (attr) - nregs = TREE_INT_CST_LOW (TREE_VALUE (TREE_VALUE (attr))); - } + int nregs = ix86_fntype_regparm (funtype); if (!nregs) return GET_MODE_SIZE (Pmode); @@ -13860,27 +13873,51 @@ x86_order_regs_for_local_alloc () reg_alloc_order [pos++] = 0; } -void -x86_output_mi_thunk (file, delta, function) - FILE *file; - int delta; +/* Returns an expression indicating where the this parameter is + located on entry to the FUNCTION. */ + +static rtx +ia32_this_parameter (function) + tree function; +{ + tree type = TREE_TYPE (function); + + if (ix86_fntype_regparm (type) > 0) + { + tree parm; + + parm = TYPE_ARG_TYPES (type); + /* Figure out whether or not the function has a variable number of + arguments. */ + for (; parm; parm = TREE_CHAIN (parm))\ + if (TREE_VALUE (parm) == void_type_node) + break; + /* If not, the this parameter is in %eax. */ + if (parm) + return gen_rtx_REG (SImode, 0); + } + + if (aggregate_value_p (TREE_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)); +} + + +void +x86_output_mi_vcall_thunk (file, thunk, delta, vcall_index, function) + FILE *file; + tree thunk ATTRIBUTE_UNUSED; + int delta; + int vcall_index; tree function; { - tree parm; rtx xops[3]; - if (ix86_regparm > 0) - parm = TYPE_ARG_TYPES (TREE_TYPE (function)); - else - parm = NULL_TREE; - for (; parm; parm = TREE_CHAIN (parm)) - if (TREE_VALUE (parm) == void_type_node) - break; - - xops[0] = GEN_INT (delta); if (TARGET_64BIT) { int n = aggregate_value_p (TREE_TYPE (TREE_TYPE (function))) != 0; + xops[0] = GEN_INT (delta); xops[1] = gen_rtx_REG (DImode, x86_64_int_parameter_registers[n]); output_asm_insn ("add{q} {%0, %1|%1, %0}", xops); if (flag_pic) @@ -13898,13 +13935,49 @@ x86_output_mi_thunk (file, delta, function) } else { - if (parm) - xops[1] = gen_rtx_REG (SImode, 0); - else if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)))) - xops[1] = gen_rtx_MEM (SImode, plus_constant (stack_pointer_rtx, 8)); - else - xops[1] = gen_rtx_MEM (SImode, plus_constant (stack_pointer_rtx, 4)); - output_asm_insn ("add{l} {%0, %1|%1, %0}", xops); + /* Adjust the this parameter by a fixed constant. */ + if (delta) + { + xops[0] = GEN_INT (delta); + xops[1] = ia32_this_parameter (function); + output_asm_insn ("add{l}\t{%0, %1|%1, %0}", xops); + } + + /* Adjust the this parameter by a value stored in the vtable. */ + if (vcall_index) + { + rtx this_parm; + + /* Put the this parameter into %eax. */ + this_parm = ia32_this_parameter (function); + if (!REG_P (this_parm)) + { + xops[0] = this_parm; + xops[1] = gen_rtx_REG (Pmode, 0); + output_asm_insn ("mov{l}\t{%0, %1|%1, %0}", xops); + } + /* Load the virtual table pointer into %edx. */ + if (ix86_fntype_regparm (TREE_TYPE (function)) > 2) + error ("virtual function `%D' cannot have more than two register parameters", + function); + xops[0] = gen_rtx_MEM (Pmode, + gen_rtx_REG (Pmode, 0)); + xops[1] = gen_rtx_REG (Pmode, 1); + output_asm_insn ("mov{l}\t{%0, %1|%1, %0}", xops); + /* Adjust the this parameter. */ + xops[0] = gen_rtx_MEM (SImode, + plus_constant (gen_rtx_REG (Pmode, 1), + vcall_index)); + xops[1] = gen_rtx_REG (Pmode, 0); + output_asm_insn ("add{l}\t{%0, %1|%1, %0}", xops); + /* Put the this parameter back where it came from. */ + if (!REG_P (this_parm)) + { + xops[0] = gen_rtx_REG (Pmode, 0); + xops[1] = ia32_this_parameter (function); + output_asm_insn ("mov{l}\t{%0, %1|%1, %0}", xops); + } + } if (flag_pic) { @@ -13928,13 +14001,24 @@ x86_output_mi_thunk (file, delta, function) } else { - fprintf (file, "\tjmp "); + fprintf (file, "\tjmp\t"); assemble_name (file, XSTR (XEXP (DECL_RTL (function), 0), 0)); fprintf (file, "\n"); } } } +void +x86_output_mi_thunk (file, thunk, delta, function) + FILE *file; + tree thunk; + int delta; + tree function; +{ + x86_output_mi_vcall_thunk (file, thunk, delta, /*vcall_index=*/0, + function); +} + int x86_field_alignment (field, computed) tree field; diff --git a/gcc/config/i386/unix.h b/gcc/config/i386/unix.h index 3ba1bd5da7d..09493b08808 100644 --- a/gcc/config/i386/unix.h +++ b/gcc/config/i386/unix.h @@ -1,5 +1,5 @@ /* Definitions for Unix assembler syntax for the Intel 80386. - Copyright (C) 1988, 1994, 1999, 2000, 2001 Free Software Foundation, Inc. + Copyright (C) 1988, 1994, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. This file is part of GNU CC. @@ -68,5 +68,5 @@ Boston, MA 02111-1307, USA. */ /* Output code to add DELTA to the first argument, and then jump to FUNCTION. Used for C++ multiple inheritance. */ -#define ASM_OUTPUT_MI_THUNK(FILE, THUNK_FNDECL, DELTA, FUNCTION) \ - x86_output_mi_thunk (FILE, DELTA, FUNCTION); +#define TARGET_ASM_OUTPUT_MI_THUNK x86_output_mi_thunk +#define TARGET_ASM_OUTPUT_MI_VCALL_THUNK x86_output_mi_vcall_thunk diff --git a/gcc/config/i960/i960-protos.h b/gcc/config/i960/i960-protos.h index 7e2685d9f09..b7b74dc0130 100644 --- a/gcc/config/i960/i960-protos.h +++ b/gcc/config/i960/i960-protos.h @@ -86,6 +86,7 @@ extern void i960_setup_incoming_varargs PARAMS ((CUMULATIVE_ARGS *, enum machine extern tree i960_build_va_list PARAMS ((void)); extern int i960_final_reg_parm_stack_space PARAMS ((int, tree)); extern int i960_reg_parm_stack_space PARAMS ((tree)); +extern void i960_output_mi_thunk PARAMS ((FILE *, tree, int, tree)); #endif /* TREE_CODE */ extern int process_pragma PARAMS ((int(*)(void), void(*)(int), const char *)); diff --git a/gcc/config/i960/i960.c b/gcc/config/i960/i960.c index 4917ae22981..fe38d45c5a2 100644 --- a/gcc/config/i960/i960.c +++ b/gcc/config/i960/i960.c @@ -2824,3 +2824,25 @@ i960_scan_opcode (p) break; } } + +void +i960_output_mi_thunk (file, thunk, delta, function) + FILE *file; + tree thunk ATTRIBUTE_UNUSED; + int delta; + tree function; +{ + int d = delta; + if (d < 0 && d > -32) + fprintf (file, "\tsubo %d,g0,g0\n", -d); + else if (d > 0 && d < 32) + fprintf (file, "\taddo %d,g0,g0\n", d); + else + { + fprintf (file, "\tldconst %d,r5\n", d); + fprintf (file, "\taddo r5,g0,g0\n"); + } + fprintf (file, "\tbx "); + assemble_name (file, XSTR (XEXP (DECL_RTL (function), 0), 0)); + fprintf (file, "\n"); +} diff --git a/gcc/config/i960/i960.h b/gcc/config/i960/i960.h index ee27398300d..11932e967f8 100644 --- a/gcc/config/i960/i960.h +++ b/gcc/config/i960/i960.h @@ -1466,19 +1466,4 @@ extern int rtx_equal_function_value_matters; /* Output code to add DELTA to the first argument, and then jump to FUNCTION. Used for C++ multiple inheritance. */ -#define ASM_OUTPUT_MI_THUNK(FILE, THUNK_FNDECL, DELTA, FUNCTION) \ -do { \ - int d = (DELTA); \ - if (d < 0 && d > -32) \ - fprintf (FILE, "\tsubo %d,g0,g0\n", -d); \ - else if (d > 0 && d < 32) \ - fprintf (FILE, "\taddo %d,g0,g0\n", d); \ - else \ - { \ - fprintf (FILE, "\tldconst %d,r5\n", d); \ - fprintf (FILE, "\taddo r5,g0,g0\n"); \ - } \ - fprintf (FILE, "\tbx "); \ - assemble_name (FILE, XSTR (XEXP (DECL_RTL (FUNCTION), 0), 0)); \ - fprintf (FILE, "\n"); \ -} while (0); +#define ASM_OUTPUT_MI_THUNK i960_output_mi_thunk diff --git a/gcc/config/ia64/ia64-protos.h b/gcc/config/ia64/ia64-protos.h index 0e0ef04f055..6efb266a83b 100644 --- a/gcc/config/ia64/ia64-protos.h +++ b/gcc/config/ia64/ia64-protos.h @@ -1,5 +1,5 @@ /* Definitions of target machine for GNU compiler for IA-64. - Copyright (C) 1999, 2000 Free Software Foundation, Inc. + Copyright (C) 1999, 2000, 2002 Free Software Foundation, Inc. This file is part of GNU CC. @@ -121,6 +121,7 @@ extern int ia64_function_arg_pass_by_reference PARAMS((CUMULATIVE_ARGS *, tree, int)); extern int ia64_return_in_memory PARAMS((tree)); extern void ia64_asm_output_external PARAMS((FILE *, tree, const char *)); +extern void ia64_output_mi_thunk PARAMS((FILE *, tree, int, tree)); #endif /* TREE_CODE */ extern int ia64_register_move_cost PARAMS((enum machine_mode, enum reg_class, diff --git a/gcc/config/ia64/ia64.c b/gcc/config/ia64/ia64.c index bcfcc321039..5fa9927f157 100644 --- a/gcc/config/ia64/ia64.c +++ b/gcc/config/ia64/ia64.c @@ -8159,4 +8159,39 @@ ia64_aix_select_rtx_section (mode, x, align) flag_pic = save_pic; } +void +ia64_output_mi_thunk (file, thunk, delta, function) + FILE *file; + tree thunk ATTRIBUTE_UNUSED; + int delta; + tree function; +{ + if (CONST_OK_FOR_I (delta)) + { + fprintf (file, "\tadds r32 = "); + fprintf (file, HOST_WIDE_INT_PRINT_DEC, (delta)); + fprintf (file, ", r32\n"); + } + else + { + if (CONST_OK_FOR_J (delta)) + { + fprintf (file, "\taddl r2 = "); + fprintf (file, HOST_WIDE_INT_PRINT_DEC, (delta)); + fprintf (file, ", r0\n"); + } + else + { + fprintf (file, "\tmovl r2 = "); + fprintf (file, HOST_WIDE_INT_PRINT_DEC, (delta)); + fprintf (file, "\n"); + } + fprintf (file, "\t;;\n"); + fprintf (file, "\tadd r32 = r2, r32\n"); + } + fprintf (file, "\tbr "); + assemble_name (file, XSTR (XEXP (DECL_RTL (function), 0), 0)); + fprintf (file, "\n"); +} + #include "gt-ia64.h" diff --git a/gcc/config/ia64/ia64.h b/gcc/config/ia64/ia64.h index 1d96eafc8ec..e0d52480093 100644 --- a/gcc/config/ia64/ia64.h +++ b/gcc/config/ia64/ia64.h @@ -1431,35 +1431,7 @@ do { \ /* A C compound statement that outputs the assembler code for a thunk function, used to implement C++ virtual function calls with multiple inheritance. */ -#define ASM_OUTPUT_MI_THUNK(FILE, THUNK_FNDECL, DELTA, FUNCTION) \ -do { \ - if (CONST_OK_FOR_I (DELTA)) \ - { \ - fprintf (FILE, "\tadds r32 = "); \ - fprintf (FILE, HOST_WIDE_INT_PRINT_DEC, (DELTA)); \ - fprintf (FILE, ", r32\n"); \ - } \ - else \ - { \ - if (CONST_OK_FOR_J (DELTA)) \ - { \ - fprintf (FILE, "\taddl r2 = "); \ - fprintf (FILE, HOST_WIDE_INT_PRINT_DEC, (DELTA)); \ - fprintf (FILE, ", r0\n"); \ - } \ - else \ - { \ - fprintf (FILE, "\tmovl r2 = "); \ - fprintf (FILE, HOST_WIDE_INT_PRINT_DEC, (DELTA)); \ - fprintf (FILE, "\n"); \ - } \ - fprintf (FILE, "\t;;\n"); \ - fprintf (FILE, "\tadd r32 = r2, r32\n"); \ - } \ - fprintf (FILE, "\tbr "); \ - assemble_name (FILE, XSTR (XEXP (DECL_RTL (FUNCTION), 0), 0)); \ - fprintf (FILE, "\n"); \ -} while (0) +#define TARGET_ASM_OUTPUT_MI_THUNK ia64_output_mi_thunk /* Output part N of a function descriptor for DECL. For ia64, both words are emitted with a single relocation, so ignore N > 0. */ diff --git a/gcc/config/m68k/linux.h b/gcc/config/m68k/linux.h index 2778d27f5f7..ce2fbb089f0 100644 --- a/gcc/config/m68k/linux.h +++ b/gcc/config/m68k/linux.h @@ -357,25 +357,4 @@ do { \ /* Output code to add DELTA to the first argument, and then jump to FUNCTION. Used for C++ multiple inheritance. */ -#define ASM_OUTPUT_MI_THUNK(FILE, THUNK_FNDECL, DELTA, FUNCTION) \ -do { \ - if (DELTA > 0 && DELTA <= 8) \ - asm_fprintf (FILE, "\taddq.l %I%d,4(%Rsp)\n", DELTA); \ - else if (DELTA < 0 && DELTA >= -8) \ - asm_fprintf (FILE, "\tsubq.l %I%d,4(%Rsp)\n", -DELTA); \ - else \ - asm_fprintf (FILE, "\tadd.l %I%d,4(%Rsp)\n", DELTA); \ - \ - if (flag_pic) \ - { \ - fprintf (FILE, "\tbra.l "); \ - assemble_name (FILE, XSTR (XEXP (DECL_RTL (FUNCTION), 0), 0)); \ - fprintf (FILE, "@PLTPC\n"); \ - } \ - else \ - { \ - fprintf (FILE, "\tjmp "); \ - assemble_name (FILE, XSTR (XEXP (DECL_RTL (FUNCTION), 0), 0)); \ - fprintf (FILE, "\n"); \ - } \ -} while (0) +#define TARGET_ASM_OUTPUT_MI_THUNK m68k_output_mi_thunk diff --git a/gcc/config/m68k/m68k-protos.h b/gcc/config/m68k/m68k-protos.h index 6a132beeb62..33accb90b7f 100644 --- a/gcc/config/m68k/m68k-protos.h +++ b/gcc/config/m68k/m68k-protos.h @@ -1,5 +1,5 @@ /* Definitions of target machine for GNU compiler. Sun 68000/68020 version. - Copyright (C) 2000 Free Software Foundation, Inc. + Copyright (C) 2000, 2002 Free Software Foundation, Inc. This file is part of GNU CC. @@ -64,6 +64,10 @@ extern int pcrel_address PARAMS ((rtx, enum machine_mode)); extern rtx legitimize_pic_address PARAMS ((rtx, enum machine_mode, rtx)); #endif /* RTX_CODE */ +#ifdef TREE_CODE +extern void m68k_output_mi_thunk PARAMS ((FILE *, tree, int, tree)); +#endif /* TREE_CODE */ + extern int flags_in_68881 PARAMS ((void)); extern int use_return_insn PARAMS ((void)); extern void override_options PARAMS ((void)); diff --git a/gcc/config/m68k/m68k.c b/gcc/config/m68k/m68k.c index fc635fb9aa8..8a1a7292838 100644 --- a/gcc/config/m68k/m68k.c +++ b/gcc/config/m68k/m68k.c @@ -3835,3 +3835,31 @@ m68k_svr3_asm_out_constructor (symbol, priority) output_asm_insn (output_move_simode (xop), xop); } #endif + +void +m68k_output_mi_thunk (file, thunk, delta, function) + FILE *file; + tree thunk ATTRIBUTE_UNUSED; + int delta; + tree function; +{ + if (delta > 0 && delta <= 8) + asm_fprintf (file, "\taddq.l %I%d,4(%Rsp)\n", delta); + else if (delta < 0 && delta >= -8) + asm_fprintf (file, "\tsubq.l %I%d,4(%Rsp)\n", -delta); + else + asm_fprintf (file, "\tadd.l %I%d,4(%Rsp)\n", delta); + + if (flag_pic) + { + fprintf (file, "\tbra.l "); + assemble_name (file, XSTR (XEXP (DECL_RTL (function), 0), 0)); + fprintf (file, "@PLTPC\n"); + } + else + { + fprintf (file, "\tjmp "); + assemble_name (file, XSTR (XEXP (DECL_RTL (function), 0), 0)); + fprintf (file, "\n"); + } +} diff --git a/gcc/config/m68k/netbsd-elf.h b/gcc/config/m68k/netbsd-elf.h index 078cd14982b..107bdeb03df 100644 --- a/gcc/config/m68k/netbsd-elf.h +++ b/gcc/config/m68k/netbsd-elf.h @@ -425,31 +425,7 @@ while (0) /* Output code to add DELTA to the first argument, and then jump to FUNCTION. Used for C++ multiple inheritance. */ -#define ASM_OUTPUT_MI_THUNK(FILE, THUNK_FNDECL, DELTA, FUNCTION) \ -do \ - { \ - if (DELTA > 0 && DELTA <= 8) \ - asm_fprintf (FILE, "\taddq.l %I%d,4(%Rsp)\n", DELTA); \ - else if (DELTA < 0 && DELTA >= -8) \ - asm_fprintf (FILE, "\tsubq.l %I%d,4(%Rsp)\n", -DELTA); \ - else \ - asm_fprintf (FILE, "\tadd.l %I%d,4(%Rsp)\n", DELTA); \ - \ - if (flag_pic) \ - { \ - fprintf (FILE, "\tbra.l "); \ - assemble_name (FILE, XSTR (XEXP (DECL_RTL (FUNCTION), 0), 0)); \ - fprintf (FILE, "@PLTPC\n"); \ - } \ - else \ - { \ - fprintf (FILE, "\tjmp "); \ - assemble_name (FILE, XSTR (XEXP (DECL_RTL (FUNCTION), 0), 0)); \ - fprintf (FILE, "\n"); \ - } \ - } \ -while (0) - +#define TARGET_ASM_OUTPUT_MI_THUNK m68k_output_mi_thunk /* Output assembler code for a block containing the constant parts of a trampoline, leaving space for the variable parts. */ diff --git a/gcc/config/mmix/mmix.h b/gcc/config/mmix/mmix.h index e3d22d6a0e6..8001f0af78e 100644 --- a/gcc/config/mmix/mmix.h +++ b/gcc/config/mmix/mmix.h @@ -795,8 +795,7 @@ typedef struct { int regs; int lib; } CUMULATIVE_ARGS; #define EPILOGUE_USES(REGNO) \ ((REGNO) == MMIX_INCOMING_RETURN_ADDRESS_REGNUM) -#define ASM_OUTPUT_MI_THUNK(FILE, THUNK_FNDECL, DELTA, FUNCTION) \ - mmix_asm_output_mi_thunk (FILE, THUNK_FNDECL, DELTA, FUNCTION) +#define TARGET_ASM_OUTPUT_MI_THUNK mmix_asm_output_mi_thunk /* Node: Profiling */ diff --git a/gcc/config/pa/pa.h b/gcc/config/pa/pa.h index e284210c96d..003838c6440 100644 --- a/gcc/config/pa/pa.h +++ b/gcc/config/pa/pa.h @@ -897,8 +897,7 @@ extern GTY(()) rtx hppa_compare_op0; extern GTY(()) rtx hppa_compare_op1; extern enum cmp_type hppa_branch_type; -#define ASM_OUTPUT_MI_THUNK(FILE, THUNK_FNDECL, DELTA, FUNCTION) \ - pa_asm_output_mi_thunk (FILE, THUNK_FNDECL, DELTA, FUNCTION) +#define TARGET_ASM_OUTPUT_MI_THUNK pa_asm_output_mi_thunk /* On HPPA, we emit profiling code as rtl via PROFILE_HOOK rather than as assembly via FUNCTION_PROFILER. Just output a local label. diff --git a/gcc/config/rs6000/sysv4.h b/gcc/config/rs6000/sysv4.h index 56aa702aa9f..d393c8e653c 100644 --- a/gcc/config/rs6000/sysv4.h +++ b/gcc/config/rs6000/sysv4.h @@ -667,8 +667,7 @@ extern int rs6000_pic_labelno; FUNCTION instead of jumping to it. The generic approach does not support varargs. */ -#define ASM_OUTPUT_MI_THUNK(FILE, THUNK_FNDECL, DELTA, FUNCTION) \ - output_mi_thunk (FILE, THUNK_FNDECL, DELTA, FUNCTION) +#define TARGET_ASM_OUTPUT_MI_THUNK output_mi_thunk /* The USER_LABEL_PREFIX stuff is affected by the -fleading-underscore flag. The LOCAL_LABEL_PREFIX variable is used by dbxelf.h. */ diff --git a/gcc/config/s390/s390-protos.h b/gcc/config/s390/s390-protos.h index aaf25d0330e..a906d446333 100644 --- a/gcc/config/s390/s390-protos.h +++ b/gcc/config/s390/s390-protos.h @@ -1,5 +1,5 @@ /* Definitions of target machine for GNU compiler, for IBM S/390. - Copyright (C) 2000 Free Software Foundation, Inc. + Copyright (C) 2000, 2002 Free Software Foundation, Inc. Contributed by Hartmut Penner (hpenner@de.ibm.com) This file is part of GNU CC. @@ -86,6 +86,7 @@ extern tree s390_build_va_list PARAMS ((void)); extern rtx s390_function_arg PARAMS ((CUMULATIVE_ARGS *, enum machine_mode, tree, int)); extern void s390_va_start PARAMS ((tree, rtx)); extern rtx s390_va_arg PARAMS ((tree, tree)); +extern void s390_output_mi_thunk PARAMS ((FILE *, tree, int, tree)); #endif /* RTX_CODE */ #endif /* TREE_CODE */ diff --git a/gcc/config/s390/s390.c b/gcc/config/s390/s390.c index b785b0b6317..f7404bc7ba7 100644 --- a/gcc/config/s390/s390.c +++ b/gcc/config/s390/s390.c @@ -5582,3 +5582,78 @@ s390_encode_section_info (decl, first) } } } + +void +s390_output_mi_thunk (file, thunk, delta, function) + FILE *file; + tree thunk ATTRIBUTE_UNUSED; + int delta; + tree function; +{ + if (TARGET_64BIT) + { + if (flag_pic) + { + fprintf (file, "\tlarl 1,0f\n"); + fprintf (file, "\tagf %d,0(1)\n", + aggregate_value_p (TREE_TYPE + (TREE_TYPE (function))) ? 3 :2 ); + fprintf (file, "\tlarl 1,"); + assemble_name (file, XSTR (XEXP (DECL_RTL (function), 0), 0)); + fprintf (file, "@GOTENT\n"); + fprintf (file, "\tlg 1,0(1)\n"); + fprintf (file, "\tbr 1\n"); + fprintf (file, "0:\t.long "); + fprintf (file, HOST_WIDE_INT_PRINT_DEC, (delta)); + fprintf (file, "\n"); + } + else + { + fprintf (file, "\tlarl 1,0f\n"); + fprintf (file, "\tagf %d,0(1)\n", + aggregate_value_p (TREE_TYPE + (TREE_TYPE (function))) ? 3 :2 ); + fprintf (file, "\tjg "); + assemble_name (file, XSTR (XEXP (DECL_RTL (function), 0), 0)); + fprintf (file, "\n"); + fprintf (file, "0:\t.long "); + fprintf (file, HOST_WIDE_INT_PRINT_DEC, (delta)); + fprintf (file, "\n"); + } + } + else + { + if (flag_pic) + { + fprintf (file, "\tbras 1,0f\n"); + fprintf (file, "\t.long _GLOBAL_OFFSET_TABLE_-.\n"); + fprintf (file, "\t.long "); + assemble_name (file, XSTR (XEXP (DECL_RTL (function), 0), 0)); + fprintf (file, "@GOT\n"); + fprintf (file, "\t.long "); + fprintf (file, HOST_WIDE_INT_PRINT_DEC, (delta)); + fprintf (file, "\n"); + fprintf (file, "0:\tal %d,8(1)\n", + aggregate_value_p (TREE_TYPE + (TREE_TYPE (function))) ? 3 : 2 ); + fprintf (file, "\tl 0,4(1)\n"); + fprintf (file, "\tal 1,0(1)\n"); + fprintf (file, "\talr 1,0\n"); + fprintf (file, "\tl 1,0(1)\n"); + fprintf (file, "\tbr 1\n"); + } else { + fprintf (file, "\tbras 1,0f\n"); + fprintf (file, "\t.long "); + assemble_name (file, XSTR (XEXP (DECL_RTL (function), 0), 0)); + fprintf (file, "-.\n"); + fprintf (file, "\t.long "); + fprintf (file, HOST_WIDE_INT_PRINT_DEC, (delta)); + fprintf (file, "\n"); + fprintf (file, "0:\tal %d,4(1)\n", + aggregate_value_p (TREE_TYPE + (TREE_TYPE (function))) ? 3 : 2 ); + fprintf (file, "\tal 1,0(1)\n"); + fprintf (file, "\tbr 1\n"); + } + } +} diff --git a/gcc/config/s390/s390.h b/gcc/config/s390/s390.h index 7bc1e0a1eac..e767aeb8a31 100644 --- a/gcc/config/s390/s390.h +++ b/gcc/config/s390/s390.h @@ -856,76 +856,7 @@ CUMULATIVE_ARGS; /* Output code to add DELTA to the first argument, and then jump to FUNCTION. Used for C++ multiple inheritance. */ -#define ASM_OUTPUT_MI_THUNK(FILE, THUNK_FNDECL, DELTA, FUNCTION) \ -do { \ - if (TARGET_64BIT) \ - { \ - if (flag_pic) \ - { \ - fprintf (FILE, "\tlarl 1,0f\n"); \ - fprintf (FILE, "\tagf %d,0(1)\n", \ - aggregate_value_p (TREE_TYPE \ - (TREE_TYPE (FUNCTION))) ? 3 :2 ); \ - fprintf (FILE, "\tlarl 1,"); \ - assemble_name (FILE, XSTR (XEXP (DECL_RTL (FUNCTION), 0), 0)); \ - fprintf (FILE, "@GOTENT\n"); \ - fprintf (FILE, "\tlg 1,0(1)\n"); \ - fprintf (FILE, "\tbr 1\n"); \ - fprintf (FILE, "0:\t.long "); \ - fprintf (FILE, HOST_WIDE_INT_PRINT_DEC, (DELTA)); \ - fprintf (FILE, "\n"); \ - } \ - else \ - { \ - fprintf (FILE, "\tlarl 1,0f\n"); \ - fprintf (FILE, "\tagf %d,0(1)\n", \ - aggregate_value_p (TREE_TYPE \ - (TREE_TYPE (FUNCTION))) ? 3 :2 ); \ - fprintf (FILE, "\tjg "); \ - assemble_name (FILE, XSTR (XEXP (DECL_RTL (FUNCTION), 0), 0)); \ - fprintf (FILE, "\n"); \ - fprintf (FILE, "0:\t.long "); \ - fprintf (FILE, HOST_WIDE_INT_PRINT_DEC, (DELTA)); \ - fprintf (FILE, "\n"); \ - } \ - } \ - else \ - { \ - if (flag_pic) \ - { \ - fprintf (FILE, "\tbras 1,0f\n"); \ - fprintf (FILE, "\t.long _GLOBAL_OFFSET_TABLE_-.\n"); \ - fprintf (FILE, "\t.long "); \ - assemble_name (FILE, XSTR (XEXP (DECL_RTL (FUNCTION), 0), 0)); \ - fprintf (FILE, "@GOT\n"); \ - fprintf (FILE, "\t.long "); \ - fprintf (FILE, HOST_WIDE_INT_PRINT_DEC, (DELTA)); \ - fprintf (FILE, "\n"); \ - fprintf (FILE, "0:\tal %d,8(1)\n", \ - aggregate_value_p (TREE_TYPE \ - (TREE_TYPE (FUNCTION))) ? 3 : 2 ); \ - fprintf (FILE, "\tl 0,4(1)\n"); \ - fprintf (FILE, "\tal 1,0(1)\n"); \ - fprintf (FILE, "\talr 1,0\n"); \ - fprintf (FILE, "\tl 1,0(1)\n"); \ - fprintf (FILE, "\tbr 1\n"); \ - } else { \ - fprintf (FILE, "\tbras 1,0f\n"); \ - fprintf (FILE, "\t.long "); \ - assemble_name (FILE, XSTR (XEXP (DECL_RTL (FUNCTION), 0), 0)); \ - fprintf (FILE, "-.\n"); \ - fprintf (FILE, "\t.long "); \ - fprintf (FILE, HOST_WIDE_INT_PRINT_DEC, (DELTA)); \ - fprintf (FILE, "\n"); \ - fprintf (FILE, "0:\tal %d,4(1)\n", \ - aggregate_value_p (TREE_TYPE \ - (TREE_TYPE (FUNCTION))) ? 3 : 2 ); \ - fprintf (FILE, "\tal 1,0(1)\n"); \ - fprintf (FILE, "\tbr 1\n"); \ - } \ - } \ -} while (0) - +#define TARGET_ASM_OUTPUT_MI_THUNK s390_output_mi_thunk /* Addressing modes, and classification of registers for them. */ diff --git a/gcc/config/sparc/sparc.h b/gcc/config/sparc/sparc.h index b793fd7d71d..8c3f70d5e9d 100644 --- a/gcc/config/sparc/sparc.h +++ b/gcc/config/sparc/sparc.h @@ -2869,8 +2869,7 @@ do { \ /* Output code to add DELTA to the first argument, and then jump to FUNCTION. Used for C++ multiple inheritance. */ -#define ASM_OUTPUT_MI_THUNK(FILE, THUNK_FNDECL, DELTA, FUNCTION) \ - sparc_output_mi_thunk (FILE, THUNK_FNDECL, DELTA, FUNCTION) +#define TARGET_ASM_OUTPUT_MI_THUNK sparc_output_mi_thunk #define PRINT_OPERAND_PUNCT_VALID_P(CHAR) \ ((CHAR) == '#' || (CHAR) == '*' || (CHAR) == '^' || (CHAR) == '(' || (CHAR) == '_') diff --git a/gcc/config/stormy16/stormy16.h b/gcc/config/stormy16/stormy16.h index 147da5c47e1..8034f89a0b2 100644 --- a/gcc/config/stormy16/stormy16.h +++ b/gcc/config/stormy16/stormy16.h @@ -1624,8 +1624,7 @@ enum reg_class frontend will generate a less efficient heavyweight thunk that calls FUNCTION instead of jumping to it. The generic approach does not support varargs. */ -#define ASM_OUTPUT_MI_THUNK(FILE, THUNK_FNDECL, DELTA, FUNCTION) \ - xstormy16_asm_output_mi_thunk (FILE, THUNK_FNDECL, DELTA, FUNCTION) +#define TARGET_ASM_OUTPUT_MI_THUNK xstormy16_asm_output_mi_thunk /* Generating Code for Profiling. */ diff --git a/gcc/config/vax/vax-protos.h b/gcc/config/vax/vax-protos.h index 059994f1196..928a2ab6554 100644 --- a/gcc/config/vax/vax-protos.h +++ b/gcc/config/vax/vax-protos.h @@ -1,5 +1,5 @@ /* Definitions of target machine for GNU compiler. VAX version. - Copyright (C) 2000 Free Software Foundation, Inc. + Copyright (C) 2000, 2002 Free Software Foundation, Inc. This file is part of GNU CC. @@ -36,6 +36,7 @@ extern int check_float_value PARAMS ((enum machine_mode, REAL_VALUE_TYPE *, int) #ifdef TREE_CODE extern void vms_check_external PARAMS ((tree, const char *, int)); +extern void vax_output_mi_thunk PARAMS ((FILE *, tree, int, tree)); #endif /* TREE_CODE */ extern void vms_flush_pending_externals PARAMS ((FILE *)); diff --git a/gcc/config/vax/vax.c b/gcc/config/vax/vax.c index ba091dc811d..35718813f3e 100644 --- a/gcc/config/vax/vax.c +++ b/gcc/config/vax/vax.c @@ -992,3 +992,17 @@ reg_was_0_p (insn, op) /* Make sure the reg hasn't been clobbered. */ && ! reg_set_between_p (op, XEXP (link, 0), insn)); } + +void +vax_output_mi_thunk (file, thunk, delta, function) + FILE *file; + tree thunk ATTRIBUTE_UNUSED; + int delta; + tree function; +{ + fprintf (file, "\t.word 0x0ffc\n"); + asm_fprintf (file, "\taddl2 $%d,4(%Rap)\n", delta); + fprintf (file, "\tjmp "); + assemble_name (file, XSTR (XEXP (DECL_RTL (function), 0), 0)); + fprintf (file, "+2\n"); +} diff --git a/gcc/config/vax/vax.h b/gcc/config/vax/vax.h index 68d5fa39526..44844867831 100644 --- a/gcc/config/vax/vax.h +++ b/gcc/config/vax/vax.h @@ -1161,14 +1161,7 @@ enum reg_class { NO_REGS, ALL_REGS, LIM_REG_CLASSES }; addl2 $DELTA, 4(ap) #adjust first argument jmp FUNCTION+2 #jump beyond FUNCTION's entry mask */ -#define ASM_OUTPUT_MI_THUNK(FILE, THUNK_FNDECL, DELTA, FUNCTION) \ -do { \ - fprintf (FILE, "\t.word 0x0ffc\n"); \ - asm_fprintf (FILE, "\taddl2 $%d,4(%Rap)\n", DELTA); \ - fprintf (FILE, "\tjmp "); \ - assemble_name (FILE, XSTR (XEXP (DECL_RTL (FUNCTION), 0), 0)); \ - fprintf (FILE, "+2\n"); \ -} while (0) +#define ASM_OUTPUT_MI_THUNK vax_output_mi_thunk /* Print an instruction operand X on file FILE. CODE is the code from the %-spec that requested printing this operand; diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 9d5a5bc845c..8da73626fce 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,9 @@ +2002-10-18 Mark Mitchell + + * Make-lang.in (method.o): Depend on TARGET_H. + * method.c (target.h): Include it. + (use_thunk): Use target hooks. Use vcall thunks, if available. + 2002-10-18 Mark Mitchell * class.c (base_derived_from): Make sure return value is a bool. diff --git a/gcc/cp/Make-lang.in b/gcc/cp/Make-lang.in index 0ec886d5a19..42656e7933d 100644 --- a/gcc/cp/Make-lang.in +++ b/gcc/cp/Make-lang.in @@ -246,7 +246,7 @@ cp/friend.o: cp/friend.c $(CXX_TREE_H) flags.h $(RTL_H) toplev.h $(EXPR_H) cp/init.o: cp/init.c $(CXX_TREE_H) flags.h $(RTL_H) $(EXPR_H) toplev.h \ $(GGC_H) except.h cp/method.o: cp/method.c $(CXX_TREE_H) toplev.h $(GGC_H) $(RTL_H) $(EXPR_H) \ - $(TM_P_H) + $(TM_P_H) $(TARGET_H) cp/cvt.o: cp/cvt.c $(CXX_TREE_H) cp/decl.h flags.h toplev.h convert.h cp/search.o: cp/search.c $(CXX_TREE_H) stack.h flags.h toplev.h $(RTL_H) cp/tree.o: cp/tree.c $(CXX_TREE_H) flags.h toplev.h $(GGC_H) $(RTL_H) \ diff --git a/gcc/cp/method.c b/gcc/cp/method.c index 6f3e0e7ba5f..5d14f57e7f3 100644 --- a/gcc/cp/method.c +++ b/gcc/cp/method.c @@ -34,6 +34,7 @@ Boston, MA 02111-1307, USA. */ #include "toplev.h" #include "ggc.h" #include "tm_p.h" +#include "target.h" /* Various flags to control the mangling process. */ @@ -408,8 +409,8 @@ use_thunk (thunk_fndecl, emit_p) BLOCK_VARS (DECL_INITIAL (thunk_fndecl)) = DECL_ARGUMENTS (thunk_fndecl); -#ifdef ASM_OUTPUT_MI_THUNK - if (!vcall_offset) + if (targetm.asm_out.output_mi_vcall_thunk + || (targetm.asm_out.output_mi_thunk && !vcall_offset)) { const char *fnname; current_function_decl = thunk_fndecl; @@ -419,18 +420,29 @@ use_thunk (thunk_fndecl, emit_p) init_function_start (thunk_fndecl, input_filename, lineno); current_function_is_thunk = 1; assemble_start_function (thunk_fndecl, fnname); - ASM_OUTPUT_MI_THUNK (asm_out_file, thunk_fndecl, delta, function); + if (targetm.asm_out.output_mi_vcall_thunk) + { + int vcall_value = (vcall_offset + ? tree_low_cst (vcall_offset, /*pos=*/0) + : 0); + targetm.asm_out.output_mi_vcall_thunk (asm_out_file, + thunk_fndecl, delta, + vcall_value, + function); + } + else + targetm.asm_out.output_mi_thunk (asm_out_file, thunk_fndecl, + delta, function); assemble_end_function (thunk_fndecl, fnname); current_function_decl = 0; cfun = 0; TREE_ASM_WRITTEN (thunk_fndecl) = 1; } else -#endif /* ASM_OUTPUT_MI_THUNK */ { - /* If we don't have the necessary macro for efficient thunks, generate - a thunk function that just makes a call to the real function. - Unfortunately, this doesn't work for varargs. */ + /* If we don't have the necessary code for efficient thunks, + generate a thunk function that just makes a call to the real + function. Unfortunately, this doesn't work for varargs. */ tree a, t; diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi index c2dfd399c27..74231e255ea 100644 --- a/gcc/doc/tm.texi +++ b/gcc/doc/tm.texi @@ -4151,9 +4151,11 @@ outputting the insns in this list, usually by calling You need not define this macro if you did not define @code{DELAY_SLOTS_FOR_EPILOGUE}. -@findex ASM_OUTPUT_MI_THUNK -@item ASM_OUTPUT_MI_THUNK (@var{file}, @var{thunk_fndecl}, @var{delta}, @var{function}) -A C compound statement that outputs the assembler code for a thunk +@end table + +@findex TARGET_ASM_OUTPUT_MI_THUNK +@deftypefn {Target Hook} void TARGET_ASM_OUTPUT_MI_THUNK (FILE *@var{file}, tree @var{thunk_fndecl}, int @var{delta}, tree @var{function}) +A function that outputs the assembler code for a thunk function, used to implement C++ virtual function calls with multiple inheritance. The thunk acts as a wrapper around a virtual function, adjusting the implicit object parameter before handing control off to @@ -4184,7 +4186,24 @@ If you do not define this macro, the target-independent code in the C++ front end will generate a less efficient heavyweight thunk that calls @var{function} instead of jumping to it. The generic approach does not support varargs. -@end table +@end deftypefn + +@findex TARGET_ASM_OUTPUT_MI_VCALL_THUNK +@deftypefn {Target Hook} void TARGET_ASM_OUTPUT_MI_VCALL_THUNK (FILE *@var{file}, tree @var{thunk_fndecl}, int @var{delta}, int @var{vcall_offset}, tree @var{function}) +A function like @code{TARGET_ASM_OUTPUT_MI_THUNK}, except that if +@var{vcall_offset} is non-zero, an additional adjustment should be made +after adding @code{delta}. In particular, if @var{p} is the +adjusted pointer, the following adjustment should be made: + +@example +p += (*((ptrdiff_t **)p))[vcall_offset/sizeof(ptrdiff_t)] +@end example + +@noindent +If this function is defined, it will always be used in place of +@code{TARGET_ASM_OUTPUT_MI_THUNK}. + +@end deftypefn @node Profiling @subsection Generating Code for Profiling diff --git a/gcc/target-def.h b/gcc/target-def.h index fbb75f0257f..b5a0345fdd3 100644 --- a/gcc/target-def.h +++ b/gcc/target-def.h @@ -103,6 +103,14 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # endif #endif +#ifndef TARGET_ASM_OUTPUT_MI_THUNK +#define TARGET_ASM_OUTPUT_MI_THUNK NULL +#endif + +#ifndef TARGET_ASM_OUTPUT_MI_VCALL_THUNK +#define TARGET_ASM_OUTPUT_MI_VCALL_THUNK NULL +#endif + #if defined(TARGET_ASM_CONSTRUCTOR) && defined(TARGET_ASM_DESTRUCTOR) #define TARGET_HAVE_CTORS_DTORS true #else @@ -173,7 +181,9 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. TARGET_ASM_SELECT_RTX_SECTION, \ TARGET_ASM_UNIQUE_SECTION, \ TARGET_ASM_CONSTRUCTOR, \ - TARGET_ASM_DESTRUCTOR} + TARGET_ASM_DESTRUCTOR, \ + TARGET_ASM_OUTPUT_MI_THUNK, \ + TARGET_ASM_OUTPUT_MI_VCALL_THUNK } /* Scheduler hooks. All of these default to null pointers, which haifa-sched.c looks for and handles. */ diff --git a/gcc/target.h b/gcc/target.h index 130f387c9f1..b05a87dc274 100644 --- a/gcc/target.h +++ b/gcc/target.h @@ -119,6 +119,13 @@ struct gcc_target /* Output a destructor for a symbol with a given priority. */ void (* destructor) PARAMS ((rtx, int)); + + /* Output the assembler code for a thunk function. */ + void (* output_mi_thunk) PARAMS ((FILE *, tree, int, tree)); + + /* Output the assembler code for a thunk function with a vcall + offset. */ + void (* output_mi_vcall_thunk) PARAMS ((FILE *, tree, int, int, tree)); } asm_out; /* Functions relating to instruction scheduling. */ diff --git a/gcc/testsuite/g++.dg/inherit/thunk1.C b/gcc/testsuite/g++.dg/inherit/thunk1.C new file mode 100644 index 00000000000..f393197d4f8 --- /dev/null +++ b/gcc/testsuite/g++.dg/inherit/thunk1.C @@ -0,0 +1,41 @@ +// { dg-do run } + +#include + +extern "C" void abort (); + +struct A { + virtual void f (int, ...) {} + int i; +}; + +struct B : virtual public A { +}; + +struct C : public B { + C (); + virtual void f (int, ...); +}; + +extern C* cp; + +C::C () { cp = this; } + +void C::f (int i, ...) { + if (this != cp) + abort (); + va_list ap; + if (i != 3) + abort (); + va_start (ap, i); + if (va_arg (ap, int) != 7) + abort (); + va_end (ap); +} + +C* cp = new C; + +int main () +{ + cp->f (3, 7); +}