Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Пропуск операции
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > Cредства разработки для МК > IAR
jorikdima
Никак понять не могу почему ИАР (4.21.2 (4.21.2.50066) для MSP430 с аппаратным умножителем) пропускает операцию умножения. Я бывало уже смотрел в сторону этого компилятора косо, но все время неправым оказывался я smile.gif Может и теперь во мне дело.
Однако, вот такой вот код есть.
Код
#include "io430.h"

typedef signed char INT8;
typedef signed short INT16;
typedef signed long INT32;
typedef signed long long INT64;

typedef unsigned char UINT8;
typedef unsigned short UINT16;
typedef unsigned long UINT32;
typedef unsigned long long UINT64;

INT16 FilterSample(const INT16 sample );

const INT16 coeffs[4][2][3] ={
      {{16384, -28354, 16384}, {16384, -28552, 14866}},
      {{16384, -26784, 16384}, {16384, -25180, 11711}},
      {{16384, -20728, 16384}, {16384, -20769, 7916}},
      {{16384, 9571, 16384}, {16384, -16608, 4444}} };

INT16 state[2][2];
INT16 (*coef)[3];

int main( void )
{
  // Stop watchdog timer to prevent time out reset
  WDTCTL = WDTPW + WDTHOLD;
  
  coef = (INT16(*)[3])&coeffs[0][0][0];

  FilterSample(783);
}


//#pragma optimize = none
INT16 FilterSample(const INT16 sample )
{
    INT32 res = (INT32)coef[0][0] * sample;
    for (UINT8 i = 0; i < 2; i++)
    {      
        INT32 r1 = (INT32)state[0][i] * coef[0][i + 1];
        INT32 r2 = (INT32)state[1][i] * coef[1][i + 1];
        
        res += r1 - r2;        

    }
    res = (INT16)(res >> 14);
        
    return res;
}


Конкретно интересует место
Код
INT32 r1 = (INT32)state[0][i] * coef[0][i + 1];
        INT32 r2 = (INT32)state[1][i] * coef[1][i + 1];
        
        res += r1 - r2;

Тут все просто берется два произведения, берется разность между ними и интегрируется в переменной res.
Так вот листинг этой функции (FilterSample) с включенной оптимизацией выглядит вот так вот:
Код
FilterSample:
004048    120A               push.w  R10
00404A    120B               push.w  R11
00404C    1208               push.w  R8
00404E    1209               push.w  R9
004050    1206               push.w  R6
    INT32 res = (INT32)coef[0][0] * sample;
004052    421A 1108          mov.w   &coef,R10
004056    1202               push.w  SR
004058    C232               dint
00405A    4303               nop
00405C    4AA2 0132          mov.w   @R10,&MPYS
004060    4C82 0138          mov.w   R12,&OP2
004064    421C 013A          mov.w   &RESLO,R12
004068    421D 013C          mov.w   &RESHI,R13
00406C    4132               pop.w   SR
    for (UINT8 i = 0; i < 2; i++)
00406E    403E 1100          mov.w   #0x1100,R14
004072    4A0B               mov.w   R10,R11
004074    522B               add.w   #0x4,R11
        res += r1 - r2;        
004076    1202               push.w  SR
004078    C232               dint
00407A    4303               nop
00407C    4132               pop.w   SR
00407E    580C               add.w   R8,R12
004080    690D               addc.w  R9,R13
004082    1202               push.w  SR
004084    C232               dint
004086    4303               nop
004088    4E92 0004 0132     mov.w   0x4(R14),&MPYS
00408E    4A92 0008 0138     mov.w   0x8(R10),&OP2
004094    4218 013A          mov.w   &RESLO,R8
004098    4219 013C          mov.w   &RESHI,R9
00409C    4132               pop.w   SR
00409E    880C               sub.w   R8,R12
0040A0    790D               subc.w  R9,R13
    for (UINT8 i = 0; i < 2; i++)
0040A2    532A               incd.w  R10
0040A4    532E               incd.w  R14


Почему я вижу только одно умножение??? Соответствующее рассчету r2. А умножение в рассчете r1 отсутствует, причем вся подготовка для него существует (в виде запрета прерывания, сохранение статусного регистра, затем его восстановления).
Я приаттачил проект, если кому интересно, точнее выдержку из рабочего проекта с интересующим кодом.
Интересно следующее, если отключить оптимизацию - работает, есть два умножения. Если включить опцию Hardware multiplier->Use only lib calls то тоже работает. В этом случае компайлер просто вызывает функции с умножением, а не инлайнит их как обычно, но работает.
Почему ИАР не умножает второй раз (точнее первый раз)?
Спасибо.

Нажмите для просмотра прикрепленного файла
jorikdima
Никто не сталкивался с таким?
Сергей Борщ
Цитата(jorikdima @ Dec 9 2009, 15:54) *
Никто не сталкивался с таким?
Не могли бы вы приложить полный листинг? Возможно опримизатор переставил вычисления местами. ИАРа нет, поэтому сам получить листинг из ваших исходников не могу.
plombir
Предположу, что вот эти множители coef[0][i + 1] и coef[1][i + 1] компилятор считает нулевыми.
Оптимизируя, убирает умножение.
Кстати, они 3-х размерные в таблице, а Вы берёте 2-ух. Так задумано?
rezident
Не вдаваясь в разбор исходника, хочу заметить, что IAR оптимизирует обращение к константам, подставляя их значение "по месту", и, вычисляя результат операций с константами заранее, на уровне препроцессора.
jorikdima
Цитата(Сергей Борщ @ Dec 9 2009, 17:29) *
Не могли бы вы приложить полный листинг? Возможно опримизатор переставил вычисления местами. ИАРа нет, поэтому сам получить листинг из ваших исходников не могу.


