Compare commits
7 Commits
e97ceb0da9
...
48c6498d1f
Author | SHA1 | Date |
---|---|---|
David Mak | 48c6498d1f | |
David Mak | 2a38d5160e | |
David Mak | b39831b388 | |
David Mak | cb39f61e79 | |
David Mak | 176f250bdb | |
David Mak | acdb1de6fe | |
David Mak | 31dcd2dde9 |
|
@ -450,7 +450,7 @@ fn rpc_codegen_callback_fn<'ctx, 'a>(
|
||||||
let alloc_bb = ctx.ctx.append_basic_block(current_function, "rpc.continue");
|
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 tail_bb = ctx.ctx.append_basic_block(current_function, "rpc.tail");
|
||||||
|
|
||||||
let ret_ty = ctx.get_llvm_type(generator, fun.0.ret);
|
let ret_ty = ctx.get_llvm_abi_type(generator, fun.0.ret);
|
||||||
let need_load = !ret_ty.is_pointer_type();
|
let need_load = !ret_ty.is_pointer_type();
|
||||||
let slot = ctx.builder.build_alloca(ret_ty, "rpc.ret.slot");
|
let slot = ctx.builder.build_alloca(ret_ty, "rpc.ret.slot");
|
||||||
let slotgen = ctx.builder.build_bitcast(slot, ptr_type, "rpc.ret.ptr");
|
let slotgen = ctx.builder.build_bitcast(slot, ptr_type, "rpc.ret.ptr");
|
||||||
|
|
|
@ -134,9 +134,7 @@ impl StaticValue for PythonValue {
|
||||||
PrimitiveValue::U32(val) => ctx.ctx.i32_type().const_int(*val as u64, false).into(),
|
PrimitiveValue::U32(val) => ctx.ctx.i32_type().const_int(*val as u64, false).into(),
|
||||||
PrimitiveValue::U64(val) => ctx.ctx.i64_type().const_int(*val as u64, false).into(),
|
PrimitiveValue::U64(val) => ctx.ctx.i64_type().const_int(*val as u64, false).into(),
|
||||||
PrimitiveValue::F64(val) => ctx.ctx.f64_type().const_float(*val).into(),
|
PrimitiveValue::F64(val) => ctx.ctx.f64_type().const_float(*val).into(),
|
||||||
PrimitiveValue::Bool(val) => {
|
PrimitiveValue::Bool(val) => ctx.ctx.i8_type().const_int(*val as u64, false).into(),
|
||||||
ctx.ctx.bool_type().const_int(*val as u64, false).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()) {
|
||||||
|
@ -808,7 +806,7 @@ impl InnerResolver {
|
||||||
} else if ty_id == self.primitive_ids.bool {
|
} else if ty_id == self.primitive_ids.bool {
|
||||||
let val: bool = obj.extract().unwrap();
|
let val: bool = obj.extract().unwrap();
|
||||||
self.id_to_primitive.write().insert(id, PrimitiveValue::Bool(val));
|
self.id_to_primitive.write().insert(id, PrimitiveValue::Bool(val));
|
||||||
Ok(Some(ctx.ctx.bool_type().const_int(val as u64, false).into()))
|
Ok(Some(ctx.ctx.i8_type().const_int(val as u64, false).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,7 @@ use crate::{
|
||||||
codegen::{
|
codegen::{
|
||||||
concrete_type::{ConcreteFuncArg, ConcreteTypeEnum, ConcreteTypeStore},
|
concrete_type::{ConcreteFuncArg, ConcreteTypeEnum, ConcreteTypeStore},
|
||||||
get_llvm_type,
|
get_llvm_type,
|
||||||
|
get_llvm_abi_type,
|
||||||
irrt::*,
|
irrt::*,
|
||||||
stmt::gen_raise,
|
stmt::gen_raise,
|
||||||
CodeGenContext, CodeGenTask,
|
CodeGenContext, CodeGenTask,
|
||||||
|
@ -58,6 +59,8 @@ pub fn get_subst_key(
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx, 'a> CodeGenContext<'ctx, 'a> {
|
impl<'ctx, 'a> CodeGenContext<'ctx, 'a> {
|
||||||
|
/// Builds a sequence of `getelementptr` and `load` instructions which stores the value of a
|
||||||
|
/// struct field into an LLVM value.
|
||||||
pub fn build_gep_and_load(
|
pub fn build_gep_and_load(
|
||||||
&mut self,
|
&mut self,
|
||||||
ptr: PointerValue<'ctx>,
|
ptr: PointerValue<'ctx>,
|
||||||
|
@ -103,7 +106,7 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> {
|
||||||
SymbolValue::I64(v) => self.ctx.i64_type().const_int(*v as u64, true).into(),
|
SymbolValue::I64(v) => self.ctx.i64_type().const_int(*v as u64, true).into(),
|
||||||
SymbolValue::U32(v) => self.ctx.i32_type().const_int(*v as u64, false).into(),
|
SymbolValue::U32(v) => self.ctx.i32_type().const_int(*v as u64, false).into(),
|
||||||
SymbolValue::U64(v) => self.ctx.i64_type().const_int(*v as u64, false).into(),
|
SymbolValue::U64(v) => self.ctx.i64_type().const_int(*v as u64, false).into(),
|
||||||
SymbolValue::Bool(v) => self.ctx.bool_type().const_int(*v as u64, true).into(),
|
SymbolValue::Bool(v) => self.ctx.i8_type().const_int(*v as u64, true).into(),
|
||||||
SymbolValue::Double(v) => self.ctx.f64_type().const_float(*v).into(),
|
SymbolValue::Double(v) => self.ctx.f64_type().const_float(*v).into(),
|
||||||
SymbolValue::Str(v) => {
|
SymbolValue::Str(v) => {
|
||||||
let str_ptr =
|
let str_ptr =
|
||||||
|
@ -160,6 +163,7 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// See [get_llvm_type].
|
||||||
pub fn get_llvm_type(
|
pub fn get_llvm_type(
|
||||||
&mut self,
|
&mut self,
|
||||||
generator: &mut dyn CodeGenerator,
|
generator: &mut dyn CodeGenerator,
|
||||||
|
@ -177,6 +181,25 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// See [get_llvm_abi_type].
|
||||||
|
pub fn get_llvm_abi_type(
|
||||||
|
&mut self,
|
||||||
|
generator: &mut dyn CodeGenerator,
|
||||||
|
ty: Type,
|
||||||
|
) -> BasicTypeEnum<'ctx> {
|
||||||
|
get_llvm_abi_type(
|
||||||
|
self.ctx,
|
||||||
|
&self.module,
|
||||||
|
generator,
|
||||||
|
&mut self.unifier,
|
||||||
|
self.top_level,
|
||||||
|
&mut self.type_cache,
|
||||||
|
&self.primitives,
|
||||||
|
ty,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Generates an LLVM variable for a [constant value][value] with a given [type][ty].
|
||||||
pub fn gen_const(
|
pub fn gen_const(
|
||||||
&mut self,
|
&mut self,
|
||||||
generator: &mut dyn CodeGenerator,
|
generator: &mut dyn CodeGenerator,
|
||||||
|
@ -186,7 +209,7 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> {
|
||||||
match value {
|
match value {
|
||||||
Constant::Bool(v) => {
|
Constant::Bool(v) => {
|
||||||
assert!(self.unifier.unioned(ty, self.primitives.bool));
|
assert!(self.unifier.unioned(ty, self.primitives.bool));
|
||||||
let ty = self.ctx.bool_type();
|
let ty = self.ctx.i8_type();
|
||||||
ty.const_int(if *v { 1 } else { 0 }, false).into()
|
ty.const_int(if *v { 1 } else { 0 }, false).into()
|
||||||
}
|
}
|
||||||
Constant::Int(val) => {
|
Constant::Int(val) => {
|
||||||
|
@ -238,6 +261,7 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Generates a binary operation `op` between two integral operands `lhs` and `rhs`.
|
||||||
pub fn gen_int_ops(
|
pub fn gen_int_ops(
|
||||||
&mut self,
|
&mut self,
|
||||||
generator: &mut dyn CodeGenerator,
|
generator: &mut dyn CodeGenerator,
|
||||||
|
@ -282,6 +306,7 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Generates a binary operation `op` between two floating-point operands `lhs` and `rhs`.
|
||||||
pub fn gen_float_ops(
|
pub fn gen_float_ops(
|
||||||
&mut self,
|
&mut self,
|
||||||
op: &Operator,
|
op: &Operator,
|
||||||
|
@ -406,6 +431,7 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Helper function for generating a LLVM variable storing a [String].
|
||||||
pub fn gen_string<S: Into<String>>(
|
pub fn gen_string<S: Into<String>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
generator: &mut dyn CodeGenerator,
|
generator: &mut dyn CodeGenerator,
|
||||||
|
@ -505,6 +531,7 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// See [CodeGenerator::gen_constructor].
|
||||||
pub fn gen_constructor<'ctx, 'a, G: CodeGenerator>(
|
pub fn gen_constructor<'ctx, 'a, G: CodeGenerator>(
|
||||||
generator: &mut G,
|
generator: &mut G,
|
||||||
ctx: &mut CodeGenContext<'ctx, 'a>,
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||||
|
@ -536,6 +563,7 @@ pub fn gen_constructor<'ctx, 'a, G: CodeGenerator>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// See [CodeGenerator::gen_func_instance].
|
||||||
pub fn gen_func_instance<'ctx, 'a>(
|
pub fn gen_func_instance<'ctx, 'a>(
|
||||||
ctx: &mut CodeGenContext<'ctx, 'a>,
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||||
obj: Option<(Type, ValueEnum<'ctx>)>,
|
obj: Option<(Type, ValueEnum<'ctx>)>,
|
||||||
|
@ -612,6 +640,7 @@ pub fn gen_func_instance<'ctx, 'a>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// See [CodeGenerator::gen_call].
|
||||||
pub fn gen_call<'ctx, 'a, G: CodeGenerator>(
|
pub fn gen_call<'ctx, 'a, G: CodeGenerator>(
|
||||||
generator: &mut G,
|
generator: &mut G,
|
||||||
ctx: &mut CodeGenContext<'ctx, 'a>,
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||||
|
@ -715,18 +744,19 @@ pub fn gen_call<'ctx, 'a, G: CodeGenerator>(
|
||||||
let ret_type = if ctx.unifier.unioned(fun.0.ret, ctx.primitives.none) {
|
let ret_type = if ctx.unifier.unioned(fun.0.ret, ctx.primitives.none) {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
Some(ctx.get_llvm_type(generator, fun.0.ret))
|
Some(ctx.get_llvm_abi_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 byrefs = Vec::new();
|
let mut byrefs = Vec::new();
|
||||||
let mut params =
|
let mut params = args.iter().enumerate()
|
||||||
args.iter().enumerate().map(|(i, arg)| match ctx.get_llvm_type(generator, arg.ty) {
|
.map(|(i, arg)| match ctx.get_llvm_abi_type(generator, arg.ty) {
|
||||||
BasicTypeEnum::StructType(ty) if is_extern => {
|
BasicTypeEnum::StructType(ty) if is_extern => {
|
||||||
byrefs.push((i, ty));
|
byrefs.push((i, ty));
|
||||||
ty.ptr_type(AddressSpace::default()).into()
|
ty.ptr_type(AddressSpace::default()).into()
|
||||||
},
|
},
|
||||||
x => x
|
x => x
|
||||||
}.into()).collect_vec();
|
}.into())
|
||||||
|
.collect_vec();
|
||||||
if has_sret {
|
if has_sret {
|
||||||
params.insert(0, ret_type.unwrap().ptr_type(AddressSpace::default()).into());
|
params.insert(0, ret_type.unwrap().ptr_type(AddressSpace::default()).into());
|
||||||
}
|
}
|
||||||
|
@ -758,9 +788,30 @@ pub fn gen_call<'ctx, 'a, G: CodeGenerator>(
|
||||||
}
|
}
|
||||||
fun_val
|
fun_val
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Convert boolean parameter values into i1
|
||||||
|
let param_vals = (&fun_val.get_params()).iter().zip(param_vals)
|
||||||
|
.map(|(p, v)| {
|
||||||
|
if p.is_int_value() && v.is_int_value() {
|
||||||
|
let expected_ty = p.into_int_value().get_type();
|
||||||
|
let param_val = v.into_int_value();
|
||||||
|
|
||||||
|
if expected_ty.get_bit_width() == 1 && param_val.get_type().get_bit_width() != 1 {
|
||||||
|
generator.bool_to_i1(ctx, param_val)
|
||||||
|
} else {
|
||||||
|
param_val
|
||||||
|
}.into()
|
||||||
|
} else {
|
||||||
|
v
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect_vec();
|
||||||
|
|
||||||
Ok(ctx.build_call_or_invoke(fun_val, ¶m_vals, "call"))
|
Ok(ctx.build_call_or_invoke(fun_val, ¶m_vals, "call"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Generates three LLVM variables representing the start, stop, and step values of a [range] class
|
||||||
|
/// respectively.
|
||||||
pub fn destructure_range<'ctx, 'a>(
|
pub fn destructure_range<'ctx, 'a>(
|
||||||
ctx: &mut CodeGenContext<'ctx, 'a>,
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||||
range: PointerValue<'ctx>,
|
range: PointerValue<'ctx>,
|
||||||
|
@ -829,6 +880,7 @@ pub fn allocate_list<'ctx, 'a, G: CodeGenerator>(
|
||||||
arr_str_ptr
|
arr_str_ptr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Generates LLVM IR for a [list comprehension expression][expr].
|
||||||
pub fn gen_comprehension<'ctx, 'a, G: CodeGenerator>(
|
pub fn gen_comprehension<'ctx, 'a, G: CodeGenerator>(
|
||||||
generator: &mut G,
|
generator: &mut G,
|
||||||
ctx: &mut CodeGenContext<'ctx, 'a>,
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||||
|
@ -963,12 +1015,14 @@ pub fn gen_comprehension<'ctx, 'a, G: CodeGenerator>(
|
||||||
let val = ctx.build_gep_and_load(arr_ptr, &[tmp], Some("val"));
|
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() {
|
||||||
let result = generator
|
let result = generator
|
||||||
.gen_expr(ctx, cond)?
|
.gen_expr(ctx, cond)?
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.to_basic_value_enum(ctx, generator, cond.custom.unwrap())?
|
.to_basic_value_enum(ctx, generator, cond.custom.unwrap())?
|
||||||
.into_int_value();
|
.into_int_value();
|
||||||
|
let result = generator.bool_to_i1(ctx, result);
|
||||||
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);
|
||||||
|
|
||||||
|
@ -996,6 +1050,13 @@ pub fn gen_comprehension<'ctx, 'a, G: CodeGenerator>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Generates LLVM IR for a [binary operator expression][expr].
|
||||||
|
///
|
||||||
|
/// * `left` - The left-hand side of the binary operator.
|
||||||
|
/// * `op` - The operator applied on the operands.
|
||||||
|
/// * `right` - The right-hand side of the binary operator.
|
||||||
|
/// * `loc` - The location of the full expression.
|
||||||
|
/// * `is_aug_assign` - Whether the binary operator expression is also an assignment operator.
|
||||||
pub fn gen_binop_expr<'ctx, 'a, G: CodeGenerator>(
|
pub fn gen_binop_expr<'ctx, 'a, G: CodeGenerator>(
|
||||||
generator: &mut G,
|
generator: &mut G,
|
||||||
ctx: &mut CodeGenContext<'ctx, 'a>,
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||||
|
@ -1092,6 +1153,7 @@ pub fn gen_binop_expr<'ctx, 'a, G: CodeGenerator>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// See [CodeGenerator::gen_expr].
|
||||||
pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
|
pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
|
||||||
generator: &mut G,
|
generator: &mut G,
|
||||||
ctx: &mut CodeGenContext<'ctx, 'a>,
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||||
|
@ -1231,6 +1293,7 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.to_basic_value_enum(ctx, generator, values[0].custom.unwrap())?
|
.to_basic_value_enum(ctx, generator, values[0].custom.unwrap())?
|
||||||
.into_int_value();
|
.into_int_value();
|
||||||
|
let left = generator.bool_to_i1(ctx, left);
|
||||||
let current = ctx.builder.get_insert_block().unwrap().get_parent().unwrap();
|
let current = ctx.builder.get_insert_block().unwrap().get_parent().unwrap();
|
||||||
let a_bb = ctx.ctx.append_basic_block(current, "a");
|
let a_bb = ctx.ctx.append_basic_block(current, "a");
|
||||||
let b_bb = ctx.ctx.append_basic_block(current, "b");
|
let b_bb = ctx.ctx.append_basic_block(current, "b");
|
||||||
|
@ -1239,7 +1302,7 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
|
||||||
let (a, b) = match op {
|
let (a, b) = match op {
|
||||||
Boolop::Or => {
|
Boolop::Or => {
|
||||||
ctx.builder.position_at_end(a_bb);
|
ctx.builder.position_at_end(a_bb);
|
||||||
let a = ctx.ctx.bool_type().const_int(1, false);
|
let a = ctx.ctx.i8_type().const_int(1, false);
|
||||||
ctx.builder.build_unconditional_branch(cont_bb);
|
ctx.builder.build_unconditional_branch(cont_bb);
|
||||||
ctx.builder.position_at_end(b_bb);
|
ctx.builder.position_at_end(b_bb);
|
||||||
let b = generator
|
let b = generator
|
||||||
|
@ -1247,6 +1310,7 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.to_basic_value_enum(ctx, generator, values[1].custom.unwrap())?
|
.to_basic_value_enum(ctx, generator, values[1].custom.unwrap())?
|
||||||
.into_int_value();
|
.into_int_value();
|
||||||
|
let b = generator.bool_to_i8(ctx, b);
|
||||||
ctx.builder.build_unconditional_branch(cont_bb);
|
ctx.builder.build_unconditional_branch(cont_bb);
|
||||||
(a, b)
|
(a, b)
|
||||||
}
|
}
|
||||||
|
@ -1257,15 +1321,16 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.to_basic_value_enum(ctx, generator, values[1].custom.unwrap())?
|
.to_basic_value_enum(ctx, generator, values[1].custom.unwrap())?
|
||||||
.into_int_value();
|
.into_int_value();
|
||||||
|
let a = generator.bool_to_i8(ctx, a);
|
||||||
ctx.builder.build_unconditional_branch(cont_bb);
|
ctx.builder.build_unconditional_branch(cont_bb);
|
||||||
ctx.builder.position_at_end(b_bb);
|
ctx.builder.position_at_end(b_bb);
|
||||||
let b = ctx.ctx.bool_type().const_int(0, false);
|
let b = ctx.ctx.i8_type().const_zero();
|
||||||
ctx.builder.build_unconditional_branch(cont_bb);
|
ctx.builder.build_unconditional_branch(cont_bb);
|
||||||
(a, b)
|
(a, b)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
ctx.builder.position_at_end(cont_bb);
|
ctx.builder.position_at_end(cont_bb);
|
||||||
let phi = ctx.builder.build_phi(ctx.ctx.bool_type(), "phi");
|
let phi = ctx.builder.build_phi(ctx.ctx.i8_type(), "");
|
||||||
phi.add_incoming(&[(&a, a_bb), (&b, b_bb)]);
|
phi.add_incoming(&[(&a, a_bb), (&b, b_bb)]);
|
||||||
phi.as_basic_value().into()
|
phi.as_basic_value().into()
|
||||||
}
|
}
|
||||||
|
@ -1399,6 +1464,7 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.to_basic_value_enum(ctx, generator, test.custom.unwrap())?
|
.to_basic_value_enum(ctx, generator, test.custom.unwrap())?
|
||||||
.into_int_value();
|
.into_int_value();
|
||||||
|
let test = generator.bool_to_i1(ctx, test);
|
||||||
let body_ty = body.custom.unwrap();
|
let body_ty = body.custom.unwrap();
|
||||||
let is_none = ctx.unifier.get_representative(body_ty) == ctx.primitives.none;
|
let is_none = ctx.unifier.get_representative(body_ty) == ctx.primitives.none;
|
||||||
let result = if !is_none {
|
let result = if !is_none {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
codegen::{expr::*, stmt::*, CodeGenContext},
|
codegen::{expr::*, stmt::*, bool_to_i1, bool_to_i8, CodeGenContext},
|
||||||
symbol_resolver::ValueEnum,
|
symbol_resolver::ValueEnum,
|
||||||
toplevel::{DefinitionId, TopLevelDef},
|
toplevel::{DefinitionId, TopLevelDef},
|
||||||
typecheck::typedef::{FunSignature, Type},
|
typecheck::typedef::{FunSignature, Type},
|
||||||
|
@ -7,7 +7,7 @@ use crate::{
|
||||||
use inkwell::{
|
use inkwell::{
|
||||||
context::Context,
|
context::Context,
|
||||||
types::{BasicTypeEnum, IntType},
|
types::{BasicTypeEnum, IntType},
|
||||||
values::{BasicValueEnum, PointerValue},
|
values::{BasicValueEnum, IntValue, PointerValue},
|
||||||
};
|
};
|
||||||
use nac3parser::ast::{Expr, Stmt, StrRef};
|
use nac3parser::ast::{Expr, Stmt, StrRef};
|
||||||
|
|
||||||
|
@ -180,6 +180,24 @@ pub trait CodeGenerator {
|
||||||
{
|
{
|
||||||
gen_stmt(self, ctx, stmt)
|
gen_stmt(self, ctx, stmt)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// See [bool_to_i1].
|
||||||
|
fn bool_to_i1<'ctx, 'a>(
|
||||||
|
&self,
|
||||||
|
ctx: &CodeGenContext<'ctx, 'a>,
|
||||||
|
bool_value: IntValue<'ctx>
|
||||||
|
) -> IntValue<'ctx> {
|
||||||
|
bool_to_i1(&ctx.builder, bool_value)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// See [bool_to_i8].
|
||||||
|
fn bool_to_i8<'ctx, 'a>(
|
||||||
|
&self,
|
||||||
|
ctx: &CodeGenContext<'ctx, 'a>,
|
||||||
|
bool_value: IntValue<'ctx>
|
||||||
|
) -> IntValue<'ctx> {
|
||||||
|
bool_to_i8(&ctx.builder, &ctx.ctx, bool_value)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct DefaultCodeGenerator {
|
pub struct DefaultCodeGenerator {
|
||||||
|
|
|
@ -9,6 +9,7 @@ use crate::{
|
||||||
use crossbeam::channel::{unbounded, Receiver, Sender};
|
use crossbeam::channel::{unbounded, Receiver, Sender};
|
||||||
use inkwell::{
|
use inkwell::{
|
||||||
AddressSpace,
|
AddressSpace,
|
||||||
|
IntPredicate,
|
||||||
OptimizationLevel,
|
OptimizationLevel,
|
||||||
attributes::{Attribute, AttributeLoc},
|
attributes::{Attribute, AttributeLoc},
|
||||||
basic_block::BasicBlock,
|
basic_block::BasicBlock,
|
||||||
|
@ -18,7 +19,7 @@ use inkwell::{
|
||||||
passes::PassBuilderOptions,
|
passes::PassBuilderOptions,
|
||||||
targets::{CodeModel, RelocMode, Target, TargetMachine, TargetTriple},
|
targets::{CodeModel, RelocMode, Target, TargetMachine, TargetTriple},
|
||||||
types::{AnyType, BasicType, BasicTypeEnum},
|
types::{AnyType, BasicType, BasicTypeEnum},
|
||||||
values::{BasicValueEnum, FunctionValue, PhiValue, PointerValue},
|
values::{BasicValueEnum, FunctionValue, IntValue, PhiValue, PointerValue},
|
||||||
debug_info::{
|
debug_info::{
|
||||||
DebugInfoBuilder, DICompileUnit, DISubprogram, AsDIScope, DIFlagsConstants, DIScope
|
DebugInfoBuilder, DICompileUnit, DISubprogram, AsDIScope, DIFlagsConstants, DIScope
|
||||||
},
|
},
|
||||||
|
@ -353,6 +354,10 @@ pub struct CodeGenTask {
|
||||||
pub id: usize,
|
pub id: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Retrieves the [LLVM type][BasicTypeEnum] corresponding to the [Type].
|
||||||
|
///
|
||||||
|
/// This function is used to obtain the in-memory representation of `ty`, e.g. a `bool` variable
|
||||||
|
/// would be represented by an `i8`.
|
||||||
fn get_llvm_type<'ctx>(
|
fn get_llvm_type<'ctx>(
|
||||||
ctx: &'ctx Context,
|
ctx: &'ctx Context,
|
||||||
module: &Module<'ctx>,
|
module: &Module<'ctx>,
|
||||||
|
@ -464,6 +469,34 @@ fn get_llvm_type<'ctx>(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Retrieves the [LLVM type][BasicTypeEnum] corresponding to the [Type].
|
||||||
|
///
|
||||||
|
/// This function is used mainly to obtain the ABI representation of `ty`, e.g. a `bool` is
|
||||||
|
/// would be represented by an `i1`.
|
||||||
|
///
|
||||||
|
/// The difference between the in-memory representation (as returned by [get_llvm_type]) and the
|
||||||
|
/// ABI representation is that the in-memory representation must be at least byte-sized and must
|
||||||
|
/// be byte-aligned for the variable to be addressable in memory, whereas there is no such
|
||||||
|
/// restriction for ABI representations.
|
||||||
|
fn get_llvm_abi_type<'ctx>(
|
||||||
|
ctx: &'ctx Context,
|
||||||
|
module: &Module<'ctx>,
|
||||||
|
generator: &mut dyn CodeGenerator,
|
||||||
|
unifier: &mut Unifier,
|
||||||
|
top_level: &TopLevelContext,
|
||||||
|
type_cache: &mut HashMap<Type, BasicTypeEnum<'ctx>>,
|
||||||
|
primitives: &PrimitiveStore,
|
||||||
|
ty: Type,
|
||||||
|
) -> BasicTypeEnum<'ctx> {
|
||||||
|
// If the type is used in the definition of a function, return `i1` instead of `i8` for ABI
|
||||||
|
// consistency.
|
||||||
|
return if unifier.unioned(ty, primitives.bool) {
|
||||||
|
ctx.bool_type().into()
|
||||||
|
} else {
|
||||||
|
get_llvm_type(ctx, module, generator, unifier, top_level, type_cache, primitives, ty)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn need_sret<'ctx>(ctx: &'ctx Context, ty: BasicTypeEnum<'ctx>) -> bool {
|
fn need_sret<'ctx>(ctx: &'ctx Context, ty: BasicTypeEnum<'ctx>) -> bool {
|
||||||
fn need_sret_impl<'ctx>(ctx: &'ctx Context, ty: BasicTypeEnum<'ctx>, maybe_large: bool) -> bool {
|
fn need_sret_impl<'ctx>(ctx: &'ctx Context, ty: BasicTypeEnum<'ctx>, maybe_large: bool) -> bool {
|
||||||
match ty {
|
match ty {
|
||||||
|
@ -477,6 +510,7 @@ fn need_sret<'ctx>(ctx: &'ctx Context, ty: BasicTypeEnum<'ctx>) -> bool {
|
||||||
need_sret_impl(ctx, ty, true)
|
need_sret_impl(ctx, ty, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Implementation for generating LLVM IR for a function.
|
||||||
pub fn gen_func_impl<'ctx, G: CodeGenerator, F: FnOnce(&mut G, &mut CodeGenContext) -> Result<(), String>> (
|
pub fn gen_func_impl<'ctx, G: CodeGenerator, F: FnOnce(&mut G, &mut CodeGenContext) -> Result<(), String>> (
|
||||||
context: &'ctx Context,
|
context: &'ctx Context,
|
||||||
generator: &mut G,
|
generator: &mut G,
|
||||||
|
@ -533,7 +567,7 @@ pub fn gen_func_impl<'ctx, G: CodeGenerator, F: FnOnce(&mut G, &mut CodeGenConte
|
||||||
(primitives.uint32, context.i32_type().into()),
|
(primitives.uint32, context.i32_type().into()),
|
||||||
(primitives.uint64, context.i64_type().into()),
|
(primitives.uint64, context.i64_type().into()),
|
||||||
(primitives.float, context.f64_type().into()),
|
(primitives.float, context.f64_type().into()),
|
||||||
(primitives.bool, context.bool_type().into()),
|
(primitives.bool, context.i8_type().into()),
|
||||||
(primitives.str, {
|
(primitives.str, {
|
||||||
let name = "str";
|
let name = "str";
|
||||||
match module.get_struct_type(name) {
|
match module.get_struct_type(name) {
|
||||||
|
@ -591,14 +625,14 @@ pub fn gen_func_impl<'ctx, G: CodeGenerator, F: FnOnce(&mut G, &mut CodeGenConte
|
||||||
let ret_type = if unifier.unioned(ret, primitives.none) {
|
let ret_type = if unifier.unioned(ret, primitives.none) {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
Some(get_llvm_type(context, &module, generator, &mut unifier, top_level_ctx.as_ref(), &mut type_cache, &primitives, ret))
|
Some(get_llvm_abi_type(context, &module, generator, &mut unifier, top_level_ctx.as_ref(), &mut type_cache, &primitives, ret))
|
||||||
};
|
};
|
||||||
|
|
||||||
let has_sret = ret_type.map_or(false, |ty| need_sret(context, ty));
|
let has_sret = ret_type.map_or(false, |ty| need_sret(context, ty));
|
||||||
let mut params = args
|
let mut params = args
|
||||||
.iter()
|
.iter()
|
||||||
.map(|arg| {
|
.map(|arg| {
|
||||||
get_llvm_type(
|
get_llvm_abi_type(
|
||||||
context,
|
context,
|
||||||
&module,
|
&module,
|
||||||
generator,
|
generator,
|
||||||
|
@ -646,19 +680,35 @@ pub fn gen_func_impl<'ctx, G: CodeGenerator, F: FnOnce(&mut G, &mut CodeGenConte
|
||||||
let offset = if has_sret { 1 } else { 0 };
|
let offset = if has_sret { 1 } else { 0 };
|
||||||
for (n, arg) in args.iter().enumerate() {
|
for (n, arg) in args.iter().enumerate() {
|
||||||
let param = fn_val.get_nth_param((n as u32) + offset).unwrap();
|
let param = fn_val.get_nth_param((n as u32) + offset).unwrap();
|
||||||
let alloca = builder.build_alloca(
|
let local_type = get_llvm_type(
|
||||||
get_llvm_type(
|
context,
|
||||||
context,
|
&module,
|
||||||
&module,
|
generator,
|
||||||
generator,
|
&mut unifier,
|
||||||
&mut unifier,
|
top_level_ctx.as_ref(),
|
||||||
top_level_ctx.as_ref(),
|
&mut type_cache,
|
||||||
&mut type_cache,
|
&primitives,
|
||||||
&primitives,
|
arg.ty,
|
||||||
arg.ty,
|
|
||||||
),
|
|
||||||
&arg.name.to_string(),
|
|
||||||
);
|
);
|
||||||
|
let alloca = builder.build_alloca(
|
||||||
|
local_type,
|
||||||
|
&format!("{}.addr", &arg.name.to_string()),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Remap boolean parameters into i8
|
||||||
|
let param = if local_type.is_int_type() && param.is_int_value() {
|
||||||
|
let expected_ty = local_type.into_int_type();
|
||||||
|
let param_val = param.into_int_value();
|
||||||
|
|
||||||
|
if expected_ty.get_bit_width() == 8 && param_val.get_type().get_bit_width() == 1 {
|
||||||
|
bool_to_i8(&builder, &context, param_val)
|
||||||
|
} else {
|
||||||
|
param_val
|
||||||
|
}.into()
|
||||||
|
} else {
|
||||||
|
param
|
||||||
|
};
|
||||||
|
|
||||||
builder.build_store(alloca, param);
|
builder.build_store(alloca, param);
|
||||||
var_assignment.insert(arg.name, (alloca, None, 0));
|
var_assignment.insert(arg.name, (alloca, None, 0));
|
||||||
}
|
}
|
||||||
|
@ -785,6 +835,15 @@ pub fn gen_func_impl<'ctx, G: CodeGenerator, F: FnOnce(&mut G, &mut CodeGenConte
|
||||||
Ok((builder, module, fn_val))
|
Ok((builder, module, fn_val))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Generates LLVM IR for a function.
|
||||||
|
///
|
||||||
|
/// * `context` - The [LLVM Context][Context] used in generating the function body.
|
||||||
|
/// * `generator` - The [CodeGenerator] for generating various program constructs.
|
||||||
|
/// * `registry` - The [WorkerRegistry] responsible for monitoring this function generation task.
|
||||||
|
/// * `builder` - The [Builder] used for generating LLVM IR.
|
||||||
|
/// * `module` - The [Module] of which the generated LLVM function will be inserted into.
|
||||||
|
/// * `task` - The [CodeGenTask] associated with this function generation task.
|
||||||
|
///
|
||||||
pub fn gen_func<'ctx, G: CodeGenerator>(
|
pub fn gen_func<'ctx, G: CodeGenerator>(
|
||||||
context: &'ctx Context,
|
context: &'ctx Context,
|
||||||
generator: &mut G,
|
generator: &mut G,
|
||||||
|
@ -801,3 +860,40 @@ pub fn gen_func<'ctx, G: CodeGenerator>(
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Converts the value of a boolean-like value `bool_value` into an `i1`.
|
||||||
|
fn bool_to_i1<'ctx>(builder: &Builder<'ctx>, bool_value: IntValue<'ctx>) -> IntValue<'ctx> {
|
||||||
|
if bool_value.get_type().get_bit_width() != 1 {
|
||||||
|
builder.build_int_compare(
|
||||||
|
IntPredicate::NE,
|
||||||
|
bool_value,
|
||||||
|
bool_value.get_type().const_zero(),
|
||||||
|
"tobool"
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
bool_value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Converts the value of a boolean-like value `bool_value` into an `i8`.
|
||||||
|
fn bool_to_i8<'ctx>(
|
||||||
|
builder: &Builder<'ctx>,
|
||||||
|
ctx: &'ctx Context,
|
||||||
|
bool_value: IntValue<'ctx>
|
||||||
|
) -> IntValue<'ctx> {
|
||||||
|
let value_bits = bool_value.get_type().get_bit_width();
|
||||||
|
match value_bits {
|
||||||
|
8 => bool_value,
|
||||||
|
1 => builder.build_int_z_extend(bool_value, ctx.i8_type(), "frombool"),
|
||||||
|
_ => bool_to_i8(
|
||||||
|
builder,
|
||||||
|
ctx,
|
||||||
|
builder.build_int_compare(
|
||||||
|
IntPredicate::NE,
|
||||||
|
bool_value,
|
||||||
|
bool_value.get_type().const_zero(),
|
||||||
|
""
|
||||||
|
)
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ use nac3parser::ast::{
|
||||||
};
|
};
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
|
|
||||||
|
/// See [CodeGenerator::gen_var_alloc].
|
||||||
pub fn gen_var<'ctx, 'a>(
|
pub fn gen_var<'ctx, 'a>(
|
||||||
ctx: &mut CodeGenContext<'ctx, 'a>,
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||||
ty: BasicTypeEnum<'ctx>,
|
ty: BasicTypeEnum<'ctx>,
|
||||||
|
@ -35,6 +36,7 @@ pub fn gen_var<'ctx, 'a>(
|
||||||
Ok(ptr)
|
Ok(ptr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// See [CodeGenerator::gen_store_target].
|
||||||
pub fn gen_store_target<'ctx, 'a, G: CodeGenerator>(
|
pub fn gen_store_target<'ctx, 'a, G: CodeGenerator>(
|
||||||
generator: &mut G,
|
generator: &mut G,
|
||||||
ctx: &mut CodeGenContext<'ctx, 'a>,
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||||
|
@ -144,6 +146,7 @@ pub fn gen_store_target<'ctx, 'a, G: CodeGenerator>(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// See [CodeGenerator::gen_assign].
|
||||||
pub fn gen_assign<'ctx, 'a, G: CodeGenerator>(
|
pub fn gen_assign<'ctx, 'a, G: CodeGenerator>(
|
||||||
generator: &mut G,
|
generator: &mut G,
|
||||||
ctx: &mut CodeGenContext<'ctx, 'a>,
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||||
|
@ -214,13 +217,21 @@ pub fn gen_assign<'ctx, 'a, G: CodeGenerator>(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generates a sequence of IR which checks whether [value] does not exceed the upper bound of the
|
/// Generates a sequence of IR which checks whether `value` does not exceed the upper bound of the
|
||||||
/// range as defined by [stop] and [step].
|
/// range as defined by `stop` and `step`.
|
||||||
///
|
///
|
||||||
/// Note that the generated IR will **not** check whether value is part of the range or whether
|
/// Note that the generated IR will **not** check whether value is part of the range or whether
|
||||||
/// value exceeds the lower bound of the range (as evident by the missing `start` argument).
|
/// value exceeds the lower bound of the range (as evident by the missing `start` argument).
|
||||||
///
|
///
|
||||||
/// Returns an [IntValue] representing the result of whether the [value] is in the range.
|
/// The generated IR is equivalent to the following Rust code:
|
||||||
|
///
|
||||||
|
/// ```rust,ignore
|
||||||
|
/// let sign = step > 0;
|
||||||
|
/// let (lo, hi) = if sign { (value, stop) } else { (stop, value) };
|
||||||
|
/// let cmp = lo < hi;
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// Returns an `i1` [IntValue] representing the result of whether the `value` is in the range.
|
||||||
fn gen_in_range_check<'ctx, 'a>(
|
fn gen_in_range_check<'ctx, 'a>(
|
||||||
ctx: &CodeGenContext<'ctx, 'a>,
|
ctx: &CodeGenContext<'ctx, 'a>,
|
||||||
value: IntValue<'ctx>,
|
value: IntValue<'ctx>,
|
||||||
|
@ -234,6 +245,7 @@ fn gen_in_range_check<'ctx, 'a>(
|
||||||
ctx.builder.build_int_compare(IntPredicate::SLT, lo, hi, "cmp")
|
ctx.builder.build_int_compare(IntPredicate::SLT, lo, hi, "cmp")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// See [CodeGenerator::gen_for].
|
||||||
pub fn gen_for<'ctx, 'a, G: CodeGenerator>(
|
pub fn gen_for<'ctx, 'a, G: CodeGenerator>(
|
||||||
generator: &mut G,
|
generator: &mut G,
|
||||||
ctx: &mut CodeGenContext<'ctx, 'a>,
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||||
|
@ -384,6 +396,7 @@ pub fn gen_for<'ctx, 'a, G: CodeGenerator>(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// See [CodeGenerator::gen_while].
|
||||||
pub fn gen_while<'ctx, 'a, G: CodeGenerator>(
|
pub fn gen_while<'ctx, 'a, G: CodeGenerator>(
|
||||||
generator: &mut G,
|
generator: &mut G,
|
||||||
ctx: &mut CodeGenContext<'ctx, 'a>,
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||||
|
@ -411,7 +424,7 @@ pub fn gen_while<'ctx, 'a, G: CodeGenerator>(
|
||||||
test.custom.unwrap(),
|
test.custom.unwrap(),
|
||||||
)?;
|
)?;
|
||||||
if let BasicValueEnum::IntValue(test) = test {
|
if let BasicValueEnum::IntValue(test) = test {
|
||||||
ctx.builder.build_conditional_branch(test, body_bb, orelse_bb);
|
ctx.builder.build_conditional_branch(generator.bool_to_i1(ctx, test), body_bb, orelse_bb);
|
||||||
} else {
|
} else {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
};
|
};
|
||||||
|
@ -447,6 +460,7 @@ pub fn gen_while<'ctx, 'a, G: CodeGenerator>(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// See [CodeGenerator::gen_if].
|
||||||
pub fn gen_if<'ctx, 'a, G: CodeGenerator>(
|
pub fn gen_if<'ctx, 'a, G: CodeGenerator>(
|
||||||
generator: &mut G,
|
generator: &mut G,
|
||||||
ctx: &mut CodeGenContext<'ctx, 'a>,
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||||
|
@ -470,13 +484,11 @@ pub fn gen_if<'ctx, 'a, G: CodeGenerator>(
|
||||||
};
|
};
|
||||||
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 test = generator.gen_expr(ctx, test)?.unwrap().to_basic_value_enum(
|
let test = generator.gen_expr(ctx, test)?
|
||||||
ctx,
|
.unwrap()
|
||||||
generator,
|
.to_basic_value_enum(ctx, generator, test.custom.unwrap())?;
|
||||||
test.custom.unwrap(),
|
|
||||||
)?;
|
|
||||||
if let BasicValueEnum::IntValue(test) = test {
|
if let BasicValueEnum::IntValue(test) = test {
|
||||||
ctx.builder.build_conditional_branch(test, body_bb, orelse_bb);
|
ctx.builder.build_conditional_branch(generator.bool_to_i1(ctx, test), body_bb, orelse_bb);
|
||||||
} else {
|
} else {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
};
|
};
|
||||||
|
@ -537,6 +549,8 @@ pub fn final_proxy<'ctx, 'a>(
|
||||||
final_paths.push(block);
|
final_paths.push(block);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Inserts the declaration of the builtin function with the specified `symbol` name, and returns
|
||||||
|
/// the function.
|
||||||
pub fn get_builtins<'ctx, 'a>(
|
pub fn get_builtins<'ctx, 'a>(
|
||||||
generator: &mut dyn CodeGenerator,
|
generator: &mut dyn CodeGenerator,
|
||||||
ctx: &mut CodeGenContext<'ctx, 'a>,
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||||
|
@ -634,6 +648,10 @@ pub fn exn_constructor<'ctx, 'a>(
|
||||||
Ok(Some(zelf.into()))
|
Ok(Some(zelf.into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Generates IR for a `raise` statement.
|
||||||
|
///
|
||||||
|
/// * `exception` - The exception thrown by the `raise` statement.
|
||||||
|
/// * `loc` - The location where the exception is raised from.
|
||||||
pub fn gen_raise<'ctx, 'a>(
|
pub fn gen_raise<'ctx, 'a>(
|
||||||
generator: &mut dyn CodeGenerator,
|
generator: &mut dyn CodeGenerator,
|
||||||
ctx: &mut CodeGenContext<'ctx, 'a>,
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||||
|
@ -685,6 +703,7 @@ pub fn gen_raise<'ctx, 'a>(
|
||||||
ctx.builder.build_unreachable();
|
ctx.builder.build_unreachable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Generates IR for a `try` statement.
|
||||||
pub fn gen_try<'ctx, 'a, G: CodeGenerator>(
|
pub fn gen_try<'ctx, 'a, G: CodeGenerator>(
|
||||||
generator: &mut G,
|
generator: &mut G,
|
||||||
ctx: &mut CodeGenContext<'ctx, 'a>,
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||||
|
@ -1006,6 +1025,7 @@ pub fn gen_try<'ctx, 'a, G: CodeGenerator>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// See [CodeGenerator::gen_with].
|
||||||
pub fn gen_with<'ctx, 'a, G: CodeGenerator>(
|
pub fn gen_with<'ctx, 'a, G: CodeGenerator>(
|
||||||
_: &mut G,
|
_: &mut G,
|
||||||
_: &mut CodeGenContext<'ctx, 'a>,
|
_: &mut CodeGenContext<'ctx, 'a>,
|
||||||
|
@ -1015,11 +1035,13 @@ pub fn gen_with<'ctx, 'a, G: CodeGenerator>(
|
||||||
Err(format!("With statement with custom types is not yet supported (at {})", stmt.location))
|
Err(format!("With statement with custom types is not yet supported (at {})", stmt.location))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Generates IR for a `return` statement.
|
||||||
pub fn gen_return<'ctx, 'a, G: CodeGenerator>(
|
pub fn gen_return<'ctx, 'a, G: CodeGenerator>(
|
||||||
generator: &mut G,
|
generator: &mut G,
|
||||||
ctx: &mut CodeGenContext<'ctx, 'a>,
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||||
value: &Option<Box<Expr<Option<Type>>>>,
|
value: &Option<Box<Expr<Option<Type>>>>,
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
|
let func = ctx.builder.get_insert_block().and_then(|bb| bb.get_parent()).unwrap();
|
||||||
let value = value
|
let value = value
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|v_expr| {
|
.map(|v_expr| {
|
||||||
|
@ -1038,12 +1060,31 @@ pub fn gen_return<'ctx, 'a, G: CodeGenerator>(
|
||||||
ctx.builder.build_store(ctx.return_buffer.unwrap(), value.unwrap());
|
ctx.builder.build_store(ctx.return_buffer.unwrap(), value.unwrap());
|
||||||
ctx.builder.build_return(None);
|
ctx.builder.build_return(None);
|
||||||
} else {
|
} else {
|
||||||
|
// Remap boolean return type into i1
|
||||||
|
let value = value.map(|v| {
|
||||||
|
let expected_ty = func.get_type().get_return_type().unwrap();
|
||||||
|
let ret_val = v.as_basic_value_enum();
|
||||||
|
|
||||||
|
if expected_ty.is_int_type() && ret_val.is_int_value() {
|
||||||
|
let ret_type = expected_ty.into_int_type();
|
||||||
|
let ret_val = ret_val.into_int_value();
|
||||||
|
|
||||||
|
if ret_type.get_bit_width() == 1 && ret_val.get_type().get_bit_width() != 1 {
|
||||||
|
generator.bool_to_i1(ctx, ret_val)
|
||||||
|
} else {
|
||||||
|
ret_val
|
||||||
|
}.into()
|
||||||
|
} else {
|
||||||
|
ret_val
|
||||||
|
}
|
||||||
|
});
|
||||||
let value = value.as_ref().map(|v| v as &dyn BasicValue);
|
let value = value.as_ref().map(|v| v as &dyn BasicValue);
|
||||||
ctx.builder.build_return(value);
|
ctx.builder.build_return(value.into());
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// See [CodeGenerator::gen_stmt].
|
||||||
pub fn gen_stmt<'ctx, 'a, G: CodeGenerator>(
|
pub fn gen_stmt<'ctx, 'a, G: CodeGenerator>(
|
||||||
generator: &mut G,
|
generator: &mut G,
|
||||||
ctx: &mut CodeGenContext<'ctx, 'a>,
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||||
|
@ -1135,6 +1176,7 @@ pub fn gen_stmt<'ctx, 'a, G: CodeGenerator>(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Generates IR for a block statement contains `stmts`.
|
||||||
pub fn gen_block<'ctx, 'a, 'b, G: CodeGenerator, I: Iterator<Item = &'b Stmt<Option<Type>>>>(
|
pub fn gen_block<'ctx, 'a, 'b, G: CodeGenerator, I: Iterator<Item = &'b Stmt<Option<Type>>>>(
|
||||||
generator: &mut G,
|
generator: &mut G,
|
||||||
ctx: &mut CodeGenContext<'ctx, 'a>,
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||||
|
|
|
@ -24,7 +24,6 @@ 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>,
|
||||||
|
|
|
@ -59,6 +59,7 @@ impl Display for SymbolValue {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait StaticValue {
|
pub trait StaticValue {
|
||||||
|
/// Returns a unique identifier for this value.
|
||||||
fn get_unique_identifier(&self) -> u64;
|
fn get_unique_identifier(&self) -> u64;
|
||||||
|
|
||||||
fn get_const_obj<'ctx, 'a>(
|
fn get_const_obj<'ctx, 'a>(
|
||||||
|
@ -67,6 +68,7 @@ pub trait StaticValue {
|
||||||
generator: &mut dyn CodeGenerator,
|
generator: &mut dyn CodeGenerator,
|
||||||
) -> BasicValueEnum<'ctx>;
|
) -> BasicValueEnum<'ctx>;
|
||||||
|
|
||||||
|
/// Converts this value to a LLVM [BasicValueEnum].
|
||||||
fn to_basic_value_enum<'ctx, 'a>(
|
fn to_basic_value_enum<'ctx, 'a>(
|
||||||
&self,
|
&self,
|
||||||
ctx: &mut CodeGenContext<'ctx, 'a>,
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||||
|
@ -74,12 +76,14 @@ pub trait StaticValue {
|
||||||
expected_ty: Type,
|
expected_ty: Type,
|
||||||
) -> Result<BasicValueEnum<'ctx>, String>;
|
) -> Result<BasicValueEnum<'ctx>, String>;
|
||||||
|
|
||||||
|
/// Returns a field within this value.
|
||||||
fn get_field<'ctx, 'a>(
|
fn get_field<'ctx, 'a>(
|
||||||
&self,
|
&self,
|
||||||
name: StrRef,
|
name: StrRef,
|
||||||
ctx: &mut CodeGenContext<'ctx, 'a>,
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||||
) -> Option<ValueEnum<'ctx>>;
|
) -> Option<ValueEnum<'ctx>>;
|
||||||
|
|
||||||
|
/// Returns a single element of this tuple.
|
||||||
fn get_tuple_element<'ctx>(&self, index: u32) -> Option<ValueEnum<'ctx>>;
|
fn get_tuple_element<'ctx>(&self, index: u32) -> Option<ValueEnum<'ctx>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1050,7 +1050,7 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo {
|
||||||
let uint32 = ctx.primitives.uint32;
|
let uint32 = ctx.primitives.uint32;
|
||||||
let uint64 = ctx.primitives.uint64;
|
let uint64 = ctx.primitives.uint64;
|
||||||
let float = ctx.primitives.float;
|
let float = ctx.primitives.float;
|
||||||
let llvm_i1 = ctx.ctx.bool_type().as_basic_type_enum();
|
let llvm_i8 = ctx.ctx.i8_type().as_basic_type_enum();
|
||||||
let llvm_i32 = ctx.ctx.i32_type().as_basic_type_enum();
|
let llvm_i32 = ctx.ctx.i32_type().as_basic_type_enum();
|
||||||
let llvm_i64 = ctx.ctx.i64_type().as_basic_type_enum();
|
let llvm_i64 = ctx.ctx.i64_type().as_basic_type_enum();
|
||||||
let llvm_f64 = ctx.ctx.f64_type().as_basic_type_enum();
|
let llvm_f64 = ctx.ctx.f64_type().as_basic_type_enum();
|
||||||
|
@ -1060,7 +1060,7 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo {
|
||||||
let n_val = args[1].1.clone().to_basic_value_enum(ctx, generator, n_ty)?;
|
let n_val = args[1].1.clone().to_basic_value_enum(ctx, generator, n_ty)?;
|
||||||
let mut is_type = |a: Type, b: Type| ctx.unifier.unioned(a, b);
|
let mut is_type = |a: Type, b: Type| ctx.unifier.unioned(a, b);
|
||||||
let (fun_name, arg_ty) = if is_type(m_ty, n_ty) && is_type(n_ty, boolean) {
|
let (fun_name, arg_ty) = if is_type(m_ty, n_ty) && is_type(n_ty, boolean) {
|
||||||
("llvm.umin.i1", llvm_i1)
|
("llvm.umin.i8", llvm_i8)
|
||||||
} else if is_type(m_ty, n_ty) && is_type(n_ty, int32) {
|
} else if is_type(m_ty, n_ty) && is_type(n_ty, int32) {
|
||||||
("llvm.smin.i32", llvm_i32)
|
("llvm.smin.i32", llvm_i32)
|
||||||
} else if is_type(m_ty, n_ty) && is_type(n_ty, int64) {
|
} else if is_type(m_ty, n_ty) && is_type(n_ty, int64) {
|
||||||
|
@ -1112,7 +1112,7 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo {
|
||||||
let uint32 = ctx.primitives.uint32;
|
let uint32 = ctx.primitives.uint32;
|
||||||
let uint64 = ctx.primitives.uint64;
|
let uint64 = ctx.primitives.uint64;
|
||||||
let float = ctx.primitives.float;
|
let float = ctx.primitives.float;
|
||||||
let llvm_i1 = ctx.ctx.bool_type().as_basic_type_enum();
|
let llvm_i8 = ctx.ctx.i8_type().as_basic_type_enum();
|
||||||
let llvm_i32 = ctx.ctx.i32_type().as_basic_type_enum();
|
let llvm_i32 = ctx.ctx.i32_type().as_basic_type_enum();
|
||||||
let llvm_i64 = ctx.ctx.i64_type().as_basic_type_enum();
|
let llvm_i64 = ctx.ctx.i64_type().as_basic_type_enum();
|
||||||
let llvm_f64 = ctx.ctx.f64_type().as_basic_type_enum();
|
let llvm_f64 = ctx.ctx.f64_type().as_basic_type_enum();
|
||||||
|
@ -1122,7 +1122,7 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo {
|
||||||
let n_val = args[1].1.clone().to_basic_value_enum(ctx, generator, n_ty)?;
|
let n_val = args[1].1.clone().to_basic_value_enum(ctx, generator, n_ty)?;
|
||||||
let mut is_type = |a: Type, b: Type| ctx.unifier.unioned(a, b);
|
let mut is_type = |a: Type, b: Type| ctx.unifier.unioned(a, b);
|
||||||
let (fun_name, arg_ty) = if is_type(m_ty, n_ty) && is_type(n_ty, boolean) {
|
let (fun_name, arg_ty) = if is_type(m_ty, n_ty) && is_type(n_ty, boolean) {
|
||||||
("llvm.umax.i1", llvm_i1)
|
("llvm.umax.i8", llvm_i8)
|
||||||
} else if is_type(m_ty, n_ty) && is_type(n_ty, int32) {
|
} else if is_type(m_ty, n_ty) && is_type(n_ty, int32) {
|
||||||
("llvm.smax.i32", llvm_i32)
|
("llvm.smax.i32", llvm_i32)
|
||||||
} else if is_type(m_ty, n_ty) && is_type(n_ty, int64) {
|
} else if is_type(m_ty, n_ty) && is_type(n_ty, int64) {
|
||||||
|
|
|
@ -1,114 +0,0 @@
|
||||||
#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();
|
|
||||||
}
|
|
|
@ -23,60 +23,30 @@ mod cslice {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn output_int32(x: i32, newline: bool) {
|
pub extern "C" fn output_int32(x: i32) {
|
||||||
let str = format!("{x}");
|
println!("{}", x);
|
||||||
|
|
||||||
if newline {
|
|
||||||
println!("{str}");
|
|
||||||
} else {
|
|
||||||
print!("{str}");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn output_int64(x: i64, newline: bool) {
|
pub extern "C" fn output_int64(x: i64) {
|
||||||
let str = format!("{x}");
|
println!("{}", x);
|
||||||
|
|
||||||
if newline {
|
|
||||||
println!("{str}");
|
|
||||||
} else {
|
|
||||||
print!("{str}");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn output_uint32(x: u32, newline: bool) {
|
pub extern "C" fn output_uint32(x: u32) {
|
||||||
let str = format!("{x}");
|
println!("{}", x);
|
||||||
|
|
||||||
if newline {
|
|
||||||
println!("{str}");
|
|
||||||
} else {
|
|
||||||
print!("{str}");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn output_uint64(x: u64, newline: bool) {
|
pub extern "C" fn output_uint64(x: u64) {
|
||||||
let str = format!("{x}");
|
println!("{}", x);
|
||||||
|
|
||||||
if newline {
|
|
||||||
println!("{str}");
|
|
||||||
} else {
|
|
||||||
print!("{str}");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn output_float64(x: f64, newline: bool) {
|
pub extern "C" fn output_float64(x: f64) {
|
||||||
// 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
|
||||||
let str = format!("{:?}", x);
|
println!("{:?}", x);
|
||||||
|
|
||||||
if newline {
|
|
||||||
println!("{str}");
|
|
||||||
} else {
|
|
||||||
print!("{str}");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
|
@ -90,18 +60,15 @@ pub extern "C" fn output_asciiart(x: i32) {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn output_str(x: &cslice::CSlice<u8>, newline: bool) {
|
pub extern "C" fn output_str(x: &cslice::CSlice<u8>) {
|
||||||
for e in x.as_ref().iter() {
|
for e in x.as_ref().iter() {
|
||||||
print!("{}", char::from(*e));
|
print!("{}", char::from(*e));
|
||||||
}
|
}
|
||||||
|
println!();
|
||||||
if newline {
|
|
||||||
println!("");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn output_int32_list(x: &cslice::CSlice<i32>, newline: bool) {
|
pub extern "C" fn output_int32_list(x: &cslice::CSlice<i32>) {
|
||||||
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() {
|
||||||
|
@ -111,11 +78,7 @@ pub extern "C" fn output_int32_list(x: &cslice::CSlice<i32>, newline: bool) {
|
||||||
print!("{}, ", e);
|
print!("{}, ", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
print!("]");
|
println!("]");
|
||||||
|
|
||||||
if newline {
|
|
||||||
println!("");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
|
@ -126,10 +89,10 @@ 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 {
|
||||||
writeln!(io::stderr(),
|
writeln!(io::stderr(),
|
||||||
"__nac3_raise(state: {:#010x}, _exception_object: {:#010x}, _context: {:#010x})",
|
"__nac3_raise(state: {:#010x}, exception_object: {:#010x}, context: {:#010x})",
|
||||||
state,
|
state,
|
||||||
exception_object,
|
exception_object,
|
||||||
context
|
context
|
||||||
).unwrap();
|
).unwrap();
|
||||||
exit(101);
|
exit(101);
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,12 +48,6 @@ 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":
|
||||||
|
@ -67,7 +61,7 @@ def patch(module):
|
||||||
"output_float64",
|
"output_float64",
|
||||||
"output_str",
|
"output_str",
|
||||||
}:
|
}:
|
||||||
return output
|
return print
|
||||||
else:
|
else:
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
|
|
|
@ -1,21 +0,0 @@
|
||||||
#!/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
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
# Different cases for using boolean variables in boolean contexts.
|
||||||
|
# Tests whether all boolean variables (expressed as i8s) are lowered into i1s before used in branching instruction (`br`)
|
||||||
|
|
||||||
|
def bfunc(b: bool) -> bool:
|
||||||
|
return not b
|
||||||
|
|
||||||
|
def run() -> int32:
|
||||||
|
b1 = True
|
||||||
|
b2 = False
|
||||||
|
|
||||||
|
if b1:
|
||||||
|
pass
|
||||||
|
|
||||||
|
if not b2:
|
||||||
|
pass
|
||||||
|
|
||||||
|
while b2:
|
||||||
|
pass
|
||||||
|
|
||||||
|
l = [i for i in range(10) if b2]
|
||||||
|
|
||||||
|
b_and = True and False
|
||||||
|
b_or = True or False
|
||||||
|
|
||||||
|
b_and = b1 and b2
|
||||||
|
b_or = b1 or b2
|
||||||
|
|
||||||
|
bfunc(b1)
|
||||||
|
|
||||||
|
return 0
|
|
@ -1,9 +1,9 @@
|
||||||
@extern
|
@extern
|
||||||
def output_int32(x: int32, newline: bool=True):
|
def output_int32(x: int32):
|
||||||
...
|
...
|
||||||
|
|
||||||
@extern
|
@extern
|
||||||
def output_int64(x: int64, newline: bool=True):
|
def output_int64(x: int64):
|
||||||
...
|
...
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
@extern
|
@extern
|
||||||
def output_int32(x: int32, newline: bool=True):
|
def output_int32(x: int32):
|
||||||
...
|
...
|
||||||
|
|
||||||
def f1(a: int32 = 4):
|
def f1(a: int32 = 4):
|
||||||
|
|
|
@ -1,21 +1,21 @@
|
||||||
@extern
|
@extern
|
||||||
def output_int32(x: int32, newline: bool=True):
|
def output_int32(x: int32):
|
||||||
...
|
...
|
||||||
|
|
||||||
@extern
|
@extern
|
||||||
def output_int64(x: int64, newline: bool=True):
|
def output_int64(x: int64):
|
||||||
...
|
...
|
||||||
|
|
||||||
@extern
|
@extern
|
||||||
def output_uint32(x: uint32, newline: bool=True):
|
def output_uint32(x: uint32):
|
||||||
...
|
...
|
||||||
|
|
||||||
@extern
|
@extern
|
||||||
def output_uint64(x: uint64, newline: bool=True):
|
def output_uint64(x: uint64):
|
||||||
...
|
...
|
||||||
|
|
||||||
@extern
|
@extern
|
||||||
def output_int32_list(x: list[int32], newline: bool=True):
|
def output_int32_list(x: list[int32]):
|
||||||
...
|
...
|
||||||
|
|
||||||
@extern
|
@extern
|
||||||
|
@ -23,7 +23,7 @@ def output_asciiart(x: int32):
|
||||||
...
|
...
|
||||||
|
|
||||||
@extern
|
@extern
|
||||||
def output_str(x: str, newline: bool=True):
|
def output_str(x: str):
|
||||||
...
|
...
|
||||||
|
|
||||||
def test_output_int32():
|
def test_output_int32():
|
||||||
|
@ -47,8 +47,7 @@ def test_output_int32_list():
|
||||||
output_int32_list([0, 1, 3, 5, 10])
|
output_int32_list([0, 1, 3, 5, 10])
|
||||||
|
|
||||||
def test_output_str_family():
|
def test_output_str_family():
|
||||||
output_str("hello ", newline=False)
|
output_str("hello world")
|
||||||
output_str("world")
|
|
||||||
|
|
||||||
def run() -> int32:
|
def run() -> int32:
|
||||||
test_output_int32()
|
test_output_int32()
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
@extern
|
@extern
|
||||||
def output_int32(x: int32, newline: bool=True):
|
def output_int32(x: int32):
|
||||||
...
|
...
|
||||||
|
|
||||||
class A:
|
class A:
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
@extern
|
@extern
|
||||||
def output_int32(x: int32, newline: bool=True):
|
def output_int32(x: int32):
|
||||||
...
|
...
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
@extern
|
||||||
|
def output_int32(x: int32):
|
||||||
|
...
|
||||||
|
|
||||||
|
@extern
|
||||||
|
def output_int32_list(x: list[int32]):
|
||||||
|
...
|
||||||
|
|
||||||
|
def run() -> int32:
|
||||||
|
bl = [True, False]
|
||||||
|
|
||||||
|
bl1 = bl[:]
|
||||||
|
bl1[1:] = [True]
|
||||||
|
output_int32_list([int32(b) for b in bl1])
|
||||||
|
output_int32_list([int32(b) for b in bl1])
|
||||||
|
|
||||||
|
return 0
|
|
@ -1,9 +1,9 @@
|
||||||
@extern
|
@extern
|
||||||
def output_int32_list(x: list[int32], newline: bool=True):
|
def output_int32_list(x: list[int32]):
|
||||||
...
|
...
|
||||||
|
|
||||||
@extern
|
@extern
|
||||||
def output_int32(x: int32, newline: bool=True):
|
def output_int32(x: int32):
|
||||||
...
|
...
|
||||||
|
|
||||||
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, newline: bool=True):
|
def output_int32(x: int32):
|
||||||
...
|
...
|
||||||
|
|
||||||
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, newline: bool=True):
|
def output_int32(x: int32):
|
||||||
...
|
...
|
||||||
|
|
||||||
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, newline: bool=True):
|
def output_int32(x: int32):
|
||||||
...
|
...
|
||||||
|
|
||||||
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, newline: bool=True):
|
def output_int32(x: int32):
|
||||||
...
|
...
|
||||||
|
|
||||||
def run() -> int32:
|
def run() -> int32:
|
||||||
|
|
|
@ -2,15 +2,15 @@
|
||||||
# Taken from https://book.pythontips.com/en/latest/for_-_else.html
|
# Taken from https://book.pythontips.com/en/latest/for_-_else.html
|
||||||
|
|
||||||
@extern
|
@extern
|
||||||
def output_int32(x: int32, newline: bool=True):
|
def output_int32(x: int32):
|
||||||
...
|
...
|
||||||
|
|
||||||
@extern
|
@extern
|
||||||
def output_float64(x: float, newline: bool=True):
|
def output_float64(x: float):
|
||||||
...
|
...
|
||||||
|
|
||||||
@extern
|
@extern
|
||||||
def output_str(x: str, newline: bool=True):
|
def output_str(x: str):
|
||||||
...
|
...
|
||||||
|
|
||||||
def run() -> int32:
|
def run() -> int32:
|
||||||
|
@ -18,16 +18,16 @@ def run() -> int32:
|
||||||
for x in range(2, n):
|
for x in range(2, n):
|
||||||
try:
|
try:
|
||||||
if n % x == 0:
|
if n % x == 0:
|
||||||
output_int32(n, newline=False)
|
output_int32(n)
|
||||||
output_str(" equals ", newline=False)
|
output_str(" equals ")
|
||||||
output_int32(x, newline=False)
|
output_int32(x)
|
||||||
output_str(" * ", newline=False)
|
output_str(" * ")
|
||||||
output_float64(n / x)
|
output_float64(n / x)
|
||||||
except: # Assume this is intended to catch x == 0
|
except: # Assume this is intended to catch x == 0
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
# loop fell through without finding a factor
|
# loop fell through without finding a factor
|
||||||
output_int32(n, newline=False)
|
output_int32(n)
|
||||||
output_str(" is a prime number")
|
output_str(" is a prime number")
|
||||||
|
|
||||||
return 0
|
return 0
|
|
@ -1,17 +1,17 @@
|
||||||
@extern
|
@extern
|
||||||
def output_int32(x: int32, newline: bool=True):
|
def output_int32(x: int32):
|
||||||
...
|
...
|
||||||
@extern
|
@extern
|
||||||
def output_uint32(x: uint32, newline: bool=True):
|
def output_uint32(x: uint32):
|
||||||
...
|
...
|
||||||
@extern
|
@extern
|
||||||
def output_int64(x: int64, newline: bool=True):
|
def output_int64(x: int64):
|
||||||
...
|
...
|
||||||
@extern
|
@extern
|
||||||
def output_uint64(x: uint64, newline: bool=True):
|
def output_uint64(x: uint64):
|
||||||
...
|
...
|
||||||
@extern
|
@extern
|
||||||
def output_float64(x: float, newline: bool=True):
|
def output_float64(x: float):
|
||||||
...
|
...
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,19 +1,19 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
@extern
|
@extern
|
||||||
def output_int32(x: int32, newline: bool=True):
|
def output_int32(x: int32):
|
||||||
...
|
...
|
||||||
@extern
|
@extern
|
||||||
def output_uint32(x: uint32, newline: bool=True):
|
def output_uint32(x: uint32):
|
||||||
...
|
...
|
||||||
@extern
|
@extern
|
||||||
def output_int64(x: int64, newline: bool=True):
|
def output_int64(x: int64):
|
||||||
...
|
...
|
||||||
@extern
|
@extern
|
||||||
def output_uint64(x: uint64, newline: bool=True):
|
def output_uint64(x: uint64):
|
||||||
...
|
...
|
||||||
@extern
|
@extern
|
||||||
def output_float64(x: float, newline: bool=True):
|
def output_float64(x: float):
|
||||||
...
|
...
|
||||||
|
|
||||||
def run() -> int32:
|
def run() -> int32:
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
@extern
|
@extern
|
||||||
def output_int32(x: int32, newline: bool=True):
|
def output_int32(x: int32):
|
||||||
...
|
...
|
||||||
|
|
||||||
class A:
|
class A:
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
@extern
|
@extern
|
||||||
def output_float64(f: float, newline: bool=True):
|
def output_float64(f: float):
|
||||||
...
|
...
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
@extern
|
@extern
|
||||||
def output_int32(a: int32, newline: bool=True):
|
def output_int32(a: int32):
|
||||||
...
|
...
|
||||||
|
|
||||||
class A:
|
class A:
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
@extern
|
@extern
|
||||||
def output_int32_list(x: list[int32], newline: bool=True):
|
def output_int32_list(x: list[int32]):
|
||||||
...
|
...
|
||||||
|
|
||||||
@extern
|
@extern
|
||||||
def output_int32(x: int32, newline: bool=True):
|
def output_int32(x: int32):
|
||||||
...
|
...
|
||||||
|
|
||||||
class A:
|
class A:
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
@extern
|
@extern
|
||||||
def output_int32(x: int32, newline: bool=True):
|
def output_int32(x: int32):
|
||||||
...
|
...
|
||||||
|
|
||||||
class A:
|
class A:
|
||||||
|
|
Loading…
Reference in New Issue