【问题标题】:Is there a compiler memory barrier for a single variable?单个变量是否存在编译器内存屏障?
【发布时间】:2012-01-17 14:15:23
【问题描述】:

编译器内存屏障的作用之一是强制编译器确保缓存在寄存器中的所有堆栈变量在屏障之前写入内存。

例如,GCC有如下语句:

asm inline ("" : : : "memory");

有没有办法告诉编译器(特别是 GCC,但我也对其他编译器感兴趣)只对 特定 变量执行相同的效果?类似于以下想象的构造:

int x;
...
asm inline ("" : : : "memory(x)");

如果 x 和 x 的值恰好缓存在寄存器中,则预期行为只会将其写入相应的内存位置。

原因是我有一个特定的变量,我需要确保它没有缓存在寄存器中,以便硬件引擎可以读取它的值。但是,一个完整的编译器内存屏障将迫使编译器将 all 其他变量的值写入内存,这些变量可能在那个时间点缓存在寄存器中,这可能会产生比我更多的数据需要写。我想知道是否有更具体的内容。

提前致谢!

【问题讨论】:

    标签: c gcc compiler-construction


    【解决方案1】:

    尝试使用{ int y = x; *(volatile int*)&x = y; } 并检查生成的程序集。

    【讨论】:

    • 对!看来,对于我的需要,即使*(volatile int*)&x = x; 也可以正常工作。非常感谢! :-)
    • 只是喜欢简单的解决方案+1
    • 如果x 在寄存器中,它会按要求行事。但是,如果x 已经在内存中提交,它将再次加载/存储它。
    【解决方案2】:

    由于您愿意使用 gcc 扩展,因此您可以将扩展用于该功能的原子指令:

    __sync_bool_compare_and_swap(&myvar, 0, 0)
    

    如果变量的值已经是0,则将其值设置为0 :),此外还暗示该内存位置的完全顺序一致性。

    【讨论】:

      【解决方案3】:

      回忆lkml上的一个线程,单变量仅编译器屏障的方法之一是:

      #define forget(x) __asm__ __volatile__("":"=m"(x):"m"(x))
      

      【讨论】:

      • 附注:这是一个完整的屏障(强制存储到内存并强制从内存重新加载)。您可以使用__asm__ __volatile__(""::"m"(x)) 获得写屏障,使用__asm__ __volatile__("":"=m"(x)) 获得读屏障
      【解决方案4】:

      我猜你可以通过在asm的输出值列表中指定你的变量来实现它:

      __asm__ __volatile__ ("" : "=r" (x) : : )
      

      有关一些信息,请参阅Extended Asm

      更新。

      使用"g" 约束而不是"r" 可能会更好。

      __asm__ __volatile__ ("" : "=g" (x) : : )
      

      另外,我发现另一个 great howto 用于内联汇编。

      【讨论】:

      • 不,首先 g 或 r 约束都不起作用,因为它们允许将值放入寄存器中。我认为对 x 地址的“m”约束可能有效,但 gcc 会发出关于内存输入 0 不能直接寻址的错误。感谢您尝试:-)
      猜你喜欢
      • 2010-12-30
      • 2010-12-07
      • 1970-01-01
      • 1970-01-01
      • 2013-01-18
      • 2011-10-12
      • 1970-01-01
      • 2014-05-29
      • 2014-12-05
      相关资源
      最近更新 更多