Skip to content

Conversation

kyon4ik
Copy link

@kyon4ik kyon4ik commented Jul 8, 2025

Generate single return op for function and jump to it from return points. It simplifies control flow, removes redundant assembly, especially if function has many return points. It also fixes the issue with repeating ret if return is called manually.

@mikmart
Copy link
Contributor

mikmart commented Jul 9, 2025

Personally I think emitting a return sequence for the return keyword results in more readable assembly if you need to inspect it manually. The issues you raise are of course valid, but I think they could be addressed in a slightly different way:

  • The issue with code duplication could be resolved by just emitting the implicit Op::Return in the compiler as you've done.
  • The repeated ret sequence with a manual return would be optimized out by Implement Dead-Code Elimination #155.
  • The compression to a single return point for reducing assembly code size could be a separate optimization step.

This way we would be able to get both the "bloated" assembly that's easy to inspect and correlate with the B code, but also the more efficient code when optimizations are enabled.

@kyon4ik
Copy link
Author

kyon4ik commented Jul 9, 2025

Personally I think emitting a return sequence for the return keyword results in more readable assembly if you need to inspect it manually. The issues you raise are of course valid, but I think they could be addressed in a slightly different way:

I don't think this makes the assembly (or ir) less readable, especially if we had custom names for labels and non-stack variables. I also wanted to introduce new Op::SetRetReg { arg: Arg }, that just sets return register, without stack allocation.

before:

IR:

ret auto[0]

x86_64:

movq ..., %rax
ret

after:

IR:

auto[1] = auto[0]
jmp label['return']

x86_64:

movq ..., (%rbp)
movq (%rbp), %rax
jmp .Lreturn

After set_ret_reg:

IR:

set_ret_reg auto[0]
jmp label['return']

x86_64:

movq ..., %rax
jmp .Lreturn

And with proper ssa, the jmp could look like function call (but it doesn't affect assembly)

jmp label['return'], auto[0]

Other points are valid, but implementing good enough opts is much harder, and it would certainly require ssa, which will make it even more similar to the current state.

@yui-915
Copy link
Contributor

yui-915 commented Jul 9, 2025

Other points are valid, but implementing good enough opts is much harder, and it would certainly require ssa, which will make it even more similar to the current state.

I'm currently working on implementing some basic optimizations for the compiler, it's able to detect and remove unreachable code and pointless assigns, with very little modifications to the current IR (only added Op::Nop, no ssa).

merging all returns points into one as an optimization step sounds like an interesting idea, but it's not my main focus right now.

@kyon4ik
Copy link
Author

kyon4ik commented Jul 9, 2025

Other points are valid, but implementing good enough opts is much harder, and it would certainly require ssa, which will make it even more similar to the current state.

I'm currently working on implementing some basic optimizations for the compiler, it's able to detect and remove unreachable code and pointless assigns, with very little modifications to the current IR (only added Op::Nop, no ssa).

merging all returns points into one as an optimization step sounds like an interesting idea, but it's not my main focus right now.

Yeah, I meant the "good" DCE, of course this case is eliminated even in my implementation. I should rename the issue, it is more about code size, than redundancies.

@kyon4ik kyon4ik changed the title Remove redundant returns Code size optimization (single return point) Jul 9, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants