]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
re PR target/14454 (virtual function with vararg won't compile)
authorEric Botcazou <ebotcazou@libertysurf.fr>
Thu, 14 Oct 2004 06:54:49 +0000 (08:54 +0200)
committerEric Botcazou <ebotcazou@gcc.gnu.org>
Thu, 14 Oct 2004 06:54:49 +0000 (06:54 +0000)
PR target/14454
* config/sparc/sparc.c (TARGET_ASM_CAN_OUTPUT_MI_THUNK): Set to
sparc_can_output_mi_thunk.
(sparc_output_mi_thunk): Simplify handling of delta offset.  Add
handling of vcall offset.
(sparc_can_output_mi_thunk): New predicate.
* doc/tm.texi (TARGET_ASM_OUTPUT_MI_THUNK): Document VCALL_OFFSET.
(TARGET_ASM_OUTPUT_MI_VCALL_THUNK): Delete.
(TARGET_ASM_CAN_OUTPUT_MI_THUNK): New target hook.

* config/sparc/sparc.md (movdi): Remove redundant test.

From-SVN: r89028

gcc/ChangeLog
gcc/config/sparc/sparc.c
gcc/config/sparc/sparc.md
gcc/doc/tm.texi
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/inherit/thunk1.C

index b86a700d3549a8a673be621405648fb20bda0a2e..c26db3afd89bbb41a87c2da24027cdefcd1e9580 100644 (file)
@@ -1,3 +1,17 @@
+2004-10-13  Eric Botcazou  <ebotcazou@libertysurf.fr>
+
+       PR target/14454
+       * config/sparc/sparc.c (TARGET_ASM_CAN_OUTPUT_MI_THUNK): Set to
+       sparc_can_output_mi_thunk.
+       (sparc_output_mi_thunk): Simplify handling of delta offset.  Add
+       handling of vcall offset.
+       (sparc_can_output_mi_thunk): New predicate.
+       * doc/tm.texi (TARGET_ASM_OUTPUT_MI_THUNK): Document VCALL_OFFSET.
+       (TARGET_ASM_OUTPUT_MI_VCALL_THUNK): Delete.
+       (TARGET_ASM_CAN_OUTPUT_MI_THUNK): New target hook.
+
+       * config/sparc/sparc.md (movdi): Remove redundant test.
+
 2004-10-07  Eric Botcazou  <ebotcazou@libertysurf.fr>
 
        * doc/install.texi (*-*-solaris2*): Fix marker for URL.
index d8cd82b6dedcf9bbe97f5912710cf2f572dd7a4c..4c627091302b2f0b96ac0871f1fc934d940d6a81 100644 (file)
@@ -178,6 +178,8 @@ static void emit_hard_tfmode_operation PARAMS ((enum rtx_code, rtx *));
 static void sparc_encode_section_info PARAMS ((tree, int));
 static void sparc_output_mi_thunk PARAMS ((FILE *, tree, HOST_WIDE_INT,
                                           HOST_WIDE_INT, tree));
+static bool sparc_can_output_mi_thunk PARAMS ((tree, HOST_WIDE_INT,
+                                              HOST_WIDE_INT, tree));
 \f
 /* Option handling.  */
 
@@ -244,7 +246,7 @@ enum processor_type sparc_cpu;
 #undef TARGET_ASM_OUTPUT_MI_THUNK
 #define TARGET_ASM_OUTPUT_MI_THUNK sparc_output_mi_thunk
 #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
-#define TARGET_ASM_CAN_OUTPUT_MI_THUNK default_can_output_mi_thunk_no_vcall
+#define TARGET_ASM_CAN_OUTPUT_MI_THUNK sparc_can_output_mi_thunk
 
 struct gcc_target targetm = TARGET_INITIALIZER;
 \f
@@ -8622,18 +8624,21 @@ sparc_encode_section_info (decl, first)
     SYMBOL_REF_FLAG (XEXP (DECL_RTL (decl), 0)) = 1;
 }
 
-/* Output code to add DELTA to the first argument, and then jump to FUNCTION.
-   Used for C++ multiple inheritance.  */
+/* Output the assembler code for a thunk function.  THUNK_DECL is the
+   declaration for the thunk function itself, FUNCTION is the decl for
+   the target function.  DELTA is an immediate constant offset to be
+   added to THIS.  If VCALL_OFFSET is nonzero, the word at address
+   (*THIS + VCALL_OFFSET) should be additionally added to THIS.  */
 
 static void
 sparc_output_mi_thunk (file, thunk_fndecl, delta, vcall_offset, function)
      FILE *file;
      tree thunk_fndecl ATTRIBUTE_UNUSED;
      HOST_WIDE_INT delta;
