【问题标题】:C - Optimization Boundary with Inline Assembly?C - 内联汇编的优化边界?
【发布时间】:2020-03-06 06:41:23
【问题描述】:

考虑以下代码:

// 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 gcc 生成:

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

由于语句已优化,因此输出不正确。

有没有办法在 GCC 中设置优化的“障碍”?


编辑:尝试 #1

将 volatile 添加到 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,但它仅适用于 gcc >= 4.5, iirc。

【问题讨论】:

  • 试着让var 也变得易变。

标签: c gcc


【解决方案1】:

输出不正确

输出完全没问题,你的代码不正确。

有没有办法在 GCC 中设置优化的“障碍”?

你能得到的最好的是

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

但是,这并不能修复您的错误代码。代码是错误的,因为内联汇编有你不告诉编译器的副作用,这几乎肯定迟早会咬你。如果跳跃是你想要的,那么就像这样:

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

【讨论】:

  • 我在 asm 块中定义符号的原因是因为我想在不使用标签作为值的情况下获取标签的地址,这是一个非标准扩展。另外,我不确定在优化后更复杂的情况下,C 标签(“labl”)是否会“精确”。我稍后会检查这个,非常感谢。
  • @imakak :这不是标签为&amp;&amp;labl 的值。标签用作符号,就像在 C 的 goto labl; 中一样。你甚至可以毫无问题地使用-std=c99 -pedantic -Wall -Wextra 进行编译。
  • 我可以在 asm goto 中跳转到变量(例如,mtlr 后跟 blr)吗?
  • @imakak :你的意思是像跳转到变量var?这完全有道理……我对 PowerPC 一无所知。您能否以与架构无关的方式重述您的问题?
  • 好的,我稍后会重申我的问题。谢谢。
猜你喜欢
  • 1970-01-01
  • 2012-09-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-23
  • 1970-01-01
  • 2017-11-01
  • 2013-11-26
相关资源
最近更新 更多