Assembly 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

我使用的Lisp实现SBCL知道,如果
x
可以作为足够短的
无符号字节进行键入,则可以将
(logcount x)
编译为x86-64
POPCNT
指令。假设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/bxx046

sb内核:%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作为回退。(或在大型阵列上,AVX2
vpshufb
用于SIMD popcount)。对于大型向量,有多种实现,在现代硬件上有基准测试。有趣的事实:对于C/C++编译器,CLAN可以自动将代码> > SuxBuffTyPopCultLL>代码转换成一个啃咬的循环(AVX2查找)循环。它链接到的另一个,也将是一个有用的参考。。。如果我能想出如何编写SBCL内部函数!
(disassemble (compile () (lambda (a) (logcount (sb-kernel:%vector-raw-bits a    0)))))