This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
fix target/6788
- From: Richard Henderson <rth at redhat dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Sat, 25 May 2002 19:46:15 -0700
- Subject: fix target/6788
The "set" assembler macro we'd been using is explicitly 32-bit.
Not good when you need a 64-bit negative number. It was pointed
out that there is a "setx" macro, but...
I'm copying the same scheme that I'm using on Alpha, that is,
generate the thunk in rtl. This allows us to make use of the
relatively sophisticated routines that exist for generating
64-bit constants.
Applied mainline and branch.
r~
* config/sparc/sparc.c (sparc_output_mi_thunk): New implementation
using rtl instead of fprintf.
* config/sparc/sparc.h (ASM_OUTPUT_MI_THUNK): Use it.
* config/sparc/sparc-protos.h: Update.
* g++.dg/opt/thunk1.C: New.
Index: gcc/config/sparc/sparc-protos.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/sparc/sparc-protos.h,v
retrieving revision 1.28
diff -c -p -d -r1.28 sparc-protos.h
*** gcc/config/sparc/sparc-protos.h 4 May 2002 05:36:40 -0000 1.28
--- gcc/config/sparc/sparc-protos.h 26 May 2002 02:00:33 -0000
*************** extern int sparc_extra_constraint_check
*** 124,127 ****
--- 124,129 ----
extern int sparc_rtx_costs PARAMS ((rtx, enum rtx_code, enum rtx_code));
#endif /* RTX_CODE */
+ extern void sparc_output_mi_thunk PARAMS ((FILE *, tree, HOST_WIDE_INT, tree));
+
#endif /* __SPARC_PROTOS_H__ */
Index: gcc/config/sparc/sparc.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/sparc/sparc.c,v
retrieving revision 1.222
diff -c -p -d -r1.222 sparc.c
*** gcc/config/sparc/sparc.c 19 May 2002 05:23:23 -0000 1.222
--- gcc/config/sparc/sparc.c 26 May 2002 02:00:34 -0000
*************** sparc_encode_section_info (decl, first)
*** 8474,8476 ****
--- 8474,8543 ----
if (TARGET_CM_EMBMEDANY && TREE_CODE (decl) == FUNCTION_DECL)
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. */
+
+ void
+ sparc_output_mi_thunk (file, thunk_fndecl, delta, function)
+ FILE *file;
+ tree thunk_fndecl ATTRIBUTE_UNUSED;
+ HOST_WIDE_INT delta;
+ tree function;
+ {
+ rtx this, insn, funexp, delta_rtx, tmp;
+
+ reload_completed = 1;
+ no_new_pseudos = 1;
+ current_function_uses_only_leaf_regs = 1;
+
+ emit_note (NULL, NOTE_INSN_PROLOGUE_END);
+
+ /* Find the "this" pointer. Normally in %o0, but in ARCH64 if the function
+ returns a structure, the structure return pointer is there instead. */
+ if (TARGET_ARCH64 && aggregate_value_p (TREE_TYPE (TREE_TYPE (function))))
+ this = gen_rtx_REG (Pmode, SPARC_INCOMING_INT_ARG_FIRST + 1);
+ else
+ this = gen_rtx_REG (Pmode, SPARC_INCOMING_INT_ARG_FIRST);
+
+ /* 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))
+ {
+ rtx scratch = gen_rtx_REG (Pmode, 1);
+ if (TARGET_ARCH64)
+ sparc_emit_set_const64 (scratch, delta_rtx);
+ else
+ sparc_emit_set_const32 (scratch, delta_rtx);
+ delta_rtx = scratch;
+ }
+
+ tmp = gen_rtx_PLUS (Pmode, this, delta_rtx);
+ emit_insn (gen_rtx_SET (VOIDmode, this, tmp));
+
+ /* Generate a tail call to the target function. */
+ if (! TREE_USED (function))
+ {
+ assemble_external (function);
+ TREE_USED (function) = 1;
+ }
+ funexp = XEXP (DECL_RTL (function), 0);
+ funexp = gen_rtx_MEM (FUNCTION_MODE, funexp);
+ insn = emit_call_insn (gen_sibcall (funexp));
+ SIBLING_CALL_P (insn) = 1;
+ emit_barrier ();
+
+ /* Run just enough of rest_of_compilation to get the insns emitted.
+ There's not really enough bulk here to make other passes such as
+ instruction scheduling worth while. Note that use_thunk calls
+ assemble_start_function and assemble_end_function. */
+ insn = get_insns ();
+ shorten_branches (insn);
+ final_start_function (insn, file, 1);
+ final (insn, file, 1, 0);
+ final_end_function ();
+
+ reload_completed = 0;
+ no_new_pseudos = 0;
+ }
Index: gcc/config/sparc/sparc.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/sparc/sparc.h,v
retrieving revision 1.197
diff -c -p -d -r1.197 sparc.h
*** gcc/config/sparc/sparc.h 19 May 2002 05:23:23 -0000 1.197
--- gcc/config/sparc/sparc.h 26 May 2002 02:00:34 -0000
*************** do { \
*** 2874,2897 ****
/* Output code to add DELTA to the first argument, and then jump to FUNCTION.
Used for C++ multiple inheritance. */
! #define ASM_OUTPUT_MI_THUNK(FILE, THUNK_FNDECL, DELTA, FUNCTION) \
! do { \
! int reg = 0; \
! \
! if (TARGET_ARCH64 \
! && aggregate_value_p (TREE_TYPE (TREE_TYPE (FUNCTION)))) \
! reg = 1; \
! if ((DELTA) >= 4096 || (DELTA) < -4096) \
! fprintf (FILE, "\tset\t%d, %%g1\n\tadd\t%%o%d, %%g1, %%o%d\n", \
! (int)(DELTA), reg, reg); \
! else \
! fprintf (FILE, "\tadd\t%%o%d, %d, %%o%d\n", reg, (int)(DELTA), reg);\
! fprintf (FILE, "\tor\t%%o7, %%g0, %%g1\n"); \
! fprintf (FILE, "\tcall\t"); \
! assemble_name (FILE, XSTR (XEXP (DECL_RTL (FUNCTION), 0), 0)); \
! fprintf (FILE, ", 0\n"); \
! fprintf (FILE, "\t or\t%%g1, %%g0, %%o7\n"); \
! } while (0)
#define PRINT_OPERAND_PUNCT_VALID_P(CHAR) \
((CHAR) == '#' || (CHAR) == '*' || (CHAR) == '^' || (CHAR) == '(' || (CHAR) == '_')
--- 2874,2881 ----
/* Output code to add DELTA to the first argument, and then jump to FUNCTION.
Used for C++ multiple inheritance. */
! #define ASM_OUTPUT_MI_THUNK(FILE, THUNK_FNDECL, DELTA, FUNCTION) \
! sparc_output_mi_thunk (FILE, THUNK_FNDECL, DELTA, FUNCTION)
#define PRINT_OPERAND_PUNCT_VALID_P(CHAR) \
((CHAR) == '#' || (CHAR) == '*' || (CHAR) == '^' || (CHAR) == '(' || (CHAR) == '_')
Index: testsuite/g++.dg/opt/thunk1.C
===================================================================
RCS file: testsuite/g++.dg/opt/thunk1.C
diff -N testsuite/g++.dg/opt/thunk1.C
*** /dev/null 1 Jan 1970 00:00:00 -0000
--- testsuite/g++.dg/opt/thunk1.C 26 May 2002 02:40:25 -0000
***************
*** 0 ****
--- 1,42 ----
+ // PR 6788
+ // Test that the thunk adjusts the this pointer properly.
+ // { dg-do run }
+
+ extern "C" void abort ();
+
+ struct A
+ {
+ virtual void foo() = 0;
+ char large[33*1024];
+ };
+
+ struct B
+ {
+ virtual void foo() = 0;
+ };
+
+ struct C : public A, public B
+ {
+ virtual void foo();
+ };
+
+ static C *match;
+
+ void C::foo()
+ {
+ if (this != match)
+ abort ();
+ }
+
+ void bar(B *x)
+ {
+ x->foo();
+ }
+
+ int main()
+ {
+ C obj;
+ match = &obj;
+ bar(&obj);
+ return 0;
+ }