人类可读的C / C ++系列优化版本

时间:2014-03-25 20:38:40

标签: c++ c gcc optimization

我有一个很长的C ++系列的OR和AND链接在一起。当然,编译器在优化它时比我好得多,而且我不应该试图超越它。但是,出于学习目的,我想知道表达式是否可以优化,以及编译器在通过-O3-Os后如何看到它。

有办法做到这一点吗?我可以逐个提取我想要的表达式并将它们放在一个新程序中。

作为一个愚蠢的例子,如果我有:

if( n < 2 && n < 1 )

我想看到编译器已经看到它可以简化为:

if ( n < 1 )

修改 可能发生优化魔法的其他情况涉及字节移位,例如以2的幂除法。

一个真实的例子是:

if(((col1 < col2) && (col1 + pdim < col2))
    || ((col2 < col1) && (col2 + pdim < col1))
    || ((row1 < row2) && (row1 + pdim < row2))
    || ((row2 < row1) && (row2 + pdim < row1))){
    overlap = false;
}

这段代码检查由左上角pdim(col1, row1)的坐标定义的两个大小为(col2, row2)的正方形是否重叠。

这主要是为了了解编译器可以为自己做些什么,而不是在生产中使用它。当然,自己编写C线的优化版本是一个坏主意,因为它只会损害可读性,并且只能在编译时节省几微秒。但是有些场景可能会变得有用,例如,在用Python编写时,没有编译器,Cython不是一个选项,访问优化版本可能会有用。

我目前正在Linux上使用GCC,但如果更方便的话,可以使用Clang或任何其他替代方法做同样的事情。

4 个答案:

答案 0 :(得分:9)

GCC的优化传递以名为GIMPLE的格式处理代码的中间表示。

使用-fdump-* options,您可以要求GCC输出树的中间状态。

E.g。

test.cc

#include <iostream>
#include <cstdlib>

int main()
{
  int n(rand());

  if (n < 2 && n < 1)
    std::cout << "OK" << std::endl;

  return 0;
}

使用

进行编译
g++ -O3 -o test1 -fdump-tree-all test.cc

你会得到很多(!)的文件,其中包括:

test.cc.165t.optimized

;; Function int main() (main, funcdef_no=1013, decl_uid=21841, cgraph_uid=229) (executed once)

int main() ()
{
  int n;
  struct basic_ostream & _6;

  <bb 2>:
  n_4 = rand ();
  if (n_4 <= 0)
    goto <bb 3>;
  else
    goto <bb 4>;

  <bb 3>:
  _6 = std::operator<< <std::char_traits<char> > (&cout, "OK");
  std::endl<char, std::char_traits<char> > (_6);

  <bb 4>:
  return 0;

}

因此,您可以查看gcc已执行的优化:

if (n < 2 && n < 1)    //  optimized in if (n_4 <= 0) ...

有时在gdb调试器中运行程序并使用disassemble /m命令查看与C / C ++代码混合的程序集是一种有效的替代方法。

答案 1 :(得分:3)

C ++通常受限于通过执行短路评估来优化大型和/或表达式。

如果你对编译器如何优化表达式感兴趣,那么阅读程序集通常是你能做到的最好的。

如果您对可能的优化感兴趣,请查看卡诺图。我经常使用那些来理解我的逻辑中的潜在模式(和弱点!)。我认为他们是程序员可以从电气工程师那里学到的最重要的工具之一。

答案 2 :(得分:2)

好吧,如果您有一个代码片段,如:

bool b = true;
int i = 3;
if ((a || b) && ((i == 3) && b))
{
    printf("Yes!\n");
}

然后使用-O0,您将获得您在此处看到的内容,但是-O3您将获得:

printf("Yes!\n");

所有条件和if语句本身都已经过优化。

如果你想看看编译器对它做了什么,请尝试编译 gcc -c -O0 -S test.cpp -o test.s 分别 gcc -c -O3 -S test.cpp -o test.s。这将生成您可以比较的装配。

答案 3 :(得分:0)

为了完整起见,我找到了一个在线工具,用不同的编译器生成汇编代码。

http://gcc.godbolt.org/

我尝试使用以下代码,但仍在尝试理解输出。

#include<iostream>
#include<stdlib.h>

int main(){
bool overlap = true;
int col1, col2, pdim, row1, row2;
bool condition;

col1 = rand();
col2 = rand();
row1 = rand();
row2 = rand();

std::cout << row2 << std::endl;

condition =((col1 < col2) && (col1 + pdim < col2))
    || ((col2 < col1) && (col2 + pdim < col1))
    || ((row1 < row2) && (row1 + pdim < row2))
    || ((row2 < row1) && (row2 + pdim < row1));

std::cout << condition << std::endl;
}