|
Я просто не верю что IAR STM8 такой тупой!, Ведь это же всегда был один из самых качественных компиляторов |
|
|
|
May 9 2017, 20:00
|

I WANT TO BELIEVE
     
Группа: Свой
Сообщений: 2 617
Регистрация: 9-03-08
Пользователь №: 35 751

|
Код #pragma inline=forced static void inline f(uint8_t i) { while(--i) asm(""); }
int main() { f(10); } В результате: Код 183 int main() 184 { \ main: \ 000000 52 01 SUB SP, #0x1 186 f(10); \ 000002 35 0A .... MOV S:?b0, #0xa \ 000006 20 00 JRA L:??main_0 \ ??main_1: \ ??main_0: \ 000008 B6 .. LD A, S:?b0 \ 00000A 4A DEC A \ 00000B B7 .. LD S:?b0, A \ 00000D 26 F9 JRNE L:??main_1 ЗАЧЕМ? Зачем он делает всё это???? Настройки компилятора по полной программе: Multi-file compilation, High, Speed +No size constraints P.S. Cosmic же на много толковее справился, хотя я конечно по прежнему не понимаю почему нельзя просто с регистром A работать.... Зачем в стек то? Код 60 .text: section .text,new 61 0000 _main: 63 0000 88 push a 64 00000001 OFST: set 1 67 ; 10 f(12); 70 0001 a60c ld a,#12 71 0003 6b01 ld (OFST+0,sp),a 74 0005 L72: 75 ; 5 _asm(""); 79 ; 4 while(--i) 81 0005 0a01 dec (OFST+0,sp) 83 0007 26fc jrne L72 /////////////////////////////////////////////// 84 0009 L73: 86 0009 20fe jra L73 99 xdef _main 118 end
--------------------
The truth is out there...
|
|
|
|
|
May 10 2017, 06:51
|

фанат дивана
     
Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684

|
Посмотрите, что из вашего кода делает sdcc, и успокойтесь  Вот: (я только заменил asm("") на asm("nop"), для однозначности). Код ld a, #0x0a 00101$: dec a tnz a jrne 00116$ ret 00116$: nop jra 00101$ ret Вот, если интересно, сравнение компиляторов для stm8. По нему видно, что IAR далеко не лидер в области размера кода. Зато он побеждает в тестах скорости.
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
May 10 2017, 10:01
|

I WANT TO BELIEVE
     
Группа: Свой
Сообщений: 2 617
Регистрация: 9-03-08
Пользователь №: 35 751

|
Грустно, потому что я в другом окне смотрю, что из этого кода делает avr-gcc( вариант с asm("nop") ) Код 00000048 LDI R24,0x09 Load immediate 00000049 NOP No operation 0000004A SUBI R24,0x01 Subtract immediate 0000004B BRNE PC-0x02 Branch if not equal Алсо не очень понятно, как IAR может быть при всех этих лишних телодвижениях быстрее........ Очень жаль, что разработчики компиляторов считают СТМ8 не важной архитектурой  У меня еще есть пример как IAR весело тупит на куске С++ кода, где на этапе компиляции рекурсивно обходится список типов и вызывается функция. Так вот там аналогичным образом IAR просто делает одно и то-же: кладет в стек, грузит в А, кладет в стек, грузит в А.... В то время как GCC просто взял и прошелся одним значением по всем вызовам(ибо они реально не меняются и это известно во время компиляции). В общем печаль полнейшая с этим IAR.... Обидно, что кроме него плюсы никто не поддерживает больше. Sdcc снапшот от 9 мая sdcc -mstm8 --std-c99 --opt-code-size main.c вариант с asm(nop) функциa объявлена как static inline dly(char i); Код 000000 81 _dly: 82; main.c: 3: while(--i) 000000 7B 03 [ 1] 83 ld a, (0x03, sp) 000002 84 00101$: 000002 4A [ 1] 85 dec a 000003 4D [ 1] 86 tnz a 000004 26 01 [ 1] 87 jrne 00115$ 000006 81 [ 4] 88 ret 000007 89 00115$: 90; main.c: 4: __asm__("nop"); 000007 9D [ 1] 91 nop 000008 20 F8 [ 2] 92 jra 00101$ 00000A 81 [ 4] 93 ret 94; main.c: 7: void main(void) 95; ----------------------------------------- 96; function main 97; ----------------------------------------- 00000B 98 _main: 99; main.c: 3: while(--i) 00000B A6 0A [ 1] 100 ld a, #0x0a 00000D 101 00101$: 00000D 4A [ 1] 102 dec a 00000E 4D [ 1] 103 tnz a 00000F 26 01 [ 1] 104 jrne 00116$ 000011 81 [ 4] 105 ret 000012 106 00116$: 107; main.c: 4: __asm__("nop"); 000012 9D [ 1] 108 nop 000013 20 F8 [ 2] 109 jra 00101$ 110; main.c: 9: dly(10); 000015 81 [ 4] 111 ret ЗАИНЛАЙНИЛ БЛИН.....  IAR при инлайне хоть тело функции догадывается убрать....
--------------------
The truth is out there...
|
|
|
|
|
May 10 2017, 18:21
|

фанат дивана
     
Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684

|
А как, по-вашему, должен выглядеть предложенный вами кусок? Покажите, интересно. Я вот сделал пару проектов с использованием sdcc, всё поместилось, всё успелось. Посмотрел в дизассемблер, улыбнулся. Всё выглядит как gcc -O0. Неиспользуемые функции не выкидываются. Ну и ладно. Многие и с gcc так работают, и не жужжат  Кстати, сейчас вроде бы появился вариант LLVM+SDCC. Теоретически, там всё может быть получше. C++ опять же... Попробуете?
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
May 10 2017, 20:01
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(sigmaN @ May 10 2017, 15:13)  Просто обидно что хорошие по переферии и цене процы стм8 так и не имеют сравнимого с авр-гцц компилятора Ну и что? Кому он реально нужен на этом ядре? Реально, а не для того чтоб "проверить". Чтобы решать какую-то вычислительную задачу, требующую серьёзных вычислений на этом ядре??? Для этого следует выбирать другое ядро. Ниша STM8 - помахать ножками немножко, поуправлять не спеша простой периферией. В случае чего в редких случаях можно и асм использовать. Да и рынок пользователей STM8 очень ограничен, это далеко не экосистема ARM - вот там реально нужны хорошие оптимизаторы, и туда и следует прикладывать максимум усилий, и сообщество пользователей там несравнимо больше. И работы по оптимизатору там ещё - море. Нефиг ресурсы разработчиков понапрасну распылять.  PS: А "реально нужен" следует ещё читать и как "кто готов за это заплатить деньги".
|
|
|
|
|
May 11 2017, 01:54
|

I WANT TO BELIEVE
     
Группа: Свой
Сообщений: 2 617
Регистрация: 9-03-08
Пользователь №: 35 751

|
Выглядеть этот кусок может и должен в точности как сделал авр-гцц: кладем в А число итераций-1, тело цикла, dec А далее условный переход на начало тела цикла(jrne метка). Все данные для такого преобразования у компилятора имеются, что гцц и продемонстрировал. LLVM надо конечно попробовать, но учитывая присутствие в связке sdcc...надежды мало  Я конечно не готов платить и использую триал версию IAR, но просто перенести мои наработки с авра на стм8 в полном объёме не получится и это печально. Придется опять на голый си и писать все "в одну функцию" ибо оно даже заинлайнить толково не может однократно вызываемую статик функцию.... я молчу уже про плюсы, где тоже есть явные недоработки оптимизатора  опять же есть с чем сравнивать, хоть меня и обвинят в холливаре. Причины наверно понятны, я конечно не могу оценить объем работ объективно, но что-то прям так и подсказывает, что ИАР просто самую малость не допилили. Вот реально чууть-чуть осталось им и всё было бы круто!
--------------------
The truth is out there...
|
|
|
|
|
May 11 2017, 06:20
|

фанат дивана
     
Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684

|
Цитата(sigmaN @ May 11 2017, 06:54)  Выглядеть этот кусок может и должен в точности как сделал авр-гцц: кладем в А число итераций-1, тело цикла, dec А далее условный переход на начало тела цикла(jrne метка). Дело в том, что любое непустое тело цикла почти гарантированно испортит аккумулятор. Вероятно поэтому IAR сразу располагает переменную цикла в ОЗУ. И вообще, судить об оптимизации по тому, как компилятор заоптмизировал пустой цикл - по меньшей мере странно. К тому же, надо ещё посчитать по тактам, какой вариант выгоднее. Вполне возможно, что IAR при большем числе команд выигрывает в скорости.
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
May 11 2017, 08:34
|

I WANT TO BELIEVE
     
Группа: Свой
Сообщений: 2 617
Регистрация: 9-03-08
Пользователь №: 35 751

|
Тоже потом подумал про испорченный A. Однако же никто не отменял direct indexed sp based адресацию, с которой в один такт может работать dec и jrne тоже сработает. В любом случае то, что делает IAR - это самый ужас, ибо там лишние действия по загрузке/выгрузке A выполняются каждую итерацию! Да, этот пример с пустым циклом он простой и показательный, хотя не претендует на полную объективность. Привести примеры, где происходит просто куча лишних движений не сложно. Опять же: гцц в случае с коротким циклом ума хватает, что такой-то регистр не затирается и его можно испоьзовать. Сделать цикл по-больше и стратегия изменится. Он полезет в стек тоже, а куда денется. Но в этом случае заметно, что компилятор(и его разработчики) стараются )))
--------------------
The truth is out there...
|
|
|
|
|
May 11 2017, 10:24
|

