реклама на сайте
подробности

 
 
4 страниц V   1 2 3 > »   
Reply to this topicStart new topic
> IAR 6.4 Optimization Bug, изменение работы алгоритма при включении оптимизации
Sagittarius
сообщение Oct 3 2012, 05:50
Сообщение #1


Местный
***

Группа: Свой
Сообщений: 207
Регистрация: 26-01-06
Из: СПб
Пользователь №: 13 659



Здравствуйте.

Была в проекте написана простая функция преобразования числа uint32 в строку, без оптимизации работает, при включении Optimization/High/Speed и наличии опции Function Inlining вместо всего числа в строку заносит только последнюю цифру. Функцию конечно поправил так чтоб работала и при оптимизации но как то все равно неприятно, где еще ждать косяков.
сам код:

CODE
//
///8*************************************************
// перевод числа i в строку символов в buf длиной = maxlen
uint32_t Int2Str(uint32_t i,uint8_t *buf,uint32_t maxlen){
uint32_t j;
uint32_t k,l;
uint32_t idx;

idx=0;
// используется только для преобразования даты
if((i<10000)&&(maxlen)&&(maxlen<=4)){
for(j=(maxlen-1);j;j--){
buf[idx]='0';
k=Pow10(j);
for(l=9;l;l--){
if(i>=k){
i-=k;
buf[idx]++;
}else l=1; // выход из цикла
}
idx++;
}
buf[idx]='0'+i;
idx++;
}
// buf[idx]=0;
return idx;
}

///8*************************************************
uint32_t Pow10(uint32_t p){// возвращает 10^p
uint32_t ret=1;
if(p>8)ret=0;
else{
for(;p;p--)ret*=10;
}
return ret;
}




Отдельный проект с этими функциями в IAR:
Прикрепленный файл  iarbug.rar ( 15.32 килобайт ) Кол-во скачиваний: 76

Было обнаружено на STM32F103, проверено наличие бага и для LPC2378

Спасибо.
Go to the top of the page
 
+Quote Post
Lotor
сообщение Oct 3 2012, 06:01
Сообщение #2


Местный
***

Группа: Свой
Сообщений: 476
Регистрация: 3-07-07
Из: Санкт-Петербург
Пользователь №: 28 866



Что Вы хотели донести до общественности? Правильнее выложить asm-листинги и указать различия до и после оптимизации.


--------------------
Ковырял чукча отверткой в ухе, звук в телевизоре и пропал.
Go to the top of the page
 
+Quote Post
Sagittarius
сообщение Oct 3 2012, 06:17
Сообщение #3


Местный
***

Группа: Свой
Сообщений: 207
Регистрация: 26-01-06
Из: СПб
Пользователь №: 13 659



Цитата(Lotor @ Oct 3 2012, 10:01) *
Что Вы хотели донести до общественности? Правильнее выложить asm-листинги и указать различия до и после оптимизации.

1. Есть баги изменяющие работающий без оптимизации алгоритм
2. выложен проект, кто хочет - скомпилит и посмотрит сам.
Go to the top of the page
 
+Quote Post
Lotor
сообщение Oct 3 2012, 06:50
Сообщение #4


Местный
***

Группа: Свой
Сообщений: 476
Регистрация: 3-07-07
Из: Санкт-Петербург
Пользователь №: 28 866



Цитата(Sagittarius @ Oct 3 2012, 10:17) *
1. Есть баги изменяющие работающий без оптимизации алгоритм
2. выложен проект, кто хочет - скомпилит и посмотрит сам.

Т.е. Вы не в состоянии указать почему эти баги появились/исчезли? Если хотите обвинить оптимизацию в иаре, то потрудитесь выложить асм код до/после оптимизации и покажите на "IAR 6.4 Optimization Bug".
Цитата(Sagittarius @ Oct 3 2012, 09:50) *
но как то все равно неприятно, где еще ждать косяков.

С таким подходом везде... =)


--------------------
Ковырял чукча отверткой в ухе, звук в телевизоре и пропал.
Go to the top of the page
 
+Quote Post
VslavX
сообщение Oct 3 2012, 06:55
Сообщение #5


embarrassed systems engineer
*****

Группа: Свой
Сообщений: 1 083
Регистрация: 24-10-05
Из: Осокорки
Пользователь №: 10 038



Цитата(Sagittarius @ Oct 3 2012, 08:50) *
Была в проекте написана простая функция преобразования числа uint32 в строку

