From 83fb7aedc6e0bdfcab163c7cd1c7069df4d29ce7 Mon Sep 17 00:00:00 2001 From: Jonas Wanke Date: Thu, 4 Apr 2024 22:55:37 +0200 Subject: [PATCH 1/6] Set CLI crate as default workspace member --- Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/Cargo.toml b/Cargo.toml index 1d8eebcb3..d1daf2c89 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,6 +11,7 @@ members = [ "compiler/vm", "compiler/vm/fuzz", ] +default-members = ["compiler/cli"] [workspace.package] edition = "2021" From e51df220fd18f03a2d4eb2d2a5831843b5477a4c Mon Sep 17 00:00:00 2001 From: Jonas Wanke Date: Thu, 18 Apr 2024 14:21:19 +0200 Subject: [PATCH 2/6] Rename result.also to .inspect Inspired by Rust: https://doc.rust-lang.org/std/option/enum.Option.html#method.inspect --- packages/Core/result.candy | 3 +-- packages/FileSystem/file.candy | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/Core/result.candy b/packages/Core/result.candy index 396a8ca0b..a6ff3050b 100644 --- a/packages/Core/result.candy +++ b/packages/Core/result.candy @@ -77,8 +77,7 @@ and resultA resultB := needs (is resultB) resultA | flatMap { value -> resultB } -# TODO: find a better name -also result okSideEffect := +inspect result okSideEffect := needs (is result) needs (function.is1 okSideEffect) result % diff --git a/packages/FileSystem/file.candy b/packages/FileSystem/file.candy index e4614a757..95611458e 100644 --- a/packages/FileSystem/file.candy +++ b/packages/FileSystem/file.candy @@ -10,11 +10,11 @@ readBytes fileSystemFile path := needs (text.is path) path | fileSystemFile.open - | result.also { file -> needs (function.is0 file) } + | result.inspect { file -> needs (function.is0 file) } | result.flatMap { file -> file | fileSystemFile.readToEnd | result.map { bytes -> [file, bytes] } } - | result.also { [bytes] -> + | result.inspect { [bytes] -> needs (list.is bytes) needs (bytes | iterator.fromList | iterator.all { byte -> int.isUnsignedByte byte }) } From 52b6f95bc9c4f38d7a150dd388924acb01130a91 Mon Sep 17 00:00:00 2001 From: Jonas Wanke Date: Thu, 18 Apr 2024 14:42:51 +0200 Subject: [PATCH 3/6] Inline recursive calls --- .../src/mir_optimize/current_expression.rs | 3 ++- .../frontend/src/mir_optimize/inlining.rs | 27 +++++++++++++++++++ compiler/frontend/src/mir_optimize/mod.rs | 2 ++ 3 files changed, 31 insertions(+), 1 deletion(-) diff --git a/compiler/frontend/src/mir_optimize/current_expression.rs b/compiler/frontend/src/mir_optimize/current_expression.rs index 9c3dbc291..e82b62170 100644 --- a/compiler/frontend/src/mir_optimize/current_expression.rs +++ b/compiler/frontend/src/mir_optimize/current_expression.rs @@ -1,4 +1,4 @@ -use super::{pure::PurenessInsights, OptimizeMir}; +use super::{inlining::InliningState, pure::PurenessInsights, OptimizeMir}; use crate::{ error::CompilerError, id::IdGenerator, @@ -16,6 +16,7 @@ pub struct Context<'a> { pub visible: &'a mut VisibleExpressions, pub id_generator: &'a mut IdGenerator, pub pureness: &'a mut PurenessInsights, + pub inlining_state: InliningState, } pub struct CurrentExpression<'a> { diff --git a/compiler/frontend/src/mir_optimize/inlining.rs b/compiler/frontend/src/mir_optimize/inlining.rs index 29a1e9bd6..fb02160b2 100644 --- a/compiler/frontend/src/mir_optimize/inlining.rs +++ b/compiler/frontend/src/mir_optimize/inlining.rs @@ -44,6 +44,7 @@ use crate::{ mir::{Expression, Id}, }; use rustc_hash::FxHashMap; +use std::{collections::hash_map::Entry, num::NonZeroUsize}; const NAME: &str = "Inlining"; @@ -113,6 +114,16 @@ pub fn inline_calls_with_constant_arguments( } } +#[derive(Clone, Debug, Default)] +pub struct InliningState { + recursive_inlining_counts: FxHashMap, +} +impl InliningState { + /// To avoid infinite recursion, we limit the number of times a function can + /// be inlined into itself in a single module. + const MAX_RECURSION_INLINING_COUNT_IN_MODULE: usize = 32; +} + impl Context<'_> { fn inline_call(&mut self, expression: &mut CurrentExpression) { let Expression::Call { @@ -126,6 +137,22 @@ impl Context<'_> { }; if arguments.contains(function) { // Callee is used as an argument → recursion + match self + .inlining_state + .recursive_inlining_counts + .entry(*function) + { + Entry::Occupied(mut entry) => { + let count = entry.get_mut(); + if count.get() >= InliningState::MAX_RECURSION_INLINING_COUNT_IN_MODULE { + return; + } + *count = count.saturating_add(1); + } + Entry::Vacant(entry) => { + entry.insert(NonZeroUsize::new(1).unwrap()); + } + } return; } diff --git a/compiler/frontend/src/mir_optimize/mod.rs b/compiler/frontend/src/mir_optimize/mod.rs index 518ac0aa5..a3b194d81 100644 --- a/compiler/frontend/src/mir_optimize/mod.rs +++ b/compiler/frontend/src/mir_optimize/mod.rs @@ -44,6 +44,7 @@ use self::{ current_expression::{Context, CurrentExpression}, + inlining::InliningState, log::OptimizationLogger, pure::PurenessInsights, }; @@ -155,6 +156,7 @@ impl Mir { visible: &mut VisibleExpressions::none_visible(), id_generator: &mut self.id_generator, pureness, + inlining_state: InliningState::default(), }; context.optimize_body(&mut self.body); if cfg!(debug_assertions) { From 1cd08b461e50dc5bb3c5f30cc2e290121d6d568b Mon Sep 17 00:00:00 2001 From: Jonas Wanke Date: Thu, 18 Apr 2024 14:52:47 +0200 Subject: [PATCH 4/6] Actually inline recursive calls --- compiler/frontend/src/mir_optimize/inlining.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/compiler/frontend/src/mir_optimize/inlining.rs b/compiler/frontend/src/mir_optimize/inlining.rs index fb02160b2..fb92236b3 100644 --- a/compiler/frontend/src/mir_optimize/inlining.rs +++ b/compiler/frontend/src/mir_optimize/inlining.rs @@ -153,7 +153,6 @@ impl Context<'_> { entry.insert(NonZeroUsize::new(1).unwrap()); } } - return; } let Expression::Function { From 9270689fb2e68034b454e23292a2ccc0c3cf915b Mon Sep 17 00:00:00 2001 From: Jonas Wanke Date: Thu, 18 Apr 2024 15:28:57 +0200 Subject: [PATCH 5/6] Reduce recursive inlining to 5 times --- compiler/frontend/src/mir_optimize/inlining.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/frontend/src/mir_optimize/inlining.rs b/compiler/frontend/src/mir_optimize/inlining.rs index fb92236b3..c010061e1 100644 --- a/compiler/frontend/src/mir_optimize/inlining.rs +++ b/compiler/frontend/src/mir_optimize/inlining.rs @@ -121,7 +121,7 @@ pub struct InliningState { impl InliningState { /// To avoid infinite recursion, we limit the number of times a function can /// be inlined into itself in a single module. - const MAX_RECURSION_INLINING_COUNT_IN_MODULE: usize = 32; + const MAX_RECURSION_INLINING_COUNT_IN_MODULE: usize = 5; } impl Context<'_> { From 15c63930cdc60a1a528a4ae0f09b1a20f0c22743 Mon Sep 17 00:00:00 2001 From: Jonas Wanke Date: Thu, 18 Apr 2024 16:15:26 +0200 Subject: [PATCH 6/6] Reduce recursive inlining to 1 time --- compiler/frontend/src/mir_optimize/inlining.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/frontend/src/mir_optimize/inlining.rs b/compiler/frontend/src/mir_optimize/inlining.rs index c010061e1..683fe40dd 100644 --- a/compiler/frontend/src/mir_optimize/inlining.rs +++ b/compiler/frontend/src/mir_optimize/inlining.rs @@ -121,7 +121,7 @@ pub struct InliningState { impl InliningState { /// To avoid infinite recursion, we limit the number of times a function can /// be inlined into itself in a single module. - const MAX_RECURSION_INLINING_COUNT_IN_MODULE: usize = 5; + const MAX_RECURSION_INLINING_COUNT_IN_MODULE: usize = 1; } impl Context<'_> {