假设我有两个名为IN和MASK的二进制输入。实际字段大小可能是32到256位,具体取决于用于完成任务的指令集。两个输入都会更改每个呼叫。
Inputs:
IN = ...1100010010010100...
MASK = ...0001111010111011...
Output:
OUT = ...0001111010111000...
Run Code Online (Sandbox Code Playgroud)
编辑:来自一些评论讨论的另一个示例结果
IN = ...11111110011010110...
MASK = ...01011011001111110...
Output:
OUT = ...01011011001111110...
Run Code Online (Sandbox Code Playgroud)
我想获得1位IN所在的MASK的连续相邻1位。(是否有这种操作的总称?也许我没有适当地称呼我的搜索词。)我正在尝试找到一种更快的方法。我愿意使用任何x86或x86 SIMD扩展,这些扩展都可以在最少的cpu周期内完成。首选更广泛的数据类型SIMD,因为它将使我能够立即处理更多数据。
我想出的最好的天真解决方案是以下伪代码,该伪代码手动向左移,直到没有更多匹配的位,然后向右重复:
// (using the variables above)
testL = testR = OUT = (IN & MASK);
LoopL:
testL = (testL << 1) & MASK;
if (testL != 0) {
OUT = OUT | testL;
goto LoopL;
}
LoopR:
testR = (testR >> 1) & MASK;
if (testR != 0) {
OUT = OUT | testR;
goto …Run Code Online (Sandbox Code Playgroud) 在最新的 x86 架构上,存储到加载转发失败的成本是多少?
特别是,存储到加载转发会失败,因为加载部分与较早的存储重叠,或者因为较早的加载或存储跨越某些导致转发失败的对齐边界。
当然存在延迟成本:它有多大?是否还存在吞吐量成本,例如,失败的存储到加载转发是否使用了其他加载和存储甚至其他非内存操作无法使用的额外资源?
当存储的所有部分都来自存储缓冲区时,与混合存储缓冲区和 L1 的情况相比,是否有区别?
我没有特定的用例; 我问这是否真的是英特尔内在函数中的设计缺陷/限制,或者我是否只是遗漏了某些内容.
如果你想将标量浮点数与现有向量相结合,那么在没有高元素归零或使用英特尔内在函数将标量广播到向量中的情况下似乎没有办法实现.我没有研究过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) (编者注:这个问题最初是: 一个人应该如何访问__m128i对象的m128i_i8成员或一般成员?,试图对GCC的定义使用MSVC特定的方法__m128i。但这是一个XY问题,并且已被接受。答案是关于XY问题。另一个答案确实回答了这个问题。)
我意识到Microsoft建议不要直接访问这些对象的成员,但是我需要对其进行设置,因此非常缺乏文档。
我继续收到错误“我在'(我的var名)'中请求成员'm128i_i8',它是非类类型'wirelabel {aka __vector(2)long long int}'”的错误,因为我已包含所有正确的标头,并且可以识别__m128i变量。
注意1:wirelabel是__m128i的typedef,即在标头中存在
typedef __m128i wirelabel
Run Code Online (Sandbox Code Playgroud)
注意2:使用注释 1的原因在下面的其他问题中进行了解释: tbb :: cache_aligned_allocator:通过__m128i获取“对成员的请求...非类类型的请求”。用户错误或错误?
注意3:我正在使用编译器g ++
注意4:以下问题不能回答我的问题,但会讨论相关信息为什么不直接访问__m128i字段?
我也知道有一个_mm_set_epi8函数,但是它要求您一次设置所有8位部分,而这对我来说目前不是一个选择。
编辑:有人问我为什么我需要访问__m128i对象的16个8位部分中的每个细节,这是为什么:我有一个bool大小为'n * 128' 的数组(n为size_t ),我需要将它们存储在大小为'n'的'wirelabel'数组中。
现在,由于wirelabel只是__m128i的别名/ typedef(如果有区别,请纠正我),因此可以将128个布尔的“ n”个索引中的每个存储在“ wirelabel”数组中。
但是,为了做到这一点,我相信需要将每个8位转换为它的带符号等效项,并将其存储在数组中每个“ wirelabel”指针中的正确8位索引中。