I WANT TO BELIEVE
     
Группа: Свой
Сообщений: 2 617
Регистрация: 9-03-08
Пользователь №: 35 751

|
Цитата Приведите лучше пример реализации БИХ-фильтра для разных компиляторов biggrin.gif Проверено на вполне боевой реализации void fir_mem16() из https://github.com/xiph/speex/blob/master/libspeex/filters.c из Speex Взято как средний случай обычного фильтра на Си, без особых оптимизаций там и всего прочего. Согласен, чистота эксперимента нарушена, т.к. это КИХ фильтр ))))) Но переделывать уже не охота ) Удивительно, но при раздутом размере IAR по тактам таки победил 19498 тактов у IAR 19929 Cosmic Оба последних версий, у обоих оптимизация на скорость включена по максимуму. Added:Мужики, ну я не удержался и скомпилил это на AVR-GCC 6.3.0 10708 тактов оптимизация -O3 Да-даа, я знаю что это разные архитектуры и сравнивать вот так в лоб нельзя, но я просто оставлю эти цифры здесь )))))) полный код теста: Код #include <stdint.h>
typedef int16_t spx_int16_t; typedef uint16_t spx_uint16_t; typedef int32_t spx_int32_t; typedef uint32_t spx_uint32_t;
#define ABS(x) ((x) < 0 ? (-(x)) : (x)) /**< Absolute integer value. */ #define ABS16(x) ((x) < 0 ? (-(x)) : (x)) /**< Absolute 16-bit value. */ #define MIN16(a,b) ((a) < (b) ? (a) : (b)) /**< Maximum 16-bit value. */ #define MAX16(a,b) ((a) > (b) ? (a) : (b)) /**< Maximum 16-bit value. */ #define ABS32(x) ((x) < 0 ? (-(x)) : (x)) /**< Absolute 32-bit value. */ #define MIN32(a,b) ((a) < (b) ? (a) : (b)) /**< Maximum 32-bit value. */ #define MAX32(a,b) ((a) > (b) ? (a) : (b)) /**< Maximum 32-bit value. */
typedef spx_int16_t spx_word16_t; typedef spx_int32_t spx_word32_t; typedef spx_word32_t spx_mem_t; typedef spx_word16_t spx_coef_t; typedef spx_word16_t spx_lsp_t; typedef spx_word32_t spx_sig_t;
#define Q15ONE 32767
#define LPC_SCALING 8192 #define SIG_SCALING 16384 #define LSP_SCALING 8192. #define GAMMA_SCALING 32768. #define GAIN_SCALING 64 #define GAIN_SCALING_1 0.015625
#define LPC_SHIFT 13 #define LSP_SHIFT 13 #define SIG_SHIFT 14 #define GAIN_SHIFT 6
#define VERY_SMALL 0 #define VERY_LARGE32 ((spx_word32_t)2147483647) #define VERY_LARGE16 ((spx_word16_t)32767) #define Q15_ONE ((spx_word16_t)32767)
#define QCONST16(x,bits) ((spx_word16_t)(.5+(x)*(((spx_word32_t)1)<<(bits)))) #define QCONST32(x,bits) ((spx_word32_t)(.5+(x)*(((spx_word32_t)1)<<(bits))))
#define NEG16(x) (-(x)) #define NEG32(x) (-(x)) #define EXTRACT16(x) ((spx_word16_t)(x)) #define EXTEND32(x) ((spx_word32_t)(x)) #define SHR16(a,shift) ((a) >> (shift)) #define SHL16(a,shift) ((a) << (shift)) #define SHR32(a,shift) ((a) >> (shift)) #define SHL32(a,shift) ((a) << (shift)) #define PSHR16(a,shift) (SHR16((a)+((1<<((shift))>>1)),shift)) #define PSHR32(a,shift) (SHR32((a)+((EXTEND32(1)<<((shift))>>1)),shift)) #define VSHR32(a, shift) (((shift)>0) ? SHR32(a, shift) : SHL32(a, -(shift))) #define SATURATE16(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x))) #define SATURATE32(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x)))
#define SHR(a,shift) ((a) >> (shift)) #define SHL(a,shift) ((spx_word32_t)(a) << (shift)) #define PSHR(a,shift) (SHR((a)+((EXTEND32(1)<<((shift))>>1)),shift)) #define SATURATE(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x)))
#define ADD16(a,b) ((spx_word16_t)((spx_word16_t)(a)+(spx_word16_t)(b))) #define SUB16(a,b) ((spx_word16_t)(a)-(spx_word16_t)(b)) #define ADD32(a,b) ((spx_word32_t)(a)+(spx_word32_t)(b)) #define SUB32(a,b) ((spx_word32_t)(a)-(spx_word32_t)(b))
/* result fits in 16 bits */ #define MULT16_16_16(a,b) ((((spx_word16_t)(a))*((spx_word16_t)(b))))
/* (spx_word32_t)(spx_word16_t) gives TI compiler a hint that it's 16x16->32 multiply */ #define MULT16_16(a,b) (((spx_word32_t)(spx_word16_t)(a))*((spx_word32_t)(spx_word16_t)(b)))
#define MAC16_16(c,a,b) (ADD32((c),MULT16_16((a),(b)))) #define MULT16_32_Q12(a,b) ADD32(MULT16_16((a),SHR((b),12)), SHR(MULT16_16((a),((b)&0x00000fff)),12)) #define MULT16_32_Q13(a,b) ADD32(MULT16_16((a),SHR((b),13)), SHR(MULT16_16((a),((b)&0x00001fff)),13)) #define MULT16_32_Q14(a,b) ADD32(MULT16_16((a),SHR((b),14)), SHR(MULT16_16((a),((b)&0x00003fff)),14))
#define MULT16_32_Q11(a,b) ADD32(MULT16_16((a),SHR((b),11)), SHR(MULT16_16((a),((b)&0x000007ff)),11)) #define MAC16_32_Q11(c,a,b) ADD32(c,ADD32(MULT16_16((a),SHR((b),11)), SHR(MULT16_16((a),((b)&0x000007ff)),11)))
#define MULT16_32_P15(a,b) ADD32(MULT16_16((a),SHR((b),15)), PSHR(MULT16_16((a),((b)&0x00007fff)),15)) #define MULT16_32_Q15(a,b) ADD32(MULT16_16((a),SHR((b),15)), SHR(MULT16_16((a),((b)&0x00007fff)),15)) #define MAC16_32_Q15(c,a,b) ADD32(c,ADD32(MULT16_16((a),SHR((b),15)), SHR(MULT16_16((a),((b)&0x00007fff)),15)))
#define MAC16_16_Q11(c,a,b) (ADD32((c),SHR(MULT16_16((a),(b)),11))) #define MAC16_16_Q13(c,a,b) (ADD32((c),SHR(MULT16_16((a),(b)),13))) #define MAC16_16_P13(c,a,b) (ADD32((c),SHR(ADD32(4096,MULT16_16((a),(b))),13)))
#define MULT16_16_Q11_32(a,b) (SHR(MULT16_16((a),(b)),11)) #define MULT16_16_Q13(a,b) (SHR(MULT16_16((a),(b)),13)) #define MULT16_16_Q14(a,b) (SHR(MULT16_16((a),(b)),14)) #define MULT16_16_Q15(a,b) (SHR(MULT16_16((a),(b)),15))
#define MULT16_16_P13(a,b) (SHR(ADD32(4096,MULT16_16((a),(b))),13)) #define MULT16_16_P14(a,b) (SHR(ADD32(8192,MULT16_16((a),(b))),14)) #define MULT16_16_P15(a,b) (SHR(ADD32(16384,MULT16_16((a),(b))),15))
#define MUL_16_32_R15(a,bh,bl) ADD32(MULT16_16((a),(bh)), SHR(MULT16_16((a),(bl)),15))
#define DIV32_16(a,b) ((spx_word16_t)(((spx_word32_t)(a))/((spx_word16_t)(b)))) #define PDIV32_16(a,b) ((spx_word16_t)(((spx_word32_t)(a)+((spx_word16_t)(b)>>1))/((spx_word16_t)(b)))) #define DIV32(a,b) (((spx_word32_t)(a))/((spx_word32_t)(b))) #define PDIV32(a,b) (((spx_word32_t)(a)+((spx_word16_t)(b)>>1))/((spx_word32_t)(b)))
////////////////// #define NVALUE 32 #define ORD 2
spx_word16_t x[NVALUE]; spx_coef_t num[ORD]; spx_word16_t y[NVALUE]; spx_mem_t mem[ORD];
void fir_mem16(const spx_word16_t *x, const spx_coef_t *num, spx_word16_t *y, int N, int ord, spx_mem_t *mem, char *stack) { int i,j; spx_word16_t xi,yi;
for (i=0;i<N;i++) { xi=x[i]; yi = EXTRACT16(SATURATE(ADD32(EXTEND32(x[i]),PSHR32(mem[0],LPC_SHIFT)),32767)); for (j=0;j<ord-1;j++) { mem[j] = MAC16_16(mem[j+1], num[j],xi); } mem[ord-1] = MULT16_16(num[ord-1],xi); y[i] = yi; } }
void main() { asm("nop"); //for brakepoints fir_mem16(&x[0], &num[0], &y[0], NVALUE, ORD, &mem[0], 0x0000); asm("nop"); //for brakepoints }
--------------------
The truth is out there...
|
|
|
|
|
May 11 2017, 11:52
|
Знающий
   
Группа: Участник
Сообщений: 825
Регистрация: 16-04-15
Из: КЧР, Нижний Архыз
Пользователь №: 86 250

|
Цитата(AHTOXA @ May 10 2017, 09:51)  Посмотрите, что из вашего кода делает sdcc, и успокойтесь  Это да. Никакой оптимизации, к сожалению. Но, учитывая то, что больше свободных компиляторов под STM8 нет, приходится пользоваться им. Хоть что-то… Правда, мне больше нравятся STM32. Но и там не все так хорошо: "изкоробочная" сборка arm-none-eabi-gcc не работает с F0 (операции умножения и деления вызывают зависон), приходится брать готовую сборку. А еще надо от opencm3 полностью уйти на "голый CMSIS" для STM32F1. Под F0 я уже от библиотек ушел. Надо лишь с USB разобраться...
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|