gpt4 book ai didi

gcc - gcc 内联汇编的 volatile 与编译器障碍

转载 作者:行者123 更新时间:2023-12-02 11:17:19 24 4
gpt4 key购买 nike

在我们的产品中,我们有一个内联互斥体实现,对硬件特定部分使用各种平台和编译器特定方法。对于一些试图“欺骗”的过度优化代码,我们的“规则”之一是,如果在互斥体外部和内部访问变量,则必须将该变量声明为 volatile。我认为这也适用于不透明互斥体实现(例如 pthread_mutex_lock/unlock),这引发了一场有趣的争论。

有人断言,这是编译器错误的迹象(特别是当互斥体实现是内联的并且对编译器“不是不透明”时)。我举了下面的例子来对此提出异议

int v = pSharedMem->myVariable ;

__asm__ __volatile__(( "isync" : : :"memory" ))

v = pSharedMem->myVariable ;

在这个 LinuxPPC gcc 代码片段中,除了我们可以通过内存约束告诉它的信息之外,编译器对 isync 的运行时影响一无所知。您会在互斥体获取的尾部找到这样的 isync 指令,以防止在实际持有互斥体之前执行成功获取互斥体之后的指令(因此,如果在 isync 之前执行了加载,则会必须被丢弃)。

在此代码片段中,我们有编译器屏障,可防止重写代码,就像下面的代码一样

int v = pSharedMem->myVariable ;
v = pSharedMem->myVariable ;

__asm__ __volatile__(( "isync" : : :"memory" ))

__asm__ __volatile__(( "isync" : : :"memory" ))

int v = pSharedMem->myVariable ;
v = pSharedMem->myVariable ;

(即:这两种编译器重新排序都应该受到 volatile 属性的抑制)

我们还有 isync 本身,可以防止运行时的第一次重新排序(但我认为不会阻止第二次重新排序,这不是那么有趣)。

但是,我的问题是,如果 myVariable 未声明为 volatile ,那么“内存”约束是否足以让 gcc 在 isync 之后重新加载“v”?我仍然倾向于为这种模式强制使用 volatile,因为这种代码与所有特定于平台的编译器内置函数过于敏感。也就是说,如果我们将讨论减少到仅 GCC 和此代码片段,那么此 asm 内存约束是否足以让代码通过一对加载而不是一个加载生成?

最佳答案

带有 "memory" 破坏器的 __asm__ __volatile__ 是必需的,并且将充当完整的重新排序屏障。变量上的 volatile 是不必要的。事实上,如果你看看 Linux 内核定义 atomic_t ,它不使用任何 volatile 修饰符,并完全依赖于具有适当约束的 __asm__ __volatile__ 语句。

另一方面,我相信 volatile 本身实际上根本不禁止重新排序,只是缓存和优化值,因此对于同步目的来说它毫无值(value)。

关于gcc - gcc 内联汇编的 volatile 与编译器障碍,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6467240/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com