繁体   English   中英

asm volatile(“ :::” memory“)的寿命是多少?

[英]What is the life-time of asm volatile(“” ::: “memory”)?

我还阅读了许多有关编译障碍和内存障碍的解释,尽管我还不确定编译器如何知道防止编译内存排序的起点和终点。 (另一方面,我了解cpu内存屏障的工作原理...)

下面是一个任意示例,没有编译障碍。

int func(int *x, int *y) {
        int var = 0;
        x[0] += 1;
        var += y[0];
        y[0] += 1;
        x[1] += 1;
        var += y[1];
        y[0] += 1;

        return var;
}

例如,如果我想仅在此函数中而不是在其他函数中阻止编译存储器排序,是否应该在返回var之前将asm volatile(“” :::“ memory”)插入函数的末尾?

喜欢:

int func(int *x, int *y) {
        int var = 0;
        x[0] += 1;
        var += y[0];
        y[0] += 1;
        x[1] += 1;
        var += y[1];
        y[0] += 1;

        asm volatile("" ::: "memory");
        return var;
}

屏障可防止您在任何地方放置重新排序(或优化)。 没有神奇的“范围”。 只需看一下内联汇编指令即可

asm volatile (""::: "memory");

volatile关键字的意思是将asm语句准确放置在我放置的位置,而不要对其进行优化(即删除它)。 在第三个之后:clobbers的列表,因此这意味着“我已经破坏了内存”。 您基本上是在告诉编译器“我做了一些影响内存的事情”。

在您的示例中,您有类似

y[0] += 1;
y[0] += 1;

编译器非常聪明,并且知道这样做效率不高。 它可能会将其编译成类似

load y[0] from memory to register
add 2 to this register
store result to y[0]

由于流水线的原因,将其与其他加载/修改/存储操作结合起来可能也会更有效。 因此,编译器可能会将其与附近的操作合并,从而进一步对其重新排序。

为了防止这种情况,可以在它们之间放置一个内存屏障:

y[0] += 1;
asm volatile (""::: "memory");
y[0] += 1;

这告诉编译器在第一条指令之后,“我已经对内存做了一些操作,您可能不知道,但是它确实发生了。” 因此,它不能使用其标准逻辑,并假设在同一存储位置加一两次与向其添加两个相同,因为两者之间发生了某些情况。 所以这将被编译成更像

load y[0] from memory to register
add 1 to this register
store result to y[0]
load y[0] from memory to register
add 1 to this register
store result to y[0]

同样,它可能会重新排列障碍物两侧的事物,但不能跨越障碍物。

另一个例子:一次,我在微控制器上使用内存映射I / O。 编译器发现我正在将不同的值写入同一地址,而没有中间的读取,因此它将其优化为一次写入最后一个值。 当然,这使我的I / O活动无法按预期进行。 在两次写入之间放置一个内存屏障会告诉编译器不要这样做。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM