| Summary: | Не правильная трансляция оператора if | ||
|---|---|---|---|
| Product: | Sisyphus | Reporter: | Dmitry A. Kharitonov <kharpost> |
| Component: | avr-gcc | Assignee: | Grigory Milev <week> |
| Status: | CLOSED FIXED | QA Contact: | qa-sisyphus |
| Severity: | blocker | ||
| Priority: | P3 | CC: | erthad, iv, kharpost, lex, vip0, viy, week |
| Version: | unstable | ||
| Hardware: | all | ||
| OS: | Linux | ||
А для двухбайтовых чисел эта же проблема присутствует? (В ответ на комментарий №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;
В общем да.
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; (В ответ на комментарий №0)
>
> Ставить вопрос об удалении из репозитория -- жалко, а кроме меня наверное никто
> не пользуется.
Пользуется. Ну или покрмере, хотелось бы пользоваться.
Тогда рекомендую сразу пользоваться макросами вроде этих #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)))) ещё отловил:
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
вру по адресу 178-17a Что то я не вижу противоречия, вот пример кода проверки 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 учитывает результат выполнения предыдущей команды. Не вижу в данном коде никаких ошибок!
что будет, если r2=1 r0=2 r3=1 r1=0? Сточки зрения компилятора числа будут равны. Так, как результат последней операции (cpc) будет равен нулю. Я почти день угрохал, когда первый раз пытался понять почему программа работает не правильно. Такая конструкция возможна только при выяснении какое число больше другого без предположения о равенстве. Честно говоря не совсем понимаю, почему на равенство не отработает: cp cpc cpc ???? видимо многие не понимают.
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 ? => перехода не будет
к стати, в ссылке, которую вы привели вообще невозможно понять как эта команда работает. (In reply to comment #13) > к стати, в ссылке, которую вы привели вообще невозможно понять как эта команда > работает. cpc не трогает флаг z если результат вычетания 0. http://www.atmel.com/dyn/resources/prod_documents/doc0856.pdf страница 61 |
Сравниваются 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> В общем, компилятор скорее мёртв, нежели жив. Ставить вопрос об удалении из репозитория -- жалко, а кроме меня наверное никто не пользуется.