-     HOST_WIDE_INT vcall_offset ATTRIBUTE_UNUSED;
+     HOST_WIDE_INT vcall_offset;
      tree function;
 {
-  rtx this, insn, funexp, delta_rtx, tmp;
+  rtx this, insn, funexp;
 
   reload_completed = 1;
   no_new_pseudos = 1;
@@ -8650,26 +8655,73 @@ sparc_output_mi_thunk (file, thunk_fndecl, delta, vcall_offset, function)
 
   /* Add DELTA.  When possible use a plain add, otherwise load it into
      a register first.  */
-  delta_rtx = GEN_INT (delta);
-  if (!SPARC_SIMM13_P (delta))
+  if (delta)
     {
+      rtx delta_rtx = GEN_INT (delta);
+
+      if (! SPARC_SIMM13_P (delta))
+       {
+         rtx scratch = gen_rtx_REG (Pmode, 1);
+         emit_move_insn (scratch, delta_rtx);
+         delta_rtx = scratch;
+       }
+
+      /* THIS += DELTA.  */
+      emit_insn (gen_add2_insn (this, delta_rtx));
+    }
+
+  /* Add the word at address (*THIS + VCALL_OFFSET).  */
+  if (vcall_offset)
+    {
+      rtx vcall_offset_rtx = GEN_INT (vcall_offset);
       rtx scratch = gen_rtx_REG (Pmode, 1);
 
-      if (input_operand (delta_rtx, GET_MODE (scratch)))
-       emit_insn (gen_rtx_SET (VOIDmode, scratch, delta_rtx));
+      if (vcall_offset >= 0)
+       abort ();
+
+      /* SCRATCH = *THIS.  */
+      emit_move_insn (scratch, gen_rtx_MEM (Pmode, this));
+
+      /* Prepare for adding VCALL_OFFSET.  The difficulty is that we
+        may not have any available scratch register at this point.  */
+      if (SPARC_SIMM13_P (vcall_offset))
+       ;
+      /* This is the case if ARCH64 (unless -ffixed-g5 is passed).  */
+      else if (! fixed_regs[5]
+              /* The below sequence is made up of at least 2 insns,
+                 while the default method may need only one.  */
+              && vcall_offset < -8192)
+       {
+         rtx scratch2 = gen_rtx_REG (Pmode, 5);
+         emit_move_insn (scratch2, vcall_offset_rtx);
+         vcall_offset_rtx = scratch2;
+       }
       else
        {
-         if (TARGET_ARCH64)
-           sparc_emit_set_const64 (scratch, delta_rtx);
-         else
-           sparc_emit_set_const32 (scratch, delta_rtx);
+         rtx increment = GEN_INT (-4096);
+
+         /* VCALL_OFFSET is a negative number whose typical range can be
+            estimated as -32768..0 in 32-bit mode.  In almost all cases
+            it is therefore cheaper to emit multiple add insns than
+            spilling and loading the constant into a register (at least
+            6 insns).  */
+         while (! SPARC_SIMM13_P (vcall_offset))
+           {
+             emit_insn (gen_add2_insn (scratch, increment));
+             vcall_offset += 4096;
+           }
+         vcall_offset_rtx = GEN_INT (vcall_offset); /* cannot be 0 */
        }
 
-      delta_rtx = scratch;
-    }
+      /* SCRATCH = *(*THIS + VCALL_OFFSET).  */
+      emit_move_insn (scratch, gen_rtx_MEM (Pmode,
+                                           gen_rtx_PLUS (Pmode,
+                                                         scratch,
+                                                         vcall_offset_rtx)));
 
-  tmp = gen_rtx_PLUS (Pmode, this, delta_rtx);
-  emit_insn (gen_rtx_SET (VOIDmode, this, tmp));
+      /* THIS += *(*THIS + VCALL_OFFSET).  */
+      emit_insn (gen_add2_insn (this, scratch));
+    }
 
   /* Generate a tail call to the target function.  */
   if (! TREE_USED (function))
@@ -8697,4 +8749,18 @@ sparc_output_mi_thunk (file, thunk_fndecl, delta, vcall_offset, function)
   no_new_pseudos = 0;
 }
 
