从Int的符号计算位掩码的最快方法是什么?

dfe*_*uer 0 haskell integer-arithmetic

是的,我知道这是一个有点疯狂的问题.请不要问我是否真的需要知道答案,或者这是否真的是"我的"问题.谢谢.

有时以下功能非常好:

isNeg# :: Int# -> Int#
isNeg# x
   | x <# 0#   = -1#
   | otherwise = 0#
Run Code Online (Sandbox Code Playgroud)

例如,它可以像这样使用:

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)
Run Code Online (Sandbox Code Playgroud)

isNeg使用带有-fllvm和-O2的GHC 7.6.3编译上述定义时,它会产生

# 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
Run Code Online (Sandbox Code Playgroud)

问题是这js是一个条件跳转,这些似乎被认为是非常紧凑的循环(其中所有东西都已经拆箱等)的效率问题.另一种方法是写

isNeg# :: Int# -> Int#
isNeg# x = uncheckedIShiftRA# x (intSize# -# 1#)
  where
    intSize# = case bitSize (undefined::Int) of
                 I# size -> size
Run Code Online (Sandbox Code Playgroud)

这产生了

# BB#0:                                 # %cny
    sarq    $63, %r14
    movq    (%rbp), %rax
    movq    %r14, %rbx
    jmpq    *%rax  # TAILCALL
Run Code Online (Sandbox Code Playgroud)

这非常简单,但我理解shift(sarq)操作相对较慢.

另一种看似非常合理的选择是

isNeg2# :: Int# -> Int#
isNeg2# x = negateInt# ( dataToTag# (x <# 0#) )
Run Code Online (Sandbox Code Playgroud)

遗憾的是,这会产生完全可怕的代码,甚至不值得在这里粘贴.

这个问题

  1. 有没有更好的办法?
  2. 将升级到GHC 7.8.2并将最后一个定义重写为

    isNeg2#x = negateInt#(x <#0#) - (注意:编辑以纠正先前的错误)

匹配新类型给一些非常好的东西?我无法测试它,因为我没有GHC 7.8.2.

Tho*_*son 5

自GHC 7.6.3以来,prims的类型已经改变.例如,比较不再导致布尔值.这意味着您的isNeg#功能应改为:

isNeg# :: Int# -> Int#
isNeg# x
   = negateInt# (x <# 0#)
Run Code Online (Sandbox Code Playgroud)

这会产生(7.8.2,-O2):

_cMj:
        testq %r14,%r14
        setl %al
        movzbl %al,%ebx
        negq %rbx
        jmp *(%rbp)
Run Code Online (Sandbox Code Playgroud)

编辑:LLVM代码包含一条sar指令(并不sarq奇怪)所以如果由于某种原因困扰你,那么也许你应该避免使用LLVM.