GCC 11.1中对易失性的非一致性优化 [英] Non-conforming optimizations of volatile in gcc 11.1

查看:33
本文介绍了GCC 11.1中对易失性的非一致性优化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在写关于编译器必须如何处理volatile的答案时,我相信我可能无意中发现了GCC的错误,希望有人在我报告它之前进行验证。

我写了一个简单的函数,如下所示:

int foo (int a, int b, int c)
{
  b = a + 1;
  c = b + 1;
  a = c + 1;
  return a;
}

如果没有优化,这会导致大量毫无意义的数据来回移动。通过优化,编译器只需获取存储a的寄存器,然后加3并返回结果。讲x86lea eax, [rdi+3]ret。到目前为止,这是意料之中的,一切顺利。

为了演示排序和易失性访问,我将示例更改为:

int foo (int a, int b, int c)
{
  b = a + 1;
  c = *(volatile int*)&b + 1;
  a = c + 1;
  return a;
}

这里有一个b内容的左值访问,它是Volatil限定的,据我所知,编译器绝对不允许优化该访问1)。从GCC 4.1.2(可能更早的版本)到GCC 10.3,我得到了一致的行为(与Clang相同)。即使使用-O3

,x86机器代码也是这样的
foo:
        add     edi, 1
        mov     DWORD PTR [rsp-4], edi
        mov     eax, DWORD PTR [rsp-4]
        add     eax, 2
        ret

然后我在GCC 11.1及更高版本上尝试相同的方法,现在得到:

foo:
        lea     eax, [rdi+3]
        ret

https://godbolt.org/z/e5x74z3Kb

ARM GCC 11.1也做了类似的事情。

这是编译器错误吗?


1)参考文献:ISO/IEC 9899:2018 5.1.2.3,特别是第2款、第4款和第6款。

推荐答案

根据C18 5.1.2.3/6,对易失性对象的访问(严格按照抽象机器的规则)是程序可观察行为的一部分,所有符合要求的实现都必须重现这一行为。本文中的术语访问包括读取和写入。

C18 5.1.2.3/2和/4强调易失性访问是需要的副作用,不包括在允许实现以避免产生不必要的副作用的规则中。

我对GCC唯一的看法是,虽然(volatile int*)&b是一个volatile限定类型的左值,但它可以证明它指定的对象(b)实际上不是一个易失性对象,如果你按照它的声明去看,它确实不是。这与GCC 11.2观察到的该版本函数的行为是一致的:

int foo (int a, int b, int c)
{
  volatile int bv = a + 1;
  c = bv + 1;
  a = c + 1;
  return a;
}

,这将生成与GCC的旧版本对原始代码(godbolt)所做的相同的程序集。

这是否构成不符合语言标准的错误尚不清楚,但可以肯定的是,GCC正在阻挠程序员的明显意图。

这篇关于GCC 11.1中对易失性的非一致性优化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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