我没有一个特定的用例;我在问,这是否真的是英特尔内部的设计缺陷/限制,或者我只是遗漏了什么。
如果您想将标量浮点与现有的向量结合起来,似乎没有一种方法可以不使用Intel Intrinsics对标量进行高元素归零或将其广播到向量中。我还没有研究过GNU C原生向量扩展和相关的内建。
如果额外的内部优化掉了,这也不会太糟,但对于gcc(5.4或6.2)就不是这样了。使用pmovzx
或insertps
作为加载也没有什么好方法,因为它们的内在属性仅采用向量参数。(而且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
}
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
shufps xmm0, xmm1, 0 # The function *should* just compile to this.
ret
TL:DR:这个问题的其余部分只是问你是否真的能有效地完成这项工作,如果不能,为什么不能。
Clang的shuffle-optimizer正确地处理了这一点,并且不会浪费将高元素清零(_mm_set_ss(x)
)或将标量复制到它们中(_mm_set1_ps(x)
)的指令。而不是编写一些编译器必须优化的东西,难道不应该有一种方法,以“高效”的编写它在第一时间?即使是最近的gcc也没有优化它,所以这是一个真正的(但很小的)问题。
如果存在__m256_mm256_castps128_ps256(__m128a)
的标量->128b等效值,则这是可能的。即生成一个__m128
,上面的元素中有未定义的垃圾,下面的元素中有float,如果标量float/double已经在xmm寄存器中,则编译为零asm指令。
以下这些本质都不存在,但它们应该存在。
>
与前面描述的_mm256_castps128_ps256
的标量->__m128等效。标量已入寄存器情况下的最通用解决方案。
__m128_mm_move_ss_scalar(__m128a,float s)
:用标量s
替换向量a
的低元素。如果有一个通用标量->__m128(前面的要点),这实际上是不必要的。(movss
的reg-reg形式合并,这与load形式不同,load形式为零,而movd
形式在这两种情况下都为上部元素为零。若要复制包含标量浮点的寄存器而不存在虚假依赖关系,请使用movaps
)。
__m128i_mm_loadzxbd(const uint8_t*four_bytes)
和其他大小的PMOVZX/pmovsx:AFAICT,没有很好的安全方法来使用PMOVZX本征作为加载,因为这种不方便的安全方法没有优化gcc。
__m128_mm_insertload_ps(__m128 a,float*S,const int imm8)
。INSERTPS作为加载的行为不同:imm8的上2位被忽略,并且它总是取有效地址处的标量(而不是内存中向量中的元素)。这使得它可以处理不是16B对齐的地址,如果浮起
就在未映射的页面之前,它甚至可以正常工作。
与PMOVZX一样,gcc无法将上元素为零的_mm_load_ss()
折叠到用于插入的内存操作数中。(注意,如果imm8的高2位不都是零,那么_mm_insert_ps(xmm0,_mm_load_ss(),imm8)
可以编译为insertpsxmm0,xmm0,foo
,使用不同的imm8将vec中的元素置零,就像--如果src元素实际上是MOVSS从内存中产生的零。在这种情况下,Clang实际上使用xorps/blendps)
是否有任何可行的变通方法来仿效那些既安全(通过例如加载可能触及下一页和segfault的16b而不在-o0处中断),又高效(至少在-o3处没有浪费当前gcc和clang,最好也是其他主要编译器的指令)的方法?最好也是以可读的方式,但如果需要,它可以放在内联包装函数后面,如__m128 float_to_vec(float a){something(a);}
。
英特尔有什么好的理由不推出那样的内含子吗?他们可以在添加_mm256_castps128_ps256
的同时添加一个带有未定义的上部元素的float->__m128。这是编译器内部的问题使它难以实现吗?也许特别是ICC内部?
x86-64上的主要调用约定(SysV或MS__vectorcall
)使用xmm0中的第一个FP参数,并返回xmm0中的标量FP参数,上面的元素未定义。(有关ABI文档,请参阅x86标记wiki)。这意味着编译器在一个带有未知上部元素的寄存器中有一个标量float/double并不少见。在向量化的内部循环中,这将是很少见的,所以我认为避免这些无用的指令将大多只是节省一点代码大小。
pmovzx的情况更为严重:这是您可能在内部循环中使用的东西(例如,对于VPERMD混洗掩码的LUT,与将每个索引填充到32位存储在内存中相比,在缓存占用空间上节省了4倍)。
pmovzx-as-a-load问题已经困扰我一段时间了,这个问题的最初版本让我想到了在xmm寄存器中使用标量浮点的相关问题。pmovzx作为负载的用例可能比标量->__m128多。
这在GNU C内联asm中是可行的,但这是很难看的,并且使许多优化失败,包括常数传播(https://gcc.GNU.org/wiki/dontuseinlineasm)。这不会是公认的答案。我将此添加为一个答案,而不是问题的一部分,因此
保持简短
的问题并不是很大。
// don't use this: defeating optimizations is probably worse than an extra instruction
#ifdef __GNUC__
__m128 float_to_vec_inlineasm(float x) {
__m128 retval;
asm ("" : "=x"(retval) : "0"(x)); // matching constraint: provide x in the same xmm reg as retval
return retval;
}
#endif
这会根据需要编译成单个ret
,并内联使您可以将标量shufps
转换成向量:
gcc5.3
float_to_vec_and_shuffle_asm(float __vector(4), float):
shufps xmm0, xmm1, 0 # tmp93, xv,
ret
请参阅Godbolt编译器资源管理器中的这段代码。
这在纯粹的汇编语言中显然是微不足道的,在这里您不必与编译器斗争以使它不发出您不想要或不需要的指令。
我还没有找到任何真正的方法来编写一个__m128 float_to_vec(float a){something(a);}
来编译一个ret
指令。使用_mm_undefined_pd()
和_mm_move_sd()
尝试使用double
实际上会使gcc的代码更糟糕(请参阅上面的Godbolt链接)。现有的float->__m128本征没有任何帮助。
离题:actual_mm_set_ss()代码生成策略:当您编写的代码上部元素必须为零时,编译器会从一系列有趣的策略中选择。有好的,也有怪的。同样的编译器(gcc或clang)上的double和float的策略也不同,正如您在上面的Godbolt链接上所看到的。
一个示例:__m128 float_to_vec(float x){return_mm_set_ss(x);}
编译为:
# gcc5.3 -march=core2
movd eax, xmm0 # movd xmm0,xmm0 would work; IDK why gcc doesn't do that
movd xmm0, eax
ret
# gcc5.3 -march=nehalem
insertps xmm0, xmm0, 0xe
ret
# clang3.8 -march=nehalem
xorps xmm1, xmm1
blendps xmm0, xmm1, 14 # xmm0 = xmm0[0],xmm1[1,2,3]
ret
我经常注意到gcc在可执行文件中将乘法转换为移位。当将与相乘时,可能会发生类似的情况。例如,可能只是将的指数增加1,从而节省一些周期。如果有人要求编译器这样做(例如,通过),编译器通常会这样做吗? 编译器通常是否足够聪明来执行此操作,还是我需要自己使用或函数系列来执行此操作?
本文向大家介绍C#中如何将容量设置为ArrayList中元素的实际数量,包括了C#中如何将容量设置为ArrayList中元素的实际数量的使用技巧和注意事项,需要的朋友参考一下 要将容量设置为ArrayList中元素的实际数量,代码如下- 示例 输出结果 这将产生以下输出- 示例 现在让我们来看另一个示例- 输出结果 这将产生以下输出-
我有一个关于Spring WebFlux和Reactor的问题。我试图编写一个简单的场景,其中在GETendpoint中,我返回一个表示实体的DTO流,这些实体中的每一个都有一个表示另一个实体的其他DTO的集合。以下是详细信息。 我有两个实体,Person和Song,定义如下: 这些实体由以下DTO表示: 我的服务(为了简洁起见,这里没有显示)确实返回Mono和flux。然后我就有了以下RESTC
问题内容: 假设我有一个numpy数组: 我有一个对应的“向量”: 我如何沿每一行进行减法或除法运算,所以结果是: 长话短说:如何使用对应于每一行的1D标量数组在2D数组的每一行上执行操作? 问题答案: 干得好。您只需要与广播结合使用(或):
是否可以使用PDFBox(或其他库)将两个PDF中的元素合并为最终PDF? 我不是在寻找页面连接,而是在合并页面元素:
变量定义 nsi脚本的变量定义用Var关键字,后跟变量名,变量是全局的并且是大小写敏感的。变量引用时需要加上前缀$。 除了用户自定义的变量外,nsi脚本中与定义寄存器变量$0~$9,$R0~$R9用于参数传递,以及系统变量用于特定用途,这些变量主要有: $INSTDIR,$OUTDIR,$CMDLINE,$LANGUAGE(这些变量都是可写的)。 $PROGRAMFILES,$COMMONFILE