This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH] Profiling bug: flow_call_edges_add clobbers libcalls
- From: Ulrich Weigand <weigand at i1 dot informatik dot uni-erlangen dot de>
- To: gcc-patches at gcc dot gnu dot org
- Date: Fri, 6 Feb 2004 00:13:39 +0100 (CET)
- Subject: [PATCH] Profiling bug: flow_call_edges_add clobbers libcalls
Hello,
when running SPECfp on s390x-ibm-linux with gcc 3.4 in profile-
directed feedback mode, all Fortran test cases currently fail.
The symptom are "corrupted profile info" errors during the
-fbranch-probabilities compile due to apparently negative
edge execution counts.
The reason for this turned out to be that code incrementing
some of the profile counters had been removed from the
-fprofile-arcs executable. This had happened because the
code was in fact *inside* a libcall sequence, and the whole
libcall sequence -including the profile counter code- was
removed as dead code in a later optimization stage.
The profile counter code was placed inside the libcall block
because the flow_call_edges_add routine had split the block
across two basic blocks in order to be able to add an exit
edge for the function call within the libcall block.
My first reaction was that this shouldn't have been done
because libcall functions should be const; however, this
turns out to be not always true, e.g. in the case where
the libcall returns a large value in memory, like __multi3
which for some reason the Fortran frontend likes to use.
Now, it would appear to me that even in such cases a basic
block split should never be introduced within a libcall block.
The patch below simply delays the split until after the
REG_RETVAL note. This fixes the SPECfp problems ...
Bootstrapped/regtested on s390-ibm-linux and s390x-ibm-linux
on mainline and 3.4 (it fixes a regression: 3.3 was able to
run SPECfp in profile-directed feedback mode).
OK for mainline and 3.4?
Bye,
Ulrich
ChangeLog:
* cfganal.c (flow_call_edges_add): Never split a libcall block.
Index: gcc/cfganal.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cfganal.c,v
retrieving revision 1.39
diff -c -p -r1.39 cfganal.c
*** gcc/cfganal.c 11 Dec 2003 00:20:36 -0000 1.39
--- gcc/cfganal.c 5 Feb 2004 19:42:01 -0000
*************** flow_call_edges_add (sbitmap blocks)
*** 333,338 ****
--- 333,339 ----
for (i = 0; i < last_bb; i++)
{
basic_block bb = BASIC_BLOCK (i);
+ rtx libcall_end = NULL_RTX;
rtx insn;
rtx prev_insn;
*************** flow_call_edges_add (sbitmap blocks)
*** 350,358 ****
edge e;
rtx split_at_insn = insn;
/* Don't split the block between a call and an insn that should
remain in the same block as the call. */
! if (GET_CODE (insn) == CALL_INSN)
while (split_at_insn != BB_END (bb)
&& keep_with_call_p (NEXT_INSN (split_at_insn)))
split_at_insn = NEXT_INSN (split_at_insn);
--- 351,363 ----
edge e;
rtx split_at_insn = insn;
+ /* Don't split libcalls. */
+ if (libcall_end)
+ split_at_insn = libcall_end;
+
/* Don't split the block between a call and an insn that should
remain in the same block as the call. */
! else if (GET_CODE (insn) == CALL_INSN)
while (split_at_insn != BB_END (bb)
&& keep_with_call_p (NEXT_INSN (split_at_insn)))
split_at_insn = NEXT_INSN (split_at_insn);
*************** flow_call_edges_add (sbitmap blocks)
*** 380,385 ****
--- 385,398 ----
make_edge (bb, EXIT_BLOCK_PTR, EDGE_FAKE);
}
+
+ /* Watch out for REG_LIBCALL/REG_RETVAL notes so that we know
+ whether we are currently in a libcall or not. Remember that
+ we are scanning backwards! */
+ if (find_reg_note (insn, REG_RETVAL, NULL_RTX))
+ libcall_end = insn;
+ if (find_reg_note (insn, REG_LIBCALL, NULL_RTX))
+ libcall_end = NULL_RTX;
if (insn == BB_HEAD (bb))
break;
--
Dr. Ulrich Weigand
weigand@informatik.uni-erlangen.de