我正在尝试使用 GNAT GCC 编译器在 Ada 2012 中为 AVX2 编写一个库。 我目前定义了一个数据类型 Vec_256_Unsigned_32,如下所示:
type Vec_256_Unsigned_32 is array (0..7) of Unsigned_32;
pragma Pack(Vec_256_Unsigned_32);
请注意,我已根据 immintrin.h
的 _mm256_load_si256
内在函数的英特尔文档中指示的 32 字节边界对齐数组。
我想实现一个操作,使用 AVX2 将这些数组中的两个相加。函数原型(prototype)如下。
function Vec_256_Unsigned_32_add(a, b: Vec_256_Unsigned_32) return Vec_256_Unsigned_32;
我实现这个功能的想法是分三步完成。
- 使用
_mm256_load_si256
将 a 和 b 加载到局部变量中。 - 使用
_mm256_add_epi32
执行加法运算。 - 使用
_mm256_store_si256
将结果转换回Vec_256_Unsigned_32
类型。
我感到困惑的地方是我将如何在 Ada 中创建 __m256i 数据类型来保存中间结果。有人可以对此有所了解吗?此外,如果您发现我的方法有任何问题,我们将不胜感激。
我在 GCC 中找到了 __m256i 的定义(位于 gcc/gcc/config/i386/avxintrin.h)。
typedef long long __m256i __attribute__ ((__vector_size__ (32), __may_alias__));
但是,这里是我卡住的地方,因为我不确定如何将其转换为 Ada 代码。
我发现 __vector_size__
属性已记录 here .
最佳答案
您需要做的第一件事是学习 Ada,因为您的 Ada 声明中有 2/3 是无效的。 Pragma Pack 只有一个参数(GNAT 没有一个有两个参数的依赖于实现的版本),在 Ada 12 中你通常应该使用 aspect 而不是 pragma。对齐方式另行规定。 Ada 没有“函数原型(prototype)”。您的加法操作的函数声明应该是
function "+" (Left : in Vec_256_Unsigned_32; Right : in Vec_256_Unsigned_32) return Vec_256_Unsigned_32;
Ada 具有用于封装和命名空间控制的运算符重载和包,因此您不需要像在缺乏这些基本功能的语言中那样对所有内容都使用前缀。
IIUC,__m256i的C定义定义了一个long long
的数组,占32字节。由于 Interfaces.C 没有为 long long
定义等效项,因此 Ada 等效项取决于 long long
的大小。如果它是 64 位,那么它相当于 Interfaces.Integer_64,即 8 个字节,所以 Ada 相当于
type M256i is array (1 .. 4) of Interfaces.Integer_64 with Convention => C;
(传递给 C 子程序的任何内容都应在 Interfaces.C 或其子程序中定义,或使用约定 C 声明。)
由于 M256i 和 Vec_256_Unsigned_32 都是 32 字节,您可以使用 Ada.Unchecked_Conversion 的实例在它们之间进行转换。
关于simd - 我将如何在 Ada 中定义 __m256i 数据类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/74821214/