Assembly SBCL优化:我们能为位向量编译一个有效的总体计数吗?
我使用的Lisp实现SBCL知道,如果Assembly SBCL优化:我们能为位向量编译一个有效的总体计数吗?,assembly,bit-manipulation,common-lisp,x86-64,sbcl,Assembly,Bit Manipulation,Common Lisp,X86 64,Sbcl,我使用的Lisp实现SBCL知道,如果x可以作为足够短的无符号字节进行键入,则可以将(logcount x)编译为x86-64POPCNT指令。假设SBCL将简单位向量存储在字对齐的连续内存段中,那么如何让编译器对其执行类似的优化填充计数呢?该标准没有提供(位向量logcount)(我认为这是一个奇怪的遗漏);它也不允许我(强制)使用fixnum 故意天真的实现如下所示;请注意,还有一个问题,而哈雷密封技术[1]可能是大矢量的更好选择。但这对于优化编译器来说足够简单,可以发现其意图: (defu
x
可以作为足够短的无符号字节进行键入,则可以将(logcount x)
编译为x86-64POPCNT
指令。假设SBCL将简单位向量
存储在字对齐的连续内存段中,那么如何让编译器对其执行类似的优化填充计数呢?该标准没有提供(位向量logcount)
(我认为这是一个奇怪的遗漏);它也不允许我(强制)
使用fixnum
故意天真的实现如下所示;请注意,还有一个问题,而哈雷密封技术[1]可能是大矢量的更好选择。但这对于优化编译器来说足够简单,可以发现其意图:
(defun bit-vector-unsigned-logcount (x)
"Not worrying about negative interpretations of X."
(declare (type (simple-bit-vector 32) x)
(optimize (speed 3) (safety 0) (debug 0)))
(loop for b across x
count (not (zerop b))))
在SBCL 2.0.1中,我得到以下信息:
; disassembly for BIT-VECTOR-UNSIGNED-LOGCOUNT
; Size: 67 bytes. Origin: #x52B88079 ; BIT-VECTOR-UNSIGNED-LOGCOUNT
; 79: 31D2 XOR EDX, EDX
; 7B: 31C0 XOR EAX, EAX
; 7D: 31C9 XOR ECX, ECX
; 7F: EB2C JMP L1
; 81: 660F1F840000000000 NOP
; 8A: 660F1F440000 NOP
; 90: L0: 488BD0 MOV RDX, RAX
; 93: 48D1FA SAR RDX, 1
; 96: 480FA35301 BT QWORD PTR [RBX+1], RDX
; 9B: 19D2 SBB EDX, EDX
; 9D: 83E202 AND EDX, 2
; A0: 4883C002 ADD RAX, 2
; A4: 4885D2 TEST RDX, RDX
; A7: 7404 JEQ L1
; A9: 4883C102 ADD RCX, 2
; AD: L1: 4883F840 CMP RAX, 64
; B1: 7CDD JL L0
; B3: 488BD1 MOV RDX, RCX
; B6: 488BE5 MOV RSP, RBP
; B9: F8 CLC
; BA: 5D POP RBP
; BB: C3 RET
我将给总统一个发言的机会
如果你的系统的性能受到了某种结构的影响,它可以有效地编译,但是SBCL编译器不能有效编译,请考虑向编译器写入补丁并提交它以包含在主要源中。
我怀疑我正面临着这样的情况,我很乐意效劳,但除了看过Paul Khong和他的文章外,我对VOP黑客几乎一无所知
x86-64/arith.lisp
定义了两个VOP,无符号字节-64计数
和正fixnum计数
,如果我们能够分离位向量
,它们看起来可以重新用于作业
[1] Muła,W.,Kurz,N.,和Lemire,D.(2017)。《计算机杂志》,61(1),111-120。doi:10.1093/comjnl/bxx046sb内核:%vector原始位是否可以作为缺失的部分
(logcount (sb-kernel:%vector-raw-bits #*100101010 0))
->四,
->(…)POPCNT(…)
如何查找:检查,例如,位和
,然后跳转到定义(M-。在sly/slime repl中,为简单位向量
选择反变换
不用说,这是特定于实现的,需要注意安全,但VOP也是如此。对于不支持popcnt
指令的CPU,这看起来不太好<代码>BT mem,reg
相当慢。这看起来像是在循环i+=2
并在i/2
处测试一个位,每次通过循环时重新计算这些偏移量,以及在将bt
的标记结果放入寄存器并返回到标记后对其进行分支。这真的很糟糕,并且会从某种类型的窥视孔优化中受益匪浅,这种优化可以识别这样的位计数操作并使用popcnt
,或者像libgcc的helper func这样的好的bithack作为回退。(或在大型阵列上,AVX2vpshufb
用于SIMD popcount)。对于大型向量,有多种实现,在现代硬件上有基准测试。有趣的事实:对于C/C++编译器,CLAN可以自动将代码> > SuxBuffTyPopCultLL>代码转换成一个啃咬的循环(AVX2查找)循环。它链接到的另一个,也将是一个有用的参考。。。如果我能想出如何编写SBCL内部函数!
(disassemble (compile () (lambda (a) (logcount (sb-kernel:%vector-raw-bits a 0)))))