Issue 1:
While trying to benchmark JuMP solvers on M1, we found that JuMP requires a compiler feature that is apparently not available on aarch64:

$ julia --project=. bench.jl
ERROR: LoadError: cfunction: closures are not supported on this platform
Stacktrace:
[1] _set_callback
@ ~/.julia/dev/GLPK/src/MOI_wrapper/MOI_wrapper.jl:259 [inlined]
[2] empty!(model::GLPK.Optimizer)
@ GLPK ~/.julia/dev/GLPK/src/MOI_wrapper/MOI_wrapper.jl:290
[3] GLPK.Optimizer(; want_infeasibility_certificates::Bool, method::GLPK.MethodEnum, kwargs::Base.Pairs{Symbol, Union{}, Tuple{}, NamedTuple{(), Tuple{}}})
@ GLPK ~/.julia/dev/GLPK/src/MOI_wrapper/MOI_wrapper.jl:206
[4] Optimizer
@ ~/.julia/dev/GLPK/src/MOI_wrapper/MOI_wrapper.jl:171 [inlined]
[5] _instantiate_and_check(optimizer_constructor::Type{GLPK.Optimizer})
@ MathOptInterface ~/.julia/packages/MathOptInterface/YDdD3/src/instantiate.jl:62
[6] instantiate(optimizer_constructor::Type; with_bridge_type::Type{Float64}, with_names::Bool)
@ MathOptInterface ~/.julia/packages/MathOptInterface/YDdD3/src/instantiate.jl:120
[7] set_optimizer(model::Model, optimizer_constructor::Type; bridge_constraints::Bool)
@ JuMP ~/.julia/packages/JuMP/klrjG/src/optimizer_interface.jl:109
[8] Model(optimizer_factory::Type; bridge_constraints::Bool, kwargs::Base.Pairs{Symbol, Union{}, Tuple{}, NamedTuple{(), Tuple{}}})
@ JuMP ~/.julia/packages/JuMP/klrjG/src/JuMP.jl:287
[9] Model
@ ~/.julia/packages/JuMP/klrjG/src/JuMP.jl:286 [inlined]
[10] example_factory_schedule(factory::Type)
@ Main ~/mlp_bench/bench.jl:557
[11] top-level scope
@ ~/mlp_bench/bench.jl:605
in expression starting at /Users/sabae/mlp_bench/bench.jl:602

The relevant code can be found here: https://github.com/jump-dev/GLPK.jl/blob/ebc73abbf0c8352c0509932aa1ad57a69716a2e6/src/MOI_wrapper/MOI_wrapper.jl#L242-L259

Reading through the docs, it appears this is advertised, but since such a prominent package uses them internally, it seems like we might want to see if there's a workaround we can use.

Issue 2:
Hi!

I've discovered that many (runtime) performance issues with broadcasting are caused by inlining not working with the highly recursive broadcasting code. It turns out that defining more methods can actually help here. Here is a piece of code you can evaluate in REPL to see that:

struct RecursiveInliningEnforcerA{T}
makeargs::T
end

struct RecursiveInliningEnforcerB{TMT,TMH,TT,TH,TF}
makeargs_tail::TMT
makeargs_head::TMH
headargs::TH
tailargs::TT
f::TF
end
for UB in [Any, RecursiveInliningEnforcerA]
@eval @inline function (bb::RecursiveInliningEnforcerB{TMT,TMH,TT,TH,TF})(args::Vararg{Any,N}) where {N,TMT,TMH<:$UB,TT,TH,TF}
args1 = bb.makeargs_head(args...)
a = bb.headargs(args1...)
b = bb.makeargs_tail(bb.tailargs(args1...)...)
return (bb.f(a...), b...)
end
end

for UB in [Any, RecursiveInliningEnforcerB]
@eval @inline (a::RecursiveInliningEnforcerA{TTA})(head::TH, tail::Vararg{Any,N}) where {TTA<:$UB,TH,N} = (head, a.makeargs(tail...)...)
end

@inline function Broadcast.make_makeargs(makeargs_tail::TT, t::Tuple) where TT
return RecursiveInliningEnforcerA(Broadcast.make_makeargs(makeargs_tail, Base.tail(t)))
end

function Broadcast.make_makeargs(makeargs_tail, t::Tuple{<:Broadcast.Broadcasted, Vararg{Any}})
bc = t[1]
# c.f. the same expression in the function on leaf nodes above. Here
# we recurse into siblings in the broadcast tree.
let makeargs_tail = Broadcast.make_makeargs(makeargs_tail, Base.tail(t)),
# Here we recurse into children. It would be valid to pass in makeargs_tail
# here, and not use it below. However, in that case, our recursion is no
# longer purely structural because we're building up one argument (the closure)
# while destructuing another.
makeargs_head = Broadcast.make_makeargs((args...)->args, bc.args),
f = bc.f
# Create two functions, one that splits of the first length(bc.args)
# elements from the tuple and one that yields the remaining arguments.
# N.B. We can't call headargs on `args...` directly because
# args is flattened (i.e. our children have not been evaluated
# yet).
headargs, tailargs = Broadcast.make_headargs(bc.args), Broadcast.make_tailargs(bc.args)
return RecursiveInliningEnforcerB(makeargs_tail, makeargs_head, headargs, tailargs, f)
end
end

This effectively duplicates these two functions:

julia/base/broadcast.jl

Lines 380 to 384
in
abbb220

return @inline function(args::Vararg{Any,N}) where N

args1 = makeargs_head(args...)

a, b = headargs(args1...), makeargs_tail(tailargs(args1...)...)

(f(a...), b...)

end

and

julia/base/broadcast.jl

Line 361
in
abbb220

(head, tail...)->(head, makeargs(tail...)...)

for different argument types.

It turns out that it's sufficient to fix the following issues:

JuliaArrays/StaticArrays.jl#560

JuliaArrays/StaticArrays.jl#682

JuliaArrays/StaticArrays.jl#609

JuliaArrays/StaticArrays.jl#797

What do you think about it?