【问题标题】:SIMD and difference between packed and scalar double precisionSIMD 和压缩和标量双精度之间的区别
【发布时间】:2013-04-19 13:53:19
【问题描述】:

在实现 SIMD 支持时,我正在阅读 Intel 的内在函数指南。我有一些困惑,我的问题如下。

  1. __m128 _mm_cmpeq_ps (__m128 a, __m128 b) 文档说它用于比较压缩单精度浮点数。 “打包”是什么意思?我是否需要以某种方式打包浮点值才能使用它们?

  2. 对于双精度,有像 _mm_cmpeq_sd 这样的内在函数,这意味着比较“较低”的双精度浮点元素。低和高双精度元素是什么意思?我可以使用它们来比较 C++ double 类型元素的向量吗?还是我需要在比较它们之前以某种方式处理它们?

【问题讨论】:

    标签: c++ x86 sse simd intrinsics


    【解决方案1】:

    在 SSE 中,128 位寄存器可以表示为 4 个 32 位元素或 2 个 64 位元素。

    SSE 定义了两种类型的操作;标量和打包。标量运算仅对最不重要的数据元素(位 0~31 或 0~63)进行运算,打包运算并行计算所有元素。

    _mm_cmpeq_sd 设计用于处理双精度(64 位)浮点元素,并且只会比较两个操作数(标量)的最低有效数据元素(前 64 位)。

    _mm_cmpeq_pd 也设计用于处理双精度(64 位)浮点元素,但会并行(打包)比较每两组 64 位。

    _mm_cmpeq_ss 设计用于处理单精度(32 位)浮点元素,并且只会比较两个操作数(标量)的最低有效数据元素(前 32 位)。

    _mm_cmpeq_ps 设计用于处理单精度(32 位)浮点元素,并将并行(打包)比较每组 32 位。

    如果您使用 32 位浮点数,您可以将浮点数打包成四组以利用 128 位空间。这样,_mm_cmpeq_ps 就可以并行进行 4 次比较。

    如果您使用 64 位双精度,您可以成对打包双精度以利用 128 位空间。这样,_mm_cmpeq_pd 就可以并行进行 2 次比较。

    如果您只想一次比较,您可以使用_mm_cmpeq_sd 比较两个 64 位双精度或 _mm_cmpeq_ss 比较两个 32 位浮点数

    请注意,_mm_cmpeq_sd_mm_cmpeq_pd 是 SSE2,而 _mm_cmpeq_ss_mm_cmpeq_ps 是 SSE。

    【讨论】:

    • 这个答案基本上没问题,除了“_mm_cmpeq_sd 只会比较最低有效的数据元素(前 32 位)”。 _mm_cmpeq_sd 设计用于doubles(因此命令名称中的字母d),因此需要更正:“_mm_cmpeq_sd 将仅比较最低有效数据元素(前 64 位)” .类似的误解是下一段(只有 2 个双精度值可以放入 128 位长的寄存器,并且函数的名称应该以字母“d”结尾)。
    • @zkoza 是的,double 和 float 操作之间存在混淆,感谢您指出。我在上次编辑中修复了它,并添加了所有四个标量/打包和单/双操作以避免任何混淆。
    【解决方案2】:

    在这种情况下,“打包”是指“将几个相同类型的东西放在一个块中” - 所以“打包单精度浮点数”是指存储为 128 位值的 4 * 32 位浮点数。

    您需要使用各种PACK* 指令将每个值“打包”到寄存器中,或者将数据已经“打包”在内存中,例如4 个浮点值的(倍数)数组[适当对齐]。

    标量表示寄存器低位 n 中的“一个值”(例如,double 将是 128 位 SSE 寄存器的低 64 位)。

    【讨论】:

    • 如果您在 XMM regs 中有多个标量浮点数来洗牌到一个寄存器中,您实际上想要使用洗牌unpcklpspack 类似 packssdw 的指令正在缩小整数运算。 (因此,用零解包有点类似于 pack(扩大整数元素),这可能是这种奇怪命名约定的来源。请记住,英特尔的整数 SIMD (MMX) 在 fp @987654327 之前就存在@SSE1 和pdSSE2。)
    猜你喜欢
    • 2012-08-06
    • 2015-09-01
    • 2023-03-18
    • 2016-05-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多