我希望能够在没有完整函数调用的开销的情况下从Haskell调用LLVM代码。例如:
-- Main.hs --
{-# LANGUAGE MagicHash #-}
{-# LANGUAGE UnboxedTuples #-}
{-# LANGUAGE GHCForeignImportPrim #-}
{-# LANGUAGE ForeignFunctionInterface #-}
{-# LANGUAGE UnliftedFFITypes #-}
{-# LANGUAGE BangPatterns #-}
import GHC.Exts(Word(W#))
import GHC.Prim(Word#)
foreign import ccall llvminc :: Word# -> Word#
main = do
line1 <- getLine
let !(W# x1) = read line1
let !r1 = llvminc x1
print (W# r1)
-- funcs.ll --
define fastcc i64 @llvminc(i64 inreg %x) {
%r = add i64 %x, 1
ret i64 %r
}
我可以通过运行来编译和链接它以生成一个正常运行的可执行文件:
ghc -O2 -fllvm Main.hs funcs.ll
实际上,即使删除-fllvm
仍会导致功能可执行,例如
ghc -O2 Main.hs funcs.ll
这让我强烈怀疑GHC是在使用普通C链接的两种情况下分别链接这些文件。
确实,当我使用以下方法调查中间输出时
ghc -O2 -fllvm -keep-s-files Main.hs funcs.ll
我在Main.s中看到以下内容:
callq suspendThread
movq %rax, %rbp
movq %rbx, %rdi
callq llvminc
movq %rax, %rbx
movq %rbp, %rdi
callq resumeThread
这又表明GHC只是要求LLVM单独编译文件,然后将结果发送到系统链接器,这不会内联调用。
相反,我希望GHC将初始LLVM文件(从GHC和用户指定)发送到llvm-link,与系统链接器不同,它只是将多个LLVM bitcode文件合并到一个LLVM bitcode中文件。最好将此结果编译为本机代码对象文件并发送到系统链接器,而不是将多个目标文件发送到系统链接器。
确实,当我手动尝试将.ll
人类可读文件组装到LLVM .bc
bitcode,llvm-link
生成的bitcode时,然后像这样反汇编bitcode:
llvm-as Main.ll
llvm-as funcs.ll
llvm-link funcs.bc Main.bc -o combined.bc
llvm-dis combined.bc
我在生成的LLVM代码中找到了以下内容
%ln59M = add i64 %ln59L, 1
直接拨打电话后,没有&#34;电话&#34;或返回。实际的功能仍然在LLVM中,但是不需要。
所以我尝试通过在命令行中添加-pgml llvm-link
来指示GHC与LLVM链接器链接,但这种情况非常失败,llvm-link
抛出了许多关于未知选项的错误。这并不奇怪,因为llvm-link
不是真正的链接器,它只是组合了LLVM文件。
那么,有没有让GHC通过LLVM链接器发送所有它的中间LLVM文件来启用LLVM级别的模块间优化?
答案 0 :(得分:2)
你试过这两件事吗?
1 - 使用 alwaysinline 功能属性:http://llvm.org/docs/LangRef.html#function-attributes
2 - 使用GHC呼叫约定,(cc 10而不是fastcc): http://llvm.org/docs/LangRef.html#calling-conventions
define cc 10 i64 @llvminc(i64 inreg %x) alwaysinline {
%r = add i64 %x, 1
ret i64 %r
}