我想编写一个 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)
我的方法正确吗?有更好的方法吗?
在浏览可用的内在函数时,我注意到无处可见可用的水平 addsub/subadd 指令。它在过时的 3DNow 中可用!扩展但是由于显而易见的原因,它的使用是不切实际的。在 SSE3 扩展中没有实现这种“基本”操作以及类似的水平和 addsub 操作的原因是什么?
顺便说一句,现代指令集(SSE3、SSE4、AVX……)中最快的替代方法是什么?(每个值有 2 个双打,即 __m128d)
假设我想反转一个非常大的字节数组的字节顺序。我可以使用主寄存器以较慢的方式执行此操作,但我想使用 XMM 或 YMM 寄存器来加快速度。
有没有办法反转 XMM 或 YMM 寄存器中的字节顺序?
我知道我们可以做这样的事情来将一个字符移动到一个 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)内在函数的作用。)
基本上我想要做的是获取一个__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) 是否有更好的方法来做到这一点(根本没有掩码或生成掩码的更好方法)。
鉴于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作为参数)?
Intel x86 汇编中执行以下操作的最有效方法是什么(a,b是 32 位浮点数):
从xmm1: [-, -, a, b]到xmm1: [a, a, b, b]
我找不到任何有用的说明。
我的想法是将a和b复制到其他寄存器,然后将xmm1寄存器移动 4 个字节并将a或b移动到最低的 4 个字节。
可以使用哪些类别的算法punpcklbw?
特别是,在punpcklbw xmm0, xmm0做什么?
然而,什么是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) 我试图让自己熟悉 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) 在某些 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()电话是否为时已晚。
sse ×10
assembly ×5
simd ×5
avx ×3
x86 ×3
intrinsics ×2
att ×1
avx2 ×1
c ×1
c++ ×1
compression ×1
disassembly ×1
memset ×1
sse2 ×1
x86-64 ×1