From 95c17b563cc07ddc52538d3fa9b2b022434be8f0 Mon Sep 17 00:00:00 2001 From: Devin Bidwell Date: Tue, 30 Dec 2025 23:34:14 -0700 Subject: [PATCH] More optimizer fixes --- .../libs/integration_tests/src/lib.rs | 7 + ...tion_tests__tests__function_with_call.snap | 2 +- ...ntegration_tests__tests__larre_script.snap | 214 ++++++++++++++++++ ...n_tests__tests__nested_function_calls.snap | 2 +- .../integration_tests__tests__tuples.snap | 8 +- .../src/test_files/test_larre_script.stlg | 72 ++++++ rust_compiler/libs/optimizer/src/dead_code.rs | 41 ++++ rust_compiler/libs/optimizer/src/lib.rs | 2 +- 8 files changed, 341 insertions(+), 7 deletions(-) create mode 100644 rust_compiler/libs/integration_tests/src/snapshots/integration_tests__tests__larre_script.snap create mode 100644 rust_compiler/libs/integration_tests/src/test_files/test_larre_script.stlg diff --git a/rust_compiler/libs/integration_tests/src/lib.rs b/rust_compiler/libs/integration_tests/src/lib.rs index 70d95ef..5d818ff 100644 --- a/rust_compiler/libs/integration_tests/src/lib.rs +++ b/rust_compiler/libs/integration_tests/src/lib.rs @@ -205,4 +205,11 @@ mod tests { let output = compile_with_and_without_optimization(source); insta::assert_snapshot!(output); } + + #[test] + fn test_larre_script() { + let source = include_str!("./test_files/test_larre_script.stlg"); + let output = compile_with_and_without_optimization(source); + insta::assert_snapshot!(output); + } } diff --git a/rust_compiler/libs/integration_tests/src/snapshots/integration_tests__tests__function_with_call.snap b/rust_compiler/libs/integration_tests/src/snapshots/integration_tests__tests__function_with_call.snap index 1c46e9c..17f740a 100644 --- a/rust_compiler/libs/integration_tests/src/snapshots/integration_tests__tests__function_with_call.snap +++ b/rust_compiler/libs/integration_tests/src/snapshots/integration_tests__tests__function_with_call.snap @@ -31,7 +31,7 @@ j ra ## Optimized Output -j 11 +j 10 pop r8 pop r9 push sp diff --git a/rust_compiler/libs/integration_tests/src/snapshots/integration_tests__tests__larre_script.snap b/rust_compiler/libs/integration_tests/src/snapshots/integration_tests__tests__larre_script.snap new file mode 100644 index 0000000..bac6c86 --- /dev/null +++ b/rust_compiler/libs/integration_tests/src/snapshots/integration_tests__tests__larre_script.snap @@ -0,0 +1,214 @@ +--- +source: libs/integration_tests/src/lib.rs +expression: output +--- +## Unoptimized Output + +j main +waitForIdle: +push sp +push ra +yield +__internal_L2: +l r1 d0 Idle +seq r2 r1 0 +beqz r2 __internal_L3 +yield +j __internal_L2 +__internal_L3: +__internal_L1: +pop ra +pop sp +j ra +deposit: +push sp +push ra +s d0 Setting 1 +jal waitForIdle +move r1 r15 +s d0 Activate 1 +jal waitForIdle +move r2 r15 +s d1 Open 0 +__internal_L4: +pop ra +pop sp +j ra +checkAndHarvest: +pop r8 +push sp +push ra +sle r1 r8 1 +ls r15 d0 255 Seeding +slt r2 r15 1 +or r3 r1 r2 +beqz r3 __internal_L6 +j __internal_L5 +__internal_L6: +__internal_L7: +ls r15 d0 255 Mature +beqz r15 __internal_L8 +yield +s d0 Activate 1 +j __internal_L7 +__internal_L8: +ls r15 d0 255 Occupied +move r9 r15 +s d0 Setting 1 +push r8 +push r9 +jal waitForIdle +pop r9 +pop r8 +move r4 r15 +push r8 +push r9 +jal deposit +pop r9 +pop r8 +move r5 r15 +beqz r9 __internal_L9 +push r8 +push r9 +jal deposit +pop r9 +pop r8 +move r6 r15 +__internal_L9: +s d0 Setting r8 +push r8 +push r9 +jal waitForIdle +pop r9 +pop r8 +move r6 r15 +ls r15 d0 0 Occupied +beqz r15 __internal_L10 +s d0 Activate 1 +__internal_L10: +push r8 +push r9 +jal waitForIdle +pop r9 +pop r8 +move r7 r15 +__internal_L5: +pop ra +pop sp +j ra +main: +move r8 0 +__internal_L11: +yield +l r1 d0 Idle +seq r2 r1 0 +beqz r2 __internal_L13 +j __internal_L11 +__internal_L13: +add r3 r8 1 +sgt r4 r3 19 +add r5 r8 1 +select r6 r4 2 r5 +move r9 r6 +push r8 +push r9 +push r8 +jal checkAndHarvest +pop r9 +pop r8 +move r7 r15 +s d0 Setting r9 +move r8 r9 +j __internal_L11 +__internal_L12: + +## Optimized Output + +j 71 +push sp +push ra +yield +l r1 d0 Idle +bne r1 0 8 +yield +j 4 +pop ra +pop sp +j ra +push sp +push ra +s d0 Setting 1 +jal 1 +s d0 Activate 1 +jal 1 +s d1 Open 0 +pop ra +pop sp +j ra +pop r8 +push sp +push ra +sle r1 r8 1 +ls r15 d0 255 Seeding +slt r2 r15 1 +or r3 r1 r2 +beqz r3 30 +j 68 +ls r15 d0 255 Mature +beqz r15 35 +yield +s d0 Activate 1 +j 30 +ls r15 d0 255 Occupied +move r9 r15 +s d0 Setting 1 +push r8 +push r9 +jal 1 +pop r9 +pop r8 +push r8 +push r9 +jal 11 +pop r9 +pop r8 +beqz r9 54 +push r8 +push r9 +jal 11 +pop r9 +pop r8 +s d0 Setting r8 +push r8 +push r9 +jal 1 +pop r9 +pop r8 +ls r15 d0 0 Occupied +beqz r15 63 +s d0 Activate 1 +push r8 +push r9 +jal 1 +pop r9 +pop r8 +pop ra +pop sp +j ra +yield +l r1 d0 Idle +bne r1 0 75 +j 71 +add r3 r8 1 +sgt r4 r3 19 +add r5 r8 1 +select r6 r4 2 r5 +move r9 r6 +push r8 +push r9 +push r8 +jal 21 +pop r9 +pop r8 +s d0 Setting r9 +j 71 diff --git a/rust_compiler/libs/integration_tests/src/snapshots/integration_tests__tests__nested_function_calls.snap b/rust_compiler/libs/integration_tests/src/snapshots/integration_tests__tests__nested_function_calls.snap index ec9b376..af05dbd 100644 --- a/rust_compiler/libs/integration_tests/src/snapshots/integration_tests__tests__nested_function_calls.snap +++ b/rust_compiler/libs/integration_tests/src/snapshots/integration_tests__tests__nested_function_calls.snap @@ -97,7 +97,7 @@ push r9 push r10 push r10 push 2 -jal 11 +jal 10 pop r10 pop r9 pop r8 diff --git a/rust_compiler/libs/integration_tests/src/snapshots/integration_tests__tests__tuples.snap b/rust_compiler/libs/integration_tests/src/snapshots/integration_tests__tests__tuples.snap index 1842e80..6f155fe 100644 --- a/rust_compiler/libs/integration_tests/src/snapshots/integration_tests__tests__tuples.snap +++ b/rust_compiler/libs/integration_tests/src/snapshots/integration_tests__tests__tuples.snap @@ -54,7 +54,7 @@ __internal_L4: ## Optimized Output -j 27 +j 25 pop r8 push sp push ra @@ -80,15 +80,15 @@ sub r0 sp 4 get ra db r0 j ra yield -jal 10 +jal 9 pop r0 pop r9 pop r8 move sp r15 -jal 10 +jal 9 pop r0 pop r0 pop r9 move sp r15 s db Setting r9 -j 27 +j 25 diff --git a/rust_compiler/libs/integration_tests/src/test_files/test_larre_script.stlg b/rust_compiler/libs/integration_tests/src/test_files/test_larre_script.stlg new file mode 100644 index 0000000..c17ea5c --- /dev/null +++ b/rust_compiler/libs/integration_tests/src/test_files/test_larre_script.stlg @@ -0,0 +1,72 @@ +/// Laree script V1 + +device self = "db"; +device larre = "d0"; +device exportChute = "d1"; + +const TOTAL_SLOTS = 19; +const EXPORT_CHUTE = 1; +const START_STATION = 2; + +let currentIndex = 0; + +/// Waits for the larre to be idle before continuing +fn waitForIdle() { + yield(); + while (!larre.Idle) { + yield(); + } +} + +/// Instructs the Larre to go to the chute and deposit +/// what is currently in its arm +fn deposit() { + larre.Setting = EXPORT_CHUTE; + waitForIdle(); + larre.Activate = true; + waitForIdle(); + exportChute.Open = false; +} + +/// This function is responsible for checking the plant under +/// the larre at this index, and harvesting if applicable +fn checkAndHarvest(currentIndex) { + if (currentIndex <= EXPORT_CHUTE || ls(larre, 255, "Seeding") < 1) { + return; + } + + // harvest from this device + while (ls(larre, 255, "Mature")) { + yield(); + larre.Activate = true; + } + let hasRemainingPlant = ls(larre, 255, "Occupied"); + + // move to the export chute + larre.Setting = EXPORT_CHUTE; + waitForIdle(); + deposit(); + if (hasRemainingPlant) { + deposit(); + } + + larre.Setting = currentIndex; + waitForIdle(); + + if (ls(larre, 0, "Occupied")) { + larre.Activate = true; + } + waitForIdle(); +} + +loop { + yield(); + if (!larre.Idle) { + continue; + } + let newIndex = currentIndex + 1 > TOTAL_SLOTS ? START_STATION : currentIndex + 1; + + checkAndHarvest(currentIndex); + larre.Setting = newIndex; + currentIndex = newIndex; +} \ No newline at end of file diff --git a/rust_compiler/libs/optimizer/src/dead_code.rs b/rust_compiler/libs/optimizer/src/dead_code.rs index ca5333b..b7dae22 100644 --- a/rust_compiler/libs/optimizer/src/dead_code.rs +++ b/rust_compiler/libs/optimizer/src/dead_code.rs @@ -46,12 +46,15 @@ pub fn remove_unreachable_code<'a>( /// Pass: Remove Redundant Jumps /// Removes jumps to the next instruction (after label resolution). /// Must run AFTER label resolution since it needs line numbers. +/// This pass also adjusts all jump targets to account for removed instructions. pub fn remove_redundant_jumps<'a>( input: Vec>, ) -> (Vec>, bool) { let mut output = Vec::with_capacity(input.len()); let mut changed = false; + let mut removed_lines = Vec::new(); + // First pass: identify redundant jumps for (i, node) in input.iter().enumerate() { // Check if this is a jump to the next line number if let Instruction::Jump(Operand::Number(target)) = &node.instruction { @@ -59,12 +62,50 @@ pub fn remove_redundant_jumps<'a>( // If jump target equals the next line, it's redundant if target.to_string().parse::().ok() == Some(i + 1) { changed = true; + removed_lines.push(i); continue; // Skip this redundant jump } } output.push(node.clone()); } + // Second pass: adjust all jump/branch targets to account for removed lines + if changed { + for node in &mut output { + // Helper to adjust a target line number + let adjust_target = |target_line: usize| -> usize { + // Count how many removed lines are before the target + let offset = removed_lines + .iter() + .filter(|&&removed| removed < target_line) + .count(); + target_line.saturating_sub(offset) + }; + + match &mut node.instruction { + Instruction::Jump(Operand::Number(target)) + | Instruction::JumpAndLink(Operand::Number(target)) => { + if let Ok(target_line) = target.to_string().parse::() { + *target = rust_decimal::Decimal::from(adjust_target(target_line)); + } + } + Instruction::BranchEq(_, _, Operand::Number(target)) + | Instruction::BranchNe(_, _, Operand::Number(target)) + | Instruction::BranchGt(_, _, Operand::Number(target)) + | Instruction::BranchLt(_, _, Operand::Number(target)) + | Instruction::BranchGe(_, _, Operand::Number(target)) + | Instruction::BranchLe(_, _, Operand::Number(target)) + | Instruction::BranchEqZero(_, Operand::Number(target)) + | Instruction::BranchNeZero(_, Operand::Number(target)) => { + if let Ok(target_line) = target.to_string().parse::() { + *target = rust_decimal::Decimal::from(adjust_target(target_line)); + } + } + _ => {} + } + } + } + (output, changed) } diff --git a/rust_compiler/libs/optimizer/src/lib.rs b/rust_compiler/libs/optimizer/src/lib.rs index d8144b7..fbb57fb 100644 --- a/rust_compiler/libs/optimizer/src/lib.rs +++ b/rust_compiler/libs/optimizer/src/lib.rs @@ -91,7 +91,7 @@ pub fn optimize<'a>(instructions: Instructions<'a>) -> Instructions<'a> { } // Final Pass: Resolve Labels to Line Numbers - let mut instructions = resolve_labels(instructions); + let instructions = resolve_labels(instructions); // Post-resolution Pass: Remove redundant jumps (must run after label resolution) let (instructions, _) = remove_redundant_jumps(instructions);