+/* Return true if sparc_output_mi_thunk would be able to output the
+   assembler code for the thunk function specified by the arguments
+   it is passed, and false otherwise.  */
+static bool
+sparc_can_output_mi_thunk (thunk_fndecl, delta, vcall_offset, function)
+     tree thunk_fndecl ATTRIBUTE_UNUSED;
+     HOST_WIDE_INT delta ATTRIBUTE_UNUSED;
+     HOST_WIDE_INT vcall_offset;
+     tree function ATTRIBUTE_UNUSED;
+{
+  /* Bound the loop used in the default method above.  */
+  return (vcall_offset >= -32768 || ! fixed_regs[5]);
+}
+
 #include "gt-sparc.h"
index 9e8117a0698e23d1495b58dedb9481bc8a679f52..3c566f1c0a816f9b71c9af36e7422abb648c4937 100644 (file)
   if (! CONSTANT_P (operands[1]) || input_operand (operands[1], DImode))
     ;
   else if (TARGET_ARCH64
-          && CONSTANT_P (operands[1])
            && GET_CODE (operands[1]) != HIGH
            && GET_CODE (operands[1]) != LO_SUM)
     {
index 5ea634a870e8f1dd1123b62e112046390f2c48ff..8ea3a91413e4aa8c9e22daa217cbf09db5887a0b 100644 (file)
@@ -4160,7 +4160,7 @@ You need not define this macro if you did not define
 @end table
 
 @findex TARGET_ASM_OUTPUT_MI_THUNK
-@deftypefn {Target Hook} void TARGET_ASM_OUTPUT_MI_THUNK (FILE *@var{file}, tree @var{thunk_fndecl}, HOST_WIDE_INT @var{delta}, tree @var{function})
+@deftypefn {Target Hook} void TARGET_ASM_OUTPUT_MI_THUNK (FILE *@var{file}, tree @var{thunk_fndecl}, HOST_WIDE_INT @var{delta}, HOST_WIDE_INT @var{vcall_offset}, 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,
@@ -4174,7 +4174,15 @@ in C++.  This is the incoming argument @emph{before} the function prologue,
 e.g.@: @samp{%o0} on a sparc.  The addition must preserve the values of
 all other incoming arguments.
 
-After the addition, emit code to jump to @var{function}, which is a
+Then, if @var{vcall_offset} is nonzero, 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:
+
+@smallexample
+p += (*((ptrdiff_t **)p))[vcall_offset/sizeof(ptrdiff_t)]
+@end smallexample
+
+After the additions, emit code to jump to @var{function}, which is a
 @code{FUNCTION_DECL}.  This is a direct pure jump, not a call, and does
 not touch the return address.  Hence returning from @var{FUNCTION} will
 return to whoever called the current @samp{thunk}.
@@ -4194,21 +4202,13 @@ front end will generate a less efficient heavyweight thunk that calls
 not support varargs.
 @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}, HOST_WIDE_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 nonzero, 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}.
-
+@findex TARGET_ASM_CAN_OUTPUT_MI_THUNK
+@deftypefn {Target Hook} bool TARGET_ASM_CAN_OUTPUT_MI_THUNK (tree @var{thunk_fndecl}, HOST_WIDE_INT @var{delta}, HOST_WIDE_INT @var{vcall_offset}, tree @var{function})
+A function that returns true if TARGET_ASM_OUTPUT_MI_THUNK would be able
+to output the assembler code for the thunk function specified by the
+arguments it is passed, and false otherwise.  In the latter case, the
+generic approach will be used by the C++ front end, with the limitations
+previously exposed.
 @end deftypefn
 
 @node Profiling
index 2853955124e2a5d23f5be3755b10e61a2bdd2018..a736c568c561fb1a3e21c2b99761c83958a484da 100644 (file)
@@ -1,3 +1,7 @@
+2004-10-13  Eric Botcazou  <ebotcazou@libertysurf.fr>
+
+       * g++.dg/inherit/thunk1.C: Run on the SPARC.
+
 2004-09-30  Release Manager
 
        * GCC 3.3.5 Released.
index 4426419e9daf4c6428b6c1eca7d92b06d2638871..3bbd05069df37261fad512b074cf463b90029b1a 100644 (file)
@@ -1,4 +1,4 @@
-// { dg-do run { target i?86-*-* x86_64-*-* s390*-*-* alpha*-*-* ia64-*-* } }
+// { dg-do run { target i?86-*-* x86_64-*-* s390*-*-* alpha*-*-* ia64-*-* sparc*-*-* } }
 
 #include <stdarg.h>