Added more optimizations in regards to function invocations and backing
up and restoring registers
This commit is contained in:
@@ -6,6 +6,9 @@
|
|||||||
- Shorthand is `lr`
|
- Shorthand is `lr`
|
||||||
- Longform is `loadReagent`
|
- Longform is `loadReagent`
|
||||||
- Update various Rust dependencies
|
- Update various Rust dependencies
|
||||||
|
- Added more optimizations, prioritizing `pop` instead of `get` when available
|
||||||
|
when backing up / restoring registers for function invocations. This should
|
||||||
|
save approximately 2 lines per backed up register
|
||||||
|
|
||||||
[0.3.3]
|
[0.3.3]
|
||||||
|
|
||||||
|
|||||||
@@ -54,9 +54,7 @@ fn nested_binary_expressions() -> Result<()> {
|
|||||||
move r15 r2
|
move r15 r2
|
||||||
j __internal_L1
|
j __internal_L1
|
||||||
__internal_L1:
|
__internal_L1:
|
||||||
sub r0 sp 1
|
pop ra
|
||||||
get ra db r0
|
|
||||||
sub sp sp 1
|
|
||||||
j ra
|
j ra
|
||||||
main:
|
main:
|
||||||
push 10
|
push 10
|
||||||
|
|||||||
@@ -18,9 +18,7 @@ fn no_arguments() -> anyhow::Result<()> {
|
|||||||
doSomething:
|
doSomething:
|
||||||
push ra
|
push ra
|
||||||
__internal_L1:
|
__internal_L1:
|
||||||
sub r0 sp 1
|
pop ra
|
||||||
get ra db r0
|
|
||||||
sub sp sp 1
|
|
||||||
j ra
|
j ra
|
||||||
main:
|
main:
|
||||||
jal doSomething
|
jal doSomething
|
||||||
@@ -61,9 +59,7 @@ fn let_var_args() -> anyhow::Result<()> {
|
|||||||
move r15 r1
|
move r15 r1
|
||||||
j __internal_L1
|
j __internal_L1
|
||||||
__internal_L1:
|
__internal_L1:
|
||||||
sub r0 sp 1
|
pop ra
|
||||||
get ra db r0
|
|
||||||
sub sp sp 1
|
|
||||||
j ra
|
j ra
|
||||||
main:
|
main:
|
||||||
__internal_L2:
|
__internal_L2:
|
||||||
@@ -71,9 +67,7 @@ fn let_var_args() -> anyhow::Result<()> {
|
|||||||
push r8
|
push r8
|
||||||
push r8
|
push r8
|
||||||
jal mul2
|
jal mul2
|
||||||
sub r0 sp 1
|
pop r8
|
||||||
get r8 db r0
|
|
||||||
sub sp sp 1
|
|
||||||
move r9 r15
|
move r9 r15
|
||||||
pow r1 r9 2
|
pow r1 r9 2
|
||||||
move r9 r1
|
move r9 r1
|
||||||
@@ -129,9 +123,7 @@ fn inline_literal_args() -> anyhow::Result<()> {
|
|||||||
move r15 5
|
move r15 5
|
||||||
j __internal_L1
|
j __internal_L1
|
||||||
__internal_L1:
|
__internal_L1:
|
||||||
sub r0 sp 1
|
pop ra
|
||||||
get ra db r0
|
|
||||||
sub sp sp 1
|
|
||||||
j ra
|
j ra
|
||||||
main:
|
main:
|
||||||
move r8 123
|
move r8 123
|
||||||
@@ -139,9 +131,7 @@ fn inline_literal_args() -> anyhow::Result<()> {
|
|||||||
push 12
|
push 12
|
||||||
push 34
|
push 34
|
||||||
jal doSomething
|
jal doSomething
|
||||||
sub r0 sp 1
|
pop r8
|
||||||
get r8 db r0
|
|
||||||
sub sp sp 1
|
|
||||||
move r9 r15
|
move r9 r15
|
||||||
"
|
"
|
||||||
}
|
}
|
||||||
@@ -171,9 +161,7 @@ fn mixed_args() -> anyhow::Result<()> {
|
|||||||
pop r9
|
pop r9
|
||||||
push ra
|
push ra
|
||||||
__internal_L1:
|
__internal_L1:
|
||||||
sub r0 sp 1
|
pop ra
|
||||||
get ra db r0
|
|
||||||
sub sp sp 1
|
|
||||||
j ra
|
j ra
|
||||||
main:
|
main:
|
||||||
move r8 123
|
move r8 123
|
||||||
@@ -181,9 +169,7 @@ fn mixed_args() -> anyhow::Result<()> {
|
|||||||
push r8
|
push r8
|
||||||
push 456
|
push 456
|
||||||
jal doSomething
|
jal doSomething
|
||||||
sub r0 sp 1
|
pop r8
|
||||||
get r8 db r0
|
|
||||||
sub sp sp 1
|
|
||||||
move r9 r15
|
move r9 r15
|
||||||
"
|
"
|
||||||
}
|
}
|
||||||
@@ -216,9 +202,7 @@ fn with_return_statement() -> anyhow::Result<()> {
|
|||||||
move r15 456
|
move r15 456
|
||||||
j __internal_L1
|
j __internal_L1
|
||||||
__internal_L1:
|
__internal_L1:
|
||||||
sub r0 sp 1
|
pop ra
|
||||||
get ra db r0
|
|
||||||
sub sp sp 1
|
|
||||||
j ra
|
j ra
|
||||||
main:
|
main:
|
||||||
push 123
|
push 123
|
||||||
@@ -252,9 +236,7 @@ fn with_negative_return_literal() -> anyhow::Result<()> {
|
|||||||
push ra
|
push ra
|
||||||
move r15 -1
|
move r15 -1
|
||||||
__internal_L1:
|
__internal_L1:
|
||||||
sub r0 sp 1
|
pop ra
|
||||||
get ra db r0
|
|
||||||
sub sp sp 1
|
|
||||||
j ra
|
j ra
|
||||||
main:
|
main:
|
||||||
jal doSomething
|
jal doSomething
|
||||||
|
|||||||
@@ -135,9 +135,7 @@ fn test_boolean_return() -> anyhow::Result<()> {
|
|||||||
move r15 1
|
move r15 1
|
||||||
j __internal_L1
|
j __internal_L1
|
||||||
__internal_L1:
|
__internal_L1:
|
||||||
sub r0 sp 1
|
pop ra
|
||||||
get ra db r0
|
|
||||||
sub sp sp 1
|
|
||||||
j ra
|
j ra
|
||||||
main:
|
main:
|
||||||
jal getTrue
|
jal getTrue
|
||||||
|
|||||||
@@ -5,7 +5,12 @@ use pretty_assertions::assert_eq;
|
|||||||
fn test_function_declaration_with_spillover_params() -> anyhow::Result<()> {
|
fn test_function_declaration_with_spillover_params() -> anyhow::Result<()> {
|
||||||
let compiled = compile!(debug r#"
|
let compiled = compile!(debug r#"
|
||||||
// we need more than 4 params to 'spill' into a stack var
|
// we need more than 4 params to 'spill' into a stack var
|
||||||
fn doSomething(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) {};
|
fn doSomething(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) {
|
||||||
|
return arg1 + arg2 + arg3 + arg4 + arg5 + arg6 + arg7 + arg8 + arg9;
|
||||||
|
};
|
||||||
|
|
||||||
|
let item1 = 1;
|
||||||
|
let returned = doSomething(item1, 2, 3, 4, 5, 6, 7, 8, 9);
|
||||||
"#);
|
"#);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@@ -21,11 +26,39 @@ fn test_function_declaration_with_spillover_params() -> anyhow::Result<()> {
|
|||||||
pop r13
|
pop r13
|
||||||
pop r14
|
pop r14
|
||||||
push ra
|
push ra
|
||||||
|
sub r0 sp 3
|
||||||
|
get r1 db r0
|
||||||
|
sub r0 sp 2
|
||||||
|
get r2 db r0
|
||||||
|
add r3 r1 r2
|
||||||
|
add r4 r3 r14
|
||||||
|
add r5 r4 r13
|
||||||
|
add r6 r5 r12
|
||||||
|
add r7 r6 r11
|
||||||
|
add r1 r7 r10
|
||||||
|
add r2 r1 r9
|
||||||
|
add r3 r2 r8
|
||||||
|
move r15 r3
|
||||||
|
j __internal_L1
|
||||||
__internal_L1:
|
__internal_L1:
|
||||||
sub r0 sp 1
|
pop ra
|
||||||
get ra db r0
|
sub sp sp 2
|
||||||
sub sp sp 3
|
|
||||||
j ra
|
j ra
|
||||||
|
main:
|
||||||
|
move r8 1
|
||||||
|
push r8
|
||||||
|
push r8
|
||||||
|
push 2
|
||||||
|
push 3
|
||||||
|
push 4
|
||||||
|
push 5
|
||||||
|
push 6
|
||||||
|
push 7
|
||||||
|
push 8
|
||||||
|
push 9
|
||||||
|
jal doSomething
|
||||||
|
pop r8
|
||||||
|
move r9 r15
|
||||||
"}
|
"}
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -60,9 +93,7 @@ fn test_early_return() -> anyhow::Result<()> {
|
|||||||
move r8 3
|
move r8 3
|
||||||
j __internal_L1
|
j __internal_L1
|
||||||
__internal_L1:
|
__internal_L1:
|
||||||
sub r0 sp 1
|
pop ra
|
||||||
get ra db r0
|
|
||||||
sub sp sp 1
|
|
||||||
j ra
|
j ra
|
||||||
main:
|
main:
|
||||||
jal doSomething
|
jal doSomething
|
||||||
@@ -91,9 +122,7 @@ fn test_function_declaration_with_register_params() -> anyhow::Result<()> {
|
|||||||
pop r9
|
pop r9
|
||||||
push ra
|
push ra
|
||||||
__internal_L1:
|
__internal_L1:
|
||||||
sub r0 sp 1
|
pop ra
|
||||||
get ra db r0
|
|
||||||
sub sp sp 1
|
|
||||||
j ra
|
j ra
|
||||||
"}
|
"}
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1115,43 +1115,26 @@ impl<'a> Compiler<'a> {
|
|||||||
Some(name.span),
|
Some(name.span),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
for register in active_registers {
|
// cleanup spilled temporary variables
|
||||||
let VariableLocation::Stack(stack_offset) = stack
|
let total_stack_usage = stack.stack_offset();
|
||||||
.get_location_of(&Cow::from(format!("temp_{register}")), None)
|
let saved_regs_count = active_registers.len() as u16;
|
||||||
.map_err(Error::Scope)?
|
|
||||||
else {
|
if total_stack_usage > saved_regs_count {
|
||||||
// This shouldn't happen if we just added it
|
let spill_amount = total_stack_usage - saved_regs_count;
|
||||||
return Err(Error::Unknown(
|
|
||||||
format!("Failed to recover temp_{register}"),
|
|
||||||
Some(name.span),
|
|
||||||
));
|
|
||||||
};
|
|
||||||
self.write_instruction(
|
self.write_instruction(
|
||||||
Instruction::Sub(
|
Instruction::Sub(
|
||||||
Operand::Register(VariableScope::TEMP_STACK_REGISTER),
|
|
||||||
Operand::StackPointer,
|
Operand::StackPointer,
|
||||||
Operand::Number(stack_offset.into()),
|
Operand::StackPointer,
|
||||||
),
|
Operand::Number(spill_amount.into()),
|
||||||
Some(name.span),
|
|
||||||
)?;
|
|
||||||
|
|
||||||
self.write_instruction(
|
|
||||||
Instruction::Get(
|
|
||||||
Operand::Register(register),
|
|
||||||
Operand::Device(Cow::from("db")),
|
|
||||||
Operand::Register(VariableScope::TEMP_STACK_REGISTER),
|
|
||||||
),
|
),
|
||||||
Some(name.span),
|
Some(name.span),
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if stack.stack_offset() > 0 {
|
// restore the registers in reverse order from the stack, now using `pop`
|
||||||
|
for register in active_registers.iter().rev() {
|
||||||
self.write_instruction(
|
self.write_instruction(
|
||||||
Instruction::Sub(
|
Instruction::Pop(Operand::Register(*register)),
|
||||||
Operand::StackPointer,
|
|
||||||
Operand::StackPointer,
|
|
||||||
Operand::Number(Decimal::from(stack.stack_offset())),
|
|
||||||
),
|
|
||||||
Some(name.span),
|
Some(name.span),
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
@@ -2735,6 +2718,21 @@ impl<'a> Compiler<'a> {
|
|||||||
|
|
||||||
self.write_instruction(Instruction::LabelDef(return_label.clone()), Some(span))?;
|
self.write_instruction(Instruction::LabelDef(return_label.clone()), Some(span))?;
|
||||||
|
|
||||||
|
if ra_stack_offset == 1 {
|
||||||
|
self.write_instruction(Instruction::Pop(Operand::ReturnAddress), Some(span))?;
|
||||||
|
|
||||||
|
let remaining_cleanup = block_scope.stack_offset() - 1;
|
||||||
|
if remaining_cleanup > 0 {
|
||||||
|
self.write_instruction(
|
||||||
|
Instruction::Sub(
|
||||||
|
Operand::StackPointer,
|
||||||
|
Operand::StackPointer,
|
||||||
|
Operand::Number(remaining_cleanup.into()),
|
||||||
|
),
|
||||||
|
Some(span),
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
self.write_instruction(
|
self.write_instruction(
|
||||||
Instruction::Sub(
|
Instruction::Sub(
|
||||||
Operand::Register(VariableScope::TEMP_STACK_REGISTER),
|
Operand::Register(VariableScope::TEMP_STACK_REGISTER),
|
||||||
@@ -2763,6 +2761,7 @@ impl<'a> Compiler<'a> {
|
|||||||
Some(span),
|
Some(span),
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
self.write_instruction(Instruction::Jump(Operand::ReturnAddress), Some(span))?;
|
self.write_instruction(Instruction::Jump(Operand::ReturnAddress), Some(span))?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@@ -661,6 +661,14 @@ fn reg_is_read(instr: &Instruction, reg: u8) -> bool {
|
|||||||
|
|
||||||
Instruction::BranchEqZero(a, _) | Instruction::BranchNeZero(a, _) => check(a),
|
Instruction::BranchEqZero(a, _) | Instruction::BranchNeZero(a, _) => check(a),
|
||||||
|
|
||||||
|
Instruction::LoadReagent(_, device, _, item_hash) => check(device) || check(item_hash),
|
||||||
|
|
||||||
|
Instruction::LoadSlot(_, dev, slot, _) => check(dev) || check(slot),
|
||||||
|
Instruction::LoadBatch(_, dev, _, mode) => check(dev) || check(mode),
|
||||||
|
Instruction::LoadBatchNamed(_, d_hash, n_hash, _, mode) => {
|
||||||
|
check(d_hash) || check(n_hash) || check(mode)
|
||||||
|
}
|
||||||
|
|
||||||
Instruction::SetEq(_, a, b)
|
Instruction::SetEq(_, a, b)
|
||||||
| Instruction::SetNe(_, a, b)
|
| Instruction::SetNe(_, a, b)
|
||||||
| Instruction::SetGt(_, a, b)
|
| Instruction::SetGt(_, a, b)
|
||||||
|
|||||||
Reference in New Issue
Block a user