如何强制GHC内联FFI调用?

lev*_*tov 6 haskell ffi ghc

我制作了小型C模块以提高性能,但GHC并没有内联外部功能,而且调用成本消除了加速.例如,test.h:

int inc (int x);
Run Code Online (Sandbox Code Playgroud)

test.c:

#include "test.h"
int inc(int x) {return x + 1;}
Run Code Online (Sandbox Code Playgroud)

Test.hc:

{-# LANGUAGE ForeignFunctionInterface #-}
module Test (inc) where
import Foreign
import Foreign.C
foreign import ccall unsafe "test.h inc" c_inc :: CInt -> CInt
inc = fromIntegral . c_inc . fromIntegral
{-# INLINE c_inc #-}
{-# INLINE inc #-}
Run Code Online (Sandbox Code Playgroud)

Main.hs:

import System.Environment
import Test
main = do {args <- getArgs; putStrLn . show . inc . read . head $ args }
Run Code Online (Sandbox Code Playgroud)

制造:

$ gcc -O2 -c test.c
$ ghc -O3 test.o Test.hs
$ ghc --make -O3 test.o Main
$ objdump -d Main > Main.as
Run Code Online (Sandbox Code Playgroud)

最后,在Main.as我有callq <inc>指示而不是理想inc的指令.

Don*_*art 9

GHC不会通过其asm后端或LLVM后端内联C代码.通常情况下,如果你打电话的东西真的花了很多钱,你只会因为性能原因打电话给C.增加一个int不是这样的事情,因为我们已经有了这个原则.

现在,如果你通过C调用,你可能会得到GCC内联的东西(检查生成的程序集).

但是,现在您已经可以做一些事情来降低通话费用:

foreign import ccall unsafe "test.h inc" c_inc :: CInt -> CInt

inc = fromIntegral . c_inc . fromIntegral
Run Code Online (Sandbox Code Playgroud)

提供类型签名inc.你在这里支付宝贵的周期转换为整数.

将调用标记为"不安全",以便在调用之前不对运行时添加书签.

测量FFI呼叫开销 - 它应该在纳秒内.但是,如果你发现它仍然太昂贵,你可以写一个新的primop并直接跳转到它.但你最好首先得到你的标准数字.