0.5.0 -- tuples and more optimizations #12
@@ -59,6 +59,7 @@ fn nested_binary_expressions() -> Result<()> {
|
|||||||
pop r8
|
pop r8
|
||||||
pop r9
|
pop r9
|
||||||
pop r10
|
pop r10
|
||||||
|
push sp
|
||||||
push ra
|
push ra
|
||||||
add r1 r10 r9
|
add r1 r10 r9
|
||||||
mul r2 r1 r8
|
mul r2 r1 r8
|
||||||
@@ -66,6 +67,7 @@ fn nested_binary_expressions() -> Result<()> {
|
|||||||
j __internal_L1
|
j __internal_L1
|
||||||
__internal_L1:
|
__internal_L1:
|
||||||
pop ra
|
pop ra
|
||||||
|
pop sp
|
||||||
j ra
|
j ra
|
||||||
main:
|
main:
|
||||||
push 10
|
push 10
|
||||||
|
|||||||
@@ -21,9 +21,11 @@ fn no_arguments() -> anyhow::Result<()> {
|
|||||||
"
|
"
|
||||||
j main
|
j main
|
||||||
doSomething:
|
doSomething:
|
||||||
|
push sp
|
||||||
push ra
|
push ra
|
||||||
__internal_L1:
|
__internal_L1:
|
||||||
pop ra
|
pop ra
|
||||||
|
pop sp
|
||||||
j ra
|
j ra
|
||||||
main:
|
main:
|
||||||
jal doSomething
|
jal doSomething
|
||||||
@@ -65,12 +67,14 @@ fn let_var_args() -> anyhow::Result<()> {
|
|||||||
j main
|
j main
|
||||||
mul2:
|
mul2:
|
||||||
pop r8
|
pop r8
|
||||||
|
push sp
|
||||||
push ra
|
push ra
|
||||||
mul r1 r8 2
|
mul r1 r8 2
|
||||||
move r15 r1
|
move r15 r1
|
||||||
j __internal_L1
|
j __internal_L1
|
||||||
__internal_L1:
|
__internal_L1:
|
||||||
pop ra
|
pop ra
|
||||||
|
pop sp
|
||||||
j ra
|
j ra
|
||||||
main:
|
main:
|
||||||
__internal_L2:
|
__internal_L2:
|
||||||
@@ -136,11 +140,13 @@ fn inline_literal_args() -> anyhow::Result<()> {
|
|||||||
doSomething:
|
doSomething:
|
||||||
pop r8
|
pop r8
|
||||||
pop r9
|
pop r9
|
||||||
|
push sp
|
||||||
push ra
|
push ra
|
||||||
move r15 5
|
move r15 5
|
||||||
j __internal_L1
|
j __internal_L1
|
||||||
__internal_L1:
|
__internal_L1:
|
||||||
pop ra
|
pop ra
|
||||||
|
pop sp
|
||||||
j ra
|
j ra
|
||||||
main:
|
main:
|
||||||
move r8 123
|
move r8 123
|
||||||
@@ -182,9 +188,11 @@ fn mixed_args() -> anyhow::Result<()> {
|
|||||||
doSomething:
|
doSomething:
|
||||||
pop r8
|
pop r8
|
||||||
pop r9
|
pop r9
|
||||||
|
push sp
|
||||||
push ra
|
push ra
|
||||||
__internal_L1:
|
__internal_L1:
|
||||||
pop ra
|
pop ra
|
||||||
|
pop sp
|
||||||
j ra
|
j ra
|
||||||
main:
|
main:
|
||||||
move r8 123
|
move r8 123
|
||||||
@@ -227,11 +235,13 @@ fn with_return_statement() -> anyhow::Result<()> {
|
|||||||
j main
|
j main
|
||||||
doSomething:
|
doSomething:
|
||||||
pop r8
|
pop r8
|
||||||
|
push sp
|
||||||
push ra
|
push ra
|
||||||
move r15 456
|
move r15 456
|
||||||
j __internal_L1
|
j __internal_L1
|
||||||
__internal_L1:
|
__internal_L1:
|
||||||
pop ra
|
pop ra
|
||||||
|
pop sp
|
||||||
j ra
|
j ra
|
||||||
main:
|
main:
|
||||||
push 123
|
push 123
|
||||||
@@ -268,10 +278,12 @@ fn with_negative_return_literal() -> anyhow::Result<()> {
|
|||||||
"
|
"
|
||||||
j main
|
j main
|
||||||
doSomething:
|
doSomething:
|
||||||
|
push sp
|
||||||
push ra
|
push ra
|
||||||
move r15 -1
|
move r15 -1
|
||||||
__internal_L1:
|
__internal_L1:
|
||||||
pop ra
|
pop ra
|
||||||
|
pop sp
|
||||||
j ra
|
j ra
|
||||||
main:
|
main:
|
||||||
jal doSomething
|
jal doSomething
|
||||||
|
|||||||
@@ -161,11 +161,13 @@ fn test_boolean_return() -> anyhow::Result<()> {
|
|||||||
"
|
"
|
||||||
j main
|
j main
|
||||||
getTrue:
|
getTrue:
|
||||||
|
push sp
|
||||||
push ra
|
push ra
|
||||||
move r15 1
|
move r15 1
|
||||||
j __internal_L1
|
j __internal_L1
|
||||||
__internal_L1:
|
__internal_L1:
|
||||||
pop ra
|
pop ra
|
||||||
|
pop sp
|
||||||
j ra
|
j ra
|
||||||
main:
|
main:
|
||||||
jal getTrue
|
jal getTrue
|
||||||
|
|||||||
@@ -189,12 +189,14 @@ fn device_used_in_function() -> anyhow::Result<()> {
|
|||||||
"
|
"
|
||||||
j main
|
j main
|
||||||
check_power:
|
check_power:
|
||||||
|
push sp
|
||||||
push ra
|
push ra
|
||||||
l r1 d0 On
|
l r1 d0 On
|
||||||
move r15 r1
|
move r15 r1
|
||||||
j __internal_L1
|
j __internal_L1
|
||||||
__internal_L1:
|
__internal_L1:
|
||||||
pop ra
|
pop ra
|
||||||
|
pop sp
|
||||||
j ra
|
j ra
|
||||||
main:
|
main:
|
||||||
jal check_power
|
jal check_power
|
||||||
|
|||||||
@@ -315,10 +315,12 @@ fn function_with_no_return() -> anyhow::Result<()> {
|
|||||||
"
|
"
|
||||||
j main
|
j main
|
||||||
no_return:
|
no_return:
|
||||||
|
push sp
|
||||||
push ra
|
push ra
|
||||||
move r8 5
|
move r8 5
|
||||||
__internal_L1:
|
__internal_L1:
|
||||||
pop ra
|
pop ra
|
||||||
|
pop sp
|
||||||
j ra
|
j ra
|
||||||
main:
|
main:
|
||||||
jal no_return
|
jal no_return
|
||||||
@@ -576,8 +578,9 @@ fn function_with_many_parameters() -> anyhow::Result<()> {
|
|||||||
pop r12
|
pop r12
|
||||||
pop r13
|
pop r13
|
||||||
pop r14
|
pop r14
|
||||||
|
push sp
|
||||||
push ra
|
push ra
|
||||||
sub r0 sp 2
|
sub r0 sp 3
|
||||||
get r1 db r0
|
get r1 db r0
|
||||||
add r2 r1 r14
|
add r2 r1 r14
|
||||||
add r3 r2 r13
|
add r3 r2 r13
|
||||||
@@ -590,7 +593,7 @@ fn function_with_many_parameters() -> anyhow::Result<()> {
|
|||||||
j __internal_L1
|
j __internal_L1
|
||||||
__internal_L1:
|
__internal_L1:
|
||||||
pop ra
|
pop ra
|
||||||
sub sp sp 1
|
pop sp
|
||||||
j ra
|
j ra
|
||||||
main:
|
main:
|
||||||
push 1
|
push 1
|
||||||
@@ -635,21 +638,25 @@ fn tuple_declaration_with_functions() -> anyhow::Result<()> {
|
|||||||
indoc! {"
|
indoc! {"
|
||||||
j main
|
j main
|
||||||
doSomething:
|
doSomething:
|
||||||
|
push sp
|
||||||
push ra
|
push ra
|
||||||
l r0 db Setting
|
l r1 db Setting
|
||||||
push r0
|
push r1
|
||||||
l r0 db Temperature
|
l r2 db Temperature
|
||||||
push r0
|
push r2
|
||||||
|
sub r0 sp 4
|
||||||
|
get r0 db r0
|
||||||
move r15 r0
|
move r15 r0
|
||||||
j __internal_L1
|
j __internal_L1
|
||||||
__internal_L1:
|
__internal_L1:
|
||||||
pop ra
|
sub r0 sp 3
|
||||||
sub sp sp 2
|
get ra db r0
|
||||||
j ra
|
j ra
|
||||||
main:
|
main:
|
||||||
jal doSomething
|
jal doSomething
|
||||||
pop r9
|
pop r9
|
||||||
pop r8
|
pop r8
|
||||||
|
move sp r15
|
||||||
"}
|
"}
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -679,19 +686,23 @@ fn tuple_from_simple_function() -> anyhow::Result<()> {
|
|||||||
indoc! {"
|
indoc! {"
|
||||||
j main
|
j main
|
||||||
get_pair:
|
get_pair:
|
||||||
|
push sp
|
||||||
push ra
|
push ra
|
||||||
push 1
|
push 1
|
||||||
push 2
|
push 2
|
||||||
move r15 2
|
sub r0 sp 4
|
||||||
|
get r0 db r0
|
||||||
|
move r15 r0
|
||||||
j __internal_L1
|
j __internal_L1
|
||||||
__internal_L1:
|
__internal_L1:
|
||||||
pop ra
|
sub r0 sp 3
|
||||||
sub sp sp 2
|
get ra db r0
|
||||||
j ra
|
j ra
|
||||||
main:
|
main:
|
||||||
jal get_pair
|
jal get_pair
|
||||||
pop r9
|
pop r9
|
||||||
pop r8
|
pop r8
|
||||||
|
move sp r15
|
||||||
"}
|
"}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -31,10 +31,11 @@ fn test_function_declaration_with_spillover_params() -> anyhow::Result<()> {
|
|||||||
pop r12
|
pop r12
|
||||||
pop r13
|
pop r13
|
||||||
pop r14
|
pop r14
|
||||||
|
push sp
|
||||||
push ra
|
push ra
|
||||||
sub r0 sp 3
|
sub r0 sp 4
|
||||||
get r1 db r0
|
get r1 db r0
|
||||||
sub r0 sp 2
|
sub r0 sp 3
|
||||||
get r2 db r0
|
get r2 db r0
|
||||||
add r3 r1 r2
|
add r3 r1 r2
|
||||||
add r4 r3 r14
|
add r4 r3 r14
|
||||||
@@ -48,7 +49,7 @@ fn test_function_declaration_with_spillover_params() -> anyhow::Result<()> {
|
|||||||
j __internal_L1
|
j __internal_L1
|
||||||
__internal_L1:
|
__internal_L1:
|
||||||
pop ra
|
pop ra
|
||||||
sub sp sp 2
|
pop sp
|
||||||
j ra
|
j ra
|
||||||
main:
|
main:
|
||||||
move r8 1
|
move r8 1
|
||||||
@@ -97,6 +98,7 @@ fn test_early_return() -> anyhow::Result<()> {
|
|||||||
"
|
"
|
||||||
j main
|
j main
|
||||||
doSomething:
|
doSomething:
|
||||||
|
push sp
|
||||||
push ra
|
push ra
|
||||||
seq r1 1 1
|
seq r1 1 1
|
||||||
beqz r1 __internal_L2
|
beqz r1 __internal_L2
|
||||||
@@ -106,6 +108,7 @@ fn test_early_return() -> anyhow::Result<()> {
|
|||||||
j __internal_L1
|
j __internal_L1
|
||||||
__internal_L1:
|
__internal_L1:
|
||||||
pop ra
|
pop ra
|
||||||
|
pop sp
|
||||||
j ra
|
j ra
|
||||||
main:
|
main:
|
||||||
jal doSomething
|
jal doSomething
|
||||||
@@ -138,9 +141,11 @@ fn test_function_declaration_with_register_params() -> anyhow::Result<()> {
|
|||||||
doSomething:
|
doSomething:
|
||||||
pop r8
|
pop r8
|
||||||
pop r9
|
pop r9
|
||||||
|
push sp
|
||||||
push ra
|
push ra
|
||||||
__internal_L1:
|
__internal_L1:
|
||||||
pop ra
|
pop ra
|
||||||
|
pop sp
|
||||||
j ra
|
j ra
|
||||||
"}
|
"}
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -95,12 +95,14 @@ fn function_parameter_scope() -> anyhow::Result<()> {
|
|||||||
j main
|
j main
|
||||||
double:
|
double:
|
||||||
pop r8
|
pop r8
|
||||||
|
push sp
|
||||||
push ra
|
push ra
|
||||||
mul r1 r8 2
|
mul r1 r8 2
|
||||||
move r15 r1
|
move r15 r1
|
||||||
j __internal_L1
|
j __internal_L1
|
||||||
__internal_L1:
|
__internal_L1:
|
||||||
pop ra
|
pop ra
|
||||||
|
pop sp
|
||||||
j ra
|
j ra
|
||||||
main:
|
main:
|
||||||
push 5
|
push 5
|
||||||
@@ -334,20 +336,24 @@ fn function_scope_isolation() -> anyhow::Result<()> {
|
|||||||
"
|
"
|
||||||
j main
|
j main
|
||||||
func1:
|
func1:
|
||||||
|
push sp
|
||||||
push ra
|
push ra
|
||||||
move r8 10
|
move r8 10
|
||||||
move r15 r8
|
move r15 r8
|
||||||
j __internal_L1
|
j __internal_L1
|
||||||
__internal_L1:
|
__internal_L1:
|
||||||
pop ra
|
pop ra
|
||||||
|
pop sp
|
||||||
j ra
|
j ra
|
||||||
func2:
|
func2:
|
||||||
|
push sp
|
||||||
push ra
|
push ra
|
||||||
move r8 20
|
move r8 20
|
||||||
move r15 r8
|
move r15 r8
|
||||||
j __internal_L2
|
j __internal_L2
|
||||||
__internal_L2:
|
__internal_L2:
|
||||||
pop ra
|
pop ra
|
||||||
|
pop sp
|
||||||
j ra
|
j ra
|
||||||
main:
|
main:
|
||||||
jal func1
|
jal func1
|
||||||
@@ -390,19 +396,23 @@ fn tuple_unpacking_scope() -> anyhow::Result<()> {
|
|||||||
"
|
"
|
||||||
j main
|
j main
|
||||||
pair:
|
pair:
|
||||||
|
push sp
|
||||||
push ra
|
push ra
|
||||||
push 1
|
push 1
|
||||||
push 2
|
push 2
|
||||||
move r15 2
|
sub r0 sp 4
|
||||||
|
get r0 db r0
|
||||||
|
move r15 r0
|
||||||
j __internal_L1
|
j __internal_L1
|
||||||
__internal_L1:
|
__internal_L1:
|
||||||
pop ra
|
sub r0 sp 3
|
||||||
sub sp sp 2
|
get ra db r0
|
||||||
j ra
|
j ra
|
||||||
main:
|
main:
|
||||||
jal pair
|
jal pair
|
||||||
pop r9
|
pop r9
|
||||||
pop r8
|
pop r8
|
||||||
|
move sp r15
|
||||||
add r1 r8 r9
|
add r1 r8 r9
|
||||||
move r10 r1
|
move r10 r1
|
||||||
"
|
"
|
||||||
|
|||||||
@@ -218,19 +218,23 @@ mod test {
|
|||||||
"
|
"
|
||||||
j main
|
j main
|
||||||
getPair:
|
getPair:
|
||||||
|
push sp
|
||||||
push ra
|
push ra
|
||||||
push 10
|
push 10
|
||||||
push 20
|
push 20
|
||||||
move r15 20
|
sub r0 sp 4
|
||||||
|
get r0 db r0
|
||||||
|
move r15 r0
|
||||||
j __internal_L1
|
j __internal_L1
|
||||||
__internal_L1:
|
__internal_L1:
|
||||||
pop ra
|
sub r0 sp 3
|
||||||
sub sp sp 2
|
get ra db r0
|
||||||
j ra
|
j ra
|
||||||
main:
|
main:
|
||||||
jal getPair
|
jal getPair
|
||||||
pop r9
|
pop r9
|
||||||
pop r8
|
pop r8
|
||||||
|
move sp r15
|
||||||
"
|
"
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@@ -262,19 +266,23 @@ mod test {
|
|||||||
"
|
"
|
||||||
j main
|
j main
|
||||||
getPair:
|
getPair:
|
||||||
|
push sp
|
||||||
push ra
|
push ra
|
||||||
push 5
|
push 5
|
||||||
push 15
|
push 15
|
||||||
move r15 15
|
sub r0 sp 4
|
||||||
|
get r0 db r0
|
||||||
|
move r15 r0
|
||||||
j __internal_L1
|
j __internal_L1
|
||||||
__internal_L1:
|
__internal_L1:
|
||||||
pop ra
|
sub r0 sp 3
|
||||||
sub sp sp 2
|
get ra db r0
|
||||||
j ra
|
j ra
|
||||||
main:
|
main:
|
||||||
jal getPair
|
jal getPair
|
||||||
pop r0
|
pop r0
|
||||||
pop r8
|
pop r8
|
||||||
|
move sp r15
|
||||||
"
|
"
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@@ -306,21 +314,25 @@ mod test {
|
|||||||
"
|
"
|
||||||
j main
|
j main
|
||||||
getTriple:
|
getTriple:
|
||||||
|
push sp
|
||||||
push ra
|
push ra
|
||||||
push 1
|
push 1
|
||||||
push 2
|
push 2
|
||||||
push 3
|
push 3
|
||||||
move r15 3
|
sub r0 sp 5
|
||||||
|
get r0 db r0
|
||||||
|
move r15 r0
|
||||||
j __internal_L1
|
j __internal_L1
|
||||||
__internal_L1:
|
__internal_L1:
|
||||||
pop ra
|
sub r0 sp 4
|
||||||
sub sp sp 3
|
get ra db r0
|
||||||
j ra
|
j ra
|
||||||
main:
|
main:
|
||||||
jal getTriple
|
jal getTriple
|
||||||
pop r10
|
pop r10
|
||||||
pop r9
|
pop r9
|
||||||
pop r8
|
pop r8
|
||||||
|
move sp r15
|
||||||
"
|
"
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@@ -354,14 +366,17 @@ mod test {
|
|||||||
"
|
"
|
||||||
j main
|
j main
|
||||||
getPair:
|
getPair:
|
||||||
|
push sp
|
||||||
push ra
|
push ra
|
||||||
push 42
|
push 42
|
||||||
push 84
|
push 84
|
||||||
move r15 84
|
sub r0 sp 4
|
||||||
|
get r0 db r0
|
||||||
|
move r15 r0
|
||||||
j __internal_L1
|
j __internal_L1
|
||||||
__internal_L1:
|
__internal_L1:
|
||||||
pop ra
|
sub r0 sp 3
|
||||||
sub sp sp 2
|
get ra db r0
|
||||||
j ra
|
j ra
|
||||||
main:
|
main:
|
||||||
move r8 1
|
move r8 1
|
||||||
@@ -369,6 +384,7 @@ mod test {
|
|||||||
jal getPair
|
jal getPair
|
||||||
pop r9
|
pop r9
|
||||||
pop r8
|
pop r8
|
||||||
|
move sp r15
|
||||||
"
|
"
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@@ -433,24 +449,30 @@ mod test {
|
|||||||
"
|
"
|
||||||
j main
|
j main
|
||||||
doSomething:
|
doSomething:
|
||||||
|
push sp
|
||||||
push ra
|
push ra
|
||||||
push 1
|
push 1
|
||||||
push 2
|
push 2
|
||||||
move r15 2
|
sub r0 sp 4
|
||||||
|
get r0 db r0
|
||||||
|
move r15 r0
|
||||||
j __internal_L1
|
j __internal_L1
|
||||||
__internal_L1:
|
__internal_L1:
|
||||||
pop ra
|
sub r0 sp 3
|
||||||
sub sp sp 2
|
get ra db r0
|
||||||
j ra
|
j ra
|
||||||
doSomethingElse:
|
doSomethingElse:
|
||||||
|
push sp
|
||||||
push ra
|
push ra
|
||||||
jal doSomething
|
jal doSomething
|
||||||
pop r9
|
pop r9
|
||||||
pop r8
|
pop r8
|
||||||
|
move sp r15
|
||||||
move r15 r9
|
move r15 r9
|
||||||
j __internal_L2
|
j __internal_L2
|
||||||
__internal_L2:
|
__internal_L2:
|
||||||
pop ra
|
pop ra
|
||||||
|
pop sp
|
||||||
j ra
|
j ra
|
||||||
main:
|
main:
|
||||||
jal doSomethingElse
|
jal doSomethingElse
|
||||||
@@ -492,28 +514,34 @@ mod test {
|
|||||||
"
|
"
|
||||||
j main
|
j main
|
||||||
getValue:
|
getValue:
|
||||||
|
push sp
|
||||||
push ra
|
push ra
|
||||||
move r15 42
|
move r15 42
|
||||||
j __internal_L1
|
j __internal_L1
|
||||||
__internal_L1:
|
__internal_L1:
|
||||||
pop ra
|
pop ra
|
||||||
|
pop sp
|
||||||
j ra
|
j ra
|
||||||
getTuple:
|
getTuple:
|
||||||
|
push sp
|
||||||
push ra
|
push ra
|
||||||
jal getValue
|
jal getValue
|
||||||
move r8 r15
|
move r8 r15
|
||||||
push r8
|
push r8
|
||||||
push r8
|
push r8
|
||||||
move r15 r8
|
sub r0 sp 4
|
||||||
|
get r0 db r0
|
||||||
|
move r15 r0
|
||||||
j __internal_L2
|
j __internal_L2
|
||||||
__internal_L2:
|
__internal_L2:
|
||||||
pop ra
|
sub r0 sp 3
|
||||||
sub sp sp 2
|
get ra db r0
|
||||||
j ra
|
j ra
|
||||||
main:
|
main:
|
||||||
jal getTuple
|
jal getTuple
|
||||||
pop r9
|
pop r9
|
||||||
pop r8
|
pop r8
|
||||||
|
move sp r15
|
||||||
"
|
"
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@@ -542,6 +570,7 @@ mod test {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_multiple_tuple_returns_in_function() -> anyhow::Result<()> {
|
fn test_multiple_tuple_returns_in_function() -> anyhow::Result<()> {
|
||||||
|
// Test multiple return paths in tuple-returning function
|
||||||
let compiled = compile!(
|
let compiled = compile!(
|
||||||
check
|
check
|
||||||
r#"
|
r#"
|
||||||
@@ -570,28 +599,34 @@ mod test {
|
|||||||
j main
|
j main
|
||||||
getValue:
|
getValue:
|
||||||
pop r8
|
pop r8
|
||||||
|
push sp
|
||||||
push ra
|
push ra
|
||||||
beqz r8 __internal_L3
|
beqz r8 __internal_L3
|
||||||
push 1
|
push 1
|
||||||
push 2
|
push 2
|
||||||
move r15 2
|
sub r0 sp 4
|
||||||
|
get r0 db r0
|
||||||
|
move r15 r0
|
||||||
j __internal_L1
|
j __internal_L1
|
||||||
j __internal_L2
|
j __internal_L2
|
||||||
__internal_L3:
|
__internal_L3:
|
||||||
push 3
|
push 3
|
||||||
push 4
|
push 4
|
||||||
move r15 4
|
sub r0 sp 4
|
||||||
|
get r0 db r0
|
||||||
|
move r15 r0
|
||||||
j __internal_L1
|
j __internal_L1
|
||||||
__internal_L2:
|
__internal_L2:
|
||||||
__internal_L1:
|
__internal_L1:
|
||||||
pop ra
|
sub r0 sp 3
|
||||||
sub sp sp 2
|
get ra db r0
|
||||||
j ra
|
j ra
|
||||||
main:
|
main:
|
||||||
push 1
|
push 1
|
||||||
jal getValue
|
jal getValue
|
||||||
pop r9
|
pop r9
|
||||||
pop r8
|
pop r8
|
||||||
|
move sp r15
|
||||||
"
|
"
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@@ -626,14 +661,17 @@ mod test {
|
|||||||
add:
|
add:
|
||||||
pop r8
|
pop r8
|
||||||
pop r9
|
pop r9
|
||||||
|
push sp
|
||||||
push ra
|
push ra
|
||||||
push r9
|
push r9
|
||||||
push r8
|
push r8
|
||||||
move r15 r8
|
sub r0 sp 4
|
||||||
|
get r0 db r0
|
||||||
|
move r15 r0
|
||||||
j __internal_L1
|
j __internal_L1
|
||||||
__internal_L1:
|
__internal_L1:
|
||||||
pop ra
|
sub r0 sp 3
|
||||||
sub sp sp 2
|
get ra db r0
|
||||||
j ra
|
j ra
|
||||||
main:
|
main:
|
||||||
push 5
|
push 5
|
||||||
@@ -641,6 +679,7 @@ mod test {
|
|||||||
jal add
|
jal add
|
||||||
pop r9
|
pop r9
|
||||||
pop r8
|
pop r8
|
||||||
|
move sp r15
|
||||||
"
|
"
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@@ -678,32 +717,40 @@ mod test {
|
|||||||
"
|
"
|
||||||
j main
|
j main
|
||||||
inner:
|
inner:
|
||||||
|
push sp
|
||||||
push ra
|
push ra
|
||||||
push 1
|
push 1
|
||||||
push 2
|
push 2
|
||||||
move r15 2
|
sub r0 sp 4
|
||||||
|
get r0 db r0
|
||||||
|
move r15 r0
|
||||||
j __internal_L1
|
j __internal_L1
|
||||||
__internal_L1:
|
__internal_L1:
|
||||||
pop ra
|
sub r0 sp 3
|
||||||
sub sp sp 2
|
get ra db r0
|
||||||
j ra
|
j ra
|
||||||
outer:
|
outer:
|
||||||
|
push sp
|
||||||
push ra
|
push ra
|
||||||
jal inner
|
jal inner
|
||||||
pop r9
|
pop r9
|
||||||
pop r8
|
pop r8
|
||||||
|
move sp r15
|
||||||
push r9
|
push r9
|
||||||
push r8
|
push r8
|
||||||
move r15 r8
|
sub r0 sp 4
|
||||||
|
get r0 db r0
|
||||||
|
move r15 r0
|
||||||
j __internal_L2
|
j __internal_L2
|
||||||
__internal_L2:
|
__internal_L2:
|
||||||
pop ra
|
sub r0 sp 3
|
||||||
sub sp sp 2
|
get ra db r0
|
||||||
j ra
|
j ra
|
||||||
main:
|
main:
|
||||||
jal outer
|
jal outer
|
||||||
pop r9
|
pop r9
|
||||||
pop r8
|
pop r8
|
||||||
|
move sp r15
|
||||||
"
|
"
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@@ -839,18 +886,22 @@ mod test {
|
|||||||
"
|
"
|
||||||
j main
|
j main
|
||||||
getValue:
|
getValue:
|
||||||
|
push sp
|
||||||
push ra
|
push ra
|
||||||
move r15 42
|
move r15 42
|
||||||
j __internal_L1
|
j __internal_L1
|
||||||
__internal_L1:
|
__internal_L1:
|
||||||
pop ra
|
pop ra
|
||||||
|
pop sp
|
||||||
j ra
|
j ra
|
||||||
getOther:
|
getOther:
|
||||||
|
push sp
|
||||||
push ra
|
push ra
|
||||||
move r15 99
|
move r15 99
|
||||||
j __internal_L2
|
j __internal_L2
|
||||||
__internal_L2:
|
__internal_L2:
|
||||||
pop ra
|
pop ra
|
||||||
|
pop sp
|
||||||
j ra
|
j ra
|
||||||
main:
|
main:
|
||||||
push r8
|
push r8
|
||||||
@@ -1006,11 +1057,13 @@ mod test {
|
|||||||
"
|
"
|
||||||
j main
|
j main
|
||||||
getY:
|
getY:
|
||||||
|
push sp
|
||||||
push ra
|
push ra
|
||||||
move r15 42
|
move r15 42
|
||||||
j __internal_L1
|
j __internal_L1
|
||||||
__internal_L1:
|
__internal_L1:
|
||||||
pop ra
|
pop ra
|
||||||
|
pop sp
|
||||||
j ra
|
j ra
|
||||||
main:
|
main:
|
||||||
l r1 db Setting
|
l r1 db Setting
|
||||||
@@ -1053,18 +1106,22 @@ mod test {
|
|||||||
"
|
"
|
||||||
j main
|
j main
|
||||||
getValue:
|
getValue:
|
||||||
|
push sp
|
||||||
push ra
|
push ra
|
||||||
move r15 10
|
move r15 10
|
||||||
j __internal_L1
|
j __internal_L1
|
||||||
__internal_L1:
|
__internal_L1:
|
||||||
pop ra
|
pop ra
|
||||||
|
pop sp
|
||||||
j ra
|
j ra
|
||||||
getOther:
|
getOther:
|
||||||
|
push sp
|
||||||
push ra
|
push ra
|
||||||
move r15 20
|
move r15 20
|
||||||
j __internal_L2
|
j __internal_L2
|
||||||
__internal_L2:
|
__internal_L2:
|
||||||
pop ra
|
pop ra
|
||||||
|
pop sp
|
||||||
j ra
|
j ra
|
||||||
main:
|
main:
|
||||||
push r8
|
push r8
|
||||||
@@ -1114,6 +1171,7 @@ mod test {
|
|||||||
"
|
"
|
||||||
j main
|
j main
|
||||||
get8:
|
get8:
|
||||||
|
push sp
|
||||||
push ra
|
push ra
|
||||||
push 1
|
push 1
|
||||||
push 2
|
push 2
|
||||||
@@ -1123,11 +1181,13 @@ mod test {
|
|||||||
push 6
|
push 6
|
||||||
push 7
|
push 7
|
||||||
push 8
|
push 8
|
||||||
move r15 8
|
sub r0 sp 10
|
||||||
|
get r0 db r0
|
||||||
|
move r15 r0
|
||||||
j __internal_L1
|
j __internal_L1
|
||||||
__internal_L1:
|
__internal_L1:
|
||||||
pop ra
|
sub r0 sp 9
|
||||||
sub sp sp 8
|
get ra db r0
|
||||||
j ra
|
j ra
|
||||||
main:
|
main:
|
||||||
jal get8
|
jal get8
|
||||||
@@ -1141,6 +1201,7 @@ mod test {
|
|||||||
pop r10
|
pop r10
|
||||||
pop r9
|
pop r9
|
||||||
pop r8
|
pop r8
|
||||||
|
move sp r15
|
||||||
sub r0 sp 1
|
sub r0 sp 1
|
||||||
get r1 db r0
|
get r1 db r0
|
||||||
add r2 r8 r1
|
add r2 r8 r1
|
||||||
@@ -1152,4 +1213,79 @@ mod test {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_tuple_return_in_loop() -> anyhow::Result<()> {
|
||||||
|
let compiled = compile!(
|
||||||
|
check
|
||||||
|
r#"
|
||||||
|
fn getValues(i) {
|
||||||
|
return (i, i * 2);
|
||||||
|
};
|
||||||
|
|
||||||
|
let sum = 0;
|
||||||
|
let i = 0;
|
||||||
|
loop {
|
||||||
|
let (a, b) = getValues(i);
|
||||||
|
sum = sum + a + b;
|
||||||
|
i = i + 1;
|
||||||
|
if (i > 3) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"#
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
compiled.errors.is_empty(),
|
||||||
|
"Expected no errors, got: {:?}",
|
||||||
|
compiled.errors
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
compiled.output,
|
||||||
|
indoc! {
|
||||||
|
"
|
||||||
|
j main
|
||||||
|
getValues:
|
||||||
|
pop r8
|
||||||
|
push sp
|
||||||
|
push ra
|
||||||
|
push r8
|
||||||
|
mul r1 r8 2
|
||||||
|
push r1
|
||||||
|
sub r0 sp 4
|
||||||
|
get r0 db r0
|
||||||
|
move r15 r0
|
||||||
|
j __internal_L1
|
||||||
|
__internal_L1:
|
||||||
|
sub r0 sp 3
|
||||||
|
get ra db r0
|
||||||
|
j ra
|
||||||
|
main:
|
||||||
|
move r8 0
|
||||||
|
move r9 0
|
||||||
|
__internal_L2:
|
||||||
|
push r9
|
||||||
|
jal getValues
|
||||||
|
pop r11
|
||||||
|
pop r10
|
||||||
|
move sp r15
|
||||||
|
add r1 r8 r10
|
||||||
|
add r2 r1 r11
|
||||||
|
move r8 r2
|
||||||
|
add r3 r9 1
|
||||||
|
move r9 r3
|
||||||
|
sgt r4 r9 3
|
||||||
|
beqz r4 __internal_L4
|
||||||
|
j __internal_L3
|
||||||
|
__internal_L4:
|
||||||
|
j __internal_L2
|
||||||
|
__internal_L3:
|
||||||
|
"
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -160,6 +160,8 @@ struct FunctionMetadata<'a> {
|
|||||||
tuple_return_size: u16,
|
tuple_return_size: u16,
|
||||||
/// Whether the SP (stack pointer) has been saved for the current function
|
/// Whether the SP (stack pointer) has been saved for the current function
|
||||||
sp_saved: bool,
|
sp_saved: bool,
|
||||||
|
/// Variable name for the saved SP at function entry (for stack unwinding)
|
||||||
|
sp_backup_var: Option<Cow<'a, str>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Default for FunctionMetadata<'a> {
|
impl<'a> Default for FunctionMetadata<'a> {
|
||||||
@@ -172,6 +174,7 @@ impl<'a> Default for FunctionMetadata<'a> {
|
|||||||
return_label: None,
|
return_label: None,
|
||||||
tuple_return_size: 0,
|
tuple_return_size: 0,
|
||||||
sp_saved: false,
|
sp_saved: false,
|
||||||
|
sp_backup_var: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1260,6 +1263,17 @@ impl<'a> Compiler<'a> {
|
|||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Restore stack pointer from r15 to clean up remaining tuple values
|
||||||
|
// (r15 contains the caller's SP from before the function was called)
|
||||||
|
self.write_instruction(
|
||||||
|
Instruction::Move(
|
||||||
|
Operand::StackPointer,
|
||||||
|
Operand::Register(VariableScope::RETURN_REGISTER),
|
||||||
|
),
|
||||||
|
None,
|
||||||
|
)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2504,136 +2518,70 @@ impl<'a> Compiler<'a> {
|
|||||||
}
|
}
|
||||||
Expression::Tuple(tuple_expr) => {
|
Expression::Tuple(tuple_expr) => {
|
||||||
let span = expr.span;
|
let span = expr.span;
|
||||||
let tuple_elements = &tuple_expr.node;
|
let tuple_elements = tuple_expr.node;
|
||||||
|
let tuple_size = tuple_elements.len();
|
||||||
|
|
||||||
// Track the last value for r15
|
// Push each tuple element onto the stack using compile_operand
|
||||||
let mut last_value_operand: Option<Operand> = None;
|
for element in tuple_elements.into_iter() {
|
||||||
|
let (push_operand, cleanup) = self.compile_operand(element, scope)?;
|
||||||
|
|
||||||
// Push each tuple element onto the stack
|
self.write_instruction(Instruction::Push(push_operand), Some(span))?;
|
||||||
for element in tuple_elements.iter() {
|
|
||||||
let push_operand = match &element.node {
|
|
||||||
Expression::Literal(lit) => extract_literal(lit.node.clone(), false)?,
|
|
||||||
Expression::Variable(var) => {
|
|
||||||
let var_loc = match scope.get_location_of(&var.node, Some(var.span))
|
|
||||||
{
|
|
||||||
Ok(l) => l,
|
|
||||||
Err(_) => {
|
|
||||||
self.errors.push(Error::UnknownIdentifier(
|
|
||||||
var.node.clone(),
|
|
||||||
var.span,
|
|
||||||
));
|
|
||||||
VariableLocation::Temporary(0)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
match &var_loc {
|
// Don't track the push in the scope's stack offset because these values
|
||||||
VariableLocation::Temporary(reg)
|
// are being returned to the caller, not allocated in this block's scope.
|
||||||
| VariableLocation::Persistant(reg) => Operand::Register(*reg),
|
// They will be left on the stack when we return.
|
||||||
VariableLocation::Constant(lit) => {
|
|
||||||
extract_literal(lit.clone(), false)?
|
|
||||||
}
|
|
||||||
VariableLocation::Stack(offset) => {
|
|
||||||
// Load from stack into temp register
|
|
||||||
self.write_instruction(
|
|
||||||
Instruction::Sub(
|
|
||||||
Operand::Register(
|
|
||||||
VariableScope::TEMP_STACK_REGISTER,
|
|
||||||
),
|
|
||||||
Operand::StackPointer,
|
|
||||||
Operand::Number((*offset).into()),
|
|
||||||
),
|
|
||||||
Some(span),
|
|
||||||
)?;
|
|
||||||
self.write_instruction(
|
|
||||||
Instruction::Get(
|
|
||||||
Operand::Register(
|
|
||||||
VariableScope::TEMP_STACK_REGISTER,
|
|
||||||
),
|
|
||||||
Operand::Device(Cow::from("db")),
|
|
||||||
Operand::Register(
|
|
||||||
VariableScope::TEMP_STACK_REGISTER,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Some(span),
|
|
||||||
)?;
|
|
||||||
Operand::Register(VariableScope::TEMP_STACK_REGISTER)
|
|
||||||
}
|
|
||||||
VariableLocation::Device(_) => {
|
|
||||||
return Err(Error::Unknown(
|
|
||||||
"You can not return a device from a function.".into(),
|
|
||||||
Some(var.span),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Expression::MemberAccess(member_access) => {
|
|
||||||
// Compile member access (e.g., device.Property)
|
|
||||||
let member_span = element.span;
|
|
||||||
|
|
||||||
// Get the device name from the object (should be a Variable expression)
|
if let Some(temp_name) = cleanup {
|
||||||
let device_name = if let Expression::Variable(var) =
|
scope.free_temp(temp_name, Some(span))?;
|
||||||
&member_access.node.object.node
|
}
|
||||||
{
|
|
||||||
&var.node
|
|
||||||
} else {
|
|
||||||
return Err(Error::Unknown(
|
|
||||||
"Member access must be on a device variable".into(),
|
|
||||||
Some(member_span),
|
|
||||||
));
|
|
||||||
};
|
|
||||||
|
|
||||||
let property_name = &member_access.node.member.node;
|
|
||||||
|
|
||||||
// Get device
|
|
||||||
let device = self.devices.get(device_name).ok_or_else(|| {
|
|
||||||
Error::UnknownIdentifier(device_name.clone(), member_span)
|
|
||||||
})?;
|
|
||||||
|
|
||||||
// Load property into temp register
|
|
||||||
self.write_instruction(
|
|
||||||
Instruction::Load(
|
|
||||||
Operand::Register(VariableScope::TEMP_STACK_REGISTER),
|
|
||||||
Operand::Device(device.clone()),
|
|
||||||
Operand::LogicType(property_name.clone()),
|
|
||||||
),
|
|
||||||
Some(member_span),
|
|
||||||
)?;
|
|
||||||
Operand::Register(VariableScope::TEMP_STACK_REGISTER)
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
// For other expression types, push 0 for now
|
|
||||||
// TODO: Support more expression types
|
|
||||||
Operand::Number(Number::Integer(0, Unit::None).into())
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
self.write_instruction(
|
|
||||||
Instruction::Push(push_operand.clone()),
|
|
||||||
Some(span),
|
|
||||||
)?;
|
|
||||||
last_value_operand = Some(push_operand);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set r15 to the last pushed value (convention for tuple returns)
|
// Load the saved SP from stack and move to r15 for caller's stack unwinding
|
||||||
if let Some(last_op) = last_value_operand {
|
if let Some(sp_var_name) = &self.function_meta.sp_backup_var {
|
||||||
self.write_instruction(
|
let sp_var_loc = scope.get_location_of(sp_var_name, Some(span))?;
|
||||||
Instruction::Move(
|
|
||||||
Operand::Register(VariableScope::RETURN_REGISTER),
|
if let VariableLocation::Stack(offset) = sp_var_loc {
|
||||||
last_op,
|
// Calculate address of saved SP, accounting for tuple values just pushed
|
||||||
),
|
let adjusted_offset = offset + tuple_size as u16;
|
||||||
Some(span),
|
self.write_instruction(
|
||||||
)?;
|
Instruction::Sub(
|
||||||
|
Operand::Register(VariableScope::TEMP_STACK_REGISTER),
|
||||||
|
Operand::StackPointer,
|
||||||
|
Operand::Number(adjusted_offset.into()),
|
||||||
|
),
|
||||||
|
Some(span),
|
||||||
|
)?;
|
||||||
|
|
||||||
|
// Load saved SP value
|
||||||
|
self.write_instruction(
|
||||||
|
Instruction::Get(
|
||||||
|
Operand::Register(VariableScope::TEMP_STACK_REGISTER),
|
||||||
|
Operand::Device(Cow::from("db")),
|
||||||
|
Operand::Register(VariableScope::TEMP_STACK_REGISTER),
|
||||||
|
),
|
||||||
|
Some(span),
|
||||||
|
)?;
|
||||||
|
|
||||||
|
// Move to r15 for caller
|
||||||
|
self.write_instruction(
|
||||||
|
Instruction::Move(
|
||||||
|
Operand::Register(VariableScope::RETURN_REGISTER),
|
||||||
|
Operand::Register(VariableScope::TEMP_STACK_REGISTER),
|
||||||
|
),
|
||||||
|
Some(span),
|
||||||
|
)?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Record the tuple return size for validation at call sites
|
// Record the tuple return size for validation at call sites
|
||||||
if let Some(func_name) = &self.function_meta.current_name {
|
if let Some(func_name) = &self.function_meta.current_name {
|
||||||
self.function_meta
|
self.function_meta
|
||||||
.tuple_return_sizes
|
.tuple_return_sizes
|
||||||
.insert(func_name.clone(), tuple_elements.len());
|
.insert(func_name.clone(), tuple_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Track tuple size for epilogue cleanup
|
// Track tuple size for epilogue cleanup
|
||||||
self.function_meta.tuple_return_size = tuple_elements.len() as u16;
|
self.function_meta.tuple_return_size = tuple_size as u16;
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
return Err(Error::Unknown(
|
return Err(Error::Unknown(
|
||||||
@@ -3355,10 +3303,20 @@ impl<'a> Compiler<'a> {
|
|||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.write_instruction(Instruction::Push(Operand::ReturnAddress), Some(span))?;
|
// Save the caller's stack pointer FIRST (before any pushes modify it)
|
||||||
|
// This is crucial for proper stack unwinding in tuple returns
|
||||||
|
let sp_backup_name = self.next_temp_name();
|
||||||
|
block_scope.add_variable(
|
||||||
|
sp_backup_name.clone(),
|
||||||
|
LocationRequest::Stack,
|
||||||
|
Some(name.span),
|
||||||
|
)?;
|
||||||
|
self.write_instruction(Instruction::Push(Operand::StackPointer), Some(span))?;
|
||||||
|
self.function_meta.sp_backup_var = Some(sp_backup_name);
|
||||||
|
self.function_meta.sp_saved = true;
|
||||||
|
|
||||||
|
// Generate return label name and track it before pushing ra
|
||||||
let return_label = self.next_label_name();
|
let return_label = self.next_label_name();
|
||||||
|
|
||||||
let prev_return_label = self
|
let prev_return_label = self
|
||||||
.function_meta
|
.function_meta
|
||||||
.return_label
|
.return_label
|
||||||
@@ -3370,6 +3328,8 @@ impl<'a> Compiler<'a> {
|
|||||||
Some(name.span),
|
Some(name.span),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
self.write_instruction(Instruction::Push(Operand::ReturnAddress), Some(span))?;
|
||||||
|
|
||||||
for expr in body.0 {
|
for expr in body.0 {
|
||||||
match expr.node {
|
match expr.node {
|
||||||
Expression::Return(ret_expr) => {
|
Expression::Return(ret_expr) => {
|
||||||
@@ -3414,28 +3374,30 @@ impl<'a> Compiler<'a> {
|
|||||||
// Write the return label and epilogue
|
// Write the return label and epilogue
|
||||||
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 {
|
// Handle stack cleanup based on whether this is a tuple-returning function
|
||||||
self.write_instruction(Instruction::Pop(Operand::ReturnAddress), Some(span))?;
|
let is_tuple_return = self.function_meta.tuple_return_size > 0;
|
||||||
|
|
||||||
// Calculate cleanup: scope variables + tuple return values
|
// For tuple returns, account for tuple values pushed onto the stack
|
||||||
let remaining_cleanup =
|
let adjusted_ra_offset = if is_tuple_return {
|
||||||
(block_scope.stack_offset() - 1) + self.function_meta.tuple_return_size;
|
ra_stack_offset + self.function_meta.tuple_return_size as u16
|
||||||
if remaining_cleanup > 0 {
|
|
||||||
self.write_instruction(
|
|
||||||
Instruction::Sub(
|
|
||||||
Operand::StackPointer,
|
|
||||||
Operand::StackPointer,
|
|
||||||
Operand::Number(remaining_cleanup.into()),
|
|
||||||
),
|
|
||||||
Some(span),
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
|
ra_stack_offset
|
||||||
|
};
|
||||||
|
|
||||||
|
// Load return address from stack
|
||||||
|
if adjusted_ra_offset == 1 && !is_tuple_return {
|
||||||
|
// Simple case: RA is at top, and we're not returning a tuple
|
||||||
|
// Just pop ra, then pop sp to restore
|
||||||
|
self.write_instruction(Instruction::Pop(Operand::ReturnAddress), Some(span))?;
|
||||||
|
self.write_instruction(Instruction::Pop(Operand::StackPointer), Some(span))?;
|
||||||
|
} else {
|
||||||
|
// RA is deeper in stack, or we're returning a tuple
|
||||||
|
// Load ra from offset
|
||||||
self.write_instruction(
|
self.write_instruction(
|
||||||
Instruction::Sub(
|
Instruction::Sub(
|
||||||
Operand::Register(VariableScope::TEMP_STACK_REGISTER),
|
Operand::Register(VariableScope::TEMP_STACK_REGISTER),
|
||||||
Operand::StackPointer,
|
Operand::StackPointer,
|
||||||
Operand::Number(ra_stack_offset.into()),
|
Operand::Number(adjusted_ra_offset.into()),
|
||||||
),
|
),
|
||||||
Some(span),
|
Some(span),
|
||||||
)?;
|
)?;
|
||||||
@@ -3449,18 +3411,36 @@ impl<'a> Compiler<'a> {
|
|||||||
Some(span),
|
Some(span),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
// Clean up scope variables + tuple return values
|
if !is_tuple_return {
|
||||||
let total_cleanup = block_scope.stack_offset() + self.function_meta.tuple_return_size;
|
// Non-tuple return: restore SP from saved value to clean up
|
||||||
if total_cleanup > 0 {
|
let sp_offset = adjusted_ra_offset - 1;
|
||||||
self.write_instruction(
|
self.write_instruction(
|
||||||
Instruction::Sub(
|
Instruction::Sub(
|
||||||
|
Operand::Register(VariableScope::TEMP_STACK_REGISTER),
|
||||||
Operand::StackPointer,
|
Operand::StackPointer,
|
||||||
|
Operand::Number(sp_offset.into()),
|
||||||
|
),
|
||||||
|
Some(span),
|
||||||
|
)?;
|
||||||
|
|
||||||
|
self.write_instruction(
|
||||||
|
Instruction::Get(
|
||||||
|
Operand::Register(VariableScope::TEMP_STACK_REGISTER),
|
||||||
|
Operand::Device(Cow::from("db")),
|
||||||
|
Operand::Register(VariableScope::TEMP_STACK_REGISTER),
|
||||||
|
),
|
||||||
|
Some(span),
|
||||||
|
)?;
|
||||||
|
|
||||||
|
self.write_instruction(
|
||||||
|
Instruction::Move(
|
||||||
Operand::StackPointer,
|
Operand::StackPointer,
|
||||||
Operand::Number(total_cleanup.into()),
|
Operand::Register(VariableScope::TEMP_STACK_REGISTER),
|
||||||
),
|
),
|
||||||
Some(span),
|
Some(span),
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
// else: Tuple return - leave tuple values on stack for caller to pop
|
||||||
}
|
}
|
||||||
|
|
||||||
self.write_instruction(Instruction::Jump(Operand::ReturnAddress), Some(span))?;
|
self.write_instruction(Instruction::Jump(Operand::ReturnAddress), Some(span))?;
|
||||||
@@ -3468,6 +3448,7 @@ impl<'a> Compiler<'a> {
|
|||||||
// Reset the flags for the next function
|
// Reset the flags for the next function
|
||||||
self.function_meta.tuple_return_size = 0;
|
self.function_meta.tuple_return_size = 0;
|
||||||
self.function_meta.sp_saved = false;
|
self.function_meta.sp_saved = false;
|
||||||
|
self.function_meta.sp_backup_var = None;
|
||||||
self.function_meta.current_name = None;
|
self.function_meta.current_name = None;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user