Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way to allow compiler to optimize away multiple calls to an extern function?

I am constructing a C++ interface to a C library similar to this:

extern "C" {

typedef struct CFooStruct *CFoo;

int CFoo_getLength(CFoo);

// other functions

}

Currently I have

class MyFoo {
    CFoo foo;
    int len;
public:
    MyFoo(CFoo foo) : foo(foo), len(CFoo_getLength(foo)) { }

    int length() const { return len; } // inline function

    // other functions
};

The length is retrieved in the constructor and cached so that MyFoo::length() can be called repeatedly in a tight loop without a performance penalty.

When using the C interface directly, one would manually retrieve the length once if needed, then use it repeatedly. If the length of a CFoo is not needed, then we would just never call CFoo_getLength().

The C++ interface is meant to be simpler to use, and let the user just use length() without needing to think about performance. The disadvantage of the above implementation is that it always calls CFoo_getLength() during the creation of every single MyFoo object, regardless of whether it will actually be used in the program.

Even though all member functions of MyFoo are inline, I believe the compiler won't optimize away the call to CFoo_getLength() because it has no way of knowing that this function has no side effects.

Question: Is there a way to implement this so that CFoo_getLength() will be called only if the length is actually used in the program? (And that it is never called more than once for a MyFoo object?) Is there a way to allow the compiler to optimize away the CFoo_getLength() call (if it is otherwise smart enough to deduce that it is not needed)?


One way would be to have a boolean flag in the class indicating whether the length has already been retrieved:

class MyFoo2 {
    CFoo foo;

    bool lenKnown = false;
    int len;
public:
    MyFoo2(CFoo foo) : foo(foo) { }

    int length() {
        if (!lenKnown) {
            len = CFoo_getLength(foo);
            lenKnown = true;
        }
        return len;
    }
};

But this is a runtime solution that makes MyFoo bigger and leads to extra computation within MyFoo::length(). I was wondering if there is a compile-time solution.

like image 663
Szabolcs Avatar asked Oct 17 '22 04:10

Szabolcs


1 Answers

You can apply the pure function attribute to mark CFoo_getLength as pure:

__attribute__ ((pure))
int CFoo_getLength(CFoo);

As you found, and to my C++-inexperienced surprise, it allows both gcc and clang to optimize your original code. Nice!

like image 62
Ry- Avatar answered Nov 28 '22 09:11

Ry-