This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[patch] Combine looses libcall notes
- From: Paul Brook <paul at codesourcery dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Thu, 7 Apr 2005 00:35:45 +0100
- Subject: [patch] Combine looses libcall notes
- Organization: CodeSourcery
The attached patch fixes an ICE that showed up on csl-arm-branch. This looks
like a latent bug in distribute_notes.
The testcase includes the following code:
return (((a % 10000)) & 0xFF) >> 8;
Which results in the following RTL before combine (slightly edited):
(insn 25 4 26 0 (set (reg:SI 0 r0 [ a ])
(reg/v:SI 102 [ a ])) 141 {*thumb_movsi_insn} (insn_list 3 (nil))
(expr_list:REG_DEAD (reg/v:SI 102 [ a ])
(insn_list:REG_LIBCALL 28 (nil))))
(insn 26 25 27 0 (set (reg:SI 1 r1) (const_int 10000)
(call_insn/u 27 26 28 0 (parallel [
(set (reg:DI 0 r0)
(call (mem:SI (symbol_ref:SI ("__aeabi_uidivmod"))
(const_int 0 [0x0])))
(use (const_int 0 [0x0]))
(clobber (reg:SI 14 lr))
]) 226 {*call_value_insn} (insn_list 25 (insn_list 26 (nil))))))
(insn 28 27 29 0 (set (reg:SI 124 [+4 ])
(reg:SI 1 r1 [+4 ])) 141 {*thumb_movsi_insn} (nil)
(expr_list:REG_DEAD (reg:SI 1 r1 [+4 ])
(insn_list:REG_RETVAL 25
(expr_list:REG_EQUAL (umod:SI (reg/v:SI 102 [ a ]])
(const_int 10000 [0x2710]))
(nil)))))
(insn 29 28 30 0 (set (reg:SI 126)
(const_int 255 [0xff])) 141 {*thumb_movsi_insn} (nil)
(nil))
(insn 30 29 31 0 (set (reg:SI 125)
(and:SI (reg:SI 124 [+4 ])
(reg:SI 126))) 55 {*thumb_andsi3_insn}
(expr_list:REG_DEAD (reg:SI 124 [+4 ])
(expr_list:REG_DEAD (reg:SI 126)
(expr_list:REG_EQUAL (and:SI (reg:SI 124 [+4 ])
(const_int 255 [0xff]))
(nil)))))
(insn 31 30 36 0 (set (reg:SI 103)
(lshiftrt:SI (reg:SI 125)
(const_int 8 [0x8]))) 94 {*thumb_lshrsi3}
(expr_list:REG_DEAD (reg:SI 125) (nil)))
The first thing that happens is combine (correctly) turns insns 29-31 into
(set (reg:SI 103) (const_int 0))
It then propagates (REG_DEAD 124) into insn 28. We notice that this insn is a
single set of a dead reg, so decide to remove it.
The code in distribute_notes at around line 12190 is responsible for
distributing the appropriate notes before they are discarded, which is where
the fun starts.
The case for REG_RETVAL in distribute_notes checks !NOTE_P(from_insn) to see
if we can put the note back on the original insn. Unfortunately this
condition holds for the temporary RTX used when deleting dead sets.
The attached patch modifies the condition to ensure the notes are not put back
onto the soon-to-be-deleted insns.
It appears that in most cases insn 28 is deleted before we combine insns
28-13. I'm not sure what's special about csl-arm-branch that tickles this
bug.
I considered doing SET_INSN_DELETED before calling distribute_notes, but
couldn't convince myself that this was safe.
Tested on arm-none-eabi, and bootstrapped i686-linux.
Ok for mainline?
Paul
2005-04-07 Paul Brook <paul@codesourcery.com>
* combine.c (distribute_notes): Don't put notes on temporary insns.
Index: gcc/combine.c
===================================================================
RCS file: /var/cvsroot/gcc-cvs/gcc/gcc/combine.c,v
retrieving revision 1.485
diff -u -p -r1.485 combine.c
--- gcc/combine.c 5 Apr 2005 14:50:28 -0000 1.485
+++ gcc/combine.c 6 Apr 2005 14:51:49 -0000
@@ -12062,7 +12062,7 @@ distribute_notes (rtx notes, rtx from_in
/* If the insn previously containing this note still exists,
put it back where it was. Otherwise move it to the previous
insn. Adjust the corresponding REG_LIBCALL note. */
- if (!NOTE_P (from_insn))
+ if (!NOTE_P (from_insn) && PATTERN (from_insn) != pc_rtx)
place = from_insn;
else
{
@@ -12082,7 +12082,7 @@ distribute_notes (rtx notes, rtx from_in
case REG_LIBCALL:
/* This is handled similarly to REG_RETVAL. */
- if (!NOTE_P (from_insn))
+ if (!NOTE_P (from_insn) && PATTERN (from_insn) != pc_rtx)
place = from_insn;
else
{
@@ -12187,6 +12187,7 @@ distribute_notes (rtx notes, rtx from_in
REG_NOTES (tem) = NULL;
distribute_notes (old_notes, tem, tem, NULL_RTX);
+ gcc_assert (REG_NOTES (tem) == NULL);
distribute_links (LOG_LINKS (tem));
SET_INSN_DELETED (tem);