Jump to content

    

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

Имеется код:

...
  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:

 

Share this post


Link to post
Share on other sites
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 выигрыш есть, в вашем же случае выигрыша нет.

Share this post


Link to post
Share on other sites
3 минуты назад, adnega сказал:

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

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

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

Share this post


Link to post
Share on other sites
В 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:

Share this post


Link to post
Share on other sites

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

 

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

Share this post


Link to post
Share on other sites
On 5/14/2019 at 5:35 PM, jcxz said:

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

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

 

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

 

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

 

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

 

Share this post


Link to post
Share on other sites
30 минут назад, VladislavS сказал:

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

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

Share this post


Link to post
Share on other sites

Да я и не утруждаюсь, просто любопытство. 

Share this post


Link to post
Share on other sites
19 минут назад, Rst7 сказал:

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

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

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

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

Цитата

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

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

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites

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

Share this post


Link to post
Share on other sites
41 минуту назад, jcxz сказал:

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

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

Share this post


Link to post
Share on other sites
5 минут назад, amaora сказал:

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

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

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

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

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

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now