标签: sse

如何使用SSE计算某个范围内的字节数?

我想编写一个 ac 程序来计算某个范围内的字节数a...c使用以下代码:

char a[16], b[16], c[16];  
int counter = 0; 
for(i = 0;  i < 16; i++)  
{  
  if((a[i] < b[i]) && (b[i] < c[i]))  
  counter++;  
}  
return counter;  
Run Code Online (Sandbox Code Playgroud)

我打算做这样的事情

__m128i result1 = _mm_cmpgt_epi8 (b, a);  
__m128i result2 = _mm_cmplt_epi8 (b, c);  
unsigned short out1 = _mm_movemask_epi8(result1);  
unsigned short out2 = _mm_movemask_epi8(result2);  
unsigned short out3 = out1 & out2;  
unsigned short out4 = _mm_popcnt_u32(out3);   
Run Code Online (Sandbox Code Playgroud)

我的方法正确吗?有更好的方法吗?

x86 sse simd

2
推荐指数
1
解决办法
379
查看次数

SSE - 不存在的 haddsub 内在?

在浏览可用的内在函数时,我注意到无处可见可用的水平 addsub/subadd 指令。它在过时的 3DNow 中可用!扩展但是由于显而易见的原因,它的使用是不切实际的。在 SSE3 扩展中没有实现这种“基本”操作以及类似的水平和 addsub 操作的原因是什么?

顺便说一句,现代指令集(SSE3、SSE4、AVX……)中最快的替代方法是什么?(每个值有 2 个双打,即 __m128d)

sse simd intrinsics

2
推荐指数
1
解决办法
371
查看次数

反转 XMM 或 YMM 寄存器中的字节顺序?

假设我想反转一个非常大的字节数组的字节顺序。我可以使用主寄存器以较慢的方式执行此操作,但我想使用 XMM 或 YMM 寄存器来加快速度。

有没有办法反转 XMM 或 YMM 寄存器中的字节顺序?

x86 assembly sse x86-64 avx

2
推荐指数
1
解决办法
1448
查看次数

将 XMM 寄存器设置为重复字节模式(广播一个常量字节)

我知道我们可以做这样的事情来将一个字符移动到一个 xmm 寄存器:

movaps xmm1, xword [.__0x20]

align 16
.__0x20 db 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20
Run Code Online (Sandbox Code Playgroud)

但由于这是一个记忆过程,我想知道是否有更好的方法?(另外,我在谈论 SSE2 而不是其他 SIMD 类型......)

我希望 xmm1 寄存器的每个字节都是 0x20,而不仅仅是一个字节..

(编者注:这可以称为广播或 splat。
这是_mm_set1_epi8(0x20)内在函数的作用。)

assembly sse micro-optimization sse2

2
推荐指数
1
解决办法
281
查看次数

使用 AVX/AVX2/SSE __m128i 将所有负字节设置为 -128 (0x80) 并保留所有其他字节

基本上我想要做的是获取一个__m128i寄存器,并为每个负字节将其值设置为 -128 (0x80) 并且不更改任何正值。

确切地说是:

signed char __m128_as_char_arr[16] = {some data};
for(int i = 0; i < 16; i++) {
     if (__m128_as_char_arr[i] < 0) { //alternative __m128_as_char_arr[i] & 0x80
           __m128_as_char_arr[i] = 0x80;
     }

}
Run Code Online (Sandbox Code Playgroud)

我认为最好的方法是:

__m128i v = some data;
int mask = _mm_movemask_epi8(_mm_cmpgt_epi8(_mm_set1_epi8(0xff), v));

// use mask in some way to only set chars with 1s bit set
Run Code Online (Sandbox Code Playgroud)

但我不知道 (1) 使用什么指令来仅设置与关联的字节mask以及 (2) 是否有更好的方法来做到这一点(根本没有掩码或生成掩码的更好方法)。

sse simd avx avx2

2
推荐指数
1
解决办法
226
查看次数

是否有一个内在函数可以将 __m128i 向量的最后 n 个字节归零?

鉴于n,我想将向量的最后一个n字节归零__m128i

例如,考虑以下__m128i向量:

11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111

将最后一个n = 4字节归零后,向量应如下所示:

11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 00000000 00000000 00000000 00000000

是否有执行此操作的 SSE 内在函数(通过接受__128i向量和n作为参数)?

c sse simd vectorization

2
推荐指数
1
解决办法
158
查看次数

将 xmm 寄存器的低两个 32 位浮点数扩展为整个 xmm 寄存器

Intel x86 汇编中执行以下操作的最有效方法是什么(ab是 32 位浮点数):

