使用单个位作为单词的掩码
Use a single bit as mask for a word(s)
我正在编写一个 LLVM 传递模块来检测程序中的每个内存操作,我的部分逻辑需要对指针执行一些非常热门的二进制逻辑。
如何在尽可能少的周期内实现 "bit ? u64_value : zero",最好不使用显式分支?我在寄存器的最低有效位中有一个位,在另一个寄存器中有一个值(假设为 u64)。如果设置了该位,我希望保留该值。如果该位为零,我想将寄存器清零。
我可以使用 x86 BMI 指令。
在 AMD、Intel Broadwell 及更高版本上,CMOV 仅为 1 uop,具有 1 个延迟周期。或者在 Haswell 及更早版本上为 2 微指令/2 个周期。这是有条件地将寄存器清零的最佳选择。
xor r10d, r10d # r10=0. hoist out of loops if possible
test al, 1 # test the low bit of RAX, setting ZF
cmovz rax, r10 # zero RAX if the low bit was zero, otherwise unmodified
(test r64, imm8
编码不存在,因此如果您要测试低 8 位之外全为零的掩码,则需要使用低 8 位寄存器。)
如果位位置在寄存器中,bt reg, reg
在 Intel 和 AMD 上只有 1 uop。 (bts reg,reg
在 AMD K8 到 Ryzen 上是 2 微指令,但是根据所选位的值设置 CF 的普通 bt
在 AMD 和英特尔上很便宜。)
bt rax, rdx # CF = RAX & (1<<rdx)
cmovnc rax, r10
有了这两个,您测试的寄存器可以不同于 CMOV 目标。
见https://agner.org/optimize/ for more performance info, and also https://whosebug.com/tags/x86/info
select
是你的朋友。它主要编译为 cmov
但后端会处理它,即使没有。从语义上讲,它是 "if arg1 is true then arg2 else arg3",更像是 C/C++/java 中的 ?:。在 C++ API 中你调用 SelectInst::Create(yourBool, yourInputValue, ConstantInt::get(i64, 0), instructionName, currentBlock);
.
如果您能为说明起出有意义的名称,您会发现生活会更轻松。一开始这并不重要,但随着代码的增长,它会越来越简化调试。
我正在编写一个 LLVM 传递模块来检测程序中的每个内存操作,我的部分逻辑需要对指针执行一些非常热门的二进制逻辑。
如何在尽可能少的周期内实现 "bit ? u64_value : zero",最好不使用显式分支?我在寄存器的最低有效位中有一个位,在另一个寄存器中有一个值(假设为 u64)。如果设置了该位,我希望保留该值。如果该位为零,我想将寄存器清零。
我可以使用 x86 BMI 指令。
在 AMD、Intel Broadwell 及更高版本上,CMOV 仅为 1 uop,具有 1 个延迟周期。或者在 Haswell 及更早版本上为 2 微指令/2 个周期。这是有条件地将寄存器清零的最佳选择。
xor r10d, r10d # r10=0. hoist out of loops if possible
test al, 1 # test the low bit of RAX, setting ZF
cmovz rax, r10 # zero RAX if the low bit was zero, otherwise unmodified
(test r64, imm8
编码不存在,因此如果您要测试低 8 位之外全为零的掩码,则需要使用低 8 位寄存器。)
如果位位置在寄存器中,bt reg, reg
在 Intel 和 AMD 上只有 1 uop。 (bts reg,reg
在 AMD K8 到 Ryzen 上是 2 微指令,但是根据所选位的值设置 CF 的普通 bt
在 AMD 和英特尔上很便宜。)
bt rax, rdx # CF = RAX & (1<<rdx)
cmovnc rax, r10
有了这两个,您测试的寄存器可以不同于 CMOV 目标。
见https://agner.org/optimize/ for more performance info, and also https://whosebug.com/tags/x86/info
select
是你的朋友。它主要编译为 cmov
但后端会处理它,即使没有。从语义上讲,它是 "if arg1 is true then arg2 else arg3",更像是 C/C++/java 中的 ?:。在 C++ API 中你调用 SelectInst::Create(yourBool, yourInputValue, ConstantInt::get(i64, 0), instructionName, currentBlock);
.
如果您能为说明起出有意义的名称,您会发现生活会更轻松。一开始这并不重要,但随着代码的增长,它会越来越简化调试。