如何更改一个功能的优化级别?
How to change optimization level of one function?
这与 有关在问题中,当使用特定版本的 GCC -O3
编译时,我在特定函数中捕获了段错误。在 -O3
,使用矢量化指令(在 -O2
,不使用)。
我想在较低的优化级别包装单个函数。根据Switching off optimization for a specific function in GCC 4.2.2,我可以做到。但是,按照问题和答案中的各种链接,我找不到 "how, exactly, to do it".
的答案
如何将单个函数标记为使用不同的优化级别?
相关,我不想将这个函数移动到一个单独的文件中,然后为它提供一个不同的makefile 配方。这样做会打开另一个蠕虫罐头,例如仅在某些平台上将其应用于 GCC 4.9。
在https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#Common-Function-Attributes
中有描述
您可以通过这样声明函数来更改级别:
void some_func() __attribute__ ((optimize(1))) {
....
}
为其强制优化级别 1。
以下是使用编译指示的方法:
#pragma GCC push_options
#pragma GCC optimize ("-O2")
void xorbuf(byte *buf, const byte *mask, size_t count)
{
...
}
#pragma GCC pop_options
为了便于携带,如下所示。
#define GCC_OPTIMIZE_AWARE (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7)) || defined(__clang__)
#if GCC_OPTIMIZE_AWARE
# pragma GCC push_options
# pragma GCC optimize ("-O2")
#endif
它需要包装,因为 -Wall
,旧版本的 GCC 不理解 -Wno-unknown-pragma
,它们会导致编译时出现噪音。在现场会遇到老版本,比如 OpenBSD 上的 GCC 4.2.1。
但是根据 Markus Trippelsdorf 在 When did 'pragma optimize' become available? 来自 GCC 邮件列表的说法:
This is a bad idea in general, because "pragma GCC optimize" is meant as
a compiler debugging aid only. It should not be used in production
code.
我知道这个问题被标记为 GCC,但我只是 looking into doing this portably 并且认为结果可能对某些人有用,所以:
- GCC 有一个
optimize(X)
函数属性
- Clang 具有
optnone
和 minsize
函数属性(使用 __has_attribute
测试支持)。因为我 相信 3.5 它也有 #pragma clang optimize on|off
.
- Intel C/C++ 编译器有
#pragma intel optimization_level 0
应用于 pragma 之后的下一个函数
- MSVC有
#pragma optimize
,适用于pragma 之后的第一个函数
- IBM XL 有
#pragma option_override(funcname, "opt(level,X)")
。请注意,13.1.6(至少)returns 对于 __has_attribute(optnone)
是正确的,但实际上并不支持它。
- ARM有
#pragma Onum
,可与#pragma push/pop
耦合
- ODS 有
#pragma opt X (funcname)
- Cray 有
#pragma _CRI [no]opt
- TI 有
#pragma FUNCTION_OPTIONS(func,"…")
(C) 和 #pragma FUNCTION_OPTIONS("…")
(C++)
- IAR 有
#pragma optimize=...
- 佩莱斯 C 有
#pragma optimize time/size/none
因此,对于 GCC/ICC/MSVC/clang/IAR/Pelles 和 TI C++,您可以定义一个刚放在函数之前的宏。如果你想支持 XL、ODS 和 TI C,你可以添加函数名作为参数。 ARM 在弹出设置的函数之后需要另一个宏。对于 Cray AFAIK,您无法恢复以前的值,只能关闭和打开优化。
我认为这样做的主要原因是禁用对有缺陷的编译器(或在代码中暴露错误的编译器)的优化,因此统一的可移植体验可能并不重要,但希望此列表可以帮助某人找到适合他们的编译器的正确解决方案。
编辑:同样值得注意的是,禁用优化是相对常见的,因为之前可以运行的代码不再运行。虽然编译器中可能存在错误,但您的代码更有可能依赖于未定义的行为,而更新、更智能的编译器可以并且将会消除未定义的情况。在这种情况下,正确的答案不是禁用优化,而是修复代码。 UBsan on clang 和 gcc 在这里可以提供很多帮助;使用 -fsanitize=undefined
编译,许多未定义的行为将在运行时开始发出警告。另外,尝试使用您可以启用的所有警告选项进行编译;对于 GCC,这意味着 -Wall -Wextra
,对于 clang throw in -Weverything
.
这与 -O3
编译时,我在特定函数中捕获了段错误。在 -O3
,使用矢量化指令(在 -O2
,不使用)。
我想在较低的优化级别包装单个函数。根据Switching off optimization for a specific function in GCC 4.2.2,我可以做到。但是,按照问题和答案中的各种链接,我找不到 "how, exactly, to do it".
的答案如何将单个函数标记为使用不同的优化级别?
相关,我不想将这个函数移动到一个单独的文件中,然后为它提供一个不同的makefile 配方。这样做会打开另一个蠕虫罐头,例如仅在某些平台上将其应用于 GCC 4.9。
在https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#Common-Function-Attributes
中有描述您可以通过这样声明函数来更改级别:
void some_func() __attribute__ ((optimize(1))) {
....
}
为其强制优化级别 1。
以下是使用编译指示的方法:
#pragma GCC push_options
#pragma GCC optimize ("-O2")
void xorbuf(byte *buf, const byte *mask, size_t count)
{
...
}
#pragma GCC pop_options
为了便于携带,如下所示。
#define GCC_OPTIMIZE_AWARE (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7)) || defined(__clang__)
#if GCC_OPTIMIZE_AWARE
# pragma GCC push_options
# pragma GCC optimize ("-O2")
#endif
它需要包装,因为 -Wall
,旧版本的 GCC 不理解 -Wno-unknown-pragma
,它们会导致编译时出现噪音。在现场会遇到老版本,比如 OpenBSD 上的 GCC 4.2.1。
但是根据 Markus Trippelsdorf 在 When did 'pragma optimize' become available? 来自 GCC 邮件列表的说法:
This is a bad idea in general, because "pragma GCC optimize" is meant as a compiler debugging aid only. It should not be used in production code.
我知道这个问题被标记为 GCC,但我只是 looking into doing this portably 并且认为结果可能对某些人有用,所以:
- GCC 有一个
optimize(X)
函数属性 - Clang 具有
optnone
和minsize
函数属性(使用__has_attribute
测试支持)。因为我 相信 3.5 它也有#pragma clang optimize on|off
. - Intel C/C++ 编译器有
#pragma intel optimization_level 0
应用于 pragma 之后的下一个函数
- MSVC有
#pragma optimize
,适用于pragma 之后的第一个函数
- IBM XL 有
#pragma option_override(funcname, "opt(level,X)")
。请注意,13.1.6(至少)returns 对于__has_attribute(optnone)
是正确的,但实际上并不支持它。 - ARM有
#pragma Onum
,可与#pragma push/pop
耦合
- ODS 有
#pragma opt X (funcname)
- Cray 有
#pragma _CRI [no]opt
- TI 有
#pragma FUNCTION_OPTIONS(func,"…")
(C) 和#pragma FUNCTION_OPTIONS("…")
(C++) - IAR 有
#pragma optimize=...
- 佩莱斯 C 有
#pragma optimize time/size/none
因此,对于 GCC/ICC/MSVC/clang/IAR/Pelles 和 TI C++,您可以定义一个刚放在函数之前的宏。如果你想支持 XL、ODS 和 TI C,你可以添加函数名作为参数。 ARM 在弹出设置的函数之后需要另一个宏。对于 Cray AFAIK,您无法恢复以前的值,只能关闭和打开优化。
我认为这样做的主要原因是禁用对有缺陷的编译器(或在代码中暴露错误的编译器)的优化,因此统一的可移植体验可能并不重要,但希望此列表可以帮助某人找到适合他们的编译器的正确解决方案。
编辑:同样值得注意的是,禁用优化是相对常见的,因为之前可以运行的代码不再运行。虽然编译器中可能存在错误,但您的代码更有可能依赖于未定义的行为,而更新、更智能的编译器可以并且将会消除未定义的情况。在这种情况下,正确的答案不是禁用优化,而是修复代码。 UBsan on clang 和 gcc 在这里可以提供很多帮助;使用 -fsanitize=undefined
编译,许多未定义的行为将在运行时开始发出警告。另外,尝试使用您可以启用的所有警告选项进行编译;对于 GCC,这意味着 -Wall -Wextra
,对于 clang throw in -Weverything
.