这是我在 AVX512BW 中的“strlen”函数的代码
vxorps zmm0, zmm0, zmm0 ; ZMM0 = 0
vpcmpeqb k0, zmm0, [ebx] ; ebx is string and it's aligned at 64-byte boundary
kortestq k0, k0 ; 0x00 found ?
jnz .chk_0x00
Run Code Online (Sandbox Code Playgroud)
现在对于'chk_0x00',在x86_64系统中,没有问题,我们可以这样处理:
chk_0x00:
kmovq rbx, k0
tzcnt rbx, rbx
add rax, rbx
Run Code Online (Sandbox Code Playgroud)
这里我们有一个 64 位寄存器,因此我们可以将掩码存储到其中,但我的问题是关于 x86 系统,我们没有任何 64 位寄存器,因此我们必须使用“内存”保留(8 字节)并检查两者掩码的DWORD一一对应(其实这是我的方式,我想知道有没有更好的方式)
chk_0x00:
kmovd ebx, k0 ; move the first dword of the mask to the ebx
test ebx, ebx ; 0x00 found in the first dword ?
jz …Run Code Online (Sandbox Code Playgroud) 当我在https://godbolt.org上使用不同的编译器时,我注意到编译器生成这样的代码是很常见的:
push rax
push rbx
push rcx
call rdx
pop rcx
pop rbx
pop rax
Run Code Online (Sandbox Code Playgroud)
我理解每个push或pop做两件事:
所以在我们上面的例子中,我假设 CPU 实际上在做 12 次操作(6 次移动,6 次加/减),不包括call. 组合添加/订阅不是更有效吗?例如:
sub rsp, 24
mov [rsp-24], rax
mov [rsp-16], rbx
mov [rsp-8], rcx
call rdx
mov rcx, [rsp-8]
mov rbx, [rsp-16]
mov rax, [rsp-24]
add rsp, 24
Run Code Online (Sandbox Code Playgroud)
现在只有 8 次操作(6 次移动,2 次加/减),不包括call. 为什么编译器不使用这种方法?
我对https://uops.info/上的指令延迟有疑问。
对于某些指令,例如PCMPEQB(XMM, M128)Skylake 表条目中的延迟被列为[1;?8]
我对延迟有一点了解,但我知道它只是一个数字!!!例如,1 或 2 或 3 或...但这是什么[1;?8]!!!???这意味着延迟取决于内存,它在 1 到 8 之间?
如果是真的,什么时候是 1 .. 什么时候是 3,等等?
例如,它的延迟是多少:
pcmpeqb xmm0, xword [.my_aligned_data]
....
....
align 16
.my_aligned_data db 5,6,7,2,5,6,7,2,5,6,7,2,5,6,7,2
Run Code Online (Sandbox Code Playgroud)
这里的确切延迟值是多少pcmpeqb xmm0, xword [.my_aligned_data]???
或者例如,
PMOVMSKB (R32, XMM)
Run Code Online (Sandbox Code Playgroud)
该指令的延迟是 (?3) !!! 什么意思 ?!这是否意味着延迟在 1 到 3 之间?如果是,则此指令仅适用于寄存器!!!那么什么时候是1 与更高的数字呢?
performance x86 assembly cpu-architecture micro-optimization
我知道我们可以做这样的事情来将一个字符移动到一个 xmm 寄存器:
movaps xmm1, xword [.__0x20]
align 16
.__0x20 db 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20
Run Code Online (Sandbox Code Playgroud)
但由于这是一个记忆过程,我想知道是否有更好的方法?(另外,我在谈论 SSE2 而不是其他 SIMD 类型......)
我希望 xmm1 寄存器的每个字节都是 0x20,而不仅仅是一个字节..
(编者注:这可以称为广播或 splat。
这是_mm_set1_epi8(0x20)内在函数的作用。)
要将一个数字乘以 2 的任意倍数,我将对其进行多次移位。
有没有这样的技术可以在更少的周期内将数字乘以 10?
什么更快:
add DWORD PTR [rbp-0x4],1
Run Code Online (Sandbox Code Playgroud)
或者
mov eax,DWORD PTR [rbp-0x4]
add eax,1
mov DWORD PTR [rbp-0x4],eax
Run Code Online (Sandbox Code Playgroud)
我已经看到编译器生成的第二个代码,所以也许调用add寄存器要快得多?
当 8 位指令和 64 位 x64/Amd64 处理器上的 64 位指令除了位宽之外相似/相同时,这些指令之间是否存在执行时序差异?有没有办法找到执行这两个微小汇编函数的真实处理器时序?
-谢谢。
; 64 bit instructions
add64:
mov $0x1, %rax
add $0x2, %rax
ret
; 8 bit instructions
add8:
mov $0x1, %al
add $0x2, %al
ret
Run Code Online (Sandbox Code Playgroud) 冒着重复的风险,也许我现在找不到类似的帖子:
我正在用 C++(具体来说是 C++20)编写。我有一个带有计数器的循环,每转一次都会进行计数。我们就这样称呼它吧counter。如果counter达到页面限制(我们称之为page_limit),程序应该继续下一页。所以它看起来像这样:
const size_t page_limit = 4942;
size_t counter = 0;
while (counter < foo) {
if (counter % page_limit == 0) {
// start new page
}
// some other code
counter += 1;
}
Run Code Online (Sandbox Code Playgroud)
现在我想知道,因为计数器变得相当高:如果我不让程序counter % page_limit每次都计算模数,而是创建另一个计数器,程序运行得会更快吗?它可能看起来像这样:
const size_t page_limit = 4942;
size_t counter = 0;
size_t page_counter = 4942;
while (counter < foo) {
if (page_counter == page_limit) {
// start new page
page_counter = 0;
} …Run Code Online (Sandbox Code Playgroud) c++ performance assembly micro-optimization branch-prediction
考虑到如/sf/answers/2356780681/ 中详述的考虑,这似乎xor reg, reg是将寄存器清零的最佳方法。但是当我审视现实世界的汇编代码(如Windows Bootloader代码,IIRC),我看到这两个xor reg, reg和sub reg, reg使用了。
为什么sub完全用于此目的?sub在某些特殊情况下有什么理由更喜欢吗?例如,它设置的标志是否与xor?
我很难解释英特尔性能事件报告。
\n考虑以下主要读/写内存的简单程序:
\n#include <stdint.h>\n#include <stdio.h>\n\nvolatile uint32_t a;\nvolatile uint32_t b;\n\nint main() {\n printf("&a=%p\\n&b=%p\\n", &a, &b);\n for(size_t i = 0; i < 1000000000LL; i++) {\n a ^= (uint32_t) i;\n b += (uint32_t) i;\n b ^= a;\n }\n return 0;\n}\nRun Code Online (Sandbox Code Playgroud)\n我用gcc -O2以下命令编译它并运行perf:
#include <stdint.h>\n#include <stdio.h>\n\nvolatile uint32_t a;\nvolatile uint32_t b;\n\nint main() {\n printf("&a=%p\\n&b=%p\\n", &a, &b);\n for(size_t i = 0; i < 1000000000LL; i++) {\n a ^= (uint32_t) i;\n b += (uint32_t) i;\n b ^= a;\n }\n …Run Code Online (Sandbox Code Playgroud)