Add OUTPUT_ASM_MI_THUNK; use r12 as temp for System V profiling, not r11
From-SVN: r22594
This commit is contained in:
parent
ccf82a75b0
commit
17167fd8b5
|
@ -1,3 +1,12 @@
|
|||
Fri Sep 25 20:30:00 1998 Michael Meissner <meissner@cygnus.com>
|
||||
|
||||
* rs6000.h (ASM_OUTPUT_MI_THUNK): Declare, call output_mi_thunk.
|
||||
(output_mi_thunk): Declare.
|
||||
|
||||
* rs6000.c (output_mi_thunk): Function to create thunks for MI.
|
||||
(output_function_profiler): Use r12 for temp, instead of r11 so
|
||||
that we preserve the static chain register.
|
||||
|
||||
Fri Sep 25 14:18:33 1998 Jim Wilson <wilson@cygnus.com>
|
||||
|
||||
* sdbout.c (sdbout_one_type): Don't look at TYPE_BINFO field of enums.
|
||||
|
|
|
@ -4447,6 +4447,223 @@ output_epilog (file, size)
|
|||
fputs (":\n", file);
|
||||
}
|
||||
}
|
||||
|
||||
/* A C compound statement 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 the real function.
|
||||
|
||||
First, emit code to add the integer DELTA to the location that contains the
|
||||
incoming first argument. Assume that this argument contains a pointer, and
|
||||
is the one used to pass the `this' pointer in C++. This is the incoming
|
||||
argument *before* the function prologue, e.g. `%o0' on a sparc. The
|
||||
addition must preserve the values of all other incoming arguments.
|
||||
|
||||
After the addition, emit code to jump to FUNCTION, which is a
|
||||
`FUNCTION_DECL'. This is a direct pure jump, not a call, and does not touch
|
||||
the return address. Hence returning from FUNCTION will return to whoever
|
||||
called the current `thunk'.
|
||||
|
||||
The effect must be as if FUNCTION had been called directly with the adjusted
|
||||
first argument. This macro is responsible for emitting all of the code for
|
||||
a thunk function; `FUNCTION_PROLOGUE' and `FUNCTION_EPILOGUE' are not
|
||||
invoked.
|
||||
|
||||
The THUNK_FNDECL is redundant. (DELTA and FUNCTION have already been
|
||||
extracted from it.) It might possibly be useful on some targets, but
|
||||
probably not.
|
||||
|
||||
If you do not define this macro, the target-independent code in the C++
|
||||
frontend will generate a less efficient heavyweight thunk that calls
|
||||
FUNCTION instead of jumping to it. The generic approach does not support
|
||||
varargs. */
|
||||
|
||||
void
|
||||
output_mi_thunk (file, thunk_fndecl, delta, function)
|
||||
FILE *file;
|
||||
tree thunk_fndecl;
|
||||
int delta;
|
||||
tree function;
|
||||
{
|
||||
char *this_reg = reg_names[ aggregate_value_p (TREE_TYPE (function)) ? 3 : 4 ];
|
||||
char *r0 = reg_names[0];
|
||||
char *sp = reg_names[1];
|
||||
char *toc = reg_names[2];
|
||||
char *schain = reg_names[11];
|
||||
char *r12 = reg_names[12];
|
||||
char *prefix;
|
||||
char *fname;
|
||||
char buf[512];
|
||||
static int labelno = 0;
|
||||
|
||||
/* Small constants that can be done by one add instruction */
|
||||
if (delta >= -32768 && delta <= 32767)
|
||||
{
|
||||
if (!TARGET_NEW_MNEMONICS)
|
||||
fprintf (file, "\tcal %s,%d(%s)\n", this_reg, delta, this_reg);
|
||||
else
|
||||
fprintf (file, "\taddi %s,%s,%d\n", this_reg, this_reg, delta);
|
||||
}
|
||||
|
||||
/* Large constants that can be done by one addis instruction */
|
||||
else if ((delta & 0xffff) == 0 && num_insns_constant_wide (delta) == 1)
|
||||
asm_fprintf (file, "\t{cau|addis} %s,%s,%d\n", this_reg, this_reg,
|
||||
delta >> 16);
|
||||
|
||||
/* 32-bit constants that can be done by an add and addis instruction. */
|
||||
else if (TARGET_32BIT || num_insns_constant_wide (delta) == 1)
|
||||
{
|
||||
/* Break into two pieces, propigating the sign bit from the low word to
|
||||
the upper word. */
|
||||
int delta_high = delta >> 16;
|
||||
int delta_low = delta & 0xffff;
|
||||
if ((delta_low & 0x8000) != 0)
|
||||
{
|
||||
delta_high++;
|
||||
delta_low = (delta_low ^ 0x8000) - 0x8000; /* sign extend */
|
||||
}
|
||||
|
||||
asm_fprintf (file, "\t{cau|addis} %s,%s,%d\n", this_reg, this_reg,
|
||||
delta_high);
|
||||
|
||||
if (!TARGET_NEW_MNEMONICS)
|
||||
fprintf (file, "\tcal %s,%d(%s)\n", this_reg, delta_low, this_reg);
|
||||
else
|
||||
fprintf (file, "\taddi %s,%s,%d\n", this_reg, this_reg, delta_low);
|
||||
}
|
||||
|
||||
/* 64-bit constants, fixme */
|
||||
else
|
||||
abort ();
|
||||
|
||||
/* Get the prefix in front of the names. */
|
||||
switch (DEFAULT_ABI)
|
||||
{
|
||||
default:
|
||||
abort ();
|
||||
|
||||
case ABI_AIX:
|
||||
prefix = ".";
|
||||
break;
|
||||
|
||||
case ABI_V4:
|
||||
case ABI_AIX_NODESC:
|
||||
case ABI_SOLARIS:
|
||||
prefix = "";
|
||||
break;
|
||||
|
||||
case ABI_NT:
|
||||
prefix = "..";
|
||||
break;
|
||||
}
|
||||
|
||||
/* If the function is compiled in this module, jump to it directly.
|
||||
Otherwise, load up its address and jump to it. */
|
||||
|
||||
fname = XSTR (XEXP (DECL_RTL (function), 0), 0);
|
||||
if (TREE_ASM_WRITTEN (function)
|
||||
&& !lookup_attribute ("longcall", TYPE_ATTRIBUTES (TREE_TYPE (function))))
|
||||
{
|
||||
fprintf (file, "\tb %s", prefix);
|
||||
assemble_name (file, fname);
|
||||
fprintf (file, "\n");
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
switch (DEFAULT_ABI)
|
||||
{
|
||||
default:
|
||||
case ABI_NT:
|
||||
abort ();
|
||||
|
||||
case ABI_AIX:
|
||||
/* Set up a TOC entry for the function. */
|
||||
ASM_GENERATE_INTERNAL_LABEL (buf, "Lthunk", labelno);
|
||||
toc_section ();
|
||||
ASM_OUTPUT_INTERNAL_LABEL (file, "Lthunk", labelno);
|
||||
labelno++;
|
||||
|
||||
/* Note, MINIMAL_TOC doesn't make sense in the case of a thunk, since
|
||||
there will be only one TOC entry for this function. */
|
||||
fputs ("\t.tc\t", file);
|
||||
assemble_name (file, buf);
|
||||
fputs ("[TC],", file);
|
||||
assemble_name (file, buf);
|
||||
putc ('\n', file);
|
||||
text_section ();
|
||||
asm_fprintf (file, (TARGET_32BIT) ? "\t{l|lwz} %s," : "\tld %s", r12);
|
||||
assemble_name (file, buf);
|
||||
asm_fprintf (file, "(%s)\n", reg_names[2]);
|
||||
asm_fprintf (file,
|
||||
(TARGET_32BIT) ? "\t{l|lwz} %s,0(%s)\n" : "\tld %s,0(%s)\n",
|
||||
r0, r12);
|
||||
|
||||
asm_fprintf (file,
|
||||
(TARGET_32BIT) ? "\t{l|lwz} %s,4(%s)\n" : "\tld %s,8(%s)\n",
|
||||
toc, r12);
|
||||
|
||||
asm_fprintf (file, "\tmtctr %s\n", r0);
|
||||
asm_fprintf (file,
|
||||
(TARGET_32BIT) ? "\t{l|lwz} %s,8(%s)\n" : "\tld %s,16(%s)\n",
|
||||
schain, r12);
|
||||
|
||||
asm_fprintf (file, "\tbctr\n");
|
||||
break;
|
||||
|
||||
/* Don't use r11, that contains the static chain, just use r0/r12. */
|
||||
case ABI_V4:
|
||||
case ABI_AIX_NODESC:
|
||||
case ABI_SOLARIS:
|
||||
if (flag_pic == 1)
|
||||
{
|
||||
fprintf (file, "\tmflr %s\n", r0);
|
||||
fputs ("\tbl _GLOBAL_OFFSET_TABLE_@local-4\n", file);
|
||||
asm_fprintf (file, "\tmflr %s\n", r12);
|
||||
asm_fprintf (file, "\tmtlr %s\n", r0);
|
||||
asm_fprintf (file, "\t{l|lwz} %s,", r0);
|
||||
assemble_name (file, fname);
|
||||
asm_fprintf (file, "@got(%s)\n", r12);
|
||||
}
|
||||
#if TARGET_ELF
|
||||
else if (flag_pic > 1 || TARGET_RELOCATABLE)
|
||||
{
|
||||
ASM_GENERATE_INTERNAL_LABEL (buf, "Lthunk", labelno);
|
||||
labelno++;
|
||||
fprintf (file, "\tmflr %s\n", r0);
|
||||
asm_fprintf (file, "\t{st|stw} %s,4(%s)\n", r0, sp);
|
||||
rs6000_pic_func_labelno = rs6000_pic_labelno;
|
||||
rs6000_output_load_toc_table (file, 12);
|
||||
asm_fprintf (file, "\t{l|lwz} %s,", r0);
|
||||
assemble_name (file, buf);
|
||||
asm_fprintf (file, "(%s)\n", r12);
|
||||
asm_fprintf (file, "\t{l|lwz} %s,4(%s)\n", r12, sp);
|
||||
asm_fprintf (file, "\tmtlr %s\n", r12);
|
||||
asm_fprintf (file, "%s\n", MINIMAL_TOC_SECTION_ASM_OP);
|
||||
assemble_name (file, buf);
|
||||
fputs (" = .-.LCTOC1\n", file);
|
||||
fputs ("\t.long ", file);
|
||||
assemble_name (file, fname);
|
||||
fputs ("\n\t.previous\n", file);
|
||||
}
|
||||
#endif
|
||||
else
|
||||
{
|
||||
asm_fprintf (file, "\t{liu|lis} %s,", r0);
|
||||
assemble_name (file, fname);
|
||||
asm_fprintf (file, "@ha\n");
|
||||
asm_fprintf (file, "\t{cal|la} %s,", r0);
|
||||
assemble_name (file, fname);
|
||||
asm_fprintf (file, "@l(%s)\n", r0);
|
||||
}
|
||||
|
||||
asm_fprintf (file, "\tmtctr %s\n", r0);
|
||||
asm_fprintf (file, "\tbctr\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Output a TOC entry. We derive the entry name from what is
|
||||
being written. */
|
||||
|
@ -4778,10 +4995,10 @@ output_function_profiler (file, labelno)
|
|||
fputs ("\tbl _GLOBAL_OFFSET_TABLE_@local-4\n", file);
|
||||
asm_fprintf (file, "\t{st|stw} %s,4(%s)\n",
|
||||
reg_names[0], reg_names[1]);
|
||||
asm_fprintf (file, "\tmflr %s\n", reg_names[11]);
|
||||
asm_fprintf (file, "\tmflr %s\n", reg_names[12]);
|
||||
asm_fprintf (file, "\t{l|lwz} %s,", reg_names[0]);
|
||||
assemble_name (file, buf);
|
||||
asm_fprintf (file, "@got(%s)\n", reg_names[11]);
|
||||
asm_fprintf (file, "@got(%s)\n", reg_names[12]);
|
||||
}
|
||||
#if TARGET_ELF
|
||||
else if (flag_pic > 1 || TARGET_RELOCATABLE)
|
||||
|
@ -4789,10 +5006,10 @@ output_function_profiler (file, labelno)
|
|||
asm_fprintf (file, "\t{st|stw} %s,4(%s)\n",
|
||||
reg_names[0], reg_names[1]);
|
||||
rs6000_pic_func_labelno = rs6000_pic_labelno;
|
||||
rs6000_output_load_toc_table (file, 11);
|
||||
asm_fprintf (file, "\t{l|lwz} %s,", reg_names[11]);
|
||||
rs6000_output_load_toc_table (file, 12);
|
||||
asm_fprintf (file, "\t{l|lwz} %s,", reg_names[12]);
|
||||
assemble_name (file, buf);
|
||||
asm_fprintf (file, "X(%s)\n", reg_names[11]);
|
||||
asm_fprintf (file, "X(%s)\n", reg_names[12]);
|
||||
asm_fprintf (file, "%s\n", MINIMAL_TOC_SECTION_ASM_OP);
|
||||
assemble_name (file, buf);
|
||||
fputs ("X = .-.LCTOC1\n", file);
|
||||
|
@ -4803,13 +5020,13 @@ output_function_profiler (file, labelno)
|
|||
#endif
|
||||
else
|
||||
{
|
||||
asm_fprintf (file, "\t{liu|lis} %s,", reg_names[11]);
|
||||
asm_fprintf (file, "\t{liu|lis} %s,", reg_names[12]);
|
||||
assemble_name (file, buf);
|
||||
fputs ("@ha\n", file);
|
||||
asm_fprintf (file, "\t{st|stw} %s,4(%s)\n", reg_names[0], reg_names[1]);
|
||||
asm_fprintf (file, "\t{cal|la} %s,", reg_names[0]);
|
||||
assemble_name (file, buf);
|
||||
asm_fprintf (file, "@l(%s)\n", reg_names[11]);
|
||||
asm_fprintf (file, "@l(%s)\n", reg_names[12]);
|
||||
}
|
||||
|
||||
fprintf (file, "\tbl %s\n", RS6000_MCOUNT);
|
||||
|
|
|
@ -1587,6 +1587,38 @@ typedef struct rs6000_args
|
|||
before returning. */
|
||||
|
||||
#define FUNCTION_EPILOGUE(FILE, SIZE) output_epilog (FILE, SIZE)
|
||||
|
||||
/* A C compound statement 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 the real function.
|
||||
|
||||
First, emit code to add the integer DELTA to the location that contains the
|
||||
incoming first argument. Assume that this argument contains a pointer, and
|
||||
is the one used to pass the `this' pointer in C++. This is the incoming
|
||||
argument *before* the function prologue, e.g. `%o0' on a sparc. The
|
||||
addition must preserve the values of all other incoming arguments.
|
||||
|
||||
After the addition, emit code to jump to FUNCTION, which is a
|
||||
`FUNCTION_DECL'. This is a direct pure jump, not a call, and does not touch
|
||||
the return address. Hence returning from FUNCTION will return to whoever
|
||||
called the current `thunk'.
|
||||
|
||||
The effect must be as if FUNCTION had been called directly with the adjusted
|
||||
first argument. This macro is responsible for emitting all of the code for
|
||||
a thunk function; `FUNCTION_PROLOGUE' and `FUNCTION_EPILOGUE' are not
|
||||
invoked.
|
||||
|
||||
The THUNK_FNDECL is redundant. (DELTA and FUNCTION have already been
|
||||
extracted from it.) It might possibly be useful on some targets, but
|
||||
probably not.
|
||||
|
||||
If you do not define this macro, the target-independent code in the C++
|
||||
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) \
|
||||
output_mi_thunk (FILE, THUNK_FNDECL, DELTA, FUNCTION)
|
||||
|
||||
/* TRAMPOLINE_TEMPLATE deleted */
|
||||
|
||||
|
@ -3263,6 +3295,7 @@ extern int rs6000_makes_calls ();
|
|||
extern rs6000_stack_t *rs6000_stack_info ();
|
||||
extern void output_prolog ();
|
||||
extern void output_epilog ();
|
||||
extern void output_mi_thunk ();
|
||||
extern void output_toc ();
|
||||
extern void output_ascii ();
|
||||
extern void rs6000_gen_section_name ();
|
||||
|
|
Loading…
Reference in New Issue