Вы меня извините, но это далеко не простая функция, сразу бросаются в глаза алгоритмические косяки:

- вычисление степени 10 в цикле (facepalm)
(это можно сделать таблицей, да и вообще без степеней можно обойтись)

- вычисление очередной цифры циклом вычитания (facepalm)
(про деление автору ничего неизвестно?)

- выход из цикла с лишним сравнением условия (l=1) (facepalm)
(банальный break там просится)

ИМХО, тут не в компиляторе "собака порылась".
Go to the top of the page
 
+Quote Post
Sagittarius
сообщение Oct 3 2012, 07:43
Сообщение #6


Местный
***

Группа: Свой
Сообщений: 207
Регистрация: 26-01-06
Из: СПб
Пользователь №: 13 659



Цитата(VslavX @ Oct 3 2012, 10:55) *
Вы меня извините, но это далеко не простая функция, сразу бросаются в глаза алгоритмические косяки:
ИМХО, тут не в компиляторе "собака порылась".

Речь не о кривости алгоритма а о разной его работе при отключенной и включенной оптимизации в компиляторе.
про степень согласен, но тогда баг скорее всего бы не вылез :-)
деление - писалось под ARM7TDMI, там нет аппаратного деления, был бы вызов библиотечной функции
break - просто мне он не нравится, так же как и return из середины функции.

2Lotr: это просто сообщение о наличии проблемы в IAR 6.4 и проект где она воспроизводится. Я ее обошел, мне не мешает. Если кому то надо то он прочитает и разберется сам.
Go to the top of the page
 
+Quote Post
Lotor
сообщение Oct 3 2012, 08:31
Сообщение #7


Местный
***

Группа: Свой
Сообщений: 476
Регистрация: 3-07-07
Из: Санкт-Петербург
Пользователь №: 28 866



Цитата(Sagittarius @ Oct 3 2012, 11:43) *
это просто сообщение о наличии проблемы в IAR 6.4 и проект где она воспроизводится. Я ее обошел, мне не мешает. Если кому то надо то он прочитает и разберется сам.

Я устал намекать, что скорее всего проблема не в оптимизаторе компилятора. Обходили Вы свои же косяки.

PS: Вам нужно самому разобраться и осознать, что 99% ошибок в наши дни - именно авторские, а не компилятора/кристалла.


--------------------
Ковырял чукча отверткой в ухе, звук в телевизоре и пропал.
Go to the top of the page
 
+Quote Post
VslavX
сообщение Oct 3 2012, 09:01
Сообщение #8


embarrassed systems engineer
*****

Группа: Свой
Сообщений: 1 083
Регистрация: 24-10-05
Из: Осокорки
Пользователь №: 10 038



Цитата(Sagittarius @ Oct 3 2012, 10:43) *
Речь не о кривости алгоритма а о разной его работе при отключенной и включенной оптимизации в компиляторе.
про степень согласен, но тогда баг скорее всего бы не вылез :-)

Ну я вообще-то осторожно намекал что там, скорее всего, еще косяки есть, а не только "бросившиеся в глаза".

Цитата(Sagittarius @ Oct 3 2012, 10:43) *
деление - писалось под ARM7TDMI, там нет аппаратного деления, был бы вызов библиотечной функции

А почему не устраивает библиотечная функция? Недостаточно быстрая для использования при выводе строки? Ну если уж такие требования к скорости, то надо было бы рассмотреть алгоритмы быстрого деления на константу (через умножение, Кнут, том 2). И сделать две явные версии - для процессоров с аппаратным делением и без (а при использовании библиотеки это автоматом).

ИМХО, разумным (чтобы не заводить таблицу из 10000 слов) по скорости для вывода в ASCII числа 0-9999 было бы одно деление на 100 с остатком, и вывод двух чисел 0-99 (частного и остатка) по готовой табличке ('00' .. '99'). В этом одном делении, даже универсальном (не константу, на любое число) программном в библиотечной функции, было бы максимум 8 итераций цикла деления. Сравните со своими средним количеством циклов 20 (циклы вычисления степени не учитываем).

Цитата(Sagittarius @ Oct 3 2012, 10:43) *
break - просто мне он не нравится, так же как и return из середины функции.

OK, имейте лишнюю проверку условия, раз уж нравится (за скорость уже не боремся?). И необходимость полной ревизии цикла, если условие в цикле надо будет изменить. "return" - то несколько из другой оперы.

