如何在不修改函数声明的前提下将非restrict指针转换为restrict指针?
如何在不修改函数声明的前提下将非restrict指针转换为restrict指针?
先给你看个很有代表性的例子,下面这个简单的循环函数:
void foo(int *A, int *B, int *N) { for (int k = 0; k < *N; k++) A[k] += B[k]; }
编译器没法对这个循环做向量化优化,因为它会默认假设指针A和N可能存在别名(alias)——也就是这两个指针指向同一块内存区域。如果给参数N加上__restrict关键字,就能解除这个假设,让编译器放心做向量化了,比如这样:
void foo(int *A, int *B, int *__restrict N) { for (int k = 0; k < *N; k++) A[k] += B[k]; }
这个版本编译后会生成类似这样的向量化汇编代码:
.LBB0_9: ldp q0, q3, [x11, #-16] subs x12, x12, #8 ldp q1, q2, [x10, #-16] add x10, x10, #32 add v0.4s, v0.4s, v1.4s add v1.4s, v3.4s, v2.4s stp q0, q1, [x11, #-16] add x11, x11, #32 b.ne .LBB0_9
这显然是我们想要的高效代码,但问题来了:我不想修改函数的声明,只想在函数内部把N转换成一个带restrict属性的指针,比如像下面这样尝试:
void foo(int *A, int *B, int *N) { int *__restrict p = N; for (int k = 0; k < *p; k++) A[k] += B[k]; }
可惜这么写根本没用,编译器还是不会做向量化优化。那有没有什么办法能实现这个需求呢?
我想这么做的原因是,我希望能给代码做“版本分支”——不用在函数声明里加__restrict,而是在运行时判断指针是否存在别名,再选择对应的优化分支,比如像下面这样的逻辑:
// 用来判断X和Y是否不存在别名的辅助函数 bool no_alias(int* X, int *Y); void foo(int *A, int *B, int *N) { if (no_alias(A,N)) { // 假设我们能在运行时判断A和N没有别名 int *__restrict p = N; for (int k = 0; k < *p; k++) A[k] += B[k]; } else { for (int k = 0; k < *N; k++) A[k] += B[k]; } }
备注:内容来源于stack exchange,提问作者A. K.
相关产品推荐
相关产品推荐

