C++ functional programming optimization on GCC 3.2

AWLaFramboise@aol.com AWLaFramboise@aol.com
Tue Nov 26 13:01:00 GMT 2002


Hello,

I've made an unfortunate discovery recently regarding GCC's optimization of
functional-style constructs in C++.  Apparently, when templated function
objects (in the style of the C++ standard library) are inlined, a bunch of
instructions manipulating the 'this' pointer (that actually have no effect)
remain.  In addition, much more stack space is allocated than is actually
needed.

This overhead can have a cost that far exceeds the cost of the actual code.
In some situations, this overhead seems unacceptably high when speed
is important.

$ gcc -v
Reading specs from c:/mingw/bin/../lib/gcc-lib/mingw32/3.2/specs
Configured with: ../gcc/configure --with-gcc --with-gnu-ld --with-gnu-as
  --host=mingw32 --target=mingw32 --prefix=/mingw --enable-threads
  --disable-nls --enable-languages=f77,c++,objc,ada
  --disable-win32-registry --disable-shared
Thread model: win32
gcc version 3.2 (mingw special 20020817-1)

binutils version 2.13

Options used to compile: -O3 -fomit-frame-pointer -maccumulate-outgoing-args
  -march=pentium

testcase:

--begin--

int f(void);
void g(int);

template<typename predicate> class noop_t {
  public:
    inline explicit noop_t(const predicate &p)
      : pred(p) {
    }

    inline noop_t(const noop_t &n)
      : pred(n.pred) {
    }

    inline int operator()() const {
      return pred();
    }

  private:
    const predicate &pred;
};

template<typename predicate> inline noop_t<predicate>
  noop(const predicate &pred) {

  return noop_t<predicate>(pred);
}

void x() {
  g(noop(noop(noop(noop(noop(noop(noop(noop(noop(f)))))))))());
}

--eof--


With the above options, the above compiles x() to this:
--begin--
__Z1xv:
LFB1:
    sub esp, 172
LCFI0:
    lea ecx, [esp+32]    #  this
    lea eax, [esp+48]    #  this
    lea edx, [esp+16]    #  this
    mov DWORD PTR [esp+48], ecx  #  <variable>.pred,  this
    mov DWORD PTR [esp+64], eax  #  <variable>.pred,  this
    lea ecx, [esp+64]    #  this
    lea eax, [esp+80]    #  this
    mov DWORD PTR [esp+32], edx  #  <variable>.pred,  this
    mov DWORD PTR [esp+80], ecx  #  <variable>.pred,  this
    mov DWORD PTR [esp+96], eax  #  <variable>.pred,  this
    lea ecx, [esp+96]    #  this
    lea edx, [esp+128]   #  this
    lea eax, [esp+112]   #  this
    mov DWORD PTR [esp+112], ecx     #  <variable>.pred,  this
    mov DWORD PTR [esp+144], edx     #  <variable>.pred,  this
    mov DWORD PTR [esp+128], eax     #  <variable>.pred,  this
    mov DWORD PTR [esp+16], OFFSET FLAT:__Z1fv   #  <variable>.pred
    call    __Z1fv
    mov DWORD PTR [esp], eax     #  <anonymous>
    call    __Z1gi
    add esp, 172
    ret
--eof--

Note all of the instructions between 'sub' and 'call' can be removed without
altering the result of this code.

As an interesting aside, a commercial compiler I tried generated a sequence
of 'this' manipulations that was hundreds of instructions long, even on
full optimization.  Apparently this is not a problem unique to GCC.

I am have only vague familiarity with GCC internals, but shouldn't one of the
optimization passes be removing these instructions which have no effect?

Is there some set of compile flags--or perhaps code modifications--that I can
use to cause these extra 'this' manipulations to be emitted?

Thanks,

Aaron W. LaFramboise
awlaframboise@aol.com



More information about the Gcc mailing list