mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-29 14:54:47 +00:00
remove by-pointer calls
This commit is contained in:
parent
45111ec7e6
commit
ae5b0d8cfd
5 changed files with 20 additions and 211 deletions
|
@ -829,58 +829,6 @@ pub fn build_exp_call<'a, 'ctx, 'env>(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
CallType::ByPointer {
|
|
||||||
name, full_layout, ..
|
|
||||||
} => {
|
|
||||||
let sub_expr = load_symbol(scope, name);
|
|
||||||
|
|
||||||
let mut arg_vals: Vec<BasicValueEnum> =
|
|
||||||
Vec::with_capacity_in(arguments.len(), env.arena);
|
|
||||||
|
|
||||||
for arg in arguments.iter() {
|
|
||||||
arg_vals.push(load_symbol(scope, arg));
|
|
||||||
}
|
|
||||||
|
|
||||||
let call = match (full_layout, sub_expr) {
|
|
||||||
(_, BasicValueEnum::PointerValue(ptr)) => {
|
|
||||||
env.builder.build_call(ptr, arg_vals.as_slice(), "tmp")
|
|
||||||
}
|
|
||||||
(Layout::Closure(_, _, _), BasicValueEnum::StructValue(closure_struct)) => {
|
|
||||||
let fpointer = env
|
|
||||||
.builder
|
|
||||||
.build_extract_value(closure_struct, 0, "fpointer")
|
|
||||||
.unwrap()
|
|
||||||
.into_pointer_value();
|
|
||||||
|
|
||||||
let closure_data = env
|
|
||||||
.builder
|
|
||||||
.build_extract_value(closure_struct, 1, "closure_data")
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
arg_vals.push(closure_data);
|
|
||||||
env.builder.build_call(fpointer, arg_vals.as_slice(), "tmp")
|
|
||||||
}
|
|
||||||
non_ptr => {
|
|
||||||
panic!(
|
|
||||||
"Tried to call by pointer, but encountered a non-pointer: {:?} {:?} {:?}",
|
|
||||||
name, non_ptr, full_layout
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if env.exposed_to_host.contains(name) {
|
|
||||||
// If this is an external-facing function, use the C calling convention.
|
|
||||||
call.set_call_convention(C_CALL_CONV);
|
|
||||||
} else {
|
|
||||||
// If it's an internal-only function, use the fast calling convention.
|
|
||||||
call.set_call_convention(FAST_CALL_CONV);
|
|
||||||
}
|
|
||||||
|
|
||||||
call.try_as_basic_value()
|
|
||||||
.left()
|
|
||||||
.unwrap_or_else(|| panic!("LLVM error: Invalid call by pointer."))
|
|
||||||
}
|
|
||||||
|
|
||||||
CallType::LowLevel { op } => {
|
CallType::LowLevel { op } => {
|
||||||
run_low_level(env, layout_ids, scope, parent, layout, *op, arguments)
|
run_low_level(env, layout_ids, scope, parent, layout, *op, arguments)
|
||||||
}
|
}
|
||||||
|
@ -2086,61 +2034,7 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>(
|
||||||
fail,
|
fail,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
CallType::ByPointer { name, .. } => {
|
|
||||||
let sub_expr = load_symbol(scope, &name);
|
|
||||||
|
|
||||||
match sub_expr {
|
|
||||||
BasicValueEnum::PointerValue(function_ptr) => {
|
|
||||||
// basic call by pointer
|
|
||||||
invoke_roc_function(
|
|
||||||
env,
|
|
||||||
layout_ids,
|
|
||||||
scope,
|
|
||||||
parent,
|
|
||||||
*symbol,
|
|
||||||
*layout,
|
|
||||||
function_ptr.into(),
|
|
||||||
call.arguments,
|
|
||||||
None,
|
|
||||||
pass,
|
|
||||||
fail,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
BasicValueEnum::StructValue(ptr_and_data) => {
|
|
||||||
// this is a closure
|
|
||||||
let builder = env.builder;
|
|
||||||
|
|
||||||
let function_ptr = builder
|
|
||||||
.build_extract_value(ptr_and_data, 0, "function_ptr")
|
|
||||||
.unwrap()
|
|
||||||
.into_pointer_value();
|
|
||||||
|
|
||||||
let closure_data = builder
|
|
||||||
.build_extract_value(ptr_and_data, 1, "closure_data")
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
invoke_roc_function(
|
|
||||||
env,
|
|
||||||
layout_ids,
|
|
||||||
scope,
|
|
||||||
parent,
|
|
||||||
*symbol,
|
|
||||||
*layout,
|
|
||||||
function_ptr.into(),
|
|
||||||
call.arguments,
|
|
||||||
Some(closure_data),
|
|
||||||
pass,
|
|
||||||
fail,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
non_ptr => {
|
|
||||||
panic!(
|
|
||||||
"Tried to call by pointer, but encountered a non-pointer: {:?}",
|
|
||||||
non_ptr
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
CallType::Foreign {
|
CallType::Foreign {
|
||||||
ref foreign_symbol,
|
ref foreign_symbol,
|
||||||
ref ret_layout,
|
ref ret_layout,
|
||||||
|
|
|
@ -545,9 +545,6 @@ where
|
||||||
|
|
||||||
match call_type {
|
match call_type {
|
||||||
CallType::ByName { .. } => {}
|
CallType::ByName { .. } => {}
|
||||||
CallType::ByPointer { name: sym, .. } => {
|
|
||||||
self.set_last_seen(*sym, stmt);
|
|
||||||
}
|
|
||||||
CallType::LowLevel { .. } => {}
|
CallType::LowLevel { .. } => {}
|
||||||
CallType::HigherOrderLowLevel { .. } => {}
|
CallType::HigherOrderLowLevel { .. } => {}
|
||||||
CallType::Foreign { .. } => {}
|
CallType::Foreign { .. } => {}
|
||||||
|
|
|
@ -399,14 +399,6 @@ impl<'a> BorrowInfState<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ByPointer { .. } => {
|
|
||||||
// the return value will be owned
|
|
||||||
self.own_var(z);
|
|
||||||
|
|
||||||
// if the function exects an owned argument (ps), the argument must be owned (args)
|
|
||||||
self.own_args(arguments);
|
|
||||||
}
|
|
||||||
|
|
||||||
LowLevel { op } => {
|
LowLevel { op } => {
|
||||||
debug_assert!(!op.is_higher_order());
|
debug_assert!(!op.is_higher_order());
|
||||||
|
|
||||||
|
@ -599,42 +591,27 @@ impl<'a> BorrowInfState<'a> {
|
||||||
|
|
||||||
#[allow(clippy::many_single_char_names)]
|
#[allow(clippy::many_single_char_names)]
|
||||||
fn preserve_tail_call(&mut self, x: Symbol, v: &Expr<'a>, b: &Stmt<'a>) {
|
fn preserve_tail_call(&mut self, x: Symbol, v: &Expr<'a>, b: &Stmt<'a>) {
|
||||||
match (v, b) {
|
if let (
|
||||||
(
|
Expr::Call(crate::ir::Call {
|
||||||
Expr::Call(crate::ir::Call {
|
call_type:
|
||||||
call_type:
|
crate::ir::CallType::ByName {
|
||||||
crate::ir::CallType::ByName {
|
name: g,
|
||||||
name: g,
|
full_layout,
|
||||||
full_layout,
|
..
|
||||||
..
|
},
|
||||||
},
|
arguments: ys,
|
||||||
arguments: ys,
|
..
|
||||||
..
|
}),
|
||||||
}),
|
Stmt::Ret(z),
|
||||||
Stmt::Ret(z),
|
) = (v, b)
|
||||||
)
|
{
|
||||||
| (
|
if self.current_proc == *g && x == *z {
|
||||||
Expr::Call(crate::ir::Call {
|
// anonymous functions (for which the ps may not be known)
|
||||||
call_type:
|
// can never be tail-recursive, so this is fine
|
||||||
crate::ir::CallType::ByPointer {
|
if let Some(ps) = self.param_map.get_symbol(*g, *full_layout) {
|
||||||
name: g,
|
self.own_params_using_args(ys, ps)
|
||||||
full_layout,
|
|
||||||
..
|
|
||||||
},
|
|
||||||
arguments: ys,
|
|
||||||
..
|
|
||||||
}),
|
|
||||||
Stmt::Ret(z),
|
|
||||||
) => {
|
|
||||||
if self.current_proc == *g && x == *z {
|
|
||||||
// anonymous functions (for which the ps may not be known)
|
|
||||||
// can never be tail-recursive, so this is fine
|
|
||||||
if let Some(ps) = self.param_map.get_symbol(*g, *full_layout) {
|
|
||||||
self.own_params_using_args(ys, ps)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -700,18 +700,6 @@ impl<'a> Context<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ByPointer { .. } => {
|
|
||||||
let v = Expr::Call(crate::ir::Call {
|
|
||||||
call_type,
|
|
||||||
arguments,
|
|
||||||
});
|
|
||||||
|
|
||||||
self.add_inc_before_consume_all(
|
|
||||||
arguments,
|
|
||||||
self.arena.alloc(Stmt::Let(z, v, l, b)),
|
|
||||||
b_live_vars,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -993,9 +981,6 @@ impl<'a> Context<'a> {
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CallType::ByPointer { .. } => {
|
|
||||||
self.add_inc_before_consume_all(call.arguments, cont, &invoke_live_vars)
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
(stmt, invoke_live_vars)
|
(stmt, invoke_live_vars)
|
||||||
|
|
|
@ -1038,15 +1038,6 @@ impl<'a> Call<'a> {
|
||||||
|
|
||||||
alloc.text("CallByName ").append(alloc.intersperse(it, " "))
|
alloc.text("CallByName ").append(alloc.intersperse(it, " "))
|
||||||
}
|
}
|
||||||
CallType::ByPointer { name, .. } => {
|
|
||||||
let it = std::iter::once(name)
|
|
||||||
.chain(arguments.iter().copied())
|
|
||||||
.map(|s| symbol_to_doc(alloc, s));
|
|
||||||
|
|
||||||
alloc
|
|
||||||
.text("CallByPointer ")
|
|
||||||
.append(alloc.intersperse(it, " "))
|
|
||||||
}
|
|
||||||
LowLevel { op: lowlevel } => {
|
LowLevel { op: lowlevel } => {
|
||||||
let it = arguments.iter().map(|s| symbol_to_doc(alloc, *s));
|
let it = arguments.iter().map(|s| symbol_to_doc(alloc, *s));
|
||||||
|
|
||||||
|
@ -1083,13 +1074,6 @@ pub enum CallType<'a> {
|
||||||
ret_layout: Layout<'a>,
|
ret_layout: Layout<'a>,
|
||||||
arg_layouts: &'a [Layout<'a>],
|
arg_layouts: &'a [Layout<'a>],
|
||||||
},
|
},
|
||||||
ByPointer {
|
|
||||||
name: Symbol,
|
|
||||||
|
|
||||||
full_layout: Layout<'a>,
|
|
||||||
ret_layout: Layout<'a>,
|
|
||||||
arg_layouts: &'a [Layout<'a>],
|
|
||||||
},
|
|
||||||
Foreign {
|
Foreign {
|
||||||
foreign_symbol: ForeignSymbol,
|
foreign_symbol: ForeignSymbol,
|
||||||
ret_layout: Layout<'a>,
|
ret_layout: Layout<'a>,
|
||||||
|
@ -4102,20 +4086,7 @@ pub fn with_hole<'a>(
|
||||||
hole,
|
hole,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
result = Stmt::Let(
|
unreachable!("calling a non-closure layout")
|
||||||
assigned,
|
|
||||||
Expr::Call(self::Call {
|
|
||||||
call_type: CallType::ByPointer {
|
|
||||||
name: function_symbol,
|
|
||||||
full_layout,
|
|
||||||
ret_layout,
|
|
||||||
arg_layouts,
|
|
||||||
},
|
|
||||||
arguments: arg_symbols,
|
|
||||||
}),
|
|
||||||
ret_layout,
|
|
||||||
hole,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
NotASymbol => {
|
NotASymbol => {
|
||||||
|
@ -5335,17 +5306,6 @@ fn substitute_in_call<'a>(
|
||||||
ret_layout: *ret_layout,
|
ret_layout: *ret_layout,
|
||||||
full_layout: *full_layout,
|
full_layout: *full_layout,
|
||||||
}),
|
}),
|
||||||
CallType::ByPointer {
|
|
||||||
name,
|
|
||||||
arg_layouts,
|
|
||||||
ret_layout,
|
|
||||||
full_layout,
|
|
||||||
} => substitute(subs, *name).map(|new| CallType::ByPointer {
|
|
||||||
name: new,
|
|
||||||
arg_layouts,
|
|
||||||
ret_layout: *ret_layout,
|
|
||||||
full_layout: *full_layout,
|
|
||||||
}),
|
|
||||||
CallType::Foreign { .. } => None,
|
CallType::Foreign { .. } => None,
|
||||||
CallType::LowLevel { .. } => None,
|
CallType::LowLevel { .. } => None,
|
||||||
CallType::HigherOrderLowLevel { .. } => None,
|
CallType::HigherOrderLowLevel { .. } => None,
|
||||||
|
@ -6050,10 +6010,6 @@ fn can_throw_exception(call: &Call) -> bool {
|
||||||
| Symbol::NUM_ABS
|
| Symbol::NUM_ABS
|
||||||
| Symbol::NUM_NEG
|
| Symbol::NUM_NEG
|
||||||
),
|
),
|
||||||
CallType::ByPointer { .. } => {
|
|
||||||
// we don't know what we're calling; it might throw, so better be safe than sorry
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
CallType::Foreign { .. } => {
|
CallType::Foreign { .. } => {
|
||||||
// calling foreign functions is very unsafe
|
// calling foreign functions is very unsafe
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue