为什么不强制使用 __restrict__ 修饰符?
Why is the __restrict__ modifier not enforced?
如果函数参数被注释 const int &x
并且我尝试在函数体中执行 x++
,我会收到修改只读引用的编译时错误。但是如果我像这样使用 __restrict__
修饰符:
void foo(int & __restrict__ a, int & __restrict__ b) {
if (a == 1)
b = 2;
if (a == 2)
b = 3;
}
int main() {
int x = 1;
foo(x, x); // should be illegal?
cout << x;
}
...我没有收到编译时错误。如果我 运行 未优化此代码,则输出为 3
,但如果我 运行 使用 -O1
或更高,则输出为 2
。检测 x
被传递两次似乎很简单,也很容易被禁止。为什么 C++ 可以防止 const
的错误使用,但不能防止 __restrict__
的错误使用?
在非常普遍的情况下,不可能在编译时对其进行诊断。正如一个微不足道的反例,请考虑:
void foo(int* __restrict__ a, int * __restrict__ b);
int x;
int y;
std::cin >> x >> y;
int* a = (x%2) ? &x : &y;
int* b = (y%2) ? &x : &y;
foo(a,b);
编译器无法知道 a
和 b
是否指向同一个 int
。实际上,如果编译器可以进行这样的分析,就不需要 __restrict__
限定符,因为这样编译器就可以自行判断两个指针是否用于访问同一内存。
一般而言,检测 restrict
违规并不容易。假设你有一个函数
void bar(int* p1, int* p2) {
foo(*p1, *p2);
}
编译器在这种情况下应该做什么?
在某些情况下(如在您的示例中),restrict
违规可以被某些编译器检测到。例如,带有 -Wrestrict
的 GCC 会产生警告:
warning: passing argument 1 to restrict-qualified parameter aliases with argument 2
GCC documentation 在 -Wrestrict
上读取:
Warn when an object referenced by a restrict
-qualified parameter (or, in C++, a __restrict
-qualified parameter) is aliased by another argument, or when copies between such objects overlap.
您可以使用 -Werror=restrict
选项将此警告转换为错误。
您正在向后看 __restrict__
。
__restrict__
是一个实现扩展,程序员可以使用它来发出 意图 信号,以最大限度地提高生成的代码质量和性能 ("optimisations")。
这不是检查,也不是对程序的附加约束。
它不是类型系统的一部分,所以它不是函数类型的一部分,所以它不能在调用点强制执行(通常)。
它就像其他一些扩展(例如 __builtin_unreachable
),你 用来告诉编译器一些事情。
在这种情况下,你告诉它 "I am not referring to the pointee via any other pointer"。
你不是在问 "please stop me from referring to the pointee via any other pointer"。
C 和 C++ 编译器已经在可以执行的地方执行了强大的 "aliasing" 检查。 __restrict__
关键字是 you 告诉 it "I am sure about this" 的一种方式,以防自动别名检测无法工作(例如,由于翻译单元边界)。由于自动别名检测不起作用,因此无法强制执行 __restrict__
。
而且,即使可以,那也与修饰符的目的相反。
如果函数参数被注释 const int &x
并且我尝试在函数体中执行 x++
,我会收到修改只读引用的编译时错误。但是如果我像这样使用 __restrict__
修饰符:
void foo(int & __restrict__ a, int & __restrict__ b) {
if (a == 1)
b = 2;
if (a == 2)
b = 3;
}
int main() {
int x = 1;
foo(x, x); // should be illegal?
cout << x;
}
...我没有收到编译时错误。如果我 运行 未优化此代码,则输出为 3
,但如果我 运行 使用 -O1
或更高,则输出为 2
。检测 x
被传递两次似乎很简单,也很容易被禁止。为什么 C++ 可以防止 const
的错误使用,但不能防止 __restrict__
的错误使用?
在非常普遍的情况下,不可能在编译时对其进行诊断。正如一个微不足道的反例,请考虑:
void foo(int* __restrict__ a, int * __restrict__ b);
int x;
int y;
std::cin >> x >> y;
int* a = (x%2) ? &x : &y;
int* b = (y%2) ? &x : &y;
foo(a,b);
编译器无法知道 a
和 b
是否指向同一个 int
。实际上,如果编译器可以进行这样的分析,就不需要 __restrict__
限定符,因为这样编译器就可以自行判断两个指针是否用于访问同一内存。
一般而言,检测 restrict
违规并不容易。假设你有一个函数
void bar(int* p1, int* p2) {
foo(*p1, *p2);
}
编译器在这种情况下应该做什么?
在某些情况下(如在您的示例中),restrict
违规可以被某些编译器检测到。例如,带有 -Wrestrict
的 GCC 会产生警告:
warning: passing argument 1 to restrict-qualified parameter aliases with argument 2
GCC documentation 在 -Wrestrict
上读取:
Warn when an object referenced by a
restrict
-qualified parameter (or, in C++, a__restrict
-qualified parameter) is aliased by another argument, or when copies between such objects overlap.
您可以使用 -Werror=restrict
选项将此警告转换为错误。
您正在向后看 __restrict__
。
__restrict__
是一个实现扩展,程序员可以使用它来发出 意图 信号,以最大限度地提高生成的代码质量和性能 ("optimisations")。
这不是检查,也不是对程序的附加约束。
它不是类型系统的一部分,所以它不是函数类型的一部分,所以它不能在调用点强制执行(通常)。
它就像其他一些扩展(例如 __builtin_unreachable
),你 用来告诉编译器一些事情。
在这种情况下,你告诉它 "I am not referring to the pointee via any other pointer"。
你不是在问 "please stop me from referring to the pointee via any other pointer"。
C 和 C++ 编译器已经在可以执行的地方执行了强大的 "aliasing" 检查。 __restrict__
关键字是 you 告诉 it "I am sure about this" 的一种方式,以防自动别名检测无法工作(例如,由于翻译单元边界)。由于自动别名检测不起作用,因此无法强制执行 __restrict__
。
而且,即使可以,那也与修饰符的目的相反。