ЗЫ: Я тоже думаю что 99% компилятор тут не при чем. "Листинг в студию, сестра!" ©
Go to the top of the page
 
+Quote Post
scifi
сообщение Oct 3 2012, 10:14
Сообщение #9


Гуру
******

Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136



Кстати, и мне интересно. Без доказательств всё это выглядит как наброс. Нет, ЯР не безгрешен, но гораздо чаще встречаются косяки программиста.
Список доказательств:
1) исходники (вроде бы есть)
2) правильный (ожидаемый) результат работы программы
3) неправильный результат
4) дизассембленый листинг кода, давшего неправильный результат
Go to the top of the page
 
+Quote Post
Sagittarius
сообщение Oct 3 2012, 11:21
Сообщение #10


Местный
***

Группа: Свой
Сообщений: 207
Регистрация: 26-01-06
Из: СПб
Пользователь №: 13 659



в архиве проект под IAR, оптимизация включена. Запускаем симулятор. Содержимое buf после выполнения функции {0,0,'7',0,0}
Отключаем оптимизацию, запускаем. Содержимое буфера {'7','7','7',0,0}. По поводу косячности функции - была проверена записью в файл и последующем чтении из файла в диапазоне входных значений 0-9999, результат корректен Задачи оптимизации данной функции не ставилось.
Go to the top of the page
 
+Quote Post
KRS
сообщение Oct 3 2012, 11:44
Сообщение #11


Профессионал
*****

Группа: Модераторы
Сообщений: 1 951
Регистрация: 27-08-04
Из: Санкт-Петербург
Пользователь №: 555



Так вы бы листинг и привели с указанием ошибки!
Честно говоря такую кривую функцию даже компилировать не хочется!

Если уж нужна быстрая - так у всех АРМ есть умножение и можно обойтись без циклов, примерно так (для 4 разрядных чисел)
Код
    d=(v*8389)>>23;
    v=v-d*1000;
    buf[0]=d+'0';
    d=(v*41)>>12;
    v=v-d*100;
    buf[1]=d+'0';
    d=(v*103)>>10;
    buf[2]=d+'0';
    v=v-d*10;
    buf[3]=d+'0';


Go to the top of the page
 
+Quote Post
scifi
сообщение Oct 3 2012, 11:47
Сообщение #12


Гуру
******

Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136



Может быть, кому-то захочется покопаться:
Исходник (орфография и пунктуация автора сохранены):
CODE
#include <ctype.h>
#include <stdint.h>
#include <intrinsics.h>


uint32_t Int2Str(uint32_t i,uint8_t *buf,uint32_t maxlen);
uint32_t Pow10(uint32_t p);

volatile uint8_t buf[5];

void main(void){
// Int2Str(777,buf,3);
while(1){
Int2Str(777,(uint8_t*)buf,3);
buf[0]++;
buf[2]++;
buf[4]++;
}
}



///8*************************************************
// перевод числа i в строку символов в buf длиной = maxlen
uint32_t Int2Str(uint32_t i,uint8_t *buf,uint32_t maxlen){
uint32_t j;
uint32_t k,l;
uint32_t idx;

idx=0;
// используется только для преобразования даты
if((i<10000)&&(maxlen)&&(maxlen<=4)){
for(j=(maxlen-1);j;j--){
buf[idx]='0';
k=Pow10(j);
for(l=9;l;l--){
if(i>=k){
i-=k;
buf[idx]++;
}else l=1; // выход из цикла
}
idx++;
}
buf[idx]='0'+i;
idx++;
}
// buf[idx]=0;
return idx;
}

/*
// корректно оптимизируемый код
uint32_t Int2Str(uint32_t i,uint8_t *buf,uint32_t maxlen){
uint32_t j;
uint32_t k,l;
uint32_t idx;

idx=0;
// используется только для преобразования даты
if((i<10000)&&(maxlen)&&(maxlen<=4)){
for(j=(maxlen-1);j;j--){
*buf='0';
k=Pow10(j);
for(l=9;l;l--){
if(i>=k){
i-=k;
(*buf)++;
}else l=1; // выход из цикла
}
buf++;
}
*buf='0'+i;
idx++;
}
// buf[idx]=0;
return idx;
}

*/



///8*************************************************
uint32_t Pow10(uint32_t p){// возвращает 10^p
uint32_t ret=1;
if(p>8)ret=0;
else{
for(;p;p--)ret*=10;
}
return ret;
}

