Merge remote-tracking branch 'origin/trunk' into unique-builtins

This commit is contained in:
Folkert 2020-02-28 00:33:43 +01:00
commit 4ee248ffac
5 changed files with 165 additions and 29 deletions

View File

@ -208,6 +208,15 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
),
);
// mul or (*) : Num a, Num a -> Num a
add_type(
Symbol::NUM_MUL,
SolvedType::Func(
vec![num_type(flex(TVAR1)), num_type(flex(TVAR1))],
Box::new(num_type(flex(TVAR1))),
),
);
// abs : Num a -> Num a
add_type(
Symbol::NUM_ABS,

View File

@ -132,20 +132,7 @@ pub fn build_expr<'a, B: Backend>(
arg_vals.push(build_expr(env, scope, module, builder, arg, procs));
}
let fn_id = match scope.get(symbol) {
Some(ScopeEntry::Func{ func_id, .. }) => *func_id,
other => panic!(
"CallByName could not find function named {:?} in scope; instead, found {:?} in scope {:?}",
symbol, other, scope
),
};
let local_func = module.declare_func_in_func(fn_id, &mut builder.func);
let call = builder.ins().call(local_func, &arg_vals);
let results = builder.inst_results(call);
debug_assert!(results.len() == 1);
results[0]
call_with_args(*symbol, arg_vals.into_bump_slice(), scope, module, builder)
}
FunctionPointer(ref name) => {
let fn_id = match scope.get(name) {
@ -517,3 +504,43 @@ pub fn define_proc_body<'a, B: Backend>(
module.clear_context(ctx);
}
#[inline(always)]
fn call_with_args<'a, B: Backend>(
symbol: Symbol,
args: &'a [Value],
scope: &Scope,
module: &mut Module<B>,
builder: &mut FunctionBuilder,
) -> Value {
match symbol {
Symbol::NUM_ADD => {
debug_assert!(args.len() == 2);
builder.ins().iadd(args[0], args[1])
}
Symbol::NUM_SUB => {
debug_assert!(args.len() == 2);
builder.ins().isub(args[0], args[1])
}
Symbol::NUM_MUL => {
debug_assert!(args.len() == 2);
builder.ins().imul(args[0], args[1])
}
_ => {
let fn_id = match scope.get(&symbol) {
Some(ScopeEntry::Func{ func_id, .. }) => *func_id,
other => panic!(
"CallByName could not find function named {:?} in scope; instead, found {:?} in scope {:?}",
symbol, other, scope
),
};
let local_func = module.declare_func_in_func(fn_id, &mut builder.func);
let call = builder.ins().call(local_func, args);
let results = builder.inst_results(call);
debug_assert!(results.len() == 1);
results[0]
}
}
}

View File

@ -137,16 +137,7 @@ pub fn build_expr<'a, 'ctx, 'env>(
arg_vals.push(build_expr(env, scope, parent, arg, procs));
}
let fn_val = env
.module
.get_function(symbol.ident_string(&env.interns))
.unwrap_or_else(|| panic!("Unrecognized function: {:?}", symbol));
let call = env.builder.build_call(fn_val, arg_vals.as_slice(), "tmp");
call.try_as_basic_value().left().unwrap_or_else(|| {
panic!("LLVM error: Invalid call by name for name {:?}", symbol)
})
call_with_args(*symbol, arg_vals.into_bump_slice(), env)
}
},
FunctionPointer(ref symbol) => {
@ -482,3 +473,58 @@ pub fn verify_fn(fn_val: FunctionValue<'_>) {
panic!("Invalid generated fn_val.")
}
}
#[inline(always)]
fn call_with_args<'a, 'ctx, 'env>(
symbol: Symbol,
args: &[BasicValueEnum<'ctx>],
env: &Env<'a, 'ctx, 'env>,
) -> BasicValueEnum<'ctx> {
match symbol {
Symbol::NUM_ADD => {
debug_assert!(args.len() == 2);
let int_val = env.builder.build_int_add(
args[0].into_int_value(),
args[1].into_int_value(),
"ADD_I64",
);
BasicValueEnum::IntValue(int_val)
}
Symbol::NUM_SUB => {
debug_assert!(args.len() == 2);
let int_val = env.builder.build_int_sub(
args[0].into_int_value(),
args[1].into_int_value(),
"SUB_I64",
);
BasicValueEnum::IntValue(int_val)
}
Symbol::NUM_MUL => {
debug_assert!(args.len() == 2);
let int_val = env.builder.build_int_mul(
args[0].into_int_value(),
args[1].into_int_value(),
"MUL_I64",
);
BasicValueEnum::IntValue(int_val)
}
_ => {
let fn_val = env
.module
.get_function(symbol.ident_string(&env.interns))
.unwrap_or_else(|| panic!("Unrecognized function: {:?}", symbol));
let call = env.builder.build_call(fn_val, args, "tmp");
call.try_as_basic_value()
.left()
.unwrap_or_else(|| panic!("LLVM error: Invalid call by name for name {:?}", symbol))
}
}
}

View File

