我正在使用SSE2内在函数来优化我的应用程序的瓶颈,并提出以下问题:
ddata = _mm_xor_si128(_mm_xor_si128(
_mm_sll_epi32(xdata, 0x7u), _mm_srl_epi32(tdata, 0x19u)), xdata);
Run Code Online (Sandbox Code Playgroud)
在Microsoft C++编译器上,这将无法编译,因为类型__m128i
和unsigned int
(传递给_mm_sll_epi32
指令)不可互换.
为什么会这样,我应该如何传递任意unsigned int
值_mm_sll_epi32
?
_m128i
是:
typedef union __declspec(intrin_type) _CRT_ALIGN(16) __m128i {
__int8 m128i_i8[16];
__int16 m128i_i16[8];
__int32 m128i_i32[4];
__int64 m128i_i64[2];
unsigned __int8 m128i_u8[16];
unsigned __int16 m128i_u16[8];
unsigned __int32 m128i_u32[4];
unsigned __int64 m128i_u64[2];
} __m128i;
Run Code Online (Sandbox Code Playgroud) 使用SSE,您可以将内存中的单个浮点数加载到__m128的所有4个插槽中,并使用内部_mm_load1_ps()
当使用带有AVX的256位宽SIMD时,似乎没有_mm256_load1_ps()将单个浮点数从存储器加载到向量的所有8个插槽中.
为什么会遗漏这个遗漏,最好的方法是什么呢?
或者甚至更好:有没有办法将单个浮点数加载到向量的目标槽0..7?
Java API中有许多内在函数的方法,但在查看源代码时仍然有与它们相关的代码.
例如,Integer.bitCount()是一个内在函数,但如果打开Integer类文件,则可以看到它的代码.
如果编译器/ jvm不一定使用此代码,那么该代码可以用于什么目的?
我有两个__m128i
s,a
并且b
,我想要洗牌,以便在64位a
的低位64位dst
和64位的高位b
落在64位的高位64位dst
.即
dst[ 0:63] = a[64:127]
dst[64:127] = b[0:63]
Run Code Online (Sandbox Code Playgroud)
相当于:
__m128i dst = _mm_unpacklo_epi64(_mm_srli_si128i(a, 8), b);
Run Code Online (Sandbox Code Playgroud)
要么
__m128i dst = _mm_castpd_si128(mm_shuffle_pd(_mm_castsi128_pd(a),_mm_castsi128_pd(b),1));
Run Code Online (Sandbox Code Playgroud)
有没有比第一种方法更好的方法呢?第二个只是一条指令,但切换到浮点SIMD执行比第一条指令的额外指令更昂贵.
我compareAndSwap
在StackOverflow答案中找到了这段代码:
boolean CompareAndSwapPointer(volatile * void * ptr,
void * new_value,
void * old_value) {
#if defined(_MSC_VER)
if (InterlockedCompareExchange(ptr, new_value, old_value) == old_value) return false;
else return true;
#elif (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) > 40100
return __sync_bool_compare_and_swap(ptr, old_value, new_value);
#else
# error No implementation
#endif
}
Run Code Online (Sandbox Code Playgroud)
这是使用便携式快速代码的最合适方式(除了程序集内联).
此外,一个问题是这些特定builtin
方法具有不同的参数并从一个编译器返回另一个编译器的值,这可能需要一些额外的更改,如if then else
本示例中所示.
另一个问题是这些builtin
方法在机器代码级别中的行为,它们的行为是否完全相同?(例如使用相同的装配说明)
注意:另一个问题是,如果有许多支持的平台不仅仅是(Windows
和Linux
)在这个例子中.代码可能会变得非常大.
我有一个64位结构,代表几个数据,其中一个是浮点值:
struct MyStruct{
uint16_t a;
uint16_t b;
float f;
};
Run Code Online (Sandbox Code Playgroud)
我有四个这样的结构,让我们说一个 std::array<MyStruct, 4>
是否可以使用AVX对浮动成员进行数组排序MyStruct::f
?
我正在开发一个应用程序,它将-1.0到1.0范围内的Float样本转换为带符号的16位,以确保优化(SSE)例程的输出是准确的我已编写了一组运行非优化版本的测试SSE版本并比较它们的输出.
在开始之前,我已经确认SSE舍入模式设置为最接近.
在我的测试用例中,公式为:
ratio = 65536 / 2
output = round(input * ratio)
Run Code Online (Sandbox Code Playgroud)
在大多数情况下,结果是准确的,但在一个特定的输入上,我看到输入失败-0.8499908447265625
.
-0.8499908447265625 * (65536 / 2) = -27852.5
Run Code Online (Sandbox Code Playgroud)
正常代码正确地将其舍入为-27853
,但SSE代码将此舍入为-27852
.
这是使用中的SSE代码:
void Float_S16(const float *in, int16_t *out, const unsigned int samples)
{
static float ratio = 65536.0f / 2.0f;
static __m128 mul = _mm_set_ps1(ratio);
for(unsigned int i = 0; i < samples; i += 4, in += 4, out += 4)
{
__m128 xin;
__m128i con;
xin = _mm_load_ps(in);
xin = _mm_mul_ps(xin, …
Run Code Online (Sandbox Code Playgroud) movemask指令采用__m256i并返回int32,其中每个位(取决于输入向量元素类型的前4位,8位或所有32位)是相应向量元素的最高有效位.
我想做反过来:取一个32(其中只有4,8或32个最低有效位有意义),并获得__m256i,其中每个int8,int32或int64大小的块的最高有效位设置为原始位.
基本上,我想从压缩的位掩码转到可被其他AVX2指令(例如maskstore,maskload,mask_gather)用作掩码的位掩码.
我无法快速找到这样做的指令,所以我在这里问.如果没有一条具有该功能的指令,您是否可以想到一个聪明的黑客,只需很少的指令即可实现这一点?
我目前的方法是使用256元素查找表.我想在一个没有其他事情发生的循环中使用这个操作来加速它.注意,我对长多指令序列或实现此操作的小循环不太感兴趣.
我没有特定的用例; 我问这是否真的是英特尔内在函数中的设计缺陷/限制,或者我是否只是遗漏了某些内容.
如果你想将标量浮点数与现有向量相结合,那么在没有高元素归零或使用英特尔内在函数将标量广播到向量中的情况下似乎没有办法实现.我没有研究过GNU C本机向量扩展和相关的内置函数.
如果额外的内在优化了,这不会太糟糕,但它不与gcc(5.4或6.2).也没有好的方法可以使用pmovzx
或insertps
作为负载,因为他们的内在函数只采用向量args的相关原因.(并且gcc不会将标量 - >向量加载到asm指令中.)
__m128 replace_lower_two_elements(__m128 v, float x) {
__m128 xv = _mm_set_ss(x); // WANTED: something else for this step, some compilers actually compile this to a separate insn
return _mm_shuffle_ps(v, xv, 0); // lower 2 elements are both x, and the garbage is gone
}
Run Code Online (Sandbox Code Playgroud)
gcc 5.3 -march = nehalem -O3输出,启用SSE4.1并调整该Intel CPU :(没有SSE4.1会更糟;多个指令将上层元素归零).
insertps xmm1, xmm1, 0xe # pointless zeroing of upper elements. shufps only reads the low element of xmm1 …
Run Code Online (Sandbox Code Playgroud) 除了测试单个寄存器是否为零之外,您还可以使用SSE4.1ptest
做什么?
您是否可以使用SF和CF的组合来测试有关两个未知输入寄存器的任何有用信息?
什么是PTEST有益?您认为检查打包比较的结果(如PCMPEQD或CMPPS)会有好处,但至少在Intel CPU上,使用PTEST + JCC比使用PMOVMSK(B)进行比较和分支的成本更高./PS/PD)+宏融合CMP + JCC.