From a6e39e66f11e36d6db91b481ece1be2e7b7bd6a5 Mon Sep 17 00:00:00 2001 From: Folkert Date: Fri, 6 Nov 2020 23:46:31 +0100 Subject: [PATCH] generate signature for foreign symbols --- compiler/gen/src/llvm/build.rs | 29 ++++++++++++++++------- compiler/load/src/file.rs | 4 ++-- compiler/mono/src/borrow.rs | 6 ++--- compiler/mono/src/inc_dec.rs | 10 ++++---- compiler/mono/src/ir.rs | 36 ++++++++++++++++++++++------- examples/effect/Effect.roc | 2 +- examples/effect/Main.roc | 9 ++++---- examples/effect/platform/src/lib.rs | 10 ++++++++ 8 files changed, 75 insertions(+), 31 deletions(-) diff --git a/compiler/gen/src/llvm/build.rs b/compiler/gen/src/llvm/build.rs index 5a24e152be..461d2aa8d1 100644 --- a/compiler/gen/src/llvm/build.rs +++ b/compiler/gen/src/llvm/build.rs @@ -810,15 +810,29 @@ pub fn build_exp_expr<'a, 'ctx, 'env>( Literal(literal) => build_exp_literal(env, literal), RunLowLevel(op, symbols) => run_low_level(env, scope, parent, layout, *op, symbols), - ForeignCall(foreign_symbol, symbols) => { - let function = get_foreign_symbol(env, foreign_symbol.clone()); + ForeignCall { + foreign_symbol, + arguments, + ret_layout, + } => { + let mut arg_vals: Vec = + Vec::with_capacity_in(arguments.len(), env.arena); - let mut arg_vals: Vec = Vec::with_capacity_in(symbols.len(), env.arena); + let mut arg_types = Vec::with_capacity_in(arguments.len(), env.arena); - for arg in symbols.iter() { - arg_vals.push(load_symbol(env, scope, arg)); + for arg in arguments.iter() { + let (value, layout) = load_symbol_and_layout(env, scope, arg); + arg_vals.push(value); + let arg_type = + basic_type_from_layout(env.arena, env.context, layout, env.ptr_bytes); + arg_types.push(arg_type); } + let ret_type = + basic_type_from_layout(env.arena, env.context, ret_layout, env.ptr_bytes); + let function_type = get_fn_type(&ret_type, &arg_types); + let function = get_foreign_symbol(env, foreign_symbol.clone(), function_type); + let call = env.builder.build_call(function, arg_vals.as_slice(), "tmp"); // this is a foreign function, use c calling convention @@ -3424,6 +3438,7 @@ fn cxa_rethrow_exception<'a, 'ctx, 'env>(env: &Env<'a, 'ctx, 'env>) -> BasicValu fn get_foreign_symbol<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, foreign_symbol: roc_module::ident::ForeignSymbol, + function_type: FunctionType<'ctx>, ) -> FunctionValue<'ctx> { let module = env.module; let context = env.context; @@ -3433,9 +3448,7 @@ fn get_foreign_symbol<'a, 'ctx, 'env>( None => { let foreign_function = module.add_function( foreign_symbol.as_str(), - context - .struct_type(&[], false) - .fn_type(&[context.i64_type().into()], false), + function_type, Some(Linkage::External), ); foreign_function.set_call_conventions(C_CALL_CONV); diff --git a/compiler/load/src/file.rs b/compiler/load/src/file.rs index 16b5888484..6b50013d9d 100644 --- a/compiler/load/src/file.rs +++ b/compiler/load/src/file.rs @@ -2309,7 +2309,7 @@ fn fabricate_host_exposed_def<'a>( match annotation.typ.shallow_dealias() { Type::Function(args, _, _) => { for i in 0..args.len() { - let name = format!("closure_arg_{}", i); + let name = format!("closure_arg_{}_{}", ident, i); let arg_symbol = { let ident = name.clone().into(); @@ -2343,7 +2343,7 @@ fn fabricate_host_exposed_def<'a>( }; let effect_closure_symbol = { - let name = "effect_closure"; + let name = format!("effect_closure_{}", ident); let ident = name.clone().into(); scope diff --git a/compiler/mono/src/borrow.rs b/compiler/mono/src/borrow.rs index 1d5751670b..571b191db8 100644 --- a/compiler/mono/src/borrow.rs +++ b/compiler/mono/src/borrow.rs @@ -374,13 +374,13 @@ impl<'a> BorrowInfState<'a> { self.own_args_using_bools(args, ps); } - ForeignCall(_, args) => { + ForeignCall { arguments, .. } => { // very unsure what demand ForeignCall should place upon its arguments self.own_var(z); - let ps = foreign_borrow_signature(self.arena, args.len()); + let ps = foreign_borrow_signature(self.arena, arguments.len()); - self.own_args_using_bools(args, ps); + self.own_args_using_bools(arguments, ps); } Literal(_) | FunctionPointer(_, _) | RuntimeErrorFunction(_) => {} diff --git a/compiler/mono/src/inc_dec.rs b/compiler/mono/src/inc_dec.rs index d0f03a0511..3068698d04 100644 --- a/compiler/mono/src/inc_dec.rs +++ b/compiler/mono/src/inc_dec.rs @@ -125,8 +125,8 @@ pub fn occuring_variables_expr(expr: &Expr<'_>, result: &mut MutSet) { RunLowLevel(_, args) => { result.extend(args.iter()); } - ForeignCall(_, args) => { - result.extend(args.iter()); + ForeignCall { arguments, .. } => { + result.extend(arguments.iter()); } EmptyArray | RuntimeErrorFunction(_) | Literal(_) => {} @@ -466,9 +466,9 @@ impl<'a> Context<'a> { self.arena.alloc(Stmt::Let(z, v, l, b)) } - ForeignCall(_, args) => { - let ps = crate::borrow::foreign_borrow_signature(self.arena, args.len()); - let b = self.add_dec_after_lowlevel(args, ps, b, b_live_vars); + ForeignCall { arguments, .. } => { + let ps = crate::borrow::foreign_borrow_signature(self.arena, arguments.len()); + let b = self.add_dec_after_lowlevel(arguments, ps, b, b_live_vars); self.arena.alloc(Stmt::Let(z, v, l, b)) } diff --git a/compiler/mono/src/ir.rs b/compiler/mono/src/ir.rs index d8ac286f40..28abf97dbf 100644 --- a/compiler/mono/src/ir.rs +++ b/compiler/mono/src/ir.rs @@ -829,7 +829,11 @@ pub enum Expr<'a> { args: &'a [Symbol], }, RunLowLevel(LowLevel, &'a [Symbol]), - ForeignCall(ForeignSymbol, &'a [Symbol]), + ForeignCall { + foreign_symbol: ForeignSymbol, + arguments: &'a [Symbol], + ret_layout: Layout<'a>, + }, Tag { tag_layout: Layout<'a>, @@ -944,11 +948,15 @@ impl<'a> Expr<'a> { .text(format!("lowlevel {:?} ", lowlevel)) .append(alloc.intersperse(it, " ")) } - ForeignCall(symbol, args) => { - let it = args.iter().map(|s| symbol_to_doc(alloc, *s)); + ForeignCall { + foreign_symbol, + arguments, + .. + } => { + let it = arguments.iter().map(|s| symbol_to_doc(alloc, *s)); alloc - .text(format!("foreign {:?} ", symbol.as_str())) + .text(format!("foreign {:?} ", foreign_symbol.as_str())) .append(alloc.intersperse(it, " ")) } Tag { @@ -3191,7 +3199,11 @@ pub fn with_hole<'a>( let result = Stmt::Let( assigned, - Expr::ForeignCall(foreign_symbol.clone(), arg_symbols), + Expr::ForeignCall { + foreign_symbol: foreign_symbol.clone(), + arguments: arg_symbols, + ret_layout: layout.clone(), + }, layout, hole, ); @@ -4035,10 +4047,14 @@ fn substitute_in_expr<'a>( None } } - ForeignCall(symbol, args) => { + ForeignCall { + foreign_symbol, + arguments, + ret_layout, + } => { let mut did_change = false; let new_args = Vec::from_iter_in( - args.iter().map(|s| match substitute(subs, *s) { + arguments.iter().map(|s| match substitute(subs, *s) { None => *s, Some(s) => { did_change = true; @@ -4051,7 +4067,11 @@ fn substitute_in_expr<'a>( if did_change { let args = new_args.into_bump_slice(); - Some(ForeignCall(symbol.clone(), args)) + Some(ForeignCall { + foreign_symbol: foreign_symbol.clone(), + arguments: args, + ret_layout: ret_layout.clone(), + }) } else { None } diff --git a/examples/effect/Effect.roc b/examples/effect/Effect.roc index 1b7e3b59ea..f01a5484c3 100644 --- a/examples/effect/Effect.roc +++ b/examples/effect/Effect.roc @@ -3,4 +3,4 @@ platform folkertdev/foo requires [ main ] imports [] effects - { putChar Int -> Effect {} } + { putChar Int -> Effect {}, putLine Str -> Effect {} } diff --git a/examples/effect/Main.roc b/examples/effect/Main.roc index 820b8b02af..767c135fbf 100644 --- a/examples/effect/Main.roc +++ b/examples/effect/Main.roc @@ -2,7 +2,8 @@ app Main provides [ main ] imports [ Effect ] main : Effect.Effect {} as Fx main = - e = Effect.putChar 69 - d = Effect.putChar 68 - - e |> Effect.after \{} -> d + + Effect.putLine "Hello" + |> Effect.after \{} -> Effect.putChar 87 + # |> Effect.after \{} -> Effect.putLine "orld" + diff --git a/examples/effect/platform/src/lib.rs b/examples/effect/platform/src/lib.rs index 30daf31e9e..60319ea905 100644 --- a/examples/effect/platform/src/lib.rs +++ b/examples/effect/platform/src/lib.rs @@ -1,5 +1,6 @@ use roc_std::alloca; use roc_std::RocCallResult; +use roc_std::RocStr; use std::alloc::Layout; use std::time::SystemTime; @@ -25,6 +26,15 @@ pub fn roc_fx_putChar(foo: i64) -> () { () } +#[no_mangle] +pub fn roc_fx_putLine(line: RocStr) -> () { + let bytes = line.as_slice(); + let string = unsafe { std::str::from_utf8_unchecked(bytes) }; + println!("{}", string); + + () +} + unsafe fn call_the_closure(function_pointer: *const u8, closure_data_ptr: *const u8) -> i64 { let size = size_Fx() as usize;