Tie*_*ies 5 c gcc clang restrict-qualifier
我正在研究通过将 C99限制类型限定符添加到数组的类型参数来允许编译器进行的优化。
例如,考虑下面的函数f:
int f(int* restrict a[2]) {
*(a[0]) = 10;
*(a[1]) = 11;
return *(a[0]);
}
Run Code Online (Sandbox Code Playgroud)
它采用一个由指向整数的限制指针组成的二元素数组a作为参数。该函数存储10到对象a[0]指向和11对象a[1]指向。a[0]最后,它返回该对象指向的值。
因为指针a[0]和a[1]是限制限定的,所以我假设编译器有足够的信息来执行典型的优化,即不再次加载a[0],而是直接返回(因为如果程序已定义行为,则10写入a[1]不能更改对象指向a[0])。
因此,如果优化发生在“C 代码级别”,则该函数将变为:
int f(int* restrict a[2]) {
*(a[0]) = 10;
*(a[1]) = 11;
return 10;
}
Run Code Online (Sandbox Code Playgroud)
然而,GCC 和 Clang(我尝试了几个版本,其中最新的是 Godbolt)都没有执行此优化(当使用 -O3 编译时)。
GCC13.2 发出的 X86 程序集是
f:
mov rax, QWORD PTR [rdi]
mov rdx, QWORD PTR [rdi+8]
mov DWORD PTR [rax], 10
mov DWORD PTR [rdx], 11
mov eax, DWORD PTR [rax]
ret
Run Code Online (Sandbox Code Playgroud)
正如我们所看到的,执行了从寄存器的重新加载,[rax]而不是仅仅10移入eax。
一个类似的程序,其中指针作为单独的参数而不是指针数组传递,确实展示了两个编译器的预期优化:
int g(int* restrict p, int* restrict q) {
*p = 10;
*q = 11;
return *p;
}
Run Code Online (Sandbox Code Playgroud)
被编译成:
g:
mov DWORD PTR [rdi], 10
mov eax, 10
mov DWORD PTR [rsi], 11
ret
Run Code Online (Sandbox Code Playgroud)
我是否误解了限制限定指针作为数组的类型参数的语义,或者预期的优化对于上述编译器来说太难了?
无法完成此优化,并且您的第二个示例无效(因为忘记了一级间接)。
int f(int* restrict * restrict a) {
*(a[0]) = 10;
*(a[1]) = 11;
return *(a[0]);
}
//this function is to illustrate the issue
void foo(void)
{
int a;
int *b[2] = {&a,&a};
f(b);
}
Run Code Online (Sandbox Code Playgroud)
int g(int* restrict * restrict p, int* restrict * restrict q) {
**p = 10;
**q = 11;
return **p;
}
Run Code Online (Sandbox Code Playgroud)
这将生成优化的代码,因为您无法访问使用引用的对象*p而不*q违反您向编译器做出的承诺。
mov rax, QWORD PTR [rdi]
mov DWORD PTR [rax], 10
mov rax, QWORD PTR [rsi]
mov DWORD PTR [rax], 11
mov eax, 10
ret
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
190 次 |
| 最近记录: |