Assembly 将CPU寄存器中的所有位有效设置为1

Assembly 将CPU寄存器中的所有位有效设置为1,assembly,arm,mips,x86-64,Assembly,Arm,Mips,X86 64,要清除所有位,您通常会看到异或eax、eax中的异或。对相反的人也有这样的把戏吗 我所能想到的就是用一条额外的指令来反转零。对于大多数具有固定宽度指令的体系结构,答案可能是一条无聊的单指令mov,即符号扩展或反转立即数,或mov lo/high对。e、 g.在手臂上,mvn r0,#0(不移动)。请参阅x86、ARM、ARM64和MIPS的gcc asm输出。IDK任何关于zseries asm或机器代码的信息 在ARM中,eor r0、r0、r0明显低于mov立即测试。它取决于旧值,没有特殊情

要清除所有位,您通常会看到异或eax、eax中的异或。对相反的人也有这样的把戏吗


我所能想到的就是用一条额外的指令来反转零。

对于大多数具有固定宽度指令的体系结构,答案可能是一条无聊的单指令
mov
,即符号扩展或反转立即数,或mov lo/high对。e、 g.在手臂上,
mvn r0,#0
(不移动)。请参阅x86、ARM、ARM64和MIPS的gcc asm输出。IDK任何关于zseries asm或机器代码的信息

在ARM中,
eor r0、r0、r0
明显低于mov立即测试。它取决于旧值,没有特殊情况处理。内存依赖顺序规则同样适用于大多数其他具有弱顺序内存的RISC ISA,但对于
内存_顺序_消耗
(在C++11术语中)不需要障碍


x86 xor归零是一种特殊的方法,因为它的指令集长度可变。 从历史上看,8086
xor ax,ax
之所以直接快是因为它很小。由于这个习惯用法被广泛使用(归零比所有的都普遍),CPU设计人员给了它特殊的支持,现在
xor eax,eax
比英特尔Sandybridge系列和其他一些CPU上的
mov eax,0
更快,即使不考虑直接和间接的代码大小影响。看看我能挖掘到的微体系结构优势

如果x86有一个固定宽度的指令集,我想知道
mov reg,0
是否会得到像xor调零那样多的特殊处理?也许,因为在编写low8或low16之前打破依赖关系很重要


最佳性能的标准选项:

  • mov eax,-1
    :5个字节,使用
    mov r32、imm32
    编码。(不幸的是,没有迹象扩展mov r32、imm8)。在所有CPU上都有出色的性能。r8-r15为6字节(REX前缀)
  • mov-rax,-1
    :7个字节,使用
    mov r/m64,sign-extended-imm32
    编码。(不是REX.W=1版本的
    eax
    版本。这将是10字节
    mov r64,imm64
    )。在所有CPU上都有出色的性能

节省一些代码大小的奇怪选项通常以牺牲性能为代价:

  • 异或eax,eax
    /
    dec rax
    (或
    非rax
    ):5个字节(4个字节代表32位
    eax
    )。缺点:前端有两个UOP。仍然只有一个未使用的域uop用于最新Intel上的调度程序/执行单元,其中在前端处理
    mov
    -immediate始终需要一个执行单元。(但整数ALU吞吐量很少成为可以使用任何端口的指令的瓶颈;额外的前端压力是问题所在)
  • xor ecx,ecx
    /
    lea eax,[rcx-1]
    两个常量总共5个字节(6个字节用于
    rax
    ):保留一个单独的调零寄存器。如果您已经想要一个归零寄存器,那么这几乎没有什么坏处
    lea
    可以在比大多数CPU上的mov r,i更少的端口上运行,但由于这是一个新依赖链的开始,CPU可以在它发出后的任何空闲执行端口周期中运行它

    如果使用
    mov reg,imm32
    执行第一个,使用
    lea r32,[base+disp8]
    执行第二个,则相同的技巧适用于附近的任意两个常量。disp8的范围为-128到+127,否则需要一个
    disp32

  • 或eax,-1
    :使用
    或r/m32符号扩展-imm8
    编码的3个字节(4个用于
    rax
    )。缺点:错误地依赖于寄存器的旧值

  • push-1
    /
    pop-rax
    :3个字节。慢但小。仅推荐用于漏洞利用/代码高尔夫适用于任何sign-extended-imm8,与大多数其他产品不同

    缺点:

    • 使用存储和加载执行单元,而不是ALU。(在AMD推土机系列上,只有两个整数执行管道,但解码/发布/退出吞吐量高于此值,这在极少数情况下可能是一个吞吐量优势。但在未经测试的情况下不要尝试。)
    • 例如,存储/重新加载延迟意味着
      rax
      在Skylake上执行后约5个周期内无法准备就绪
    • (英特尔):将堆栈引擎置于rsp修改模式,因此下次直接读取
      rsp
      时,它将采用堆栈同步uop。(例如,对于
      添加rsp,28
      ,或对于
      mov eax,[rsp+8]
    • 存储可能在缓存中丢失,从而触发额外的内存流量。(如果没有接触长循环中的堆栈,则可能)

向量reg是不同的 将向量寄存器设置为具有pcmpeqd xmm0、xmm0的所有寄存器在大多数CPU上都是特殊情况,即依赖关系破坏(不是Silvermont/KNL),但仍然需要一个执行单元来实际写入这些寄存器
pcmpeqb/w/d/q
所有工作,但在某些CPU上
q
速度较慢

对于AVX2,与
ymm
等效的
vpcmpeqd ymm0、ymm0、ymm0
也是最佳选择

对于没有AVX2的AVX,选择不太明确:没有一种明显的最佳方法。编译器使用:gcc更喜欢加载带有
vmovdqa
的32字节常量,而较旧的clang使用128位
vpcmpeqd
后跟一个交叉通道
vinsertf128
来填充高半部分。较新的clang使用
vxorps
将寄存器归零,然后
vcmtrueps
将寄存器填充为零。这在道德上等同于
vpcmpeqd
方法,但需要
vxorps
来打破对先前版本寄存器和
vmptrueps