从uint32_t [16]数组到uint32_t变量序列的64位副本
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了从uint32_t [16]数组到uint32_t变量序列的64位副本相关的知识,希望对你有一定的参考价值。
我已经能够在相同大小的uint32_t阵列上使用64位副本来获得性能增益,并希望对来自uint32_t [16]数组的16个uint32_t变量序列执行相同的操作。我无法用数组替换变量,因为它会导致性能回归。
我注意到编译器将指针地址按顺序提供给一系列声明的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
", (void *) x15u64ptr);
printf("x15 %p
", (void *) &x15);
我有一个想法来创建一个数组,并使用x ??变量作为指向数组中各个元素的指针,然后在两个数组上执行64位副本,我希望以这种方式将值分配给uint32_t变量,但是编译器失败警告有关=赋值的无效ivalue。也许我在语法上做错了。使用64位memcpy替代方案和自定义64位eqxor,我已经将散列函数的性能提高了10%以上,如果我只能让它工作,我希望它能再提高5-10%。
*更新13-09-2018
我结束使用结构然后基于氖的操作。使用32位代码和memcpy,比原始性能提高20%。我还能够扩展技术以添加和保存和salsa20 / 8使用的eqxor操作。
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,arr);
更新16-10-2018如果发现这个允许联盟演员的宏......
#define UNION_CAST(x, destType)
(((union {__typeof__(x) a; destType b;})x).b)
下面是使用基于Arm的neon uint32x4_t向量的自定义类型为具有8个索引的数组创建1024位指针的示例,但是可以使用任何数据类型。这使得铸件符合严格的混叠。
uint32x4x8_t *pointer = (uint32x4x8_t *) UNION_CAST(originalpointer, uint32x4x8_t *);
无法保证变量将按声明中的顺序放入内存中。
我会用自己的工会惩罚。
#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
", mydata[!LITTLEENDIAN], mydata[LITTLEENDIAN]);
}
return 0;
}
它将在相反的方向上以完全相同的方式工作
以上是关于从uint32_t [16]数组到uint32_t变量序列的64位副本的主要内容,如果未能解决你的问题,请参考以下文章
uint8_t / uint16_t / uint32_t /uint64_t 是什么数据类型 - 大总结
uint8_t / uint16_t / uint32_t /uint64_t 这些数据类型是什么?
uint8_t / uint16_t / uint32_t /uint64_t 这些数据类型是什么?
从 uint8_t* 到 uint32_t 的无效转换 - 从 32 位架构迁移到 64 位架构时?
uint8_t / uint16_t / uint32_t /uint64_t 是什么数据类型 - 大总结,看完全明白了