在过去的几年里,我一直在做很多SIMD编程,大多数时候我一直依赖于编译器内部函数(例如用于SSE编程的函数)或编程汇编来实现真正的俏皮东西.但是,到目前为止,我几乎找不到任何内置支持SIMD的编程语言.
现在显然有一些着色器语言,如HLSL,Cg和GLSL,它们对这种东西有本机支持,但是,我正在寻找能够至少在没有自动向量化的情况下编译到SSE但内置支持向量操作的东西.这种语言存在吗?
这是(部分)Cg着色器的一个例子,它做了一个聚光灯,在语法方面,这可能是我最接近我正在寻找的.
float4 pixelfunction(
output_vs IN,
uniform sampler2D texture : TEX0,
uniform sampler2D normals : TEX1,
uniform float3 light,
uniform float3 eye ) : COLOR
{
float4 color = tex2D( texture, IN.uv );
float4 normal = tex2D( normals, IN.uv ) * 2 - 1;
float3 T = normalize(IN.T);
float3 B = normalize(IN.B);
float3 N =
normal.b * normalize(IN.normal) +
normal.r * T +
normal.g * B;
float3 V = normalize(eye - IN.pos.xyz);
float3 L = normalize(light - IN.pos);
float3 …Run Code Online (Sandbox Code Playgroud) 我将使用什么内在函数来对x86_64上的以下内容进行矢量化(如果它甚至可以进行矢量化)?
double myNum = 0;
for(int i=0;i<n;i++){
myNum += a[b[i]] * c[i]; //b[i] = int, a[b[i]] = double, c[i] = double
}
Run Code Online (Sandbox Code Playgroud) 我正在使用SSE内在函数为英特尔x86 Nehalem微架构优化一些代码.
我的程序的一部分计算4个点产品,并将每个结果添加到阵列的连续块中的先前值.进一步来说,
tmp0 = _mm_dp_ps(A_0m, B_0m, 0xF1);
tmp1 = _mm_dp_ps(A_1m, B_0m, 0xF2);
tmp2 = _mm_dp_ps(A_2m, B_0m, 0xF4);
tmp3 = _mm_dp_ps(A_3m, B_0m, 0xF8);
tmp0 = _mm_add_ps(tmp0, tmp1);
tmp0 = _mm_add_ps(tmp0, tmp2);
tmp0 = _mm_add_ps(tmp0, tmp3);
tmp0 = _mm_add_ps(tmp0, C_0n);
_mm_storeu_ps(C_2, tmp0);
Run Code Online (Sandbox Code Playgroud)
请注意,我通过使用4个临时xmm寄存器来保存每个点积的结果.在每个xmm寄存器中,结果被放入相对于其他临时xmm寄存器的唯一32位,这样最终结果如下所示:
tmp0 = R0-零 - 零
tmp1 =零-R1-零
tmp2 =零 - 零 - 零
tmp3 =零 - 零 - R3
我将每个tmp变量中包含的值组合成一个xmm变量,并将它们与以下说明相加:
tmp0 = _mm_add_ps(tmp0, tmp1);
tmp0 = _mm_add_ps(tmp0, tmp2);
tmp0 = _mm_add_ps(tmp0, tmp3);
Run Code Online (Sandbox Code Playgroud)
最后,我将包含点积的所有4个结果的寄存器添加到数组的连续部分,以便数组的索引以点积递增,就像这样(C_0n是数组中当前要更新的4个值) ; C_2是指向这4个值的地址):
tmp0 = _mm_add_ps(tmp0, …Run Code Online (Sandbox Code Playgroud) 大家好:)
我试图抓住一些关于浮点,SIMD /数学内在函数和gcc的快速数学标志的概念.更具体地说,我在x86 cpu上使用MinGW和gcc v4.5.0.
我现在已经搜索了一会儿,这就是我(我想)我现在所理解的:
当我没有标志编译时,任何fp代码将是标准x87,没有simd内在函数,math.h函数将从msvcrt.dll链接.
当我使用mfpmath,mssen和/或march使得mmx/sse/avx代码被启用时,gcc实际上只有在我还指定一些优化标志时才使用simd指令,如On或ftree-vectorize.在这种情况下,内部函数是由gcc自动选择的,并且一些数学函数(我仍在谈论math.h上的标准数学函数)将成为内在函数或通过内联代码进行优化,其他函数仍将来自msvcrt. DLL.如果我没有指定优化标志,这会改变吗?
当我使用特定的simd数据类型(那些可用作gcc扩展,如v4si或v8qi)时,我可以选择直接调用内部函数,或者再次将自动决定留给gcc.如果我没有通过正确的标志启用simd指令,Gcc仍然可以选择标准的x87代码.同样,如果我没有指定优化标志,这会改变吗?
如果我的任何陈述错误,请纠正我:p
现在的问题是:
感谢任何想要帮助的人:D
我想用SSE4乘以一个__m128i带有16个无符号8位整数的对象,但我只能找到一个乘以16位整数的内在函数.有没有这样的_mm_mult_epi8?
我想使用SSE将无符号短数组转换为float.让我们说吧
__m128i xVal; // Has 8 16-bit unsigned integers
__m128 y1, y2; // 2 xmm registers for 8 float values
Run Code Online (Sandbox Code Playgroud)
我希望y1中的前4个uint16和y2中的下一个4 uint16.需要知道哪些内在使用.
我编写了该函数int compare_16bytes(__m128i lhs, __m128i rhs),以便使用SSE指令比较两个16字节数:该函数返回执行比较后相等的字节数.
现在我想使用上面的函数来比较任意长度的两个字节数组:长度可能不是16字节的倍数,所以我需要处理这个问题.我怎样才能完成下面这个功能的实现?我怎样才能改进下面的功能?
int fast_compare(const char* s, const char* t, int length)
{
int result = 0;
const char* sPtr = s;
const char* tPtr = t;
while(...)
{
const __m128i* lhs = (const __m128i*)sPtr;
const __m128i* rhs = (const __m128i*)tPtr;
// compare the next 16 bytes of s and t
result += compare_16bytes(*lhs,*rhs);
sPtr += 16;
tPtr += 16;
}
return result;
}
Run Code Online (Sandbox Code Playgroud) 我应该计算__m128i寄存器的设置位数.特别是,我应该使用以下方法编写两个能够计算寄存器位数的函数.
是否有可以完全或部分执行上述操作的内在功能?
哪些指令用于比较由4*32位浮点值组成的两个128位向量?
是否存在将双方的NaN值视为相等的指令?如果不是,提供反身性的解决方案(即NaN等于NaN)的性能影响有多大?
我听说,与IEEE语义相比,确保反身性会产生显着的性能影响,因为NaN不等于自己,我想知道这种影响是否会很大.
我知道您在处理浮点值时通常需要使用epsilon比较而不是精确的质量.但是这个问题是关于完全相等的比较,例如,您可以使用它来消除哈希集中的重复值.
要求
+0并且-0必须相等.NaN 必须与自己相等.true如果两个向量中的所有四个float元素相同,则结果应为布尔值,如果至少一个元素不同,则结果为false.其中true由标量整数1和falseby表示0.测试用例
(NaN, 0, 0, 0) == (NaN, 0, 0, 0) // for all representations of NaN
(-0, 0, 0, 0) == (+0, 0, 0, 0) // equal despite different bitwise representations
(1, 0, 0, 0) == (1, 0, 0, 0)
(0, 0, 0, 0) != (1, 0, 0, 0) // at least one different element => not equal …Run Code Online (Sandbox Code Playgroud) 我有一个行的行数组(~20 cols x~1M行),我需要一次从两个__m256寄存器中提取两列.
...a0.........b0......
...a1.........b1......
// ...
...a7.........b7......
// end first __m256
Run Code Online (Sandbox Code Playgroud)
一个天真的方法是这样做
__m256i vindex = _mm256_setr_epi32(
0,
1 * stride,
2 * stride,
// ...
7 * stride);
__m256 colA = _mm256_i32gather_ps(baseAddrColA, vindex, sizeof(float));
__m256 colB = _mm256_i32gather_ps(baseAddrColB, vindex, sizeof(float));
Run Code Online (Sandbox Code Playgroud)
但是,我想知道我是否会通过a0, b0, a1, b1, a2, b2, a3, b3在一个中检索gather而a4, b4, ... a7, b7在另一个中获得更好的性能,因为它们在内存中更接近,然后对它们进行反交错.那是:
// __m256 lo = a0 b0 a1 b1 a2 b2 a3 b3 // load proximal elements
// __m256 hi …Run Code Online (Sandbox Code Playgroud)