如何指示结构成员没有锯齿?

How to indicate absence of aliasing for a struct member?

本文关键字:成员 结构 何指示 指示      更新时间:2023-10-16

如果你写这样的语句:

a[i] = b[i] + c[i];

。您可能希望向编译器指示a[i]b[i]c[i]指向内存中的不同位置,从而实现各种优化(例如矢量化(。这可以通过在声明中添加一个特殊的关键字来完成:

float * __restrict__ a; // same for b and c

但是,如果您使用的是更复杂的对象,而不是float,您会怎么做:

struct item {
float foo, bar;
};

请考虑以下代码:

float *a, *b;
item *c;
// ...
for (int i = 0; i < 42; ++i) {
a[i] = b[i] * c[i].foo + c[i].bar;
}

在循环中,编译器不关心c[i],而是关心c[i].fooc[i].bar。在这种情况下,如何针对结构的各个字段声明关于指针独立的等效断言?

目前,我已经设法使用以下方法解决了这个问题:

#pragma GCC ivdep

但是,这会完全关闭依赖项检查。我仍然对更具选择性的解决方案感兴趣。

该标准不要求编译器适应a[anything]b[anything]可用于访问struct item的任何部分的可能性。 它列出了实现必须始终允许用于访问结构(如struct item(的左值类型,而非字符成员类型(如int(不在其中。 不需要特殊权限即可让编译器假设ab都不会为struct item别名。

当然,编译器允许代码采用非字符类型的结构或联合成员的地址,但实际上从未允许使用生成的指针访问成员,即使在不涉及 aliasing(*( 的情况下,编译器也是相当无益的。 然而,该标准没有区分涉及别名的情况和不涉及别名的情况,并且将何时允许使用成员类型标签值访问结构的问题完全取决于实现者的判断。 gcc 和 clang 的作者可能已经决定,在非锯齿场景中支持使用指针来结构成员的最简单方法是在所有场景中支持它们,但标准几乎不需要这样的处理,我认为作者不希望这样做。

该标准为实现提供了空间,可以从以下假设中受益:ab都不会别名c,但仍然支持大多数需要使用指向结构或工会成员的指针的程序。 虽然在某些情况下,更多类似于__restrict的限定符会有所帮助,但我不确定您认为在您展示的情况中实现需要什么额外的权限。

(*( 即没有操作访问存储区域的情况,或者派生将用于执行此操作的指针/引用,有时存在较新的指针/引用,该指针/引用也将用于以冲突的方式访问或寻址同一存储。

没有必要这样做。

要么编译器足够聪明,知道这些结构成员不能别名,要么不够聪明,无法对这些信息做任何有用的事情。

__restrict__和 C99restrict关键字的原因是,与结构不同,数组可能会别名。因此,关键字为编译器提供了真实而有用的信息。