如何更改一个功能的优化级别?

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 具有 optnoneminsize 函数属性(使用 __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.