Sagittarius 0 3 октября, 2012 Опубликовано 3 октября, 2012 · Жалоба Здравствуйте. Была в проекте написана простая функция преобразования числа uint32 в строку, без оптимизации работает, при включении Optimization/High/Speed и наличии опции Function Inlining вместо всего числа в строку заносит только последнюю цифру. Функцию конечно поправил так чтоб работала и при оптимизации но как то все равно неприятно, где еще ждать косяков. сам код: // ///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 Было обнаружено на STM32F103, проверено наличие бага и для LPC2378 Спасибо. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
lotor 0 3 октября, 2012 Опубликовано 3 октября, 2012 · Жалоба Что Вы хотели донести до общественности? Правильнее выложить asm-листинги и указать различия до и после оптимизации. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Sagittarius 0 3 октября, 2012 Опубликовано 3 октября, 2012 · Жалоба Что Вы хотели донести до общественности? Правильнее выложить asm-листинги и указать различия до и после оптимизации. 1. Есть баги изменяющие работающий без оптимизации алгоритм 2. выложен проект, кто хочет - скомпилит и посмотрит сам. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
lotor 0 3 октября, 2012 Опубликовано 3 октября, 2012 · Жалоба 1. Есть баги изменяющие работающий без оптимизации алгоритм 2. выложен проект, кто хочет - скомпилит и посмотрит сам. Т.е. Вы не в состоянии указать почему эти баги появились/исчезли? Если хотите обвинить оптимизацию в иаре, то потрудитесь выложить асм код до/после оптимизации и покажите на "IAR 6.4 Optimization Bug". но как то все равно неприятно, где еще ждать косяков. С таким подходом везде... =) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
VslavX 0 3 октября, 2012 Опубликовано 3 октября, 2012 · Жалоба Была в проекте написана простая функция преобразования числа uint32 в строку Вы меня извините, но это далеко не простая функция, сразу бросаются в глаза алгоритмические косяки: - вычисление степени 10 в цикле (facepalm) (это можно сделать таблицей, да и вообще без степеней можно обойтись) - вычисление очередной цифры циклом вычитания (facepalm) (про деление автору ничего неизвестно?) - выход из цикла с лишним сравнением условия (l=1) (facepalm) (банальный break там просится) ИМХО, тут не в компиляторе "собака порылась". Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Sagittarius 0 3 октября, 2012 Опубликовано 3 октября, 2012 · Жалоба Вы меня извините, но это далеко не простая функция, сразу бросаются в глаза алгоритмические косяки: ИМХО, тут не в компиляторе "собака порылась". Речь не о кривости алгоритма а о разной его работе при отключенной и включенной оптимизации в компиляторе. про степень согласен, но тогда баг скорее всего бы не вылез :-) деление - писалось под ARM7TDMI, там нет аппаратного деления, был бы вызов библиотечной функции break - просто мне он не нравится, так же как и return из середины функции. 2Lotr: это просто сообщение о наличии проблемы в IAR 6.4 и проект где она воспроизводится. Я ее обошел, мне не мешает. Если кому то надо то он прочитает и разберется сам. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
lotor 0 3 октября, 2012 Опубликовано 3 октября, 2012 · Жалоба это просто сообщение о наличии проблемы в IAR 6.4 и проект где она воспроизводится. Я ее обошел, мне не мешает. Если кому то надо то он прочитает и разберется сам. Я устал намекать, что скорее всего проблема не в оптимизаторе компилятора. Обходили Вы свои же косяки. PS: Вам нужно самому разобраться и осознать, что 99% ошибок в наши дни - именно авторские, а не компилятора/кристалла. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
VslavX 0 3 октября, 2012 Опубликовано 3 октября, 2012 · Жалоба Речь не о кривости алгоритма а о разной его работе при отключенной и включенной оптимизации в компиляторе. про степень согласен, но тогда баг скорее всего бы не вылез :-) Ну я вообще-то осторожно намекал что там, скорее всего, еще косяки есть, а не только "бросившиеся в глаза". деление - писалось под ARM7TDMI, там нет аппаратного деления, был бы вызов библиотечной функции А почему не устраивает библиотечная функция? Недостаточно быстрая для использования при выводе строки? Ну если уж такие требования к скорости, то надо было бы рассмотреть алгоритмы быстрого деления на константу (через умножение, Кнут, том 2). И сделать две явные версии - для процессоров с аппаратным делением и без (а при использовании библиотеки это автоматом). ИМХО, разумным (чтобы не заводить таблицу из 10000 слов) по скорости для вывода в ASCII числа 0-9999 было бы одно деление на 100 с остатком, и вывод двух чисел 0-99 (частного и остатка) по готовой табличке ('00' .. '99'). В этом одном делении, даже универсальном (не константу, на любое число) программном в библиотечной функции, было бы максимум 8 итераций цикла деления. Сравните со своими средним количеством циклов 20 (циклы вычисления степени не учитываем). break - просто мне он не нравится, так же как и return из середины функции. OK, имейте лишнюю проверку условия, раз уж нравится (за скорость уже не боремся?). И необходимость полной ревизии цикла, если условие в цикле надо будет изменить. "return" - то несколько из другой оперы. ЗЫ: Я тоже думаю что 99% компилятор тут не при чем. "Листинг в студию, сестра!" © Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
scifi 1 3 октября, 2012 Опубликовано 3 октября, 2012 · Жалоба Кстати, и мне интересно. Без доказательств всё это выглядит как наброс. Нет, ЯР не безгрешен, но гораздо чаще встречаются косяки программиста. Список доказательств: 1) исходники (вроде бы есть) 2) правильный (ожидаемый) результат работы программы 3) неправильный результат 4) дизассембленый листинг кода, давшего неправильный результат Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Sagittarius 0 3 октября, 2012 Опубликовано 3 октября, 2012 · Жалоба в архиве проект под IAR, оптимизация включена. Запускаем симулятор. Содержимое buf после выполнения функции {0,0,'7',0,0} Отключаем оптимизацию, запускаем. Содержимое буфера {'7','7','7',0,0}. По поводу косячности функции - была проверена записью в файл и последующем чтении из файла в диапазоне входных значений 0-9999, результат корректен Задачи оптимизации данной функции не ставилось. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
KRS 1 3 октября, 2012 Опубликовано 3 октября, 2012 · Жалоба Так вы бы листинг и привели с указанием ошибки! Честно говоря такую кривую функцию даже компилировать не хочется! Если уж нужна быстрая - так у всех АРМ есть умножение и можно обойтись без циклов, примерно так (для 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'; Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
scifi 1 3 октября, 2012 Опубликовано 3 октября, 2012 · Жалоба Может быть, кому-то захочется покопаться: Исходник (орфография и пунктуация автора сохранены): #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; } Дизассемблер: 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'. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
KRS 1 3 октября, 2012 Опубликовано 3 октября, 2012 · Жалоба Видно что buf[idx]++; компилятор выкинул Кстати если inline отключить, т.е. и Pow и Int2Str будут как функции! Все равно buf[idx]++; выкидывает! На самом деле бага довольно серьезная!!! И может вылезти в проектах :( Если в цикле используется buf++, а после цикла присваивание последнему элементу массива проявляется! Для иллюстрации 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 Видно что в первом варианте код весь убран! Вы будете смеяться!!! все еще проще :) void test_bug3(uint8_t *buf) { unsigned i; for(i=0;i<3;i++){ buf=0; } buf=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 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
chernenko 0 3 октября, 2012 Опубликовано 3 октября, 2012 · Жалоба Может я не то что-то делаю, но у меня на 6.10 (другого нет) корректно работает. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
KRS 1 3 октября, 2012 Опубликовано 3 октября, 2012 · Жалоба так писали про 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=0, не учитывает что в цикле индекс меняется и buf это разные элементы массива. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться