optimizer: compute side-effect-freeness for array allocations (#43565)
This would be useful for Julia-level optimizations on arrays.
Initially I want to have this in order to add array primitives support
in EscapeAnalysis.jl, which should help us implement a variety of array
optimizations including dead array allocation elimination, copy-elision
from `Array` to `ImmutableArray` conversion (#42465), etc., but I found
this might be already useful for us since this enables some DCE in very
simple cases like:
```julia
julia> function simple!(x::T) where T
d = IdDict{T,T}() # dead alloc
# ... computations that don't use `d` at all
return nothing
end
simple! (generic function with 1 method)
julia> @code_typed simple!("foo")
CodeInfo(
1 ─ return Main.nothing
) => Nothing
```
This enhancement is super limited though, e.g. DCE won't happen when
array allocation involves other primitive operations like `arrayset`:
```julia
julia> code_typed() do
a = Int[0,1,2]
nothing
end
1-element Vector{Any}:
CodeInfo(
1 ─ %1 = $(Expr(:foreigncall, :(:jl_alloc_array_1d), Vector{Int64}, svec(Any, Int64), 0, :(:ccall), Vector{Int64}, 3, 3))::Vector{Int64}
│ Base.arrayset(false, %1, 0, 1)::Vector{Int64}
│ Base.arrayset(false, %1, 1, 2)::Vector{Int64}
│ Base.arrayset(false, %1, 2, 3)::Vector{Int64}
└── return Main.nothing
) => Nothing
```
Further enhancement o optimize cases like above will be based on top of
incoming EA.jl (Julia-level escape analysis) or LLVM-level escape analysis.