1
0
forked from M-Labs/nac3

Merge pull request 'Add floor and ceil, move built-in functions to a separate file' (#120) from built_in_floor_ceil into master

Reviewed-on: M-Labs/nac3#120
This commit is contained in:
sb10q 2021-12-02 10:40:50 +08:00
commit b030aec191
3 changed files with 583 additions and 412 deletions

View File

@ -0,0 +1,580 @@
use std::cell::RefCell;
use inkwell::{IntPredicate, FloatPredicate};
use crate::symbol_resolver::SymbolValue;
use super::*;
type BuiltinInfo = (
Vec<(Arc<RwLock<TopLevelDef>>, Option<Stmt>)>,
&'static [&'static str]
);
pub fn get_built_ins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo {
let int32 = primitives.0.int32;
let int64 = primitives.0.int64;
let float = primitives.0.float;
let boolean = primitives.0.bool;
let range = primitives.0.range;
let string = primitives.0.str;
let num_ty = primitives.1.get_fresh_var_with_range(&[int32, int64, float, boolean]);
let var_map: HashMap<_, _> = vec![(num_ty.1, num_ty.0)].into_iter().collect();
let top_level_def_list = vec![
Arc::new(RwLock::new(TopLevelComposer::make_top_level_class_def(
0,
None,
"int32".into(),
None,
))),
Arc::new(RwLock::new(TopLevelComposer::make_top_level_class_def(
1,
None,
"int64".into(),
None,
))),
Arc::new(RwLock::new(TopLevelComposer::make_top_level_class_def(
2,
None,
"float".into(),
None,
))),
Arc::new(RwLock::new(TopLevelComposer::make_top_level_class_def(3, None, "bool".into(), None))),
Arc::new(RwLock::new(TopLevelComposer::make_top_level_class_def(4, None, "none".into(), None))),
Arc::new(RwLock::new(TopLevelComposer::make_top_level_class_def(
5,
None,
"range".into(),
None,
))),
Arc::new(RwLock::new(TopLevelComposer::make_top_level_class_def(6, None, "str".into(), None))),
Arc::new(RwLock::new(TopLevelDef::Function {
name: "int32".into(),
simple_name: "int32".into(),
signature: primitives.1.add_ty(TypeEnum::TFunc(RefCell::new(FunSignature {
args: vec![FuncArg { name: "_".into(), ty: num_ty.0, default_value: None }],
ret: int32,
vars: var_map.clone(),
}))),
var_id: Default::default(),
instance_to_symbol: Default::default(),
instance_to_stmt: Default::default(),
resolver: None,
codegen_callback: Some(Arc::new(GenCall::new(Box::new(
|ctx, _, fun, args| {
let int32 = ctx.primitives.int32;
let int64 = ctx.primitives.int64;
let float = ctx.primitives.float;
let boolean = ctx.primitives.bool;
let arg_ty = fun.0.args[0].ty;
let arg = args[0].1;
if ctx.unifier.unioned(arg_ty, boolean) {
Some(
ctx.builder
.build_int_s_extend(
arg.into_int_value(),
ctx.ctx.i32_type(),
"sext",
)
.into(),
)
} else if ctx.unifier.unioned(arg_ty, int32) {
Some(arg)
} else if ctx.unifier.unioned(arg_ty, int64) {
Some(
ctx.builder
.build_int_truncate(
arg.into_int_value(),
ctx.ctx.i32_type(),
"trunc",
)
.into(),
)
} else if ctx.unifier.unioned(arg_ty, float) {
let val = ctx
.builder
.build_float_to_signed_int(
arg.into_float_value(),
ctx.ctx.i32_type(),
"fptosi",
)
.into();
Some(val)
} else {
unreachable!()
}
},
)))),
})),
Arc::new(RwLock::new(TopLevelDef::Function {
name: "int64".into(),
simple_name: "int64".into(),
signature: primitives.1.add_ty(TypeEnum::TFunc(RefCell::new(FunSignature {
args: vec![FuncArg { name: "_".into(), ty: num_ty.0, default_value: None }],
ret: int64,
vars: var_map.clone(),
}))),
var_id: Default::default(),
instance_to_symbol: Default::default(),
instance_to_stmt: Default::default(),
resolver: None,
codegen_callback: Some(Arc::new(GenCall::new(Box::new(
|ctx, _, fun, args| {
let int32 = ctx.primitives.int32;
let int64 = ctx.primitives.int64;
let float = ctx.primitives.float;
let boolean = ctx.primitives.bool;
let arg_ty = fun.0.args[0].ty;
let arg = args[0].1;
if ctx.unifier.unioned(arg_ty, boolean)
|| ctx.unifier.unioned(arg_ty, int32)
{
Some(
ctx.builder
.build_int_s_extend(
arg.into_int_value(),
ctx.ctx.i64_type(),
"sext",
)
.into(),
)
} else if ctx.unifier.unioned(arg_ty, int64) {
Some(arg)
} else if ctx.unifier.unioned(arg_ty, float) {
let val = ctx
.builder
.build_float_to_signed_int(
arg.into_float_value(),
ctx.ctx.i64_type(),
"fptosi",
)
.into();
Some(val)
} else {
unreachable!()
}
},
)))),
})),
Arc::new(RwLock::new(TopLevelDef::Function {
name: "float".into(),
simple_name: "float".into(),
signature: primitives.1.add_ty(TypeEnum::TFunc(RefCell::new(FunSignature {
args: vec![FuncArg { name: "_".into(), ty: num_ty.0, default_value: None }],
ret: float,
vars: var_map.clone(),
}))),
var_id: Default::default(),
instance_to_symbol: Default::default(),
instance_to_stmt: Default::default(),
resolver: None,
codegen_callback: Some(Arc::new(GenCall::new(Box::new(
|ctx, _, fun, args| {
let int32 = ctx.primitives.int32;
let int64 = ctx.primitives.int64;
let boolean = ctx.primitives.bool;
let float = ctx.primitives.float;
let arg_ty = fun.0.args[0].ty;
let arg = args[0].1;
if ctx.unifier.unioned(arg_ty, boolean)
|| ctx.unifier.unioned(arg_ty, int32)
|| ctx.unifier.unioned(arg_ty, int64)
{
let arg = args[0].1.into_int_value();
let val = ctx
.builder
.build_signed_int_to_float(arg, ctx.ctx.f64_type(), "sitofp")
.into();
Some(val)
} else if ctx.unifier.unioned(arg_ty, float) {
Some(arg)
} else {
unreachable!()
}
},
)))),
})),
Arc::new(RwLock::new(TopLevelDef::Function {
name: "round".into(),
simple_name: "round".into(),
signature: primitives.1.add_ty(TypeEnum::TFunc(RefCell::new(FunSignature {
args: vec![FuncArg { name: "_".into(), ty: float, default_value: None }],
ret: int32,
vars: Default::default(),
}))),
var_id: Default::default(),
instance_to_symbol: Default::default(),
instance_to_stmt: Default::default(),
resolver: None,
codegen_callback: Some(Arc::new(GenCall::new(Box::new(|ctx, _, _, args| {
let arg = args[0].1;
let round_intrinsic =
ctx.module.get_function("llvm.round.f64").unwrap_or_else(|| {
let float = ctx.ctx.f64_type();
let fn_type = float.fn_type(&[float.into()], false);
ctx.module.add_function("llvm.round.f64", fn_type, None)
});
let val = ctx
.builder
.build_call(round_intrinsic, &[arg], "round")
.try_as_basic_value()
.left()
.unwrap();
Some(
ctx.builder
.build_float_to_signed_int(
val.into_float_value(),
ctx.ctx.i32_type(),
"fptosi",
)
.into(),
)
})))),
})),
Arc::new(RwLock::new(TopLevelDef::Function {
name: "round64".into(),
simple_name: "round64".into(),
signature: primitives.1.add_ty(TypeEnum::TFunc(RefCell::new(FunSignature {
args: vec![FuncArg { name: "_".into(), ty: float, default_value: None }],
ret: int64,
vars: Default::default(),
}))),
var_id: Default::default(),
instance_to_symbol: Default::default(),
instance_to_stmt: Default::default(),
resolver: None,
codegen_callback: Some(Arc::new(GenCall::new(Box::new(|ctx, _, _, args| {
let arg = args[0].1;
let round_intrinsic =
ctx.module.get_function("llvm.round.f64").unwrap_or_else(|| {
let float = ctx.ctx.f64_type();
let fn_type = float.fn_type(&[float.into()], false);
ctx.module.add_function("llvm.round.f64", fn_type, None)
});
let val = ctx
.builder
.build_call(round_intrinsic, &[arg], "round")
.try_as_basic_value()
.left()
.unwrap();
Some(
ctx.builder
.build_float_to_signed_int(
val.into_float_value(),
ctx.ctx.i64_type(),
"fptosi",
)
.into(),
)
})))),
})),
Arc::new(RwLock::new(TopLevelDef::Function {
name: "range".into(),
simple_name: "range".into(),
signature: primitives.1.add_ty(TypeEnum::TFunc(RefCell::new(FunSignature {
args: vec![
FuncArg { name: "start".into(), ty: int32, default_value: None },
FuncArg {
name: "stop".into(),
ty: int32,
// placeholder
default_value: Some(SymbolValue::I32(0)),
},
FuncArg {
name: "step".into(),
ty: int32,
default_value: Some(SymbolValue::I32(1)),
},
],
ret: range,
vars: Default::default(),
}))),
var_id: Default::default(),
instance_to_symbol: Default::default(),
instance_to_stmt: Default::default(),
resolver: None,
codegen_callback: Some(Arc::new(GenCall::new(Box::new(|ctx, _, _, args| {
let mut start = None;
let mut stop = None;
let mut step = None;
let int32 = ctx.ctx.i32_type();
let zero = int32.const_zero();
for (i, arg) in args.iter().enumerate() {
if arg.0 == Some("start".into()) {
start = Some(arg.1);
} else if arg.0 == Some("stop".into()) {
stop = Some(arg.1);
} else if arg.0 == Some("step".into()) {
step = Some(arg.1);
} else if i == 0 {
start = Some(arg.1);
} else if i == 1 {
stop = Some(arg.1);
} else if i == 2 {
step = Some(arg.1);
}
}
// TODO: error when step == 0
let step = step.unwrap_or_else(|| int32.const_int(1, false).into());
let stop = stop.unwrap_or_else(|| {
let v = start.unwrap();
start = None;
v
});
let start = start.unwrap_or_else(|| int32.const_zero().into());
let ty = int32.array_type(3);
let ptr = ctx.builder.build_alloca(ty, "range");
unsafe {
let a = ctx.builder.build_in_bounds_gep(ptr, &[zero, zero], "start");
let b = ctx.builder.build_in_bounds_gep(
ptr,
&[zero, int32.const_int(1, false)],
"end",
);
let c = ctx.builder.build_in_bounds_gep(
ptr,
&[zero, int32.const_int(2, false)],
"step",
);
ctx.builder.build_store(a, start);
ctx.builder.build_store(b, stop);
ctx.builder.build_store(c, step);
}
Some(ptr.into())
})))),
})),
Arc::new(RwLock::new(TopLevelDef::Function {
name: "str".into(),
simple_name: "str".into(),
signature: primitives.1.add_ty(TypeEnum::TFunc(RefCell::new(FunSignature {
args: vec![FuncArg { name: "_".into(), ty: string, default_value: None }],
ret: string,
vars: Default::default(),
}))),
var_id: Default::default(),
instance_to_symbol: Default::default(),
instance_to_stmt: Default::default(),
resolver: None,
codegen_callback: Some(Arc::new(GenCall::new(Box::new(|_, _, _, args| {
Some(args[0].1)
})))),
})),
Arc::new(RwLock::new(TopLevelDef::Function {
name: "bool".into(),
simple_name: "bool".into(),
signature: primitives.1.add_ty(TypeEnum::TFunc(RefCell::new(FunSignature {
args: vec![FuncArg { name: "_".into(), ty: num_ty.0, default_value: None }],
ret: primitives.0.bool,
vars: var_map,
}))),
var_id: Default::default(),
instance_to_symbol: Default::default(),
instance_to_stmt: Default::default(),
resolver: None,
codegen_callback: Some(Arc::new(GenCall::new(Box::new(
|ctx, _, fun, args| {
let int32 = ctx.primitives.int32;
let int64 = ctx.primitives.int64;
let float = ctx.primitives.float;
let boolean = ctx.primitives.bool;
let arg_ty = fun.0.args[0].ty;
let arg = args[0].1;
if ctx.unifier.unioned(arg_ty, boolean) {
Some(arg)
} else if ctx.unifier.unioned(arg_ty, int32) {
Some(ctx.builder.build_int_compare(
IntPredicate::NE,
ctx.ctx.i32_type().const_zero(),
arg.into_int_value(),
"bool",
).into())
} else if ctx.unifier.unioned(arg_ty, int64) {
Some(ctx.builder.build_int_compare(
IntPredicate::NE,
ctx.ctx.i64_type().const_zero(),
arg.into_int_value(),
"bool",
).into())
} else if ctx.unifier.unioned(arg_ty, float) {
let val = ctx.builder.
build_float_compare(
// UEQ as bool(nan) is True
FloatPredicate::UEQ,
arg.into_float_value(),
ctx.ctx.f64_type().const_zero(),
"bool"
).into();
Some(val)
} else {
unreachable!()
}
},
)))),
})),
Arc::new(RwLock::new(TopLevelDef::Function {
name: "floor".into(),
simple_name: "floor".into(),
signature: primitives.1.add_ty(TypeEnum::TFunc(RefCell::new(FunSignature {
args: vec![FuncArg { name: "_".into(), ty: float, default_value: None }],
ret: int32,
vars: Default::default(),
}))),
var_id: Default::default(),
instance_to_symbol: Default::default(),
instance_to_stmt: Default::default(),
resolver: None,
codegen_callback: Some(Arc::new(GenCall::new(Box::new(|ctx, _, _, args| {
let arg = args[0].1;
let floor_intrinsic =
ctx.module.get_function("llvm.floor.f64").unwrap_or_else(|| {
let float = ctx.ctx.f64_type();
let fn_type = float.fn_type(&[float.into()], false);
ctx.module.add_function("llvm.floor.f64", fn_type, None)
});
let val = ctx
.builder
.build_call(floor_intrinsic, &[arg], "floor")
.try_as_basic_value()
.left()
.unwrap();
Some(
ctx.builder
.build_float_to_signed_int(
val.into_float_value(),
ctx.ctx.i32_type(),
"fptosi",
)
.into(),
)
})))),
})),
Arc::new(RwLock::new(TopLevelDef::Function {
name: "floor64".into(),
simple_name: "floor64".into(),
signature: primitives.1.add_ty(TypeEnum::TFunc(RefCell::new(FunSignature {
args: vec![FuncArg { name: "_".into(), ty: float, default_value: None }],
ret: int64,
vars: Default::default(),
}))),
var_id: Default::default(),
instance_to_symbol: Default::default(),
instance_to_stmt: Default::default(),
resolver: None,
codegen_callback: Some(Arc::new(GenCall::new(Box::new(|ctx, _, _, args| {
let arg = args[0].1;
let floor_intrinsic =
ctx.module.get_function("llvm.floor.f64").unwrap_or_else(|| {
let float = ctx.ctx.f64_type();
let fn_type = float.fn_type(&[float.into()], false);
ctx.module.add_function("llvm.floor.f64", fn_type, None)
});
let val = ctx
.builder
.build_call(floor_intrinsic, &[arg], "floor")
.try_as_basic_value()
.left()
.unwrap();
Some(
ctx.builder
.build_float_to_signed_int(
val.into_float_value(),
ctx.ctx.i64_type(),
"fptosi",
)
.into(),
)
})))),
})),
Arc::new(RwLock::new(TopLevelDef::Function {
name: "ceil".into(),
simple_name: "ceil".into(),
signature: primitives.1.add_ty(TypeEnum::TFunc(RefCell::new(FunSignature {
args: vec![FuncArg { name: "_".into(), ty: float, default_value: None }],
ret: int32,
vars: Default::default(),
}))),
var_id: Default::default(),
instance_to_symbol: Default::default(),
instance_to_stmt: Default::default(),
resolver: None,
codegen_callback: Some(Arc::new(GenCall::new(Box::new(|ctx, _, _, args| {
let arg = args[0].1;
let ceil_intrinsic =
ctx.module.get_function("llvm.ceil.f64").unwrap_or_else(|| {
let float = ctx.ctx.f64_type();
let fn_type = float.fn_type(&[float.into()], false);
ctx.module.add_function("llvm.ceil.f64", fn_type, None)
});
let val = ctx
.builder
.build_call(ceil_intrinsic, &[arg], "ceil")
.try_as_basic_value()
.left()
.unwrap();
Some(
ctx.builder
.build_float_to_signed_int(
val.into_float_value(),
ctx.ctx.i32_type(),
"fptosi",
)
.into(),
)
})))),
})),
Arc::new(RwLock::new(TopLevelDef::Function {
name: "ceil64".into(),
simple_name: "ceil64".into(),
signature: primitives.1.add_ty(TypeEnum::TFunc(RefCell::new(FunSignature {
args: vec![FuncArg { name: "_".into(), ty: float, default_value: None }],
ret: int64,
vars: Default::default(),
}))),
var_id: Default::default(),
instance_to_symbol: Default::default(),
instance_to_stmt: Default::default(),
resolver: None,
codegen_callback: Some(Arc::new(GenCall::new(Box::new(|ctx, _, _, args| {
let arg = args[0].1;
let ceil_intrinsic =
ctx.module.get_function("llvm.ceil.f64").unwrap_or_else(|| {
let float = ctx.ctx.f64_type();
let fn_type = float.fn_type(&[float.into()], false);
ctx.module.add_function("llvm.ceil.f64", fn_type, None)
});
let val = ctx
.builder
.build_call(ceil_intrinsic, &[arg], "ceil")
.try_as_basic_value()
.left()
.unwrap();
Some(
ctx.builder
.build_float_to_signed_int(
val.into_float_value(),
ctx.ctx.i64_type(),
"fptosi",
)
.into(),
)
})))),
})),
];
let ast_list: Vec<Option<ast::Stmt<()>>> =
(0..top_level_def_list.len()).map(|_| None).collect();
(
izip!(top_level_def_list, ast_list).collect_vec(),
&[
"int32",
"int64",
"float",
"round",
"round64",
"range",
"str",
"bool",
"floor",
"floor64",
"ceil",
"ceil64"
]
)
}

