函数的restrict限定指针参数是否允许对调用者函数优化?
函数的restrict限定指针参数是让编译器对该函数做优化的有效手段:
int f(const int *restrict p) { int n=*p; printf("Debug\n"); return *p==n; }
开启-O3优化的Clang 17会直接返回1,不用重新读取*p或者执行比较操作。要是没有restrict限定,编译器就必须重新读取*p并做比较——因为printf是外部函数,编译器没法确定它会不会修改*p。实际上,如果p指向stdout的文件位置指示器,printf确实会修改它。
所以一般原则是:如果想让函数获得最大程度的优化,而且该函数会调用外部函数,给所有参数加restrict限定是有意义的。当然,这会给调用者加上严格限制,要求调用者不能用意外的别名指针调用这个函数。
现在有个更进一步的问题:restrict限定是否允许编译器对函数的调用者进行优化?
看这段代码:
int f(const int *restrict p); int caller(int *p) { int n=*p; f(p); return *p==n; }
从逻辑上看,restrict似乎应该能保证f不会修改*p,所以编译器可以跳过重新读取*p和比较的步骤,直接返回1。但实际测试里,Clang和GCC都没做这个优化。
我们要明确的是:编译器是否被允许做这种优化?(这主要是程序语义层面的问题,不是性能问题。)
答案:编译器被允许进行这种优化
根据C标准对restrict的定义,restrict限定的指针是其指向对象的唯一可达指针(在该指针的作用域内)。对于函数f的参数const int *restrict p,这意味着在f执行期间,所有对p指向对象的访问都必须通过p(或基于p的指针)进行。同时,因为p是const限定的,f本身不能通过p修改该对象;而restrict的约束又排除了其他别名指针修改该对象的可能——调用者必须保证这一点,否则就违反了标准规定的程序行为。
从语义上来说,编译器完全可以推断出调用f(p)不会修改*p,因此可以对caller函数进行优化,直接返回1。
Clang和GCC没做这个优化只是它们实现上的选择,并非C标准不允许。标准赋予了编译器进行这种优化的权利,只要优化后的程序行为符合标准规定的语义。
内容的提问来源于stack exchange,提问作者log65536

