nac3core: irrt list of tuple use struct value representation

This commit is contained in:
ychenfo 2022-01-21 03:44:17 +08:00
parent 77608346b1
commit e50f1017fa
2 changed files with 143 additions and 59 deletions
nac3core/src/codegen/irrt

View File

@ -129,3 +129,74 @@ int32_t __nac3_range_slice_len(const int32_t start, const int32_t end, const int
DEF_SLICE_ASSIGN(uint8_t) DEF_SLICE_ASSIGN(uint8_t)
DEF_SLICE_ASSIGN(uint32_t) DEF_SLICE_ASSIGN(uint32_t)
DEF_SLICE_ASSIGN(uint64_t) DEF_SLICE_ASSIGN(uint64_t)
int32_t __nac3_list_slice_assign_var_size(
int32_t dest_start,
int32_t dest_end,
int32_t dest_step,
uint8_t *dest_arr,
int32_t dest_arr_len,
int32_t src_start,
int32_t src_end,
int32_t src_step,
uint8_t *src_arr,
int32_t src_arr_len,
const int32_t size
) {
/* if dest_arr_len == 0, do nothing since we do not support extending list */
if (dest_arr_len == 0) return dest_arr_len;
/* if both step is 1, memmove directly, handle the dropping of the list, and shrink size */
if (src_step == dest_step && dest_step == 1) {
const int32_t src_len = (src_end >= src_start) ? (src_end - src_start + 1) : 0;
const int32_t dest_len = (dest_end >= dest_start) ? (dest_end - dest_start + 1) : 0;
if (src_len > 0) {
__builtin_memmove(
dest_arr + dest_start * size,
src_arr + src_start * size,
src_len * size
);
}
if (dest_len > 0) {
/* dropping */
__builtin_memmove(
dest_arr + (dest_start + src_len) * size,
dest_arr + (dest_end + 1) * size,
(dest_arr_len - dest_end - 1) * size
);
}
/* shrink size */
return dest_arr_len - (dest_len - src_len);
}
/* if two range overlaps, need alloca */
uint8_t need_alloca =
(dest_arr == src_arr)
&& !(
MAX(dest_start, dest_end) < MIN(src_start, src_end)
|| MAX(src_start, src_end) < MIN(dest_start, dest_end)
);
if (need_alloca) {
uint8_t *tmp = alloca(src_arr_len * size);
__builtin_memcpy(tmp, src_arr, src_arr_len * size);
src_arr = tmp;
}
int32_t src_ind = src_start;
int32_t dest_ind = dest_start;
for (;
(src_step > 0) ? (src_ind <= src_end) : (src_ind >= src_end);
src_ind += src_step, dest_ind += dest_step
) {
/* memcpy for var size, cannot overlap after previous alloca */
__builtin_memcpy(dest_arr + dest_ind * size, src_arr + src_ind * size, size);
}
/* only dest_step == 1 can we shrink the dest list. */
/* size should be ensured prior to calling this function */
if (dest_step == 1 && dest_end >= dest_start) {
__builtin_memmove(
dest_arr + dest_ind * size,
dest_arr + (dest_end + 1) * size,
(dest_arr_len - dest_end - 1) * size
);
return dest_arr_len - (dest_end - dest_ind) - 1;
}
return dest_arr_len;
}

View File

@ -239,48 +239,52 @@ pub fn list_slice_assignment<'ctx, 'a>(
let int32 = ctx.ctx.i32_type(); let int32 = ctx.ctx.i32_type();
let int32_ptr = int32.ptr_type(AddressSpace::Generic); let int32_ptr = int32.ptr_type(AddressSpace::Generic);
let int64_ptr = ctx.ctx.i64_type().ptr_type(AddressSpace::Generic); let int64_ptr = ctx.ctx.i64_type().ptr_type(AddressSpace::Generic);
let fun_symbol = if let BasicTypeEnum::IntType(ty) = ty { let elem_size = match ty {
match ty.get_bit_width() { BasicTypeEnum::IntType(ty) => match ty.get_bit_width() {
w if w < 32 => "__nac3_list_slice_assign_uint8_t", w if w < 32 => Some(8),
32 => "__nac3_list_slice_assign_uint32_t", w if w == 32 || w == 64 => Some(w),
64 => "__nac3_list_slice_assign_uint64_t",
_ => unreachable!(), _ => unreachable!(),
} },
} else if ty.is_float_type() { BasicTypeEnum::FloatType(_) => Some(64),
"__nac3_list_slice_assign_uint64_t" BasicTypeEnum::PointerType(_) => match size_ty.get_bit_width() {
} else if ty.is_pointer_type() { w if w == 32 || w == 64 => Some(w),
match size_ty.get_bit_width() {
32 => "__nac3_list_slice_assign_uint32_t",
64 => "__nac3_list_slice_assign_uint64_t",
_ => unreachable!(), _ => unreachable!(),
} },
} else { BasicTypeEnum::StructType(_) => None,
unreachable!()
};
let elem_ptr_type = match fun_symbol {
"__nac3_list_slice_assign_uint8_t" => int8_ptr,
"__nac3_list_slice_assign_uint32_t" => int32_ptr,
"__nac3_list_slice_assign_uint64_t" => int64_ptr,
_ => unreachable!(), _ => unreachable!(),
}; };
let slice_assign_fun = ctx.module.get_function(fun_symbol).unwrap_or_else(|| { let (fun_symbol, elem_ptr_type) = match elem_size {
let fn_t = int32.fn_type( Some(8) => ("__nac3_list_slice_assign_uint8_t", int8_ptr),
&[ Some(32) => ("__nac3_list_slice_assign_uint32_t", int32_ptr),
int32.into(), // dest start idx Some(64) => ("__nac3_list_slice_assign_uint64_t", int64_ptr),
int32.into(), // dest end idx _ => ("__nac3_list_slice_assign_var_size", int8_ptr),
int32.into(), // dest step };
elem_ptr_type.into(), // dest arr ptr let slice_assign_fun = {
int32.into(), // dest arr len let mut ty_vec = vec![
int32.into(), // src start idx int32.into(), // dest start idx
int32.into(), // src end idx int32.into(), // dest end idx
int32.into(), // src step int32.into(), // dest step
elem_ptr_type.into(), // src arr ptr elem_ptr_type.into(), // dest arr ptr
int32.into(), // src arr len int32.into(), // dest arr len
], int32.into(), // src start idx
false, int32.into(), // src end idx
); int32.into(), // src step
ctx.module.add_function(fun_symbol, fn_t, None) elem_ptr_type.into(), // src arr ptr
}); int32.into(), // src arr len
];
ctx.module.get_function(fun_symbol).unwrap_or_else(|| {
let fn_t = int32.fn_type(
{
if fun_symbol == "__nac3_list_slice_assign_var_size" {
ty_vec.push(int32.into());
}
ty_vec.as_slice()
},
false,
);
ctx.module.add_function(fun_symbol, fn_t, None)
})
};
let zero = int32.const_zero(); let zero = int32.const_zero();
let one = int32.const_int(1, false); let one = int32.const_int(1, false);
@ -304,27 +308,36 @@ pub fn list_slice_assignment<'ctx, 'a>(
// index in bound and positive should be done // index in bound and positive should be done
// TODO: assert if dest.step == 1 then len(src) <= len(dest) else len(src) == len(dest), and // TODO: assert if dest.step == 1 then len(src) <= len(dest) else len(src) == len(dest), and
// throw exception if not satisfied // throw exception if not satisfied
let new_len = ctx let new_len = {
.builder let mut args = vec![
.build_call( dest_idx.0.into(), // dest start idx
slice_assign_fun, dest_idx.1.into(), // dest end idx
&[ dest_idx.2.into(), // dest step
dest_idx.0.into(), // dest start idx dest_arr_ptr.into(), // dest arr ptr
dest_idx.1.into(), // dest end idx dest_len.into(), // dest arr len
dest_idx.2.into(), // dest step src_idx.0.into(), // src start idx
dest_arr_ptr.into(), // dest arr ptr src_idx.1.into(), // src end idx
dest_len.into(), // dest arr len src_idx.2.into(), // src step
src_idx.0.into(), // src start idx src_arr_ptr.into(), // src arr ptr
src_idx.1.into(), // src end idx src_len.into(), // src arr len
src_idx.2.into(), // src step ];
src_arr_ptr.into(), // src arr ptr ctx.builder
src_len.into(), // src arr len .build_call(
], slice_assign_fun,
"slice_assign", {
) if fun_symbol == "__nac3_list_slice_assign_var_size" {
.try_as_basic_value() let s = ty.into_struct_type().size_of().unwrap();
.unwrap_left() let s = ctx.builder.build_int_truncate_or_bit_cast(s, int32, "size");
.into_int_value(); args.push(s.into());
}
args.as_slice()
},
"slice_assign",
)
.try_as_basic_value()
.unwrap_left()
.into_int_value()
};
// update length // update length
let need_update = let need_update =
ctx.builder.build_int_compare(IntPredicate::NE, new_len, dest_len, "need_update"); ctx.builder.build_int_compare(IntPredicate::NE, new_len, dest_len, "need_update");