有没有办法告诉 C 编译器指针没有别名存储?
Is there a way to tell the C compiler that a pointer has no aliasing stores?
如果 C 编译器知道指针没有别名,它可以执行许多优化。例如,如果我用 gcc -O2
编译以下函数:
int f_noalias(int *arr, int x)
{
int res = 0;
int *p = &arr[17];
*p = x;
res += *p;
res += *p;
return res;
}
编译器知道读取 *p
的结果总是 x
因此生成的代码等同于为以下函数生成的代码:
int f_noalias2(int *arr, int x)
{
int *p = &arr[17];
*p = x;
return 2*x;
}
但是,如果编译器认为指针可能存在别名,它就不再执行此优化。例如,如果我们修改 f
以便在读取到 *p
之间调用未知函数,生成的代码将取消引用 p
两次。编译器假设 read_arr
函数可能修改了 p
指向的值。
int f_withalias(int *arr, int x)
{
int res = 0;
int *p = &arr[17];
*p = x;
res += *p;
read_array(arr);
res += *p;
return res;
}
在我的特定程序中,当 f
函数是 运行 时,它持有的 p
指针是唯一写入 arr
的那个元素的指针大批。这段时间代码中的其他函数可能会从 arr
读取,但不会写入。 (他们可能会在 f
完成 运行 之后将其他值写入 arr
。)
所以现在我有三个问题:
首先:有没有一种方法可以声明我的变量以向 C 编译器提供此提示?我尝试向 p
添加限制注释,但是生成的gcc -O2
下的代码与 f_withalias
的生成代码相同
int f_restrict(int *arr, int x)
{
int res = 0;
int * restrict p = &arr[17];
*p = x;
res += *p;
read_array(arr);
res += *p;
return res;
}
其次:我在这里使用 restrict 的尝试有效吗?我的理解是 restrict 意味着没有其他指针可以为 p 作为读或写的别名。但在我的例子中,read_arr
函数显然也可以访问 p
指向的 arr
数组。
第三:如果上一个问题的答案是"no",有什么不同的东西可以代替restrict
吗?
基本上,我需要确保如果我在 f
中执行 *p = x
,那么从 arr[17]
读取的其他函数会立即注意到该写入。但是,我希望 GCC 可以自由地将 x = *p; y = *p
优化为 x = *p; y = x
,即使两次读取之间存在函数调用。
First: Is there a way I can declare my variables to give this hint to the C compiler?
int * restrict p = &arr[17];
断言只有 p
和基于 p
的指针表达式将用于访问任何对象 p
在块的持续时间内指向(除了对于未以任何方式修改的对象)。这可以实现您建议的 res += *p;
的优化。 GCC没有这么优化是GCC的质量问题。
Second: Is my attempt to use restrict here valid? …
Basically, I need to make sure that if I do *p = x in f then that write will be immediately noticed by other functions reading from arr[17].
后者 属性 不是 restrict
的有效用法。 p
声明为 restrict
并且 arr[17]
通过 p
修改的事实意味着不应该使用不基于 p
的指针来访问 arr[17]
在包含 p
的块执行期间,甚至不用于读取。因此,如果 read_array
中的某些内容确实读取了 arr[17]
(使用 arr
,它不是基于 p
),这将违反 restrict
断言.
如果 C 编译器知道指针没有别名,它可以执行许多优化。例如,如果我用 gcc -O2
编译以下函数:
int f_noalias(int *arr, int x)
{
int res = 0;
int *p = &arr[17];
*p = x;
res += *p;
res += *p;
return res;
}
编译器知道读取 *p
的结果总是 x
因此生成的代码等同于为以下函数生成的代码:
int f_noalias2(int *arr, int x)
{
int *p = &arr[17];
*p = x;
return 2*x;
}
但是,如果编译器认为指针可能存在别名,它就不再执行此优化。例如,如果我们修改 f
以便在读取到 *p
之间调用未知函数,生成的代码将取消引用 p
两次。编译器假设 read_arr
函数可能修改了 p
指向的值。
int f_withalias(int *arr, int x)
{
int res = 0;
int *p = &arr[17];
*p = x;
res += *p;
read_array(arr);
res += *p;
return res;
}
在我的特定程序中,当 f
函数是 运行 时,它持有的 p
指针是唯一写入 arr
的那个元素的指针大批。这段时间代码中的其他函数可能会从 arr
读取,但不会写入。 (他们可能会在 f
完成 运行 之后将其他值写入 arr
。)
所以现在我有三个问题:
首先:有没有一种方法可以声明我的变量以向 C 编译器提供此提示?我尝试向 p
添加限制注释,但是生成的gcc -O2
下的代码与 f_withalias
int f_restrict(int *arr, int x)
{
int res = 0;
int * restrict p = &arr[17];
*p = x;
res += *p;
read_array(arr);
res += *p;
return res;
}
其次:我在这里使用 restrict 的尝试有效吗?我的理解是 restrict 意味着没有其他指针可以为 p 作为读或写的别名。但在我的例子中,read_arr
函数显然也可以访问 p
指向的 arr
数组。
第三:如果上一个问题的答案是"no",有什么不同的东西可以代替restrict
吗?
基本上,我需要确保如果我在 f
中执行 *p = x
,那么从 arr[17]
读取的其他函数会立即注意到该写入。但是,我希望 GCC 可以自由地将 x = *p; y = *p
优化为 x = *p; y = x
,即使两次读取之间存在函数调用。
First: Is there a way I can declare my variables to give this hint to the C compiler?
int * restrict p = &arr[17];
断言只有 p
和基于 p
的指针表达式将用于访问任何对象 p
在块的持续时间内指向(除了对于未以任何方式修改的对象)。这可以实现您建议的 res += *p;
的优化。 GCC没有这么优化是GCC的质量问题。
Second: Is my attempt to use restrict here valid? … Basically, I need to make sure that if I do *p = x in f then that write will be immediately noticed by other functions reading from arr[17].
后者 属性 不是 restrict
的有效用法。 p
声明为 restrict
并且 arr[17]
通过 p
修改的事实意味着不应该使用不基于 p
的指针来访问 arr[17]
在包含 p
的块执行期间,甚至不用于读取。因此,如果 read_array
中的某些内容确实读取了 arr[17]
(使用 arr
,它不是基于 p
),这将违反 restrict
断言.