1

在启用优化的情况下,我在使用 GCC for ARM 时遇到了一个非常奇怪的问题。在没有优化的情况下编译我的 C++ 应用程序会生成一个在运行时输出预期结果的可执行文件。一旦我打开优化 - 即 -O1 - 我的应用程序就无法产生预期的结果。我尝试了几天来发现问题,但我一无所知。我从我的代码中消除了任何未初始化的变量,我纠正了严格别名可能导致问题的地方,但我仍然没有得到正确的结果。

我正在为 ARM 使用 GCC 4.2.0(处理器是 ARM926ej-s)并在 Montavista Linux 发行版上运行该应用程序。

以下是我正在使用的标志:

-O1 -fno-unroll-loops fno-merge-constants -fno-omit-frame-pointer -fno-toplevel-reorder \
-fno-defer-pop -fno-function-cse -Wuninitialized -Wstrict-aliasing=3 -Wstrict-overflow=3 \
-fsigned-char -march=armv5te -mtune=arm926ej-s -ffast-math

只要我去掉 -O1 标志并重新编译/重新链接应用程序,我就会得到正确的输出结果。正如您从标志中看到的那样,我试图禁用任何优化,我认为它可能会导致问题,但仍然没有运气。

有没有人对我如何进一步解决这个问题有任何指示?

谢谢

4

4 回答 4

9

一般来说,如果您说“优化破坏了我的程序”,那么您的程序有 99.9%被破坏了。启用优化只会发现代码中的错误。

您还应该轻松使用优化选项。只有在非常特殊的情况下,您才需要标准选项 -O0、-O2、-O3 和可能的 -Os 之外的任何其他内容。如果您觉得确实需要比这更具体的设置,请注意优化的口头禅:

测量、优化、测量。

永远不要在这里“直觉”。证明某个非标准优化选项确实显着地有益于您的应用程序,并了解原因(即,准确了解该选项的作用,以及它为什么会影响您的代码)。

这不是一个蒙着眼睛导航的好地方。

看看你如何使用最具防御性的选项 (-O1),然后禁用六个优化,然后添加 -ffast-math,让我假设你目前正在这样做。

好吧,也许是独眼。

但底线是:如果启用优化会破坏您的代码,则很可能是您的代码有问题。

编辑:我刚刚在 GCC 手册中找到了这个:

-ffast-math: 任何 -O 选项都不应打开此选项,因为它可能导致依赖于数学函数的 IEEE 或 ISO 规则/规范的精确实现的程序的错误输出。

基本上,这确实表明您-O1 -ffast-math确实可以破坏正确的代码。但是,即使-ffast-math删除可以解决您当前的问题,您至少应该知道原因。否则,您可能只是在以后更不方便的时刻(例如,当您的产品在客户的位置发生故障时)交换您的问题。真的是问题所在,还是您发现了被破坏的数学代码?-ffast-math-ffast-math

于 2010-10-04T11:23:35.330 回答
2

-ffast-math应尽可能避免。暂时使用-O1并删除所有其他优化开关。如果您仍然看到问题,那么是时候开始调试了。

于 2010-10-04T11:08:59.417 回答
1

如果没有看到您的代码,很难比“您可能有错误”更具体。

启用优化会改变程序的语义有两种情况:

  • 编译器中存在错误,或者
  • 您的代码中有一个错误。

后者可能是最有可能的。具体来说,您可能依赖于程序中某处的未定义行为。当您在这台计算机上使用带有这些编译器标志的编译器进行编译时,您依赖的东西恰好是真的,但语言不能保证这一点。因此,当您启用优化时,GCC 没有义务保留该行为。

向我们展示您的代码。或者在调试器中单步执行,直到出现问题。

我不能再具体了。它可能是一个悬空指针、未初始化的变量、破坏了别名规则,甚至只是做了许多会产生未定义结果的事情之一(例如i = i++

于 2010-10-04T11:20:19.313 回答
1

Try to make a minimal test case. Rewrite the program, removing things that don't affect the error. It's likely that you'll discover the bug yourself in the process, but if you don't, you should have a one-screen example program you can post.

顺便说一句,如果正如其他人所推测的那样,它会-ffast-math导致你的麻烦(即编译-O1工作正常),那么你很可能在那里有一些数学,你应该无论如何都要重写。这有点过度简化,但-ffast-math允许编译器从本质上重新排列计算,因为您可以抽象数学数字 - 即使在真实硬件上这样做可能会导致略有不同的结果,因为浮点数不精确。依赖这种浮点细节很可能是无意的。

如果您想了解这个错误,那么在任何情况下,一个最小的测试用例都是至关重要的。

于 2010-10-04T11:52:16.303 回答