Skip to content

pathplan: movement towards value semantics

In C, you can pass a parameter by value or by reference (pointer):

void by_value(int x) {
  printf("x is %d\n", x);
}

void by_reference(int *x) {
  printf("x is %d\n", *x);
}

When passing an input-only parameter, you can choose either by-value or by-reference. When passing an output parameter or an input/output parameter, you must pass by-reference to ensure that original value is actually updated.

Historically, people have chosen to pass >2-word input-only structs by-reference due to performance concerns around calling conventions. On architectures like x86-64, small structs can be passed in registers but beyond a small size they spill to the stack. Once you spill a function parameter to the stack, its members need to be reloaded into registers (via memory accesses) in order to be operated on within the callee. In hot loops, this can become noticeably slow.

Fast forward to 2024 and the preceding paragraph is irrelevant. Anyone who cares about performance at this level compiles their code and dependencies with an optimizing compiler with LTO. By-value parameter passing, even for large structs effectively has no cost anymore.

With this in mind, by-reference parameter passing for input-only parameters causes only confusion. Instead of looking purely at the call site, you now need to look at the callee to see whether the usage is const or not. Ironically (not sure I’m using that word correctly…) this problem also affects non-LTO compilers. A compiler that cannot see across translation units is forced to pessimistically assume any pass by-reference call modifies its arguments.¹

This MR rephrases some const input-only parameter usage into pass by-value. The intent here is improving readability and debuggability, which has clearly been an issue given the outstanding bugs in this area.

¹ What a compiler can and cannot assume about a call across a translation unit boundary is depressingly little. Diving deep down this rabbit hole will expose that const is a lie and other cursed facts. So this (pass by-reference blocking compiler visibility) is admittedly not a very strong argument.

Merge request reports