From: Eric Botcazou Date: Thu, 14 Oct 2004 06:54:49 +0000 (+0200) Subject: re PR target/14454 (virtual function with vararg won't compile) X-Git-Tag: releases/gcc-3.3.6~270 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c0d0d7d79322d788c17b29f8d871f9cd0a7e06c3;p=thirdparty%2Fgcc.git re PR target/14454 (virtual function with vararg won't compile) 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 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index b86a700d3549..c26db3afd89b 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,17 @@ +2004-10-13 Eric Botcazou + + 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 * doc/install.texi (*-*-solaris2*): Fix marker for URL. diff --git a/gcc/config/sparc/sparc.c b/gcc/config/sparc/sparc.c index d8cd82b6dedc..4c627091302b 100644 --- a/gcc/config/sparc/sparc.c +++ b/gcc/config/sparc/sparc.c @@ -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)); /* 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; @@ -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" diff --git a/gcc/config/sparc/sparc.md b/gcc/config/sparc/sparc.md index 9e8117a0698e..3c566f1c0a81 100644 --- a/gcc/config/sparc/sparc.md +++ b/gcc/config/sparc/sparc.md @@ -2048,7 +2048,6 @@ 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) { diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi index 5ea634a870e8..8ea3a91413e4 100644 --- a/gcc/doc/tm.texi +++ b/gcc/doc/tm.texi @@ -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 diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 2853955124e2..a736c568c561 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2004-10-13 Eric Botcazou + + * g++.dg/inherit/thunk1.C: Run on the SPARC. + 2004-09-30 Release Manager * GCC 3.3.5 Released. diff --git a/gcc/testsuite/g++.dg/inherit/thunk1.C b/gcc/testsuite/g++.dg/inherit/thunk1.C index 4426419e9daf..3bbd05069df3 100644 --- a/gcc/testsuite/g++.dg/inherit/thunk1.C +++ b/gcc/testsuite/g++.dg/inherit/thunk1.C @@ -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