Перейти к содержанию
    

Почему такая высокая цена за инструкцию перехода?

Имеется код:

...
  if (n >= 4) continue;
  if ((u32)(j - pcv->min) > pcv->range) e |= 1u << FaultState::GF_volt << n;
} while ((int)--n >= 0);

После компиляции IAR_v7.80.4 с максимальной оптимизацией, Balanced, получаю:

...
000001C6   0x2D04             CMP      R5,#+4         
000001C8   0xBF3F             ITTTT    CC             
000001CA   0x8899             LDRHCC   R1,[R3, #+4]   
000001CC   0xF8B3 0x9002      LDRHCC   R9,[R3, #+2]   
000001D0   0xEBA0 0x0009      SUBCC    R0,R0,R9       
000001D4   0x4281             CMPCC    R1,R0          
000001D6   0xBF3C             ITT      CC             
000001D8   0xFA08 0xF005      LSLCC    R0,R8,R5       
000001DC   0x4302             ORRCC    R2,R0,R2       
000001DE   0x1E6D             SUBS     R5,R5,#+1      
000001E0   0x1E7F             SUBS     R7,R7,#+1      
000001E2   0x2D00             CMP      R5,#+0         
000001E4   0xF1AC 0x0C02      SUB      R12,R12,#+2    
000001E8   0xD5CB             BPL.N    ??ProcessAdcV_7

Видно, что вместо того, чтобы по адресу 0x1C8 поставить инструкцию BCS на адрес 0x1DE, компилятор использовал инструкцию IT. Интересно - почему так? Ведь цена инструкции BCS здесь будет меньше (потребуется меньше тактов в случае сработавшего перехода)? А в данном случае, процессор пропустит последующие 7 инструкций по условию CS. И это потребует намного больше тактов.

Просто интересно....  :smile:

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

11 минут назад, jcxz сказал:

Просто интересно....  :smile:

Цитата

The Definitive Guide to ARM Cortex-M3 and Cortex-M4 Processors (Joseph Yiu):
Third EditionIn many cases, the IT instruction can help improve the performance of program
code significantly because it avoids some of the branch penalty, as well as reducing
the number of branch instructions. For example, a short IF-THEN-ELSE program
sequence that normally requires one conditional branch and an unconditional branch
can be replaced by a single IT instruction.
In some other cases, traditional branch methods can be better than the IT instruction
because a conditional failed instruction in an IT instruction sequence will still
take a cycle to run. So if you specified ITTTT <cond> and the condition failed due
to the APSR value in run-time, it could be quicker to use a conditional branch (three
cycles) than using IT instruction block (up to five cycles in this case, including the IT
instruction itself).

В случае коротких IT выигрыш есть, в вашем же случае выигрыша нет.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

3 минуты назад, adnega сказал:

В случае коротких IT выигрыш есть, в вашем же случае выигрыша нет.

Вот именно, я об этом. Поэтому и удивляюсь зачем IAR так делает?

Даже не то что нет выигрыша, а даже есть проигрыш. Надо наверное в поддержку писать, ибо похоже на баг оптимизатора.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

В 14.05.2019 в 20:07, VladislavS сказал:

А с оптимизацией speed что будет?

Проверил - то же самое. Те же 7 пропускаемых инструкций после условной IT. Только регистры другие.

При оптимизации "size" количество условных команд (с префиксом) стало меньше, но баг тем не менее всё равно присутствует. Даже, пожалуй, усугубился:

              if (n >= VOLT_CH_MON_n) continue;
000001D4   0x2B04             CMP      R3,#+4
000001D6   0xBF3F             ITTTT    CC
000001D8   0x88B9             LDRHCC   R1,[R7, #+4]
000001DA   0xF8B7 0xE002      LDRHCC   LR,[R7, #+2]
000001DE   0xEBA0 0x000E      SUBCC    R0,R0,LR
000001E2   0x4281             CMPCC    R1,R0
              if ((u32)(j - pcv->min) > pcv->range) e |= 1u << FaultState::GF_volt << n;
000001E4   0xD203             BCS.N    ??ProcessAdcV_10
000001E6   0xF44F 0x5000      MOV      R0,#+8192
000001EA   0x4098             LSLS     R0,R0,R3
000001EC   0x4302             ORRS     R2,R0,R2
            } while ((int)--n >= 0);
                  ??ProcessAdcV_10: (+1)
000001EE   0x1E5B             SUBS     R3,R3,#+1
000001F0   0xD5CB             BPL.N    ??ProcessAdcV_9

PS: Только заметил Ваше сообщение....  :scratch_one-s_head:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

К сожалению, мне трудно воспроизвести этот код, а так бы попробовал на крайней версии компилятора.

 

Можно также посмотреть как тот же gcc с этим справится.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

On 5/14/2019 at 5:35 PM, jcxz said:

А в данном случае, процессор пропустит последующие 7 инструкций по условию CS. И это потребует намного больше тактов.

Просто интересно....  :smile:

 

А Вы попробуйте этот код побенчмаркать на настоящем МК. Только не в ОЗУ, а во флеше. Какой-нибудь акселератор доступа во флеш вполне может давать куда более вменяемые результаты при последовательном доступе, нежели при переходе.

 

Возможно, именно некой среднепотолочной статистикой работы различных акселераторов в различных МК и обусловлено такое поведение оптимизатора.

 

Возможно, кстати, что компиляция функции с модификатором __ramfunc изменит поведение оптимизатора. 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

30 минут назад, VladislavS сказал:

К сожалению, мне трудно воспроизвести этот код, а так бы попробовал на крайней версии компилятора.

Не утруждайтесь: только что проверил на IAR-8.32.1 - результат точно тот же. Те же 7 команд. Что balanced что speed. Конечно 8.32.1 - не самый край, но всё же....

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

19 минут назад, Rst7 сказал:

А Вы попробуйте этот код побенчмаркать на настоящем МК. Только не в ОЗУ, а во флеше. Какой-нибудь акселератор доступа во флеш вполне может давать куда более вменяемые результаты при последовательном доступе, нежели при переходе.

Возможно, именно некой среднепотолочной статистикой работы различных акселераторов в различных МК и обусловлено такое поведение оптимизатора.

Я считал, что штатные 4 условные инструкции (включённые в возможности инструкции IT) уже как раз и включают особенности работы усреднённого кеша инструкций.

Да и если просто взять: 144МГц(макс.тактовая ядра)/30МГц(частота флешь?) = ~4.8 инструкций - как раз примерно соответствует возможностям команды IT. Т.е. - при кеш-промахе (переходе) потребуется ~5 тактов на чтение новой порции кода, а не 7.

Цитата

Возможно, кстати, что компиляция функции с модификатором __ramfunc изменит поведение оптимизатора. 

Не изменяет. Проверил.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 час назад, VladislavS сказал:

К сожалению, мне трудно воспроизвести этот код, а так бы попробовал на крайней версии компилятора.

Можно также посмотреть как тот же gcc с этим справится.

Если ещё интересно - я выхолостил функцию. Так что она должна компилиться без привязки к остальной программе. Вот её код:

Спойлер

u32 Z1()
{
  enum {VOLT_CH_n = 5};
  struct VoltCfg {
    u16 scale;      //масштабирующие коэфф. для приведения данных АЦП к напряжению в V/VOLT_PNT в формате UQ12.20
    u16 min, range; //ADC_VOLT_..._MIN, ADC_VOLT_..._MAX - ADC_VOLT_..._MIN
  } static const voltCfg[VOLT_CH_n] = {
    {0x7FFF, 0x100, 0x1010},
    {0x7F3F, 0x112, 0x1450},
    {0x7F56, 0x101, 0x1023},
    {0x7012, 0x140, 0x1440},
    {0x7342, 0x103, 0x1555}};
  static u8 const toAdcVolt[VOLT_CH_n] = {34, 36, 24, 18, 10};
  u32 j, e = 0;
  VoltCfg const *pcv = &voltCfg[0] + VOLT_CH_n;
  u32 const *p = (u32 *)0x20004000;
  u32 const *pa = (u32 *)0x20001230;
  u32 *pc = (u32 *)0x20005600;
  u16 *pr = (u16 *)0x20002200;
  uint n = VOLT_CH_n - 1;
  do {
    u64 q = (j = *p++) * 2 * (u64)(1 << 15);
    pc[n] = j += *(u16 *)((u8 *)pa + toAdcVolt[n]) - (u32)(q >> 32) - ((u32)q >> 31);
    q = j * 2 * (u64)(1 << 15);
    j = __USAT((u32)(q >> 32) + ((u32)q >> 31), 16) * (--pcv)->scale; //результат - напряжение в V/VOLT_PNT в формате UQ12.20
    *pr++ = j = j + (1u << 19) >> 20;
    if (n >= 4u) continue;
    if ((u32)(j - pcv->min) > pcv->range) e |= 1u << 13 << n;
  } while ((int)--n >= 0);
  return e;
}

 

При компиляции IAR_8.32.1 получаю тот же эффект - 7 условных инструкций после IT.

Если интересно можете проверить на gcc.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

41 минуту назад, jcxz сказал:

Если ещё интересно - я выхолостил функцию.

Гляну, конечно, чуть позже. Для багрепорта это всё равно же надо было сделать.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

5 минут назад, amaora сказал:

GCC делает переход в этом месте. Второй блок ITT есть при Os и O2.

Т.е. - для первого условия не лепит в один единый блок условного выполнения? Ну так и правильно по идее.

3 минуты назад, VladislavS сказал:

Гляну, конечно, чуть позже. Для багрепорта это всё равно же надо было сделать.

Чуть позже отправлю им багрепорт пожалуй. Они обещали в начале июня новую версию.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

35 minutes ago, jcxz said:

Т.е. - для первого условия не лепит в один единый блок условного выполнения? Ну так и правильно по идее. 

        cmp     r4, #4
        beq     .L5
        ldrh    r9, [r6, #2]
        ldrh    r2, [r6, #4]
        sub     r3, r3, r9
        cmp     r3, r2
        itt     hi
        lslhi   r3, r8, r4
        orrhi   r0, r0, r3

        subs    r4, r4, #1
        adds    r2, r4, #1
        mov     r3, r4
        beq     .L8
.L3:
        add     r3, r3, lr
        ldrb    r3, [r3, #32]   @ zero_extendqisi2
        ldrh    r9, [r6, #-6]
        b       .L2
.L5:
        movs    r3, #3
        mov     r4, r3
        b       .L3

Это -O2.

        cmp     r2, #4
        beq     .L2
        ldrh    r9, [r4, #26]
        sub     r3, r3, r9
        ldrh    r9, [r4, #28]
        cmp     r3, r9
        itt     hi
        lslhi   r3, r8, r2
        orrhi   r0, r0, r3

.L2:
        subs    r2, r2, #1
        adds    r3, r2, #1
        sub     r4, r4, #6
        bne     .L4

А это -Os.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

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

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...