C - Граница оптимизации со встроенной сборкой? - PullRequest
1 голос
/ 06 марта 2020

Рассмотрим следующий код:

// String literals
#define _def0Impl(a0) #a0
#define _def0(a0) _def0Impl(a0)
// Labels
#define _asm_label(tag) tag: asm volatile (_def0(tag) ":")
// Assume 32 bits
typedef unsigned int uptr; 

int main (int argc, void *argv[]) {
    register int ctr, var;
    uptr tbl[0x4];
    ctr = 0x0;
    var = 0x0;

    // Push some tasks to tbl ...

    // Suppose that tbl holds {&&tag0, &&tag1, &&tag2, &&tag1}
    // Suppose that ctr holds 0xC
    // tag* may exported to somewhere else.
    ctr = 0x3 * sizeof(uptr);
    tbl[0x0] = &&tag0;
    tbl[0x1] = &&tag1;
    tbl[0x2] = &&tag2;
    tbl[0x3] = &&tag1;

    // Run tasks table
    goto *(((uptr)&tbl[0x0]) + ctr);

    _asm_label(tag2);
    // Task I
    ctr -= sizeof(uptr);
    var += 0x1;
    goto *(((uptr)&tbl[0x0]) + ctr);

    _asm_label(tag1);
    // Task II
    ctr -= sizeof(uptr);
    var -= 0x1;
    goto *(((uptr)&tbl[0x0]) + ctr);

    _asm_label(tag0);
    // Continue executation
    return var;   
}

Можно ли переписать эту реализацию со встроенной сборкой?


Старый оператор

Рассмотрим следующий код:

#define _asm_label(tag) asm volatile(tag ":")
// PowerPC for example
#define _asm_jump(tag) asm volatile ("b " tag)
#define _asm_bar() asm volatile ("" ::: "cc", "memory")

int main(int argc, void *argv[]) {
    register int var;
    var = 0;

    _asm_jump("bar");
    _asm_bar(); // Boundary

    var += 1;

    _asm_label("bar");
    _asm_bar(); // Boundary

    var += 1;

    return var;
}

С -O0 g cc создает:

li 30,0
b bar
# 0 "" 2
addi 30,30,1
bar:
# 0 "" 2
addi 30,30,1
mr 9,30
mr 3,9 # r3 = 0x1

Но с -O2:

b bar
# 0 "" 2
bar:
# 0 "" 2
lwz 0,12(1) # restore link register
li 3,2 # incorrect

Вывод неправильный, поскольку операторы оптимизированы.

Есть ли способы сделать «барьер» оптимизации в G CC?


Редактировать: Попытка # 1

Добавление энергозависимости к var .

С -O2:

li 9,0
stw 9,8(1)
# 10 "attempt1.c" 1
b bar
# 0 "" 2
lwz 9,8(1)
addi 9,9,1
stw 9,8(1)
# 15 "attempt1.c" 1
bar:
# 0 "" 2
lwz 9,8(1)
lwz 0,28(1)
addi 9,9,1
stw 9,8(1)

В этом случае var помещается в стек (r1 + 0x8).

Однако, установите volatile на var остановит всю оптимизацию около var.

Я думаю об использовании asm goto, но она доступна только для g cc> = 4.5, iir c.

1 Ответ

2 голосов
/ 06 марта 2020

Вывод неверный

Вывод полностью в порядке, ваш код неверен.

Есть ли способы сделать «барьер» оптимизации в G CC?

Лучшее, что вы можете получить, это

__asm volatile ("" ::: "memory", <more-clobbers>)

Однако, это не исправит ваш неправильный код. Код неправильный, потому что у встроенного asm есть побочные эффекты, о которых вы не говорите компилятору, это почти наверняка укусит вас рано или поздно. Если вы хотите прыгать, то вот так:

int func (void)
{
    int var = 0;

    __asm volatile goto ("b %0" :::: labl);

    var += 1;

labl:;
    var += 1;

    return var;
}

Сгенерированный код:

func:
 # 5 "b.c" 1
    b .L3
 # 0 "" 2
    li 3,2
    blr
    .p2align 4,,15
.L3:
.L2:
    li 3,1
    blr
...