eye*_*van 2 c compiler-construction gcc llvm clang
我出于纯粹的兴趣而学习 C 和计算机科学主题,这让我对编译器产生了兴趣。我读过的所有内容都告诉我,别名会导致程序集输出速度变慢,需要在每次迭代时重新加载值。
\n我已经能够使用 flag 使英特尔 C/C++ 编译器的一些基准测试略有提高-fno-alias。GCC 和 Clang / LLVM 没有等效的标志。-fargument-noalias我猜测它-fargument-noalias-global会禁用函数参数 \xe2\x80\x94 上的别名,如果我错了,请纠正我\xe2\x80\x94 但我没有注意到它对运行时甚至编译时性能有任何影响。
是否声明
\n\n\n别名会阻止编译器进行某些优化,从而影响性能。
\n
始终如此,编译器别名有什么好处?为什么它是现代编译器的一个功能,除了英特尔编译器之外,不能通过标志轻松关闭?不使用别名进行编译会导致代码不符合 ABI 标准吗?
\n编译器不执行别名。您的程序可能会执行别名操作。
编译器要么允许您执行别名,要么假设您没有执行别名,然后编写在您执行别名时不起作用的机器代码。
例如,您编写这样的代码:
void f(int *x, int *y, int *z) {
*y += *x;
*z += *x;
}
Run Code Online (Sandbox Code Playgroud)
该函数只是将和*x相加,对吗?那么汇编代码应该是这样的吧?(我用伪C语言编写了汇编代码)*y*z
eax = argument x
ebx = argument y
ecx = *eax
*ebx += ecx
ebx = argument z
*ebx += ecx
Run Code Online (Sandbox Code Playgroud)
错误的。如果y和x指向同一位置,则此汇编代码的工作方式与 C 代码不同,因为它使用旧的 *x. 为了正常工作,它必须是这样的:
eax = argument x
ebx = argument y
ecx = *eax
*ebx += ecx
ebx = argument z
ecx = *eax // extra instruction
*ebx += ecx
Run Code Online (Sandbox Code Playgroud)
这又是一条指令,它仅在 if 时有用x==y,但编译器必须将其放在那里以防万一。别名意味着*x和*y是同一变量的不同名称。如果编译器假设x和y不能是相同的指针(即没有别名),那么它可以跳过该指令,因此指令更少,程序运行得更快。
您可以使用单词 告诉编译器它们不使用别名restrict,如下所示:
void f(int *restrict x, int *restrict y, int *restrict z) {
*y += *x;
*z += *x;
}
Run Code Online (Sandbox Code Playgroud)
-fno-alias告诉英特尔编译器别名不能在任何地方发生。这可能会在某个地方产生错误,因为参数有时会产生别名 - 尽管它可能在没有一个参数的小程序上工作得很好。restrict更仔细地针对您知道不会别名的特定参数。