- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
在AVX2中,我们具有_mm256_srlv_epi32(a, b)
和_mm256_sllv_epi32(a, b)
,用于将“a”中的一组8个值偏移“b”中的8个值。是否有使用AVX的有效替代方法,以便我可以留在AVX中而不必吐出标量代码?
最佳答案
AVX1没有256b整数运算,只有FP。因此,我认为您确实在寻找__m128i _mm_srlv_epi32()
的替代方法。使用extractf128/insertf128,您可以轻松地对256b vector 执行此操作,但是最好使用更多128b加载/存储,尤其是。如果您具有可以在具有AVX2支持的CPU上运行的AVX2版本。 (现有的仅限AVX1的CPU都恰好具有128b加载/存储数据路径,因此256b加载/存储几乎没有优势。)
从 vector 到标量的往返非常昂贵(在标量存储后重新加载时存储转发停顿,或者很多movd
/pextrd
/pinsrd
),因此即使有些笨重的东西也可能比整数代码更好,这取决于吞吐量是否或延迟在您使用此代码中更重要。
我最好的主意基本上是 vector regs的标量:4个移位(每个不同的移位计数一个)和3个立即混合来组合结果。
更新:想法2:左移32位乘以2count。请参阅此答案的结尾。
如果移位计数不是编译时常量,则需要解压缩移位计数的 vector ,以便将每个移位计数作为 vector 的64b。 (非可变移位指令可以将其计数存储在寄存器中,但它们会查看整个低64b。并且,它们不会像标量移位那样屏蔽(模字大小),而是饱和。
将xmm寄存器的4个元素中的每个元素都隔离在原本为零的目标中是很棘手的。您不能只将它们字节向下移动到底部,因为那会在第二个元素中留下非零字节。
由于这是针对不带AVX2的AVX,因此我假设您具有用于AVX2 CPU的单独版本。因此,对于Intel,此版本将在SnB/IvB上使用。这意味着您有两个128b随机播放单元,而不是Haswell及更高版本上的一个。
## 4 shift-counts in the elements of xmm0 = [ D C B A ]. element 1 isolated in xmm1, etc.
vpsrlq xmm2, xmm0, 32 ; xmm2 = [ 0 D 0 B ]
vpunpckhqdq xmm4, xmm2, xmm0 ; xmm4 = [ D C 0 D ]
vpshufd xmm3, xmm4, 0b01010110 ; xmm3 = [ 0 0 0 C ]
vblendps xmm1, xmm2, xmm0, 0b0001 ; xmm1 = [ 0 D 0 A ]
; or
vpblendw xmm1, xmm2, xmm0, 0b00000011 ; xmm1 = [ 0 D 0 A ]
vblendps
在SnB/IvB的p0/5上运行。等效的
vpblendw
在SnB/IvB的p1/p5上运行。在Haswell/SKL上,它是p015与p5,所以blendps更好(端口选择与
PAND
相同)。对于SnB,也许使用两者的组合来混合移位结果。对于内在函数,在整数数据上使用FP指令需要大量转换,这使源代码很难看又难以读取。除非您打算使用性能计数器和微基准调整它使其最适合周围的代码,否则请对snB/IvB使用
pblendw
。否则,只需转换并使用
blendps
即可。
[ 0 -1 0 -1 ]
掩码,则可以替代, vector AND可以在更多端口上运行,并缩短
xmm3
的依赖链。这不足以证明加载或生成 mask 是合理的,因此更喜欢使用移位/混洗/混合来完成所有操作的先前版本。
vpcmpeqw xmm5, xmm5,xmm5 ; all-ones
vpsrlq xmm5, xmm5, 32 ; [ 0 -1 0 -1 ]: generate the mask on the fly if desired
vpand xmm1, xmm5, xmm0 ; [ 0 C 0 A ]
vpsrlq xmm2, xmm0, 32 ; [ 0 D 0 B ]
vpunpckhqdq xmm3, xmm1,xmm1 ; [ 0 C 0 C ] ; saves 1B vs. the equivalent pshufd: no imm8 byte
vpunpckhqdq xmm4, xmm2,xmm2 ; [ 0 D 0 D ]
VPSRLVD ymm,ymm,ymm
(1 uop)比
PSRLD xmm,xmm,xmm
(2 uop)便宜。但是,立即计数
PSRLD
仅1 uop。 (来自
Agner Fog's insn tables)。
movaps [rsp - 16], xmm0
shr [rsp - 16], 3 ; 3 uops with a memory-destination. 5 uops for variable count with a memory destination
shr [rsp - 12], 1
shr [rsp - 8], 4
shr [rsp - 4], 1
movaps xmm0, [rsp - 16] ; store-forwarding stall here from the 4x 32b stores to the 128b load
## data in xmm0, shift counts in xmm1, results in xmm2
vmovd eax, xmm0 ; 1 uop
vmovd ecx, xmm1 ; 1 uop
shr eax, cl ; 3 uops because of CISC stupidity
vmovd xmm2, eax ; 1 uop
vpextrd eax, xmm0, 1 ; 2 uops
vpextrd ecx, xmm1, 1 ; 2 uops
shr eax, cl ; 3 uops because of CISC stupidity
vpinsrd xmm2, eax, 1 ; 2 uops
... repeat twice more, for indices 2 and 3
因此,可变计数移位的所有寄存器方式为6uops + 9uops * 3,总计33 uops。
pextr
计数将更多,因为每个可变计数偏移量比立即计数偏移量多2 uop。
vpsrld xmm,xmm
insns vpblendw
或vblendps
合并这些结果。 vpsrlvd ymm, ymm, ymm
是1 uop,1c延迟,每0.5c吞吐量之一。 vpsrlvd ymm, ymm, ymm
是3微码,2c延迟,每2c吞吐量中的一个。 pmulld
乘以2的幂进行左移。
pmulld
是1 uop,5c延迟,每1c吞吐量之一。
pshufb
作为LUT将计数 vector 映射到2 ^ c vector 。每个元素低字节中的
0
必须变为
1
(20),但其他字节中的
0
必须保持为零。
## 1<<8 or higher is 0, in an 8bit element
## xmm5 = _mm_set_epi8(0, 0, ..., 1<<7, ..., 1<<2, 1<<1, 1<<0);
## xmm4 = _mm_set1_epi32(0x000000ff);
## data in xmm0, shift counts in xmm1
movdqa xmm2, xmm5 ; avoid this with AVX
pshufb xmm2, xmm5 ; 2^count
pand xmm2, xmm4 ; zero all but the low byte in each element
pmulld xmm0, xmm2 ; data * 2^count
英特尔SnB/IvB:3微秒(不算AVX不需要的movdqa)。从移位计数到结果的延迟:7c。从移位数据到结果的延迟:5c。吞吐量:每1c一个(因为所有三个uops都可以在不同的端口上运行)。
pmulld
上的花费也要比SnB多,但不像Haswell那样糟糕。
[ D-8 C-8 B-8 A-8 ]
中使用多个LUT进行查找,以获取每个32b元素的第二个字节的值,依此类推。等等。请注意,如果
C-8
,
C<8
设置了符号位,并且
BLENDVB
根据符号位合并被设置。但是,它很昂贵,因此一系列合并可能并不仅仅比使用早期的shift/blend-inmediate方法更好。
pshufb
结果之外,您还可以添加一个
set1_epi32(1)
vector 。然后,LUT中具有非零字节的索引范围将为1..8,而移位计数 vector 中的填充0字节将查找LUT的低位元素(应为0)。这样做可以使动态常量生成更加可行:
## xmm5 = _mm_set_epi8(0, 0, ..., 1<<7, ..., 1<<2, 1<<1, 1<<0, 0);
## data in xmm0, shift counts in xmm1
pcmpeqw xmm4,xmm4 ; all-ones
psubd xmm1, xmm4 ; shift_counts -= -1
movdqa xmm2, xmm5
pshufb xmm2, xmm1 ; 2^count
pmulld xmm0, xmm2 ; data * 2^count
除非您真的想在一个少的insn中动态生成一个常量,否则对此没有任何好处。 (使用pcmpeqw/psrld 24可以快速生成set1_epi32(0xff),但是编译器通常只能在一个insn中进行动态生成。)
2<<count
。
[ 0 0 D+8 D | 0 0 C+8 C | ... ]
用作控制掩码。在LUT的每一半中都有正确的数据,这将产生正确的两个字节。
关于c++ - AVX2的 vector 移位的AVX替代方案?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36637315/
我想将这个无符号数:1479636484000 向右移动 7 位。这在 JavaScript 中可能吗? 两者 1479636484000 >> 7 和 1479636484000 >>> 7 返回错
鉴于以下代码: import matplotlib.pyplot as plt import numpy as np x = [1.0, 1.1, 2.0, 5.7] y = np.arange(le
我有一个低级键盘钩子(Hook),目前允许我从任何应用程序(包括游戏)中控制媒体播放器。 它通过查看捕获的特定击键来工作。 我想扩展它以查找键的组合。我可以对一些逻辑进行硬编码,但我觉得必须有一种更合
我需要一些帮助来理解这段C代码。我不知道这里的“L”和“\”是什么?请也说明一点:) #define l2n(l,c) (*((c)++)=(unsigned char)(((l)>>2
我正在查看一段代码: int result = 0 ; char byte = foo[j] for (i = 7 ; i>0 ; i--) { byte = (byte & ~0x1)>>1
我们有一个项目要求我们编写一个程序,允许用户输入一系列数字“将数字读入数组以进行进一步处理,用户通过输入负数表示他们已完成(负数不用于计算),在读取所有数字后执行以下操作,总结输入的#,计算输入的#,
锁定。有disputes about this question’s content正在解决中。它目前不接受新的答案或互动。 def menu(): choice = input("Pres
为什么如果 int x = -1 // binary: 11111111111111111111111111111111 x = x >>> 31; 我们有 000000000000000000000
我的问题其实应该很简单:我有一个玩家对象数组。(玩家[])我想要一个函数来旋转这个数组直到一个索引: public void rotateArray(Object[] array, int index
我有一个编码为 boost 动态位集的数字列表。我根据此列表中的任何数字可以采用的最大值动态选择此位集的大小。所以假设我有从 0 到 7 的数字,我只需要三位,我的字符串 0,2,7 将被编码为000
我能想到一些令人讨厌的低效方法来完成这项任务,但我想知道最好的方法是什么。 例如,我想复制一个字节中从第 3 位开始的 10 个字节,并像往常一样复制到一个指针。 有没有比一次复制一个移位字节更好的方
我正在尝试为该问题添加更多规则,并且该规则一直给我带来这种转变/减少冲突的能力,我不知道为什么会这样做,并且在过去的24小时内我一直在尝试解决问题 FuncDecl : RetTyp
This question already has answers here: Why does it make a difference if left and right shift are us
我在 Perl 中遇到这个问题已经有几天了,在搜索了无数的手册页、perldocs 和谷歌搜索了太多的搜索词之后,希望这里有人能帮助我。 我得到两个表示十六进制值的字符串,即“FFFF”,而不是 Pe
我有一个主 div,两个 div 水平并排放置在这个父 div 中。 .parent{ height: 360px; margin-top: 0px; bo
我想 float 我的元素列表并从第二个元素创建一个移动效果。 如何避免第二个 .item 之后的“清除”行为? .shift { float: right; width: 50%;
我正在使用 SSE3 优化我的代码。代码中有一点迫使我将 vector 中的所有元素移动一个元素 v[0] = 0 //v is some char* and N = v.size() for(i
.file "calcnew.c" .text .globl calcnew .type calcnew, @function calcnew:
我有一个点对象: class Point { final int x,y; ... } 因为这些点将在我的代码中到处使用/创建,所以我想开始使用 guavas 缓存。不幸的是
x = "Foo 890 bar *()" 如何将包括 "*()" 在内的小写字母“未移位”返回到 890?期望的结果: foo 890 bar 890 不需要的: x.lower() => "foo
我是一名优秀的程序员,十分优秀!