不知道如何让 gcc/clang 相信我的指针不相交;就我所见,它看起来restrict只有在函数参数中指定时才会受到尊重,否则会被忽略。这是我的代码:
#if defined(_MSC_VER) || defined(__cplusplus)
#define restrict __restrict
#endif
struct s {
int sz;
int *a;
int *b;
};
struct s_r {
int sz;
int *restrict a;
int *restrict b;
};
void foo_dumb_struct(struct s *s, int c) {
int sz = s->sz;
for(int i = 0; i != sz; ++i) {
s->a[i] = s->b[0] + c;
}
}
void foo_restricted_arrays(int sz,
int *restrict a, int *restrict b,
int c) {
for(int i = 0; i != sz; ++i) {
a[i] = b[0] + c;
}
}
void foo_restricted_struct(struct s_r *s, int c) {
int sz = s->sz;
for(int i = 0; i != sz; ++i) {
s->a[i] = s->b[0] + c;
}
}
void foo_restricted_subcall(struct s *s, int c) {
foo_restricted_arrays(s->sz, s->a, s->b, c);
}
void foo_restricted_cast(struct s *s, int c) {
int sz = s->sz;
int *restrict a = s->a;
int *restrict b = s->b;
for(int i = 0; i != sz; ++i) {
a[i] = b[0] + c;
}
}
Run Code Online (Sandbox Code Playgroud)
Icc 对这段代码没问题,但是 gcc/clangb[0]在每次迭代时都会重新读取foo_restricted_struct和foo_restricted_cast,对于我可以用 Godbolt 测试的所有架构。任何时候在函数参数(包括嵌套函数或 C++ lambdas)中使用它都很好,并且会移除额外的负载。https://cellperformance.beyond3d.com/articles/2006/05/demystifying-the-restrict-keyword.html表明它实际上按我想要的方式工作,但我不确定他们的 gcc 不是为单元定制的具体来说。
我对restrict的使用是错误的,还是gcc/clang只对函数参数实现了restrict而没有别的?
据我所知,似乎
restrict只有在函数参数中指定时才会受到尊重
这种特征听起来像是您认为restrict资格承担着某种更积极地优化的义务。显然情况并非如此:
翻译者可以自由地忽略使用限制的任何或所有别名含义。
(C 标准,第 6.7.3.1/6 段)
我确实承认,在某些情况下利用restrict资格执行额外优化的编译器在其他类似情况下不会执行相同的操作,这有点令人惊讶,但这并不意味着代码或编译器处于任何情况错了。(但请记住埃里克对限制资格结构成员的观察)。然而,此外,所提供的示例可能并不像您想象的那样彼此相似。
我对restrict的使用是否错误,或者gcc/clang只对函数参数实现了restrict而没有其他?
尽管该标准定义了restrict限定块范围变量的语义,但它们实际上并没有多大用处。限制限定是将依赖性分析的部分责任从编译器转移给程序员的一种方法,但程序员没有比编译器在示例等情况下已经拥有的信息更多的信息来承担foo_restricted_cast()。我想说的是,是的,您的用法(语义上)是错误的,因为您没有合理的基础来隐式保证局部变量a和b不会彼此别名。从这个角度来看,我认为 GCC 和 Clang 的行为是谨慎和适当的,而 ICC 则有些鲁莽。
至于restrict-qualified 结构成员,我不同意其他答案的断言,即没有为它们定义语义。确实,结构成员的标识符不是“普通标识符”,但标准语义定义的措辞restrict似乎是专门设计的,目的是通过包含结构成员的结构对象的普通标识符的声明来覆盖结构成员。语言当然可以这样解读,如果不是这样的话,就会比平常更令人担忧。
因此,我认为 的情况foo_restricted_struct()具有明确定义的语义,此外,icc利用参数结构成员的限定所传达的非别名断言是合理的restrict,就像它们是直接函数参数一样。我不可能说出原因gcc,也不Clang利用正在进行的优化选项,但同样,他们没有义务这样做。
另一方面,foo_restricted_subcall()表现出与 中的语义问题类似的语义问题foo_restricted_cast()。我认为,出于这个原因,GCC 和/或 Clang 可能会避免更积极地优化foo_restricted_struct(),这foo_restricted_subcall()会使用语义上有问题的参数进行调用。不过,这些编译器可能只是没有执行足够深入的分析来发现这种情况下的优化机会。
| 归档时间: |
|
| 查看次数: |
317 次 |
| 最近记录: |