GCC 11.1中对易失性的非一致性优化 [英] Non-conforming optimizations of volatile in 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
:
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屋!