I sometimes use array(s) of function pointers.Edmund wrote:Thats about the algorithm I was thinking of too. I just wonder how the inline assembly should be slower than the additional indirection.Onno Garms wrote:...
Using gcc enhancements of C++ or using inline assembly in msvc, it is possible to store the address of the lables rather then the enum. This saves the switch at the end, one can directly jump to the label. However I found the inline assembly based solution in msvc slower then with the case switch. Also I could not find a way to port to 64 bit in msvc. So I decided to stay in the C++ standard and have the case switch.
I was thinking of something like:
first a jumptable is initialized holding the addresses of all labelsthen to jump to a specific label I would have used a macro with an inlined assembly statement.Code: Select all
// init Jumptable int jmptable[64]; #define ADD_JUMPER(jmp) \ mov edx, DWORD PTR jmp \ mov [esi], edx \ add esi, 4 __asm { lea esi, jmptable ;Load address of the jmptable into esi ADD_JUMPER(PV) ADD_JUMPER(ZW) ADD_JUMPER(QS) [...] } #undef ADD_JUMPER [...]
E.g. something like this:
genmoves[piecetype][color](rank, file);
where genmoves is a 6x2 array of function pointers.
It removes all the goto branches (if you don't count calls and returns).
That approach used to be a *lot* faster than a switch if it were in a critical path, but lately the difference has pretty well vanished.
Here is a benchmark program to test your compiler for pointer, array, and switch invocation (a profiler will tell you which approach is fastest):
Code: Select all
#include <math.h>
#include <stdio.h>
typedef double (*f_t) (double);
static f_t f[] = {log, log10, sqrt, cos, cosh, exp, sin, sinh, tan, tanh, 0};
static double accum0 = 0;
static double accum1 = 0;
static double accum2 = 0;
void arr(void)
{
int i;
double d = 0;
for (i = 0; f[i]; i++) {
d += f[i] (0.5);
}
accum0 += d;
}
void poi(void)
{
f_t *flist = f;
double d = 0;
while (*flist) {
f_t ff = *flist;
d += ff(0.5);
flist++;
}
accum1 += d;
}
void swi(void)
{
int i;
double d = 0;
for (i = 0; f[i]; i++) {
switch (i) {
case 0:
d += f[0] (0.5);
break;
case 1:
d += f[1] (0.5);
break;
case 2:
d += f[2] (0.5);
break;
case 3:
d += f[3] (0.5);
break;
case 4:
d += f[4] (0.5);
break;
case 5:
d += f[5] (0.5);
break;
case 6:
d += f[6] (0.5);
break;
case 7:
d += f[7] (0.5);
break;
case 8:
d += f[8] (0.5);
break;
case 9:
d += f[9] (0.5);
break;
default:
break;
}
}
accum2 += d;
}
int main(void)
{
long i;
for (i = 0; i < 1000000; i++) {
arr();
poi();
swi();
}
printf("%.20g, %.20g, %.20g\n", accum0, accum1, accum2);
return 0;
}