assembly - 分配给具有特定索引的位的好方法是什么?

标签 assembly optimization bit-manipulation bitwise-operators micro-optimization

这个问题:

How do you set, clear, and toggle a single bit?

讨论了对较大值内的特定位的三种操作,它们以直接的方式对应于该位上的 OR 1、AND 0 和 XOR 1。但是如果我们事先不知道第二位的值怎么办?如果我们想要执行赋值,而我们在编译时不知道其他操作数位怎么办?也就是说,我们想要将位 block 中某个位置的一位设置为运行时提供的新的不相关位的值?

我希望在 Intel x86_64 上尽可能快地实现这一点(并忽略矢量化,我希望这与此无关)。另外,为简单起见,假设位 block 类型为 uint32_t

编辑:我的答案是 C 而不是 C++,因为这个问题实际上与 C++ 无关。

最佳答案

对于 32 位 block 类型的情况,这里有两种可能的实现:

#include <cstdint>

uint32_t bit_assign_v1(uint32_t block, uint8_t bit_index, bool x)
{
    uint32_t mask = uint32_t { 1 } << bit_index;
    return (block & ~mask) | (((uint32_t) x) << bit_index);
}

uint32_t bit_assign_v2(uint32_t block, uint8_t bit_index, bool x)
{
    uint32_t mask = uint32_t { 1 } << bit_index;
    return x ? (block & ~mask) : (block | mask);
}

使用 GodBolt,我为这两个选项获得了不同优化的代码,随着我们更改平台和编译器,这些代码也会有所不同。这是 example对于 Skylake(或者更好的是,查看 this version ,它是相同的代码,但分为更多的 C 语句,以便您可以更好地将程序集与 C 代码关联起来)。

GCC 8.2 组件:

bit_assign_1:
        movzx   eax, sil
        btr     edi, eax
        movzx   edx, dl
        shlx    eax, edx, eax
        or      eax, edi
        ret
bit_assign_2:
        mov     ecx, 1
        shlx    esi, ecx, esi
        andn    eax, esi, edi
        or      esi, edi
        test    dl, dl
        cmove   eax, esi
        ret

clang 7.0 组件:

bit_assign_1:                           # @bit_assign_1
        btr     edi, esi
        shlx    eax, edx, esi
        or      eax, edi
        ret
bit_assign_2:                           # @bit_assign_2
        mov     eax, edi
        btr     eax, esi
        bts     edi, esi
        test    edx, edx
        cmovne  edi, eax
        mov     eax, edi
        ret

我还没有对这些进行任何基准测试。

关于assembly - 分配给具有特定索引的位的好方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52632484/

相关文章:

c++ - 使用 SSE/AVX 获取存储在 __m256d 中的值的总和

c# - C# 中的 Java Integer.highestOneBit

c++ - 将 1 到 32 位数字附加到 char 缓冲区

assembly - MUL 在不应该设置 OF 时设置了 OF

c - 如何取__m256的高音部分

c++ - 内存中的 DLL 大小和硬盘上的大小

mysql - 在 MySQL 中生成海量数据集报告的最有效方法

java - 位运算符在 Java 中究竟是如何工作的?

c - 在 Win32 上使用 GCC 向程序集符号添加前导下划线?

c - mmap 相关的段错误