正如其他人所说,如果C ++ 14中没有任何意义,那么让我们考虑rdi GCC扩展,其功能与C99 restrict相同。
C99
rdi说两个指针不能指向重叠的内存区域。 最常见的用法是函数参数。
这限制了函数的调用方式,但允许更多的编译优化。
如果调用者未遵循rdi合同,则定义未定义的行为。
C99 N1256草案6.7.3 / 7“类型限定符”说:
restrict限定符(如寄存器存储类)的预期用途是促进优化,并且从构成符合程序的所有预处理转换单元中删除限定符的所有实例不会改变其含义(即,可观察行为)。
和6.7.3.1“限制的正式定义”给出了血淋淋的细节。
可能的优化
维基百科的例子很有启发性。
它清楚地显示了它如何允许保存一个汇编指令。
没有限制:
void f(int *a, int *b, int *x) {
*a += *x;
*b += *x;
}
伪装配:
load R1 ← *x ; Load the value of x pointer
load R2 ← *a ; Load the value of a pointer
add R2 += R1 ; Perform Addition
set R2 → *a ; Update the value of a pointer
; Similarly for b, note that x is loaded twice,
; because a may be equal to x.
load R1 ← *x
load R2 ← *b
add R2 += R1
set R2 → *b
有限制:
void fr(int *__restrict__ a, int *__restrict__ b, int *__restrict__ x);
伪装配:
load R1 ← *x
load R2 ← *a
add R2 += R1
set R2 → *a
; Note that x is not reloaded,
; because the compiler knows it is unchanged
; load R1 ← *x
load R2 ← *b
add R2 += R1
set R2 → *b
海湾合作委员会真的这样做吗?
rdi 4.8 Linux x86-64:
g++ -g -std=gnu++98 -O0 -c main.cpp
objdump -S main.o
与rdi,他们是一样的。
随着rdi:
void f(int *a, int *b, int *x) {
*a += *x;
0: 8b 02 mov (%rdx),%eax
2: 01 07 add %eax,(%rdi)
*b += *x;
4: 8b 02 mov (%rdx),%eax
6: 01 06 add %eax,(%rsi)
void fr(int *__restrict__ a, int *__restrict__ b, int *__restrict__ x) {
*a += *x;
10: 8b 02 mov (%rdx),%eax
12: 01 07 add %eax,(%rdi)
*b += *x;
14: 01 06 add %eax,(%rsi)
对于没有经验的人,调用约定是:
rdi =第一个参数
this =第二个参数
this =第三个参数
GCC输出甚至比wiki文章更清晰:4条指令vs 3条指令。
数组
到目前为止,我们有单指令节省,但如果指针表示要循环的数组,一个常见的用例,那么可以保存一堆指令,如supercat和michael所述。
考虑例如:
void f(char *restrict p1, char *restrict p2, size_t size) {
for (size_t i = 0; i < size; i++) {
p1[i] = 4;
p2[i] = 9;
}
}
由于this,智能编译器(或人工)可以优化它:
memset(p1, 4, size);
memset(p2, 9, size);
哪个可能更高效,因为它可能在一个体面的libc实现(如glibc)上进行程序集优化。在性能方面使用std :: memcpy()或std :: copy()是否更好?可能使用SIMD指令。
没有,限制,这种优化无法完成,例如, 考虑:
char p1[4];
char *p2 = &p1[1];
f(p1, p2, 3);
然后this版本:
p1 == {4, 4, 4, 9}
而this版本使:
p1 == {4, 9, 9, 9}
海湾合作委员会真的这样做吗?
GCC 5.2.1.Linux x86-64 Ubuntu 15.10:
gcc -g -std=c99 -O0 -c main.c
objdump -dr main.o
与this,两者是相同的。
随着this:
限制:
this
两个this按预期调用。
没有限制:没有stdlib调用,只是一个16迭代宽的循环展开,我不打算在这里重现:-)
我没有耐心对它们进行基准测试,但我相信限制版本会更快。
严格别名规则
this关键字仅影响兼容类型的指针(例如,两个int*),因为严格的别名规则表明,默认情况下别名不兼容类型是未定义的行为,因此编译器可以假设它不会发生并优化掉。
请参阅:什么是严格别名规则?
它适用于参考?
根据海湾合作委员会的文件,它确实:[https://gcc.gnu.org/onlinedocs/gcc-5.1.0/gcc/Restricted-Pointers.html],语法为:
int &__restrict__ rref
甚至有this成员函数的版本:
void T::fn () __restrict__