codegen: Add `blackbox` and `compilerbarrier(:blackbox, ...)` for benchmarking (#61438)
Adds `Base.blackbox(x)` and the corresponding `:blackbox` setting for
`compilerbarrier`, motivated by the LICM-hoisting issue seen in #61394.
`Base.blackbox(x)` returns `x` but treats the output as opaque to the
optimizer: it cannot be constant-folded, CSE'd, or treated as
loop-invariant. This is Julia's equivalent of Google Benchmark's
`DoNotOptimize`.
https://google.github.io/benchmark/user_guide.html#preventing-optimization
`blackbox` is implemented as `compilerbarrier(:blackbox, x)`, keeping
all compiler-barrier functionality consolidated in one builtin rather
than introducing a new one.
## Implementation
**Julia-level (inference):** `:blackbox` has `consistent=ALWAYS_FALSE`
and returns `widenconst(val)`, preventing constant propagation and CSE
at the abstract interpretation level.
**Codegen level**, three cases based on the value's LLVM type:
- **Non-pointer scalars** (integers, floats — anything that fits in a
register): emits `asm "" "=r,0"` directly, tying the output register to
the input.
- **Boxed/GC-tracked pointers**: cannot use register-tied asm on
GC-tracked address spaces. Instead, emits a `julia.blackbox` intrinsic
call that is lowered to `asm "" "=r,0"` on the raw untracked pointer
after GC frame expansion.
- **Unboxed aggregates / unboxed pointers** (e.g., structs, `Ptr{T}`):
uses `asm sideeffect "" "~{memory}"` to clobber memory, making the value
appear non-invariant without needing a register constraint.
Ghost types (`Nothing`, etc.) pass through unchanged with no code
emitted.
---------
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Valentin Churavy <v.churavy@gmail.com>
Co-authored-by: Keno Fischer <1291671+Keno@users.noreply.github.com>