是否可以?对于没有任何分支/循环的小代码。是否有任何gcc
标志或内在指令,如 SSEx86
和其他处理器系列?我只是好奇,因为这些天所有可用的处理器都遵循乱序执行模型。
提前致谢
是否可以?对于没有任何分支/循环的小代码。是否有任何gcc
标志或内在指令,如 SSEx86
和其他处理器系列?我只是好奇,因为这些天所有可用的处理器都遵循乱序执行模型。
提前致谢
大多数现代无序 CPU 本质上都是无序的,无法在有序和无序模式之间切换。
你可以试着找一些有序的CPU,有一些:
虽然不可能在典型的乱序 CPU 中直接关闭指令重新排序,但您可以在每条指令之间注入一些序列化(如cpuid
在 x86 世界中)以模拟按顺序执行。
有一部分关于序列化指令的英特尔手册(第 3a 卷)(从http://objectmix.com/asm-x86-asm-370/69413-serializing-instructions.html复制):
第 3A 卷:系统编程指南状态
7.4 序列化指令
Intel 64 和 IA-32 架构定义了几个序列化指令。这些指令强制处理器完成先前指令对标志、寄存器和内存的所有修改,并在获取和执行下一条指令之前清空所有缓冲的内存写入。例如,当使用 MOV 控制寄存器指令将新值加载到控制寄存器 CR0 以启用保护模式时,处理器必须在进入保护模式之前执行序列化操作。这种串行化操作确保在处理器处于实地址模式时启动的所有操作在切换到保护模式之前完成。
序列化指令的概念被引入到带有 Pentium 处理器的 IA-32 架构中,以支持并行指令执行。序列化指令对 Intel486 及更早版本的处理器没有意义,这些处理器不实现并行指令执行。
需要注意的是,在 P6 和更新的处理器系列上执行序列化指令会限制推测执行,因为推测执行指令的结果会被丢弃。以下指令是序列化指令:
o 特权序列化指令 - MOV(到控制寄存器,除了 MOV CR8)、MOV(到调试寄存器)、WRMSR、INVD、INVLPG、WBINVD、LGDT、LLDT、LIDT 和 LTR。
o 非特权序列化指令 - CPUID、IRET 和 RSM。
当处理器串行化指令执行时,它会确保在执行下一条指令之前完成所有待处理的内存事务(包括存储在其存储缓冲区中的写入)。没有任何东西可以传递序列化指令,序列化指令也不能传递任何其他指令(读、写、取指或 I/O)。例如,CPUID 可以在任何特权级别执行,以序列化指令执行,而不影响程序流,除了修改 EAX、EBX、ECX 和 EDX 寄存器。
这是可能的,但这取决于CPU。再说一次,指令本身并不重要,内存访问很重要。
AFAIK 所有 CPU 保证寄存器(以及内部状态)按顺序更新,无论执行如何发生。在某些 CPU 中,临时寄存器被分配了一个值,结果在适当的时候被“写回”(寄存器重命名,因此本身没有副本)。
对于内存访问,大多数 CPU 都有某种内存屏障,这限制了内存访问的重新排序。有几种不同类型的内存屏障,它们因 CPU 而异。可以想象,您可以在每条指令之间放置一个完整的内存屏障,并且您将到达一半。如果你有一台多处理器机器,你可能需要做一些额外的工作来确保缓存也被刷新。如果没有明确的指示,其他核心可能无法按顺序看到结果。
这在很大程度上取决于您要实现的目标以及特定的 CPU。那里的每个 CPU 在某种程度上都是不同的。并且不会有任何神奇的 gcc 标志。在 gcc 中,您将拥有的最好的是内置原子类型(下面的链接)。话题很大。没有简单的答案。
推荐阅读清单: