diff --git a/.github/workflows/compiler.yaml b/.github/workflows/compiler.yaml index 83828d830..0f360affc 100644 --- a/.github/workflows/compiler.yaml +++ b/.github/workflows/compiler.yaml @@ -136,6 +136,8 @@ jobs: benchmark: name: Benchmark runs-on: ubuntu-latest + # Benchmarks on pushes to main should run sequentially. + concurrency: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' && format('{0}-{1}-{2}', github.workflow, github.job, github.ref) || github.run_id }} steps: - uses: actions/checkout@v4 - uses: dsherret/rust-toolchain-file@v1 diff --git a/compiler/frontend/src/lib.rs b/compiler/frontend/src/lib.rs index 9f8bfd46c..b33946c6f 100644 --- a/compiler/frontend/src/lib.rs +++ b/compiler/frontend/src/lib.rs @@ -2,6 +2,7 @@ anonymous_lifetime_in_impl_trait, box_patterns, entry_insert, + extract_if, hasher_prefixfree_extras, io_error_more, let_chains, diff --git a/compiler/frontend/src/mir_optimize/constant_lifting.rs b/compiler/frontend/src/mir_optimize/constant_lifting.rs index 3b097d02e..dfd7ac87f 100644 --- a/compiler/frontend/src/mir_optimize/constant_lifting.rs +++ b/compiler/frontend/src/mir_optimize/constant_lifting.rs @@ -37,41 +37,47 @@ use super::current_expression::{Context, CurrentExpression}; use crate::mir::Expression; +use itertools::Itertools; pub fn lift_constants(context: &mut Context, expression: &mut CurrentExpression) { let Expression::Function { body, .. } = &mut **expression else { return; }; - let mut constants = vec![]; + let return_value = body.return_value(); + let mut new_return_reference_target = None; + let constants = body + .expressions + .extract_if(|(id, expression)| { + let id = *id; - let mut index = 0; - while index < body.expressions.len() { - let (id, expression) = &body.expressions[index]; - let id = *id; + if !context.pureness.is_definition_const(expression) { + return false; + } - if !context.pureness.is_definition_const(expression) { - index += 1; - continue; - } + let is_return_value = id == return_value; + if is_return_value && let Expression::Reference(_) = expression { + // Returned references shouldn't be lifted. If we would lift one, + // we'd have to add a reference anyway. + return false; + } - let is_return_value = id == body.return_value(); - if is_return_value && let Expression::Reference(_) = expression { - // Returned references shouldn't be lifted. If we would lift one, - // we'd have to add a reference anyway. - index += 1; - continue; - } + // This is a constant and should be lifted. - // This is a constant and should be lifted. + if is_return_value { + // The return value was removed. Add a reference to the lifted + // constant. + new_return_reference_target = Some(id); + } + true + }) + .collect_vec(); - constants.push(body.expressions.remove(index)); - - if is_return_value { - // The return value was removed. Add a reference to the lifted - // constant. - body.push(context.id_generator.generate(), Expression::Reference(id)); - } + if let Some(new_return_reference_target) = new_return_reference_target { + body.push( + context.id_generator.generate(), + Expression::Reference(new_return_reference_target), + ); } expression.prepend_optimized(context.visible, constants);