@ -612,6 +612,58 @@ mod test_gen {
);
}
#[test]
fn gen_add_i64() {
assert_evals_to!(
indoc!(
r#"
1 + 2 + 3
"#
),
6,
i64
);
}
#[test]
fn gen_sub_i64() {
assert_evals_to!(
indoc!(
r#"
1 - 2 - 3
"#
),
-4,
i64
);
}
#[test]
fn gen_mul_i64() {
assert_evals_to!(
indoc!(
r#"
2 * 4 * 6
"#
),
48,
i64
);
}
#[test]
fn gen_order_of_arithmetic_ops() {
assert_evals_to!(
indoc!(
r#"
1 + 3 * 7 - 2
"#
),
20,
i64
);
}
#[test]
fn return_unnamed_fn() {
assert_evals_to!(

View File

@ -1024,7 +1024,7 @@ mod test_infer_uniq {
\{ left, right } -> { left, right }
"#
),
"Attr * (Attr (* | a | b) { left : (Attr b c), right : (Attr a d) }* -> Attr * { left : (Attr b c), right : (Attr a d) })",
"Attr * (Attr (* | a | b) { left : (Attr a c), right : (Attr b d) }* -> Attr * { left : (Attr a c), right : (Attr b d) })",
);
}
@ -1066,7 +1066,7 @@ mod test_infer_uniq {
// TODO: is it safe to ignore uniqueness constraints from patterns that bind no identifiers?
// i.e. the `b` could be ignored in this example, is that true in general?
// seems like it because we don't really extract anything.
"Attr * (Attr (* | a | b) [ Foo (Attr a c) (Attr b *) ]* -> Attr * [ Foo (Attr a c) (Attr * Str) ]*)",
"Attr * (Attr (* | a | b) [ Foo (Attr b c) (Attr a *) ]* -> Attr * [ Foo (Attr b c) (Attr * Str) ]*)",
);
}
@ -1289,7 +1289,7 @@ mod test_infer_uniq {
r
"#
),
"Attr * (Attr (a | b) { foo : (Attr a { bar : (Attr Shared d), baz : (Attr Shared c) }e) }f -> Attr (a | b) { foo : (Attr a { bar : (Attr Shared d), baz : (Attr Shared c) }e) }f)"
"Attr * (Attr (a | b) { foo : (Attr b { bar : (Attr Shared d), baz : (Attr Shared c) }e) }f -> Attr (a | b) { foo : (Attr b { bar : (Attr Shared d), baz : (Attr Shared c) }e) }f)"
);
}
@ -1307,7 +1307,7 @@ mod test_infer_uniq {
r
"#
),
"Attr * (Attr (a | b) { foo : (Attr a { bar : (Attr Shared c) }d) }e -> Attr (a | b) { foo : (Attr a { bar : (Attr Shared c) }d) }e)"
"Attr * (Attr (a | b) { foo : (Attr b { bar : (Attr Shared c) }d) }e -> Attr (a | b) { foo : (Attr b { bar : (Attr Shared c) }d) }e)"
);
}
@ -1342,7 +1342,9 @@ mod test_infer_uniq {
r.tic.tac.toe
"#
),
"Attr * (Attr (* | a | b | c | d | e) { foo : (Attr (b | d | e) { bar : (Attr (b | d) { baz : (Attr b f) }*) }*), tic : (Attr (a | b | c) { tac : (Attr (b | c) { toe : (Attr b f) }*) }*) }* -> Attr b f)"
"Attr * (Attr (* | a | b | c | d | e) { foo : (Attr (b | c | d) { bar : (Attr (c | d) { baz : (Attr d f) }*) }*), tic : (Attr (a | d | e) { tac : (Attr (d | e) { toe : (Attr d f) }*) }*) }* -> Attr d f)"
// "Attr * (Attr (* | a | b | c | d | e) { foo : (Attr (c | d | e) { bar : (Attr (c | d) { baz : (Attr c f) }*) }*), tic : (Attr (a | b | c) { tac : (Attr (a | c) { toe : (Attr c f) }*) }*) }* -> Attr c f)"
// "Attr * (Attr (* | a | b | c | d | e) { foo : (Attr (b | d | e) { bar : (Attr (b | d) { baz : (Attr b f) }*) }*), tic : (Attr (a | b | c) { tac : (Attr (b | c) { toe : (Attr b f) }*) }*) }* -> Attr b f)"
// "Attr * (Attr (* | a | b | c | d | e) { foo : (Attr (b | c | e) { bar : (Attr (b | e) { baz : (Attr b f) }*) }*), tic : (Attr (a | b | d) { tac : (Attr (b | d) { toe : (Attr b f) }*) }*) }* -> Attr b f)"
// "Attr * (Attr (* | a | b | c | d | e) { foo : (Attr (a | c | d) { bar : (Attr (a | c) { baz : (Attr c f) }*) }*), tic : (Attr (b | c | e) { tac : (Attr (c | e) { toe : (Attr c f) }*) }*) }* -> Attr c f)"
// "Attr * (Attr (* | a | b | c | d | e) { foo : (Attr (a | c | d) { bar : (Attr (c | d) { baz : (Attr d f) }*) }*), tic : (Attr (b | d | e) { tac : (Attr (b | d) { toe : (Attr d f) }*) }*) }* -> Attr d f)"