From cad3803a7e849f7063347a907fbb2c95c6883144 Mon Sep 17 00:00:00 2001 From: Richard Feldman Date: Sun, 23 Feb 2020 22:05:52 -0500 Subject: [PATCH 1/7] Add test for monomorphized Num.add --- tests/test_gen.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/test_gen.rs b/tests/test_gen.rs index 65e0009056..a1370e926b 100644 --- a/tests/test_gen.rs +++ b/tests/test_gen.rs @@ -612,6 +612,19 @@ mod test_gen { ); } + #[test] + fn gen_add_i64() { + assert_evals_to!( + indoc!( + r#" + 1 + 2 + "# + ), + 3, + i64 + ); + } + #[test] fn return_unnamed_fn() { assert_evals_to!( From d6383a6200d38c8e5efb76fade03f801f94b7710 Mon Sep 17 00:00:00 2001 From: Richard Feldman Date: Tue, 25 Feb 2020 23:20:51 -0500 Subject: [PATCH 2/7] Gen integer addition --- src/crane/build.rs | 47 ++++++++++++++++++++++++++++++++-------------- src/llvm/build.rs | 44 +++++++++++++++++++++++++++++++++---------- 2 files changed, 67 insertions(+), 24 deletions(-) diff --git a/src/crane/build.rs b/src/crane/build.rs index c50ee5f9f3..b3c8e09668 100644 --- a/src/crane/build.rs +++ b/src/crane/build.rs @@ -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,35 @@ 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, + builder: &mut FunctionBuilder, +) -> Value { + match symbol { + Symbol::NUM_ADD => { + debug_assert!(args.len() == 2); + builder.ins().iadd(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] + } + } +} diff --git a/src/llvm/build.rs b/src/llvm/build.rs index 1f6f2e139a..0376ae0421 100644 --- a/src/llvm/build.rs +++ b/src/llvm/build.rs @@ -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,36 @@ 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(), + "IADD", + ); + + 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)) + } + } +} From 46c7474d941d3d559af28a0afcac5ff47b29b291 Mon Sep 17 00:00:00 2001 From: Richard Feldman Date: Tue, 25 Feb 2020 23:27:57 -0500 Subject: [PATCH 3/7] Gen integer subtraction --- src/crane/build.rs | 4 ++++ src/llvm/build.rs | 13 ++++++++++++- tests/test_gen.rs | 17 +++++++++++++++-- 3 files changed, 31 insertions(+), 3 deletions(-) diff --git a/src/crane/build.rs b/src/crane/build.rs index b3c8e09668..6a4cb98372 100644 --- a/src/crane/build.rs +++ b/src/crane/build.rs @@ -518,6 +518,10 @@ fn call_with_args<'a, B: Backend>( 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]) + } _ => { let fn_id = match scope.get(&symbol) { Some(ScopeEntry::Func{ func_id, .. }) => *func_id, diff --git a/src/llvm/build.rs b/src/llvm/build.rs index 0376ae0421..913528b0b5 100644 --- a/src/llvm/build.rs +++ b/src/llvm/build.rs @@ -487,7 +487,18 @@ fn call_with_args<'a, 'ctx, 'env>( let int_val = env.builder.build_int_add( args[0].into_int_value(), args[1].into_int_value(), - "IADD", + "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) diff --git a/tests/test_gen.rs b/tests/test_gen.rs index a1370e926b..343646d917 100644 --- a/tests/test_gen.rs +++ b/tests/test_gen.rs @@ -617,10 +617,23 @@ mod test_gen { assert_evals_to!( indoc!( r#" - 1 + 2 + 1 + 2 + 3 "# ), - 3, + 6, + i64 + ); + } + + #[test] + fn gen_sub_i64() { + assert_evals_to!( + indoc!( + r#" + 1 - 2 - 3 + "# + ), + -4, i64 ); } From 8e7783e105db2f9a8e49aac1e9d10c3a6330286d Mon Sep 17 00:00:00 2001 From: Richard Feldman Date: Tue, 25 Feb 2020 23:27:27 -0500 Subject: [PATCH 4/7] Add a type for multiplication --- src/builtins.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/builtins.rs b/src/builtins.rs index c4d46155a7..87ad4f5bfa 100644 --- a/src/builtins.rs +++ b/src/builtins.rs @@ -208,6 +208,15 @@ pub fn types() -> MutMap { ), ); + // 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, From 71eacdabab71138afd919a7219158807de5a0d52 Mon Sep 17 00:00:00 2001 From: Richard Feldman Date: Tue, 25 Feb 2020 23:28:14 -0500 Subject: [PATCH 5/7] Gen integer multiplication --- src/crane/build.rs | 4 ++++ src/llvm/build.rs | 11 +++++++++++ tests/test_gen.rs | 13 +++++++++++++ 3 files changed, 28 insertions(+) diff --git a/src/crane/build.rs b/src/crane/build.rs index 6a4cb98372..07492f43fb 100644 --- a/src/crane/build.rs +++ b/src/crane/build.rs @@ -522,6 +522,10 @@ fn call_with_args<'a, B: Backend>( 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, diff --git a/src/llvm/build.rs b/src/llvm/build.rs index 913528b0b5..a91a8fb6f0 100644 --- a/src/llvm/build.rs +++ b/src/llvm/build.rs @@ -503,6 +503,17 @@ fn call_with_args<'a, 'ctx, 'env>( 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 diff --git a/tests/test_gen.rs b/tests/test_gen.rs index 343646d917..62e8b9bf22 100644 --- a/tests/test_gen.rs +++ b/tests/test_gen.rs @@ -638,6 +638,19 @@ mod test_gen { ); } + #[test] + fn gen_mul_i64() { + assert_evals_to!( + indoc!( + r#" + 2 * 4 * 6 + "# + ), + 48, + i64 + ); + } + #[test] fn return_unnamed_fn() { assert_evals_to!( From e90b8fd62f621b12d9b9ea98d8075543ebf1a8c7 Mon Sep 17 00:00:00 2001 From: Richard Feldman Date: Tue, 25 Feb 2020 23:28:29 -0500 Subject: [PATCH 6/7] Test gen order of operations arithmetic --- tests/test_gen.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/test_gen.rs b/tests/test_gen.rs index 62e8b9bf22..6e2ef64f3d 100644 --- a/tests/test_gen.rs +++ b/tests/test_gen.rs @@ -651,6 +651,19 @@ mod test_gen { ); } + #[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!( From 23899bfd5dbd487c46c96248143984f1a9288d28 Mon Sep 17 00:00:00 2001 From: Richard Feldman Date: Wed, 26 Feb 2020 19:43:51 -0500 Subject: [PATCH 7/7] Fix spurious test failures --- tests/test_uniqueness_infer.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/test_uniqueness_infer.rs b/tests/test_uniqueness_infer.rs index 02133c2d57..1ca4395034 100644 --- a/tests/test_uniqueness_infer.rs +++ b/tests/test_uniqueness_infer.rs @@ -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)" );