gpt4 book ai didi

c - 如何使用 GNU C vector 扩展从 double 组加载/存储到 double 组?

转载 作者:行者123 更新时间:2023-12-02 01:22:28 24 4
gpt4 key购买 nike

我正在使用GNU C Vector Extensions ,而不是英特尔的 _mm_* 内在函数。

我想做与英特尔的_m256_loadu_pd内在函数相同的事情。逐一赋值的速度很慢:gcc 生成的代码有 4 个加载指令,而不是一个 vmovupd(_m256_loadu_pd 确实生成)。

typedef double vector __attribute__((vector_size(4 * sizeof(double))));

int main(int argc, char **argv) {
double a[4] = {1.0, 2.0, 3.0, 4.0};
vector v;

/* I currently do this */
v[0] = a[0];
v[1] = a[1];
v[2] = a[2];
v[3] = a[3];
}

我想要这样的东西:

v = (vector)(a);

v = *((vector*)(a));

但都不起作用。第一个失败,并显示“无法将值转换为 vector ”,而第二个则导致段错误。

最佳答案

更新:我看到您正在使用 GNU C 的 native vector 语法,而不是 Intel 内在函数。您是否避免使用 Intel 内在函数来实现向非 x86 的移植? gcc 目前在编译使用比目标机器支持范围更广的 GNU C vector 的代码时表现不佳。 (您希望它只使用两个 128b vector 并分别对每个 vector 进行操作,但显然它比这更糟糕。)

无论如何,这个答案展示了如何使用 Intel x86 内在函数将数据加载到 GNU C vector 语法类型

<小时/>

首先,查看小于 -O2 的编译器输出如果您想了解什么可以编译成好的代码,那么这是浪费时间。您的main()将优化为 ret在-O2。

除此之外,一次为 vector 的元素分配一个元素而导致汇编错误也就不足为奇了。

<小时/>

旁白:普通人会将该类型称为 v4df (4 Double Float 的 vector )或其他东西,不是 vector ,这样他们在与 C++ 一起使用时就不会发疯 std::vector 。对于单精度,v8sf 。 IIRC,gcc 在内部使用类似这样的类型名称 __m256d .

在 x86 上,Intel 内在类型(如 __m256d )是在 GNU C vector 语法之上实现的(这就是为什么您可以在 GNU C 中执行 v1 * v2 而不是编写 _mm256_mul_pd(v1, v2) )。您可以从__m256d自由转换至v4df ,就像我在这里所做的那样。

我已经在函数中封装了执行此操作的两种合理方法,因此我们可以查看它们的汇编。请注意,我们没有从同一函数内定义的数组加载,因此编译器不会对其进行优化。

我把它们放在Godbolt compiler explorer上这样您就可以查看具有各种编译选项和编译器版本的 asm。

typedef double v4df __attribute__((vector_size(4 * sizeof(double))));

#include <immintrin.h>

// note the return types. gcc6.1 compiles with no warnings, even at -Wall -Wextra
v4df load_4_doubles_intel(const double *p) { return _mm256_loadu_pd(p); }
vmovupd ymm0, YMMWORD PTR [rdi] # tmp89,* p
ret

v4df avx_constant() { return _mm256_setr_pd( 1.0, 2.0, 3.0, 4.0 ); }
vmovapd ymm0, YMMWORD PTR .LC0[rip]
ret

如果参数为_mm_set*内在函数不是编译时常量,编译器将尽最大努力编写高效的代码,将所有元素放入单个 vector 中。通常最好这样做,而不是编写 C 来存储到 tmp 数组并从中加载,因为这并不总是最好的策略。 (多个窄存储转发到宽负载时的存储转发失败,除了通常的存储转发延迟之外,还需要额外约 10 个周期 (IIRC) 的延迟。如果您的 double 已经在寄存器中,通常最好只需将它们混在一起即可。)

<小时/>

另请参阅Is it possible to cast floats directly to __m128 if they are 16 byte alligned?用于将单个标量转换为 vector 的各种内在函数的列表。 tag wiki 有英特尔手册及其内在函数查找器的链接。

<小时/>

加载/存储不带 Intel 内在函数的 GNU C vector :

我不确定你“应该”如何做到这一点。 This Q&A建议将指针转换为要加载的内存,并使用像 typedef char __attribute__ ((vector_size (16),aligned (1))) unaligned_byte16; 这样的 vector 类型(请注意 aligned(1) 属性)。

您从 *(v4df *)a 得到一个段错误因为大概a未在 32 字节边界上对齐,但您使用的 vector 类型确实假设自然对齐。 (就像__m256d,如果您取消引用指向它的指针而不是使用加载/存储内在函数向编译器传达对齐信息。)

关于c - 如何使用 GNU C vector 扩展从 double 组加载/存储到 double 组?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39114159/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com