64-битная копия из массива uint32_t [16] в последовательность переменных uint32_t - PullRequest
0 голосов
/ 07 сентября 2018

Я смог использовать 64-битную копию на равных по размеру массивах uint32_t для повышения производительности и хотел сделать то же самое для последовательности из 16 переменных uint32_t из массива uint32_t [16]. Я не могу заменить переменные массивом, поскольку это приводит к снижению производительности.

Я заметил, что компилятор выдает адреса указателей последовательно последовательности объявленных переменных uint32_t, в обратном порядке последняя переменная получает самый низкий адрес и увеличивается на 4 байта до первой объявленной переменной. Я попытался использовать начальный адрес назначения последней переменной и преобразовал его в указатель uint64_t *, но это не сработало. Однако указатели для массива uint32_t [16] находятся в последовательности.

Вот пример моей последней попытки.

uint32_t x00,x01,x02,x03,x04,x05,x06,x07,x08,x09,x10,x11,x12,x13,x14,x15;
uint64_t *Bu64ptr = (uint64_t *) B;
uint64_t *x15u64ptr = (uint64_t *) &x15;

/* This is an inline function that does 64-bit eqxor on two uint32_t[16] 
& stores the results in uint32_t B[16]*/
salsa8eqxorload64(B,Bx);

/* Trying to 64-bit copy here */
*x15u64ptr++ = *Bu64ptr++;
*x15u64ptr++ = *Bu64ptr++;
*x15u64ptr++ = *Bu64ptr++;
*x15u64ptr++ = *Bu64ptr++;
*x15u64ptr++ = *Bu64ptr++;
*x15u64ptr++ = *Bu64ptr++;
*x15u64ptr++ = *Bu64ptr++;
*x15u64ptr++ = *Bu64ptr++;

Я преследую невозможное или мое отсутствие навыков мешает мне снова? Я проверил значение адреса указателя x15 и x15u64ptr, и они совершенно разные, используя метод ниже.

printf("x15u64ptr %p\n", (void *) x15u64ptr);
printf("x15 %p\n", (void *) &x15);

У меня была одна идея создать массив и использовать x ?? переменные в качестве указателей на отдельные элементы в массиве, а затем выполняют 64-битное копирование обоих массивов, которые, как я надеялся, таким образом присвоили бы значения переменным uint32_t, но получили предупреждение о сбое компилятора о недопустимом значении ivalue для присваивания =. Может я что-то не так делаю в синтаксисе. Используя 64-битные альтернативы memcpy и пользовательский 64-битный eqxor, я увеличил производительность функции хеширования более чем на 10% и ожидаю, что это даст еще 5-10% улучшение, если я только смогу заставить его работать.

* ОБНОВЛЕНИЕ 13-09-2018

Я закончил использовать структуру, а затем неоновую операцию. Повышение производительности на 20% по сравнению с оригиналом с использованием 32-битного кода и memcpy. Я также смог расширить технику для добавления, сохранения и обработки операций, которые использует salsa20 / 8.

struct XX
{
uint32_t x00, x01, x02, x03, x04, x05, x06, x07, x08, x09, x10, x11, x12,x13,x14,x15;
} X;

//dst & src must be uint32_t[32]. Note only 8 operations, to account for "128-bit" though neon really only does 64-bit at a time.
static inline void memcpy128neon(uint32_t * __restrict dst, uint32_t * __restrict src)
{
uint32x4_t *s1 = (uint32x4_t *) dst;
uint32x4_t *s2 = (uint32x4_t *) src;

*s1++ = *s2++;*s1++ = *s2++;*s1++ = *s2++;*s1++ = *s2++;*s1++ = *s2++;*s1++ = *s2++;*s1++ = *s2++;*s1++ = *s2++;
}

Тогда вызывай вот так ... memcpy128neon (& X.x00, обр);

Обновление 16-10-2018 Если найден этот макрос, который позволяет Union Casting ...

#define UNION_CAST(x, destType) \
   (((union {__typeof__(x) a; destType b;})x).b)

Вот пример создания 1024-битного указателя с использованием пользовательского типа на основе неонового вектора Arm uint32x4_t для массива с 8 индексами, но можно использовать любой тип данных. Это делает приведение в соответствие со строгим псевдонимом.

uint32x4x8_t *pointer = (uint32x4x8_t *) UNION_CAST(originalpointer, uint32x4x8_t *);

1 Ответ

0 голосов
/ 07 сентября 2018

Нет гарантии, что переменные будут помещены в память в порядке, указанном в объявлении.

Я бы использовал союз, наказывающий себя.

#include <stdio.h>
#include <stdint.h>
#include <string.h>

#define SOMETHING   (uint64_t *)0x12345676   // only
#define LITTLEENDIAN 1

typedef union
{
    uint32_t u32[2];
    uint64_t u64;
}data_64;

int main()
{
    uint64_t *Bu64ptr = SOMETHING;

    data_64 mydata[10];

    //you can copy memory
    memcpy(mydata, Bu64ptr, sizeof(mydata));

    //or just loop
    for(size_t index = 0; index < sizeof(mydata) / sizeof(mydata[0]); index++)
    {
        mydata[index].u64 = *Bu64ptr++;
    }

    for(size_t index = 0; index < sizeof(mydata) / sizeof(mydata[0]); index++)
    {   
        printf("Lower word = %x, Upper word = %x\n", mydata[!LITTLEENDIAN], mydata[LITTLEENDIAN]);
    }    

    return 0;
}

Он будет работать точно так же в противоположном направлении

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...