61539

Using `foreign import prim` with a C function using STG calling convention

Question:

I have a simple C routine that takes four words and returns four words, and for which gcc can optimize and emit some primops that GHC doesn't support. I'm trying to benchmark various ways of calling this procedure, and am having trouble trying to adapt the technique <a href="http://breaks.for.alienz.org/blog/2012/02/09/parsing-market-data-feeds-with-ragel/" rel="nofollow">described here</a> to use foreign import prim.

The following is meant to just add 1 to each input word, but 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); }

I don't really know what I'm doing. Is there a way to adapt the technique from that blog post? And is this a bad idea?

Answer1:

If you're willing to hand-write assembly you can do it like this (for x86_64). Put this in a file with a .s extension and provide it as an argument on the ghc command line.

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

The mapping between STG registers and machine registers is defined in <a href="https://github.com/ghc/ghc/blob/master/includes/stg/MachRegs.h#L159" rel="nofollow">https://github.com/ghc/ghc/blob/master/includes/stg/MachRegs.h#L159</a>.

Note that there will still be a function call involved, so it won't be as efficient as the code you are getting from LLVM.

Recommend

  • IJulia install - WARNING: Module BinDeps uuid did not match cache file
  • JavaFX apllication does not run with Selenium WebDriver
  • Asterisk IVR After Hangup
  • Unable to generate call to cell phone using asterisk
  • QBOv3 XML Validation Fault
  • npm thinks node is out of date, but it isn't
  • SIP Makefile fail (gnuwin and mingw)
  • Nginx rewrite equivalent to Apache RewriteRule that converts URL params into QueryString key/value p
  • Transpose table then set and rename index
  • ConfigurationBuilder not working in azure function
  • Uber API - requests endpoint cannot read read json
  • Unable to play media with vlc ocx
  • Embedded Google Maps in Rails not responsive
  • How to resolve this packager error on react native Android
  • Are Richfaces and Primefaces compatible with each other?
  • PushKit for VOIP iOS apps
  • Installing PHP 7 on digitalocean
  • android google indoor map
  • Eclipse CDT error: Unable to compile
  • Django rest serializer Breaks when data exists
  • Is it possible to access block's scope in method?
  • Checking free space on FTP server
  • Can I check if a recipient has an automatic reply before I send an email?
  • output of program is not same as passed argument
  • How to make Safari send if-modified-since header?
  • Why is the timeout on a windows udp receive socket always 500ms longer than set by SO_RCVTIMEO?
  • align graphs with different xlab
  • Akka Routing: Reply's send to router ends up as dead letters
  • Return words with double consecutive letters
  • How to pass list parameters for each object using Spring MVC?
  • Arrays break string types in Julia
  • Buffer size for converting unsigned long to string
  • Hits per day in Google Big Query
  • Setting background image for body element in xhtml (for different monitors and resolutions)
  • How to get Windows thread pool to call class member function?
  • unknown Exception android
  • JaxB to read class hierarchy
  • Checking variable from a different class in C#
  • Reading document lines to the user (python)
  • Python/Django TangoWithDjango Models and Databases