简体   繁体   English

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

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

I have read a number of explanations about compile barriers and memory barriers, though I am not sure yet about how the compiler knows where the prevention of compile memory ordering starts and where it ends. 我还阅读了许多有关编译障碍和内存障碍的解释,尽管我还不确定编译器如何知道防止编译内存排序的起点和终点。 (On the other hand I understand how a cpu memory barrier works...) (另一方面,我了解cpu内存屏障的工作原理...)

Below is an arbitrary example, with no compile barrier. 下面是一个任意示例,没有编译障碍。

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;
}

For example if I want to prevent the compile memory ordering only in this function, and not in other functions, should I insert the asm volatile("" ::: "memory") to end of the function, before returning var? 例如,如果我想仅在此函数中而不是在其他函数中阻止编译存储器排序,是否应该在返回var之前将asm volatile(“” :::“ memory”)插入函数的末尾?

Like: 喜欢:

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;
}

The barrier prevents reordering (or optimization) wherever you put it. 屏障可防止您在任何地方放置重新排序(或优化)。 There is no magical "scope". 没有神奇的“范围”。 Just look at the inline assembly instruction : 只需看一下内联汇编指令即可

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

The volatile keyword means to put the asm statement exactly where I put it, and don't optimize it away (ie remove it). volatile关键字的意思是将asm语句准确放置在我放置的位置,而不要对其进行优化(即删除它)。 After the third : is the list of clobbers , so this means "I have clobbered the memory." 在第三个之后:clobbers的列表,因此这意味着“我已经破坏了内存”。 You are basically telling the compiler "I have done something to affect the memory." 您基本上是在告诉编译器“我做了一些影响内存的事情”。

In your example, you have something like 在您的示例中,您有类似

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

The compiler is very clever and knows this is not as efficient as it could be. 编译器非常聪明,并且知道这样做效率不高。 It will probably compile this into something like 它可能会将其编译成类似

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

Because of pipelining reasons, it may also be more efficient to combine this with other load/modify/store operations. 由于流水线的原因,将其与其他加载/修改/存储操作结合起来可能也会更有效。 So the compiler may reorder this even further by merging it with nearby operations. 因此,编译器可能会将其与附近的操作合并,从而进一步对其重新排序。

To prevent this, you can place a memory barrier between them: 为了防止这种情况,可以在它们之间放置一个内存屏障:

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

This tells the compiler that after the first instruction, "I have done something to the memory, you may not know about it, but it happened." 这告诉编译器在第一条指令之后,“我已经对内存做了一些操作,您可能不知道,但是它确实发生了。” So it can not use its standard logic and assume that adding one twice to the same memory location is the same as adding two to it, since something happened in between. 因此,它不能使用其标准逻辑,并假设在同一存储位置加一两次与向其添加两个相同,因为两者之间发生了某些情况。 So this would be compiled into something more like 所以这将被编译成更像

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]

Again, it could possibly reorder things on each side of the barrier, but not across it. 同样,它可能会重新排列障碍物两侧的事物,但不能跨越障碍物。

Another example: Once, I was working with memory-mapped I/O on a microcontroller. 另一个例子:一次,我在微控制器上使用内存映射I / O。 The compiler saw that I was writing different values to the same address with no read in between, so it kindly optimized it into a single write of the last value. 编译器发现我正在将不同的值写入同一地址,而没有中间的读取,因此它将其优化为一次写入最后一个值。 Of course, this made my I/O activity not work as expected. 当然,这使我的I / O活动无法按预期进行。 Placing a memory barrier between writes told the compiler not to do this. 在两次写入之间放置一个内存屏障会告诉编译器不要这样做。

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

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