I would like to do some microbenchmarking in Swift. I have been using package-benchmark for this. It comes with a blackHole
helper function that forces the compiler to assume that a variable is read and thus prevent dead-code elimination.
However, I would like to go a step further and block common subexpression elimination and loop-invariant code motion too. For that I had come up with the following based on the blackHole
implementation.
@_optimize(none)
func assumePointeeIsClobbered(_ x: UnsafeMutableRawPointer) {}
My understanding is that this should force the compiler to assume that x
can be both read and written to. This had been working for me up to Swift 5.11, but appears to have been broken in Swift 6.0.3 -- Compiler Explorer Link (I know that this is a very synthetic benchmark that doesn't even measure the latency of sqrt
properly, but that is not the point of this question).
The diff shows that the benchmarkee (sqrt
) gets optimized out in Swift 6.0.3, but not in Swift 5.10. I have the following questions.
- Is the behavior in Swift 6.0.3 a bug? If not, then what exactly is the optimizer's view of the function? I.e. why exactly is it allowed to do this transformation?
- Is there a better way to implement
assumePointeeIsClobbered
?