Add OUTPUT_ASM_MI_THUNK; use r12 as temp for System V profiling, not r11
authorMichael Meissner <meissner@cygnus.com>
Fri, 25 Sep 1998 17:49:19 +0000 (17:49 +0000)
committerMichael Meissner <meissner@gcc.gnu.org>
Fri, 25 Sep 1998 17:49:19 +0000 (17:49 +0000)
From-SVN: r22594

gcc/ChangeLog
gcc/config/rs6000/rs6000.c
gcc/config/rs6000/rs6000.h

index 1972e4c356843c832140b1f3e13039d8ecd36268..b48812138fd5b2233ea9f60333be424d6d41cb60 100644 (file)
@@ -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.
index e5f199c606681e4bf588b8be3182d5e2ea1998a0..eed242ecb934d72acbaf7e15070710e27017d35d 100644 (file)
@@ -4447,6 +4447,223 @@ output_epilog (file, size)
       fputs (":\n", file);
     }
 }
+\f
+/* 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;
+       }
+    }
+}
+
 \f
 /* 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);
index 53c99d617c23b7ddd30fd2da710bc8ed14c79862..0e10ad671606622ac795144616009a3f4cc13a66 100644 (file)
@@ -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)
 \f
 /* 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 ();