Я упростил код немного для иллюстрации. Предыдущий вариант кода был выдран из рабочего, поэтому с точки зрения демонстрации был перегружен непонятностями. Вот ниже упрощенный с полным листингом.
Код
#include "io430.h"

typedef signed char INT8;
typedef signed short INT16;
typedef signed long INT32;

typedef unsigned char UINT8;
typedef unsigned short UINT16;
typedef unsigned long UINT32;

INT16 FilterSample(const INT16 sample );

const INT16 coeffs[2][3] =
     {{16384, -28354, 16384}, {16384, -28552, 14866}};

INT16 state[2][2];

int main( void )
{
  // Stop watchdog timer to prevent time out reset
  WDTCTL = WDTPW + WDTHOLD;
  
  FilterSample(783);
}

//#pragma optimize = none
INT16 FilterSample(const INT16 sample )
{
    INT32 res = (INT32)coeffs[0][0] * sample;
    for (UINT8 i = 0; i < 2; i++)
    {      
        INT32 r1 = (INT32)state[0][i] * coeffs[0][i + 1];
        INT32 r2 = (INT32)state[1][i] * coeffs[1][i + 1];
        
        res += r1 - r2;        

    }        
    return res;
}


Листинг полный приаттачен. Никаких переставлений не узрел.

Нажмите для просмотра прикрепленного файла

Цитата(plombir @ Dec 9 2009, 17:35) *
Предположу, что вот эти множители coef[0][i + 1] и coef[1][i + 1] компилятор считает нулевыми.
Оптимизируя, убирает умножение.
Кстати, они 3-х размерные в таблице, а Вы берёте 2-ух. Так задумано?

coef это указатель на массив, а не сам массив, который назывался coeffs. Похожими названиями запутал, поэтому упростил код, см. выше.

Цитата(rezident @ Dec 9 2009, 17:37) *
Не вдаваясь в разбор исходника, хочу заметить, что IAR оптимизирует обращение к константам, подставляя их значение "по месту", и, вычисляя результат операций с константами заранее, на уровне препроцессора.

Константность непричем, я убирал const - нет разницы. Кроме того, константа умножалась на переменную все же, а это заранее не расчитать.

Упрощенный проет прикрепил.
Нажмите для просмотра прикрепленного файла
plombir
Цитата(jorikdima @ Dec 9 2009, 22:54) *
coef это указатель на массив...
Виноват, выше не заметил...

Тогда нулевой state[][]. Присвоение к нему не нашёл.
jorikdima
Цитата(plombir @ Dec 10 2009, 15:21) *
Виноват, выше не заметил...

Тогда нулевой state[][]. Присвоение к нему не нашёл.

обнуляется при инициализации, ибо глобальная переменная. В исходном коде (не образанном мною для демонстрации) ей присваиваются значения.
Более того, компайлер не может так поступить с глобальной переменной, он понятия не имеет как и где она меняется.
Еще более того, почему расчет r2 он делает, а r1 - нет, хотя делает всю подготовку для этого в виде запрета прерываний. r1 ничем не хуже r2.
scifi
Такой вопрос: а вообще код работает корректно? То есть если не заглядывать в дизассемблер, результаты выдаёт правильные или нет?
jorikdima
Цитата(scifi @ Dec 10 2009, 18:44) *
Такой вопрос: а вообще код работает корректно? То есть если не заглядывать в дизассемблер, результаты выдаёт правильные или нет?

нет, неправильные. Конкретно тот проект, что я прикрепил работает корректно с точки зрения конечного результата при самом первом вызове функции (собственно как у меня, я только единожды вызвал ф-цию FilterSample )? но это чисто случайно, так как регистры R8, R9 там равны 0 еще после инициализации контроллера. Но в рабочем варианте в R8 R9 лежит мусор от предыдущих операций и этот мусор используется в
Код
00407E    580C               add.w   R8,R12
004080    690D               addc.w  R9,R13

Хотя правильно было бы строчкой выше залить в R8 R9 результаты с умножителя, как это делается в
Код
004084    C232               dint
004086    4303               nop
004088    4E92 0004 0132     mov.w   0x4(R14),&MPYS
00408E    4A92 0008 0138     mov.w   0x8(R10),&OP2
004094    4218 013A          mov.w   &RESLO,R8
004098    4219 013C          mov.w   &RESHI,R9
00409C    4132               pop.w   SR
00409E    880C               sub.w   R8,R12
0040A0    790D               subc.w  R9,R13


Может кто проверить на более ранних версиях ИАР с включенной оптимизацией? Просто этот код я сделал давно и частично его отладил (конкретно это место) и вопросов у меня тогда не возникло. А сейчас взялся доделать и... Но может я и путаю чего.
jorikdima
Судя по всему это был баг ИАРа. В одном из патчей пролечили, скачав последний патч, благодаря Ксении, увидел правильный код.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.