727 字
4 分钟
C/C++中restrict关键词的用法
在阅读 Nvidia 的技术博客的过程中,发现了这么一段函数:
void saxpy(int n, float a, float * restrict x, float * restrict y)
{
for (int i = 0; i < n; ++i)
y[i] = a*x[i] + y[i];
}
此前没有见过restrict
这种关键词的写法,于是去查了一下,发现这个关键词主要是对编译器生成的代码做优化的,假设我们有这样的一段函数:
void func(int * sum, int * num1, int * num2)
{
*sum += *num1;
*sum += *num2;
}
在 m2 芯片搭载的 macos 操作系统,使用 clang 19.1.7 编译器的情况下,启用-O3
编译优化选项,并去除一些无关的符号后,得到的汇编指令如下:
ldr w8, [x1] # num1的值加载到w8寄存器
ldr w9, [x0] # sum的值加载到w9寄存器
add w8, w9, w8 # w8与w9寄存器的值相加并将结果放入w8寄存器
str w8, [x0] # w8的值存入sum指针指向的地址
ldr w9, [x2] # num2的值加载到w9寄存器
add w8, w9, w8
str w8, [x0] # w8的值存入sum指针指向的地址
可以看到,编译器生成的代码,在执行源代码*sum += *num2
之前执行了str w8, [x0]
指令,这是因为在编译器,我们无法得知sum
与num2
是否指向的是同一块内存区域,当这两个指针指向的是同一区域的时候,出于正确性的考虑,我们就需要在加载num2
的值之前将寄存器的值写回对应的内存区域。而如果我们已经确切的知道sum
和num2
指向的是不同的内存区域,我们就可以通过restrict
关键词来显式地告诉编译器这件事,从而让编译器做更多的优化,将源代码改为如下:
void func(int * restrict sum, int * num1, int * restrict num2)
{
*sum += *num1;
*sum += *num2;
}
重新编译,得到生成的汇编指令:
ldr w8, [x1]
ldr w9, [x0]
ldr w10, [x2]
add w8, w9, w8
add w8, w10, w8
str w8, [x0]
此时可以看到,编译器生成的汇编指令相较于此前减少了一条,且在指令执行的过程中无需等待str
写回操作的完成,从而提升了代码的执行效率。在这里,restrict
关键词的作用就是告诉编译器,该指针指向的内存地址没有被其他指针所指,因此可以更为激进地去优化代码,相当于是程序员人为保证了这件事情,而如果用了restrict
但实际上存在多个指针指向同一块内存区域,就可能产生未定义行为。
在c++
中同样支持了类似于restrict
的关键词:GCC
与Clang
编译器支持__restrict__
以及__restrict
关键词,它们的使用方式与c
中restrict
关键词一致。
C/C++中restrict关键词的用法
https://0130w.github.io/posts/computer/cpp_restrict_keyword_usage/