codegen: optimize const fields of mutable objects (#53484)
For example, we seek to eliminate the gc frame from this function, as
observed here:
```julia
julia> code_llvm((BitSet,), raw=true) do x; r = x.bits; GC.safepoint(); @inbounds r[1]; end
; Function Signature: var"https://github.com/JuliaLang/julia/issues/3"(Base.BitSet)
; @ REPL[1]:1 within `https://github.com/JuliaLang/julia/issues/3`
define swiftcc i64 @"julia_#3_494"(ptr nonnull swiftself %pgcstack, ptr noundef nonnull align 8 dereferenceable(16) %"x::BitSet") #0 !dbg !5 {
top:
call void @llvm.dbg.declare(metadata ptr %"x::BitSet", metadata !21, metadata !DIExpression()), !dbg !22
%ptls_field = getelementptr inbounds ptr, ptr %pgcstack, i64 2
%ptls_load = load ptr, ptr %ptls_field, align 8, !tbaa !23
%0 = getelementptr inbounds ptr, ptr %ptls_load, i64 2
%safepoint = load ptr, ptr %0, align 8, !tbaa !27
fence syncscope("singlethread") seq_cst
%1 = load volatile i64, ptr %safepoint, align 8, !dbg !22
fence syncscope("singlethread") seq_cst
; ┌ @ Base.jl:49 within `getproperty`
%"x::BitSet.bits" = load atomic ptr, ptr %"x::BitSet" unordered, align 8, !dbg !29, !tbaa !27, !alias.scope !33, !noalias !36, !nonnull !11, !dereferenceable !41, !align !42
; └
; ┌ @ gcutils.jl:253 within `safepoint`
%ptls_load4 = load ptr, ptr %ptls_field, align 8, !dbg !43, !tbaa !23
%2 = getelementptr inbounds ptr, ptr %ptls_load4, i64 2, !dbg !43
%safepoint5 = load ptr, ptr %2, align 8, !dbg !43, !tbaa !27
fence syncscope("singlethread") seq_cst, !dbg !43
%3 = load volatile i64, ptr %safepoint5, align 8, !dbg !43
fence syncscope("singlethread") seq_cst, !dbg !43
; └
; ┌ @ essentials.jl:892 within `getindex`
%4 = load ptr, ptr %"x::BitSet.bits", align 8, !dbg !46, !tbaa !49, !alias.scope !52, !noalias !53
%5 = load i64, ptr %4, align 8, !dbg !46, !tbaa !54, !alias.scope !57, !noalias !58
ret i64 %5, !dbg !46
; └
}
```