我已经读过有关将C / C ++内在类型用于SIMD功能(如MMX和SSE)的所有内容,这些都表明您应该将它们用作不透明类型,而不是直接引用内部结构。
但是,当我看许多示例时,它们的工作方式是(指向)原始数据的指针(明确对齐),然后在进行工作之前将它们重新解释为内部类型的指针。但是,通过使用指向内部类型的指针,尤其是在将其他数据作为这些类型的别名时,您是否没有违反该规则?
我想知道我是否可以在GPU代码中使用SIMD内在函数,如CUDA内核或openCL代码.那可能吗?
在gcc 4.1.2中,vec_ld()在CPU MPC74XX板上不能正常工作。
float temp[4];
__vector float Src;
Src = (__vector float)vec_ld(0, temp);
Run Code Online (Sandbox Code Playgroud)
但是,如果float变量对齐到16个字节,则它可以正常工作:
float temp[4] __attribute__((aligned(16)));
Run Code Online (Sandbox Code Playgroud)
这是设计使然吗?
我想将双精度值的向量转换为char.我必须制作两种不同的方法,一种用于SSE2,另一种用于AVX2.
我开始使用AVX2.
__m128i sub_proc(__m256d& in)
{
__m256d _zero_pd = _mm256_setzero_pd();
__m256d ih_pd = _mm256_unpackhi_pd(in,_zero_pd);
__m256d il_pd = _mm256_unpacklo_pd(in,_zero_pd);
__m128i ih_si = _mm256_cvtpd_epi32(ih_pd);
__m128i il_si = _mm256_cvtpd_epi32(il_pd);
ih_si = _mm_shuffle_epi32(ih_si,_MM_SHUFFLE(3,1,2,0));
il_si = _mm_shuffle_epi32(il_si,_MM_SHUFFLE(3,1,2,0));
ih_si = _mm_packs_epi32(_mm_unpacklo_epi32(il_si,ih_si),_mm_unpackhi_epi32(il_si,ih_si));
return ih_si;
}
__m128i proc(__m256d& in1,__m256d& in2)
{
__m256d _zero_pd = _mm_setzeros_pd();
__m128i in1_si = sub_proc(in1);
__m128i in2_si = sub_proc(in2);
return _mm_packs_epi16(in1_si,in2_si);
}
int main()
{
double input[32] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32};
char output[32] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
char check[8];
double* ibeg = input;
char* obeg = output;
for(int …Run Code Online (Sandbox Code Playgroud) 我正在对每个像素执行32次比较的图像执行人口普查变换.我可以有效地生成一个0x0100010100010100的256位向量...其中每个8位对应于0x00或0x01.该载体在下面标识为"比较".我需要折叠这个256位向量来生成一个32位的汉明字符串.数组'census'是我存储8位比较的地方.请注意,此时我并不关心汉明距离,我只对尽快生成字符串感兴趣.我有AVX2可供我使用.我目前的代码:
uint8_t* census = (uint8_t*) _mm_malloc(sizeof(int)*8,32);
...
_mm256_storeu_si256((__m256i*) census, comparisons);
uint32_t hammingString = (uint32_t) (census[0] +
(census[1] << 1) +
(census[2] << 2) +
...
(census[31] << 31));
Run Code Online (Sandbox Code Playgroud) 我有以下联盟:
union problem {
int i;
int *v;
};
Run Code Online (Sandbox Code Playgroud)
在我的系统上int是4个字节,int*而是8.我有一个数组,其中有10个这样的结构.在某段代码中,我碰巧知道数组的所有成员都使用int了union.我需要将这些int复制到一个int数组中.现在,如果源数组是一个int数组,我可以memcpy用来快速复制数据.
是否可以保证int存储在联合的低或高内存中?我希望能够在不进行迭代的情况下复制数据,因此我在考虑使用SIMD和shuffle进行循环.要做到这一点,我必须知道int实际上在union中的位置,我猜这是特定于实现的.
我有一个__m128i充满32位整数的寄存器。我想从寄存器中提取第4个元素。
例如,如果
int extract;
__m128i register = _mm_set_epi32(3,2,1,0);
Run Code Online (Sandbox Code Playgroud)
然后我想“提取”值为3。
似乎_mm_extract_epi32()应该可以完成工作。但是,它有一个imm8参数。
图: 在英特尔网站上的描述
我只是不了解imm8工作方式(或者在这种情况下会工作)。有人可以详细说明如何使用imm8作为参数吗?
我正在使用Fasm(程序集),我正在寻找这些内在指令的SSE2汇编指令:
_mm_set1_epi8
_mm_cmpeq_epi8
_mm_movemask_epi8
Run Code Online (Sandbox Code Playgroud)
我从哪里得到它们(网站,pdf ......)?
问题:movaps给我一个分段错误.
上下文:x86-64指令vmovaps设计用于Core i系列处理器(我运行此系统)上的AVX寄存器.AVX寄存器的宽度是SSE寄存器的两倍(分别为256和128位).指令vmovaps应将对齐的浮点值(32位)的向量移动到指定的ymm寄存器中.
可能的原因:源数据的对齐特别重要,因为错误对齐的数据是分段错误的来源.但是,即使我对齐了数据,我自己也遇到了分段错误.
segment .data
align 16
xs:
dd 0.0
dd 1.1
dd 2.2
dd 3.3
dd 4.4
dd 5.5
dd 6.6
dd 7.7
align 16
ys:
dd 8.8
dd 7.7
dd 6.6
dd 5.5
dd 4.4
dd 3.3
dd 2.2
dd 1.1
segment .text
global main
main:
push rbp
mov rbp, rsp
; Move eight 32-bit floats from "xs" into ymm0
vmovaps ymm0, [xs]
; Move …Run Code Online (Sandbox Code Playgroud) 我目前正在进行科学模拟(引力体)。我首先使用朴素的单线程算法编写了该代码,并且对于少量粒子而言,该代码的性能令人满意。然后,我对该算法进行了多线程处理(令人尴尬的是,它是并行的),程序花了大约3倍的时间。以下是具有相似属性并输出到/ tmp中的文件的琐碎算法的最小,完整,可验证的示例(该示例旨在在Linux上运行,但C ++也是标准的)。请注意,如果您决定运行此代码,它将生成152.62MB的文件。输出数据是为了防止编译器从程序中优化计算。
#include <iostream>
#include <functional>
#include <thread>
#include <vector>
#include <atomic>
#include <random>
#include <fstream>
#include <chrono>
constexpr unsigned ITERATION_COUNT = 2000;
constexpr unsigned NUMBER_COUNT = 10000;
void runThreaded(unsigned count, unsigned batchSize, std::function<void(unsigned)> callback){
unsigned threadCount = std::thread::hardware_concurrency();
std::vector<std::thread> threads;
threads.reserve(threadCount);
std::atomic<unsigned> currentIndex(0);
for(unsigned i=0;i<threadCount;++i){
threads.emplace_back([¤tIndex, batchSize, count, callback]{
unsigned startAt = currentIndex.fetch_add(batchSize);
if(startAt >= count){
return;
}else{
for(unsigned i=0;i<count;++i){
unsigned index = startAt+i;
if(index >= count){
return;
}
callback(index);
}
}
});
}
for(std::thread &thread : threads){ …Run Code Online (Sandbox Code Playgroud)