是的,我知道这是一个有点疯狂的问题。请不要问我是否真的需要知道答案,或者这是否真的是“我的”问题所在。谢谢。
有时以下功能非常好:
isNeg# :: Int# -> Int#
isNeg# x
| x <# 0# = -1#
| otherwise = 0#
例如,它可以这样使用:
cc# f x y = word2Int# (f (int2Word# x) (int2Word# y))
andi# x y = cc# and# x y
xori# x y = cc# xor# x y
ori# x y = cc# or# x y
ifNegFstElseSnd# :: Int# -> Int# -> Int#
ifNegFstElseSnd# x y = case isNeg# x of
n -> ori# (andi# n y) (xori# n y)
当使用带有 -fllvm 和 -O2 的 GHC 7.6.3 编译上述定义时isNeg
,它会产生
# BB#0: # %ci4
movq (%rbp), %rax
testq %r14, %r14
js .LBB0_2
# BB#1: # %nid
xorl %ebx, %ebx
jmpq *%rax # TAILCALL
.LBB0_2: # %cic
movq $-1, %rbx
jmpq *%rax # TAILCALL
问题是这js
是一个条件跳转,这些似乎被认为是非常紧凑的循环的效率问题(所有东西都已经拆箱等)。另一种方法是写
isNeg# :: Int# -> Int#
isNeg# x = uncheckedIShiftRA# x (intSize# -# 1#)
where
intSize# = case bitSize (undefined::Int) of
I# size -> size
这产生
# BB#0: # %cny
sarq $63, %r14
movq (%rbp), %rax
movq %r14, %rbx
jmpq *%rax # TAILCALL
这非常简单,但我知道班次 ( sarq
) 是相对较慢的操作。
另一个看起来很合理的选择是
isNeg2# :: Int# -> Int#
isNeg2# x = negateInt# ( dataToTag# (x <# 0#) )
可悲的是,这会产生非常糟糕的代码,甚至不值得在这里粘贴。
问题
有没有更好的办法?
将升级到 GHC 7.8.2 并将最后一个定义重写为
isNeg2# x = negateInt# (x <# 0#) -- (注意:已编辑以纠正较早的错误)
与新类型相匹配的东西真的很棒吗?我无法测试它,因为我没有 GHC 7.8.2。