[3.x] Return primitive types by value#120866
Conversation
bbcef9e to
8297eb2
Compare
|
One downside to returning the primitive itself instead of a ref is that you can no longer store a pointer to it, and it's a bit of a 'gotcha' that these types return plain values instead of a ref. In all non-dev builds, the compiler will optimize the ref away. I don't think we have a large performance problem with dev builds either, so I'm not sure I agree with this change. |
8297eb2 to
0cd715d
Compare
Yes, I've removed the
There are still issues with aliasing etc. With by value, the intention is clear to the compiler, and it doesn't have to second guess. The other problem is that other contributors may see this pattern and duplicate it into new code. My opinion is that we should strive to make our code as correct as possible (where there is no cost to doing this). Although I know we don't like to rely on AI, I would suggest asking this question to any major AI in order to get full (unbiased) explanation from a "third party":
ExampleHere is an example of the aliasing issue: If we look at the assembly, the difference is massive: const int32_t &Because why can't the compiler see that you are not modifying
|
|
|
||
| uint32_t &get_item_ref_id(uint32_t p_id) { return item_ref_ids[p_id]; } | ||
| const uint32_t &get_item_ref_id(uint32_t p_id) const { return item_ref_ids[p_id]; } | ||
| uint32_t get_item_ref_id(uint32_t p_id) const { return item_ref_ids[p_id]; } |
There was a problem hiding this comment.
This was actually my mistake.
It may have crept in during refactoring (maybe passing a larger struct and then renaming).
There was a problem hiding this comment.
I have doubts the examples are true, and meanwhile I'm pretty sure there's no difference in assembly in all regular cases.
I won't reiterate my explanation now; we're talking about it in RC but I remain doubtful that this is an improvement we want to integrate. Just 'requesting changes' to represent the current state of discussion.
Changes low hanging fruit from returning primitive types (32/64 bit) from
const T&to byT(by value).I traced these back and the main problematic versions (
Vector2etc) had been like this for years.What problem(s) does this PR solve?
For small primitive types, returning by
const referenceis generally suboptimal compared to returning by value.Benefits:
const refis effectively treated by the compiler as a pointer. For types that fit in a register, there is no benefit, and often measurable downside, to using a pointer.Additional information
During optimization compilers can often (but not always) tell your intention and instead pass in a register even when you specify a
const ref(especially when inlined), however this is not guaranteed:DEVbuildscppfileGeneral rule of thumb is:
const reffor larger / expensive to copy typesProfile when in doubt, as modern CPUs / compilers can make by-value surprisingly good even for medium sized structs.
Notes
Stringthat @Repiteo found, as it does seem like a barrel of worms for compatibility, as a lot of functions seem to use this to grab an address rather than using the value (i.e. they use it as a pointer)