+2002-10-18 Mark Mitchell <mark@codesourcery.com>
+
+ * 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 <thorpej@wasabisystems.com>
* config/netbsd.h (NETBSD_ENABLE_EXECUTE_STACK): Define
/* 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
/* 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)
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));
}
}
#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);
+}
+
/* 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. */
#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 */
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
\f
/* Generating Code for Profiling. */
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
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
{
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 *));
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;
}
\f
void
return 1;
}
\f
+/* 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),
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);
reg_alloc_order [pos++] = 0;
}
+/* 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_thunk (file, delta, function)
+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)
}
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)
{
}
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;
/* 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.
/* 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
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 *));
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");
+}
/* 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
/* 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.
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,
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"
/* 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. */
\f
/* 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
/* 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.
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));
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");
+ }
+}
/* 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. */
#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 */
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.
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. */
/* 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.
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 */
}
}
}
+
+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");
+ }
+ }
+}
/* 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. */
/* 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) == '_')
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
\f
/* Generating Code for Profiling. */
/* 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.
#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 *));
/* 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");
+}
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;
2002-10-18 Mark Mitchell <mark@codesourcery.com>
+ * 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 <mark@codesourcery.com>
+
* class.c (base_derived_from): Make sure return value is a bool.
2002-10-18 Mark Mitchell <mark@codesourcery.com>
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) \
#include "toplev.h"
#include "ggc.h"
#include "tm_p.h"
+#include "target.h"
/* Various flags to control the mangling process. */
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;
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;
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
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
# 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
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. */
/* 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. */
--- /dev/null
+// { dg-do run }
+
+#include <stdarg.h>
+
+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);
+}