Added more optimizations in regards to function invocations and backing
up and restoring registers
This commit is contained in:
@@ -54,9 +54,7 @@ fn nested_binary_expressions() -> Result<()> {
|
||||
move r15 r2
|
||||
j __internal_L1
|
||||
__internal_L1:
|
||||
sub r0 sp 1
|
||||
get ra db r0
|
||||
sub sp sp 1
|
||||
pop ra
|
||||
j ra
|
||||
main:
|
||||
push 10
|
||||
|
||||
@@ -18,9 +18,7 @@ fn no_arguments() -> anyhow::Result<()> {
|
||||
doSomething:
|
||||
push ra
|
||||
__internal_L1:
|
||||
sub r0 sp 1
|
||||
get ra db r0
|
||||
sub sp sp 1
|
||||
pop ra
|
||||
j ra
|
||||
main:
|
||||
jal doSomething
|
||||
@@ -61,9 +59,7 @@ fn let_var_args() -> anyhow::Result<()> {
|
||||
move r15 r1
|
||||
j __internal_L1
|
||||
__internal_L1:
|
||||
sub r0 sp 1
|
||||
get ra db r0
|
||||
sub sp sp 1
|
||||
pop ra
|
||||
j ra
|
||||
main:
|
||||
__internal_L2:
|
||||
@@ -71,9 +67,7 @@ fn let_var_args() -> anyhow::Result<()> {
|
||||
push r8
|
||||
push r8
|
||||
jal mul2
|
||||
sub r0 sp 1
|
||||
get r8 db r0
|
||||
sub sp sp 1
|
||||
pop r8
|
||||
move r9 r15
|
||||
pow r1 r9 2
|
||||
move r9 r1
|
||||
@@ -129,9 +123,7 @@ fn inline_literal_args() -> anyhow::Result<()> {
|
||||
move r15 5
|
||||
j __internal_L1
|
||||
__internal_L1:
|
||||
sub r0 sp 1
|
||||
get ra db r0
|
||||
sub sp sp 1
|
||||
pop ra
|
||||
j ra
|
||||
main:
|
||||
move r8 123
|
||||
@@ -139,9 +131,7 @@ fn inline_literal_args() -> anyhow::Result<()> {
|
||||
push 12
|
||||
push 34
|
||||
jal doSomething
|
||||
sub r0 sp 1
|
||||
get r8 db r0
|
||||
sub sp sp 1
|
||||
pop r8
|
||||
move r9 r15
|
||||
"
|
||||
}
|
||||
@@ -171,9 +161,7 @@ fn mixed_args() -> anyhow::Result<()> {
|
||||
pop r9
|
||||
push ra
|
||||
__internal_L1:
|
||||
sub r0 sp 1
|
||||
get ra db r0
|
||||
sub sp sp 1
|
||||
pop ra
|
||||
j ra
|
||||
main:
|
||||
move r8 123
|
||||
@@ -181,9 +169,7 @@ fn mixed_args() -> anyhow::Result<()> {
|
||||
push r8
|
||||
push 456
|
||||
jal doSomething
|
||||
sub r0 sp 1
|
||||
get r8 db r0
|
||||
sub sp sp 1
|
||||
pop r8
|
||||
move r9 r15
|
||||
"
|
||||
}
|
||||
@@ -216,9 +202,7 @@ fn with_return_statement() -> anyhow::Result<()> {
|
||||
move r15 456
|
||||
j __internal_L1
|
||||
__internal_L1:
|
||||
sub r0 sp 1
|
||||
get ra db r0
|
||||
sub sp sp 1
|
||||
pop ra
|
||||
j ra
|
||||
main:
|
||||
push 123
|
||||
@@ -252,9 +236,7 @@ fn with_negative_return_literal() -> anyhow::Result<()> {
|
||||
push ra
|
||||
move r15 -1
|
||||
__internal_L1:
|
||||
sub r0 sp 1
|
||||
get ra db r0
|
||||
sub sp sp 1
|
||||
pop ra
|
||||
j ra
|
||||
main:
|
||||
jal doSomething
|
||||
|
||||
@@ -135,9 +135,7 @@ fn test_boolean_return() -> anyhow::Result<()> {
|
||||
move r15 1
|
||||
j __internal_L1
|
||||
__internal_L1:
|
||||
sub r0 sp 1
|
||||
get ra db r0
|
||||
sub sp sp 1
|
||||
pop ra
|
||||
j ra
|
||||
main:
|
||||
jal getTrue
|
||||
|
||||
@@ -5,7 +5,12 @@ use pretty_assertions::assert_eq;
|
||||
fn test_function_declaration_with_spillover_params() -> anyhow::Result<()> {
|
||||
let compiled = compile!(debug r#"
|
||||
// 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!(
|
||||
@@ -21,11 +26,39 @@ fn test_function_declaration_with_spillover_params() -> anyhow::Result<()> {
|
||||
pop r13
|
||||
pop r14
|
||||
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:
|
||||
sub r0 sp 1
|
||||
get ra db r0
|
||||
sub sp sp 3
|
||||
pop ra
|
||||
sub sp sp 2
|
||||
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
|
||||
j __internal_L1
|
||||
__internal_L1:
|
||||
sub r0 sp 1
|
||||
get ra db r0
|
||||
sub sp sp 1
|
||||
pop ra
|
||||
j ra
|
||||
main:
|
||||
jal doSomething
|
||||
@@ -91,9 +122,7 @@ fn test_function_declaration_with_register_params() -> anyhow::Result<()> {
|
||||
pop r9
|
||||
push ra
|
||||
__internal_L1:
|
||||
sub r0 sp 1
|
||||
get ra db r0
|
||||
sub sp sp 1
|
||||
pop ra
|
||||
j ra
|
||||
"}
|
||||
);
|
||||
|
||||
@@ -1115,43 +1115,26 @@ impl<'a> Compiler<'a> {
|
||||
Some(name.span),
|
||||
)?;
|
||||
|
||||
for register in active_registers {
|
||||
let VariableLocation::Stack(stack_offset) = stack
|
||||
.get_location_of(&Cow::from(format!("temp_{register}")), None)
|
||||
.map_err(Error::Scope)?
|
||||
else {
|
||||
// This shouldn't happen if we just added it
|
||||
return Err(Error::Unknown(
|
||||
format!("Failed to recover temp_{register}"),
|
||||
Some(name.span),
|
||||
));
|
||||
};
|
||||
// cleanup spilled temporary variables
|
||||
let total_stack_usage = stack.stack_offset();
|
||||
let saved_regs_count = active_registers.len() as u16;
|
||||
|
||||
if total_stack_usage > saved_regs_count {
|
||||
let spill_amount = total_stack_usage - saved_regs_count;
|
||||
self.write_instruction(
|
||||
Instruction::Sub(
|
||||
Operand::Register(VariableScope::TEMP_STACK_REGISTER),
|
||||
Operand::StackPointer,
|
||||
Operand::Number(stack_offset.into()),
|
||||
),
|
||||
Some(name.span),
|
||||
)?;
|
||||
|
||||
self.write_instruction(
|
||||
Instruction::Get(
|
||||
Operand::Register(register),
|
||||
Operand::Device(Cow::from("db")),
|
||||
Operand::Register(VariableScope::TEMP_STACK_REGISTER),
|
||||
Operand::StackPointer,
|
||||
Operand::Number(spill_amount.into()),
|
||||
),
|
||||
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(
|
||||
Instruction::Sub(
|
||||
Operand::StackPointer,
|
||||
Operand::StackPointer,
|
||||
Operand::Number(Decimal::from(stack.stack_offset())),
|
||||
),
|
||||
Instruction::Pop(Operand::Register(*register)),
|
||||
Some(name.span),
|
||||
)?;
|
||||
}
|
||||
@@ -2735,33 +2718,49 @@ impl<'a> Compiler<'a> {
|
||||
|
||||
self.write_instruction(Instruction::LabelDef(return_label.clone()), Some(span))?;
|
||||
|
||||
self.write_instruction(
|
||||
Instruction::Sub(
|
||||
Operand::Register(VariableScope::TEMP_STACK_REGISTER),
|
||||
Operand::StackPointer,
|
||||
Operand::Number(ra_stack_offset.into()),
|
||||
),
|
||||
Some(span),
|
||||
)?;
|
||||
if ra_stack_offset == 1 {
|
||||
self.write_instruction(Instruction::Pop(Operand::ReturnAddress), Some(span))?;
|
||||
|
||||
self.write_instruction(
|
||||
Instruction::Get(
|
||||
Operand::ReturnAddress,
|
||||
Operand::Device(Cow::from("db")),
|
||||
Operand::Register(VariableScope::TEMP_STACK_REGISTER),
|
||||
),
|
||||
Some(span),
|
||||
)?;
|
||||
|
||||
if block_scope.stack_offset() > 0 {
|
||||
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(
|
||||
Instruction::Sub(
|
||||
Operand::Register(VariableScope::TEMP_STACK_REGISTER),
|
||||
Operand::StackPointer,
|
||||
Operand::StackPointer,
|
||||
Operand::Number(block_scope.stack_offset().into()),
|
||||
Operand::Number(ra_stack_offset.into()),
|
||||
),
|
||||
Some(span),
|
||||
)?;
|
||||
|
||||
self.write_instruction(
|
||||
Instruction::Get(
|
||||
Operand::ReturnAddress,
|
||||
Operand::Device(Cow::from("db")),
|
||||
Operand::Register(VariableScope::TEMP_STACK_REGISTER),
|
||||
),
|
||||
Some(span),
|
||||
)?;
|
||||
|
||||
if block_scope.stack_offset() > 0 {
|
||||
self.write_instruction(
|
||||
Instruction::Sub(
|
||||
Operand::StackPointer,
|
||||
Operand::StackPointer,
|
||||
Operand::Number(block_scope.stack_offset().into()),
|
||||
),
|
||||
Some(span),
|
||||
)?;
|
||||
}
|
||||
}
|
||||
|
||||
self.write_instruction(Instruction::Jump(Operand::ReturnAddress), Some(span))?;
|
||||
|
||||
Reference in New Issue
Block a user