Bug 877 - gcc 2.95.2 generates incorrect code on i386
Summary: gcc 2.95.2 generates incorrect code on i386
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: c (show other bugs)
Version: 2.95.2
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords: wrong-code
Depends on:
Blocks:
 
Reported: 2000-11-24 05:06 UTC by aeb
Modified: 2003-07-25 17:33 UTC (History)
3 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed:


Attachments
bug.c (605 bytes, text/x-c )
2003-05-21 15:16 UTC, aeb
Details

Note You need to log in before you can comment on or make changes to this bug.
Description aeb 2000-11-24 05:06:00 UTC
It seems that a variable length shift of a long long
is miscompiled. This causes Linux kernel bugs.

Release:
gcc 2.95.2

Environment:
ix86 with Linux or *BSD

How-To-Repeat:
gcc -Wall -O2 -o bug bug.c; ./bug
Comment 1 Bernd Schmidt 2000-11-24 15:40:05 UTC
From: Bernd Schmidt <bernds@redhat.com>
To: aeb@cwi.nl
Cc: gcc-gnats@gcc.gnu.org, gcc-prs@gcc.gnu.org, gcc-bugs@gcc.gnu.org,
   gcc-patches@gcc.gnu.org
Subject: Re: c/877: gcc 2.95.2 generates incorrect code on i386
Date: Fri, 24 Nov 2000 15:40:05 +0000 (GMT)

 On 24 Nov 2000 aeb@cwi.nl wrote:
 
 > >Synopsis:       gcc 2.95.2 generates incorrect code on i386
 
 > It seems that a variable length shift of a long long
 > is miscompiled. This causes Linux kernel bugs.
 
 This is (as usual) a bug in reload.  We have two insns:
 
 (insn 69 67 70 (set (reg:QI 46)
         (subreg:QI (reg:SI 43) 0))
 
 (insn 70 69 72 (set (reg:DI 44)
         (ashiftrt:DI (reg:DI 44)
             (reg:QI 46)))		(expr_list:REG_DEAD 46)
 
 Neither reg 46 nor reg 44 gets a hard register.  While processing insn 70,
 reload decides that it will need reg 2 (%cl) for reg 46, and reg 3/4
 (%ebx/%esi) for reg 44.  It also notices that the value of reg 44 is
 already available in reg 1/2 (%edx/%ecx), so it can avoid loading it from
 the stack and instead use reg 1/2 as overriding input.  It then notices
 that reg 46 dies in insn 70 and is set in insn 69, so it would be possible
 simply to replace the destination of insn 69 with the reload reg (%cl).
 
 The problem is that by changing insn 69 to store into %cl, the input
 override for the other reload gets clobbered.  Oops.  The function
 reload_reg_free_for_value_p doesn't test for this case.
 
 I'm currently bootstrapping with the patch below; I'll check it in (along
 with a testcase) once that finishes.  It won't apply cleanly to 2.95, but
 it should be quite easy to figure out how to apply it.  This is an obvious
 candidate should we decide to make a 2.95.3 release.
 
 (As a side note, this bug has nothing to do with the fact that there's a
 long long shift in this testcase, although I think I've noticed a bunch
 of potential bugs related to multiword values in the reload inheritance
 code while looking at this testcase...)
 
 
 Bernd
 
 	* reload1.c (conflicts_with_override): New function.
 	(emit_input_reload_insns): Use it to tighten test for validity
 	of substituting into output of previous insn.
 
 Index: reload1.c
 ===================================================================
 RCS file: /cvs/gcc/egcs/gcc/reload1.c,v
 retrieving revision 1.241
 diff -u -p -r1.241 reload1.c
 --- reload1.c	2000/11/14 10:23:37	1.241
 +++ reload1.c	2000/11/24 15:11:43
 @@ -417,6 +417,7 @@ static int reload_reg_reaches_end_p	PARA
  						 enum reload_type));
  static int allocate_reload_reg		PARAMS ((struct insn_chain *, int,
  						 int));
 +static int conflicts_with_override	PARAMS ((rtx));
  static void failed_reload		PARAMS ((rtx, int));
  static int set_reload_reg		PARAMS ((int, int));
  static void choose_reload_regs_init	PARAMS ((struct insn_chain *, rtx *));
 @@ -4882,6 +4883,21 @@ reload_reg_free_for_value_p (regno, opnu
    return 1;
  }
  
 +/* Determine whether the reload reg X overlaps any rtx'es used for
 +   overriding inheritance.  Return nonzero if so.  */
 +
 +static int
 +conflicts_with_override (x)
 +     rtx x;
 +{
 +  int i;
 +  for (i = 0; i < n_reloads; i++)
 +    if (reload_override_in[i]
 +	&& reg_overlap_mentioned_p (x, reload_override_in[i]))
 +      return 1;
 +  return 0;
 +}
 +
  /* Give an error message saying we failed to find a reload for INSN,
     and clear out reload R.  */
  static void
 @@ -6215,6 +6231,7 @@ emit_input_reload_insns (chain, rl, old,
  	   && dead_or_set_p (insn, old)
  	   /* This is unsafe if some other reload
  	      uses the same reg first.  */
 +	   && ! conflicts_with_override (reloadreg)
  	   && reload_reg_free_for_value_p (REGNO (reloadreg),
  					   rl->opnum,
  					   rl->when_needed,
 
Comment 2 Mark Mitchell 2001-04-13 21:04:42 UTC
State-Changed-From-To: open->closed
State-Changed-Why: Fixed in GCC 3.0.
Comment 3 Mark Mitchell 2001-04-14 04:04:42 UTC
From: mmitchel@gcc.gnu.org
To: aeb@cwi.nl, bernds@redhat.com, gcc-gnats@gcc.gnu.org, nobody@gcc.gnu.org
Cc:  
Subject: Re: c/877
Date: 14 Apr 2001 04:04:42 -0000

 Synopsis: gcc 2.95.2 generates incorrect code on i386
 
 State-Changed-From-To: open->closed
 State-Changed-By: mmitchel
 State-Changed-When: Fri Apr 13 21:04:42 2001
 State-Changed-Why:
     Fixed in GCC 3.0.
 
 http://gcc.gnu.org/cgi-bin/gnatsweb.pl?cmd=view&pr=877&database=gcc