VslavX 0 4 ноября, 2011 Опубликовано 4 ноября, 2011 · Жалоба Попробовал IAR 6.30.1 для Cortex-M3, нарисовалась проблема. Есть такой код: #define b0_l(L) ((unsigned char)((L) & 0xFF)) #define b1_l(L) ((unsigned char)(((L)>>8) & 0xFF)) #define b2_l(L) ((unsigned char)(((L)>>16) & 0xFF)) #define b3_l(L) ((unsigned char)(((L)>>24) & 0xFF)) unsigned long IsDate(unsigned long d) { if ( (b0_l(d)<1) || (b0_l(d)>31) || (b1_l(d)<1) || (b1_l(d)>12) || (b2_l(d)>21) || (b3_l(d)!=0)) { return 0; } if (d == 0x101) { return 0; } return 1; } Функция просто предварительно проверяет значение даты, упакованной в unsigned long. При наличии ключей оптимизации -Om (или -Ohz, другую не пробовал) превращается в такое: \ In section .text, align 2, keep-with-next 49 unsigned long IsDate(unsigned long d) 50 { 51 if ( (b0_l(d)<1) || (b0_l(d)>31) 52 || (b1_l(d)<1) || (b1_l(d)>12) 53 || (b2_l(d)>21) || (b3_l(d)!=0)) \ IsDate: \ 00000000 0x1E41 SUBS R1,R0,#+1 \ 00000002 0x291F CMP R1,#+31 \ 00000004 0xBF3E ITTT CC \ 00000006 0x0A01 LSRCC R1,R0,#+8 \ 00000008 0x1E49 SUBCC R1,R1,#+1 \ 0000000A 0x290C CMPCC R1,#+12 \ 0000000C 0xBF3E ITTT CC \ 0000000E 0x0C01 LSRCC R1,R0,#+16 \ 00000010 0xB2C9 UXTBCC R1,R1 \ 00000012 0x2916 CMPCC R1,#+22 \ 00000014 0xD205 BCS.N ??IsDate_0 \ 00000016 0x0E01 LSRS R1,R0,#+24 \ 00000018 0xD103 BNE.N ??IsDate_0 54 { 55 return 0; 56 } 57 if (d == 0x101) \ 0000001A 0xF240 0x1101 MOVW R1,#+257 \ 0000001E 0x4288 CMP R0,R1 \ 00000020 0xD101 BNE.N ??IsDate_1 58 { 59 return 0; \ ??IsDate_0: \ 00000022 0x2000 MOVS R0,#+0 \ 00000024 0x4770 BX LR 60 } 61 return 1; \ ??IsDate_1: \ 00000026 0x2001 MOVS R0,#+1 \ 00000028 0x4770 BX LR ;; return 62 } И не работает правильно. На версии 5.41 компилируется в рабочий код. Вопрос такой - это я C плоховато знаю или таки глюк компилятора? upd: привел пример к стандартным типам (убрал typedef свои), чтобы не путались Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
KRS 0 4 ноября, 2011 Опубликовано 4 ноября, 2011 · Жалоба Да - в оптимизации явно глюк! Возможно связан с тем что в макросе лишняя операция : & 0xff и (unsigned char) преобразование типа к байту можно оставить что то одно! Лучше убрать (unsigned char) так производительность выше! Потому что если локальная переменная в регистре байтовая ей ARM компилер постоянно чистит старшие биты! Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
VslavX 0 4 ноября, 2011 Опубликовано 4 ноября, 2011 · Жалоба Да - в оптимизации явно глюк! Возможно связан с тем что в макросе лишняя операция : & 0xff и (unsigned char) преобразование типа к байту можно оставить что то одно! Да, если убрать преобразование типа (unsigned char) в макросах, то именно это место компилируется правильно. Беда в том, что этим макросам лет 20, и страшно представить сколько кода на данный момент на них основано - для 8-битных AVR, 16-битных x86 и для 32-битных ARM. Поэтому поменять макросы малореально. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
scifi 1 4 ноября, 2011 Опубликовано 4 ноября, 2011 · Жалоба Может расскажете, где именно в дизассемблере неправильно? Я смотрел, но ничего особенного не увидел... Update: Кажется, увидел. На первой же инструкции делает вычитание из 32-битного аргумента, а должен был сначала отрезать старшие 24 бита. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
KRS 0 4 ноября, 2011 Опубликовано 4 ноября, 2011 · Жалоба 8-битных AVR, 16-битных x86 и для 32-битных ARM. Поэтому поменять макросы малореально. Есть же #ifdef к тому же если убрать одну из операций, оптимальнее преобразование типа - макросы все равно будут рабочими и более оптимальными. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
VslavX 0 5 ноября, 2011 Опубликовано 5 ноября, 2011 · Жалоба Есть же #ifdef к тому же если убрать одну из операций, оптимальнее преобразование типа - макросы все равно будут рабочими и более оптимальными. 1. Убирание "& 0xFF" ситуацию не исправляет - компилируется с той же ошибкой, глючит именно на unsigned char. 2. #ifdef не поможет скомпилировать желаемое для выражений подразумевающих что макрос bx_l() имеет тип unsigned char. То есть - эти выражения все надо будет патчить в куче мест, вставляя явное приведение типа (которое Вы предлагаете выбросить из макроса). Пример - код типа: "unsigned char var1 = b0_l((unsigned long)var2);" даст предупреждение. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
dvb 0 6 ноября, 2011 Опубликовано 6 ноября, 2011 · Жалоба 1. Убирание "& 0xFF" ситуацию не исправляет - компилируется с той же ошибкой, глючит именно на unsigned char. 2. #ifdef не поможет скомпилировать желаемое для выражений подразумевающих что макрос bx_l() имеет тип unsigned char. То есть - эти выражения все надо будет патчить в куче мест, вставляя явное приведение типа (которое Вы предлагаете выбросить из макроса). Пример - код типа: "unsigned char var1 = b0_l((unsigned long)var2);" даст предупреждение. Основная проблема не в том, что определенными телодвижениями можно замести это под ковер, и заставить код работать правильно. А в том, что этот код правильно компилировался десятком разных компиляторов, начиная с BC3.1 и заканчивая IAR 5.41. И не факт, что где-нибудь компилятор не оставит незаметную мину, которая сработает в очень редко вызываемой ветке программы в самый неподходящий момент. Пока от версии IAR 6.30 пришлось отказаться. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
KRS 0 6 ноября, 2011 Опубликовано 6 ноября, 2011 · Жалоба а у IAR периодически вылезают баги с количеством битов при преобразованиях типов и & скоро вылечат! Относительно недавно на подобный баг натыкался, поэтому сразу и понял что проблема в преобразовании типов. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться