Bug 36609

Summary: AVR wrong code using incorrect RTL for test reversal pattern
Product: gcc Reporter: Andy Hutchinson <hutchinsonandy>
Component: targetAssignee: Not yet assigned to anyone <unassigned>
Status: RESOLVED FIXED    
Severity: normal CC: eric.weddington, gcc-bugs
Priority: P3    
Version: 4.4.0   
Target Milestone: 4.4.0   
Host: i686-pc-cygwin Target: avr-unknown-none
Build: i686-pc-cygwin Known to work:
Known to fail: Last reconfirmed:
Attachments: Patch to target files

Description Andy Hutchinson 2008-06-23 22:52:24 UTC
I found problem with AVR test instructions such used by c/c++ code (x>0)
and demonstrated by testsuite test gcc.c-torture/execute/pr22493-1.c

#include <limits.h>
extern void abort ();
extern void exit (int);
void f(int i)
{
  if (i>0)
    abort();
  i = -i;
  if (i<0)
    return;
  abort ();
}

int main(int argc, char *argv[])
{
  f(INT_MIN);
  exit (0);
}


Compiling this with:

avr-gcc -c -mmcu=atmega128 -I. -w  -Os  -fwrapv  -mmcu=atmega128 -Wall -Wstrict-prototypes -Wa,-ahlms=test.s  -std=gnu99 test.c -o test.o


produces wrong code.

An integer test x>0 is translated into RTL:

CC0=Rx

from which we create AVR assembler code

TST Rx

which is equivalent to CMP Rx,0


AVR target also have negated_tst  RTL patterns to reverse tests in avr_reorg so that we can match the available branches on AVR. For example AVR has BRLT and BRGE but not BRLE and BRGT.

So

CC0 = Rx
Jump LE

becomes reorganized as

CC0 = NEG:xx(Rx)
Jump GE

which emits the following code via  define_insn "*negated_tst.....

CMP 0,Rx
BRGE


For such test reversals  the final code is correct. However, the intermediate RTL used by translation is WRONG

CC0=Rx
Jump LE

is NOT equivalent to

CC0 = NEG:xx(Rx)
Jump GE

For test reversal the problem is hidden - 2 wrongs making a right in this case.
BUT the bug appears when we have a normal code sequence such as

NEG:xx(Rx)
CC0 = Rx

which the combine phase will match against the RTL of *negated_tst and result in assembler code of:

CMP 0,Rx

which is incorrect. Consider the case where Rx= -32768

NEG:HI(-32768) => -32768
CC0 = -32768 => Negative correct!

but the replacment:

CMP 0,-32768 =>Positive - WRONG


The fix is to redefine  the "*negated_tst" RTL patterns to use correct COMPARES  and have avr_reorg to emit the corrected RTL.


(define_insn "*reversed_tsthi"
  [(set (cc0)
	(compare (const_int 0)
	(match_operand:HI 0 "register_operand"  "r")))

Test reversals will be unaffected. But now combine won't find any bad RTL.

I have not studied to see if the above RTL is ever generated. If it is, it is perfectly safe.
Comment 1 Andy Hutchinson 2008-07-23 10:43:57 UTC
Created attachment 15945 [details]
Patch to target files

http://gcc.gnu.org/ml/gcc-patches/2008-07/msg00391.html
Comment 2 Andy Hutchinson 2008-09-08 22:26:53 UTC
Subject: Bug 36609

Author: hutchinsonandy
Date: Mon Sep  8 22:25:42 2008
New Revision: 140124

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=140124
Log:
PR target/36609
* config/avr/avr.c (avr_reorg): Create RTL for reversed compare with zero.
* config/avr/avr.md  (QISI) : Define mode iterator.
(negated_tst<mode>) : Redefine as split using mode macro.
(reversed_tstqi): Define insn as reversed compare with zero.
(reversed_tsthi): Ditto.
(reversed_tstsi): Ditto.

Modified:
    trunk/gcc/ChangeLog
    trunk/gcc/config/avr/avr.c
    trunk/gcc/config/avr/avr.md

Comment 3 Andy Hutchinson 2008-09-08 22:45:00 UTC
4.4 fixed.