把GCC/LLVM的 C2y预处理器向量扩展与数组混合使用,并在GCC中提供对LLVM __builtin_vectorelements的替代方案
在GCC中,是否有 __builtin_vectorelements 的替代方案?
用其他方案替换GCC的 vec_countof 可能会有帮助。
array.h - C预处理器 arr/vec(T,N) 数据类型
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#include <stdalign.h>
#include <sys/param.h>
#if defined(__clang__)
#pragma clang diagnostic ignored "-Wgnu-alignof-expression"
#endif
#ifdef _MSC_VER
#define INLINE __force_inline __flatten __declspec(nothrow) __declspec(noalias) inline
#else
#define INLINE __attribute__((always_inline,flatten,nothrow,const)) inline
#endif
#define BITOP_RUP01__(x) ( (x) | ( (x) >> 1))
#define BITOP_RUP02__(x) (BITOP_RUP01__(x) | (BITOP_RUP01__(x) >> 2))
#define BITOP_RUP04__(x) (BITOP_RUP02__(x) | (BITOP_RUP02__(x) >> 4))
#define BITOP_RUP08__(x) (BITOP_RUP04__(x) | (BITOP_RUP04__(x) >> 8))
#define BITOP_RUP16__(x) (BITOP_RUP08__(x) | (BITOP_RUP08__(x) >> 16))
#define bitceil(x) (const uint32_t)(BITOP_RUP16__(((uint32_t)(x)) - 1) + 1)
/* arr(T,N) aligned array type */
#define arr(T,N) alignas((N == bitceil(N) ? N : 1) * alignof(T)) typeof(T[N])
#define countof(a) sizeof((a))/sizeof(typeof((a)[0]))
#define isarray(a) __builtin_choose_expr(__builtin_types_compatible_p(typeof((a)[0]) [], typeof((a))), true, false)
#define rc_arr(src,n) (*(arr(typeof((src)[0]),n)*)&src)
#define rc_vec(src,n) (*(vec(typeof((src)[0]),n)*)&src)
/* vec(T,N) for LLVM SIMD Vector Extension */
#if defined(__clang__)
#define vec(T,N) typeof(T __attribute__((ext_vector_type(N))))
#define vec_countof(a) __builtin_vectorelements(rc_vec(a,countof(a)))
#define isvector(a) !isarray(a) && \
__builtin_choose_expr( \
bitceil(vec_countof(a)) == countof(a),true,false)
/* vec(T,N) for GCC SIMD Vector Extension */
#elif defined(__GNUC__)
#define vec(T,N) typeof(T __attribute__((vector_size(bitceil(N) * alignof(T)))))
#define vec_countof(a) countof(a)
#define isvector(a) !isarray(a) && \
_Generic(__builtin_convertvector(rc_vec(a,vec_countof(a)), \
vec(float,bitceil(vec_countof(a)))), \
vec(float,bitceil(vec_countof(a))): true, \
default: false)
#endif
下面的点积/叉积示例展示了如何使用arr(T,N) 和vec(T,N) 来支持任意类型和向量长度(现在还没有霍奇对偶算子)。
dotcross.c - 使用 arr/vec(T,N) 的点积/叉积
#include "array.h"
#define dot(a,b,t,n,i) \
({ \
t _dst = (t)i; \
static_assert((isarray(a) || isvector(a)),"ERROR: dot - a is not of array or vector type!"); \
static_assert((isarray(b) || isvector(b)),"ERROR: dot - b is not of array or vector type!"); \
size_t len = (size_t)llabs((ssize_t)n); \
len = MIN(MIN(!isarray(a) ? vec_countof(a) : countof(a), \
!isarray(b) ? vec_countof(b) : countof(b)), \
(ssize_t)n>0?len:0); \
_Pragma("omp simd reduction(+:_dst)") \
for(size_t j = 0; j < len; j++) \
_dst += (t)((a)[j]) * (t)((b)[j]); \
_dst; \
})
typedef float real;
#define dot3(a,b) dot(a,b,real,3,0)
#define dot4(a,b) dot(a,b,real,4,0)
#define perm3(a,x,y,z,t,n) (vec(t,n)){ (t)(a)[x], (t)(a)[y], (t)(a)[z] }
#define perm4(a,x,y,z,w,t,n) (vec(t,n)){ (t)(a)[x], (t)(a)[y], (t)(a)[z], (t)(a)[w] }
#define rc_cross3(a,b,t,n) perm3(a,1,2,0,t,n) * perm3(b,2,0,1,t,n) - perm3(a,2,0,1,t,n) * perm3(b,1,2,0,t,n)
#define cross3(a,b) rc_cross3(a,b,typeof((rc_vec(a,3) * rc_vec(b,3))[0]),3)
void usage(int argc, char** argv)
{
fprintf(stderr,"Usage: %s NUM NUM NUM NUM NUM NUM\n", argv[0]);
}
int main(int argc, char** argv)
{
if(argc < 7) { usage(argc,argv); exit(EXIT_FAILURE); }
vec(real,3) a = { (real)strtod(argv[1],NULL), (real)strtod(argv[2],NULL), (real)strtod(argv[3],NULL) };
arr(real,3) b = { (real)strtod(argv[4],NULL), (real)strtod(argv[5],NULL), (real)strtod(argv[6],NULL) };
vec(real,3) c = cross3(a,b);
vec(real,3) d = cross3(b,a);
printf("array vector vec_countof countof alignof sizeof\n");
printf("%5b %6b %11zu %7zu %7zu %6zu\n", isarray(a), isvector(a),vec_countof(a),countof(a), alignof(a), sizeof(a));
printf("%5b %6b %11zu %7zu %7zu %6zu\n", isarray(b), isvector(b),vec_countof(b),countof(b), alignof(b), sizeof(b));
puts("");
printf("dot3(a,b) = %+e\n", dot3(a,b));
printf("dot3(b,a) = %+e\n", dot3(b,a));
printf("cross3(a,b) = [%+e %+e %+e]\n", c[0],c[1],c[2]);
printf("cross3(b,a) = [%+e %+e %+e]\n", d[0],d[1],d[2]);
exit(EXIT_SUCCESS);
}
编译命令:
export CFLAGS="-march=native -mfpmath=<your simd> -ftree-vectorize -fopenmp -fopenmp-simd -O3 -std=<c|gnu>2y -I."
gcc $CFLAGS -o dotcross_gcc dotcross.c
clang $CFLAGS -o dotcross_clang dotcross.c
输出 - ./dotcross 1 0 0 0 1 0
array vector vec_countof countof alignof sizeof
0 1 4 4 16 16
1 0 3 3 4 12
dot3(a,b) = +0.000000e+00
dot3(b,a) = +0.000000e+00
cross3(a,b) = [+0.000000e+00 +0.000000e+00 +1.000000e+00]
cross3(b,a) = [+0.000000e+00 +0.000000e+00 -1.000000e+00]
解决方案
简短回答:没有直接对应GCC的 __builtin_vectorelements。
使用 sizeof(vec) / sizeof(vec[0]) 作为元素计数,或将其包装在一个宏中。若要实现通用处理,可将 _Generic 与 sizeof 结合,或依赖GCC的向量扩展(__attribute__((vector_size)))并手动计算长度。
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。