私は4単語を返し、4単語を返し、GHCがサポートしていないいくつかのプリムプを最適化して出力する単純なCルーチンを持っています。私はこの手順を呼び出す様々な方法をベンチマークしようとしており、技術を適応させることを試みることに問題がありますdescribed hereforeign import prim
を使用してください。STG呼び出し規約を使用してC関数で `foreign import prim`を使用する
以下は、各入力単語に1を追加するだけですが、segfaultsを意味します。
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);
}
私は本当に私がやっているのか分かりません。そのブログ記事から技術を適用する方法はありますか?そしてこれは悪い考えですか?
これは非常に低レベルです。あなたは本当にこのレベルのパフォーマンスが必要ですか? AFAICSのブログ記事では、clangを使ってLLVMを生成し、Cの呼び出し規則をLLVM cc10(GHCのもの)に変更して出力をパッチし、llcでコンパイルします。恐ろしい。これはコンフォートゾーンを超えています(つまり、このレベルで何が起こっているかについての知識はほとんどありません)。しかし、cc10呼び出し規約を使用することは非常に重要です。 – chi
@chi通常の外国コールから4ワードの構造体を返すベンチマーキングも進行中ですが、オーバーヘッドがそれほど価値があると思っています(でも驚くかもしれません)。私は、LLVMバックエンドを使用していないときに生成されたローテート命令を取得しようとしています。しかし、これもまた不思議です – jberryman
これはうまくいかないでしょう。ブログの投稿は次のように述べています。「これはまだccallの機能ですが、後でそれを修正します。現在、clangのcc10(GHCの呼び出し規約のLLVMの内部名)として定義する方法はありません。 Cの呼び出し規約はGHCのものとは異なります。例えば、Cは最初の引数 'baseReg'が' rdi'(x86_64を前提としている)でなければならないと考えていますが、GHCは 'r13'に' baseReg'を渡しています。 –