Meta changes from #301 #324
@ -529,7 +529,7 @@ pub fn attributes_writeback<'ctx, 'a>(
|
|||||||
let index = ctx.get_attr_index(ty, *name);
|
let index = ctx.get_attr_index(ty, *name);
|
||||||
values.push((*field_ty, ctx.build_gep_and_load(
|
values.push((*field_ty, ctx.build_gep_and_load(
|
||||||
obj.into_pointer_value(),
|
obj.into_pointer_value(),
|
||||||
&[zero, int32.const_int(index as u64, false)])));
|
&[zero, int32.const_int(index as u64, false)], None)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !attributes.is_empty() {
|
if !attributes.is_empty() {
|
||||||
|
@ -660,7 +660,8 @@ impl Nac3 {
|
|||||||
|
|
||||||
let pass_options = PassBuilderOptions::create();
|
let pass_options = PassBuilderOptions::create();
|
||||||
pass_options.set_merge_functions(true);
|
pass_options.set_merge_functions(true);
|
||||||
let result = main.run_passes("default<O3>", &target_machine, pass_options);
|
let passes = format!("default<O{}>", self.llvm_options.opt_level as u32);
|
||||||
|
let result = main.run_passes(passes.as_str(), &target_machine, pass_options);
|
||||||
if let Err(err) = result {
|
if let Err(err) = result {
|
||||||
panic!("Failed to run optimization for module `main`: {}", err.to_string());
|
panic!("Failed to run optimization for module `main`: {}", err.to_string());
|
||||||
}
|
}
|
||||||
@ -916,7 +917,6 @@ impl Nac3 {
|
|||||||
llvm_options: CodeGenLLVMOptions {
|
llvm_options: CodeGenLLVMOptions {
|
||||||
opt_level: OptimizationLevel::Default,
|
opt_level: OptimizationLevel::Default,
|
||||||
target: Nac3::get_llvm_target_options(isa),
|
target: Nac3::get_llvm_target_options(isa),
|
||||||
emit_llvm: false,
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -62,8 +62,9 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> {
|
|||||||
&mut self,
|
&mut self,
|
||||||
ptr: PointerValue<'ctx>,
|
ptr: PointerValue<'ctx>,
|
||||||
index: &[IntValue<'ctx>],
|
index: &[IntValue<'ctx>],
|
||||||
|
name: Option<&str>,
|
||||||
) -> BasicValueEnum<'ctx> {
|
) -> BasicValueEnum<'ctx> {
|
||||||
unsafe { self.builder.build_load(self.builder.build_gep(ptr, index, "gep"), "load") }
|
unsafe { self.builder.build_load(self.builder.build_gep(ptr, index, ""), name.unwrap_or_default()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_subst_key(
|
fn get_subst_key(
|
||||||
@ -338,6 +339,7 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> {
|
|||||||
let mut return_slot = None;
|
let mut return_slot = None;
|
||||||
if fun.count_params() > 0 {
|
if fun.count_params() > 0 {
|
||||||
let sret_id = Attribute::get_named_enum_kind_id("sret");
|
let sret_id = Attribute::get_named_enum_kind_id("sret");
|
||||||
|
let byref_id = Attribute::get_named_enum_kind_id("byref");
|
||||||
let byval_id = Attribute::get_named_enum_kind_id("byval");
|
let byval_id = Attribute::get_named_enum_kind_id("byval");
|
||||||
|
|
||||||
let offset = if fun.get_enum_attribute(AttributeLoc::Param(0), sret_id).is_some() {
|
let offset = if fun.get_enum_attribute(AttributeLoc::Param(0), sret_id).is_some() {
|
||||||
@ -349,7 +351,8 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> {
|
|||||||
0
|
0
|
||||||
};
|
};
|
||||||
for (i, param) in params.iter().enumerate() {
|
for (i, param) in params.iter().enumerate() {
|
||||||
if fun.get_enum_attribute(AttributeLoc::Param((i + offset) as u32), byval_id).is_some() {
|
let loc = AttributeLoc::Param((i + offset) as u32);
|
||||||
|
if fun.get_enum_attribute(loc, byref_id).is_some() || fun.get_enum_attribute(loc, byval_id).is_some() {
|
||||||
// lazy update
|
// lazy update
|
||||||
if loc_params.is_empty() {
|
if loc_params.is_empty() {
|
||||||
loc_params.extend(params[0..i+offset].iter().copied());
|
loc_params.extend(params[0..i+offset].iter().copied());
|
||||||
@ -714,11 +717,11 @@ pub fn gen_call<'ctx, 'a, G: CodeGenerator>(
|
|||||||
Some(ctx.get_llvm_type(generator, fun.0.ret))
|
Some(ctx.get_llvm_type(generator, fun.0.ret))
|
||||||
};
|
};
|
||||||
let has_sret = ret_type.map_or(false, |ret_type| need_sret(ctx.ctx, ret_type));
|
let has_sret = ret_type.map_or(false, |ret_type| need_sret(ctx.ctx, ret_type));
|
||||||
let mut byvals = Vec::new();
|
let mut byrefs = Vec::new();
|
||||||
let mut params =
|
let mut params =
|
||||||
args.iter().enumerate().map(|(i, arg)| match ctx.get_llvm_type(generator, arg.ty) {
|
args.iter().enumerate().map(|(i, arg)| match ctx.get_llvm_type(generator, arg.ty) {
|
||||||
BasicTypeEnum::StructType(ty) if is_extern => {
|
BasicTypeEnum::StructType(ty) if is_extern => {
|
||||||
byvals.push((i, ty));
|
byrefs.push((i, ty));
|
||||||
ty.ptr_type(AddressSpace::default()).into()
|
ty.ptr_type(AddressSpace::default()).into()
|
||||||
},
|
},
|
||||||
x => x
|
x => x
|
||||||
@ -738,9 +741,19 @@ pub fn gen_call<'ctx, 'a, G: CodeGenerator>(
|
|||||||
} else {
|
} else {
|
||||||
0
|
0
|
||||||
};
|
};
|
||||||
for (i, ty) in byvals {
|
|
||||||
fun_val.add_attribute(AttributeLoc::Param((i as u32) + offset),
|
// The attribute ID used to mark arguments of a structure type.
|
||||||
ctx.ctx.create_type_attribute(Attribute::get_named_enum_kind_id("byval"), ty.as_any_type_enum()));
|
// Structure-Typed parameters of extern functions must **not** be marked as `byval`, as
|
||||||
|
// `byval` explicitly specifies that the argument is to be passed on the stack, which breaks
|
||||||
|
// on most ABIs where the first several arguments are expected to be passed in registers.
|
||||||
|
let passing_attr_id = Attribute::get_named_enum_kind_id(
|
||||||
|
if is_extern { "byref" } else { "byval" }
|
||||||
|
);
|
||||||
|
for (i, ty) in byrefs {
|
||||||
|
fun_val.add_attribute(
|
||||||
|
AttributeLoc::Param((i as u32) + offset),
|
||||||
|
ctx.ctx.create_type_attribute(passing_attr_id, ty.as_any_type_enum())
|
||||||
|
);
|
||||||
}
|
}
|
||||||
fun_val
|
fun_val
|
||||||
});
|
});
|
||||||
@ -753,43 +766,66 @@ pub fn destructure_range<'ctx, 'a>(
|
|||||||
) -> (IntValue<'ctx>, IntValue<'ctx>, IntValue<'ctx>) {
|
) -> (IntValue<'ctx>, IntValue<'ctx>, IntValue<'ctx>) {
|
||||||
let int32 = ctx.ctx.i32_type();
|
let int32 = ctx.ctx.i32_type();
|
||||||
let start = ctx
|
let start = ctx
|
||||||
.build_gep_and_load(range, &[int32.const_zero(), int32.const_int(0, false)])
|
.build_gep_and_load(range, &[int32.const_zero(), int32.const_int(0, false)], Some("range.start"))
|
||||||
.into_int_value();
|
.into_int_value();
|
||||||
let end = ctx
|
let end = ctx
|
||||||
.build_gep_and_load(range, &[int32.const_zero(), int32.const_int(1, false)])
|
.build_gep_and_load(range, &[int32.const_zero(), int32.const_int(1, false)], Some("range.stop"))
|
||||||
.into_int_value();
|
.into_int_value();
|
||||||
let step = ctx
|
let step = ctx
|
||||||
.build_gep_and_load(range, &[int32.const_zero(), int32.const_int(2, false)])
|
.build_gep_and_load(range, &[int32.const_zero(), int32.const_int(2, false)], Some("range.step"))
|
||||||
.into_int_value();
|
.into_int_value();
|
||||||
(start, end, step)
|
(start, end, step)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Allocates a List structure with the given [type][ty] and [length]. The name of the resulting
|
||||||
|
/// LLVM value is `{name}.addr`, or `list.addr` if [name] is not specified.
|
||||||
|
///
|
||||||
|
/// Returns an instance of [PointerValue] pointing to the List structure. The List structure is
|
||||||
|
/// defined as `type { ty*, size_t }` in LLVM, where the first element stores the pointer to the
|
||||||
|
/// data, and the second element stores the size of the List.
|
||||||
pub fn allocate_list<'ctx, 'a, G: CodeGenerator>(
|
pub fn allocate_list<'ctx, 'a, G: CodeGenerator>(
|
||||||
generator: &mut G,
|
generator: &mut G,
|
||||||
ctx: &mut CodeGenContext<'ctx, 'a>,
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||||
ty: BasicTypeEnum<'ctx>,
|
ty: BasicTypeEnum<'ctx>,
|
||||||
length: IntValue<'ctx>,
|
length: IntValue<'ctx>,
|
||||||
|
name: Option<&str>,
|
||||||
) -> PointerValue<'ctx> {
|
) -> PointerValue<'ctx> {
|
||||||
let arr_ptr = ctx.builder.build_array_alloca(ty, length, "tmparr");
|
|
||||||
let size_t = generator.get_size_type(ctx.ctx);
|
let size_t = generator.get_size_type(ctx.ctx);
|
||||||
let i32_t = ctx.ctx.i32_type();
|
let i32_t = ctx.ctx.i32_type();
|
||||||
let arr_ty =
|
// List structure; type { ty*, size_t }
|
||||||
ctx.ctx.struct_type(&[ty.ptr_type(AddressSpace::default()).into(), size_t.into()], false);
|
let arr_ty = ctx.ctx
|
||||||
|
.struct_type(&[ty.ptr_type(AddressSpace::default()).into(), size_t.into()], false);
|
||||||
let zero = ctx.ctx.i32_type().const_zero();
|
let zero = ctx.ctx.i32_type().const_zero();
|
||||||
let arr_str_ptr = ctx.builder.build_alloca(arr_ty, "tmparrstr");
|
|
||||||
|
let arr_str_ptr = ctx.builder.build_alloca(
|
||||||
|
arr_ty, format!("{}.addr", name.unwrap_or("list")).as_str()
|
||||||
|
);
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
|
// Pointer to the `length` element of the list structure
|
||||||
let len_ptr = ctx.builder.build_in_bounds_gep(
|
let len_ptr = ctx.builder.build_in_bounds_gep(
|
||||||
arr_str_ptr,
|
arr_str_ptr,
|
||||||
&[zero, i32_t.const_int(1, false)],
|
&[zero, i32_t.const_int(1, false)],
|
||||||
"len_ptr",
|
""
|
||||||
|
);
|
||||||
|
let length = ctx.builder.build_int_z_extend(
|
||||||
|
length,
|
||||||
|
size_t,
|
||||||
|
""
|
||||||
);
|
);
|
||||||
let length = ctx.builder.build_int_z_extend(length, size_t, "zext");
|
|
||||||
ctx.builder.build_store(len_ptr, length);
|
ctx.builder.build_store(len_ptr, length);
|
||||||
let ptr_to_arr =
|
|
||||||
ctx.builder.build_in_bounds_gep(arr_str_ptr, &[zero, i32_t.const_zero()], "ptr_to_arr");
|
// Pointer to the `data` element of the list structure
|
||||||
|
let arr_ptr = ctx.builder.build_array_alloca(ty, length, "");
|
||||||
|
let ptr_to_arr = ctx.builder.build_in_bounds_gep(
|
||||||
|
arr_str_ptr,
|
||||||
|
&[zero, i32_t.const_zero()],
|
||||||
|
""
|
||||||
|
);
|
||||||
ctx.builder.build_store(ptr_to_arr, arr_ptr);
|
ctx.builder.build_store(ptr_to_arr, arr_ptr);
|
||||||
arr_str_ptr
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
arr_str_ptr
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn gen_comprehension<'ctx, 'a, G: CodeGenerator>(
|
pub fn gen_comprehension<'ctx, 'a, G: CodeGenerator>(
|
||||||
@ -799,9 +835,15 @@ pub fn gen_comprehension<'ctx, 'a, G: CodeGenerator>(
|
|||||||
) -> Result<BasicValueEnum<'ctx>, String> {
|
) -> Result<BasicValueEnum<'ctx>, String> {
|
||||||
if let ExprKind::ListComp { elt, generators } = &expr.node {
|
if let ExprKind::ListComp { elt, generators } = &expr.node {
|
||||||
let current = ctx.builder.get_insert_block().unwrap().get_parent().unwrap();
|
let current = ctx.builder.get_insert_block().unwrap().get_parent().unwrap();
|
||||||
let test_bb = ctx.ctx.append_basic_block(current, "test");
|
|
||||||
let body_bb = ctx.ctx.append_basic_block(current, "body");
|
let init_bb = ctx.ctx.append_basic_block(current, "listcomp.init");
|
||||||
let cont_bb = ctx.ctx.append_basic_block(current, "cont");
|
let test_bb = ctx.ctx.append_basic_block(current, "listcomp.test");
|
||||||
|
let body_bb = ctx.ctx.append_basic_block(current, "listcomp.body");
|
||||||
|
let cont_bb = ctx.ctx.append_basic_block(current, "listcomp.cont");
|
||||||
|
|
||||||
|
ctx.builder.build_unconditional_branch(init_bb);
|
||||||
|
|
||||||
|
ctx.builder.position_at_end(init_bb);
|
||||||
|
|
||||||
let Comprehension { target, iter, ifs, .. } = &generators[0];
|
let Comprehension { target, iter, ifs, .. } = &generators[0];
|
||||||
let iter_val = generator.gen_expr(ctx, iter)?.unwrap().to_basic_value_enum(ctx, generator, iter.custom.unwrap())?;
|
let iter_val = generator.gen_expr(ctx, iter)?.unwrap().to_basic_value_enum(ctx, generator, iter.custom.unwrap())?;
|
||||||
@ -830,10 +872,11 @@ pub fn gen_comprehension<'ctx, 'a, G: CodeGenerator>(
|
|||||||
// in case length is non-positive
|
// in case length is non-positive
|
||||||
let is_valid =
|
let is_valid =
|
||||||
ctx.builder.build_int_compare(inkwell::IntPredicate::SGT, length, zero_32, "check");
|
ctx.builder.build_int_compare(inkwell::IntPredicate::SGT, length, zero_32, "check");
|
||||||
let normal = ctx.ctx.append_basic_block(current, "normal_list");
|
let normal = ctx.ctx.append_basic_block(current, "listcomp.normal_list");
|
||||||
let empty = ctx.ctx.append_basic_block(current, "empty_list");
|
let empty = ctx.ctx.append_basic_block(current, "listcomp.empty_list");
|
||||||
let list_init = ctx.ctx.append_basic_block(current, "list_init");
|
let list_init = ctx.ctx.append_basic_block(current, "listcomp.list_init");
|
||||||
ctx.builder.build_conditional_branch(is_valid, normal, empty);
|
ctx.builder.build_conditional_branch(is_valid, normal, empty);
|
||||||
|
|
||||||
// normal: allocate a list
|
// normal: allocate a list
|
||||||
ctx.builder.position_at_end(normal);
|
ctx.builder.position_at_end(normal);
|
||||||
let list_a = allocate_list(
|
let list_a = allocate_list(
|
||||||
@ -841,21 +884,31 @@ pub fn gen_comprehension<'ctx, 'a, G: CodeGenerator>(
|
|||||||
ctx,
|
ctx,
|
||||||
elem_ty,
|
elem_ty,
|
||||||
ctx.builder.build_int_z_extend_or_bit_cast(length, size_t, "z_ext_len"),
|
ctx.builder.build_int_z_extend_or_bit_cast(length, size_t, "z_ext_len"),
|
||||||
|
Some("listcomp"),
|
||||||
);
|
);
|
||||||
ctx.builder.build_unconditional_branch(list_init);
|
ctx.builder.build_unconditional_branch(list_init);
|
||||||
|
|
||||||
ctx.builder.position_at_end(empty);
|
ctx.builder.position_at_end(empty);
|
||||||
let list_b = allocate_list(generator, ctx, elem_ty, zero_size_t);
|
let list_b = allocate_list(
|
||||||
|
generator,
|
||||||
|
ctx,
|
||||||
|
elem_ty,
|
||||||
|
zero_size_t,
|
||||||
|
Some("list_b")
|
||||||
|
);
|
||||||
ctx.builder.build_unconditional_branch(list_init);
|
ctx.builder.build_unconditional_branch(list_init);
|
||||||
|
|
||||||
ctx.builder.position_at_end(list_init);
|
ctx.builder.position_at_end(list_init);
|
||||||
let phi = ctx.builder.build_phi(list_a.get_type(), "phi");
|
let phi = ctx.builder.build_phi(list_a.get_type(), "phi");
|
||||||
phi.add_incoming(&[(&list_a, normal), (&list_b, empty)]);
|
phi.add_incoming(&[(&list_a, normal), (&list_b, empty)]);
|
||||||
list = phi.as_basic_value().into_pointer_value();
|
list = phi.as_basic_value().into_pointer_value();
|
||||||
list_content =
|
list_content = ctx.build_gep_and_load(list, &[zero_size_t, zero_32], Some("list_content"))
|
||||||
ctx.build_gep_and_load(list, &[zero_size_t, zero_32]).into_pointer_value();
|
.into_pointer_value();
|
||||||
|
|
||||||
let i = generator.gen_store_target(ctx, target, Some("i.addr"))?;
|
let i = generator.gen_store_target(ctx, target, Some("i.addr"))?;
|
||||||
ctx.builder.build_store(i, ctx.builder.build_int_sub(start, step, "start_init"));
|
ctx.builder.build_store(i, ctx.builder.build_int_sub(start, step, "start_init"));
|
||||||
ctx.builder.build_unconditional_branch(test_bb);
|
ctx.builder.build_unconditional_branch(test_bb);
|
||||||
|
|
||||||
ctx.builder.position_at_end(test_bb);
|
ctx.builder.position_at_end(test_bb);
|
||||||
let sign =
|
let sign =
|
||||||
ctx.builder.build_int_compare(inkwell::IntPredicate::SGT, step, zero_32, "sign");
|
ctx.builder.build_int_compare(inkwell::IntPredicate::SGT, step, zero_32, "sign");
|
||||||
@ -877,32 +930,36 @@ pub fn gen_comprehension<'ctx, 'a, G: CodeGenerator>(
|
|||||||
body_bb,
|
body_bb,
|
||||||
cont_bb,
|
cont_bb,
|
||||||
);
|
);
|
||||||
|
|
||||||
ctx.builder.position_at_end(body_bb);
|
ctx.builder.position_at_end(body_bb);
|
||||||
} else {
|
} else {
|
||||||
let length = ctx
|
let length = ctx
|
||||||
.build_gep_and_load(
|
.build_gep_and_load(
|
||||||
iter_val.into_pointer_value(),
|
iter_val.into_pointer_value(),
|
||||||
&[zero_size_t, int32.const_int(1, false)],
|
&[zero_size_t, int32.const_int(1, false)],
|
||||||
|
Some("length"),
|
||||||
)
|
)
|
||||||
.into_int_value();
|
.into_int_value();
|
||||||
list = allocate_list(generator, ctx, elem_ty, length);
|
list = allocate_list(generator, ctx, elem_ty, length, Some("listcomp"));
|
||||||
list_content =
|
list_content =
|
||||||
ctx.build_gep_and_load(list, &[zero_size_t, zero_32]).into_pointer_value();
|
ctx.build_gep_and_load(list, &[zero_size_t, zero_32], Some("list_content")).into_pointer_value();
|
||||||
let counter = generator.gen_var_alloc(ctx, size_t.into(), Some("counter.addr"))?;
|
let counter = generator.gen_var_alloc(ctx, size_t.into(), Some("counter.addr"))?;
|
||||||
// counter = -1
|
// counter = -1
|
||||||
ctx.builder.build_store(counter, size_t.const_int(u64::max_value(), true));
|
ctx.builder.build_store(counter, size_t.const_int(u64::max_value(), true));
|
||||||
ctx.builder.build_unconditional_branch(test_bb);
|
ctx.builder.build_unconditional_branch(test_bb);
|
||||||
|
|
||||||
ctx.builder.position_at_end(test_bb);
|
ctx.builder.position_at_end(test_bb);
|
||||||
let tmp = ctx.builder.build_load(counter, "i").into_int_value();
|
let tmp = ctx.builder.build_load(counter, "i").into_int_value();
|
||||||
let tmp = ctx.builder.build_int_add(tmp, size_t.const_int(1, false), "inc");
|
let tmp = ctx.builder.build_int_add(tmp, size_t.const_int(1, false), "inc");
|
||||||
ctx.builder.build_store(counter, tmp);
|
ctx.builder.build_store(counter, tmp);
|
||||||
let cmp = ctx.builder.build_int_compare(inkwell::IntPredicate::SLT, tmp, length, "cmp");
|
let cmp = ctx.builder.build_int_compare(inkwell::IntPredicate::SLT, tmp, length, "cmp");
|
||||||
ctx.builder.build_conditional_branch(cmp, body_bb, cont_bb);
|
ctx.builder.build_conditional_branch(cmp, body_bb, cont_bb);
|
||||||
|
|
||||||
ctx.builder.position_at_end(body_bb);
|
ctx.builder.position_at_end(body_bb);
|
||||||
let arr_ptr = ctx
|
let arr_ptr = ctx
|
||||||
.build_gep_and_load(iter_val.into_pointer_value(), &[zero_size_t, zero_32])
|
.build_gep_and_load(iter_val.into_pointer_value(), &[zero_size_t, zero_32], Some("arr.addr"))
|
||||||
.into_pointer_value();
|
.into_pointer_value();
|
||||||
let val = ctx.build_gep_and_load(arr_ptr, &[tmp]);
|
let val = ctx.build_gep_and_load(arr_ptr, &[tmp], Some("val"));
|
||||||
generator.gen_assign(ctx, target, val.into())?;
|
generator.gen_assign(ctx, target, val.into())?;
|
||||||
}
|
}
|
||||||
for cond in ifs.iter() {
|
for cond in ifs.iter() {
|
||||||
@ -913,8 +970,10 @@ pub fn gen_comprehension<'ctx, 'a, G: CodeGenerator>(
|
|||||||
.into_int_value();
|
.into_int_value();
|
||||||
let succ = ctx.ctx.append_basic_block(current, "then");
|
let succ = ctx.ctx.append_basic_block(current, "then");
|
||||||
ctx.builder.build_conditional_branch(result, succ, test_bb);
|
ctx.builder.build_conditional_branch(result, succ, test_bb);
|
||||||
|
|
||||||
ctx.builder.position_at_end(succ);
|
ctx.builder.position_at_end(succ);
|
||||||
}
|
}
|
||||||
|
|
||||||
let elem = generator.gen_expr(ctx, elt)?.unwrap();
|
let elem = generator.gen_expr(ctx, elt)?.unwrap();
|
||||||
let i = ctx.builder.build_load(index, "i").into_int_value();
|
let i = ctx.builder.build_load(index, "i").into_int_value();
|
||||||
let elem_ptr = unsafe { ctx.builder.build_gep(list_content, &[i], "elem_ptr") };
|
let elem_ptr = unsafe { ctx.builder.build_gep(list_content, &[i], "elem_ptr") };
|
||||||
@ -923,11 +982,13 @@ pub fn gen_comprehension<'ctx, 'a, G: CodeGenerator>(
|
|||||||
ctx.builder
|
ctx.builder
|
||||||
.build_store(index, ctx.builder.build_int_add(i, size_t.const_int(1, false), "inc"));
|
.build_store(index, ctx.builder.build_int_add(i, size_t.const_int(1, false), "inc"));
|
||||||
ctx.builder.build_unconditional_branch(test_bb);
|
ctx.builder.build_unconditional_branch(test_bb);
|
||||||
|
|
||||||
ctx.builder.position_at_end(cont_bb);
|
ctx.builder.position_at_end(cont_bb);
|
||||||
let len_ptr = unsafe {
|
let len_ptr = unsafe {
|
||||||
ctx.builder.build_gep(list, &[zero_size_t, int32.const_int(1, false)], "length")
|
ctx.builder.build_gep(list, &[zero_size_t, int32.const_int(1, false)], "length")
|
||||||
};
|
};
|
||||||
ctx.builder.build_store(len_ptr, ctx.builder.build_load(index, "index"));
|
ctx.builder.build_store(len_ptr, ctx.builder.build_load(index, "index"));
|
||||||
|
|
||||||
Ok(list.into())
|
Ok(list.into())
|
||||||
} else {
|
} else {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
@ -1070,7 +1131,7 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
ExprKind::Name { id, .. } => match ctx.var_assignment.get(id) {
|
ExprKind::Name { id, .. } => match ctx.var_assignment.get(id) {
|
||||||
Some((ptr, None, _)) => ctx.builder.build_load(*ptr, "load").into(),
|
Some((ptr, None, _)) => ctx.builder.build_load(*ptr, id.to_string().as_str()).into(),
|
||||||
Some((_, Some(static_value), _)) => ValueEnum::Static(static_value.clone()),
|
Some((_, Some(static_value), _)) => ValueEnum::Static(static_value.clone()),
|
||||||
None => {
|
None => {
|
||||||
let resolver = ctx.resolver.clone();
|
let resolver = ctx.resolver.clone();
|
||||||
@ -1101,8 +1162,9 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
|
|||||||
elements[0].get_type()
|
elements[0].get_type()
|
||||||
};
|
};
|
||||||
let length = generator.get_size_type(ctx.ctx).const_int(elements.len() as u64, false);
|
let length = generator.get_size_type(ctx.ctx).const_int(elements.len() as u64, false);
|
||||||
let arr_str_ptr = allocate_list(generator, ctx, ty, length);
|
let arr_str_ptr = allocate_list(generator, ctx, ty, length, Some("list"));
|
||||||
let arr_ptr = ctx.build_gep_and_load(arr_str_ptr, &[zero, zero]).into_pointer_value();
|
let arr_ptr = ctx.build_gep_and_load(arr_str_ptr, &[zero, zero], Some("list.ptr.addr"))
|
||||||
|
.into_pointer_value();
|
||||||
unsafe {
|
unsafe {
|
||||||
for (i, v) in elements.iter().enumerate() {
|
for (i, v) in elements.iter().enumerate() {
|
||||||
let elem_ptr = ctx.builder.build_gep(
|
let elem_ptr = ctx.builder.build_gep(
|
||||||
@ -1148,6 +1210,7 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
|
|||||||
Ok(ValueEnum::Dynamic(ctx.build_gep_and_load(
|
Ok(ValueEnum::Dynamic(ctx.build_gep_and_load(
|
||||||
v.into_pointer_value(),
|
v.into_pointer_value(),
|
||||||
&[zero, int32.const_int(index as u64, false)],
|
&[zero, int32.const_int(index as u64, false)],
|
||||||
|
None,
|
||||||
))) as Result<_, String>
|
))) as Result<_, String>
|
||||||
}, Ok)?,
|
}, Ok)?,
|
||||||
ValueEnum::Dynamic(v) => {
|
ValueEnum::Dynamic(v) => {
|
||||||
@ -1155,6 +1218,7 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
|
|||||||
ValueEnum::Dynamic(ctx.build_gep_and_load(
|
ValueEnum::Dynamic(ctx.build_gep_and_load(
|
||||||
v.into_pointer_value(),
|
v.into_pointer_value(),
|
||||||
&[zero, int32.const_int(index as u64, false)],
|
&[zero, int32.const_int(index as u64, false)],
|
||||||
|
None,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1511,7 +1575,8 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
|
|||||||
.to_basic_value_enum(ctx, generator, value.custom.unwrap())?
|
.to_basic_value_enum(ctx, generator, value.custom.unwrap())?
|
||||||
.into_pointer_value();
|
.into_pointer_value();
|
||||||
let ty = ctx.get_llvm_type(generator, *ty);
|
let ty = ctx.get_llvm_type(generator, *ty);
|
||||||
let arr_ptr = ctx.build_gep_and_load(v, &[zero, zero]).into_pointer_value();
|
let arr_ptr = ctx.build_gep_and_load(v, &[zero, zero], Some("arr.addr"))
|
||||||
|
.into_pointer_value();
|
||||||
if let ExprKind::Slice { lower, upper, step } = &slice.node {
|
if let ExprKind::Slice { lower, upper, step } = &slice.node {
|
||||||
let one = int32.const_int(1, false);
|
let one = int32.const_int(1, false);
|
||||||
let (start, end, step) =
|
let (start, end, step) =
|
||||||
@ -1535,7 +1600,7 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
|
|||||||
.into_int_value(),
|
.into_int_value(),
|
||||||
step,
|
step,
|
||||||
);
|
);
|
||||||
let res_array_ret = allocate_list(generator, ctx, ty, length);
|
let res_array_ret = allocate_list(generator, ctx, ty, length, Some("ret"));
|
||||||
let res_ind =
|
let res_ind =
|
||||||
handle_slice_indices(&None, &None, &None, ctx, generator, res_array_ret)?;
|
handle_slice_indices(&None, &None, &None, ctx, generator, res_array_ret)?;
|
||||||
list_slice_assignment(
|
list_slice_assignment(
|
||||||
@ -1550,7 +1615,7 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
|
|||||||
res_array_ret.into()
|
res_array_ret.into()
|
||||||
} else {
|
} else {
|
||||||
let len = ctx
|
let len = ctx
|
||||||
.build_gep_and_load(v, &[zero, int32.const_int(1, false)])
|
.build_gep_and_load(v, &[zero, int32.const_int(1, false)], Some("len"))
|
||||||
.into_int_value();
|
.into_int_value();
|
||||||
let raw_index = generator
|
let raw_index = generator
|
||||||
.gen_expr(ctx, slice)?
|
.gen_expr(ctx, slice)?
|
||||||
@ -1590,7 +1655,7 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
|
|||||||
[Some(raw_index), Some(len), None],
|
[Some(raw_index), Some(len), None],
|
||||||
expr.location,
|
expr.location,
|
||||||
);
|
);
|
||||||
ctx.build_gep_and_load(arr_ptr, &[index]).into()
|
ctx.build_gep_and_load(arr_ptr, &[index], None).into()
|
||||||
}
|
}
|
||||||
} else if let TypeEnum::TTuple { .. } = &*ctx.unifier.get_ty(value.custom.unwrap()) {
|
} else if let TypeEnum::TTuple { .. } = &*ctx.unifier.get_ty(value.custom.unwrap()) {
|
||||||
let index: u32 =
|
let index: u32 =
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
typedef _ExtInt(8) int8_t;
|
typedef _BitInt(8) int8_t;
|
||||||
typedef unsigned _ExtInt(8) uint8_t;
|
typedef unsigned _BitInt(8) uint8_t;
|
||||||
typedef _ExtInt(32) int32_t;
|
typedef _BitInt(32) int32_t;
|
||||||
typedef unsigned _ExtInt(32) uint32_t;
|
typedef unsigned _BitInt(32) uint32_t;
|
||||||
typedef _ExtInt(64) int64_t;
|
typedef _BitInt(64) int64_t;
|
||||||
typedef unsigned _ExtInt(64) uint64_t;
|
typedef unsigned _BitInt(64) uint64_t;
|
||||||
|
|
||||||
# define MAX(a, b) (a > b ? a : b)
|
# define MAX(a, b) (a > b ? a : b)
|
||||||
# define MIN(a, b) (a > b ? b : a)
|
# define MIN(a, b) (a > b ? b : a)
|
||||||
|
@ -162,7 +162,7 @@ pub fn handle_slice_indices<'a, 'ctx, G: CodeGenerator>(
|
|||||||
let int32 = ctx.ctx.i32_type();
|
let int32 = ctx.ctx.i32_type();
|
||||||
let zero = int32.const_zero();
|
let zero = int32.const_zero();
|
||||||
let one = int32.const_int(1, false);
|
let one = int32.const_int(1, false);
|
||||||
let length = ctx.build_gep_and_load(list, &[zero, one]).into_int_value();
|
let length = ctx.build_gep_and_load(list, &[zero, one], Some("length")).into_int_value();
|
||||||
let length = ctx.builder.build_int_truncate_or_bit_cast(length, int32, "leni32");
|
let length = ctx.builder.build_int_truncate_or_bit_cast(length, int32, "leni32");
|
||||||
Ok(match (start, end, step) {
|
Ok(match (start, end, step) {
|
||||||
(s, e, None) => (
|
(s, e, None) => (
|
||||||
@ -309,21 +309,21 @@ pub fn list_slice_assignment<'ctx, 'a>(
|
|||||||
|
|
||||||
let zero = int32.const_zero();
|
let zero = int32.const_zero();
|
||||||
let one = int32.const_int(1, false);
|
let one = int32.const_int(1, false);
|
||||||
let dest_arr_ptr = ctx.build_gep_and_load(dest_arr, &[zero, zero]);
|
let dest_arr_ptr = ctx.build_gep_and_load(dest_arr, &[zero, zero], Some("dest.addr"));
|
||||||
let dest_arr_ptr = ctx.builder.build_pointer_cast(
|
let dest_arr_ptr = ctx.builder.build_pointer_cast(
|
||||||
dest_arr_ptr.into_pointer_value(),
|
dest_arr_ptr.into_pointer_value(),
|
||||||
elem_ptr_type,
|
elem_ptr_type,
|
||||||
"dest_arr_ptr_cast",
|
"dest_arr_ptr_cast",
|
||||||
);
|
);
|
||||||
let dest_len = ctx.build_gep_and_load(dest_arr, &[zero, one]).into_int_value();
|
let dest_len = ctx.build_gep_and_load(dest_arr, &[zero, one], Some("dest.len")).into_int_value();
|
||||||
let dest_len = ctx.builder.build_int_truncate_or_bit_cast(dest_len, int32, "srclen32");
|
let dest_len = ctx.builder.build_int_truncate_or_bit_cast(dest_len, int32, "srclen32");
|
||||||
let src_arr_ptr = ctx.build_gep_and_load(src_arr, &[zero, zero]);
|
let src_arr_ptr = ctx.build_gep_and_load(src_arr, &[zero, zero], Some("src.addr"));
|
||||||
let src_arr_ptr = ctx.builder.build_pointer_cast(
|
let src_arr_ptr = ctx.builder.build_pointer_cast(
|
||||||
src_arr_ptr.into_pointer_value(),
|
src_arr_ptr.into_pointer_value(),
|
||||||
elem_ptr_type,
|
elem_ptr_type,
|
||||||
"src_arr_ptr_cast",
|
"src_arr_ptr_cast",
|
||||||
);
|
);
|
||||||
let src_len = ctx.build_gep_and_load(src_arr, &[zero, one]).into_int_value();
|
let src_len = ctx.build_gep_and_load(src_arr, &[zero, one], Some("src.len")).into_int_value();
|
||||||
let src_len = ctx.builder.build_int_truncate_or_bit_cast(src_len, int32, "srclen32");
|
let src_len = ctx.builder.build_int_truncate_or_bit_cast(src_len, int32, "srclen32");
|
||||||
|
|
||||||
// index in bound and positive should be done
|
// index in bound and positive should be done
|
||||||
|
@ -61,9 +61,6 @@ pub struct CodeGenLLVMOptions {
|
|||||||
|
|
||||||
/// Options related to the target machine.
|
/// Options related to the target machine.
|
||||||
pub target: CodeGenTargetMachineOptions,
|
pub target: CodeGenTargetMachineOptions,
|
||||||
|
|
||||||
/// Whether to output the LLVM IR after generation is complete.
|
|
||||||
pub emit_llvm: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Additional options for code generation for the target machine.
|
/// Additional options for code generation for the target machine.
|
||||||
@ -322,8 +319,7 @@ impl WorkerRegistry {
|
|||||||
let result = module.verify();
|
let result = module.verify();
|
||||||
if let Err(err) = result {
|
if let Err(err) = result {
|
||||||
println!("{}", module.print_to_string().to_str().unwrap());
|
println!("{}", module.print_to_string().to_str().unwrap());
|
||||||
println!("{}", err.to_string());
|
panic!("{}", err.to_string())
|
||||||
panic!()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let pass_options = PassBuilderOptions::create();
|
let pass_options = PassBuilderOptions::create();
|
||||||
@ -331,7 +327,6 @@ impl WorkerRegistry {
|
|||||||
self.llvm_options.opt_level
|
self.llvm_options.opt_level
|
||||||
).expect(format!("could not create target machine from properties {:?}", self.llvm_options.target).as_str());
|
).expect(format!("could not create target machine from properties {:?}", self.llvm_options.target).as_str());
|
||||||
let passes = format!("default<O{}>", self.llvm_options.opt_level as u32);
|
let passes = format!("default<O{}>", self.llvm_options.opt_level as u32);
|
||||||
|
|
||||||
let result = module.run_passes(passes.as_str(), &target_machine, pass_options);
|
let result = module.run_passes(passes.as_str(), &target_machine, pass_options);
|
||||||
if let Err(err) = result {
|
if let Err(err) = result {
|
||||||
panic!("Failed to run optimization for module `{}`: {}",
|
panic!("Failed to run optimization for module `{}`: {}",
|
||||||
@ -339,11 +334,6 @@ impl WorkerRegistry {
|
|||||||
err.to_string());
|
err.to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.llvm_options.emit_llvm {
|
|
||||||
println!("LLVM IR for {}\n{}", module.get_name().to_str().unwrap(), module.to_string());
|
|
||||||
println!();
|
|
||||||
}
|
|
||||||
|
|
||||||
f.run(&module);
|
f.run(&module);
|
||||||
let mut lock = self.task_count.lock();
|
let mut lock = self.task_count.lock();
|
||||||
*lock += 1;
|
*lock += 1;
|
||||||
|
@ -93,7 +93,7 @@ pub fn gen_store_target<'ctx, 'a, G: CodeGenerator>(
|
|||||||
.to_basic_value_enum(ctx, generator, value.custom.unwrap())?
|
.to_basic_value_enum(ctx, generator, value.custom.unwrap())?
|
||||||
.into_pointer_value();
|
.into_pointer_value();
|
||||||
let len = ctx
|
let len = ctx
|
||||||
.build_gep_and_load(v, &[zero, i32_type.const_int(1, false)])
|
.build_gep_and_load(v, &[zero, i32_type.const_int(1, false)], Some("len"))
|
||||||
.into_int_value();
|
.into_int_value();
|
||||||
let raw_index = generator
|
let raw_index = generator
|
||||||
.gen_expr(ctx, slice)?
|
.gen_expr(ctx, slice)?
|
||||||
@ -135,7 +135,7 @@ pub fn gen_store_target<'ctx, 'a, G: CodeGenerator>(
|
|||||||
);
|
);
|
||||||
unsafe {
|
unsafe {
|
||||||
let arr_ptr = ctx
|
let arr_ptr = ctx
|
||||||
.build_gep_and_load(v, &[i32_type.const_zero(), i32_type.const_zero()])
|
.build_gep_and_load(v, &[i32_type.const_zero(), i32_type.const_zero()], Some("arr.addr"))
|
||||||
.into_pointer_value();
|
.into_pointer_value();
|
||||||
ctx.builder.build_gep(arr_ptr, &[index], name.unwrap_or(""))
|
ctx.builder.build_gep(arr_ptr, &[index], name.unwrap_or(""))
|
||||||
}
|
}
|
||||||
@ -327,6 +327,7 @@ pub fn gen_for<'ctx, 'a, G: CodeGenerator>(
|
|||||||
.build_gep_and_load(
|
.build_gep_and_load(
|
||||||
iter_val.into_pointer_value(),
|
iter_val.into_pointer_value(),
|
||||||
&[zero, int32.const_int(1, false)],
|
&[zero, int32.const_int(1, false)],
|
||||||
|
Some("len")
|
||||||
)
|
)
|
||||||
.into_int_value();
|
.into_int_value();
|
||||||
ctx.builder.build_unconditional_branch(test_bb);
|
ctx.builder.build_unconditional_branch(test_bb);
|
||||||
@ -338,9 +339,9 @@ pub fn gen_for<'ctx, 'a, G: CodeGenerator>(
|
|||||||
|
|
||||||
ctx.builder.position_at_end(body_bb);
|
ctx.builder.position_at_end(body_bb);
|
||||||
let arr_ptr = ctx
|
let arr_ptr = ctx
|
||||||
.build_gep_and_load(iter_val.into_pointer_value(), &[zero, zero])
|
.build_gep_and_load(iter_val.into_pointer_value(), &[zero, zero], Some("arr.addr"))
|
||||||
.into_pointer_value();
|
.into_pointer_value();
|
||||||
let val = ctx.build_gep_and_load(arr_ptr, &[index]);
|
let val = ctx.build_gep_and_load(arr_ptr, &[index], Some("val"));
|
||||||
generator.gen_assign(ctx, target, val.into())?;
|
generator.gen_assign(ctx, target, val.into())?;
|
||||||
gen_block(generator, ctx, body.iter())?;
|
gen_block(generator, ctx, body.iter())?;
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@ use nac3parser::{
|
|||||||
use parking_lot::RwLock;
|
use parking_lot::RwLock;
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
use inkwell::targets::{InitializationConfig, Target};
|
||||||
|
|
||||||
struct Resolver {
|
struct Resolver {
|
||||||
id_to_type: HashMap<StrRef, Type>,
|
id_to_type: HashMap<StrRef, Type>,
|
||||||
@ -182,23 +183,17 @@ fn test_primitives() {
|
|||||||
; ModuleID = 'test'
|
; ModuleID = 'test'
|
||||||
source_filename = \"test\"
|
source_filename = \"test\"
|
||||||
|
|
||||||
define i32 @testing(i32 %0, i32 %1) !dbg !4 {
|
; Function Attrs: mustprogress nofree norecurse nosync nounwind readnone willreturn
|
||||||
|
define i32 @testing(i32 %0, i32 %1) local_unnamed_addr #0 !dbg !4 {
|
||||||
init:
|
init:
|
||||||
%add = add i32 %0, %1, !dbg !9
|
%add = add i32 %1, %0, !dbg !9
|
||||||
%cmp = icmp eq i32 %add, 1, !dbg !10
|
%cmp = icmp eq i32 %add, 1, !dbg !10
|
||||||
br i1 %cmp, label %then, label %else, !dbg !10
|
%. = select i1 %cmp, i32 %0, i32 0, !dbg !11
|
||||||
|
ret i32 %., !dbg !12
|
||||||
then: ; preds = %init
|
|
||||||
br label %cont, !dbg !11
|
|
||||||
|
|
||||||
else: ; preds = %init
|
|
||||||
br label %cont, !dbg !12
|
|
||||||
|
|
||||||
cont: ; preds = %else, %then
|
|
||||||
%if_exp_result.0 = phi i32 [ %0, %then ], [ 0, %else ], !dbg !13
|
|
||||||
ret i32 %if_exp_result.0, !dbg !14
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
attributes #0 = { mustprogress nofree norecurse nosync nounwind readnone willreturn }
|
||||||
|
|
||||||
!llvm.module.flags = !{!0, !1}
|
!llvm.module.flags = !{!0, !1}
|
||||||
!llvm.dbg.cu = !{!2}
|
!llvm.dbg.cu = !{!2}
|
||||||
|
|
||||||
@ -213,19 +208,18 @@ fn test_primitives() {
|
|||||||
!8 = !{}
|
!8 = !{}
|
||||||
!9 = !DILocation(line: 1, column: 9, scope: !4)
|
!9 = !DILocation(line: 1, column: 9, scope: !4)
|
||||||
!10 = !DILocation(line: 2, column: 15, scope: !4)
|
!10 = !DILocation(line: 2, column: 15, scope: !4)
|
||||||
!11 = !DILocation(line: 2, column: 5, scope: !4)
|
!11 = !DILocation(line: 0, scope: !4)
|
||||||
!12 = !DILocation(line: 2, column: 22, scope: !4)
|
!12 = !DILocation(line: 3, column: 8, scope: !4)
|
||||||
!13 = !DILocation(line: 0, scope: !4)
|
|
||||||
!14 = !DILocation(line: 3, column: 8, scope: !4)
|
|
||||||
"}
|
"}
|
||||||
.trim();
|
.trim();
|
||||||
assert_eq!(expected, module.print_to_string().to_str().unwrap().trim());
|
assert_eq!(expected, module.print_to_string().to_str().unwrap().trim());
|
||||||
})));
|
})));
|
||||||
|
|
||||||
|
Target::initialize_all(&InitializationConfig::default());
|
||||||
|
|
||||||
let llvm_options = CodeGenLLVMOptions {
|
let llvm_options = CodeGenLLVMOptions {
|
||||||
opt_level: OptimizationLevel::Default,
|
opt_level: OptimizationLevel::Default,
|
||||||
target: CodeGenTargetMachineOptions::from_host_triple(),
|
target: CodeGenTargetMachineOptions::from_host_triple(),
|
||||||
emit_llvm: false,
|
|
||||||
};
|
};
|
||||||
let (registry, handles) = WorkerRegistry::create_workers(
|
let (registry, handles) = WorkerRegistry::create_workers(
|
||||||
threads,
|
threads,
|
||||||
@ -373,19 +367,23 @@ fn test_simple_call() {
|
|||||||
; ModuleID = 'test'
|
; ModuleID = 'test'
|
||||||
source_filename = \"test\"
|
source_filename = \"test\"
|
||||||
|
|
||||||
define i32 @testing(i32 %0) !dbg !5 {
|
; Function Attrs: mustprogress nofree norecurse nosync nounwind readnone willreturn
|
||||||
|
define i32 @testing(i32 %0) local_unnamed_addr #0 !dbg !5 {
|
||||||
init:
|
init:
|
||||||
%call = call i32 @foo.0(i32 %0), !dbg !10
|
%add.i = shl i32 %0, 1, !dbg !10
|
||||||
%mul = mul i32 %call, 2, !dbg !11
|
%mul = add i32 %add.i, 2, !dbg !10
|
||||||
ret i32 %mul, !dbg !11
|
ret i32 %mul, !dbg !10
|
||||||
}
|
}
|
||||||
|
|
||||||
define i32 @foo.0(i32 %0) !dbg !12 {
|
; Function Attrs: mustprogress nofree norecurse nosync nounwind readnone willreturn
|
||||||
|
define i32 @foo.0(i32 %0) local_unnamed_addr #0 !dbg !11 {
|
||||||
init:
|
init:
|
||||||
%add = add i32 %0, 1, !dbg !13
|
%add = add i32 %0, 1, !dbg !12
|
||||||
ret i32 %add, !dbg !13
|
ret i32 %add, !dbg !12
|
||||||
}
|
}
|
||||||
|
|
||||||
|
attributes #0 = { mustprogress nofree norecurse nosync nounwind readnone willreturn }
|
||||||
|
|
||||||
!llvm.module.flags = !{!0, !1}
|
!llvm.module.flags = !{!0, !1}
|
||||||
!llvm.dbg.cu = !{!2, !4}
|
!llvm.dbg.cu = !{!2, !4}
|
||||||
|
|
||||||
@ -399,19 +397,19 @@ fn test_simple_call() {
|
|||||||
!7 = !{!8}
|
!7 = !{!8}
|
||||||
!8 = !DIBasicType(name: \"_\", flags: DIFlagPublic)
|
!8 = !DIBasicType(name: \"_\", flags: DIFlagPublic)
|
||||||
!9 = !{}
|
!9 = !{}
|
||||||
!10 = !DILocation(line: 1, column: 9, scope: !5)
|
!10 = !DILocation(line: 2, column: 12, scope: !5)
|
||||||
!11 = !DILocation(line: 2, column: 12, scope: !5)
|
!11 = distinct !DISubprogram(name: \"foo.0\", linkageName: \"foo.0\", scope: null, file: !3, line: 1, type: !6, scopeLine: 1, flags: DIFlagPublic, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !4, retainedNodes: !9)
|
||||||
!12 = distinct !DISubprogram(name: \"foo.0\", linkageName: \"foo.0\", scope: null, file: !3, line: 1, type: !6, scopeLine: 1, flags: DIFlagPublic, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !4, retainedNodes: !9)
|
!12 = !DILocation(line: 1, column: 12, scope: !11)
|
||||||
!13 = !DILocation(line: 1, column: 12, scope: !12)
|
|
||||||
"}
|
"}
|
||||||
.trim();
|
.trim();
|
||||||
assert_eq!(expected, module.print_to_string().to_str().unwrap().trim());
|
assert_eq!(expected, module.print_to_string().to_str().unwrap().trim());
|
||||||
})));
|
})));
|
||||||
|
|
||||||
|
Target::initialize_all(&InitializationConfig::default());
|
||||||
|
|
||||||
let llvm_options = CodeGenLLVMOptions {
|
let llvm_options = CodeGenLLVMOptions {
|
||||||
opt_level: OptimizationLevel::Default,
|
opt_level: OptimizationLevel::Default,
|
||||||
target: CodeGenTargetMachineOptions::from_host_triple(),
|
target: CodeGenTargetMachineOptions::from_host_triple(),
|
||||||
emit_llvm: false,
|
|
||||||
};
|
};
|
||||||
let (registry, handles) = WorkerRegistry::create_workers(
|
let (registry, handles) = WorkerRegistry::create_workers(
|
||||||
threads,
|
threads,
|
||||||
|
@ -1013,6 +1013,7 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo {
|
|||||||
.build_gep_and_load(
|
.build_gep_and_load(
|
||||||
arg.into_pointer_value(),
|
arg.into_pointer_value(),
|
||||||
&[zero, int32.const_int(1, false)],
|
&[zero, int32.const_int(1, false)],
|
||||||
|
None,
|
||||||
)
|
)
|
||||||
.into_int_value();
|
.into_int_value();
|
||||||
if len.get_type().get_bit_width() != 32 {
|
if len.get_type().get_bit_width() != 32 {
|
||||||
|
114
nac3standalone/demo/demo.c
Normal file
114
nac3standalone/demo/demo.c
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
#include <assert.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define min(a, b) \
|
||||||
|
({ \
|
||||||
|
__typeof__(a) _a = (a); \
|
||||||
|
__typeof__(b) _b = (b); \
|
||||||
|
_a < _b ? _a : _b; \
|
||||||
|
})
|
||||||
|
|
||||||
|
#if __SIZEOF_POINTER__ == 8
|
||||||
|
#define usize uint64_t
|
||||||
|
#elif __SIZEOF_POINTER__ == 4
|
||||||
|
#define usize uint32_t
|
||||||
|
#elif __SIZEOF_POINTER__ == 2
|
||||||
|
#define usize uint16_t
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct cslice {
|
||||||
|
const void *data;
|
||||||
|
usize len;
|
||||||
|
};
|
||||||
|
|
||||||
|
void output_int32(const int32_t x, bool newline) {
|
||||||
|
printf("%d", x);
|
||||||
|
|
||||||
|
if (newline) {
|
||||||
|
fputc('\n', stdout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void output_int64(const int64_t x) {
|
||||||
|
printf("%ld", x);
|
||||||
|
|
||||||
|
if (newline) {
|
||||||
|
fputc('\n', stdout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void output_uint32(const uint32_t x) {
|
||||||
|
printf("%d", x);
|
||||||
|
|
||||||
|
if (newline) {
|
||||||
|
fputc('\n', stdout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void output_uint64(const uint64_t x) {
|
||||||
|
printf("%ld", x);
|
||||||
|
|
||||||
|
if (newline) {
|
||||||
|
fputc('\n', stdout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void output_asciiart(const int32_t x) {
|
||||||
|
const char* chars = " .,-:;i+hHM$*#@ ";
|
||||||
|
if (x < 0) {
|
||||||
|
fputc('\n', stdout);
|
||||||
|
} else {
|
||||||
|
fputc(chars[x], stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newline) {
|
||||||
|
fputc('\n', stdout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void output_str(struct cslice *slice, bool newline) {
|
||||||
|
for (usize i = 0; i < slice->len; ++i) {
|
||||||
|
fputc(((const char *) slice->data)[i], stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newline) {
|
||||||
|
fputc('\n', stdout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void output_int32_list(struct cslice *slice) {
|
||||||
|
fputc('[', stdout);
|
||||||
|
for (usize i = 0; i < slice->len; ++i) {
|
||||||
|
if (i == slice->len - 1) {
|
||||||
|
printf("%d", ((const int32_t *) slice->data)[i]);
|
||||||
|
} else {
|
||||||
|
printf("%d, ", ((const int32_t *) slice->data)[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
puts("]");
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t __nac3_personality(
|
||||||
|
__attribute__((unused)) uint32_t state,
|
||||||
|
__attribute__((unused)) uint32_t exception_object,
|
||||||
|
__attribute__((unused)) uint32_t context) {
|
||||||
|
assert(false && "__nac3_personality not implemented");
|
||||||
|
exit(101);
|
||||||
|
__builtin_unreachable();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t __nac3_raise(uint32_t state, uint32_t exception_object, uint32_t context) {
|
||||||
|
printf("__nac3_raise(state: %x, exception_object: %x, context: %x\n", state, exception_object, context);
|
||||||
|
exit(101);
|
||||||
|
__builtin_unreachable();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern int32_t run();
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
run();
|
||||||
|
}
|
@ -1,3 +1,7 @@
|
|||||||
|
use std::io;
|
||||||
|
use std::io::Write;
|
||||||
|
use std::process::exit;
|
||||||
|
|
||||||
mod cslice {
|
mod cslice {
|
||||||
// copied from https://github.com/dherman/cslice
|
// copied from https://github.com/dherman/cslice
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
@ -19,30 +23,60 @@ mod cslice {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn output_int32(x: i32) {
|
pub extern "C" fn output_int32(x: i32, newline: bool) {
|
||||||
println!("{}", x);
|
let str = format!("{x}");
|
||||||
|
|
||||||
|
if newline {
|
||||||
|
println!("{str}");
|
||||||
|
} else {
|
||||||
|
print!("{str}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn output_int64(x: i64) {
|
pub extern "C" fn output_int64(x: i64, newline: bool) {
|
||||||
println!("{}", x);
|
let str = format!("{x}");
|
||||||
|
|
||||||
|
if newline {
|
||||||
|
println!("{str}");
|
||||||
|
} else {
|
||||||
|
print!("{str}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn output_uint32(x: u32) {
|
pub extern "C" fn output_uint32(x: u32, newline: bool) {
|
||||||
println!("{}", x);
|
let str = format!("{x}");
|
||||||
|
|
||||||
|
if newline {
|
||||||
|
println!("{str}");
|
||||||
|
} else {
|
||||||
|
print!("{str}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn output_uint64(x: u64) {
|
pub extern "C" fn output_uint64(x: u64, newline: bool) {
|
||||||
println!("{}", x);
|
let str = format!("{x}");
|
||||||
|
|
||||||
|
if newline {
|
||||||
|
println!("{str}");
|
||||||
|
} else {
|
||||||
|
print!("{str}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn output_float64(x: f64) {
|
pub extern "C" fn output_float64(x: f64, newline: bool) {
|
||||||
// debug output to preserve the digits after the decimal points
|
// debug output to preserve the digits after the decimal points
|
||||||
// to match python `print` function
|
// to match python `print` function
|
||||||
println!("{:?}", x);
|
let str = format!("{:?}", x);
|
||||||
|
|
||||||
|
if newline {
|
||||||
|
println!("{str}");
|
||||||
|
} else {
|
||||||
|
print!("{str}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
@ -56,7 +90,18 @@ pub extern "C" fn output_asciiart(x: i32) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn output_int32_list(x: &cslice::CSlice<i32>) {
|
pub extern "C" fn output_str(x: &cslice::CSlice<u8>, newline: bool) {
|
||||||
|
for e in x.as_ref().iter() {
|
||||||
|
print!("{}", char::from(*e));
|
||||||
|
}
|
||||||
|
|
||||||
|
if newline {
|
||||||
|
println!("");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn output_int32_list(x: &cslice::CSlice<i32>, newline: bool) {
|
||||||
print!("[");
|
print!("[");
|
||||||
let mut it = x.as_ref().iter().peekable();
|
let mut it = x.as_ref().iter().peekable();
|
||||||
while let Some(e) = it.next() {
|
while let Some(e) = it.next() {
|
||||||
@ -66,7 +111,11 @@ pub extern "C" fn output_int32_list(x: &cslice::CSlice<i32>) {
|
|||||||
print!("{}, ", e);
|
print!("{}, ", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
println!("]");
|
print!("]");
|
||||||
|
|
||||||
|
if newline {
|
||||||
|
println!("");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
@ -75,10 +124,19 @@ pub extern "C" fn __nac3_personality(_state: u32, _exception_object: u32, _conte
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn __nac3_raise(_state: u32, _exception_object: u32, _context: u32) -> u32 {
|
pub extern "C" fn __nac3_raise(state: u32, exception_object: u32, context: u32) -> u32 {
|
||||||
unimplemented!();
|
writeln!(io::stderr(),
|
||||||
|
"__nac3_raise(state: {:#010x}, _exception_object: {:#010x}, _context: {:#010x})",
|
||||||
|
state,
|
||||||
|
exception_object,
|
||||||
|
context
|
||||||
|
).unwrap();
|
||||||
|
exit(101);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn __nac3_end_catch() {}
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
fn run() -> i32;
|
fn run() -> i32;
|
||||||
}
|
}
|
||||||
|
@ -48,6 +48,12 @@ def patch(module):
|
|||||||
else:
|
else:
|
||||||
sys.stdout.write(" .,-:;i+hHM$*#@ "[x])
|
sys.stdout.write(" .,-:;i+hHM$*#@ "[x])
|
||||||
|
|
||||||
|
def output(x, newline: bool=True):
|
||||||
|
if newline:
|
||||||
|
print(x)
|
||||||
|
else:
|
||||||
|
print(x, end="")
|
||||||
|
|
||||||
def extern(fun):
|
def extern(fun):
|
||||||
name = fun.__name__
|
name = fun.__name__
|
||||||
if name == "output_asciiart":
|
if name == "output_asciiart":
|
||||||
@ -58,9 +64,10 @@ def patch(module):
|
|||||||
"output_int32_list",
|
"output_int32_list",
|
||||||
"output_uint32",
|
"output_uint32",
|
||||||
"output_uint64",
|
"output_uint64",
|
||||||
"output_float64"
|
"output_float64",
|
||||||
|
"output_str",
|
||||||
}:
|
}:
|
||||||
return print
|
return output
|
||||||
else:
|
else:
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
|
21
nac3standalone/demo/run_demo_lli.sh
Executable file
21
nac3standalone/demo/run_demo_lli.sh
Executable file
@ -0,0 +1,21 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
if [ -z "$1" ]; then
|
||||||
|
echo "No argument supplied"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -e ../../target/release/nac3standalone ]; then
|
||||||
|
nac3standalone=../../target/release/nac3standalone
|
||||||
|
else
|
||||||
|
# used by Nix builds
|
||||||
|
nac3standalone=../../target/x86_64-unknown-linux-gnu/release/nac3standalone
|
||||||
|
fi
|
||||||
|
|
||||||
|
rm -f *.o *.bc
|
||||||
|
$nac3standalone --emit-llvm "$@"
|
||||||
|
gcc -c -std=c11 -Wall -Wextra -pedantic-errors -Werror=pedantic -O3 -o demo.o demo.c
|
||||||
|
clang -S -Wall -Wextra -O3 -emit-llvm -o irrt.bc ../../nac3core/src/codegen/irrt/irrt.c
|
||||||
|
lli --extra-object demo.o --extra-module irrt.bc main.bc
|
@ -1,9 +1,9 @@
|
|||||||
@extern
|
@extern
|
||||||
def output_int32(x: int32):
|
def output_int32(x: int32, newline: bool=True):
|
||||||
...
|
...
|
||||||
|
|
||||||
@extern
|
@extern
|
||||||
def output_int64(x: int64):
|
def output_int64(x: int64, newline: bool=True):
|
||||||
...
|
...
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
@extern
|
@extern
|
||||||
def output_int32(x: int32):
|
def output_int32(x: int32, newline: bool=True):
|
||||||
...
|
...
|
||||||
|
|
||||||
def f1(a: int32 = 4):
|
def f1(a: int32 = 4):
|
||||||
|
61
nac3standalone/demo/src/demo_test.py
Normal file
61
nac3standalone/demo/src/demo_test.py
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
@extern
|
||||||
|
def output_int32(x: int32, newline: bool=True):
|
||||||
|
...
|
||||||
|
|
||||||
|
@extern
|
||||||
|
def output_int64(x: int64, newline: bool=True):
|
||||||
|
...
|
||||||
|
|
||||||
|
@extern
|
||||||
|
def output_uint32(x: uint32, newline: bool=True):
|
||||||
|
...
|
||||||
|
|
||||||
|
@extern
|
||||||
|
def output_uint64(x: uint64, newline: bool=True):
|
||||||
|
...
|
||||||
|
|
||||||
|
@extern
|
||||||
|
def output_int32_list(x: list[int32], newline: bool=True):
|
||||||
|
...
|
||||||
|
|
||||||
|
@extern
|
||||||
|
def output_asciiart(x: int32):
|
||||||
|
...
|
||||||
|
|
||||||
|
@extern
|
||||||
|
def output_str(x: str, newline: bool=True):
|
||||||
|
...
|
||||||
|
|
||||||
|
def test_output_int32():
|
||||||
|
output_int32(-128)
|
||||||
|
|
||||||
|
def test_output_int64():
|
||||||
|
output_int64(int64(-256))
|
||||||
|
|
||||||
|
def test_output_uint32():
|
||||||
|
output_uint32(uint32(128))
|
||||||
|
|
||||||
|
def test_output_uint64():
|
||||||
|
output_uint64(uint64(256))
|
||||||
|
|
||||||
|
def test_output_asciiart():
|
||||||
|
for i in range(17):
|
||||||
|
output_asciiart(i)
|
||||||
|
output_asciiart(0)
|
||||||
|
|
||||||
|
def test_output_int32_list():
|
||||||
|
output_int32_list([0, 1, 3, 5, 10])
|
||||||
|
|
||||||
|
def test_output_str_family():
|
||||||
|
output_str("hello ", newline=False)
|
||||||
|
output_str("world")
|
||||||
|
|
||||||
|
def run() -> int32:
|
||||||
|
test_output_int32()
|
||||||
|
test_output_int64()
|
||||||
|
test_output_uint32()
|
||||||
|
test_output_uint64()
|
||||||
|
test_output_asciiart()
|
||||||
|
test_output_int32_list()
|
||||||
|
test_output_str_family()
|
||||||
|
return 0
|
@ -1,7 +1,7 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
@extern
|
@extern
|
||||||
def output_int32(x: int32):
|
def output_int32(x: int32, newline: bool=True):
|
||||||
...
|
...
|
||||||
|
|
||||||
class A:
|
class A:
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
@extern
|
@extern
|
||||||
def output_int32(x: int32):
|
def output_int32(x: int32, newline: bool=True):
|
||||||
...
|
...
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
@extern
|
@extern
|
||||||
def output_int32_list(x: list[int32]):
|
def output_int32_list(x: list[int32], newline: bool=True):
|
||||||
...
|
...
|
||||||
|
|
||||||
@extern
|
@extern
|
||||||
def output_int32(x: int32):
|
def output_int32(x: int32, newline: bool=True):
|
||||||
...
|
...
|
||||||
|
|
||||||
class A:
|
class A:
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
# For Loop using an increasing range() expression as its iterable
|
# For Loop using an increasing range() expression as its iterable
|
||||||
|
|
||||||
@extern
|
@extern
|
||||||
def output_int32(x: int32):
|
def output_int32(x: int32, newline: bool=True):
|
||||||
...
|
...
|
||||||
|
|
||||||
def run() -> int32:
|
def run() -> int32:
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
# For Loop using a decreasing range() expression as its iterable
|
# For Loop using a decreasing range() expression as its iterable
|
||||||
|
|
||||||
@extern
|
@extern
|
||||||
def output_int32(x: int32):
|
def output_int32(x: int32, newline: bool=True):
|
||||||
...
|
...
|
||||||
|
|
||||||
def run() -> int32:
|
def run() -> int32:
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
# For Loop using a list as its iterable
|
# For Loop using a list as its iterable
|
||||||
|
|
||||||
@extern
|
@extern
|
||||||
def output_int32(x: int32):
|
def output_int32(x: int32, newline: bool=True):
|
||||||
...
|
...
|
||||||
|
|
||||||
def run() -> int32:
|
def run() -> int32:
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
# For Loop using an range() expression as its iterable, additionally reassigning the target on each iteration
|
# For Loop using an range() expression as its iterable, additionally reassigning the target on each iteration
|
||||||
|
|
||||||
@extern
|
@extern
|
||||||
def output_int32(x: int32):
|
def output_int32(x: int32, newline: bool=True):
|
||||||
...
|
...
|
||||||
|
|
||||||
def run() -> int32:
|
def run() -> int32:
|
||||||
|
@ -1,17 +1,17 @@
|
|||||||
@extern
|
@extern
|
||||||
def output_int32(x: int32):
|
def output_int32(x: int32, newline: bool=True):
|
||||||
...
|
...
|
||||||
@extern
|
@extern
|
||||||
def output_uint32(x: uint32):
|
def output_uint32(x: uint32, newline: bool=True):
|
||||||
...
|
...
|
||||||
@extern
|
@extern
|
||||||
def output_int64(x: int64):
|
def output_int64(x: int64, newline: bool=True):
|
||||||
...
|
...
|
||||||
@extern
|
@extern
|
||||||
def output_uint64(x: uint64):
|
def output_uint64(x: uint64, newline: bool=True):
|
||||||
...
|
...
|
||||||
@extern
|
@extern
|
||||||
def output_float64(x: float):
|
def output_float64(x: float, newline: bool=True):
|
||||||
...
|
...
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,19 +1,19 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
@extern
|
@extern
|
||||||
def output_int32(x: int32):
|
def output_int32(x: int32, newline: bool=True):
|
||||||
...
|
...
|
||||||
@extern
|
@extern
|
||||||
def output_uint32(x: uint32):
|
def output_uint32(x: uint32, newline: bool=True):
|
||||||
...
|
...
|
||||||
@extern
|
@extern
|
||||||
def output_int64(x: int64):
|
def output_int64(x: int64, newline: bool=True):
|
||||||
...
|
...
|
||||||
@extern
|
@extern
|
||||||
def output_uint64(x: uint64):
|
def output_uint64(x: uint64, newline: bool=True):
|
||||||
...
|
...
|
||||||
@extern
|
@extern
|
||||||
def output_float64(x: float):
|
def output_float64(x: float, newline: bool=True):
|
||||||
...
|
...
|
||||||
|
|
||||||
def run() -> int32:
|
def run() -> int32:
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
@extern
|
@extern
|
||||||
def output_int32(x: int32):
|
def output_int32(x: int32, newline: bool=True):
|
||||||
...
|
...
|
||||||
|
|
||||||
class A:
|
class A:
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
@extern
|
@extern
|
||||||
def output_float64(f: float):
|
def output_float64(f: float, newline: bool=True):
|
||||||
...
|
...
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
@extern
|
@extern
|
||||||
def output_int32(a: int32):
|
def output_int32(a: int32, newline: bool=True):
|
||||||
...
|
...
|
||||||
|
|
||||||
class A:
|
class A:
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
@extern
|
@extern
|
||||||
def output_int32_list(x: list[int32]):
|
def output_int32_list(x: list[int32], newline: bool=True):
|
||||||
...
|
...
|
||||||
|
|
||||||
@extern
|
@extern
|
||||||
def output_int32(x: int32):
|
def output_int32(x: int32, newline: bool=True):
|
||||||
...
|
...
|
||||||
|
|
||||||
class A:
|
class A:
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
@extern
|
@extern
|
||||||
def output_int32(x: int32):
|
def output_int32(x: int32, newline: bool=True):
|
||||||
...
|
...
|
||||||
|
|
||||||
class A:
|
class A:
|
||||||
|
@ -305,7 +305,6 @@ fn main() {
|
|||||||
features: target_features,
|
features: target_features,
|
||||||
..host_target_machine
|
..host_target_machine
|
||||||
},
|
},
|
||||||
emit_llvm,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let task = CodeGenTask {
|
let task = CodeGenTask {
|
||||||
@ -340,11 +339,19 @@ fn main() {
|
|||||||
let main = context
|
let main = context
|
||||||
.create_module_from_ir(MemoryBuffer::create_from_memory_range(&buffers[0], "main"))
|
.create_module_from_ir(MemoryBuffer::create_from_memory_range(&buffers[0], "main"))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
for buffer in buffers.iter().skip(1) {
|
if emit_llvm {
|
||||||
|
main.write_bitcode_to_path(Path::new("main.bc"));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (idx, buffer) in buffers.iter().skip(1).enumerate() {
|
||||||
let other = context
|
let other = context
|
||||||
.create_module_from_ir(MemoryBuffer::create_from_memory_range(buffer, "main"))
|
.create_module_from_ir(MemoryBuffer::create_from_memory_range(buffer, "main"))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
if emit_llvm {
|
||||||
|
other.write_bitcode_to_path(Path::new(&format!("module{}.bc", idx)));
|
||||||
|
}
|
||||||
|
|
||||||
main.link_in_module(other).unwrap();
|
main.link_in_module(other).unwrap();
|
||||||
}
|
}
|
||||||
main.link_in_module(load_irrt(&context)).unwrap();
|
main.link_in_module(load_irrt(&context)).unwrap();
|
||||||
@ -363,7 +370,8 @@ fn main() {
|
|||||||
|
|
||||||
let pass_options = PassBuilderOptions::create();
|
let pass_options = PassBuilderOptions::create();
|
||||||
pass_options.set_merge_functions(true);
|
pass_options.set_merge_functions(true);
|
||||||
let result = main.run_passes("default<O3>", &target_machine, pass_options);
|
let passes = format!("default<O{}>", opt_level as u32);
|
||||||
|
let result = main.run_passes(passes.as_str(), &target_machine, pass_options);
|
||||||
if let Err(err) = result {
|
if let Err(err) = result {
|
||||||
panic!("Failed to run optimization for module `main`: {}", err.to_string());
|
panic!("Failed to run optimization for module `main`: {}", err.to_string());
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user