所有形式上尊重依赖关系的CPU都允许独立依赖关系吗? 问题的上下文是普通缓存的内存,如C和C++对象的内存。

所有形式上尊重依赖关系的CPU都允许独立依赖关系吗? 问题的上下文是普通缓存的内存,如C和C++对象的内存。,c++,dependencies,cpu-architecture,cpu-cache,stdatomic,C++,Dependencies,Cpu Architecture,Cpu Cache,Stdatomic,许多CPU无序地执行内存加载(这样做的好处是不会在缓存未命中时完全暂停执行线程),并且不会在稍后检查另一个内核是否未请求更改这些(*)的权限,因此在程序顺序中稍后出现的读操作实际上是在较早时检索到的,另一个线程可能在这段时间内取得了进展,这意味着这两个与程序顺序一致的线程之间不可能就内存操作的顺序达成一致 (*)请求本地缓存使包含它的缓存线无效,这是在任何支持正常线程编程的体系结构中更改值之前的先决条件 许多允许这种行为的CPU类型还保证,当一个值取决于先前加载的结果时,所有依赖于该值的后续操作

许多CPU无序地执行内存加载(这样做的好处是不会在缓存未命中时完全暂停执行线程),并且不会在稍后检查另一个内核是否未请求更改这些(*)的权限,因此在程序顺序中稍后出现的读操作实际上是在较早时检索到的,另一个线程可能在这段时间内取得了进展,这意味着这两个与程序顺序一致的线程之间不可能就内存操作的顺序达成一致

(*)请求本地缓存使包含它的缓存线无效,这是在任何支持正常线程编程的体系结构中更改值之前的先决条件

许多允许这种行为的CPU类型还保证,当一个值取决于先前加载的结果时,所有依赖于该值的后续操作都会在加载之后发生,特别是从该值派生的地址处的加载

但从另一个导出的值在数学上与参数无关;事实上,将寄存器设置为零的一个常见习惯用法是将其值与其自身进行异或运算,这在语法上是从前一个寄存器派生出值,但在语义上不是

所有跟踪值依赖关系以保证基于依赖于先前负载的值的内存操作是否允许此类非语义依赖关系创建独立的依赖关系,以便对内存操作进行排序?这是否适用于位运算或所有算术运算,包括但不限于吸收元素的使用

最明显的例子是:

  • x^x
  • x&0
  • x|-1
  • x-x
  • x*0
  • x/x
    (如果为零,则引发异常)
这个问题的目的显然是理解编译器如何在C和C++中支持这些代码中的<代码>内存MyOrthOrthOuto.<代码>,遵循该特性的意图(而不是以定义MyEube为MyAub的方式退化)。 问题陈述

问题在于编译代码,例如

r1 = x.load(memory_order_consume);
r2 = y | (r1&0);
r3 = z + (r1-r1);
r4 = (&E)[r1*0];
其中,在中间代码中重命名
r1
并使其“register volatile”(类似volatile,不可优化,除非在寄存器中)的简单策略会在每个操作上产生正确的“consume”(值/地址相关负载)行为

奖金问题

是否有CPU直接支持依赖常量?这是一条“设置立即值”指令,它引入了常量对寄存器值的显式依赖关系:

load.i.dep r1,8,r4 ; sets r1 to 8 but dependency on value of r4 is respected
lea r0,r0,r1       ; r0 += r1, r0 depends on r4
load.w r2,r1       ; loads one word at r1 to r2 only after r4 is known

对主要问题的直接回答是否定的。即使是英特尔的CPU也不支持所有可能的破坏依赖关系的操作。这就是为什么会有习语(即做事的首选方式)。“更小”的设计很可能根本不支持任何破坏依赖关系的操作。与奖金问题一样,通常很容易在寄存器上创建依赖项(即通过将其设置为0或1等标识值),特别是如果before的答案为“否”。这太特殊了。@MargaretBloom您似乎误解了我的问题,也许我应该包括一个示例。我想看看在C++中,消费顺序的天真的非优化编译在所有情况下都是有效的,甚至像<代码>(e)[x.Load(MyEube)* 0 ] < /C>。英特尔甚至没有消费/获取的区别,因为不需要获取障碍,因此编译器不能在英特尔上错误编译消费操作。我认为主要危险之一是编译器有时会将数据依赖性转换为控制依赖性(受分支预测+推测性执行的影响,而不等待分支的输入)。例如,如果加载在
if
中,允许编译器推断指针值等于其他值,它可能会破坏/忽略数据依赖关系。据我所知,这不是。您可以使用
asm(“:”+r”(var))
使编译器“忘记”该值,例如
inttmp=r1;
然后使用
asm
使其“忘记”该
tmp=r1
。但在这一点上,使用
asm(“和%0,#0):“+r”(var_to_zero))
对内联asm进行调零(这是ARM/AArch64语法)@好奇的家伙,我给出的链接回答了你:PowerPC不会优化掉一个依赖项,即使它不会对地址的最终值做出贡献。打破依赖项取决于程序员。但是这种依赖项必须首先在代码中实现,因为C++11
x-x
是一个依赖项。