Tag: intrinsics

GNU C本机向量:如何广播标量,如x86的_mm_set1_epi16

我如何编写一个可移植的GNU C内置向量版本,它不依赖于x86 set1内在函数? typedef uint16_t v8su __attribute__((vector_size(16))); v8su set1_u16_x86(uint16_t scalar) { return (v8su)_mm_set1_epi16(scalar); // cast needed for gcc } 当然必须有一个更好的方式 v8su set1_u16(uint16_t s) { return (v8su){s,s,s,s, s,s,s,s}; } 我不想写一个用于广播单个字节的AVX2版本! 对于你想要分配给一个变量而不是仅仅用作二元运算符的操作数(这与gcc一起使用,见下文)的情况, 即使只是gcc-only或clang-only这个部分的答案也会很有趣 。 如果我想使用广播标量作为二元运算符的一个操作数,则可以使用gcc( 如手册中所述 ),但不能使用clang: v8su vecdiv10(v8su v) { return v / 10; } // doesn’t compile with clang 有了clang,如果我只针对x86并且只使用本机向量语法来让编译器为我生成模数乘法逆常数和指令 ,我可以写: v8su vecdiv_set1(v8su v) { […]

如果它们是16字节对齐,是否可以直接将浮点数转换为__m128?

如果它们是16字节对齐的话,将浮点数直接转换为__m128是否安全/可行/可取? 我注意到使用_mm_load_ps和_mm_store_ps来“包装”原始数组会增加很大的开销。 我应该注意哪些潜在的陷阱? 编辑: 使用加载和存储指令实际上没有开销,我得到了一些数字混合,这就是为什么我有更好的性能。 即使你能够在__m128实例中使用原始内存地址进行一些HORRENDOUS修改,当我运行测试时,如果没有_mm_load_ps指令则需要TWICE AS LONG完成,可能会回退到一些故障安全代码路径。

逻辑SSE内在函数之间有什么区别?

不同类型的逻辑SSE内在函数之间有什么区别吗? 例如,如果我们采用OR运算,有三个内在函数:_mm_or_ps,_mm_or_pd和_mm_or_si128所有这些都做同样的事情:计算其操作数的按位 OR。 我的问题: 使用一个或另一个内在(使用适当的类型转换)之间是否有任何区别。 在某些特定情况下,是否会有更长的执行等隐藏成本? 这些内在函数映射到三个不同的x86指令(por,orps,orpd)。 有没有人有任何想法为什么英特尔浪费宝贵的操作码空间的几个指令做同样的事情?

混合SSE整数/浮点SIMD指令时,是否会降低性能?

我最近以内在函数的forms使用了x86 SIMD指令(SSE1234)。 我发现令人沮丧的是SSE ISA有几个简单的指令,只能用于浮点数或仅用于整数,但理论上应该对两者都有相同的效果。 例如,float和double向量都有指令从地址( movhps , movhpd )加载更高的64位128位向量,但是没有这样的整数向量指令。 我的问题: 在整数向量上使用浮点指令时,有没有理由期望性能受到影响,例如使用movhps将数据加载到整数向量? 我写了几个测试来检查,但我认为他们的结果不可信。 编写一个正确的测试来探索这些事情的所有极端情况真的很难,特别是在这里最可能涉及指令调度时。 相关问题: 其他平凡相似的东西也有几个基本相同的指令。 例如,我可以使用por , orps或orpd按位OR。 任何人都可以解释这些附加说明的目的是什么? 我想这可能与应用于每条指令的不同调度算法有关。

clflush通过C函数使缓存行无效

我试图使用clflush手动驱逐缓存行,以确定缓存和行大小。 我没有找到关于如何使用该指令的任何指南。 我所看到的,是一些使用更高级别function的代码。 有一个内核函数void clflush_cache_range(void *vaddr, unsigned int size) ,但我仍然不知道在我的代码中包含什么以及如何使用它。 我不知道该function的size是多少。 更重要的是,我怎样才能确定该行被驱逐以validation我的代码的正确性? 更新: 这是我想要做的初始代码。 #include #include #include #include int main() { int array[ 100 ]; /* will bring array in the cache */ for ( int i = 0; i < 100; i++ ) array[ i ] = i; /* FLUSH A LINE */ /* […]

打印__m128i变量

我正在尝试学习使用内在函数进行编码,下面是一个添加代码的代码 compiler used: icc #include #include int main() { __m128i a = _mm_set_epi32(1,2,3,4); __m128i b = _mm_set_epi32(1,2,3,4); __m128i c; c = _mm_add_epi32(a,b); printf(“%d\n”,c[2]); return 0; } 我得到以下错误: test.c(9): error: expression must have pointer-to-object type printf(“%d\n”,c[2]); 如何在变量c打印__m128i类型的__m128i

如何在没有编译器浪费指令归零上层元素的情况下将标量合并到向量中? 英特尔内在函数的设计限制?

我没有特定的用例; 我问这是否真的是英特尔内在函数中的设计缺陷/限制,或者我是否只是遗漏了某些内容。 如果你想将标量浮点数与现有向量相结合,那么使用英特尔内在函数时,如果没有高元素归零或将标量广播到向量中,似乎没有办法实现。 我没有研究过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 } gcc 5.3 […]