Improve binary folding

This commit is contained in:
2026-01-01 15:57:35 -07:00
parent e3a38ec110
commit 647c3d29d5
4 changed files with 73 additions and 11 deletions

View File

@@ -391,6 +391,26 @@ impl<'a> Compiler<'a> {
} }
Expression::Ternary(tern) => Ok(Some(self.expression_ternary(tern.node, scope)?)), Expression::Ternary(tern) => Ok(Some(self.expression_ternary(tern.node, scope)?)),
Expression::Invocation(expr_invoke) => { Expression::Invocation(expr_invoke) => {
// Special case: hash() with string literal can be evaluated at compile time
if expr_invoke.node.name.node == "hash" && expr_invoke.node.arguments.len() == 1 {
if let Expression::Literal(Spanned {
node: Literal::String(str_to_hash),
..
}) = &expr_invoke.node.arguments[0].node
{
// Evaluate hash at compile time
let hash_value = crc_hash_signed(str_to_hash);
return Ok(Some(CompileLocation {
location: VariableLocation::Constant(Literal::Number(Number::Integer(
hash_value,
Unit::None,
))),
temp_name: None,
}));
}
}
// Non-constant hash calls or other function calls
self.expression_function_invocation(expr_invoke, scope)?; self.expression_function_invocation(expr_invoke, scope)?;
// Invocation returns result in r15 (RETURN_REGISTER). // Invocation returns result in r15 (RETURN_REGISTER).
// If used as an expression, we must move it to a temp to avoid overwrite. // If used as an expression, we must move it to a temp to avoid overwrite.
@@ -2359,7 +2379,19 @@ impl<'a> Compiler<'a> {
// 4. Handle Binary Ops: Recurse BOTH sides, then combine // 4. Handle Binary Ops: Recurse BOTH sides, then combine
Expression::Binary(bin) => fold_binary_expression(&bin.node), Expression::Binary(bin) => fold_binary_expression(&bin.node),
// 5. Handle hash() macro - evaluates to a constant at compile time // 5. Handle hash() syscall - evaluates to a constant at compile time
Expression::Syscall(Spanned {
node:
SysCall::System(System::Hash(Spanned {
node: Literal::String(str_to_hash),
..
})),
..
}) => {
return Some(Number::Integer(crc_hash_signed(str_to_hash), Unit::None));
}
// 6. Handle hash() macro as invocation - evaluates to a constant at compile time
Expression::Invocation(inv) => { Expression::Invocation(inv) => {
if inv.node.name.node == "hash" && inv.node.arguments.len() == 1 { if inv.node.name.node == "hash" && inv.node.arguments.len() == 1 {
if let Expression::Literal(Spanned { if let Expression::Literal(Spanned {
@@ -2374,7 +2406,7 @@ impl<'a> Compiler<'a> {
None None
} }
// 6. Anything else cannot be compile-time folded // 7. Anything else cannot be compile-time folded
_ => None, _ => None,
} }
} }

View File

@@ -74,4 +74,20 @@ mod bitwise_tests {
let output = compile_with_and_without_optimization(source); let output = compile_with_and_without_optimization(source);
insta::assert_snapshot!(output); insta::assert_snapshot!(output);
} }
#[test]
fn test_sorter_bitwise_operations() {
let source = indoc! {r#"
device self = "db";
device sorter = "d0";
loop {
yield();
// allow Hay with an op_code of `1`
sorter[0] = (hash("ItemCropHay") << 8) | 1;
}
"#};
let output = compile_with_and_without_optimization(source);
insta::assert_snapshot!(output);
}
} }

View File

@@ -0,0 +1,20 @@
---
source: libs/integration_tests/src/bitwise_tests.rs
assertion_line: 91
expression: output
---
## Unoptimized Output
j main
main:
__internal_L1:
yield
put d0 0 55164456193
j __internal_L1
__internal_L2:
## Optimized Output
yield
put d0 0 55164456193
j 0

View File

@@ -7,19 +7,13 @@ expression: output
j main j main
main: main:
sll r1 -952768015 16 move r8 -62440604628430
or r2 r1 2560
or r3 r2 50
move r8 r3
put d0 255 r8 put d0 255 r8
get r4 d0 255 get r1 d0 255
move r9 r4 move r9 r1
## Optimized Output ## Optimized Output
move r1 -62440604631040
move r2 -62440604628480
move r3 -62440604628430
move r8 -62440604628430 move r8 -62440604628430
put d0 255 r8 put d0 255 r8
get r9 d0 255 get r9 d0 255