gpt4 book ai didi

optimization - 如何说服 Lisp SBCL 进行内联 fixnum 运算?

转载 作者:太空宇宙 更新时间:2023-11-03 18:52:12 25 4
gpt4 key购买 nike

我在其他 SO 答案中找到了一些技巧,但显然我无法说服 SBCL 进行内联 fixnum 算术:

(declaim (optimize (speed 2) (safety 1)))

(declaim (ftype (function (fixnum fixnum) double-float) fixnumtest) (inline fixnumtest))
(defun fixnumtest (i j)
(declare (type fixnum i j))
(let* ((n (the fixnum (+ i j)))
(n+1 (the fixnum (1+ n))))
(declare (type fixnum n n+1))
(/ 1.0d0 (the fixnum (* n n+1)) )
)
)

(defun main ()
(format t "~11,9F~%" (fixnumtest 2 3))
)

:results in forced to do GENERIC-* (cost 30)

我还应该尝试什么?

$ sbcl --eval '(load (compile-file "play.lisp"))'
This is SBCL 1.5.1,

; compiling file "/opt/tmp/play.lisp" (written 16 OCT 2019 08:03:15 PM):
; compiling (DECLAIM (OPTIMIZE # ...))
; compiling (DECLAIM (FTYPE # ...) ...)
; compiling (DEFUN FIXNUMTEST ...)
; file: /opt/tmp/play.lisp
; in: DEFUN FIXNUMTEST
; (* N N+1)
;
; note: forced to do GENERIC-* (cost 30)
; unable to do inline fixnum arithmetic (cost 4) because:
; The result is a (VALUES
; (INTEGER -21267647932558653961849226946058125312
; 21267647932558653961849226946058125312)
; &OPTIONAL), not a (VALUES FIXNUM &REST T).
; unable to do inline (signed-byte 64) arithmetic (cost 5) because:
; The result is a (VALUES
; (INTEGER -21267647932558653961849226946058125312
; 21267647932558653961849226946058125312)
; &OPTIONAL), not a (VALUES (SIGNED-BYTE 64) &REST T).
; etc.

此外,我是否认为将 float 强制转换为指针(成本 13) 是从函数返回 float 的普通结果?

;     (DEFUN FIXNUMTEST (I J)
; (DECLARE (TYPE FIXNUM I J))
; (LET* ((N (THE FIXNUM #)) (N+1 (THE FIXNUM #)))
; (DECLARE (TYPE FIXNUM N N+1))
; (/ 1.0d0 (THE FIXNUM (* N N+1)))))
; --> PROGN SB-IMPL::%DEFUN SB-IMPL::%DEFUN SB-INT:NAMED-LAMBDA
; ==>
; #'(SB-INT:NAMED-LAMBDA FIXNUMTEST
; (I J)
; (DECLARE (SB-C::TOP-LEVEL-FORM))
; (DECLARE (TYPE FIXNUM I J))
; (BLOCK FIXNUMTEST
; (LET* ((N #) (N+1 #))
; (DECLARE (TYPE FIXNUM N N+1))
; (/ 1.0d0 (THE FIXNUM #)))))
;
; note: doing float to pointer coercion (cost 13) to "<return value>"

最佳答案

好吧,编译器正在告诉你答案,也许是以一种有点无用的方式。如果你有两个 fixnums 那么情况就不是这样,例如,将它们相加会得到一个 fixnum:类型 fixnum 在算术运算下不闭合(甚至在 + 下也不闭合) >、-*,忽略 /)。

来自SBCL manual :

The SBCL compiler treats type declarations differently from most other Lisp compilers. Under default compilation policy the compiler doesn’t blindly believe type declarations, but considers them assertions about the program that should be checked: all type declarations that have not been proven to always hold are asserted at runtime.

如果你想编译机器算法,你需要做的是告诉编译器它正在使用的类型足够好,它可以知道结果类型足够好,可以立即表示它们。

鉴于您在函数中的算法,并假设一个 64 位实现,那么一个好的类型是 (signed-byte 31):使用 (signed-byte 32) 但这失败了,因为你最终得到的东西比 (signed-byte 64) 大。

所以除了在返回时使用最后的双 float 之外,这段代码不会发出警告:

(deftype smallish-integer (&optional (bits 31))
`(signed-byte ,bits))


(declaim (ftype (function (smallish-integer smallish-integer) double-float)
fixnumtest)
(inline fixnumtest))

(defun fixnumtest (i j)
(declare (optimize (speed 2)))
(declare (type smallish-integer i j))
(let* ((n (+ i j))
(n+1 (1+ n)))
(/ 1.0d0 (* n n+1))))

值得注意的是 (signed-byte 64)fixnum 大很多:这没关系,因为在一个函数中编译器可以处理适合寄存器的数字,即使它们大于 fixnums。

我对 x64 汇编器不够熟悉,无法检查所有算术是否都编译为机器指令,但看起来确实如此。

有可能说服 SBCL 编译器您不关心获得正确答案并且它应该只执行机器算术,即使它知道它可能会溢出。我不知道该怎么做。

关于optimization - 如何说服 Lisp SBCL 进行内联 fixnum 运算?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58424422/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com