微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

这些变量之间的依赖是什么?

如何解决这些变量之间的依赖是什么?

给定这段汇编代码

(Line 1) .L6:
(Line 2) movsd -8(%rdx,%rax,8),%xmm0 
(Line 3) .L2:
(Line 4) addsd (%rcx,%xmm0
(Line 5) movsd %xmm0,(%rdx,8)
(Line 6) addq $1,%rax
(Line 7) cmpq %rax,%r8
(Line 8) jne .L6

1 ) 第 2 行和第 4 行中的 xmm0 之间的依赖关系是什么?我对先读后写的猜测是否正确?

2 ) 第 4 行和第 5 行之间的依赖关系如何?在第 4 行中,似乎 xmm0 被读取和写入(按此顺序)。在第 5 行,它被读取然后复制到位置 (%rdx,8)。那么它是阅读后阅读吗?还是写后读

我很困惑,因为发生了超过 2 个(读、写、读)操作,所以不确定在查看数据依赖项时会考虑哪些操作。

这是c代码

void randomgenericfunction(double a[],double p[],long n)
{
     long i;
     p[0] = a[0];
     for (i=1; i<n; i++) {
         p[i] = p[i-1] + a[i];
     }
     return;
}

任何帮助将不胜感激,谢谢!

解决方法

第2行只写xmm0,第4行读然后写,第5行只读。所以2到4和4到5都是写后读。

我想你可能会争辩说 4 到 5 也是在读取后读取的,但这并不是真正的依赖,因为两次读取对彼此没有任何影响。如果将第 4 行更改为仅读取 xmm0,而不写入它,那么编译器或 CPU 用第 5 行重新排序它就完全没问题了。因此第二个“依赖项”不值得一提。

,

addsd 读取和写入其目标操作数,因此其读取端是相对于较早加载的 RAW。

写入端将是 WAW,但写入操作要在读取后才能发生(因为 addd 在其两个输入都准备就绪后才能生成值),因此您通常不会将其称为单独的风险.以任何正常/标准方式处理 RAW 依赖项的任何方式都已经可以避免/处理 WAW 危害。

例如寄存器重命名 (Tomasulo) 将跟踪 addsd 正在读取加载结果,随后对 XMM0 的读取正在读取 addsd 结果,直到下一次写入创建另一个版本的寄存器。 (很像 SSA 静态单赋值)。或者在任何类型的管道中,在安全读取加载值之前,不会有值要写回。

我猜你可以想象在加载和 addsd 之间有一个像 mulsd %xmm0,%xmm5 这样的情况,你需要它来读取加载结果,而不是 addsd 结果,即使 XMM5 是一个的结果缓存未命中加载并且在 XMM0 之后很久才可用,因此 addsd 可能在更早的 XMM0 读取之前执行。显然,在执行可以到达读取+写入 XMM0 的 addsd 之前,有序管道将停止等待 XMM5 准备就绪,并且寄存器重命名管道(如所有现代 x86)将通过重命名来处理它。


第 4 行和第 5 行之间的依赖关系?那么是读后读吗?

那并不危险。让多个并发读取器同时读取同一个寄存器或值总是安全的。 不存在 RAR 危害;必须至少涉及一次写入才能使事情变得棘手。

是的,存储 addsd 结果是一种 RAW 危害(真正的依赖)。 store-data uop 需要等待 FP add 的结果。

(有趣的事实:在 Intel CPU 上,存储地址 uop 在单独的执行端口上运行,独立于存储数据,将地址写入在 uops 发出/分配/重命名期间分配的存储缓冲区条目这条指令的进入乱序后端。存储地址uop只读取%rdx和%rax,因此它在前一次迭代中对addq $1,%rax有RAW依赖性,假设这是一个循环.)

所以第 5 行对第 4 行有 RAW 依赖性,并且不以任何方式直接依赖于第 2 行。 (加载在通向存储的依赖链中较早,但通过 addsd 与它分离。)


如果 .L6.L3 之前的某处,那么这是一个循环,在底部的存储和下一次迭代中的加载之间存在一个 WAR anti-dependency,进入 XMM0。

另见

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。