我注意到 clang 和 gcc 优化了易失性的构造或分配struct
在某些情况下,在堆栈上声明。例如,以下代码:
struct nonvol2 {
uint32_t a, b;
};
void volatile_struct2()
{
volatile nonvol2 temp = {1, 2};
}
Compiles在 clang 上:
volatile_struct2(): # @volatile_struct2()
ret
另一方面,gcc 不会删除存储,尽管它确实将两个隐含存储优化为单个存储:
volatile_struct2():
movabs rax, 8589934593
mov QWORD PTR [rsp-8], rax
ret
奇怪的是,clang 不会将易失性存储优化为单个int
多变的:
void volatile_int() {
volatile int x = 42;
}
编译为:
volatile_int(): # @volatile_int()
mov dword ptr [rsp - 4], 1
ret
此外,具有 1 个成员而不是 2 个成员的结构不会被优化掉。
虽然 gcc 不会删除这种特殊情况下的构造,但它可能会在以下情况下进行更积极的优化:struct
成员本身被宣布volatile
,而不是struct
其本身在构造时:
typedef struct {
volatile uint32_t a, b;
} vol2;
void volatile_def2()
{
vol2 temp = {1, 2};
vol2 temp2 = {1, 2};
temp.a = temp2.a;
temp.a = temp2.a;
}
简单地编译成一个简单的ret
.
虽然删除这些几乎不可能通过任何合理过程观察到的商店似乎完全“合理”,但我的印象是,在标准中volatile
假设加载和存储是一部分可观察的行为程序(除了调用 IO 函数),完全停止。这意味着它们不会被“好像”删除,因为根据定义它会改变可观察的行为的程序。
是我错了,还是 clang 违反了这里的规则?也许建造被排除在以下情况之外:volatile
必须假设有副作用吗?