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
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,
State-Changed-From-To: open->closed State-Changed-Why: Fixed in GCC 3.0.
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