这个问题是关于Can the C compiler optimizer violate short-circuiting and reorder memory accesses for operands in a logical-AND expression?的后续问题。
考虑下面的代码。
if (*p && *q) {
/* do something */
}
现在,根据Can the C compiler optimizer violate short-circuiting and reorder memory accesses for operands in a logical-AND expression?的讨论(特别是David Schwartz的注释和答案),标准一致C编译器的优化器可以发出在
*q
之前访问*p
的CPU指令,同时仍然保持用&&
运算符建立的序列点的可观察行为。因此,尽管优化器可能在
*q
之前发出访问*p
的代码,但它仍然需要确保只有当*q
为非零时,*p
的任何副作用(例如分段错误)才是可观察的如果*p
为零,则不应观察到由*q
引起的故障,即首先在CPU上执行*q
将导致推测性故障,但一旦执行*p
并发现为0,则会忽略推测性故障。我的问题是:这一推测性错误是如何在幕后实施的?
如果你能在回答这个问题时对以下几点多加说明,我将不胜感激。
据我所知,当CPU检测到一个故障时,它会生成一个陷阱,内核必须处理这个陷阱(要么采取页面交换之类的恢复操作,要么向进程发送SIGSEGV之类的故障信号)。我说的对吗?
因此,如果编译器必须发出代码来执行推测性错误,那么在我看来,内核和编译器(可能还有CPU)必须相互协作才能实现推测性错误编译器如何发出指令,告诉内核或CPU由于代码而产生的错误应该被认为是推测性的?
最佳答案
它是作为正常推测性获取过程的一部分实现的。推测性获取的结果,无论是数值结果还是错误,都是推测性的只有在以后需要时才使用。
据我所知,当CPU检测到一个故障时,它会生成一个陷阱,内核必须处理这个陷阱(要么采取页面交换之类的恢复操作,要么向进程发送SIGSEGV之类的故障信号)。我说的对吗?
非推测性地执行产生错误的获取的结果是陷阱执行fetch的结果推测性地产生一个错误,这是一个推测性陷阱,只有在使用推测性fetch的结果时才会实际发生。如果你仔细想想,没有这个机制,投机获取是不可能的。
因此,如果编译器必须发出代码来执行推测性错误,那么在我看来,内核和编译器(可能还有CPU)必须相互协作才能实现推测性错误编译器如何发出指令,告诉内核或CPU由于代码而产生的错误应该被认为是推测性的?
编译器通过在对*q
的结果进行测试之后放置*p
的fetch来完成此操作。这向CPU发出信号,表示提取是推测性的,并且它只能在对*p
结果的测试结果已知后使用结果。
CPU可以在知道是否需要它之前执行*q
的获取。这几乎是必不可少的,因为一个fetch可能需要很慢的内核间操作——您不希望等待的时间超过需要的时间因此,现代多核cpu实现了积极的投机获取。
这就是现代CPU所做的(对于具有显式推测性获取操作的CPU,答案是不同的。)
关于c - 如何在后台实现由于编译器优化而引起的推测性错误?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/38072450/