Bug 22884 - Не правильная трансляция оператора if
Summary: Не правильная трансляция оператора if
Status: CLOSED FIXED
Alias: None
Product: Sisyphus
Classification: Development
Component: avr-gcc (show other bugs)
Version: unstable
Hardware: all Linux
: P3 blocker
Assignee: Grigory Milev
QA Contact: qa-sisyphus
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2010-02-03 19:55 MSK by Dmitry A. Kharitonov
Modified: 2011-01-19 23:39 MSK (History)
7 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Dmitry A. Kharitonov 2010-02-03 19:55:09 MSK
Сравниваются long и long

            //Nouse skiped
                // test for holdkey
                if(keybuf.keys!=keys.keys) {
 20c:	20 91 fa 00 	lds	r18, 0x00FA
 210:	30 91 fb 00 	lds	r19, 0x00FB
 214:	40 91 fc 00 	lds	r20, 0x00FC
 218:	50 91 fd 00 	lds	r21, 0x00FD
 21c:	80 91 04 01 	lds	r24, 0x0104
 220:	90 91 05 01 	lds	r25, 0x0105
 224:	a0 91 06 01 	lds	r26, 0x0106
 228:	b0 91 07 01 	lds	r27, 0x0107
 22c:	28 17       	cp	r18, r24
 22e:	39 07       	cpc	r19, r25
 230:	4a 07       	cpc	r20, r26
 232:	5b 07       	cpc	r21, r27
 234:	e1 f0       	breq	.+56     	; 0x26e <__stack+0xf>

Здесь проверяется результат последнего (старшего байта), а результаты сравнения предыдущих байтов игнорируются
Правильно так:
 22c:	28 17       	cp	r18, r24
 234:	e1 f0       	brne      .....
 22e:	39 07       	cp	r19, r25
 234:	e1 f0       	brne	  ..... 
 230:	4a 07       	cp	r20, r26
 234:	e1 f0       	brne	  ..... 
 232:	5b 07       	cp	r21, r27
 234:	e1 f0       	brne	  .....

и далее проверка на не нулевое значение


                // test for presskey
                if(keybuf.keys) {
 26e:	80 91 fa 00 	lds	r24, 0x00FA
 272:	90 91 fb 00 	lds	r25, 0x00FB
 276:	a0 91 fc 00 	lds	r26, 0x00FC
 27a:	b0 91 fd 00 	lds	r27, 0x00FD
 27e:	00 97       	sbiw	r24, 0x00	; 0
 280:	a1 05       	cpc	r26, r1
 282:	b1 05       	cpc	r27, r1
 284:	79 f1       	breq	.+94     	; 0x2e4 <__stack+0x85>
                // key pressed
Тоже самое проверяется равенство нулю только последнего байта

Правильно так
 27e:	00 97       	or	r24,r25
 280:	a1 05       	or 	r24,r26
 282:	b1 05       	or 	r24,r27
 284:	79 f1       	breq	.+94     	; 0x2e4 <__stack+0x85>


В общем, компилятор скорее мёртв, нежели жив.

Ставить вопрос об удалении из репозитория -- жалко, а кроме меня наверное никто не пользуется.
Comment 1 Timur Batyrshin 2010-02-04 10:13:58 MSK
А для двухбайтовых чисел эта же проблема присутствует?
Comment 2 Dmitry A. Kharitonov 2010-02-04 13:04:20 MSK
(В ответ на комментарий №1)
> А для двухбайтовых чисел эта же проблема присутствует?

[user@localhost Documents]$ cat bugif.c
#include <avr/io.h>

int main(void) {
    volatile uint16_t a=8,b=7;
a++;
b++;
if(a==b) a++;
if(b) b++;
return 0;
}
[user@localhost Documents]$ avr-gcc -Wall -Werror -g -Os -o bugif.elf -mint8 -I/usr/include/avr -mmcu=atmega8535 bugif.c; avr-objdump -S -h bugif.elf >bugif.S

  8c:	8b 83       	std	Y+3, r24	; 0x03
if(a==b) a++;
  8e:	29 81       	ldd	r18, Y+1	; 0x01
  90:	3a 81       	ldd	r19, Y+2	; 0x02
  92:	8b 81       	ldd	r24, Y+3	; 0x03
  94:	9c 81       	ldd	r25, Y+4	; 0x04
  96:	28 17       	cp	r18, r24
  98:	39 07       	cpc	r19, r25
  9a:	29 f4       	brne	.+10     	; 0xa6 <main+0x44>
  9c:	89 81       	ldd	r24, Y+1	; 0x01
  9e:	9a 81       	ldd	r25, Y+2	; 0x02
  a0:	01 96       	adiw	r24, 0x01	; 1
  a2:	9a 83       	std	Y+2, r25	; 0x02
  a4:	89 83       	std	Y+1, r24	; 0x01
if(b) b++;
  a6:	8b 81       	ldd	r24, Y+3	; 0x03
  a8:	9c 81       	ldd	r25, Y+4	; 0x04
  aa:	89 2b       	or	r24, r25
  ac:	29 f0       	breq	.+10     	; 0xb8 <main+0x56>
  ae:	8b 81       	ldd	r24, Y+3	; 0x03
  b0:	9c 81       	ldd	r25, Y+4	; 0x04
  b2:	01 96       	adiw	r24, 0x01	; 1
  b4:	9c 83       	std	Y+4, r25	; 0x04
  b6:	8b 83       	std	Y+3, r24	; 0x03
return 0;

В общем да.
Comment 3 Dmitry A. Kharitonov 2010-02-05 18:23:38 MSK
Windowая версия работает так же:

if(a==b) a++;
  6c:   29 81           ldd     r18, Y+1        ; 0x01
  6e:   3a 81           ldd     r19, Y+2        ; 0x02
  70:   8b 81           ldd     r24, Y+3        ; 0x03
  72:   9c 81           ldd     r25, Y+4        ; 0x04
  74:   28 17           cp      r18, r24
  76:   39 07           cpc     r19, r25
  78:   29 f4           brne    .+10            ; 0x84 <__SREG__+0x45>
  7a:   89 81           ldd     r24, Y+1        ; 0x01
  7c:   9a 81           ldd     r25, Y+2        ; 0x02
  7e:   01 96           adiw    r24, 0x01       ; 1
  80:   9a 83           std     Y+2, r25        ; 0x02
  82:   89 83           std     Y+1, r24        ; 0x01
if(b) b++;
  84:   8b 81           ldd     r24, Y+3        ; 0x03
  86:   9c 81           ldd     r25, Y+4        ; 0x04
  88:   89 2b           or      r24, r25
  8a:   29 f0           breq    .+10            ; 0x96 <__SREG__+0x57>
  8c:   8b 81           ldd     r24, Y+3        ; 0x03
  8e:   9c 81           ldd     r25, Y+4        ; 0x04
  90:   01 96           adiw    r24, 0x01       ; 1
  92:   9c 83           std     Y+4, r25        ; 0x04
  94:   8b 83           std     Y+3, r24        ; 0x03
return 0;
Comment 4 Dmitry A. Kharitonov 2010-02-08 00:26:47 MSK
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=42976
Comment 5 Vyatcheslav Perevalov 2010-05-09 23:49:35 MSD
(В ответ на комментарий №0)

> 
> Ставить вопрос об удалении из репозитория -- жалко, а кроме меня наверное никто
> не пользуется.
Пользуется. Ну или покрмере, хотелось бы пользоваться.
Comment 6 Dmitry A. Kharitonov 2010-05-11 11:45:36 MSD
Тогда рекомендую сразу пользоваться макросами вроде этих

#define isnz(a) ((uint8_t)(a)|(uint8_t)((uint16_t)(a)>>8)|(uint8_t)((uint32_t)(a)>>16)|(uint8_t)((uint32_t)(a)>>24))

#define isne(a,b) ((((uint8_t)(a))^((uint8_t)(b)))|(((uint8_t)((uint16_t)(a)>>8))^((uint8_t)((uint16_t)(b)>>8)))|(((uint8_t)((uint32_t)(a)>>16))^((uint8_t)((uint32_t)(b)>>16)))|(((uint8_t)((uint32_t)(a)>>24))^((uint8_t)((uint32_t)(b)>>24))))
Comment 7 Dmitry A. Kharitonov 2010-07-07 16:30:32 MSD
ещё отловил:
void getparam(uint8_t len) {
 15a:	0f 93       	push	r16
 15c:	1f 93       	push	r17
 15e:	cf 93       	push	r28
 160:	df 93       	push	r29
 162:	08 2f       	mov	r16, r24
 164:	c8 e6       	ldi	r28, 0x68	; 104
 166:	d0 e0       	ldi	r29, 0x00	; 0
 168:	0b c0       	rjmp	.+22     	; 0x180 <getparam+0x26>
    uint8_t *buf=cmdbuf,tt;
//     len--;
    for(;len>0;len--) {
 16a:	1a e0       	ldi	r17, 0x0A	; 10
        int16_t t;
        for(tt=10;tt>0;tt--) {
            t=uart_getchar();
 16c:	2d d1       	rcall	.+602    	; 0x3c8 <uart_getchar>
            if(t>0) break;
 16e:	18 16       	cp	r1, r24
 170:	19 06       	cpc	r1, r25
 172:	24 f0       	brlt	.+8      	; 0x17c <getparam+0x22>
void getparam(uint8_t len) {
    uint8_t *buf=cmdbuf,tt;
//     len--;
    for(;len>0;len--) {
        int16_t t;
        for(tt=10;tt>0;tt--) {
 174:	11 50       	subi	r17, 0x01	; 1
 176:	d1 f7       	brne	.-12     	; 0x16c <getparam+0x12>
            t=uart_getchar();
            if(t>0) break;
        }
        if(t<0) return;
 178:	00 97       	sbiw	r24, 0x00	; 0
 17a:	21 f4       	brne	.+8      	; 0x184 <getparam+0x2a>
        *buf++ =t;
 17c:	89 93       	st	Y+, r24
uint8_t cmdbuf[8];

void getparam(uint8_t len) {
    uint8_t *buf=cmdbuf,tt;
//     len--;
    for(;len>0;len--) {
 17e:	01 50       	subi	r16, 0x01	; 1
 180:	00 23       	and	r16, r16
 182:	99 f7       	brne	.-26     	; 0x16a <getparam+0x10>
 184:	df 91       	pop	r29
 186:	cf 91       	pop	r28
 188:	1f 91       	pop	r17
 18a:	0f 91       	pop	r16
 18c:	08 95       	ret

по адресу 174-176
Comment 8 Dmitry A. Kharitonov 2010-07-07 16:36:24 MSD
вру по адресу 178-17a
Comment 9 Grigory Milev 2011-01-18 12:59:27 MSK
Что то я не вижу противоречия, вот пример кода проверки 2х байтных чисел:
                         ; Сравнить r3 : r2 с r1 : r0
         cp r2, r0  ; Сравнить старший байт
         cpc r3, r1 ; Сравнить младший байт
         brne noteq ; Перейти если не равно
(взято вот тут: http://www.gaw.ru/html.cgi/txt/doc/micros/avr/asm/cpc.htm)

Чем не устраивает вызов CP и вслед за ним CPC, судя по документации CPC учитывает результат выполнения предыдущей команды. Не вижу в данном коде никаких ошибок!
Comment 10 Dmitry A. Kharitonov 2011-01-18 16:09:09 MSK
что будет, если r2=1 r0=2 r3=1 r1=0? Сточки зрения компилятора числа будут равны. Так, как результат последней операции (cpc) будет равен нулю.
Я почти день угрохал, когда первый раз пытался понять почему программа работает не правильно.
Такая конструкция возможна только при выяснении какое число больше другого без предположения о равенстве.
Comment 11 Grigory Milev 2011-01-18 17:23:46 MSK
Честно говоря не совсем понимаю, почему на равенство не отработает:
cp
cpc
cpc
????
Comment 12 Dmitry A. Kharitonov 2011-01-18 17:52:55 MSK
видимо многие не понимают.
r2=1 
r0=2 
r3=1 
r1=0

         cp r2, r0  ; r2-r0   => 1-2=-1 => 0xff : c=1 : z=0
         cpc r3, r1 ; r3-r1-c => 1-0-1  => 0x00 : c=0 : z=1
         brne noteq ; z==0 ? => перехода не будет
Comment 13 Dmitry A. Kharitonov 2011-01-18 18:00:50 MSK
к стати, в ссылке, которую вы привели вообще невозможно понять как эта команда работает.
Comment 14 Ivan A. Melnikov 2011-01-19 23:39:30 MSK
(In reply to comment #13)
> к стати, в ссылке, которую вы привели вообще невозможно понять как эта команда
> работает.

cpc не трогает флаг z если результат вычетания 0.

http://www.atmel.com/dyn/resources/prod_documents/doc0856.pdf страница 61