Цифровые раскопки: 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 (ну а где ж ещё-то?) полезный пример. Итак требуется:

  1. Выполнить объявление функции (указателя на функцию) в *.h-файле.

  2. Выполнить описание функции (указателя на функцию) в *.cpp-файле значением по умолчанию.

  3. В функции 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-инструкции раскладывать неплохо (уж всяко лучше меня ;) ).