使用 STG 调用约定将“foreign import prim”与 C 函数一起使用
Using `foreign import prim` with a C function using STG calling convention
我有一个简单的 C 例程,它包含四个字和 returns 四个字,gcc 可以为此优化并发出一些 GHC 不支持的 primops。我正在尝试对调用此过程的各种方式进行基准测试,但在尝试调整技术 described here 以使用 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);
}
我真的不知道自己在做什么。有没有办法从那个博客 post 中改编技术?这是个坏主意吗?
如果你愿意手写汇编,你可以这样做(for 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中定义。
请注意,仍将涉及函数调用,因此它不会像您从 LLVM 获得的代码那样高效。
我有一个简单的 C 例程,它包含四个字和 returns 四个字,gcc 可以为此优化并发出一些 GHC 不支持的 primops。我正在尝试对调用此过程的各种方式进行基准测试,但在尝试调整技术 described here 以使用 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);
}
我真的不知道自己在做什么。有没有办法从那个博客 post 中改编技术?这是个坏主意吗?
如果你愿意手写汇编,你可以这样做(for 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中定义。
请注意,仍将涉及函数调用,因此它不会像您从 LLVM 获得的代码那样高效。