This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH] Fix PR optimization/8746 (x86)
- From: Eric Botcazou <ebotcazou at libertysurf dot fr>
- To: gcc-patches at gcc dot gnu dot org
- Date: Wed, 19 Mar 2003 16:08:36 +0100
- Subject: [PATCH] Fix PR optimization/8746 (x86)
Hi,
This is a kernel miscompilation bug on i586 present on the 3.2 branch only, a
regression from gcc 2.95.3.
The following insn
(insn 19 62 20 (parallel[
(set (reg:CCGOC 17 flags)
(compare:CCGOC (and:QI (reg/v:QI 0 al [60])
(const_int -16 [0xfffffff0]))
(const_int 0 [0x0])))
(set (reg/v:QI 0 al [60])
(and:QI (reg/v:QI 0 al [60])
(const_int -16 [0xfffffff0])))
] ) 300 {*andqi_2} (nil)
(nil))
is transformed by the split pass into
(insn 19 62 20 (parallel[
(set (reg:CCNO 17 flags)
(compare:CCNO (and:SI (reg:SI 0 eax [60])
(const_int 240 [0xf0]))
(const_int 0 [0x0])))
(set (reg:SI 0 eax [60])
(and:SI (reg:SI 0 eax [60])
(const_int 240 [0xf0])))
] ) -1 (insn_list 62 (nil))
(nil))
which is wrong because the sign bit, considered by both CC modes, is shifted
from bit 7 to bit 31. And the associated jump insn uses CCGOC mode.
(jump_insn 20 19 54 (set (pc)
(if_then_else (lt (reg:CCGOC 17 flags)
(const_int 0 [0x0]))
(label_ref 35)
(pc))) 490 {*jcc_1} (insn_list 19 (nil))
(expr_list:REG_BR_PROB (const_int 5000 [0x1388])
(nil)))
This was fixed on mainline a while ago by Jan (at one point the bug prevented
the compiler from bootstrapping on i586) by the following patch:
Thu Jun 6 23:14:46 CEST 2002 Jan Hubicka <jh at suse dot cz>
* i386.md (and promoting splitters): Disable QI to SImode promoting
when doing so changes immediate to be 32bit.
Only the first hunk of the patch is necessary in order to fix the bug, but I
think the second hunk is low risk.
Bootstrapped/regtested on i586-redhat-linux-gnu (c,c++,objc,f77 3.2 branch).
--
Eric Botcazou
2003-03-19 Eric Botcazou <ebotcazou at libertysurf dot fr>
PR optimization/8746
Backport from mainline:
Thu Jun 6 23:14:46 CEST 2002 Jan Hubicka <jh at suse dot cz>
* i386.md (and promoting splitters): Disable QI to SImode promoting
when doing so changes immediate to be 32bit.
2003-03-18 Eric Botcazou <ebotcazou at libertysurf dot fr>
* gcc.dg/20030319-1.c: New testIndex: config/i386/i386.md
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/i386/i386.md,v
retrieving revision 1.369
retrieving revision 1.370
diff -u -r1.369 -r1.370
--- config/i386/i386.md 29 May 2002 20:54:00 -0000 1.369
+++ config/i386/i386.md 6 Jun 2002 21:20:43 -0000 1.370
@@ -16358,6 +16358,8 @@
&& ix86_match_ccmode (insn, CCNOmode)
&& (GET_MODE (operands[0]) == HImode
|| (GET_MODE (operands[0]) == QImode
+ /* Ensure that the operand will remain sign extended immediate. */
+ && INTVAL (operands[2]) >= 0
&& (TARGET_PROMOTE_QImode || optimize_size)))"
[(parallel [(set (reg:CCNO 17)
(compare:CCNO (and:SI (match_dup 1) (match_dup 2))
@@ -16371,16 +16373,17 @@
operands[0] = gen_lowpart (SImode, operands[0]);
operands[1] = gen_lowpart (SImode, operands[1]);")
+; Don't promote the QImode tests, as i386 don't have encoding of
+; the test instruction with 32bit sign extended immediate and thus
+; the code grows.
(define_split
[(set (reg 17)
- (compare (and (match_operand 0 "aligned_operand" "")
- (match_operand 1 "const_int_operand" ""))
+ (compare (and (match_operand:HI 0 "aligned_operand" "")
+ (match_operand:HI 1 "const_int_operand" ""))
(const_int 0)))]
"! TARGET_PARTIAL_REG_STALL && reload_completed
&& ix86_match_ccmode (insn, CCNOmode)
- && (GET_MODE (operands[0]) == HImode
- || (GET_MODE (operands[0]) == QImode
- && (TARGET_PROMOTE_QImode || optimize_size)))"
+ && GET_MODE (operands[0]) == HImode"
[(set (reg:CCNO 17)
(compare:CCNO (and:SI (match_dup 0) (match_dup 1))
(const_int 0)))]
/* PR optimization/8746 */
/* { dg-do run } */
/* { dg-options "-mcpu=i586 -O" { target i?86-*-* } } */
extern void abort (void);
unsigned char r0;
int foo(int x)
{
unsigned char r = x&0xf0;
if (!(r&0x80))
{
r0 = r;
return 0;
}
else
return 1;
}
int main(void)
{
if (foo(0x80) != 1)
abort();
return 0;
}