Предсказание статического ветвления для ARM с __builtin_expect не работает !!? - PullRequest
0 голосов
/ 17 января 2012

Я делаю оптимизацию в коде C, работающем в Cortex-R4. во-первых, я не увидел никаких изменений в выводе кода сборки, когда указал "__builtin_expect" в проверке состояния. Похоже, компилятор сгенерировал ненужный переход.

Мой код C:

           bit ++; (Likely)

if(__builtin_expect(bit >= 32),0) 
{ 
  bit -=32; // unlikely code
  xxxxxx;   // unlikely code
  xxxxxx;   // unlikely code
  xxxxxx;   // unlikely code
} 

bit = bit*2 // something  (Likely)
return bit; 

---- Сгенерированный код ASM -------- (бит => r0)

                      ADD   r2,r2,#1 
                      CMP   r0,#0x20 
                      BCC  NoDecrement 
                      SUB   r0,r0,#0x20 
                      XXXXXXXXX 
                      XXXXXXXXX 
                      XXXXXXXXX 
NoDecrement LSL   r0,r0,#1 
                          BX  lr 

---- Мой ожидаемый код ASM --------

                          ADD   r2,r2,#1 
                          CMP   r0,#0x20 
                          BHE   Decrement 
JumbBack       LSL   r0,r0,#1 
                          BX  lr 
Decrement      SUB   r0,r0,#0x20 
                          XXXXXXXXX 
                          XXXXXXXXX 
                          XXXXXXXXX 
                          B JumbBack

предположим, что если этот фрагмент кода C выполняется в цикле, то каждый раз он должен перескакивать (потому что условие if передается только один раз). Есть ли какая-либо другая настройка компилятора, которая на самом деле генерирует код, как и ожидалось .. ??

1 Ответ

6 голосов
/ 01 сентября 2012

Вы писали:

if(__builtin_expect(bit >= 32),0)
{
    ...
}

Код внутри фигурных скобок не будет никогда выполняться, потому что он окружен if(foo,0), что эквивалентно if(0) для любого значения foo, независимо от того, какую встроенную функцию вы пытаетесь использовать. Если вы включите оптимизацию с помощью -O2, вы увидите, что компилятор полностью удаляет мертвый код, а не просто перепрыгивает через него. Я думаю, что вы, вероятно, хотели написать

if (__builtin_expect(bit >= 32, 0)) {
    bit -= 32;
}

Если я сделаю это, я получу именно ту ветвь, которую я ожидаю (с clang -O1 или выше).

extern void something();
int foo(int bit)
{
    ++bit;
    if (__builtin_expect(bit >= 32, 0)) {
        bit -= 32;  // "Decrement"
        something();
    }
    bit = bit*2;
    something();
    return bit;
}

Вот код из clang -arch armv7 -O2 -S:

_foo:
@ BB#0:
push    {r4, r7, lr}
adds    r4, r0, #1
add r7, sp, #4
cmp r4, #32
bge LBB0_2           // a forward branch for the unlikely case
LBB0_1:
lsls    r4, r4, #1
blx _something
mov r0, r4
pop {r4, r7, pc}
LBB0_2:                      // "Decrement"
sub.w   r4, r0, #31
blx _something
b   LBB0_1
...