xmm1: [-, -, a, b]xmm1: [a, a, b, b]

我找不到任何有用的说明。
我的想法是将ab复制到其他寄存器,然后将xmm1寄存器移动 4 个字节并将ab移动到最低的 4 个字节。

x86 assembly sse

2
推荐指数
1
解决办法
83
查看次数

punpcklbw(在 MMX/SSE/AVX 中交错)有哪些用例?

  1. 可以使用哪些类别的算法punpcklbw

  2. 特别是,在punpcklbw xmm0, xmm0做什么?

  3. 然而,什么是maskedPow2_Value有用的?

    maskedValue = 0x101010101010101i64 * *(_QWORD *)&Val; // Val 是 int maskedPow2_Value = 0x101010101010101i64 * maskedValue;

(或mov r9, 101010101010101h; imul rdx, r9;两次)

一个完整的例子(该函数名为 CompressPacket 但它可能会产生误导),作为 IDA 反编译的结果:

void *__cdecl CompressPacket(void *Dst, int Val, size_t Size)
{
  __int64 maskedPow2_Value; // rdx
  unsigned int v5; // ecx
  __int64 *bufferOut; // rcx
  size_t size_; // r9
  size_t i; // r9
  size_t size__; // r9
  size_t counter; // r8
  size_t j; // …
Run Code Online (Sandbox Code Playgroud)

compression assembly sse memset disassembly

2
推荐指数
1
解决办法
99
查看次数

为什么 movaps 会导致分段错误?

介绍

我试图让自己熟悉 AES 指令,然后使用能够更有意识地利用这些技术的库。然而,我不经常用汇编编程,所以我对这门语言有一些信心,但我不认为自己是专家。我已经编写了大约 150 条装配线的清单,以尝试使用英特尔提供的文档来使用这些功能。然而,我并没有成功地向前迈出许多步骤。

当我使用该指令时,由于 main 中的分段错误,程序崩溃了movaps。我已经尝试使用 gdb 和 valgrind 进行调试,但似乎一切正常,但事实并非如此。以下是导致问题的行。

代码

main:
start_f

    printstr

    movaps (string), %xmm15
==> movaps (key), %xmm0
    call   aes_encript

    movaps %xmm15, string
    printstr

end_f
Run Code Online (Sandbox Code Playgroud)

start_f并且end_f只是宏来启动和结束函数。我还提供了 .data 部分的代码,以显示应该没有问题:

    .data
string:
    .string "string"
    .fill   (128 - (.-string)), 1, 0

newline:
    .byte   0x0a

key:
    .fill   128, 1, 0

    .text
    .global _start
Run Code Online (Sandbox Code Playgroud)

调试信息

至于错误,无论是通过静态反汇编还是在gdb中,我都无法获得任何有用的信息。Valgrind 也没有帮助,这是意料之中的,因为我根本不接触堆。我展示了 gdb 中主要反汇编的部分清单:

   0x0000000000401022 <+0>:     push   %rbp
   0x0000000000401023 <+1>:     mov    %rsp,%rbp
   0x0000000000401026 <+4>:     mov    $0x402000,%rsi
   0x000000000040102d <+11>:    call …
Run Code Online (Sandbox Code Playgroud)

assembly sse memory-alignment segmentation-fault att

2
推荐指数
1
解决办法
126
查看次数

我需要在 2021 年使用 _mm256_zeroupper 吗?

摘自Agner Fog 的“用 C++ 优化软件”

在某些 Intel 处理器上混合使用和不使用 AVX 支持编译的代码时会出现问题。由于 YMM 寄存器状态的变化,从 AVX 代码到非 AVX 代码会导致性能下降。在从 AVX 代码到非 AVX 代码的任何转换之前,应该通过调用内部函数 _mm256_zeroupper() 来避免这种惩罚。在以下情况下,这可能是必要的:

• 如果程序的一部分是使用 AVX 支持编译的,而程序的另一部分是在没有 AVX 支持的情况下编译的,则在离开 AVX 部分之前调用 _mm256_zeroupper()。

• 如果使用 CPU 调度在使用和不使用 AVX 的多个版本中编译函数,则在离开 AVX 部分之前调用 _mm256_zeroupper()。

• 如果一段使用AVX 支持编译的代码调用了编译器自带的库以外的库中的函数,而该库没有AVX 支持,则在调用库函数之前先调用_mm256_zeroupper()。

我想知道什么是英特尔处理器。具体来说,是否有过去五年制造的处理器。这样我就知道修复丢失的_mm256_zeroupper()电话是否为时已晚。

c++ sse simd intrinsics avx

2
推荐指数
1
解决办法
137
查看次数