Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Assembly 为什么现代x86掩码会将计数移到CL中的5个低位_Assembly_X86_Cpu Architecture_Bit Shift_Cpu Registers - Fatal编程技术网

Assembly 为什么现代x86掩码会将计数移到CL中的5个低位

Assembly 为什么现代x86掩码会将计数移到CL中的5个低位,assembly,x86,cpu-architecture,bit-shift,cpu-registers,Assembly,X86,Cpu Architecture,Bit Shift,Cpu Registers,我正在深入研究x86 ASM中的左右移位操作,比如shl eax,cl 摘自IA-32英特尔体系结构软件开发人员手册3 所有IA-32 处理器(从Intel 286处理器开始)确实掩盖了这种变化 计数为5位,最大计数为31。这个掩蔽是 在所有操作模式(包括虚拟8086模式)下完成 减少指令的最大执行时间 我试图理解这个逻辑背后的原因。也许它是这样工作的,因为在硬件级别上,很难使用1个周期实现寄存器中所有32(或64)位的移位 任何详细的解释都会很有帮助 我不认为32位寄存器移位32比31位寄存器

我正在深入研究x86 ASM中的左右移位操作,比如
shl eax,cl

摘自IA-32英特尔体系结构软件开发人员手册3

所有IA-32 处理器(从Intel 286处理器开始)确实掩盖了这种变化 计数为5位,最大计数为31。这个掩蔽是 在所有操作模式(包括虚拟8086模式)下完成 减少指令的最大执行时间

我试图理解这个逻辑背后的原因。也许它是这样工作的,因为在硬件级别上,很难使用1个周期实现寄存器中所有32(或64)位的移位


任何详细的解释都会很有帮助

我不认为32位寄存器移位32比31位寄存器移位更困难。 从数学角度来看,对移位计数进行饱和将比对掩码进行饱和更合适。我们必须记住,
SHR EAX,32
什么都不做,必须使用其他指令来清除EAX的内容


也许英特尔开发人员希望使用相同的内部机制来执行旋转移位操作。例如
ROR-EAX,35
相当于
ROR-EAX,3
,因此
SHR-EAX,35
相当于
SHR-EAX,3

编辑以更正re:80386的陈述(令我惊讶的是)确实有一个桶移位器


很高兴听到286被描述为“现代”:-)

8086以8个时钟+4个时钟/位移位运行一个
SHL AX,CL
。因此,如果
CL
=255,这是一条非常慢的指令

所以286帮了大家一个忙,把计数设为0..31。将指令限制为最多5+31个时钟。对于16位寄存器来说,这是一个有趣的折衷方案

[我找到了“80186/80188 80C186/80C188硬件参考手册”(订单号270788-001),上面说这项创新首先出现在那里。
SHL
等人运行了5+n时钟(用于寄存器操作),与286.FWIW相同,186还添加了PUSHA/POPA、PUSH immed、INS/OUTS、BOND、ENTER/LEFT、INUL immed.和SHL/ROL等immed。我不知道为什么186看起来是非个人。]

对于386,它们保持相同的掩码,但这也适用于32位寄存器移位。我找到了一份“80386程序员参考手册”(订单号230985-001),它给出了所有寄存器移位的时钟计数为3。“英特尔80386硬件参考手册”(订单号231732-002)第2.4节“执行单元”指出,执行单元包括:

•数据单元包含ALU、八个32位通用寄存器文件和一个64位桶形移位器(在一个时钟中执行多个位移位)

所以,我不知道为什么他们没有屏蔽32位移位到0..63。在这一点上,我只能提出错误的历史理论

我同意,对于任何计数>=参数大小,都没有返回零的(GPR)移位,这是一个遗憾。这需要硬件检查超出底部6/5的任何位集,并返回零。作为一种折衷方案,也许只需要Bit6/Bit5

[我没有尝试过,但我怀疑使用
PSLLQ
等是一项艰苦的工作——将计数和值洗牌到
xmm
并再次洗牌结果——与测试移位计数和以某种无分支方式掩盖移位结果相比。]


无论如何。。。这种行为的原因似乎是历史原因。

对于电子产品;如果移位计数为常量,则可以不执行任何操作进行移位(就像将“输入位0”的导线连接到“输出位1”的导线,等等)

您可以将一个可变移位计数分解为多个“带常量计数的移位”操作,最终的结果大致如下:

if( (count & 1) != 0) { v = v << 1; }
if( (count & 2) != 0) { v = v << 2; }
if( (count & 4) != 0) { v = v << 4; }
if( (count & 8) != 0) { v = v << 8; }
if( (count & 16) != 0) { v = v << 16; }

如果((计数和1)!=0){v=v尽管英特尔目前的手册上说,屏蔽移位计数在186年是新的。例如,在反向工程中,SE使用这一事实来区分8086/88和80186/88。也许英特尔没有计算186,而是打算用于嵌入式系统?或者英特尔当前的手册是错误的;这不是第一个ti我


在x86从简单的微代码8086发展到186、286和386的过程中,这几乎是一个任意的设计决策,但我们可以看到一些动机。386有一个桶形移位器(恒定时间移位),186和286没有。IDK如果ISA设计决策是在硬件设计决策之前或之后确定的

ARM的选择不同,它对移位计数进行饱和,而不是对其进行包装。按寄存器宽度或更大的ARM移位会使值为零

x86 SIMD移位类似于饱和计数;您可以使用MMX/SSE/AVX移位移出每个元素的所有位,或者基于每个元素进行移位,如果您使用
c-192
c-128
c-64
c
或其他方法计算每个元素的移位计数,这可能会很好将计数设为操作数大小-1,这样就不可能让某些元素一直移动到边界之外,并且在目标元素中只保留src2中的位。正如下面对386 scalar
shrd
所讨论的,这将需要更宽的桶移位器,或者一些高计数的特殊外壳


186/286具有O(n)移位/旋转(无桶形移位器),因此掩蔽限制了最坏情况下的移位性能。

8086:
SHL AX,CL
每位移位需要8个时钟+4个时钟。CL=255的最坏情况是1028个周期。286:5+n,最坏情况是5+31=36个周期

如果移位不能中止mid指令,并且没有任何更慢的指令,286移位计数掩蔽还可以限制多任务系统最坏情况下的中断延迟。(286推出了其保护模式版本,因此英特尔