assembly - 在 double/simd 中构建 2^n

标签 assembly simd

我正在尝试使用 double 表示构建 2^n 。这个技巧是众所周知的

// tips to calculate 2^n using the exponent of the double IEEE representation
union ieee754{
    double d;
    uint32_t i[2];
};

// Converts an unsigned long long to a double
inline double uint642dp(uint64_t ll) {
  ieee754 tmp;
  tmp.ll=ll;
  return tmp.d;
}
-----------------------------------
// e^x = 2^n e^y, n = round(x/log(2)+0.5)

double x = 4.3; // start from there
double y = round(x/log(2)+0.5)
int n = (int)y; // convert in to double 
uint642dp(( ((uint64_t)n) +1023)<<52); // calculate 2^n fastly

如果 n = 4,则返回 16。

目前我正在寻找相同的,但用于 SIMD 计算。考虑到 SSE2 double,在 round 函数之后我将得到一个寄存器 sse2 __m128d v = (4.0, 3.0);形成这个寄存器如何计算 2^v ...我被阻止主要是由于将 __m128d 强制转换为 __m128i,它不存在(它仍然存在强制转换但它不移动位,只需更改寄存器 double 的“解释”/int)。

我不想将 simd 寄存器中的数据返回到普通寄存器中进行转换。它确实存在 SIMD 的提示,但我不知道。

请帮忙^_^'

最好,

最佳答案

您正在寻找的技巧实际上是_mm256_castsi256_pd内在函数,它允许您将SIMD整数数组转换为SIMD double 组。这仅用于 C/C++ 类型检查,不会转换为任何指令。

这里是执行此操作的代码片段(仅在某些指数范围内有效):

#include <immintrin.h>

__m256d pow2n (__m256i n)
{
    const __m256i bias = _mm256_set1_epi64x( 1023 );
    __m256i t = _mm256_add_epi64 (n, bias);
    t = _mm256_slli_epi64 (t, 52);
    return _mm256_castsi256_pd (t) ;
}

#include <cstdio>

int main ()
{
        __m256i rn = _mm256_set_epi64x( 7, 9, 4, 2 );
        __m256d pn = pow2n (rn) ;
        double v [4] ;
        _mm256_storeu_pd (v, pn) ;
        printf ("v = %lf %lf %lf %lf\n", v[0], v[1], v[2], v[3]) ;
        return 0 ;
}

pow2n 仅编译为 2 个 insn,as you can see on the Godbolt Compiler Explorer

输出是:

v = 4.000000 16.000000 512.000000 128.000000

这需要 AVX2,但 128 位版本只需要 SSE2。请注意,指数以 64 位整数形式提供。如果您有 32 位整数,请使用 _mm256_cvtepu32_epi64

如果您从 double 向量开始(如 OP),则使用 _mm256_cvtpd_epi32_mm256_cvtepu32_epi64。 (double -> int64 直接在 AVX-512 之前不可用)。

关于assembly - 在 double/simd 中构建 2^n,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19938973/

相关文章:

c - -masm 中的第一个 m 是什么意思?

assembly - `test` 指令是如何工作的?

c - MASM 和 C 跳转到函数

这个 C 循环可以进一步优化吗?

x86 - _mm_set_epi8- "set"是什么意思?

c++ - SSE 加载/存储内存事务

rust - 如何正确使用 std::arch::_mm_loadu_si128/_mm_storeu_si128

arrays - x86-64 汇编中的数组元素比较(AT&T 语法)

c - 包装函数的内联汇编器由于某种原因不起作用

c++ - 顶点分量的 AVX2 重心插值