- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在编写一个例程,以便在BCD(每十进制数字4位)和Densely Packed Decimal (DPD)(每3个十进制数字10位)之间转换。在Mike Cowlishaw's web site上进一步记录了DPD(建议使用软件使用查找表)。
该例程只需要它使用的寄存器的低16位,但是对于较短的指令编码,我已尽可能使用32位指令。与以下代码相关的速度损失:
mov data,%eax # high 16 bit of data are cleared
...
shl %al
shr %eax
and $0x888,%edi # = 0000 a000 e000 i000
imul $0x0490,%di # = aei0 0000 0000 0000
imul
的替代方案是32位
imul
和后续的
and
或一系列
lea
指令和最终的
and
。
.section .text
.type bcd2dpd_mul,@function
.globl bcd2dpd_mul
# convert BCD to DPD with multiplication tricks
# input abcd efgh iklm in edi
.align 8
bcd2dpd_mul:
mov %edi,%eax # = 0000 abcd efgh iklm
shl %al # = 0000 abcd fghi klm0
shr %eax # = 0000 0abc dfgh iklm
test $0x880,%edi # fast path for a = e = 0
jz 1f
and $0x888,%edi # = 0000 a000 e000 i000
imul $0x0490,%di # = aei0 0000 0000 0000
mov %eax,%esi
and $0x66,%esi # q = 0000 0000 0fg0 0kl0
shr $13,%edi # u = 0000 0000 0000 0aei
imul tab-8(,%rdi,4),%si # v = q * tab[u-2][0]
and $0x397,%eax # r = 0000 00bc d00h 0klm
xor %esi,%eax # w = r ^ v
or tab-6(,%rdi,4),%ax # x = w | tab[u-2][1]
and $0x3ff,%eax # = 0000 00xx xxxx xxxx
1: ret
.size bcd2dpd_mul,.-bcd2dpd_mul
.section .rodata
.align 4
tab:
.short 0x0011 ; .short 0x000a
.short 0x0000 ; .short 0x004e
.short 0x0081 ; .short 0x000c
.short 0x0008 ; .short 0x002e
.short 0x0081 ; .short 0x000e
.short 0x0000 ; .short 0x006e
.size tab,.-tab
.section .text
.type bcd2dpd_mul,@function
.globl bcd2dpd_mul
# convert BCD to DPD with multiplication tricks
# input abcd efgh iklm in edi
.align 8
bcd2dpd_mul:
mov %edi,%eax # = 0000 abcd efgh iklm
shl %al # = 0000 abcd fghi klm0
shr %eax # = 0000 0abc dfgh iklm
test $0x880,%edi # fast path for a = e = 0
jnz 1f
ret
.align 8
1: and $0x888,%edi # = 0000 a000 e000 i000
imul $0x49,%edi # = 0ae0 aei0 ei00 i000
mov %eax,%esi
and $0x66,%esi # q = 0000 0000 0fg0 0kl0
shr $8,%edi # = 0000 0000 0ae0 aei0
and $0xe,%edi # = 0000 0000 0000 aei0
movzwl lookup-4(%rdi),%edx
movzbl %dl,%edi
imul %edi,%esi # v = q * tab[u-2][0]
and $0x397,%eax # r = 0000 00bc d00h 0klm
xor %esi,%eax # w = r ^ v
or %dh,%al # = w | tab[u-2][1]
and $0x3ff,%eax # = 0000 00xx xxxx xxxx
ret
.size bcd2dpd_mul,.-bcd2dpd_mul
.section .rodata
.align 4
lookup:
.byte 0x11
.byte 0x0a
.byte 0x00
.byte 0x4e
.byte 0x81
.byte 0x0c
.byte 0x08
.byte 0x2e
.byte 0x81
.byte 0x0e
.byte 0x00
.byte 0x6e
.size lookup,.-lookup
最佳答案
(我将BMI2版本分为一个单独的答案,因为它最终可能会完全不同)
在查看完您使用该imul/shr
进行的操作以获取表索引之后,我可以看到在哪里可以使用BMI2 pextr
替换and/imul/shr
或BMI1 bextr
仅替换shr
(允许使用imul32而不是imul16,因为您d仅提取所需的位,而不需要从上16移零)。有些AMD CPU带有BMI1,但即使压路机也缺少BMI2。英特尔与Haswell同时推出了BMI1和BMI2。
您可以使用64位pextr一次处理两个或四个16位字。但不是整个算法:您不能进行4个并行表查找。 (在这里不值得使用AVX2 VPGATHERDD。)实际上,您可以使用pshufb
来实现索引最大为4位的LUT,请参见下文。
次要改进版本:
.section .rodata
# This won't won't assemble, written this way for humans to line up with comments.
extmask_lobits: .long 0b0000 0111 0111 0111
extmask_hibits: .long 0b0000 1000 1000 1000
# pext doesn't have an immediate-operand form, but it can take the mask from a memory operand.
# Load these into regs if running in a tight loop.
#### TOTALLY UNTESTED #####
.text
.p2align 4,,10
bcd2dpd_bmi2:
# mov %edi,%eax # = 0000 abcd efgh iklm
# shl %al # = 0000 abcd fghi klm0
# shr %eax # = 0000 0abc dfgh iklm
pext extmask_lobits, %edi, %eax
# = 0000 0abc dfgh iklm
mov %eax, %esi # insn scheduling for 4-issue front-end: Fast-path is 4 fused-domain uops
# And doesn't waste issue capacity when we're taking the slow path. CPUs with mov-elimination won't waste execution units from issuing an extra mov
test $0x880, %edi # fast path for a = e = 0
jnz .Lslow_path
ret
.p2align 4
.Lslow_path:
# 8 uops, including the `ret`: can issue in 2 clocks.
# replaces and/imul/shr
pext extmask_hibits, %edi, %edi #u= 0000 0000 0000 0aei
and $0x66, %esi # q = 0000 0000 0fg0 0kl0
imul tab-8(,%rdi,4), %esi # v = q * tab[u-2][0]
and $0x397, %eax # r = 0000 00bc d00h 0klm
xor %esi, %eax # w = r ^ v
or tab-6(,%rdi,4), %eax # x = w | tab[u-2][1]
and $0x3ff, %eax # = 0000 00xx xxxx xxxx
ret
aei
选择器,然后使用
pdep
将它们存储在不同字节的低位中。然后将
movq
编码到向量寄存器,在其中将其用作
pshufb
的随机控制掩码,以执行多个4位LUT查找。
shrd
在寄存器之间移动位以处理对字节可寻址存储器的加载/存储。)
pmovzx
,但是处理其余数据将需要在向量寄存器中进行位改组。甚至慢速的AVX2可变位移insns都不会很容易做到这一点。 (尽管完全考虑如何使用BMI2来实现这一点很有趣,但对于仅使用SSSE3(即每个相关CPU)或SSE4.1的CPU来说,则可以大大提高速度。)
shrd
insns来将剩余的4位从最后64b转换为下一个低4位。或者,当4个被忽略的位是64b的低4或高4时,可以使用两个偏移pextr掩码工作。无论如何,我认为一次进行5组操作是不值得考虑的。
ignored | group 3 | group 2 | group 1 | group 0
16bits | abcd efgh iklm | abcd efgh iklm | abcd efgh iklm | abcd efgh iklm
3 2 1 | 0
pext -> aei|aei|aei|aei # packed together in the low bits
2 | 1 | 0
pdep -> ... |0000 0000 0000 0aei|0000 0000 0000 0aei # each in a separate 16b word
movq -> xmm vector register.
(Then pinsrq another group of 4 selectors into the upper 64b of the vector reg). So the vector part can handle 2 (or AVX2: 4) of this at once
vpshufb xmm2 -> map each byte to another byte (IMUL table)
vpshufb xmm3 -> map each byte to another byte (OR table)
Get the bits other than `aei` from each group of 3 BCD digits unpacked from 48b to 64b, into separate 16b words:
group 3 | group 2 | group 1 | group 0
pdep(src)-> 0000 abcd efgh iklm | 0000 abcd efgh iklm | 0000 abcd efgh iklm | 0000 abcd efgh iklm
movq this into a vector reg (xmm1). (And repeat for the next 48b and pinsrq that to the upper64)
VPAND xmm1, mask (to zero aei in each group)
Then use the vector-LUT results:
VPMULLW xmm1, xmm2 -> packed 16b multiply, keeping only the low16 of the result
VPAND xmm1, mask
VPXOR xmm1, something
VPOR xmm1, xmm3
movq / pextrq back to integer regs
pext to pack the bits back together
You don't need the AND 0x3ff or equivalent:
Those bits go away when you pext to pack each 16b down to 10b
shrd or something to pack the 40b results of this into 64b chunks for store to memory.
Or: 32b store, then shift and store the last 8b, but that seems lame
Or: just do 64b stores, overlapping with the previous. So you write 24b of garbage every time. Take care at the very end of the buffer.
movdqa
不覆盖
pshufb
的表。只要您从不运行256b AVX指令,就无需弄乱
vzeroupper
。不过,如果使用任何矢量指令,也可以使用
v
(VEX)版本。在VM内部,您可能正在具有BMI2但不支持AVX的虚拟CPU上运行,因此可能是这样。检查两个CPU功能标志还是一个好主意,而不是如果看到BMI2则假定为AVX(即使对于当前存在的所有物理硬件来说都是安全的)。
shrd
用于将数据从一个reg转移到另一个reg?
关于performance - 将BCD打包到DPD : How to improve this amd64 assembly routine?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34111959/
我正在尝试启动已部署的应用程序。键入 dpd-d 后,我收到以下错误消息: starting deployd v0.6.11... Failed to start MongoDB 在我输入“DEBUG
我已经安装部署了 pdf 模块 dpd-pdf https://github.com/diadistis/dpd-pdf 在仪表板中,我创建了一个/pdf,其中包含conf路径 C:\export\w
首先让我说我真的很喜欢Deployd .我想在生产中使用它,但我想合并 OAuth 和社交登录,所以我安装了 dpd-passport模块。它工作得很好,除了两个小(大)问题: 当用户通过 OAuth
我正在构建一个项目,使用 Deployd 协助我的 API,并使用 dpd-passport 进行身份验证。 我似乎对所有内容进行了身份验证, session key 在后面分发,用户通过 Googl
我正在尝试从 dpd.com 获取运输标签。为此,我需要使用肥皂来完成任务。我已经完成登录认证并获得了AuthToken。这是相关代码。 getAuth(array( 'delisId' =>
您好,我作为网络开发人员工作了好几年,在今天之前没有使用过任何 API。现在我必须将一家航运公司的 api 与客户网站集成,我试图了解其 api 文档,但没有任何有用的结果。客户向我提供了一个我难以理
我是一名优秀的程序员,十分优秀!