我正在学习汇编程序很长一段时间,我正在尝试重写一些简单的过程\函数来查看性能优势(如果有的话).我的主要开发工具是Delphi 2007,第一个例子将使用该语言,但它们也可以很容易地翻译成其他语言.
问题表明:
我们给出了一个无符号字节值,其中八位中的每一位代表一行屏幕中的一个像素.每个单个像素可以是实心(1)或透明(0).换句话说,我们在一个字节值中包含8个像素.我想将这些像素解压缩成一个8字节的数组,就像最年轻的像素(位)将落在数组的最低索引之下一样,依此类推.这是一个例子:
One byte value -----------> eight byte array
10011011 -----------------> [1][1][0][1][1][0][0][1]
Array index number -------> 0 1 2 3 4 5 6 7
Run Code Online (Sandbox Code Playgroud)
下面我介绍解决问题的五种方法.接下来,我将展示他们的时间比较以及我如何衡量这些时间.
我的问题包括两部分:
我问您详细的有关方法的答案DecodePixels4a和DecodePixels4b.为什么方法4b有点慢4a?
例如,如果我的代码没有正确对齐,它会慢一些,那么告诉我给定方法中哪些指令可以更好地对齐,以及如何做到这一点不破坏方法.
我想看看这个理论背后的真实例子.请记住,我正在学习汇编,我想从你的答案中获得知识,这使我将来能够编写更好的优化代码.
你能写更快的常规DecodePixels4a吗?如果是,请提供并描述您已采取的优化步骤.通过更快的例程,我的意思是在测试环境中在最短的时间段内运行的例程,在此处提供的所有例程中.
允许使用所有Intel系列处理器以及与之兼容的处理器.
您将在下面找到我编写的例程:
procedure DecodePixels1(EncPixels: Byte; var DecPixels: TDecodedPixels);
var
i3: Integer;
begin
DecPixels[0] := EncPixels and $01;
for i3 := 1 to 7 do
begin
EncPixels := EncPixels shr 1;
DecPixels[i3] := …Run Code Online (Sandbox Code Playgroud) movemask指令采用__m256i并返回int32,其中每个位(取决于输入向量元素类型的前4位,8位或所有32位)是相应向量元素的最高有效位.
我想做反过来:取一个32(其中只有4,8或32个最低有效位有意义),并获得__m256i,其中每个int8,int32或int64大小的块的最高有效位设置为原始位.
基本上,我想从压缩的位掩码转到可被其他AVX2指令(例如maskstore,maskload,mask_gather)用作掩码的位掩码.
我无法快速找到这样做的指令,所以我在这里问.如果没有一条具有该功能的指令,您是否可以想到一个聪明的黑客,只需很少的指令即可实现这一点?
我目前的方法是使用256元素查找表.我想在一个没有其他事情发生的循环中使用这个操作来加速它.注意,我对长多指令序列或实现此操作的小循环不太感兴趣.
将32位存储在uint32_t内存中,将每个位解压缩到AVX寄存器的单独字节元素的最快方法是什么?这些位可以位于各自字节内的任何位置.
编辑:澄清,我的意思是位0进入字节0,位1到字节1.显然,字节内的所有其他位都为零.我现在最好的是2 PSHUFB并且每个位置都有一个掩码寄存器.
如果uint32_t是位图,则相应的向量元素应为0或非0.(即我们可以得到一个矢量掩码,其中vpcmpeqb一个矢量为全零的矢量).
首先我将描述该任务:
我需要:
__m128i。uint16_t值(可能使用_mm_movemask_epi8先然后只是&)。blend结果计算初始值。所以问题是,正如您可能已经猜到的那样,混合接受__m128i作为掩模,而我将拥有uint16_t. 因此,我要么需要某种反向指令,_mm_movemask_epi8要么完全做其他事情。
有些观点——我可能无法将该uint16_t值更改为其他类型,这很复杂;我在 SSE4.2 上这样做,所以没有 AVX;这里有一个类似的问题How to Perform the inverse of _mm256_movemask_epi8 (VPMOVMSKB)? 但这是关于 avx 的,我对此非常缺乏经验,所以我无法采用该解决方案。
PS:我可能也需要为手臂做这件事,希望得到任何建议。
我想要实现的是基于一个字节中的每个位,设置为ymm寄存器(或内存位置)中每个dword中的所有位
例如
al = 0110 0001
ymm0 = 0x00000000 FFFFFFFF FFFFFFFF 00000000 00000000 00000000 00000000 FFFFFFFF
Run Code Online (Sandbox Code Playgroud)
即vmovmskps eax, ymm0/ 的倒数_mm256_movemask_ps,将位图转换为矢量蒙版.
我想有一些sse/avx指令可以相对简单地做到这一点,但我还是无法解决这个问题.优选沙桥兼容,因此没有avx2.
有没有办法转换以下代码:
int mask16 = 0b1010101010101010; // int or short, signed or unsigned, it does not matter
Run Code Online (Sandbox Code Playgroud)
到
__uint128_t mask128 = ((__uint128_t)0x0100010001000100 << 64) | 0x0100010001000100;
Run Code Online (Sandbox Code Playgroud)
所以要特别清楚,比如:
int mask16 = 0b1010101010101010;
__uint128_t mask128 = intrinsic_bits_to_bytes(mask16);
Run Code Online (Sandbox Code Playgroud)
或直接敷面膜:
int mask16 = 0b1010101010101010;
__uint128_t v = ((__uint128_t)0x2828282828282828 << 64) | 0x2828282828282828;
__uint128_t w = intrinsic_bits_to_bytes_mask(v, mask16); // w = ((__uint128_t)0x2928292829282928 << 64) | 0x2928292829282928;
Run Code Online (Sandbox Code Playgroud) 是否有一个内在函数可以在输入数组中的所有位置设置单个值,其中相应位置在提供的 BitMask 中具有 1 位?
10101010 是位掩码
值为 121
它将设置位置 0,2,4,6 值为 121