How to implement a Swift analogue of `benchmark::DoNotOptimize`?

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.

  1. 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?
  2. Is there a better way to implement assumePointeeIsClobbered?
1 Like

Cross-posted to StackOverflow, somebody pointed out in the comments that

@_optimize(none) only truly works for symbols in another module.

So, single-file reproducers on Compiler Explorer won't work. I tested this locally and it seems to hold for Swift 6.0.3.

1 Like