diff options
author | meissner <meissner@138bc75d-0d04-0410-961f-82ee72b054a4> | 1998-09-25 17:49:19 +0000 |
---|---|---|
committer | meissner <meissner@138bc75d-0d04-0410-961f-82ee72b054a4> | 1998-09-25 17:49:19 +0000 |
commit | 1c9aa673e7705ea7be83aafed2f413c4b54b6160 (patch) | |
tree | 74280e09ee509423fc4326d042930e2370cc1a95 /gcc | |
parent | 9314bb4aed9ce0cf81a8318652aa31b624e5ba09 (diff) | |
download | gcc-1c9aa673e7705ea7be83aafed2f413c4b54b6160.tar.gz |
Add OUTPUT_ASM_MI_THUNK; use r12 as temp for System V profiling, not r11
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@22594 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 9 | ||||
-rw-r--r-- | gcc/config/rs6000/rs6000.c | 231 | ||||
-rw-r--r-- | gcc/config/rs6000/rs6000.h | 33 |
3 files changed, 266 insertions, 7 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 1972e4c3568..b48812138fd 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -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. diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c index e5f199c6066..eed242ecb93 100644 --- a/gcc/config/rs6000/rs6000.c +++ b/gcc/config/rs6000/rs6000.c @@ -4448,6 +4448,223 @@ 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. */ + +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); diff --git a/gcc/config/rs6000/rs6000.h b/gcc/config/rs6000/rs6000.h index 53c99d617c2..0e10ad67160 100644 --- a/gcc/config/rs6000/rs6000.h +++ b/gcc/config/rs6000/rs6000.h @@ -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 (); |