相对于流行的编译器的函数优化行为__restrict [英] __restrict vis-a-vis a function optimization behavior of popular compilers

查看:144
本文介绍了相对于流行的编译器的函数优化行为__restrict的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

请考虑以下函数:

int bar(const int* __restrict x, void g())
{
    int result = *x;
    g();
    result += *x;
    return result;
}

我们是否需要从 x读取两次是因为调用了 g()?或者 __ restrict ion是否足以保证 g()的调用不会访问/不会更改以下位置的值地址 x

Do we need to read twice from x because of the call to g()? Or is the __restriction enough to guarantee the invocation of g() does not access/does not alter the value at address x?

此链接,我们看到最流行的编译器不得不对此发表意见(GodBolt;语言标准C99,平台AMD64):

At this link we see the most popular compilers have to say about this (GodBolt; language standard C99, platform AMD64):


  • clang 7.0:遵守限制。

  • GCC 8.3:无限制。

  • MSVC 19.16:无限制。

用clang正确地优化了秒读功能,不是吗?我在这里要求使用C和C ++,因为行为相同(感谢@PSkocik)。

Is clang rightly optimizing the second read away, or isn't it? I'm asking both for C and C++ here, as the behavior is the same (thanks @PSkocik).

相关信息和一些注意事项:

Related information and some notes:

  • Readers unfamiliar with __restrict (or __restrict__) may want to have a look at: What does the restrict keyword mean in C++?
  • GCC's documentation page on restricted pointers in C++.
  • I've opened a bug against GCC on this point.
  • The fact that x is marked const is not significant here - we get the same behavior if we drop the const and the question stands as is.

推荐答案

我认为实际上是C的问题,因为C实际上是具有 restrict 的语言,并附加了正式的规范。

I think this is effectively a C question, since C is effectively the language that has restrict, with a formal spec attached to it.

C标准中用于控制 restrict 的部分为 6.7.3.1

The part of the C standard that governs the use of restrict is 6.7.3.1:


1设D为声明普通标识符,它提供
的方式来指定对象P作为指向
类型T的限制限定指针。

1 Let D be a declaration of an ordinary identifier that provides a means of designating an object P as a restrict-qualified pointer to type T.

2如果出现D在一个块内并且没有存储类extern,
让B表示该块。如果D出现在函数定义的参数
声明列表中,则B表示关联的
块。否则,让B表示main块(或
块,无论在独立的
环境中程序启动时调用什么函数)。

2 If D appears inside a block and does not have storage class extern, let B denote the block. If D appears in the list of parameter declarations of a function definition, let B denote the associated block. Otherwise, let B denote the block of main (or the block of whatever function is called at program startup in a freestanding environment).

3接下来,如果(在E的
评估之前B执行的某个顺序点上)修改P使其指向副本,则认为指针表达式E基于
对象P先前指向的数组对象
的值将更改E.137的值。)请注意,
基于仅针对具有指针类型的表达式定义。

3 In what follows, a pointer expression E is said to be based on object P if (at some sequence point in the execution of B prior to the evaluation of E) modifying P to point to a copy of the array object into which it formerly pointed would change the value of E.137) Note that ''based'' is defined only for expressions with pointer types.

4在每次执行B时,让L为具有
P的& L的任何左值。如果L用于访问对象X的值,则
指定并且X也被修改(通过任何方式),则以下
要求适用:T不得为const限定的。用于访问X值的所有其他左值
的地址也应基于P。
修改X的每次访问也应被认为是修改P,对于
而言,本小节。如果为P分配了基于与块B2关联的另一个受限制指针
对象P2的
指针表达式E的值,则B2
的执行应在执行以下命令之前开始B或B2的执行应在分配前结束。如果不满足这些要求,则
的行为是不确定的。

4 During each execution of B, let L be any lvalue that has &L based on P. If L is used to access the value of the object X that it designates, and X is also modified (by any means), then the following requirements apply: T shall not be const-qualified. Every other lvalue used to access the value of X shall also have its address based on P. Every access that modifies X shall be considered also to modify P, for the purposes of this subclause. If P is assigned the value of a pointer expression E that is based on another restricted pointer object P2, associated with block B2, then either the execution of B2 shall begin before the execution of B, or the execution of B2 shall end prior to the assignment. If these requirements are not met, then the behavior is undefined.

5这里的B执行意味着
执行的那一部分程序,该程序将与标量
类型的对象的生存期以及与B关联的自动存储持续时间相对应。

5 Here an execution of B means that portion of the execution of the program that would correspond to the lifetime of an object with scalar type and automatic storage duration associated with B.

我读到了, g()的执行属于 bar 的块的执行,所以 g()不允许修改 * x clang 来优化第二个负载的权利(如果 * x 指的是非常量全局变量,则是IOW, g()不得在全局范围内进行修改。

The way I read it, the execution of g() falls under the execution of the bar's block, so g() is disallowed from modifying *x and clang is right to optimize out the second load (IOW, if *x refers to a non-const global, g() must not modify that global).

这篇关于相对于流行的编译器的函数优化行为__restrict的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