View File

@ -1,10 +1,8 @@
use std::cell::RefCell;
use nac3parser::ast::fold::Fold;
use inkwell::{FloatPredicate, IntPredicate};
use crate::{
symbol_resolver::SymbolValue,
typecheck::type_inferencer::{FunctionData, Inferencer},
codegen::expr::get_subst_key,
};
@ -42,413 +40,7 @@ impl TopLevelComposer {
builtins: Vec<(StrRef, FunSignature, Arc<GenCall>)>,
) -> (Self, HashMap<StrRef, DefinitionId>, HashMap<StrRef, Type>) {
let mut primitives = Self::make_primitives();
let int32 = primitives.0.int32;
let int64 = primitives.0.int64;
let float = primitives.0.float;
let boolean = primitives.0.bool;
let range = primitives.0.range;
let string = primitives.0.str;
let num_ty = primitives.1.get_fresh_var_with_range(&[int32, int64, float, boolean]);
let var_map: HashMap<_, _> = vec![(num_ty.1, num_ty.0)].into_iter().collect();
let mut definition_ast_list = {
let top_level_def_list = vec![
Arc::new(RwLock::new(Self::make_top_level_class_def(
0,
None,
"int32".into(),
None,
))),
Arc::new(RwLock::new(Self::make_top_level_class_def(
1,
None,
"int64".into(),
None,
))),
Arc::new(RwLock::new(Self::make_top_level_class_def(
2,
None,
"float".into(),
None,
))),
Arc::new(RwLock::new(Self::make_top_level_class_def(3, None, "bool".into(), None))),
Arc::new(RwLock::new(Self::make_top_level_class_def(4, None, "none".into(), None))),
Arc::new(RwLock::new(Self::make_top_level_class_def(
5,
None,
"range".into(),
None,
))),
Arc::new(RwLock::new(Self::make_top_level_class_def(6, None, "str".into(), None))),
Arc::new(RwLock::new(TopLevelDef::Function {
name: "int32".into(),
simple_name: "int32".into(),
signature: primitives.1.add_ty(TypeEnum::TFunc(RefCell::new(FunSignature {
args: vec![FuncArg { name: "_".into(), ty: num_ty.0, default_value: None }],
ret: int32,
vars: var_map.clone(),
}))),
var_id: Default::default(),
instance_to_symbol: Default::default(),
instance_to_stmt: Default::default(),
resolver: None,
codegen_callback: Some(Arc::new(GenCall::new(Box::new(
|ctx, _, fun, args| {
let int32 = ctx.primitives.int32;
let int64 = ctx.primitives.int64;
let float = ctx.primitives.float;
let boolean = ctx.primitives.bool;
let arg_ty = fun.0.args[0].ty;
let arg = args[0].1;
if ctx.unifier.unioned(arg_ty, boolean) {
Some(
ctx.builder
.build_int_s_extend(
arg.into_int_value(),
ctx.ctx.i32_type(),
"sext",
)
.into(),
)
} else if ctx.unifier.unioned(arg_ty, int32) {
Some(arg)
} else if ctx.unifier.unioned(arg_ty, int64) {
Some(
ctx.builder
.build_int_truncate(
arg.into_int_value(),
ctx.ctx.i32_type(),
"trunc",
)
.into(),
)
} else if ctx.unifier.unioned(arg_ty, float) {
let val = ctx
.builder
.build_float_to_signed_int(
arg.into_float_value(),
ctx.ctx.i32_type(),
"fptosi",
)
.into();
Some(val)
} else {
unreachable!()
}
},
)))),
})),
Arc::new(RwLock::new(TopLevelDef::Function {
name: "int64".into(),
simple_name: "int64".into(),
signature: primitives.1.add_ty(TypeEnum::TFunc(RefCell::new(FunSignature {
args: vec![FuncArg { name: "_".into(), ty: num_ty.0, default_value: None }],
ret: int64,
vars: var_map.clone(),
}))),
var_id: Default::default(),
instance_to_symbol: Default::default(),
instance_to_stmt: Default::default(),
resolver: None,
codegen_callback: Some(Arc::new(GenCall::new(Box::new(
|ctx, _, fun, args| {
let int32 = ctx.primitives.int32;
let int64 = ctx.primitives.int64;
let float = ctx.primitives.float;
let boolean = ctx.primitives.bool;
let arg_ty = fun.0.args[0].ty;
let arg = args[0].1;
if ctx.unifier.unioned(arg_ty, boolean)
|| ctx.unifier.unioned(arg_ty, int32)
{
Some(
ctx.builder
.build_int_s_extend(
arg.into_int_value(),
ctx.ctx.i64_type(),
"sext",
)
.into(),
)
} else if ctx.unifier.unioned(arg_ty, int64) {
Some(arg)
} else if ctx.unifier.unioned(arg_ty, float) {
let val = ctx
.builder
.build_float_to_signed_int(
arg.into_float_value(),
ctx.ctx.i64_type(),
"fptosi",
)
.into();
Some(val)
} else {
unreachable!()
}
},
)))),
})),
Arc::new(RwLock::new(TopLevelDef::Function {
name: "float".into(),
simple_name: "float".into(),
signature: primitives.1.add_ty(TypeEnum::TFunc(RefCell::new(FunSignature {
args: vec![FuncArg { name: "_".into(), ty: num_ty.0, default_value: None }],
ret: float,
vars: var_map.clone(),
}))),
var_id: Default::default(),
instance_to_symbol: Default::default(),
instance_to_stmt: Default::default(),
resolver: None,
codegen_callback: Some(Arc::new(GenCall::new(Box::new(
|ctx, _, fun, args| {
let int32 = ctx.primitives.int32;
let int64 = ctx.primitives.int64;
let boolean = ctx.primitives.bool;
let float = ctx.primitives.float;
let arg_ty = fun.0.args[0].ty;
let arg = args[0].1;
if ctx.unifier.unioned(arg_ty, boolean)
|| ctx.unifier.unioned(arg_ty, int32)
|| ctx.unifier.unioned(arg_ty, int64)
{
let arg = args[0].1.into_int_value();
let val = ctx
.builder
.build_signed_int_to_float(arg, ctx.ctx.f64_type(), "sitofp")
.into();
Some(val)
} else if ctx.unifier.unioned(arg_ty, float) {
Some(arg)
} else {
unreachable!()
}
},
)))),
})),
Arc::new(RwLock::new(TopLevelDef::Function {
name: "round".into(),
simple_name: "round".into(),
signature: primitives.1.add_ty(TypeEnum::TFunc(RefCell::new(FunSignature {
args: vec![FuncArg { name: "_".into(), ty: float, default_value: None }],
ret: int32,
vars: Default::default(),
}))),
var_id: Default::default(),
instance_to_symbol: Default::default(),
instance_to_stmt: Default::default(),
resolver: None,
codegen_callback: Some(Arc::new(GenCall::new(Box::new(|ctx, _, _, args| {
let arg = args[0].1;
let round_intrinsic =
ctx.module.get_function("llvm.round.f64").unwrap_or_else(|| {
let float = ctx.ctx.f64_type();
let fn_type = float.fn_type(&[float.into()], false);
ctx.module.add_function("llvm.round.f64", fn_type, None)
});
let val = ctx
.builder
.build_call(round_intrinsic, &[arg], "round")
.try_as_basic_value()
.left()
.unwrap();
Some(
ctx.builder
.build_float_to_signed_int(
val.into_float_value(),
ctx.ctx.i32_type(),
"fptosi",
)
.into(),
)
})))),
})),
Arc::new(RwLock::new(TopLevelDef::Function {
name: "round64".into(),
simple_name: "round64".into(),
signature: primitives.1.add_ty(TypeEnum::TFunc(RefCell::new(FunSignature {
args: vec![FuncArg { name: "_".into(), ty: float, default_value: None }],
ret: int64,
vars: Default::default(),
}))),
var_id: Default::default(),
instance_to_symbol: Default::default(),
instance_to_stmt: Default::default(),
resolver: None,
codegen_callback: Some(Arc::new(GenCall::new(Box::new(|ctx, _, _, args| {
let arg = args[0].1;
let round_intrinsic =
ctx.module.get_function("llvm.round.f64").unwrap_or_else(|| {
let float = ctx.ctx.f64_type();
let fn_type = float.fn_type(&[float.into()], false);
ctx.module.add_function("llvm.round.f64", fn_type, None)
});
let val = ctx
.builder
.build_call(round_intrinsic, &[arg], "round")
.try_as_basic_value()
.left()
.unwrap();
Some(
ctx.builder
.build_float_to_signed_int(
val.into_float_value(),
ctx.ctx.i64_type(),
"fptosi",
)
.into(),
)
})))),
})),
Arc::new(RwLock::new(TopLevelDef::Function {
name: "range".into(),
simple_name: "range".into(),
signature: primitives.1.add_ty(TypeEnum::TFunc(RefCell::new(FunSignature {
args: vec![
FuncArg { name: "start".into(), ty: int32, default_value: None },
FuncArg {
name: "stop".into(),
ty: int32,
// placeholder
default_value: Some(SymbolValue::I32(0)),
},
FuncArg {
name: "step".into(),
ty: int32,
default_value: Some(SymbolValue::I32(1)),
},
],
ret: range,
vars: Default::default(),
}))),
var_id: Default::default(),
instance_to_symbol: Default::default(),
instance_to_stmt: Default::default(),
resolver: None,
codegen_callback: Some(Arc::new(GenCall::new(Box::new(|ctx, _, _, args| {
let mut start = None;
let mut stop = None;
let mut step = None;
let int32 = ctx.ctx.i32_type();
let zero = int32.const_zero();
for (i, arg) in args.iter().enumerate() {
if arg.0 == Some("start".into()) {
start = Some(arg.1);
} else if arg.0 == Some("stop".into()) {
stop = Some(arg.1);
} else if arg.0 == Some("step".into()) {
step = Some(arg.1);
} else if i == 0 {
start = Some(arg.1);
} else if i == 1 {
stop = Some(arg.1);
} else if i == 2 {
step = Some(arg.1);
}
}
// TODO: error when step == 0
let step = step.unwrap_or_else(|| int32.const_int(1, false).into());
let stop = stop.unwrap_or_else(|| {
let v = start.unwrap();
start = None;
v
});
let start = start.unwrap_or_else(|| int32.const_zero().into());
let ty = int32.array_type(3);
let ptr = ctx.builder.build_alloca(ty, "range");
unsafe {
let a = ctx.builder.build_in_bounds_gep(ptr, &[zero, zero], "start");
let b = ctx.builder.build_in_bounds_gep(
ptr,
&[zero, int32.const_int(1, false)],
"end",
);
let c = ctx.builder.build_in_bounds_gep(
ptr,
&[zero, int32.const_int(2, false)],
"step",
);
ctx.builder.build_store(a, start);
ctx.builder.build_store(b, stop);
ctx.builder.build_store(c, step);
}
Some(ptr.into())
})))),
})),
Arc::new(RwLock::new(TopLevelDef::Function {
name: "str".into(),
simple_name: "str".into(),
signature: primitives.1.add_ty(TypeEnum::TFunc(RefCell::new(FunSignature {
args: vec![FuncArg { name: "_".into(), ty: string, default_value: None }],
ret: string,
vars: Default::default(),
}))),
var_id: Default::default(),
instance_to_symbol: Default::default(),
instance_to_stmt: Default::default(),
resolver: None,
codegen_callback: Some(Arc::new(GenCall::new(Box::new(|_, _, _, args| {
Some(args[0].1)
})))),
})),
Arc::new(RwLock::new(TopLevelDef::Function {
name: "bool".into(),
simple_name: "bool".into(),
signature: primitives.1.add_ty(TypeEnum::TFunc(RefCell::new(FunSignature {
args: vec![FuncArg { name: "_".into(), ty: num_ty.0, default_value: None }],
ret: primitives.0.bool,
vars: var_map,
}))),
var_id: Default::default(),
instance_to_symbol: Default::default(),
instance_to_stmt: Default::default(),
resolver: None,
codegen_callback: Some(Arc::new(GenCall::new(Box::new(
|ctx, _, fun, args| {
let int32 = ctx.primitives.int32;
let int64 = ctx.primitives.int64;
let float = ctx.primitives.float;
let boolean = ctx.primitives.bool;
let arg_ty = fun.0.args[0].ty;
let arg = args[0].1;
if ctx.unifier.unioned(arg_ty, boolean) {
Some(arg)
} else if ctx.unifier.unioned(arg_ty, int32) {
Some(ctx.builder.build_int_compare(
IntPredicate::NE,
ctx.ctx.i32_type().const_zero(),
arg.into_int_value(),
"bool",
).into())
} else if ctx.unifier.unioned(arg_ty, int64) {
Some(ctx.builder.build_int_compare(
IntPredicate::NE,
ctx.ctx.i64_type().const_zero(),
arg.into_int_value(),
"bool",
).into())
} else if ctx.unifier.unioned(arg_ty, float) {
let val = ctx.builder.
build_float_compare(
// UEQ as bool(nan) is True
FloatPredicate::UEQ,
arg.into_float_value(),
ctx.ctx.f64_type().const_zero(),
"bool"
).into();
Some(val)
} else {
unreachable!()
}
},
)))),
})),
];
let ast_list: Vec<Option<ast::Stmt<()>>> =
(0..top_level_def_list.len()).map(|_| None).collect();
izip!(top_level_def_list, ast_list).collect_vec()
};
let (mut definition_ast_list, builtin_name_list) = builtins::get_built_ins(&mut primitives);
let primitives_ty = primitives.0;
let mut unifier = primitives.1;
let mut keyword_list: HashSet<StrRef> = HashSet::from_iter(vec![
@ -474,9 +66,7 @@ impl TopLevelComposer {
let mut built_in_id: HashMap<StrRef, DefinitionId> = Default::default();
let mut built_in_ty: HashMap<StrRef, Type> = Default::default();
for (id, name) in
["int32", "int64", "float", "round", "round64", "range", "str", "bool"].iter().rev().enumerate()
{
for (id, name) in builtin_name_list.iter().rev().enumerate() {
let name = (**name).into();
let id = definition_ast_list.len() - id - 1;
let def = definition_ast_list[id].0.read();

View File

@ -24,6 +24,7 @@ pub struct DefinitionId(pub usize);
pub mod composer;
pub mod helper;
pub mod builtins;
pub mod type_annotation;
use composer::*;
use type_annotation::*;