Цифровые раскопки: SIMD, x86-код и указатели на функции¶
Когда я пытался запускать свежеоткомпилированные исходники gps-sdr, то одной из первых проблем был нерабочий код SSE-функций.
Вообще-то это странно! Кажется, тогда, давным-давно такой проблемы не было. А тут вызов этих функций (функций с префиксом „sse_“) приводил к Segfault. Ещё предстоит разобраться в причинах этого. Впрочем ad hoc решением было использование аналогичных функций, написанных на чистом C++ (без каких-либо ассемблерных вставок) и имеющих префик „x86_“.
На скорую руку и так сошло. Но во время исследований исходников gps-sdr была найдена интересная функция void Init_SIMD() в файле cpuid.cpp.
1void Init_SIMD()
2{
3 // if(CPU_SSE3())
4 // {
5 // simd_add = &sse_add;
6 // simd_sub = &sse_sub;
7 // simd_mul = &sse_mul;
8 // simd_dot = &sse_dot;
9 //
10 // simd_conj = &sse_conj;
11 // simd_cacc = &sse_cacc;
12 // simd_cmul = &sse_cmul;
13 // simd_cmuls = &sse_cmuls;
14 // simd_cmulsc = &sse_cmulsc;
15 // }
16 // else
17 // {
18 // simd_add = &x86_add;
19 // simd_sub = &x86_sub;
20 // simd_mul = &x86_mul;
21 // simd_dot = &x86_dot;
22 //
23 // simd_conj = &x86_conj;
24 // simd_cacc = &x86_cacc;
25 // simd_cmul = &x86_cmul;
26 // simd_cmuls = &x86_cmuls;
27 // simd_cmulsc = &x86_cmulsc;
28 //
29 // }
30 //
31 // simd_cmag = &x86_cmag;
32 // simd_max = &x86_max;
33}
Задумка - хорошая! Но почему-то код закомментирован. Что ж почему бы не реализовать эту задумку?! Указатели на функции - штука полезная, хотя и не самая тривиальная (по крайней мере для меня). Разбираясь, как реализовать задумку автора, нашёл на stackoverflow (ну а где ж ещё-то?) полезный пример. Итак требуется:
Выполнить объявление функции (указателя на функцию) в *.h-файле.
Выполнить описание функции (указателя на функцию) в *.cpp-файле значением по умолчанию.
В функции Init_SIMD() выполнить переназначение указателя на функцию (при необходимости).
Для простоты сокращу пример до использования одной функции.
В файле simd.h выполняется объявление указателя на функцию по имени simd_add. Этот указатель в зависимости от потребностей будет указывать либо на функцию void sse_add(int16 *A, int16 *B, int32 cnt), либо на функцию void x86_add(int16 *A, int16 *B, int32 cnt).
1extern void (*simd_add)(int16 *A, int16 *B, int32 cnt);
В файле cpuid.cpp выполняется определение указателя на функцию и при необходимости его переопределение в функции Init_SIMD(). Изначальное определение требуется, чтобы указатель на функцию сразу же был бы проинициализирован значением по умолчанию.
1void (*simd_add)(int16 *A, int16 *B, int32 cnt) = &x86_add;
2
3void Init_SIMD()
4 {
5
6 if (0) ///if(CPU_SSE3())
7 {
8 void (*simd_add)(int16 *A, int16 *B, int32 cnt) = &sse_add; //simd_add = &sse_add;
9 }
10 else
11 {
12 void (*simd_add)(int16 *A, int16 *B, int32 cnt) = &x86_add; //simd_add = &x86_add;
13 }
14
15}
Ну а так как в причинах неработоспособности SSE-функций ещё только предстоит разобраться, то вместо условия if(CPU_SSE3()) - стоит просто if (0).
P.S. Надо бы ещё исследовать код, который генерирует gcc с соответствующими опциями. Есть предположение, что сам компилятор умеет в SIMD-инструкции раскладывать неплохо (уж всяко лучше меня ;) ).