请看以下C语言程序:
据我所知,根据C标准,
我会期望一个优化编译器会执行以下之一: (A) 直接将
Clang正确地编译了B。
如下所示:(实际上将其转换为 A)
typedef struct { int x; } Foo;
void original(Foo***** xs, Foo* foo) {
xs[0][1][2][3] = foo;
xs[0][1][2][3]->x = 42;
}
据我所知,根据C标准,
Foo**
不能与Foo*
等别名,因为它们的类型不兼容。然而,使用clang 14.0和-O3
编译程序会导致重复加载。 mov rax, qword ptr [rdi]
mov rax, qword ptr [rax + 8]
mov rax, qword ptr [rax + 16]
mov qword ptr [rax + 24], rsi
mov rax, qword ptr [rdi]
mov rax, qword ptr [rax + 8]
mov rax, qword ptr [rax + 16]
mov rax, qword ptr [rax + 24]
mov dword ptr [rax], 42
ret
我会期望一个优化编译器会执行以下之一: (A) 直接将
x
分配给foo
,并将foo
分配给xs
(任何顺序)。
(B) 为xs
执行一次地址计算,并将其用于分配foo
和x
。Clang正确地编译了B。
void fixed(Foo***** xs, Foo* foo) {
Foo** ix = &xs[0][1][2][3];
*ix = foo;
(*ix)->x = 42;
}
如下所示:(实际上将其转换为 A)
mov rax, qword ptr [rdi]
mov rax, qword ptr [rax + 8]
mov rax, qword ptr [rax + 16]
mov qword ptr [rax + 24], rsi
mov dword ptr [rsi], 42
ret
有趣的是,gcc将两个定义都编译成了A。为什么clang不愿意或不能优化original
定义中的地址计算?
foo
不存在 - 相反,我使用malloc,所以我知道它是noalias
(由于这不影响问题,我已经删除了malloc)。 - Maciej Goszczycki