From 76c5df5dc25d9a8b8f324433cb414c2ccb78cf53 Mon Sep 17 00:00:00 2001 From: Devin Bidwell Date: Thu, 1 Jan 2026 14:00:10 -0700 Subject: [PATCH] Bitwise folding with hash() as well --- rust_compiler/libs/compiler/src/v1.rs | 31 ++++- .../src/device_indexing_tests.rs | 107 ++++++++++++++++++ .../libs/integration_tests/src/lib.rs | 2 + ...ts__bitwise_tests__bitwise_operations.snap | 9 +- ..._tests__bitwise_tests__bitwise_shifts.snap | 12 +- ...s__device_indexing_complex_expression.snap | 54 +++++++++ ...indexing_optimization_folds_constants.snap | 25 ++++ ..._device_indexing_with_binary_literals.snap | 25 ++++ ...__device_indexing_with_computed_index.snap | 27 +++++ ...ndexing_with_hash_and_binary_literals.snap | 34 ++++++ .../optimizer/src/constant_propagation.rs | 57 ++++++++++ 11 files changed, 368 insertions(+), 15 deletions(-) create mode 100644 rust_compiler/libs/integration_tests/src/device_indexing_tests.rs create mode 100644 rust_compiler/libs/integration_tests/src/snapshots/integration_tests__device_indexing_tests__device_indexing_tests__device_indexing_complex_expression.snap create mode 100644 rust_compiler/libs/integration_tests/src/snapshots/integration_tests__device_indexing_tests__device_indexing_tests__device_indexing_optimization_folds_constants.snap create mode 100644 rust_compiler/libs/integration_tests/src/snapshots/integration_tests__device_indexing_tests__device_indexing_tests__device_indexing_with_binary_literals.snap create mode 100644 rust_compiler/libs/integration_tests/src/snapshots/integration_tests__device_indexing_tests__device_indexing_tests__device_indexing_with_computed_index.snap create mode 100644 rust_compiler/libs/integration_tests/src/snapshots/integration_tests__device_indexing_tests__device_indexing_tests__device_indexing_with_hash_and_binary_literals.snap diff --git a/rust_compiler/libs/compiler/src/v1.rs b/rust_compiler/libs/compiler/src/v1.rs index 49c1bbb..d137146 100644 --- a/rust_compiler/libs/compiler/src/v1.rs +++ b/rust_compiler/libs/compiler/src/v1.rs @@ -67,6 +67,9 @@ pub enum Error<'a> { #[error("Expected a {0}-tuple, but you're trying to destructure into {1} variables")] TupleSizeMismatch(usize, usize, Span), + #[error("{0}")] + OperationNotSupported(String, Span), + #[error("{0}")] Unknown(String, Option), } @@ -89,7 +92,8 @@ impl<'a> From> for lsp_types::Diagnostic { | ConstAssignment(_, span) | DeviceAssignment(_, span) | AgrumentMismatch(_, span) - | TupleSizeMismatch(_, _, span) => Diagnostic { + | TupleSizeMismatch(_, _, span) + | OperationNotSupported(_, span) => Diagnostic { range: span.into(), message: value.to_string(), severity: Some(DiagnosticSeverity::ERROR), @@ -497,9 +501,9 @@ impl<'a> Compiler<'a> { // Check if device is "db" (not allowed) if let Operand::Device(ref dev_str) = device { if dev_str.as_ref() == "db" { - return Err(Error::Unknown( + return Err(Error::OperationNotSupported( "Direct stack access on 'db' is not yet supported".to_string(), - Some(expr.span), + expr.span, )); } } @@ -1152,9 +1156,9 @@ impl<'a> Compiler<'a> { // Check if device is "db" (not allowed) if let Operand::Device(ref dev_str) = device { if dev_str.as_ref() == "db" { - return Err(Error::Unknown( + return Err(Error::OperationNotSupported( "Direct stack access on 'db' is not yet supported".to_string(), - Some(assignee.span), + assignee.span, )); } } @@ -2355,7 +2359,22 @@ impl<'a> Compiler<'a> { // 4. Handle Binary Ops: Recurse BOTH sides, then combine Expression::Binary(bin) => fold_binary_expression(&bin.node), - // 5. Anything else (Variables, Function Calls) cannot be compile-time folded + // 5. Handle hash() macro - evaluates to a constant at compile time + Expression::Invocation(inv) => { + if inv.node.name.node == "hash" && inv.node.arguments.len() == 1 { + if let Expression::Literal(Spanned { + node: Literal::String(str_to_hash), + .. + }) = &inv.node.arguments[0].node + { + // hash() takes a string literal and returns a signed integer + return Some(Number::Integer(crc_hash_signed(str_to_hash), Unit::None)); + } + } + None + } + + // 6. Anything else cannot be compile-time folded _ => None, } } diff --git a/rust_compiler/libs/integration_tests/src/device_indexing_tests.rs b/rust_compiler/libs/integration_tests/src/device_indexing_tests.rs new file mode 100644 index 0000000..378b63e --- /dev/null +++ b/rust_compiler/libs/integration_tests/src/device_indexing_tests.rs @@ -0,0 +1,107 @@ +#[cfg(test)] +mod device_indexing_tests { + use crate::common::compile_with_and_without_optimization; + use indoc::indoc; + + #[test] + fn test_device_indexing_with_hash_and_binary_literals() { + let source = indoc! {" + device printer = \"d0\"; + + let item_type = hash(\"ItemIronIngot\"); + let quality = 16; + let quantity = 7; + + // Pack into a single value using bitwise operations + // Format: (itemHash << 16) | (quality << 8) | quantity + let packed = (item_type << 16) | (quality << 8) | quantity; + + // Write to device stack at address 255 + let addr = 255; + printer[addr] = packed; + + // Read it back + let result = printer[addr]; + "}; + let output = compile_with_and_without_optimization(source); + insta::assert_snapshot!(output); + } + + #[test] + fn test_device_indexing_with_computed_index() { + let source = indoc! {" + device storage = \"d1\"; + + let base_addr = 10; + let offset = 5; + let index = base_addr + offset; + + let value = 42; + storage[index] = value; + + let retrieved = storage[index]; + "}; + let output = compile_with_and_without_optimization(source); + insta::assert_snapshot!(output); + } + + #[test] + fn test_device_indexing_with_binary_literals() { + let source = indoc! {" + device mem = \"d0\"; + + // Binary literals for bitwise operations + let flags = 0b1010_0101; + let mask = 0b1111_0000; + let masked = flags & mask; + + // Write to device + mem[0] = masked; + + // Read back + let read_value = mem[0]; + "}; + let output = compile_with_and_without_optimization(source); + insta::assert_snapshot!(output); + } + + #[test] + fn test_device_indexing_complex_expression() { + let source = indoc! {" + device db = \"d0\"; + + let item = hash(\"ItemCopper\"); + let quality = 5; + let quantity = 100; + + // Complex bitwise expression + let packed = (item << 16) | ((quality & 0xFF) << 8) | (quantity & 0xFF); + + // Index with computed address + let slot = 1; + let address = slot * 256 + 100; + db[address] = packed; + + // Read back with different computation + let read_addr = (slot + 0) * 256 + 100; + let stored_value = db[read_addr]; + "}; + let output = compile_with_and_without_optimization(source); + insta::assert_snapshot!(output); + } + + #[test] + fn test_device_indexing_optimization_folds_constants() { + let source = indoc! {" + device cache = \"d0\"; + + // This should optimize to a single constant + let packed_constant = (hash(\"ItemSilver\") << 16) | (10 << 8) | 50; + + cache[255] = packed_constant; + let result = cache[255]; + "}; + let output = compile_with_and_without_optimization(source); + insta::assert_snapshot!(output); + } +} diff --git a/rust_compiler/libs/integration_tests/src/lib.rs b/rust_compiler/libs/integration_tests/src/lib.rs index 0f24065..5b58111 100644 --- a/rust_compiler/libs/integration_tests/src/lib.rs +++ b/rust_compiler/libs/integration_tests/src/lib.rs @@ -8,6 +8,8 @@ mod bitwise_tests; #[cfg(test)] mod common; #[cfg(test)] +mod device_indexing_tests; +#[cfg(test)] mod function_tests; #[cfg(test)] mod number_literal_tests; diff --git a/rust_compiler/libs/integration_tests/src/snapshots/integration_tests__bitwise_tests__bitwise_tests__bitwise_operations.snap b/rust_compiler/libs/integration_tests/src/snapshots/integration_tests__bitwise_tests__bitwise_tests__bitwise_operations.snap index 042f486..597b6bd 100644 --- a/rust_compiler/libs/integration_tests/src/snapshots/integration_tests__bitwise_tests__bitwise_tests__bitwise_operations.snap +++ b/rust_compiler/libs/integration_tests/src/snapshots/integration_tests__bitwise_tests__bitwise_tests__bitwise_operations.snap @@ -22,8 +22,11 @@ move r13 r4 move r8 5 move r9 3 -and r10 r8 r9 -or r11 r8 r9 -xor r12 r8 r9 +move r1 1 +move r10 1 +move r2 7 +move r11 7 +move r3 6 +move r12 6 not r4 r8 move r13 r4 diff --git a/rust_compiler/libs/integration_tests/src/snapshots/integration_tests__bitwise_tests__bitwise_tests__bitwise_shifts.snap b/rust_compiler/libs/integration_tests/src/snapshots/integration_tests__bitwise_tests__bitwise_tests__bitwise_shifts.snap index 56bd8aa..bd3d19f 100644 --- a/rust_compiler/libs/integration_tests/src/snapshots/integration_tests__bitwise_tests__bitwise_tests__bitwise_shifts.snap +++ b/rust_compiler/libs/integration_tests/src/snapshots/integration_tests__bitwise_tests__bitwise_tests__bitwise_shifts.snap @@ -18,9 +18,9 @@ move r11 r3 ## Optimized Output move r8 8 -sll r1 r8 2 -move r9 r1 -sra r2 r8 1 -move r10 r2 -srl r3 r8 1 -move r11 r3 +move r1 32 +move r9 32 +move r2 4 +move r10 4 +move r3 4 +move r11 4 diff --git a/rust_compiler/libs/integration_tests/src/snapshots/integration_tests__device_indexing_tests__device_indexing_tests__device_indexing_complex_expression.snap b/rust_compiler/libs/integration_tests/src/snapshots/integration_tests__device_indexing_tests__device_indexing_tests__device_indexing_complex_expression.snap new file mode 100644 index 0000000..b9ef518 --- /dev/null +++ b/rust_compiler/libs/integration_tests/src/snapshots/integration_tests__device_indexing_tests__device_indexing_tests__device_indexing_complex_expression.snap @@ -0,0 +1,54 @@ +--- +source: libs/integration_tests/src/device_indexing_tests.rs +assertion_line: 90 +expression: output +--- +## Unoptimized Output + +j main +main: +move r8 r15 +move r9 5 +move r10 100 +sll r1 r8 16 +and r2 r9 255 +sll r3 r2 8 +or r4 r1 r3 +and r5 r10 255 +or r6 r4 r5 +move r11 r6 +move r12 1 +mul r7 r12 256 +add r2 r7 100 +move r13 r2 +put d0 r13 r11 +add r1 r12 0 +mul r3 r1 256 +add r4 r3 100 +move r14 r4 +get r5 d0 r14 +push r5 +sub sp sp 1 + +## Optimized Output + +move r8 r15 +move r9 5 +move r10 100 +sll r1 r8 16 +move r3 1280 +or r4 r1 r3 +move r5 100 +or r11 r4 r5 +move r12 1 +move r7 256 +move r2 356 +move r13 356 +put d0 r13 r11 +move r1 1 +move r3 256 +move r4 356 +move r14 356 +get r5 d0 r14 +push r5 +sub sp sp 1 diff --git a/rust_compiler/libs/integration_tests/src/snapshots/integration_tests__device_indexing_tests__device_indexing_tests__device_indexing_optimization_folds_constants.snap b/rust_compiler/libs/integration_tests/src/snapshots/integration_tests__device_indexing_tests__device_indexing_tests__device_indexing_optimization_folds_constants.snap new file mode 100644 index 0000000..59c0e72 --- /dev/null +++ b/rust_compiler/libs/integration_tests/src/snapshots/integration_tests__device_indexing_tests__device_indexing_tests__device_indexing_optimization_folds_constants.snap @@ -0,0 +1,25 @@ +--- +source: libs/integration_tests/src/device_indexing_tests.rs +assertion_line: 105 +expression: output +--- +## Unoptimized Output + +j main +main: +sll r1 -952768015 16 +or r2 r1 2560 +or r3 r2 50 +move r8 r3 +put d0 255 r8 +get r4 d0 255 +move r9 r4 + +## Optimized Output + +move r1 -62440604631040 +move r2 -62440604628480 +move r3 -62440604628430 +move r8 -62440604628430 +put d0 255 r8 +get r9 d0 255 diff --git a/rust_compiler/libs/integration_tests/src/snapshots/integration_tests__device_indexing_tests__device_indexing_tests__device_indexing_with_binary_literals.snap b/rust_compiler/libs/integration_tests/src/snapshots/integration_tests__device_indexing_tests__device_indexing_tests__device_indexing_with_binary_literals.snap new file mode 100644 index 0000000..f7ce277 --- /dev/null +++ b/rust_compiler/libs/integration_tests/src/snapshots/integration_tests__device_indexing_tests__device_indexing_tests__device_indexing_with_binary_literals.snap @@ -0,0 +1,25 @@ +--- +source: libs/integration_tests/src/device_indexing_tests.rs +assertion_line: 65 +expression: output +--- +## Unoptimized Output + +j main +main: +move r8 165 +move r9 240 +and r1 r8 r9 +move r10 r1 +put d0 0 r10 +get r2 d0 0 +move r11 r2 + +## Optimized Output + +move r8 165 +move r9 240 +move r1 160 +move r10 160 +put d0 0 r10 +get r11 d0 0 diff --git a/rust_compiler/libs/integration_tests/src/snapshots/integration_tests__device_indexing_tests__device_indexing_tests__device_indexing_with_computed_index.snap b/rust_compiler/libs/integration_tests/src/snapshots/integration_tests__device_indexing_tests__device_indexing_tests__device_indexing_with_computed_index.snap new file mode 100644 index 0000000..839f776 --- /dev/null +++ b/rust_compiler/libs/integration_tests/src/snapshots/integration_tests__device_indexing_tests__device_indexing_tests__device_indexing_with_computed_index.snap @@ -0,0 +1,27 @@ +--- +source: libs/integration_tests/src/device_indexing_tests.rs +assertion_line: 45 +expression: output +--- +## Unoptimized Output + +j main +main: +move r8 10 +move r9 5 +add r1 r8 r9 +move r10 r1 +move r11 42 +put d1 r10 r11 +get r2 d1 r10 +move r12 r2 + +## Optimized Output + +move r8 10 +move r9 5 +move r1 15 +move r10 15 +move r11 42 +put d1 r10 r11 +get r12 d1 r10 diff --git a/rust_compiler/libs/integration_tests/src/snapshots/integration_tests__device_indexing_tests__device_indexing_tests__device_indexing_with_hash_and_binary_literals.snap b/rust_compiler/libs/integration_tests/src/snapshots/integration_tests__device_indexing_tests__device_indexing_tests__device_indexing_with_hash_and_binary_literals.snap new file mode 100644 index 0000000..a7829b6 --- /dev/null +++ b/rust_compiler/libs/integration_tests/src/snapshots/integration_tests__device_indexing_tests__device_indexing_tests__device_indexing_with_hash_and_binary_literals.snap @@ -0,0 +1,34 @@ +--- +source: libs/integration_tests/src/device_indexing_tests.rs +assertion_line: 27 +expression: output +--- +## Unoptimized Output + +j main +main: +move r8 r15 +move r9 16 +move r10 7 +sll r1 r8 16 +sll r2 r9 8 +or r3 r1 r2 +or r4 r3 r10 +move r11 r4 +move r12 255 +put d0 r12 r11 +get r5 d0 r12 +move r13 r5 + +## Optimized Output + +move r8 r15 +move r9 16 +move r10 7 +sll r1 r8 16 +move r2 4096 +or r3 r1 r2 +or r11 r3 r10 +move r12 255 +put d0 r12 r11 +get r13 d0 r12 diff --git a/rust_compiler/libs/optimizer/src/constant_propagation.rs b/rust_compiler/libs/optimizer/src/constant_propagation.rs index c9fb9cd..8e6d6a0 100644 --- a/rust_compiler/libs/optimizer/src/constant_propagation.rs +++ b/rust_compiler/libs/optimizer/src/constant_propagation.rs @@ -31,6 +31,26 @@ pub fn constant_propagation<'a>( Instruction::Mod(dst, a, b) => try_fold_math(dst, a, b, ®isters, |x, y| { if y.is_zero() { Decimal::ZERO } else { x % y } }), + Instruction::And(dst, a, b) => try_fold_bitwise(dst, a, b, ®isters, |x, y| x & y), + Instruction::Or(dst, a, b) => try_fold_bitwise(dst, a, b, ®isters, |x, y| x | y), + Instruction::Xor(dst, a, b) => try_fold_bitwise(dst, a, b, ®isters, |x, y| x ^ y), + Instruction::Sll(dst, a, b) => try_fold_bitwise(dst, a, b, ®isters, |x, y| { + if y >= 64 { 0 } else { x << y as u32 } + }), + Instruction::Sra(dst, a, b) => try_fold_bitwise(dst, a, b, ®isters, |x, y| { + if y >= 64 { + (if x < 0 { -1 } else { 0 }) + } else { + x >> y as u32 + } + }), + Instruction::Srl(dst, a, b) => try_fold_bitwise(dst, a, b, ®isters, |x, y| { + if y >= 64 { + 0 + } else { + (x as u64 >> y as u32) as i64 + } + }), Instruction::BranchEq(a, b, l) => { try_resolve_branch(a, b, l, ®isters, |x, y| x == y) } @@ -110,6 +130,43 @@ where )) } +fn decimal_to_i64(d: Decimal) -> i64 { + // Convert decimal to i64, truncating if needed + if let Ok(int_val) = d.try_into() { + int_val + } else { + // For very large or very small values, use a default + if d.is_sign_negative() { + i64::MIN + } else { + i64::MAX + } + } +} + +fn i64_to_decimal(i: i64) -> Decimal { + Decimal::from(i) +} + +fn try_fold_bitwise<'a, F>( + dst: &Operand<'a>, + a: &Operand<'a>, + b: &Operand<'a>, + regs: &[Option; 16], + op: F, +) -> Option> +where + F: Fn(i64, i64) -> i64, +{ + let val_a = resolve_value(a, regs)?; + let val_b = resolve_value(b, regs)?; + let result = op(decimal_to_i64(val_a), decimal_to_i64(val_b)); + Some(Instruction::Move( + dst.clone(), + Operand::Number(i64_to_decimal(result)), + )) +} + fn try_resolve_branch<'a, F>( a: &Operand<'a>, b: &Operand<'a>,