Skip to content

Convert if/else chain to switch statement #106523

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

nukethebees
Copy link

@nukethebees nukethebees commented May 17, 2025

RendererSceneCull::_scene_cull contains a large if/else chain which can be converted to a switch statement. In MSVC's optimised assembly, all if/else checks are done sequentially whereas the switch jumps directly. The if/else probably wasn't optimised as the final conditional isn't versus a constant (but we can just handle that in the default branch).

Part of the original if/else asm with MSVC:

  2840: 				uint32_t base_type = idata.flags & InstanceData::FLAG_BASE_TYPE_MASK;
mov         r13d,1  
mov         edx,dword ptr [r15]  
movzx       ecx,dl  
  2841: 				if (base_type == RS::INSTANCE_LIGHT) {
cmp         ecx,5  
jne         RendererSceneCull::_scene_cull+1122h (07FF7A6806AD2h)  


  2848: 				} else if (base_type == RS::INSTANCE_REFLECTION_PROBE) {
cmp         ecx,6  
jne         RendererSceneCull::_scene_cull+1298h (07FF7A6806C48h)



  2868: 				} else if (base_type == RS::INSTANCE_DECAL) {
cmp         ecx,7  
jne         RendererSceneCull::_scene_cull+1370h (07FF7A6806D20h)  

And so on. New switch asm:

  2842: 				switch (base_type) {
lea         eax,[rdx-5]  
cmp         eax,7  
ja          $LN48+0BFh (07FF6BFFC703Ch)  
lea         rbx,[__ImageBase (07FF6BAE40000h)]  
mov         ecx,dword ptr [rbx+rax*4+5188C14h]  
add         rcx,rbx  
jmp         rcx  

@lawnjelly
Copy link
Member

lawnjelly commented May 17, 2025

It does appear (at least pre-2022) that MSVC compiler might not be so good at optimizing if else compared to switch.

First question though - have you got some profiles indicating this to be a bottleneck in real world (or benchmark) cases?
We usually prefer to limit micro-optimization to cases where there's evidence of a bottleneck.

(Culling can be, so it could well be useful, but it would be nice to confirm this either way. 👍 )

@nukethebees
Copy link
Author

I profiled it with the official culling benchmarks and it doesn't make any measurable difference as most of the time is spent in a much larger conditional earlier in the function.

You may as well close this then I guess.

Is there a threshold for what's considered a sufficient improvement?

@lawnjelly
Copy link
Member

Is there a threshold for what's considered a sufficient improvement?

There's no hard rules, but generally for optimization only PRs we like to see things make a significant improvement in benchmarks (i.e. measureable), and more so for ones that may make code more difficult to read - there is a trade off here, as optimizations often make less readable code, and often less easily maintainable code.

See https://docs.godotengine.org/en/stable/tutorials/performance/general_optimization.html#principles

Generally it is advisable for optimization PRs (CPU) to:

  1. Find a slow project / benchmark
  2. Profile
  3. Optimize bottleneck

This avoids wasting development / review time on areas which will not improve things.

@jss2a98aj
Copy link
Contributor

I do find this to be an improvement to readability even if the performance impact is negligible.

@AThousandShips AThousandShips changed the title Converted if/else chain to switch statement Convert if/else chain to switch statement May 22, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants