diff --git a/compiler/gen/src/llvm/build.rs b/compiler/gen/src/llvm/build.rs index 229ac0ffc6..0f211333f8 100644 --- a/compiler/gen/src/llvm/build.rs +++ b/compiler/gen/src/llvm/build.rs @@ -348,7 +348,6 @@ pub fn build_expr<'a, 'ctx, 'env>( .left() .unwrap_or_else(|| panic!("LLVM error: Invalid call by pointer.")) } - LoadWithoutIncrement(_symbol) => todo!("implement load without increment"), Load(symbol) => load_symbol(env, scope, symbol), Str(str_literal) => { if str_literal.is_empty() { @@ -655,6 +654,31 @@ pub fn build_expr<'a, 'ctx, 'env>( } RunLowLevel(op, args) => run_low_level(env, layout_ids, scope, parent, *op, args), + Inc(symbol, expr) => { + match scope.get(symbol) { + None => panic!("There was no entry for {:?} in scope {:?}", symbol, scope), + Some((layout, ptr)) => { + match layout { + Layout::Builtin(Builtin::List(Ownership::Owned, _elem_layout)) => { + let load = env + .builder + .build_load(*ptr, symbol.ident_string(&env.interns)); + + let wrapper_struct = env + .builder + .build_load(*ptr, symbol.ident_string(&env.interns)) + .into_struct_value(); + + increment_refcount_list(env, wrapper_struct, load) + } + _ => { + // not refcounted, do nothing special + build_expr(env, layout_ids, scope, parent, expr) + } + } + } + } + } DecAfter(symbol, expr) => { match scope.get(symbol) { None => panic!("There was no entry for {:?} in scope {:?}", symbol, scope), @@ -817,23 +841,9 @@ fn load_symbol<'a, 'ctx, 'env>( symbol: &Symbol, ) -> BasicValueEnum<'ctx> { match scope.get(symbol) { - Some((layout, ptr)) => match layout { - Layout::Builtin(Builtin::List(Ownership::Owned, _)) => { - let load = env - .builder - .build_load(*ptr, symbol.ident_string(&env.interns)); - - let wrapper_struct = env - .builder - .build_load(*ptr, symbol.ident_string(&env.interns)) - .into_struct_value(); - - increment_refcount_list(env, wrapper_struct, load) - } - _ => env - .builder - .build_load(*ptr, symbol.ident_string(&env.interns)), - }, + Some((_, ptr)) => env + .builder + .build_load(*ptr, symbol.ident_string(&env.interns)), None => panic!("There was no entry for {:?} in scope {:?}", symbol, scope), } } diff --git a/compiler/mono/src/expr.rs b/compiler/mono/src/expr.rs index 68e1fe979a..c3974c2b07 100644 --- a/compiler/mono/src/expr.rs +++ b/compiler/mono/src/expr.rs @@ -322,7 +322,7 @@ pub enum Expr<'a> { Store(&'a [(Symbol, Layout<'a>, Expr<'a>)], &'a Expr<'a>), /// RC instructions - LoadWithoutIncrement(Symbol), + Inc(Symbol, &'a Expr<'a>), DecAfter(Symbol, &'a Expr<'a>), // Functions diff --git a/compiler/mono/src/reset_reuse.rs b/compiler/mono/src/reset_reuse.rs index c5eb356916..8315e70755 100644 --- a/compiler/mono/src/reset_reuse.rs +++ b/compiler/mono/src/reset_reuse.rs @@ -156,7 +156,7 @@ pub fn function_r<'a>(env: &mut Env<'a, '_>, body: &'a Expr<'a>) -> Expr<'a> { | Byte(_) | Load(_) | EmptyArray - | LoadWithoutIncrement(_) + | Inc(_, _) | FunctionPointer(_, _) | RuntimeError(_) | RuntimeErrorFunction(_) => body.clone(), @@ -334,7 +334,7 @@ fn function_s<'a>( | Byte(_) | Load(_) | EmptyArray - | LoadWithoutIncrement(_) + | Inc(_, _) | FunctionPointer(_, _) | RuntimeError(_) | RuntimeErrorFunction(_) => Err(body), @@ -352,7 +352,7 @@ fn symbols_in_expr<'a>(initial: &Expr<'a>) -> MutSet { while let Some(expr) = stack.pop() { match expr { - FunctionPointer(symbol, _) | LoadWithoutIncrement(symbol) | Load(symbol) => { + FunctionPointer(symbol, _) | Load(symbol) => { result.insert(*symbol); } @@ -417,7 +417,7 @@ fn symbols_in_expr<'a>(initial: &Expr<'a>) -> MutSet { stack.push(body) } - DecAfter(symbol, body) => { + DecAfter(symbol, body) | Inc(symbol, body) => { result.insert(*symbol); stack.push(body); } diff --git a/compiler/mono/tests/test_mono.rs b/compiler/mono/tests/test_mono.rs index f40cc05a13..6c25255f67 100644 --- a/compiler/mono/tests/test_mono.rs +++ b/compiler/mono/tests/test_mono.rs @@ -1027,4 +1027,52 @@ mod test_mono { ), ) } + + #[test] + fn is_nil() { + compiles_to_string( + r#" + isNil = \xs -> + when xs is + Nil -> True + Cons _ _ -> False + + isNil Nil + "#, + indoc!( + r#" + procedure Test.0 (Test.2): + Store Test.2: Load Test.2 + Store Test.3: Lowlevel.And (Lowlevel.Eq true (Load Test.2)) true + if Test.3 then + true + else + false + Dec Test.2 + + Call Test.0 true + "# + ), + ) + } + + #[test] + fn y_is_dead() { + compiles_to_string( + r#" + f = \y -> Pair y y + + f [1] + "#, + indoc!( + r#" + procedure Test.0 (Test.2): + Struct [(Load(`Test.y`), Builtin(List(Owned, Builtin(Int64)))), (Load(`Test.y`), Builtin(List(Owned, Builtin(Int64))))] + Dec Test.2 + + Call Test.0 [ 1i64 ] + "# + ), + ) + } }