mirror of
https://github.com/roc-lang/roc.git
synced 2024-09-22 08:17:40 +03:00
Merge pull request #203 from rtfeldman/mono
Code gen integer addition, subtraction, and multiplication
This commit is contained in:
commit
2fbfdf2b72
@ -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,
|
||||
|
@ -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]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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!(
|
||||
|
@ -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) ]*)",
|
||||
);
|
||||
}
|
||||
|
||||
@ -1341,7 +1341,7 @@ mod test_infer_uniq {
|
||||
r.tic.tac.toe
|
||||
"#
|
||||
),
|
||||
"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 (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 (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)"
|
||||
);
|
||||
|
Loading…
Reference in New Issue
Block a user