Emil Loer dot com

Const function substitution in Clang

Posted on July 17, 2011

I am currently working on a synthesizer for the iPad. An important thing here is that the sound rendering callback must be as fast as possible so that you can reduce the audio buffer size and thus get a lower latency.

This means that, if you want to do anything more than a stupid non-bandlimited monosynth with horrible sound quality (such as the currently trending free Core Synth, but there are many others), you will have to spend a lot of time optimizing the renderer. This is especially important when you want to build a polyphonic synthesizer, where rendering time scales linear with the amount of concurrently playing notes.

Recently I discovered that Clang optimizes differently depending on whether you use single or double precision floating point numbers. The result of this is something you would not expect. Today I want to focus on a single aspect which might slow a lot of things down. Suppose you have this piece of code:

double y = exp(123.456);

Any sane programmer would convert this to machine code by evaluating the exponential function during compilation and writing down a single load-constant operation in the compiled program. In other words, the compiler would treat the exponential function as a const function. That is a function that produces an output value that only depends on the input, meaning that there are no side effects and every invocation of the function with a constant input value will always result in the same output value.

However, it turns out that Clang can only optimize away some of these functions when they are called with constant parameters. So I’ve made a little table which tells you what functions you can safely use with constants. The functions that have a “no” will be compiled to a normal function call even when the input is a constant, so they should be replaced with precomputed constants if possible.

So here’s the table. Measurements were done using the Apple LLVM 3.0 compiler which is found in the XCode 4.2 beta.

Function float double
sin yes yes
cos yes yes
tan no yes
asin no no
acos no no
atan no yes
atan2 no yes
sinh no yes
cosh no yes
tanh no yes
exp no yes
exp2 no no
expm1 no no
log no yes
log2 no no
log10 no yes
log1p no no
fmod no yes
fabs yes yes
sqrt yes yes
pow no no
ceil no yes
floor no yes
rint no no
round no no
trunc no no

When you write your own functions you can give Clang a hint that this function is a const function and has no side effects. This helps Clang to optimize away instances which are called with constants. In order to help Clang you have to modify your function declaration to be as follows:

int __attribute__ ((const)) myfunction(int arg) {
    return 42 + arg;
}

This trick originates from GCC, so more documentation about function attributes can be found in the GCC documentation.