Compare commits
5 Commits
e9315c4ca2
...
c3b7aa6386
Author | SHA1 | Date |
---|---|---|
David Mak | c3b7aa6386 | |
David Mak | ae3b9bfd79 | |
David Mak | 3cdeba2f87 | |
David Mak | 69320a6cf1 | |
David Mak | 9e0601837a |
|
@ -24,3 +24,4 @@ features = ["llvm14-0", "target-x86", "target-arm", "target-riscv", "no-libffi-l
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
init-llvm-profile = []
|
init-llvm-profile = []
|
||||||
|
no-escape-analysis = ["nac3core/no-escape-analysis"]
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
from min_artiq import *
|
||||||
|
from numpy import ndarray, zeros as np_zeros
|
||||||
|
|
||||||
|
|
||||||
|
@nac3
|
||||||
|
class StrFail:
|
||||||
|
core: KernelInvariant[Core]
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.core = Core()
|
||||||
|
|
||||||
|
@kernel
|
||||||
|
def hello(self, arg: str):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@kernel
|
||||||
|
def consume_ndarray(self, arg: ndarray[str, 1]):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
self.hello("world")
|
||||||
|
self.consume_ndarray(np_zeros([10], dtype=str))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
StrFail().run()
|
|
@ -1,9 +1,12 @@
|
||||||
use nac3core::{
|
use nac3core::{
|
||||||
codegen::{
|
codegen::{
|
||||||
classes::{ListValue, NDArrayValue, RangeValue, UntypedArrayLikeAccessor},
|
classes::{
|
||||||
|
ArrayLikeIndexer, ArrayLikeValue, ArraySliceValue, ListValue, NDArrayType,
|
||||||
|
NDArrayValue, ProxyType, ProxyValue, RangeValue, UntypedArrayLikeAccessor,
|
||||||
|
},
|
||||||
expr::{destructure_range, gen_call},
|
expr::{destructure_range, gen_call},
|
||||||
irrt::call_ndarray_calc_size,
|
irrt::call_ndarray_calc_size,
|
||||||
llvm_intrinsics::{call_int_smax, call_stackrestore, call_stacksave},
|
llvm_intrinsics::{call_int_smax, call_memcpy_generic, call_stackrestore, call_stacksave},
|
||||||
stmt::{gen_block, gen_for_callback_incrementing, gen_if_callback, gen_with},
|
stmt::{gen_block, gen_for_callback_incrementing, gen_if_callback, gen_with},
|
||||||
CodeGenContext, CodeGenerator,
|
CodeGenContext, CodeGenerator,
|
||||||
},
|
},
|
||||||
|
@ -17,8 +20,8 @@ use nac3parser::ast::{Expr, ExprKind, Located, Stmt, StmtKind, StrRef};
|
||||||
use inkwell::{
|
use inkwell::{
|
||||||
context::Context,
|
context::Context,
|
||||||
module::Linkage,
|
module::Linkage,
|
||||||
types::IntType,
|
types::{BasicType, IntType},
|
||||||
values::{BasicValueEnum, StructValue},
|
values::{BasicValueEnum, PointerValue, StructValue},
|
||||||
AddressSpace, IntPredicate,
|
AddressSpace, IntPredicate,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -422,7 +425,10 @@ fn gen_rpc_tag(
|
||||||
} else {
|
} else {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
};
|
};
|
||||||
assert!((0u64..=u64::from(u8::MAX)).contains(&ndarray_ndims));
|
assert!(
|
||||||
|
(0u64..=u64::from(u8::MAX)).contains(&ndarray_ndims),
|
||||||
|
"Only NDArrays of sizes between 0 and 255 can be RPCed"
|
||||||
|
);
|
||||||
|
|
||||||
buffer.push(b'a');
|
buffer.push(b'a');
|
||||||
buffer.push((ndarray_ndims & 0xFF) as u8);
|
buffer.push((ndarray_ndims & 0xFF) as u8);
|
||||||
|
@ -434,6 +440,313 @@ fn gen_rpc_tag(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Formats an RPC argument to conform to the expected format required by `send_value`.
|
||||||
|
///
|
||||||
|
/// See `artiq/firmware/libproto_artiq/rpc_proto.rs` for the expected format.
|
||||||
|
fn format_rpc_arg<'ctx>(
|
||||||
|
generator: &mut dyn CodeGenerator,
|
||||||
|
ctx: &mut CodeGenContext<'ctx, '_>,
|
||||||
|
(arg, arg_ty, arg_idx): (BasicValueEnum<'ctx>, Type, usize),
|
||||||
|
) -> PointerValue<'ctx> {
|
||||||
|
let llvm_i8 = ctx.ctx.i8_type();
|
||||||
|
let llvm_pi8 = llvm_i8.ptr_type(AddressSpace::default());
|
||||||
|
|
||||||
|
let arg_slot = match &*ctx.unifier.get_ty_immutable(arg_ty) {
|
||||||
|
TypeEnum::TObj { obj_id, .. } if *obj_id == PrimDef::NDArray.id() => {
|
||||||
|
// NAC3: NDArray = { usize, usize*, T* }
|
||||||
|
// libproto_artiq: NDArray = [data[..], dim_sz[..]]
|
||||||
|
|
||||||
|
let llvm_i1 = ctx.ctx.bool_type();
|
||||||
|
let llvm_usize = generator.get_size_type(ctx.ctx);
|
||||||
|
|
||||||
|
let (elem_ty, _) = unpack_ndarray_var_tys(&mut ctx.unifier, arg_ty);
|
||||||
|
let llvm_arg_ty =
|
||||||
|
NDArrayType::new(generator, ctx.ctx, ctx.get_llvm_type(generator, elem_ty));
|
||||||
|
let llvm_arg = NDArrayValue::from_ptr_val(arg.into_pointer_value(), llvm_usize, None);
|
||||||
|
|
||||||
|
let llvm_usize_sizeof = ctx
|
||||||
|
.builder
|
||||||
|
.build_int_truncate_or_bit_cast(llvm_arg_ty.size_type().size_of(), llvm_usize, "")
|
||||||
|
.unwrap();
|
||||||
|
let llvm_pdata_sizeof = ctx
|
||||||
|
.builder
|
||||||
|
.build_int_truncate_or_bit_cast(
|
||||||
|
llvm_arg_ty.element_type().ptr_type(AddressSpace::default()).size_of(),
|
||||||
|
llvm_usize,
|
||||||
|
"",
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let dims_buf_sz =
|
||||||
|
ctx.builder.build_int_mul(llvm_arg.load_ndims(ctx), llvm_usize_sizeof, "").unwrap();
|
||||||
|
|
||||||
|
let buffer_size =
|
||||||
|
ctx.builder.build_int_add(dims_buf_sz, llvm_pdata_sizeof, "").unwrap();
|
||||||
|
|
||||||
|
let buffer = ctx.builder.build_array_alloca(llvm_i8, buffer_size, "rpc.arg").unwrap();
|
||||||
|
let buffer = ArraySliceValue::from_ptr_val(buffer, buffer_size, Some("rpc.arg"));
|
||||||
|
|
||||||
|
call_memcpy_generic(
|
||||||
|
ctx,
|
||||||
|
buffer.base_ptr(ctx, generator),
|
||||||
|
llvm_arg.ptr_to_data(ctx),
|
||||||
|
llvm_pdata_sizeof,
|
||||||
|
llvm_i1.const_zero(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let pbuffer_dims_begin =
|
||||||
|
unsafe { buffer.ptr_offset_unchecked(ctx, generator, &llvm_pdata_sizeof, None) };
|
||||||
|
call_memcpy_generic(
|
||||||
|
ctx,
|
||||||
|
pbuffer_dims_begin,
|
||||||
|
llvm_arg.dim_sizes().base_ptr(ctx, generator),
|
||||||
|
dims_buf_sz,
|
||||||
|
llvm_i1.const_zero(),
|
||||||
|
);
|
||||||
|
|
||||||
|
buffer.base_ptr(ctx, generator)
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => {
|
||||||
|
let arg_slot = generator
|
||||||
|
.gen_var_alloc(ctx, arg.get_type(), Some(&format!("rpc.arg{arg_idx}")))
|
||||||
|
.unwrap();
|
||||||
|
ctx.builder.build_store(arg_slot, arg).unwrap();
|
||||||
|
|
||||||
|
ctx.builder
|
||||||
|
.build_bitcast(arg_slot, llvm_pi8, "rpc.arg")
|
||||||
|
.map(BasicValueEnum::into_pointer_value)
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
debug_assert_eq!(arg_slot.get_type(), llvm_pi8);
|
||||||
|
|
||||||
|
arg_slot
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Formats an RPC return value to conform to the expected format required by NAC3.
|
||||||
|
fn format_rpc_ret<'ctx>(
|
||||||
|
generator: &mut dyn CodeGenerator,
|
||||||
|
ctx: &mut CodeGenContext<'ctx, '_>,
|
||||||
|
ret_ty: Type,
|
||||||
|
) -> Option<BasicValueEnum<'ctx>> {
|
||||||
|
// -- receive value:
|
||||||
|
// T result = {
|
||||||
|
// void *ret_ptr = alloca(sizeof(T));
|
||||||
|
// void *ptr = ret_ptr;
|
||||||
|
// loop: int size = rpc_recv(ptr);
|
||||||
|
// // Non-zero: Provide `size` bytes of extra storage for variable-length data.
|
||||||
|
// if(size) { ptr = alloca(size); goto loop; }
|
||||||
|
// else *(T*)ret_ptr
|
||||||
|
// }
|
||||||
|
|
||||||
|
let llvm_i8 = ctx.ctx.i8_type();
|
||||||
|
let llvm_i32 = ctx.ctx.i32_type();
|
||||||
|
let llvm_pi8 = llvm_i8.ptr_type(AddressSpace::default());
|
||||||
|
let llvm_ppi8 = llvm_pi8.ptr_type(AddressSpace::default());
|
||||||
|
|
||||||
|
let rpc_recv = ctx.module.get_function("rpc_recv").unwrap_or_else(|| {
|
||||||
|
ctx.module.add_function("rpc_recv", llvm_i32.fn_type(&[llvm_pi8.into()], false), None)
|
||||||
|
});
|
||||||
|
|
||||||
|
if ctx.unifier.unioned(ret_ty, ctx.primitives.none) {
|
||||||
|
ctx.build_call_or_invoke(rpc_recv, &[llvm_pi8.const_null().into()], "rpc_recv");
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let prehead_bb = ctx.builder.get_insert_block().unwrap();
|
||||||
|
let current_function = prehead_bb.get_parent().unwrap();
|
||||||
|
let head_bb = ctx.ctx.append_basic_block(current_function, "rpc.head");
|
||||||
|
let alloc_bb = ctx.ctx.append_basic_block(current_function, "rpc.continue");
|
||||||
|
let tail_bb = ctx.ctx.append_basic_block(current_function, "rpc.tail");
|
||||||
|
|
||||||
|
let llvm_ret_ty = ctx.get_llvm_abi_type(generator, ret_ty);
|
||||||
|
|
||||||
|
let result = match &*ctx.unifier.get_ty_immutable(ret_ty) {
|
||||||
|
TypeEnum::TObj { obj_id, .. } if *obj_id == PrimDef::NDArray.id() => {
|
||||||
|
let llvm_i1 = ctx.ctx.bool_type();
|
||||||
|
let llvm_usize = generator.get_size_type(ctx.ctx);
|
||||||
|
|
||||||
|
let (elem_ty, ndims) = unpack_ndarray_var_tys(&mut ctx.unifier, ret_ty);
|
||||||
|
let llvm_elem_ty = ctx.get_llvm_type(generator, elem_ty);
|
||||||
|
let llvm_ret_ty = NDArrayType::new(generator, ctx.ctx, llvm_elem_ty);
|
||||||
|
let ndarray = llvm_ret_ty.new_value(generator, ctx, Some("rpc.result"));
|
||||||
|
|
||||||
|
let ndims =
|
||||||
|
if let TypeEnum::TLiteral { values, .. } = &*ctx.unifier.get_ty_immutable(ndims) {
|
||||||
|
assert_eq!(values.len(), 1);
|
||||||
|
|
||||||
|
u64::try_from(values[0].clone()).unwrap()
|
||||||
|
} else {
|
||||||
|
unreachable!();
|
||||||
|
};
|
||||||
|
ndarray.store_ndims(ctx, generator, llvm_usize.const_int(ndims, false));
|
||||||
|
ndarray.create_dim_sizes(ctx, llvm_usize, ndarray.load_ndims(ctx));
|
||||||
|
|
||||||
|
let llvm_usize_sizeof = ctx
|
||||||
|
.builder
|
||||||
|
.build_int_truncate_or_bit_cast(llvm_ret_ty.size_type().size_of(), llvm_usize, "")
|
||||||
|
.unwrap();
|
||||||
|
let llvm_pdata_sizeof = ctx
|
||||||
|
.builder
|
||||||
|
.build_int_truncate_or_bit_cast(
|
||||||
|
llvm_ret_ty.element_type().size_of().unwrap(),
|
||||||
|
llvm_usize,
|
||||||
|
"",
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let dims_buf_sz =
|
||||||
|
ctx.builder.build_int_mul(ndarray.load_ndims(ctx), llvm_usize_sizeof, "").unwrap();
|
||||||
|
|
||||||
|
let buffer_size =
|
||||||
|
ctx.builder.build_int_add(dims_buf_sz, llvm_pdata_sizeof, "").unwrap();
|
||||||
|
|
||||||
|
let buffer =
|
||||||
|
ctx.builder.build_array_alloca(llvm_pi8, buffer_size, "rpc.buffer").unwrap();
|
||||||
|
let buffer = ctx
|
||||||
|
.builder
|
||||||
|
.build_bitcast(buffer, llvm_pi8, "")
|
||||||
|
.map(BasicValueEnum::into_pointer_value)
|
||||||
|
.unwrap();
|
||||||
|
let buffer = ArraySliceValue::from_ptr_val(
|
||||||
|
buffer,
|
||||||
|
ctx.builder
|
||||||
|
.build_left_shift(buffer_size, llvm_usize.const_int(2, false), "")
|
||||||
|
.unwrap(),
|
||||||
|
Some("rpc.buffer.ptr"),
|
||||||
|
);
|
||||||
|
|
||||||
|
let i_addr = ctx.builder.build_alloca(llvm_usize, "i.addr").unwrap();
|
||||||
|
ctx.builder.build_store(i_addr, llvm_usize.const_zero()).unwrap();
|
||||||
|
ctx.builder.build_unconditional_branch(head_bb).unwrap();
|
||||||
|
|
||||||
|
ctx.builder.position_at_end(head_bb);
|
||||||
|
let phi = ctx.builder.build_phi(llvm_pi8, "rpc.ptr").unwrap();
|
||||||
|
phi.add_incoming(&[(&buffer.base_ptr(ctx, generator), prehead_bb)]);
|
||||||
|
let alloc_size = ctx
|
||||||
|
.build_call_or_invoke(rpc_recv, &[phi.as_basic_value()], "rpc.size.next")
|
||||||
|
.map(BasicValueEnum::into_int_value)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// Parse metadata block for ndarrays
|
||||||
|
gen_if_callback(
|
||||||
|
generator,
|
||||||
|
ctx,
|
||||||
|
|_, ctx| {
|
||||||
|
let i = ctx
|
||||||
|
.builder
|
||||||
|
.build_load(i_addr, "")
|
||||||
|
.map(BasicValueEnum::into_int_value)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
Ok(ctx
|
||||||
|
.builder
|
||||||
|
.build_int_compare(IntPredicate::EQ, i, llvm_usize.const_zero(), "")
|
||||||
|
.unwrap())
|
||||||
|
},
|
||||||
|
|generator, ctx| {
|
||||||
|
let data_addr = phi.as_basic_value().into_pointer_value();
|
||||||
|
let data_addr = ctx
|
||||||
|
.builder
|
||||||
|
.build_load(
|
||||||
|
ctx.builder
|
||||||
|
.build_bitcast(data_addr, llvm_ppi8, "")
|
||||||
|
.map(BasicValueEnum::into_pointer_value)
|
||||||
|
.unwrap(),
|
||||||
|
"",
|
||||||
|
)
|
||||||
|
.map(BasicValueEnum::into_pointer_value)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
call_memcpy_generic(
|
||||||
|
ctx,
|
||||||
|
ndarray.ptr_to_data(ctx),
|
||||||
|
data_addr,
|
||||||
|
llvm_pdata_sizeof,
|
||||||
|
llvm_i1.const_zero(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let pbuffer_dims_begin = unsafe {
|
||||||
|
buffer.ptr_offset_unchecked(ctx, generator, &llvm_pdata_sizeof, None)
|
||||||
|
};
|
||||||
|
call_memcpy_generic(
|
||||||
|
ctx,
|
||||||
|
ndarray.dim_sizes().base_ptr(ctx, generator),
|
||||||
|
pbuffer_dims_begin,
|
||||||
|
dims_buf_sz,
|
||||||
|
llvm_i1.const_zero(),
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
},
|
||||||
|
|_, _| Ok(()),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let is_done = ctx
|
||||||
|
.builder
|
||||||
|
.build_int_compare(IntPredicate::EQ, llvm_i32.const_zero(), alloc_size, "rpc.done")
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
ctx.builder.build_conditional_branch(is_done, tail_bb, alloc_bb).unwrap();
|
||||||
|
ctx.builder.position_at_end(alloc_bb);
|
||||||
|
|
||||||
|
let alloc_ptr =
|
||||||
|
ctx.builder.build_array_alloca(llvm_pi8, alloc_size, "rpc.alloc").unwrap();
|
||||||
|
let alloc_ptr = ctx
|
||||||
|
.builder
|
||||||
|
.build_bitcast(alloc_ptr, llvm_pi8, "")
|
||||||
|
.map(BasicValueEnum::into_pointer_value)
|
||||||
|
.unwrap();
|
||||||
|
phi.add_incoming(&[(&alloc_ptr, alloc_bb)]);
|
||||||
|
let i =
|
||||||
|
ctx.builder.build_load(i_addr, "i").map(BasicValueEnum::into_int_value).unwrap();
|
||||||
|
let i = ctx.builder.build_int_add(i, llvm_usize.const_int(1, false), "").unwrap();
|
||||||
|
ctx.builder.build_store(i_addr, i).unwrap();
|
||||||
|
ctx.builder.build_unconditional_branch(head_bb).unwrap();
|
||||||
|
|
||||||
|
ctx.builder.position_at_end(tail_bb);
|
||||||
|
ndarray.as_base_value().into()
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => {
|
||||||
|
let slot = ctx.builder.build_alloca(llvm_ret_ty, "rpc.ret.slot").unwrap();
|
||||||
|
let slotgen = ctx.builder.build_bitcast(slot, llvm_pi8, "rpc.ret.ptr").unwrap();
|
||||||
|
ctx.builder.build_unconditional_branch(head_bb).unwrap();
|
||||||
|
ctx.builder.position_at_end(head_bb);
|
||||||
|
|
||||||
|
let phi = ctx.builder.build_phi(llvm_pi8, "rpc.ptr").unwrap();
|
||||||
|
phi.add_incoming(&[(&slotgen, prehead_bb)]);
|
||||||
|
let alloc_size = ctx
|
||||||
|
.build_call_or_invoke(rpc_recv, &[phi.as_basic_value()], "rpc.size.next")
|
||||||
|
.unwrap()
|
||||||
|
.into_int_value();
|
||||||
|
let is_done = ctx
|
||||||
|
.builder
|
||||||
|
.build_int_compare(IntPredicate::EQ, llvm_i32.const_zero(), alloc_size, "rpc.done")
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
ctx.builder.build_conditional_branch(is_done, tail_bb, alloc_bb).unwrap();
|
||||||
|
ctx.builder.position_at_end(alloc_bb);
|
||||||
|
|
||||||
|
let alloc_ptr =
|
||||||
|
ctx.builder.build_array_alloca(llvm_pi8, alloc_size, "rpc.alloc").unwrap();
|
||||||
|
let alloc_ptr =
|
||||||
|
ctx.builder.build_bitcast(alloc_ptr, llvm_pi8, "rpc.alloc.ptr").unwrap();
|
||||||
|
phi.add_incoming(&[(&alloc_ptr, alloc_bb)]);
|
||||||
|
ctx.builder.build_unconditional_branch(head_bb).unwrap();
|
||||||
|
|
||||||
|
ctx.builder.position_at_end(tail_bb);
|
||||||
|
|
||||||
|
ctx.builder.build_load(slot, "rpc.result").unwrap()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Some(result)
|
||||||
|
}
|
||||||
|
|
||||||
fn rpc_codegen_callback_fn<'ctx>(
|
fn rpc_codegen_callback_fn<'ctx>(
|
||||||
ctx: &mut CodeGenContext<'ctx, '_>,
|
ctx: &mut CodeGenContext<'ctx, '_>,
|
||||||
obj: Option<(Type, ValueEnum<'ctx>)>,
|
obj: Option<(Type, ValueEnum<'ctx>)>,
|
||||||
|
@ -441,10 +754,10 @@ fn rpc_codegen_callback_fn<'ctx>(
|
||||||
args: Vec<(Option<StrRef>, ValueEnum<'ctx>)>,
|
args: Vec<(Option<StrRef>, ValueEnum<'ctx>)>,
|
||||||
generator: &mut dyn CodeGenerator,
|
generator: &mut dyn CodeGenerator,
|
||||||
) -> Result<Option<BasicValueEnum<'ctx>>, String> {
|
) -> Result<Option<BasicValueEnum<'ctx>>, String> {
|
||||||
let ptr_type = ctx.ctx.i8_type().ptr_type(AddressSpace::default());
|
|
||||||
let size_type = generator.get_size_type(ctx.ctx);
|
|
||||||
let int8 = ctx.ctx.i8_type();
|
let int8 = ctx.ctx.i8_type();
|
||||||
let int32 = ctx.ctx.i32_type();
|
let int32 = ctx.ctx.i32_type();
|
||||||
|
let size_type = generator.get_size_type(ctx.ctx);
|
||||||
|
let ptr_type = int8.ptr_type(AddressSpace::default());
|
||||||
let tag_ptr_type = ctx.ctx.struct_type(&[ptr_type.into(), size_type.into()], false);
|
let tag_ptr_type = ctx.ctx.struct_type(&[ptr_type.into(), size_type.into()], false);
|
||||||
|
|
||||||
let service_id = int32.const_int(fun.1 .0 as u64, false);
|
let service_id = int32.const_int(fun.1 .0 as u64, false);
|
||||||
|
@ -517,22 +830,25 @@ fn rpc_codegen_callback_fn<'ctx>(
|
||||||
.0
|
.0
|
||||||
.args
|
.args
|
||||||
.iter()
|
.iter()
|
||||||
.map(|arg| mapping.remove(&arg.name).unwrap().to_basic_value_enum(ctx, generator, arg.ty))
|
.map(|arg| {
|
||||||
.collect::<Result<Vec<_>, _>>()?;
|
mapping
|
||||||
|
.remove(&arg.name)
|
||||||
|
.unwrap()
|
||||||
|
.to_basic_value_enum(ctx, generator, arg.ty)
|
||||||
|
.map(|llvm_val| (llvm_val, arg.ty))
|
||||||
|
})
|
||||||
|
.collect::<Result<Vec<(_, _)>, _>>()?;
|
||||||
if let Some(obj) = obj {
|
if let Some(obj) = obj {
|
||||||
if let ValueEnum::Static(obj) = obj.1 {
|
if let ValueEnum::Static(obj_val) = obj.1 {
|
||||||
real_params.insert(0, obj.get_const_obj(ctx, generator));
|
real_params.insert(0, (obj_val.get_const_obj(ctx, generator), obj.0));
|
||||||
} else {
|
} else {
|
||||||
// should be an error here...
|
// should be an error here...
|
||||||
panic!("only host object is allowed");
|
panic!("only host object is allowed");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i, arg) in real_params.iter().enumerate() {
|
for (i, (arg, arg_ty)) in real_params.iter().enumerate() {
|
||||||
let arg_slot =
|
let arg_slot = format_rpc_arg(generator, ctx, (*arg, *arg_ty, i));
|
||||||
generator.gen_var_alloc(ctx, arg.get_type(), Some(&format!("rpc.arg{i}"))).unwrap();
|
|
||||||
ctx.builder.build_store(arg_slot, *arg).unwrap();
|
|
||||||
let arg_slot = ctx.builder.build_bitcast(arg_slot, ptr_type, "rpc.arg").unwrap();
|
|
||||||
let arg_ptr = unsafe {
|
let arg_ptr = unsafe {
|
||||||
ctx.builder.build_gep(
|
ctx.builder.build_gep(
|
||||||
args_ptr,
|
args_ptr,
|
||||||
|
@ -566,63 +882,13 @@ fn rpc_codegen_callback_fn<'ctx>(
|
||||||
// reclaim stack space used by arguments
|
// reclaim stack space used by arguments
|
||||||
call_stackrestore(ctx, stackptr);
|
call_stackrestore(ctx, stackptr);
|
||||||
|
|
||||||
// -- receive value:
|
let result = format_rpc_ret(generator, ctx, fun.0.ret);
|
||||||
// T result = {
|
|
||||||
// void *ret_ptr = alloca(sizeof(T));
|
|
||||||
// void *ptr = ret_ptr;
|
|
||||||
// loop: int size = rpc_recv(ptr);
|
|
||||||
// // Non-zero: Provide `size` bytes of extra storage for variable-length data.
|
|
||||||
// if(size) { ptr = alloca(size); goto loop; }
|
|
||||||
// else *(T*)ret_ptr
|
|
||||||
// }
|
|
||||||
let rpc_recv = ctx.module.get_function("rpc_recv").unwrap_or_else(|| {
|
|
||||||
ctx.module.add_function("rpc_recv", int32.fn_type(&[ptr_type.into()], false), None)
|
|
||||||
});
|
|
||||||
|
|
||||||
if ctx.unifier.unioned(fun.0.ret, ctx.primitives.none) {
|
if !result.is_some_and(|res| res.get_type().is_pointer_type()) {
|
||||||
ctx.build_call_or_invoke(rpc_recv, &[ptr_type.const_null().into()], "rpc_recv");
|
|
||||||
return Ok(None);
|
|
||||||
}
|
|
||||||
|
|
||||||
let prehead_bb = ctx.builder.get_insert_block().unwrap();
|
|
||||||
let current_function = prehead_bb.get_parent().unwrap();
|
|
||||||
let head_bb = ctx.ctx.append_basic_block(current_function, "rpc.head");
|
|
||||||
let alloc_bb = ctx.ctx.append_basic_block(current_function, "rpc.continue");
|
|
||||||
let tail_bb = ctx.ctx.append_basic_block(current_function, "rpc.tail");
|
|
||||||
|
|
||||||
let ret_ty = ctx.get_llvm_abi_type(generator, fun.0.ret);
|
|
||||||
let need_load = !ret_ty.is_pointer_type();
|
|
||||||
let slot = ctx.builder.build_alloca(ret_ty, "rpc.ret.slot").unwrap();
|
|
||||||
let slotgen = ctx.builder.build_bitcast(slot, ptr_type, "rpc.ret.ptr").unwrap();
|
|
||||||
ctx.builder.build_unconditional_branch(head_bb).unwrap();
|
|
||||||
ctx.builder.position_at_end(head_bb);
|
|
||||||
|
|
||||||
let phi = ctx.builder.build_phi(ptr_type, "rpc.ptr").unwrap();
|
|
||||||
phi.add_incoming(&[(&slotgen, prehead_bb)]);
|
|
||||||
let alloc_size = ctx
|
|
||||||
.build_call_or_invoke(rpc_recv, &[phi.as_basic_value()], "rpc.size.next")
|
|
||||||
.unwrap()
|
|
||||||
.into_int_value();
|
|
||||||
let is_done = ctx
|
|
||||||
.builder
|
|
||||||
.build_int_compare(inkwell::IntPredicate::EQ, int32.const_zero(), alloc_size, "rpc.done")
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
ctx.builder.build_conditional_branch(is_done, tail_bb, alloc_bb).unwrap();
|
|
||||||
ctx.builder.position_at_end(alloc_bb);
|
|
||||||
|
|
||||||
let alloc_ptr = ctx.builder.build_array_alloca(ptr_type, alloc_size, "rpc.alloc").unwrap();
|
|
||||||
let alloc_ptr = ctx.builder.build_bitcast(alloc_ptr, ptr_type, "rpc.alloc.ptr").unwrap();
|
|
||||||
phi.add_incoming(&[(&alloc_ptr, alloc_bb)]);
|
|
||||||
ctx.builder.build_unconditional_branch(head_bb).unwrap();
|
|
||||||
|
|
||||||
ctx.builder.position_at_end(tail_bb);
|
|
||||||
|
|
||||||
let result = ctx.builder.build_load(slot, "rpc.result").unwrap();
|
|
||||||
if need_load {
|
|
||||||
call_stackrestore(ctx, stackptr);
|
call_stackrestore(ctx, stackptr);
|
||||||
}
|
}
|
||||||
Ok(Some(result))
|
|
||||||
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn attributes_writeback(
|
pub fn attributes_writeback(
|
||||||
|
|
|
@ -163,7 +163,7 @@ impl StaticValue for PythonValue {
|
||||||
PrimitiveValue::Bool(val) => {
|
PrimitiveValue::Bool(val) => {
|
||||||
ctx.ctx.i8_type().const_int(u64::from(*val), false).into()
|
ctx.ctx.i8_type().const_int(u64::from(*val), false).into()
|
||||||
}
|
}
|
||||||
PrimitiveValue::Str(val) => ctx.ctx.const_string(val.as_bytes(), true).into(),
|
PrimitiveValue::Str(val) => ctx.gen_string(generator, val).into(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if let Some(global) = ctx.module.get_global(&self.id.to_string()) {
|
if let Some(global) = ctx.module.get_global(&self.id.to_string()) {
|
||||||
|
@ -977,7 +977,7 @@ impl InnerResolver {
|
||||||
} else if ty_id == self.primitive_ids.string || ty_id == self.primitive_ids.np_str_ {
|
} else if ty_id == self.primitive_ids.string || ty_id == self.primitive_ids.np_str_ {
|
||||||
let val: String = obj.extract().unwrap();
|
let val: String = obj.extract().unwrap();
|
||||||
self.id_to_primitive.write().insert(id, PrimitiveValue::Str(val.clone()));
|
self.id_to_primitive.write().insert(id, PrimitiveValue::Str(val.clone()));
|
||||||
Ok(Some(ctx.ctx.const_string(val.as_bytes(), true).into()))
|
Ok(Some(ctx.gen_string(generator, val).into()))
|
||||||
} else if ty_id == self.primitive_ids.float || ty_id == self.primitive_ids.float64 {
|
} else if ty_id == self.primitive_ids.float || ty_id == self.primitive_ids.float64 {
|
||||||
let val: f64 = obj.extract().unwrap();
|
let val: f64 = obj.extract().unwrap();
|
||||||
self.id_to_primitive.write().insert(id, PrimitiveValue::F64(val));
|
self.id_to_primitive.write().insert(id, PrimitiveValue::F64(val));
|
||||||
|
|
|
@ -4,6 +4,9 @@ version = "0.1.0"
|
||||||
authors = ["M-Labs"]
|
authors = ["M-Labs"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
no-escape-analysis = []
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
itertools = "0.13"
|
itertools = "0.13"
|
||||||
crossbeam = "0.8"
|
crossbeam = "0.8"
|
||||||
|
|
|
@ -1330,7 +1330,7 @@ impl<'ctx> NDArrayValue<'ctx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the pointer to the field storing the number of dimensions of this `NDArray`.
|
/// Returns the pointer to the field storing the number of dimensions of this `NDArray`.
|
||||||
fn ptr_to_ndims(&self, ctx: &CodeGenContext<'ctx, '_>) -> PointerValue<'ctx> {
|
pub fn ptr_to_ndims(&self, ctx: &CodeGenContext<'ctx, '_>) -> PointerValue<'ctx> {
|
||||||
let llvm_i32 = ctx.ctx.i32_type();
|
let llvm_i32 = ctx.ctx.i32_type();
|
||||||
let var_name = self.name.map(|v| format!("{v}.ndims.addr")).unwrap_or_default();
|
let var_name = self.name.map(|v| format!("{v}.ndims.addr")).unwrap_or_default();
|
||||||
|
|
||||||
|
@ -1366,7 +1366,7 @@ impl<'ctx> NDArrayValue<'ctx> {
|
||||||
|
|
||||||
/// Returns the double-indirection pointer to the `dims` array, as if by calling `getelementptr`
|
/// Returns the double-indirection pointer to the `dims` array, as if by calling `getelementptr`
|
||||||
/// on the field.
|
/// on the field.
|
||||||
fn ptr_to_dims(&self, ctx: &CodeGenContext<'ctx, '_>) -> PointerValue<'ctx> {
|
pub fn ptr_to_dims(&self, ctx: &CodeGenContext<'ctx, '_>) -> PointerValue<'ctx> {
|
||||||
let llvm_i32 = ctx.ctx.i32_type();
|
let llvm_i32 = ctx.ctx.i32_type();
|
||||||
let var_name = self.name.map(|v| format!("{v}.dims.addr")).unwrap_or_default();
|
let var_name = self.name.map(|v| format!("{v}.dims.addr")).unwrap_or_default();
|
||||||
|
|
||||||
|
@ -1404,7 +1404,7 @@ impl<'ctx> NDArrayValue<'ctx> {
|
||||||
|
|
||||||
/// Returns the double-indirection pointer to the `data` array, as if by calling `getelementptr`
|
/// Returns the double-indirection pointer to the `data` array, as if by calling `getelementptr`
|
||||||
/// on the field.
|
/// on the field.
|
||||||
fn ptr_to_data(&self, ctx: &CodeGenContext<'ctx, '_>) -> PointerValue<'ctx> {
|
pub fn ptr_to_data(&self, ctx: &CodeGenContext<'ctx, '_>) -> PointerValue<'ctx> {
|
||||||
let llvm_i32 = ctx.ctx.i32_type();
|
let llvm_i32 = ctx.ctx.i32_type();
|
||||||
let var_name = self.name.map(|v| format!("{v}.data.addr")).unwrap_or_default();
|
let var_name = self.name.map(|v| format!("{v}.data.addr")).unwrap_or_default();
|
||||||
|
|
||||||
|
@ -1420,7 +1420,7 @@ impl<'ctx> NDArrayValue<'ctx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Stores the array of data elements `data` into this instance.
|
/// Stores the array of data elements `data` into this instance.
|
||||||
fn store_data(&self, ctx: &CodeGenContext<'ctx, '_>, data: PointerValue<'ctx>) {
|
pub fn store_data(&self, ctx: &CodeGenContext<'ctx, '_>, data: PointerValue<'ctx>) {
|
||||||
ctx.builder.build_store(self.ptr_to_data(ctx), data).unwrap();
|
ctx.builder.build_store(self.ptr_to_data(ctx), data).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -212,6 +212,9 @@ impl<'a> Inferencer<'a> {
|
||||||
/// This is a workaround preventing the caller from using a variable `alloca`-ed in the body, which
|
/// This is a workaround preventing the caller from using a variable `alloca`-ed in the body, which
|
||||||
/// is freed when the function returns.
|
/// is freed when the function returns.
|
||||||
fn check_return_value_ty(&mut self, ret_ty: Type) -> bool {
|
fn check_return_value_ty(&mut self, ret_ty: Type) -> bool {
|
||||||
|
if cfg!(feature = "no-escape-analysis") {
|
||||||
|
true
|
||||||
|
} else {
|
||||||
match &*self.unifier.get_ty_immutable(ret_ty) {
|
match &*self.unifier.get_ty_immutable(ret_ty) {
|
||||||
TypeEnum::TObj { .. } => [
|
TypeEnum::TObj { .. } => [
|
||||||
self.primitives.int32,
|
self.primitives.int32,
|
||||||
|
@ -227,6 +230,7 @@ impl<'a> Inferencer<'a> {
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// check statements for proper identifier def-use and return on all paths
|
// check statements for proper identifier def-use and return on all paths
|
||||||
fn check_stmt(
|
fn check_stmt(
|
||||||
|
|
|
@ -4,6 +4,9 @@ version = "0.1.0"
|
||||||
authors = ["M-Labs"]
|
authors = ["M-Labs"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
no-escape-analysis = ["nac3core/no-escape-analysis"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
parking_lot = "0.12"
|
parking_lot = "0.12"
|
||||||
nac3parser = { path = "../nac3parser" }
|
nac3parser = { path = "../nac3parser" }
|
||||||
|
|
Loading…
Reference in New Issue