【问题标题】:Fastest way to spread 4 bytes into 8 bytes (32bit -> 64bit)将 4 个字节扩展到 8 个字节(32 位 -> 64 位)的最快方法
【发布时间】:2021-01-05 16:43:59
【问题描述】:

假设您有一个 32 位无符号整数,其中字节的组织方式如下:a b c d。 以这种方式将这些字节扩展到 64 位无符号整数的最快方法是什么: 0 a 0 b 0 c 0 d?它适用于x86-64 架构。我想知道不使用特殊内在函数的最快方法,尽管这也很有趣。 (我说“最快”,但性能合理的紧凑型解决方案也不错)。

为需要上下文的人编辑。这似乎是一项非常简单的工作,只需移动一些字节,但它需要的指令比您想象的要多 (check this godbolt with optimizations)。因此,我只是想知道是否有人知道用更少的指令解决问题的方法。

【问题讨论】:

  • 可能只是位移然后将它们异或在一起
  • 您尝试过什么 - 请将您最好的代码编辑到您的问题中,并说明您认为它不是您需要的原因
  • 来自performance 标签:“有关测量或改进代码和应用程​​序效率的问题。”你还没有什么可以衡量或改进的。除非你有东西,否则任何东西最快的。闻起来像过早的优化。请出示您的代码
  • 这适用于 16 位到 32 位的传播:((x * 0x0101010101010101L & 0x8040201008040201L) * 0x0102040810204081L >> 49) & 0x5555。取自this thread
  • 选择你最喜欢的godbolt.org/z/3E7Gsa,但要考虑到在 x86_64 上,更少的指令并不一定意味着更快的执行时间。

标签: c++ c performance low-level-code


【解决方案1】:
uint64_t x = ...;
// 0 0 0 0 a b c d
x |= x << 16;
// 0 0 a b ? ? c d
x = x << 8 & 0x00ff000000ff0000 | x & 0x000000ff000000ff;
// 0 a 0 b 0 c 0 d

为了完整起见,现代 x86 处理器可以通过一条快速指令完成此操作:

x = _pdep_u64(x, 0xff00ff00ff00ff)

【讨论】:

  • 我喜欢!与我在问题中提供的神螺栓相比,更短并节省了 3 次操作。
  • 不会 _pdep_u64(x, 0xff00ff00ff00ff) 简单地传递指定位置的位吗?它具有 32 位输入和 32 位输出。我发现可以进行所请求的字节到字转换的唯一指令是各种形式的双关语。在 x64 上,我发现的唯一一个采用 __m256i 的高或低 __m128i 并将其分布在整个 __m256i 上。 32 位代码可能有 32 到 64 位版本,但我发现无法在 x64 代码中使用。
  • @SornelHaetir,任务是将位传递到指定的位置。相当于其他解决方案godbolt.org/z/7vq49n
【解决方案2】:

这样的?

_mm256_cvtepu8_epi16(eight_bit_numbers):获取一个由十六个 8 位数字组成的 128 位向量,并将其转换为一个由十六个 16 位有符号整数组成的 256 位向量。例如:

 __m128i value1 = _mm_setr_epi8(0x11, 0x22, 0x33, 0x44, 
    0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x00);
 __m256i value2 = _mm256_cvtepu8_epi16(value1);

或者对于 32 位 -> 64 位:

https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_cvtepu32_epi64

【讨论】:

    猜你喜欢
    • 2014-08-05
    • 1970-01-01
    • 2023-02-24
    • 2023-03-04
    • 2015-03-21
    • 1970-01-01
    • 2015-03-03
    • 1970-01-01
    相关资源
    最近更新 更多