Pee*_*oot 5 gcc constraints inline-assembly
在我们的产品中,我们有一个内联互斥实现,使用各种平台和编译器特定方法来处理硬件特定部分.对于试图"欺骗"的一些过度优化代码,我们的一个"规则"是,如果在互斥体之外和内部访问变量,那么该变量必须声明为volatile.我认为这也适用于不透明的互斥体实现(例如pthread_mutex_lock/unlock),这导致了一个有趣的争论.
一个人断言这是编译器错误的指示(特别是当互斥实现被内联并且对编译器"不透明"时).我给出了以下示例来对此提出异议
int v = pSharedMem->myVariable ;
__asm__ __volatile__(( "isync" : : :"memory" ))
v = pSharedMem->myVariable ;
Run Code Online (Sandbox Code Playgroud)
在这个LinuxPPC gcc代码片段中,编译器不了解isync的运行时效果,除了我们可以通过内存约束告诉它.你会在互斥锁的尾端发现这样的isync指令,以防止在实际保持互斥锁之前执行成功获取互斥锁之后的指令(所以如果在异步之前已经执行了加载,那么必须被丢弃).
在这个代码片段中,我们有编译器屏障,可以防止重写代码,就好像它是如下所示
int v = pSharedMem->myVariable ;
v = pSharedMem->myVariable ;
__asm__ __volatile__(( "isync" : : :"memory" ))
Run Code Online (Sandbox Code Playgroud)
要么
__asm__ __volatile__(( "isync" : : :"memory" ))
int v = pSharedMem->myVariable ;
v = pSharedMem->myVariable ;
Run Code Online (Sandbox Code Playgroud)
(即:这两个编译器重新排序应该被volatile属性禁止)
我们还有isync本身可以防止在运行时进行第一次重新排序(但我不认为防止第二次没有那么有趣).
但是,我的问题是,如果myVariable 没有声明为volatile,那么"内存"约束是否足以使gcc在异步后必须重新加载"v"?我仍然倾向于为这种模式强制使用volatile,因为这种代码对于所有特定于平台的编译器内置都太敏感了.也就是说,如果我们将讨论简化为GCC和这个代码片段,这个asm内存约束是否足以让代码用一对负载而不是一个负载生成?