如果CPU是一台二进制机器,为什么它的比特操作速度慢



我发现x86 CPU在处理二进制操作指令(如SHR、BT、BTR、ROL等)时速度非常慢,这与它的二进制/双状态性质相反。

例如,我从某个地方读到,比特移位/旋转超过1个位置被认为是缓慢的(具有高延迟、性能损失和那些可怕的东西)。当操作数在内存中时,情况会更糟(内存不是双状态外设吗?)

shl eax,1  ;ok
shl eax,7  ;slow?

那么是什么让它们变慢了呢?具有讽刺意味的是,像CPU这样的二进制机器在比特操作上很慢,而这种操作本应是自然的。它给人的印象是二进制CPU很难将位移位到位!

编辑:现在再看一眼手册中的SHL条目,它确实涉及到一些沉重的微码逻辑!

从英特尔shl第2卷手册。。。

Operation
TemporaryCount = Count & 0x1F;
TemporaryDestination = Destination;
while(TemporaryCount != 0) {
if(Instruction == SAL || Instruction == SHL) {
CF = MSB(Destination);
Destination = Destination << 1;
}
//instruction is SAR or SHR
else {
CF = LSB(Destination);
if(Instruction == SAR) Destination = Destination / 2; //Signed divide, rounding toward negative infinity
//Instruction is SHR
else Destination = Destination / 2; //Unsigned divide
}
TemporaryCount = TemporaryCount - 1;
}
//Determine overflow
if(Count & 0x1F == 1) {
if(Instruction == SAL || Instruction == SHL) OF = MSB(Destination) ^ CF;
else if(Instruction == SAR) OF = 0;
//Instruction == SHR
else OF = MSB(TemporaryDestination);
}
else OF = Undefined;

难以置信的是,看到这样一个简单的布尔代数变成了一场实现噩梦。

这只是指令的伪代码,确切地指定了它的作用。该指令实际上并不是这样实现的。在实践中,所有现代CPU都有桶形移位器或类似的移位器,允许它们在一个周期内移位任意量。例如,参见Agner Fog的表,其中显示了几乎所有位篡改指令的延迟为1。

一些篡改指令比较慢,下面是一些例子:

  • btbtrbtsbtc在与内存操作数一起使用时较慢,因为它们执行(a)读取-修改-写入操作和(b)位串索引
  • 具有大于1的旋转量的rcr是缓慢的,因为该指令几乎从不需要,因此没有被优化
  • pdeppext在Intel上稍慢,在AMD上慢得多,可能是因为它们的实现非常复杂,并且将实现拆分会更容易

在旧的处理器(比如8086)上,CPU将占用与移位量一样多的周期,每个周期进行一次移位。这种实现方式允许ALU在没有任何额外硬件的情况下用于移位,从而减少了处理器所需的门的数量。据我所知,没有一个现代CPU具有这种性能行为。

只是一个注释。

shl eax,1 ; opcode: d1 e0
shl eax,7 ; opcode: c1 e0 07

实际上是具有不同操作码的不同指令,其可能由ALU的不同逻辑块处理。它们在汇编中使用相同的助记符,这可能会混淆,但从CPU的角度来看,它们是具有不同操作码和编码的不同指令。

最新更新