~jojo/Carth

d9a33e51cabff81908736c389351a603efaaa5ec — JoJo 1 year, 10 months ago ca7366c
Pass `byval` when passing by reference

So instead of

LLVM:
  declare @foo(%Foo* %x)

Rust:
  extern fn foo(x: &Foo) { ... }

we do

LLVM:
  declare @foo(%Foo* byval %x)

Rust:
  extern fn foo(x: Foo) { ... }

It just seemed like a nice thing to do, especially now that
we (mostly?) conform to C calling convention / System V ABI.
3 files changed, 28 insertions(+), 35 deletions(-)

M examples/hello-world.carth
M foreign-core/src/lib.rs
M src/Codegen.hs
M examples/hello-world.carth => examples/hello-world.carth +1 -10
@@ 2,16 2,7 @@
  (Pair a b))

(define (start _)
  (display "Hello, world!"))


(define (display s)
  ;; TODO: This is broken:
  ;; (display-inline (id (-str-append (id (Pair s "\n")))))
  (display-inline (str-append s "\n"))
  )

;; (define (id x) x)
  (display-inline (str-append "Hello, world!" "\n")))

(define (str-append s1 s2) (-str-append (Pair s1 s2)))


M foreign-core/src/lib.rs => foreign-core/src/lib.rs +19 -19
@@ 4,7 4,7 @@ use std::io::{self, Write};
use std::{alloc, ptr, slice, str};

macro_rules! def_carth_closure {
    ($e:expr, $s:ident, $f:ident; $ta:ty, $tr:ty; $a:ident => $b:expr) => {
    ($e:expr, $s:ident, $f:ident; $ta:ty, $tr:ty; $a:pat => $b:expr) => {
        #[export_name = $e]
        pub static $s: Closure<$ta, $tr> = Closure::new($f);
        pub extern "C" fn $f(_: Captures, $a: $ta) -> $tr {


@@ 84,8 84,8 @@ pub extern "C" fn carth_alloc(size: u64) -> *mut u8 {

def_carth_closure! {
    "display-inline", DISPLAY_INLINE, display_inline;
    *const Str, (); s => unsafe {
        let s = from_carth_str(&*s);
    Str, (); s => {
        let s = from_carth_str(&s);
        print!("{}", s);
        io::stdout().flush().ok();
    }


@@ 93,37 93,37 @@ def_carth_closure! {

def_carth_closure! {
    "-str-append", STR_APPEND, str_append;
    *const Pair<Str, Str>, Str; pair => unsafe {
        let (s1, s2) = (from_carth_str(&(*pair).fst), from_carth_str(&(*pair).snd));
    Pair<Str, Str>, Str; Pair { fst, snd, .. } => {
        let (s1, s2) = (from_carth_str(&fst), from_carth_str(&snd));
        Str::new(s1.to_string() + s2)
    }
}

fn from_carth_str(s: &Str) -> &str {
fn from_carth_str<'s>(s: &'s Str) -> &'s str {
    unsafe {
        let Array { elems, len, .. } = (*s).array;
        let Array { elems, len, .. } = s.array;
        let slice = slice::from_raw_parts(elems, len as usize);
        str::from_utf8_unchecked(slice)
    }
}

def_carth_closure! {
    "-add-int", ADD_INT, add_int;
    *const Pair<i64, i64>, i64; pair => unsafe {
        (*pair).fst + (*pair).snd
    }
    "add-int", ADD_INT, add_int;
    Pair<i64, i64>, i64; Pair { fst, snd, .. } => fst + snd
}

def_carth_closure! {
    "-gt-int", GT_INT, gt_int;
    *const Pair<i64, i64>, bool; pair => unsafe {
        (*pair).fst > (*pair).snd
    }
    "gt-int", GT_INT, gt_int;
    Pair<i64, i64>, bool; Pair { fst, snd, .. } => fst > snd
}

def_carth_closure! {
    "-eq-int", EQ_INT, eq_int;
    *const Pair<i64, i64>, bool; pair => unsafe {
        (*pair).fst == (*pair).snd
    }
    "eq-int", EQ_INT, eq_int;
    Pair<i64, i64>, bool; Pair { fst, snd, .. } => fst == snd
}

def_carth_closure! {
    "show-int", SHOW_INT, show_int;
    i64, Str; n =>
        Str::new(n.to_string())
}

M src/Codegen.hs => src/Codegen.hs +8 -6
@@ 301,15 301,15 @@ genFunDef (name, fvs, ptv@(TypedVar px pt), body) = do
        px' <- newName px
        -- Load params according to calling convention
        passParamByRef <- passByRef pt'
        let (withParam, pt'') = if passParamByRef
                then (withVar, LLType.ptr pt')
                else (withLocal, pt')
        let (withParam, pt'', pattrs) = if passParamByRef
                then (withVar, LLType.ptr pt', [ByVal])
                else (withLocal, pt', [])
        let pRef = LocalReference pt'' px'
        result <- getLocal
            =<< withParam ptv pRef (withLocals captureLocals (genExpr body))
        let rt' = typeOf result
        let fParams' =
                [uncurry Parameter capturesParam [], Parameter pt'' px' []]
                [uncurry Parameter capturesParam [], Parameter pt'' px' pattrs]
        -- Return result according to calling convention
        returnResultByRef <- passByRef rt'
        if returnResultByRef


@@ 482,8 482,10 @@ app closure a rt = do
    captures <- emitReg' "captures" (extractvalue closure' [0])
    f <- emitReg' "function" (extractvalue closure' [1])
    passArgByRef <- passByRef (typeOf a)
    a' <- if passArgByRef then getVar a else getLocal a
    let args = [(captures, []), (a', [])]
    (a', aattrs) <- if passArgByRef
        then fmap (, [ByVal]) (getVar a)
        else fmap (, []) (getLocal a)
    let args = [(captures, []), (a', aattrs)]
    returnByRef <- passByRef rt
    if returnByRef
        then do