This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
loop vs exceptions
- From: Richard Henderson <rth at redhat dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Sat, 29 Dec 2001 11:08:37 -0800
- Subject: loop vs exceptions
The following fixes an ia64 miscompilation of __cxa_vec_ctor.
There are a couple of problems here.
One, since the existing loop code doesn't use the CFG, it didn't
actually know about the exit from the loop via the exception edge.
Thus it decided that it was possible to reverse the loop and fix
up the live BIVs at loop exit.
Two, ia64 uses schedule_ebbs for post-reload scheduling, which means
that insns in a fallthru basic block are given the opportunity to be
scheduled into the preceeding basic block. Which allowed the BIV
increment to be scheduled before the call.
Unfortunately, this doesn't completely fix g++.abi/cxa_vec.C, but we
do get farther, and what is remaining is some kind of unwind problem.
Tested on alphaev6 and ia64 linux.
r~
* loop.c (prescan_loop): Set has_multiple_exit_targets for exception
edges. Rearrange jump interpretation code to use pc_set.
(check_dbra_loop): Examine has_multiple_exit_targets not exit_count.
* sched-deps.c (sched_analyze_insn): Set scheduling barrier for
all insns that can throw, not just if flag_non_call_exceptions.
* g++.dg/eh/loop1.C: New.
Index: loop.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/loop.c,v
retrieving revision 1.373
diff -c -p -d -r1.373 loop.c
*** loop.c 2001/12/23 02:16:02 1.373
--- loop.c 2001/12/29 18:41:35
*************** prescan_loop (loop)
*** 2450,2457 ****
for (insn = NEXT_INSN (start); insn != NEXT_INSN (end);
insn = NEXT_INSN (insn))
{
! if (GET_CODE (insn) == NOTE)
{
if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG)
{
++level;
--- 2450,2458 ----
for (insn = NEXT_INSN (start); insn != NEXT_INSN (end);
insn = NEXT_INSN (insn))
{
! switch (GET_CODE (insn))
{
+ case NOTE:
if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG)
{
++level;
*************** prescan_loop (loop)
*** 2459,2482 ****
loop->level++;
}
else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_END)
! {
! --level;
! }
! }
! else if (GET_CODE (insn) == CALL_INSN)
! {
if (! CONST_OR_PURE_CALL_P (insn))
{
loop_info->unknown_address_altered = 1;
loop_info->has_nonconst_call = 1;
}
loop_info->has_call = 1;
! }
! else if (GET_CODE (insn) == INSN || GET_CODE (insn) == JUMP_INSN)
! {
! rtx label1 = NULL_RTX;
! rtx label2 = NULL_RTX;
if (volatile_refs_p (PATTERN (insn)))
loop_info->has_volatile = 1;
--- 2460,2532 ----
loop->level++;
}
else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_END)
! --level;
! break;
!
! case CALL_INSN:
if (! CONST_OR_PURE_CALL_P (insn))
{
loop_info->unknown_address_altered = 1;
loop_info->has_nonconst_call = 1;
}
loop_info->has_call = 1;
! if (can_throw_internal (insn))
! loop_info->has_multiple_exit_targets = 1;
! break;
!
! case JUMP_INSN:
! if (! loop_info->has_multiple_exit_targets)
! {
! rtx set = pc_set (insn);
!
! if (set)
! {
! rtx label1, label2;
!
! if (GET_CODE (SET_SRC (set)) == IF_THEN_ELSE)
! {
! label1 = XEXP (SET_SRC (set), 1);
! label2 = XEXP (SET_SRC (set), 2);
! }
! else
! {
! label1 = SET_SRC (PATTERN (insn));
! label2 = NULL_RTX;
! }
!
! do
! {
! if (label1 && label1 != pc_rtx)
! {
! if (GET_CODE (label1) != LABEL_REF)
! {
! /* Something tricky. */
! loop_info->has_multiple_exit_targets = 1;
! break;
! }
! else if (XEXP (label1, 0) != exit_target
! && LABEL_OUTSIDE_LOOP_P (label1))
! {
! /* A jump outside the current loop. */
! loop_info->has_multiple_exit_targets = 1;
! break;
! }
! }
+ label1 = label2;
+ label2 = NULL_RTX;
+ }
+ while (label1);
+ }
+ else
+ {
+ /* A return, or something tricky. */
+ loop_info->has_multiple_exit_targets = 1;
+ }
+ }
+ /* FALLTHRU */
+
+ case INSN:
if (volatile_refs_p (PATTERN (insn)))
loop_info->has_volatile = 1;
*************** prescan_loop (loop)
*** 2488,2536 ****
note_stores (PATTERN (insn), note_addr_stored, loop_info);
if (! loop_info->first_loop_store_insn && loop_info->store_mems)
loop_info->first_loop_store_insn = insn;
-
- if (! loop_info->has_multiple_exit_targets
- && GET_CODE (insn) == JUMP_INSN
- && GET_CODE (PATTERN (insn)) == SET
- && SET_DEST (PATTERN (insn)) == pc_rtx)
- {
- if (GET_CODE (SET_SRC (PATTERN (insn))) == IF_THEN_ELSE)
- {
- label1 = XEXP (SET_SRC (PATTERN (insn)), 1);
- label2 = XEXP (SET_SRC (PATTERN (insn)), 2);
- }
- else
- {
- label1 = SET_SRC (PATTERN (insn));
- }
! do
! {
! if (label1 && label1 != pc_rtx)
! {
! if (GET_CODE (label1) != LABEL_REF)
! {
! /* Something tricky. */
! loop_info->has_multiple_exit_targets = 1;
! break;
! }
! else if (XEXP (label1, 0) != exit_target
! && LABEL_OUTSIDE_LOOP_P (label1))
! {
! /* A jump outside the current loop. */
! loop_info->has_multiple_exit_targets = 1;
! break;
! }
! }
! label1 = label2;
! label2 = NULL_RTX;
! }
! while (label1);
! }
}
- else if (GET_CODE (insn) == RETURN)
- loop_info->has_multiple_exit_targets = 1;
}
/* Now, rescan the loop, setting up the LOOP_MEMS array. */
--- 2538,2551 ----
note_stores (PATTERN (insn), note_addr_stored, loop_info);
if (! loop_info->first_loop_store_insn && loop_info->store_mems)
loop_info->first_loop_store_insn = insn;
! if (flag_non_call_exceptions && can_throw_internal (insn))
! loop_info->has_multiple_exit_targets = 1;
! break;
! default:
! break;
}
}
/* Now, rescan the loop, setting up the LOOP_MEMS array. */
*************** check_dbra_loop (loop, insn_count)
*** 7962,7968 ****
which is reversible. */
int reversible_mem_store = 1;
! if (bl->giv_count == 0 && ! loop->exit_count)
{
rtx bivreg = regno_reg_rtx[bl->regno];
struct iv_class *blt;
--- 7977,7983 ----
which is reversible. */
int reversible_mem_store = 1;
! if (bl->giv_count == 0 && ! loop_info->has_multiple_exit_targets)
{
rtx bivreg = regno_reg_rtx[bl->regno];
struct iv_class *blt;
*************** check_dbra_loop (loop, insn_count)
*** 8003,8011 ****
}
}
! /* A biv has uses besides counting if it is used to set another biv. */
for (blt = ivs->list; blt; blt = blt->next)
! if (blt->init_set && reg_mentioned_p (bivreg, SET_SRC (blt->init_set)))
{
no_use_except_counting = 0;
break;
--- 8018,8028 ----
}
}
! /* A biv has uses besides counting if it is used to set
! another biv. */
for (blt = ivs->list; blt; blt = blt->next)
! if (blt->init_set
! && reg_mentioned_p (bivreg, SET_SRC (blt->init_set)))
{
no_use_except_counting = 0;
break;
Index: sched-deps.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/sched-deps.c,v
retrieving revision 1.28
diff -c -p -d -r1.28 sched-deps.c
*** sched-deps.c 2001/10/28 20:09:15 1.28
--- sched-deps.c 2001/12/29 18:41:35
*************** sched_analyze_insn (deps, x, insn, loop_
*** 1141,1147 ****
/* If this instruction can throw an exception, then moving it changes
where block boundaries fall. This is mighty confusing elsewhere.
Therefore, prevent such an instruction from being moved. */
! if (flag_non_call_exceptions && can_throw_internal (insn))
schedule_barrier_found = 1;
/* Add dependencies if a scheduling barrier was found. */
--- 1141,1147 ----
/* If this instruction can throw an exception, then moving it changes
where block boundaries fall. This is mighty confusing elsewhere.
Therefore, prevent such an instruction from being moved. */
! if (can_throw_internal (insn))
schedule_barrier_found = 1;
/* Add dependencies if a scheduling barrier was found. */
Index: g++.dg/eh/loop1.C
===================================================================
RCS file: loop1.C
diff -N loop1.C
*** /dev/null Tue May 5 13:32:27 1998
--- loop1.C Sat Dec 29 10:56:01 2001
***************
*** 0 ****
--- 1,30 ----
+ // Verify that loop optimization takes into account the exception edge
+ // and does not increment I before the call.
+ // { dg-do run }
+ // { dg-options "-O2" }
+
+ extern "C" void abort();
+ static void bar(char *);
+
+ static void foo(unsigned long element_count, char *ptr)
+ {
+ unsigned long i;
+ try {
+ for (i = 0; i != element_count; i++, ptr += 8)
+ bar (ptr);
+ }
+ catch (...) {
+ if (i)
+ abort ();
+ }
+ }
+
+ static void bar(char *)
+ {
+ throw 1;
+ }
+
+ int main()
+ {
+ foo(2, 0);
+ }