相关疑难解决方法(0)

在 x86_64 中,如果条件为假,32 位 cmov 是否清除最高位?

在 x86 上的 64 位模式下,大多数 32 位算术运算会清除目标寄存器的前 32 位。如果算术运算是“cmov”指令,并且条件为假怎么办?(我看过的参考手册中似乎没有涵盖这种情况)。

assembly x86-64

3
推荐指数
1
解决办法
123
查看次数

折叠 __mask64 又名 64 位整数值,计算已设置所有位的半字节?

我有__mask64一些 AVX512 操作的结果:

__mmask64 mboth = _kand_mask64(lres, hres);

我想计算其中所有位均已设置的半字节数 ( 0xF)。

简单的解决方案是这样做:

uint64 imask = (uint64)mboth;
while (imask) {
    if (imask & 0xf == 0xf)
        ret++;
    imask = imask >> 4;
} 
Run Code Online (Sandbox Code Playgroud)

我想要更好的东西,但我想出的东西并不优雅:

    //outside the loop
    __m512i b512_1s = _mm512_set1_epi32(0xffffffff);
    __m512i b512_0s = _mm512_set1_epi32(0x00000000);

    //then...
    __m512i vboth = _mm512_mask_set1_epi8(b512_0s, mboth, 0xff);
    __mmask16 bits = _mm512_cmpeq_epi32_mask(b512_1s, vboth);
    ret += __builtin_popcount((unsigned int)fres);
Run Code Online (Sandbox Code Playgroud)

上面将一个0xff字节放入一个向量中,其中掩码中存在 1 位,然后当现在发现bits放大的半字节为' 时,在掩码中获取一个 1 位。0xf0xffffffff int32

我觉得当原始数据存在于 64 位数字中时,两个 512 …

c++ bit-manipulation avx avx512

3
推荐指数
1
解决办法
169
查看次数

查找 32 位数字中唯一设置位的位置

我需要得到一个32位数字中的1位数字,其中只有一个1位(总是)。最快的方式是C++或者asm。

例如

input:    0x00000001, 0x10000000
output:            0,         28
Run Code Online (Sandbox Code Playgroud)

c++ x86 assembly bit-manipulation intrinsics

2
推荐指数
1
解决办法
1185
查看次数

使用 C++20 的 std::popcount 和向量优化是否等同于 popcnt 内在?

C++20 引入了许多新函数,例如std::popcount,我使用Intel Intrinsic使用相同的功能。

我编译了这两个选项 - 可以在编译器资源管理器代码中看到:

  1. 使用英特尔的 AVX2 内在
  2. 使用 std::popcount 和 GCC 编译器标志“-mavx2”

除了 std 模板中使用的类型检查之外,生成的汇编代码看起来是相同的。

就操作系统不可知代码并具有相同的优化而言 - 假设使用std::popcount和 apt 编译器向量优化标志比直接使用内在函数更好是否正确?

谢谢。

c++ intrinsics language-lawyer avx2 c++20

2
推荐指数
1
解决办法
301
查看次数

有什么方法可以使用 MOV 在 32 位 x86 中移动 2 个字节而不会导致模式切换或 CPU 停顿?

如果我想将 2 个无符号字节从内存移动到 32 位寄存器中,我可以用MOV指令而不用模式切换来做到这一点吗?

我注意到您可以使用MOVSEMOVZE说明来做到这一点。例如,通过MOVSE编码0F B7将 16 位移动到 32 位寄存器。不过,它是一个 3 周期指令。

或者,我想我可以将 4 个字节移动到寄存器中,然后以某种方式仅 CMP 中的两个。

在 32 位 x86 上检索和比较 16 位数据的最快策略是什么?请注意,我主要进行 32 位操作,因此我无法切换到 16 位模式并留在那里。


仅供初学者参考:这里的问题是 32 位 Intel x86 处理器可以处理MOV8 位数据和 16 位 OR 32 位数据,具体取决于它们所处的模式。这种模式称为“D 位”设置。您可以使用特殊前缀 0x66 和 0x67 来使用非默认模式。例如,如果您处于 32 位模式,并且您使用 0x66 作为指令前缀,这将导致操作数被视为 16 位。唯一的问题是这样做会导致性能下降。

performance x86 assembly intel

1
推荐指数
1
解决办法
3670
查看次数

x64 支持是否意味着 BMI1 支持?

可以安全地假设 x64 构建可以使用TZCNT而无需通过 cpu 标志检查其支持吗?

assembly x86-64 instruction-set bmi

1
推荐指数
1
解决办法
247
查看次数

C 中的内联汇编

我正在用 c 语言编写一个国际象棋引擎,速度至关重要。国际象棋引擎基于 unsigned long long,我将其表示为 u64,并且它严重依赖于最低有效位扫描。到目前为止,我一直在使用 gcc 函数 __builtin_ctzll ,它做得很好。然而,我使用 gcc -S -O2 为这个独立函数生成了汇编代码。它给了我以下内容:

xorl     %eax, %eax
rep bsfq %rdi, %rax
cltq
ret
Run Code Online (Sandbox Code Playgroud)

然而经过一番调查似乎代码

rep bsfq %rdi, %rax
ret
Run Code Online (Sandbox Code Playgroud)

在我的国际象棋程序中做了完全相同的事情。然而现在速度慢了约 20%。它应该更快,因为它的指令更少。然而,原始的 __builtin_ctzll 内联在我的 C 代码中。这是我的自定义汇编代码运行速度比原始代码慢的原因吗?因为当我声明函数 ctzll 时,我当然不能在 c 中内联声明它,除非我有定义(不在汇编代码中)。

是否有另一种方法来优化汇编指令,或者我应该尝试直接在 c 中内联 asm 的新汇编代码?

c assembly gcc x86-64 micro-optimization

0
推荐指数
1
解决办法
374
查看次数