Включение HVX в Hexagon DSP с помощью встроенных инструкций

Я использовал Hexagon-SDK 3.0 для компиляции моего примера приложения для архитектуры HVX DSP. Есть много инструментов, связанных с Hexagon-LLVM доступно для использования в расположенной папке по адресу:

~/Qualcomm/HEXAGON_Tools/7.2.12/Tools/bin

Я написал небольшой пример для вычисления произведения двух массивов, чтобы убедиться, что я могу использовать HVX аппаратное ускорение. Однако, когда я создаю свою сборку, либо с -S или, с -S -emit-llvm Я не нахожу никакого определения инструкций HVX, таких как vmem, vXи т. д. Мое приложение C выполняется на hexagon-sim пока, пока мне не удастся найти способ забежать и на доску.

Насколько я понял, мне нужно определить мою часть кода HVX в C Intrinsic, но не смог адаптировать существующие примеры под свои нужды. Было бы здорово, если бы кто-нибудь смог продемонстрировать, как этот процесс может быть выполнен. Также в [Hexagon V62 Programmer's Reference Manual][1] многие из внутренних инструкций не определены.

Вот мое небольшое приложение на чистом C:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#if defined(__hexagon__)
#include "hexagon_standalone.h"
#include "subsys.h"
#endif
#include "io.h"
#include "hvx.cfg.h"


#define KERNEL_SIZE     9
#define Q               8
#define PRECISION       (1<<Q)

double vectors_dot_prod2(const double *x, const double *y, int n)
{
    double res = 0.0;
    int i = 0;
    for (; i <= n-4; i+=4)
    {
        res += (x[i] * y[i] +
                x[i+1] * y[i+1] +
                x[i+2] * y[i+2] +
                x[i+3] * y[i+3]);
    }
    for (; i < n; i++)
    {
        res += x[i] * y[i];
    }
    return res;
}


int main (int argc, char* argv[])
{
    int n;
    long long start_time, total_cycles;
/* -----------------------------------------------------*/
/*  Allocate memory for input/output                    */
/* -----------------------------------------------------*/
    //double *res  = memalign(VLEN, 4 *sizeof(double));
    const double *x  = memalign(VLEN, n *sizeof(double));
    const double *y  = memalign(VLEN, n *sizeof(double));

    if (  *x  == NULL || *y == NULL ){
        printf("Error: Could not allocate Memory for image\n");
        return 1;
}   
    #if defined(__hexagon__)
        subsys_enable();
        SIM_ACQUIRE_HVX;
    #if LOG2VLEN == 7
        SIM_SET_HVX_DOUBLE_MODE;
    #endif
    #endif

    /* -----------------------------------------------------*/                                                
    /*  Call fuction                                        */
    /* -----------------------------------------------------*/
    RESET_PMU();
    start_time = READ_PCYCLES();

    vectors_dot_prod2(x,y,n);

    total_cycles = READ_PCYCLES() - start_time;
    DUMP_PMU();



    printf("Array product of x[i] * y[i] = %f\n",vectors_dot_prod2(x,y,4));

    #if defined(__hexagon__)
        printf("AppReported (HVX%db-mode):  Array product of x[i] * y[i] =%f\n", VLEN, vectors_dot_prod2(x,y,4));
    #endif

return 0;
}

Я скомпилирую это, используя hexagon-clang:

hexagon-clang -v  -O2 -mv60 -mhvx-double -DLOG2VLEN=7 -I../../common/include -I../include -DQDSP6SS_PUB_BASE=0xFE200000 -o arrayProd.o  -c  arrayProd.c

Затем свяжите это с subsys.o (находится в DSK и уже скомпилирована) и -lhexagon создать мой исполняемый файл:

hexagon-clang -O2 -mv60 -o arrayProd.exe  arrayProd.o subsys.o -lhexagon

Наконец, запустите его, используя сим:

hexagon-sim -mv60 arrayProd.exe

1 ответ

Немного поздно, но все еще может быть полезным.

Расширения Hexagon Vector не генерируются автоматически, и текущий набор команд (начиная с 8.0 SDK) поддерживает только целочисленные манипуляции, поэтому компилятор не будет генерировать что-либо для кода C, содержащего тип "double" (это похоже на программирование SSE, вы должны вручную упаковать пакет). xmm регистрирует и использует встроенные функции SSE, чтобы делать то, что вам нужно).

Вы должны определить, что действительно требует ваше приложение. Например, если вы пишете что-то, относящееся к 3D, и вам действительно нужно рассчитать двойные (или плавающие) точечные произведения, вы можете преобразовать свои плавающие числа в 16.16 с фиксированной точкой и затем использовать инструкции (например, встроенные Си), такие какQ6_Vw_vmpyio_VwVh а также Q6_Vw_vmpye_VwVuh эмулировать умножение с фиксированной запятой.

Чтобы "включить" HVX, вы должны использовать типы, связанные с HVX, определенные в

#include <hexagon_types.h>
#include <hexagon_protos.h>

Инструкции типа 'vmem' и 'vmemu' автоматически генерируются для операторов типа

// I assume 64-byte mode, no `-mhvx-double`. For 128-byte mode use 32 int array
int values[16] = { 1, 2, 3, ..... };

/* The following line compiles to 
     {
          r4 = __address_of_values
          v1 = vmem(r4 + #0)
     }
   You can get the exact code by using '-S' switch, as you already do
*/
HVX_Vector v = *(HVX_Vector*)values;

Ваша (с фиксированной запятой) версия dot_product может считывать 16 целых чисел за раз, умножить все 16 целых чисел в паре инструкций (см. Руководство по программированию HVX62, есть совет по реализации умножения 32-битных целых чисел на 16-битное) затем перемешайте / обработайте / скомпонуйте данные и суммируйте переставленные векторы, чтобы получить точечное произведение (таким образом, вы можете вычислять 4-точечные произведения почти одновременно, а если предварительно загрузить 4 регистра HVX - то есть 16 4D-векторов - вы можете вычислить 16-точечные произведения в параллели).

Если то, что вы делаете, на самом деле является просто обработкой изображений в байтах / int, вы можете использовать определенные 16-битные и 8-битные аппаратные точечные продукты в наборе команд Hexagon вместо эмуляции doubleс и floats.

Другие вопросы по тегам