使用 STG 调用约定将 `foreign import prim` 与 C 函数一起使用

2024-01-02

我有一个简单的 C 例程,它接受四个字并返回四个字,gcc 可以对其进行优化并发出一些 GHC 不支持的 primops。我正在尝试对调用此过程的各种方法进行基准测试,但在尝试适应该技术时遇到了困难此处描述 http://breaks.for.alienz.org/blog/2012/02/09/parsing-market-data-feeds-with-ragel/ to use foreign import prim.

下面的代码只是给每个输入单词加 1,但是会出现段错误。

Main.hs:

{-# LANGUAGE GHCForeignImportPrim #-}
{-# LANGUAGE ForeignFunctionInterface #-}
{-# LANGUAGE MagicHash #-}
{-# LANGUAGE UnboxedTuples  #-}
{-# LANGUAGE UnliftedFFITypes #-}
import Foreign.C
import GHC.Prim
import GHC.Int
import GHC.Word

foreign import prim "sipRound"
  sipRound_c# :: Word# -> Word# -> Word# -> Word# -> (# Word#, Word#, Word#, Word# #)

sipRound_c ::  Word64 -> Word64 -> Word64 -> Word64 -> (Word64, Word64, Word64, Word64)
sipRound_c (W64# v0) (W64# v1) (W64# v2) (W64# v3) = case sipRound_c# v0 v1 v2 v3 of
  (# v0', v1', v2', v3' #) -> (W64# v0', W64# v1', W64# v2', W64# v3')

main = do
  print $ sipRound_c 1 2 3 4

sip.c:

#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>



// define a function pointer type that matches the STG calling convention
typedef void (*HsCall)(int64_t*, int64_t*, int64_t*, int64_t, int64_t, int64_t, int64_t,
                       int64_t, int64_t, int64_t*, float, float, float, float, double, double);

extern void
sipRound(
    int64_t* restrict baseReg,
    int64_t* restrict sp,
    int64_t* restrict hp,

    uint64_t v0, // R1
    uint64_t v1, // R2
    uint64_t v2, // R3
    uint64_t v3, // R4
    int64_t r5,
    int64_t r6,

    int64_t* restrict spLim,
    float f1,
    float f2,
    float f3,
    float f4,
    double d1,
    double d2)
{

    v0 += 1;
    v1 += 1;
    v2 += 1;
    v3 += 1;

    // create undefined variables, clang will emit these as a llvm undef literal
    const int64_t iUndef;
    const float fUndef;
    const double dUndef;

    const HsCall fun = (HsCall)sp[0];
    return fun(
            baseReg,
            sp,
            hp,

            v0,
            v1,
            v2,
            v3,
            iUndef,
            iUndef,

            spLim,
            fUndef,
            fUndef,
            fUndef,
            fUndef,
            dUndef,
            dUndef);
}

我真的不知道自己在做什么。有没有办法改编该博客文章中的技术?这是一个坏主意吗?


如果您愿意手写程序集,您可以这样做(对于 x86_64)。将其放入一个带有.s扩展名并将其作为 ghc 命令行上的参数提供。

.global sipRound
sipRound:
    inc %rbx
    inc %r14
    inc %rsi
    inc %rdi
    jmp *(%rbp)

STG寄存器和机器寄存器之间的映射定义在https://github.com/ghc/ghc/blob/master/includes/stg/MachRegs.h#L159 https://github.com/ghc/ghc/blob/master/includes/stg/MachRegs.h#L159.

请注意,仍然会涉及函数调用,因此它不会像从 LLVM 获得的代码那样高效。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 STG 调用约定将 `foreign import prim` 与 C 函数一起使用 的相关文章

随机推荐