c++ - Clang内置矩阵和 vector 扩展: efficient matrix-vector multiplication

标签 c++ clang vectorization simd clang-extensions

我正在编写一个小型图形 3D 应用程序,以了解 Clang vector 和矩阵扩展 ( matrices still seem to be developed if I read the right versions of the doc )。

我不确定如何使用这些类型编写最有效的矩阵 vector 乘法代码。使用:

typedef float float4 __attribute__((ext_vector_type(4)));
typedef float m4x4 __attribute__((matrix_type(4, 4)));

文档说(关于访问矩阵元素的索引):

The first specifies the number of rows, and the second specifies the number of columns.

     Column
        |
        v
Row->| M00 M01 M02 M03 |
     | M10 M11 M12 M13 |
     | M20 M21 M22 X23 |
     | M30 M31 M32 M33 |

所以我知道执行 m[2][3] (其中 m 是 m4x4),会给我在上面的矩阵中记下 X 的元素。

然后(关于元素在内存中的布局方式):

The elements of a value of a matrix type are laid out in column-major order without padding.

因此,我从这篇文章中得知,如果我可以查看元素在内存中存储的方式,我会得到:

M00 M10 M20 M30 - M01 M11 M21 M31 - M02 M12 M22 M32 - M03 M13 X23 M33 

到目前为止我做对了吗?

我们访问矩阵元素的顺序重要吗? (我这样做对吗?)

然后我假设,如果我想提高 mat-float4 乘法的效率,我需要按照元素在内存中的布局方式访问它们:

m4x3 m;
float4 v = {0.2, 0.3, 0.4, 1};
float4 res = {
    v.x * m[0][0] + v.y * m[1][0] + v.z * m[2][0] + v.w * m[3][0],
    v.x * m[0][1] + v.y * m[1][1] + v.z * m[2][1] + v.w * m[3][1],
    v.x * m[0][2] + v.y * m[1][2] + v.z * m[2][2] + v.w * m[3][2],
    1 // ignore w element for now
}

当然,我可以使用 __builtin_matrix_column_major_load 之类的东西在 m[0][0]、m[0][1]、... 中加载正确的值。 .

我是否把事情过于复杂化了,或者这里的顺序应该重要吗?上面的等式实际上优于:

float4 res = {
    v.x * m[0][0] + v.y * m[0][1] + v.z * m[0][2] + v.w * m[0][3],
    v.x * m[1][0] + v.y * m[1][1] + v.z * m[1][2] + v.w * m[1][3],
    v.x * m[2][0] + v.y * m[2][1] + v.z * m[2][2] + v.w * m[2][3],
    1 // ignore w element for now
}

(假设我在调用 __builtin_matrix_column_major_load 之前已经转置了元素。

有更好的方法吗?

现在我知道这些类型目前正在开发中。但我知道这些类型的全部意义在于利用 SIMD 指令。如果我这样做:

float4 a = {...};
float4 b = {...};
float4 c = a + b;

然后添加 a 的 4 个 float 分别为 b 的 4 个 float 发生在一个周期内?那么关于 mat-float4 乘法,因为我在代码中单独调用 float4 和 m4x4 的元素,所以在这种特殊情况下我似乎不会利用任何优化?

所以我的第二个问题:有更好的方法吗?

  • 我应该将矩阵 vector 保留为 4 个 float4 并进行 float4 * float4 乘法吗?
  • 我看到了这篇文章Matrix-Vector and Matrix-Matrix multiplication using SSE给出了如何使用 SIMD 指令实现 mat vector 乘法的示例。 这似乎可以将矩阵的元素堆叠成 __m128并使用这些来获取矩阵元素乘以 vector 的元素,并使用附加的 SIMD 指令,例如 _mm_add_psmm_mul_ps .
  • 我应该等待这个开发更加成熟吗?

如有任何反馈或建议,我们将不胜感激。我这样做是为了了解这些新的内置类型的练习。

最佳答案

如果有人现在发现这个:

typedef float float4 __attribute__((ext_vector_type(4)));
typedef float float4x4 __attribute__((matrix_type(4, 4)));

float4 mulmv4(float4x4 mat, float4 vec) {
    typedef float float4x1 __attribute__((matrix_type(4, 1)));
    float4 dst;
    float4x1 col = __builtin_matrix_column_major_load((float *)&vec, 4, 1, 4);
    __builtin_matrix_column_major_store(mat * col, (float *)&dst, 4);
    return dst;
}

转换为“矩阵”列并定义乘积。这确实应该是内置的,尽管正如您所说,Clang matrix_types 尚未完成。

顺便说一句:您可以将相同的概念应用于 ext_vector_types 的点积,因为(AFAIK)它也不是内置的。 Dot 会将 float1x4 乘以 float4x1(按该顺序)。

关于c++ - Clang内置矩阵和 vector 扩展: efficient matrix-vector multiplication,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72859045/

相关文章:

objective-c - 如何在 Xcode 中找到构建日志中不存在的 Clang 警告标志

python - 如何在 python 中向量化一组项目

c# - 如何在 C++ 中验证 Validate NCName

c++ - 英特尔 TBB 内存分配器的性能?

具有多个参数错误的 C++ 宏和模板

c - 如何使用 clang 在 OS X 上使用 c11 标准库进行编译?

xcode - Xcode中的静音错误

python - 如何加速分析 NumPy 代码 - 矢量化,Numba?

matlab - MATLAB 中的均值滤波器没有循环或信号处理工具箱

c++ - cin 中的冗余输入