Reputation:
I have a performance critical inline function. It generates some data, based on a parameter. I want the compiler to optimize the data generation for all invocations, where the parameter is known at compile-time. The problem is that I can't force the compiler to put the optimized data out of the stack to a static constant, since marking the data static
would break the case when parameter is not a compile-time constant. Having constant data on the stack hurts performance. Is there a way to deduce (maybe using templates/boost::enable_if), that the parameter is a compile-time constant and choose appropriate implementation of the data generation?
CLARIFICATION
Basically I have something like the following:
struct Data {
int d_[16];
};
inline Data fun(int param)
{ //param can sometimes be a compile-time constant
... //generate the data
Data res = {gen0, gen2, gen3, ..., gen15}; //put the data into result
return res;
}
So when param
isn't compile-time constant, we just generate all the data and return.
When param
is known, the compiler can optimize data generation out. But then it fails to optimize the following line out and generates a lot of code, that just sets res
members to known data (the data is embedded to program code). I want the compiler to create a static constant, and then copy it to the return object (that is faster than executing much code with embedded data). Since this is an inline function, even the copy may be not necessary.
Disclaimer
This question is not the same as How to use different overload of an inline function, depending on a compile time parameter?. This is more generic problem.
Upvotes: 5
Views: 488
Reputation: 1002
This is not portable, but on GCC and possibly Clang there is a __builtin_constant_p
compiler function. This lets you ask the compiler if it knows the value of a variable during compile time. You can use it like this:
void f(int arg) {
if (__builtin_constant_p(arg) && arg == 0) {
// Handle case where arg is 0 AND known at compile time.
} else {
// Generic code.
}
}
With this, the compiler will not generate the code in the else
branch if arg
is both known at compile time and is 0.
A useful trick to make this more portable might be to use a bit of macro hackery.
#ifdef __GNUC__
# define CONSTANT_P(x) __builtin_constant_p(x)
#else
# define CONSTANT_P(x) 0
#endif
Add other compilers that support something similar to this as needed and you are now able to use this with no extra overhead on compilers that don't support this. That is those compilers, if they are worth anything at all, will eliminate the CONSTANT_P
branches leaving only the generic code.
Upvotes: 1
Reputation: 96241
Did you actually profile your code and prove that passing constants to your (inline?) function(s) is the bottleneck?
If you did do the profiling, then you're going to have to help the compiler figure this one out, as there's no way to do it automatically. You'll have to manually call the template version of the function when you know the constant and the normal version otherwise.
Upvotes: 1
Reputation: 146910
If the function is inlined, then the compiler will perform constant folding optimizations where appropriate, when it inlines the function, assuming that you have a fairly reasonable compiler.
Upvotes: 1
Reputation: 72271
So it sounds like you have:
template <int N> myfunc_const_N() { /*...*/ }
inline myfunc_var_N(int N);
and you want to be able to type myfunc(n);
and have the compiler call myfunc_const_N<n>();
if valid or myfunc_var_N(n);
if not?
My guess is this impossible, but that's a difficult thing to prove.
But would it really gain you much if you could? How often do you not know at code-writing time whether a given expression is a compile-time constant or not? Why not just use the template version yourself if you do have a constant and the function parameter version if you don't?
Upvotes: 1
Reputation: 210427
I don't believe there is any way to do that; it's the compiler's responsibility to optimize the calls, not the language's... so there's no portable way to do that. :\
Upvotes: 2