This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[c++ patch] fix for mi-thunk emission
- From: Michael Matz <matz at suse dot de>
- To: gcc-patches at gcc dot gnu dot org
- Date: Mon, 1 Aug 2005 01:37:29 +0200 (CEST)
- Subject: [c++ patch] fix for mi-thunk emission
Hi,
this patch is required at least on sparc for the genattrtab speedup
patches, to generate the same code with and without them for kdecore.cc.
But the bug is lurking anyway. The problem is how some backends
(alpha,ia64,mips,rs6000 on OSF,sh and sparc) emit mi-thunks by not going
through the proper channels and instead calling final() themself.
The code in the arch.c usually looks similar to this:
insn = get_insns ();
insn_locators_initialize ();
shorten_branches (insn);
final_start_function (insn, file, 1);
final (insn, file, 1);
final_end_function ();
with the C++ frontend side (in method.c) being (partly):
current_function_decl = thunk_fndecl;
init_function_start (thunk_fndecl);
current_function_is_thunk = 1;
assemble_start_function (thunk_fndecl, fnname);
targetm.asm_out.output_mi_thunk (asm_out_file, thunk_fndecl,
assemble_end_function (thunk_fndecl, fnname);
current_function_decl = 0;
cfun = 0;
Now the problem is, that this together creates a new function calling
passes from the backend on it, and generally doing stuff. But it misses
to call the pass_clean_state, which is done normally right after
pass_final. This means that some structures remain initialized
(incorrectly) for the next function to be compiled. Unfortunately one
can't just use pass_clean_state here, as not all structures are set up
(for instance the basic blocks), also because the backend doesn't go
through the proper channel of emitting functions.
The problem at hand is the insn_length array used in final.c by
get_attr_length. It is set up by shorten_branches to reflect the real
length per insn. If it is initialized get_attr_length() will use that
array, otherwise it will call ultimately insn_default_length() (and
attribute defined by insn-attrtab.c).
So, what happens is the following:
mi-thunk is emitted
shorten_branch is called --> insn_length[] set up
final and friends are called
mi-thunk done
next normal function is compiled
... different passes run ...
pass_delay_slots is run
dbr_schedule
requests certain attributes, some of them depend on attr_length
on sparc --> get_attr_length is called, returns wrong cached
length from the mi-thunk *
pass_shorten_branches is run
setup insn_length[] correctly for current function
...
pass_clean_state is run
init_insn_length called, which clears insn_length[]
At * this results in different code depending on if get_attr_length() is
actually called for the other attributes (like eligible_for_delay in
sparc's case), or if that call is optimized away by genattrtab (to the
value insn_default_length would return). They would agree on the value if
insn_length[] wouldn't be incorrectly initialized.
Note that this is just _different_, not wrong code. Just the filling of
delay slots is different, it's not incorrect. Of course it could result
also in wrong code under other circumstances.
I fixed this by just adding a call to init_insn_length() at the right
place in cp/method.c . But conceptually how mi-thunks are emitted
currently is a mess, and could possibly also result in other funny effects
from not running clean_state afterwards.
bootstrapped + regtested (together with the genattrtab patches) on
x86-64-linux. I have no testcase really, as kdecore.cc is much too large,
and as no wrong code was emitted it would also be hard to check.
Okay for mainline?
Ciao,
Michael.
--
* method.c (use_thunk): Call init_insn_lengths.
Index: cp/method.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/method.c,v
retrieving revision 1.336
diff -u -p -r1.336 method.c
--- cp/method.c 25 Jun 2005 00:58:12 -0000 1.336
+++ cp/method.c 30 Jul 2005 22:42:55 -0000
@@ -441,6 +441,7 @@ use_thunk (tree thunk_fndecl, bool emit_
fixed_offset, virtual_value, alias);
assemble_end_function (thunk_fndecl, fnname);
+ init_insn_lengths ();
current_function_decl = 0;
cfun = 0;
TREE_ASM_WRITTEN (thunk_fndecl) = 1;