You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在AVX/AVX2中实现Pair-wise与Component-wise内存布局转换?

AVX/AVX2下Double-Double内存布局双向转换实现

问题背景

我正在为AVX/AVX2编写一个double-double算术库,遇到的问题是非SIMD版本与SIMD版本采用不同的内存布局:

两种布局定义

// Pair-wise 布局:内存中按{hi, lo}对连续存储,顺序为{x0,y0}, {x1,y1}, {x2,y2}, {x3,y3}
struct Float64x2 { 
    double hi;
    double lo;
};

// Component-wise 布局:所有hi分量和lo分量分别打包存储,顺序为{x0,x1,x2,x3}, {y0,y1,y2,y3}
struct __m256dx2 { 
    __m256d hi; // 存储4个hi分量:x0, x1, x2, x3
    __m256d lo; // 存储4个lo分量:y0, y1, y2, y3
};

需要实现两种布局的双向转换:从Pair-wise加载转换为Component-wise,以及从Component-wise存储转换为Pair-wise。


转换实现代码

1. Pair-wise → Component-wise(加载转换)

该函数从Pair-wise布局的内存中加载数据,并转换为Component-wise的__m256dx2结构:

#include <immintrin.h>

struct __m256dx2 { 
    __m256d hi;
    __m256d lo;
};

__m256dx2 _mm256x2_loadu_pdx2(const double* mem_addr) {
    // 加载8个double到两个256位寄存器
    __m256d vec0 = _mm256_loadu_pd(mem_addr);       // [x0, y0, x1, y1]
    __m256d vec1 = _mm256_loadu_pd(mem_addr + 4);   // [x2, y2, x3, y3]

    // 提取所有hi分量的临时结果:[x0, x2, x1, x3]
    __m256d hi_temp = _mm256_unpacklo_pd(vec0, vec1);
    // 提取所有lo分量的临时结果:[y0, y2, y1, y3]
    __m256d lo_temp = _mm256_unpackhi_pd(vec0, vec1);

    // 重排hi分量顺序为[x0, x1, x2, x3]
    __m256d hi = _mm256_permute4x64_pd(hi_temp, 0x27);
    // 重排lo分量顺序为[y0, y1, y2, y3]
    __m256d lo = _mm256_permute4x64_pd(lo_temp, 0x27);

    __m256dx2 result;
    result.hi = hi;
    result.lo = lo;
    return result;
}

指令说明

  • _mm256_unpacklo_pd:从两个输入寄存器的低128位段中,分别取每个double对的第0个元素,交叉组合成新的寄存器。
  • _mm256_unpackhi_pd:从两个输入寄存器的低128位段中,分别取每个double对的第1个元素,交叉组合成新的寄存器。
  • _mm256_permute4x64_pd:对256位寄存器中的4个double元素进行任意重排,0x27的二进制是00100111,对应将临时结果的顺序调整为目标顺序。

2. Component-wise → Pair-wise(存储转换)

该函数将Component-wise的__m256dx2结构转换为Pair-wise布局并存储到内存:

void _mm256x2_storeu_pdx2(double* mem_addr, __m256dx2 val) {
    __m256d hi = val.hi; // [x0, x1, x2, x3]
    __m256d lo = val.lo; // [y0, y1, y2, y3]

    // 交叉组合得到Pair-wise布局的寄存器
    __m256d vec0 = _mm256_unpacklo_pd(hi, lo); // [x0, y0, x1, y1]
    __m256d vec1 = _mm256_unpackhi_pd(hi, lo); // [x2, y2, x3, y3]

    // 存储到内存
    _mm256_storeu_pd(mem_addr, vec0);
    _mm256_storeu_pd(mem_addr + 4, vec1);
}

指令说明

  • _mm256_unpacklo_pd:将hi的低两个元素与lo的低两个元素交叉,组成{x0,y0}, {x1,y1}的布局。
  • _mm256_unpackhi_pd:将hi的高两个元素与lo的高两个元素交叉,组成{x2,y2}, {x3,y3}的布局。

内容的提问来源于stack exchange,提问作者Vortex 2728182818

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 04:47:11