Дизассемблер:
CODE
void main(void){
main:
0x2f4: 0x480f LDR.N R0, ??DataTable1 ; buf
0x2f6: 0xe00f B.N ??main_0 ; 0x318
}else l=1; // auoia ec oeeea
??main_1:
0x2f8: 0x2601 MOVS R6, #1
for(l=9;l;l--){
??main_2:
0x2fa: 0x1e76 SUBS R6, R6, #1
0x2fc: 0xd116 BNE.N ??main_3 ; 0x32c
for(j=(maxlen-1);j;j--){
0x2fe: 0x1e64 SUBS R4, R4, #1
for(j=(maxlen-1);j;j--){
0x300: 0xd10c BNE.N ??main_4 ; 0x31c
buf[idx]='0'+i;
0x302: 0x3330 ADDS R3, R3, #48 ; 0x30
0x304: 0x7083 STRB R3, [R0, #0x2]
return idx;
0x306: 0x7803 LDRB R3, [R0]
0x308: 0x1c5b ADDS R3, R3, #1
0x30a: 0x7003 STRB R3, [R0]
0x30c: 0x7883 LDRB R3, [R0, #0x2]
0x30e: 0x1c5b ADDS R3, R3, #1
0x310: 0x7083 STRB R3, [R0, #0x2]
0x312: 0x7903 LDRB R3, [R0, #0x4]
0x314: 0x1c5b ADDS R3, R3, #1
0x316: 0x7103 STRB R3, [R0, #0x4]
??main_0:
0x318: 0x4b07 LDR.N R3, ??DataTable1_1 ; 0x309 (777)
for(j=(maxlen-1);j;j--){
0x31a: 0x2402 MOVS R4, #2
uint32_t ret=1;
??main_4:
0x31c: 0x2501 MOVS R5, #1
if(p>8)ret=0;
0x31e: 0x0026 MOVS R6, R4
for(;p;p--)ret*=10;
??main_5:
0x320: 0x00af LSLS R7, R5, #2
0x322: 0x197d ADDS R5, R7, R5
0x324: 0x006d LSLS R5, R5, #1
for(;p;p--)ret*=10;
0x326: 0x1e76 SUBS R6, R6, #1
for(;p;p--)ret*=10;
0x328: 0xd1fa BNE.N ??main_5 ; 0x320
for(l=9;l;l--){
0x32a: 0x2609 MOVS R6, #9
if(i>=k){
??main_3:
0x32c: 0x42ab CMP R3, R5
0x32e: 0xd3e3 BCC.N ??main_1 ; 0x2f8
i-=k;
0x330: 0x1b5b SUBS R3, R3, R5
buf[idx]++;
0x332: 0xe7e2 B.N ??main_2 ; 0x2fa
??DataTable1:
0x334: 0x40000120 DC32 buf
??DataTable1_1:
0x338: 0x00000309 DC32 777 ; ' ...'
exit:
0x33c: 0xb580 PUSH {R7, LR}
0x33e: 0xf000 0xf825 BL ?Veneer (4) for _exit ; 0x38c
0x342: 0xbc09 POP {R0, R3}
0x344: 0x4718 BX R3

Да, код заполняет в буфере только позицию buf[2] = '7'.
Go to the top of the page
 
+Quote Post
KRS
сообщение Oct 3 2012, 12:30
Сообщение #13


Профессионал
*****

Группа: Модераторы
Сообщений: 1 951
Регистрация: 27-08-04
Из: Санкт-Петербург
Пользователь №: 555



Видно что
buf[idx]++;
компилятор выкинул

Кстати если inline отключить, т.е. и Pow и Int2Str будут как функции!
Все равно buf[idx]++; выкидывает!


На самом деле бага довольно серьезная!!! И может вылезти в проектах sad.gif
Если в цикле используется buf[i]++, а после цикла присваивание последнему элементу массива проявляется!

Для иллюстрации 2 простых функции
Код
void test_bug(uint32_t v, uint8_t *buf)
{
    unsigned i;
    for(i=0;i<3;i++){
        buf[i]='0';
        if (v & 1<<i)
            buf[i]++;
    }
    buf[i]=v & 0x8;
}

void test_bug2(uint32_t v, uint8_t *buf)
{
    unsigned i;
    for(i=0;i<3;i++){
        buf[i]='0';
        if (v & 1<<i)
            buf[i]++;
    }
}


А вот листинг

Код
  19          void test_bug(uint32_t v, uint8_t *buf)
     20          {
     21              unsigned i;
     22              for(i=0;i<3;i++){
     23                  buf[i]='0';
     24                  if (v & 1<<i)
     25                      buf[i]++;
     26              }
     27              buf[i]=v & 0x8;
   \                     test_bug:
   \   00000000   0x2208             MOVS     R2,#+8
   \   00000002   0x4010             ANDS     R0,R0,R2
   \   00000004   0x70C8             STRB     R0,[R1, #+3]
     28          }
   \   00000006   0x4770             BX       LR              ;; return
     29          

   \                                 In section .text, align 2, keep-with-next
     30          void test_bug2(uint32_t v, uint8_t *buf)
     31          {
   \                     test_bug2:
   \   00000000   0xB418             PUSH     {R3,R4}
     32              unsigned i;
     33              for(i=0;i<3;i++){
   \   00000002   0x2230             MOVS     R2,#+48
     34                  buf[i]='0';
   \   00000004   0x2330             MOVS     R3,#+48
     35                  if (v & 1<<i)
   \   00000006   0x07C4             LSLS     R4,R0,#+31
   \   00000008   0xD500             BPL      ??test_bug2_0
     36                      buf[i]++;
   \   0000000A   0x2331             MOVS     R3,#+49
   \                     ??test_bug2_0:
   \   0000000C   0x700B             STRB     R3,[R1, #+0]
   \   0000000E   0x2330             MOVS     R3,#+48
   \   00000010   0x0784             LSLS     R4,R0,#+30
   \   00000012   0xD500             BPL      ??test_bug2_1
   \   00000014   0x2331             MOVS     R3,#+49
   \                     ??test_bug2_1:
   \   00000016   0x704B             STRB     R3,[R1, #+1]
   \   00000018   0x0740             LSLS     R0,R0,#+29
   \   0000001A   0xD500             BPL      ??test_bug2_2
   \   0000001C   0x2231             MOVS     R2,#+49
   \                     ??test_bug2_2:
   \   0000001E   0x708A             STRB     R2,[R1, #+2]
     37              }
     38          }
   \   00000020   0xBC11             POP      {R0,R4}
   \   00000022   0x4770             BX       LR              ;; return

   \                                 In section .text, align 4, keep-with-next
   \                     ??DataTable0:
   \   00000000   0x........         DC32     buf


Видно что в первом варианте код весь убран!

Вы будете смеяться!!!
все еще проще sm.gif

void test_bug3(uint8_t *buf)
{
unsigned i;
for(i=0;i<3;i++){
buf[i]=0;
}
buf[i]=0;
}

Код
                                In section .text, align 2, keep-with-next
     40          void test_bug3(uint8_t *buf)
     41          {
     42              unsigned i;
     43              for(i=0;i<3;i++){
     44                  buf[i]=0;
     45              }
     46              buf[i]=0;
   \                     test_bug3:
   \   00000000   0x2100             MOVS     R1,#+0
   \   00000002   0x70C1             STRB     R1,[R0, #+3]
     47          }
   \   00000004   0x4770             BX       LR              ;; return

Go to the top of the page
 
+Quote Post
chernenko
сообщение Oct 3 2012, 12:40
Сообщение #14


Частый гость
**

Группа: Свой
Сообщений: 170
Регистрация: 8-02-06
Из: Москва
Пользователь №: 14 116



Может я не то что-то делаю, но у меня на 6.10 (другого нет) корректно работает.
Go to the top of the page
 
+Quote Post
KRS
сообщение Oct 3 2012, 12:52
Сообщение #15


Профессионал
*****

Группа: Модераторы
Сообщений: 1 951
Регистрация: 27-08-04
Из: Санкт-Петербург
Пользователь №: 555



так писали про 6.4

у меня
IAR ANSI C/C++ Compiler V6.40.1.53790/W32 for ARM

в итоге самый простой код приводящий к ошибке
Код
void test_bug3(uint8_t *buf)
{
    unsigned i;
    for(i=0;i<100;i++){
        buf[i]=0;
    }
    buf[i]=0;
}


в цикле константа может быть любая! (пробовал 3,4,7,100)
видимо ЯР видя за циклом buf[i]=0, не учитывает что в цикле индекс меняется и buf[i] это разные элементы массива.
Go to the top of the page
 
+Quote Post

4 страниц V   1 2 3 > » 
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 20th July 2025 - 23:52
Рейтинг@Mail.ru


Страница сгенерированна за 0.01443 секунд с 7
ELECTRONIX ©2004-2016