Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Human readable optimised version of C/C++ line

I have a long C++ line of ORs and ANDs chained together. Of course, the compiler is much better than me at optimising it, and I shouldn't try to oversmart it. But, for learning purposes, I would like to know if the expression can be optimised, and how is the compiler seeing it after passing with -O3 and -Os.

Is there a way to do this? I can just extract the expressions I want one by one and put them in a new program.

As a silly example, if I have:

if( n < 2 && n < 1 )

I want to see that the compiler has seen that it can be simplified to:

if ( n < 1 )

Edit: Other cases where optimisation magic can occur involve byte shifting, for example in division by powers of 2.

A real example is this:

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

This piece of code checks if two squares of size pdim defined by the coordinates of the upper left corner (col1, row1), (col2, row2) are overlapping.

This is mostly to learn what the compiler can do for itself, not to use it in production. Of course, writing the optimised version of the C line myself is a bad idea, as it will just hurt readability, and only save a few microseconds in compiling time. But there are scenarios where it could turn useful, for example, when writing in Python, where there is no compiler an Cython is not an option, having access to an optimised version may be useful.

I am currently using GCC on Linux, but could do the same thing with Clang or any other alternative, if it were more convenient.

like image 266
Davidmh Avatar asked Dec 03 '25 08:12

Davidmh


1 Answers

GCC's optimization passes work on an intermediary representation of your code in a format called GIMPLE.

Using the -fdump-* options, you can ask GCC to output intermediary states of the tree.

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;
}

compiling with

g++ -O3 -o test1 -fdump-tree-all test.cc

You'll get a lot (!) of files and among them:

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;

}

So you can check what optimizations gcc has performed:

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

Sometimes running the program in the gdb debugger and using the disassemble /m command to view the assembly mixed with the C / C++ code is a valid alternative.

like image 174
manlio Avatar answered Dec 04 '25 23:12

manlio