Issue 1:
In Julia master (but not in Julia 0.6) this apparently harmless function:

using StaticArrays

const v1 = SVector(1)
const v2 = SVector(2)
const v3 = SVector(3)
const v4 = SVector(4)

function foo()
a, b, c, d = 1:4
arg = @. v1 * a + v2 * b + v3 * c + v4 * d
end

is type-unstable:

julia> @code_warntype foo()
Variables:
#1::getfield(Main, Symbol("##1#2"))
a::Int64
b::Int64
c::Int64
d::Int64
#temp#@_7::Int64
arg<optimized out>
#temp#@_9::Tuple{Int64,Int64}
#temp#@_10::Tuple{Int64,Int64}
#temp#@_11::Tuple{Int64,Int64}
#temp#@_12::Tuple{Int64,Int64}

Body:
begin
SSAValue(0) = $(Expr(:new, UnitRange{Int64}, 1, :((Base.select_value)((Base.sle_int)(1, 4)::Bool, 4, (Base.sub_int)(1, 1)::Int64)::Int64)))
#temp#@_7::Int64 = (Core.getfield)(SSAValue(0), :start)::Int64
# meta: location tuple.jl indexed_next 60
unless (#temp#@_7::Int64 === (Base.add_int)((Core.getfield)(SSAValue(0), :stop)::Int64, 1)::Int64)::Bool goto 7
#temp#@_9::Tuple{Int64,Int64} = (Base.throw)($(Expr(:invoke, MethodInstance for BoundsError(::Any, ::Int64), :(Base.BoundsError), SSAValue(0), 1))::BoundsError)::Union{}
goto 9
7:
#temp#@_9::Tuple{Int64,Int64} = (Core.tuple)(#temp#@_7::Int64, (Base.add_int)(#temp#@_7::Int64, 1)::Int64)::Tuple{Int64,Int64}
9:
# meta: pop location
SSAValue(1) = #temp#@_9::Tuple{Int64,Int64}
a::Int64 = (Core.getfield)(SSAValue(1), 1)::Int64
#temp#@_7::Int64 = (Core.getfield)(SSAValue(1), 2)::Int64
# meta: location tuple.jl indexed_next 60
unless (#temp#@_7::Int64 === (Base.add_int)((Core.getfield)(SSAValue(0), :stop)::Int64, 1)::Int64)::Bool goto 18
#temp#@_10::Tuple{Int64,Int64} = (Base.throw)($(Expr(:invoke, MethodInstance for BoundsError(::Any, ::Int64), :(Base.BoundsError), SSAValue(0), 2))::BoundsError)::Union{}
goto 20
18:
#temp#@_10::Tuple{Int64,Int64} = (Core.tuple)(#temp#@_7::Int64, (Base.add_int)(#temp#@_7::Int64, 1)::Int64)::Tuple{Int64,Int64}
20:
# meta: pop location
SSAValue(2) = #temp#@_10::Tuple{Int64,Int64}
b::Int64 = (Core.getfield)(SSAValue(2), 1)::Int64
#temp#@_7::Int64 = (Core.getfield)(SSAValue(2), 2)::Int64
# meta: location tuple.jl indexed_next 60
unless (#temp#@_7::Int64 === (Base.add_int)((Core.getfield)(SSAValue(0), :stop)::Int64, 1)::Int64)::Bool goto 29
#temp#@_11::Tuple{Int64,Int64} = (Base.throw)($(Expr(:invoke, MethodInstance for BoundsError(::Any, ::Int64), :(Base.BoundsError), SSAValue(0), 3))::BoundsError)::Union{}
goto 31
29:
#temp#@_11::Tuple{Int64,Int64} = (Core.tuple)(#temp#@_7::Int64, (Base.add_int)(#temp#@_7::Int64, 1)::Int64)::Tuple{Int64,Int64}
31:
# meta: pop location
SSAValue(3) = #temp#@_11::Tuple{Int64,Int64}
c::Int64 = (Core.getfield)(SSAValue(3), 1)::Int64
#temp#@_7::Int64 = (Core.getfield)(SSAValue(3), 2)::Int64
# meta: location tuple.jl indexed_next 60
unless (#temp#@_7::Int64 === (Base.add_int)((Core.getfield)(SSAValue(0), :stop)::Int64, 1)::Int64)::Bool goto 40
#temp#@_12::Tuple{Int64,Int64} = (Base.throw)($(Expr(:invoke, MethodInstance for BoundsError(::Any, ::Int64), :(Base.BoundsError), SSAValue(0), 4))::BoundsError)::Union{}
goto 42
40:
#temp#@_12::Tuple{Int64,Int64} = (Core.tuple)(#temp#@_7::Int64, (Base.add_int)(#temp#@_7::Int64, 1)::Int64)::Tuple{Int64,Int64}
42:
# meta: pop location
SSAValue(4) = #temp#@_12::Tuple{Int64,Int64}
d::Int64 = (Core.getfield)(SSAValue(4), 1)::Int64
#temp#@_7::Int64 = (Core.getfield)(SSAValue(4), 2)::Int64
#= line 11 =#
#1::getfield(Main, Symbol("##1#2")) = $(Expr(:new, :(Main.##1#2)))
# meta: location broadcast.jl broadcast 434
# meta: location /home/mose/.julia/v0.7/StaticArrays/src/broadcast.jl broadcast_c 33
SSAValue(10) = (Core._apply)(Core.tuple, (Size(1,),), $(Expr(:invoke, MethodInstance for broadcast_sizes(::Int64, ::SVector{1,Int64}, ::Vararg{Any,N} where N), :(StaticArrays.broadcast_sizes), :(a), :(Main.v2), :(b), :(Main.v3), :(c), :(Main.v4), :(d)))::Tuple{StaticArrays.Size{()},StaticArrays.Size{(1,)},Vararg{Any,N} where N})::Tuple{StaticArrays.Size{(1,)},StaticArrays.Size{()},StaticArrays.Size{(1,)},Vararg{Any,N} where N}
# meta: pop locations (2)
SSAValue(9) = (StaticArrays._broadcast)(#1::getfield(Main, Symbol("##1#2")), SSAValue(10), Main.v1, a::Int64, Main.v2, b::Int64, Main.v3, c::Int64, Main.v4, d::Int64)::Any
return SSAValue(9)
end::Any

It is instead stable if broadcast is not used (remove the @.):

julia> function foo()
a, b, c, d = 1:4
arg = v1 * a + v2 * b + v3 * c + v4 * d
end
foo (generic function with 1 method)

julia> @code_warntype foo()
Variables:
a::Int64
b::Int64
c::Int64
d::Int64
#temp#@_6::Int64
arg<optimized out>
#temp#@_8::Tuple{Int64,Int64}
#temp#@_9::Tuple{Int64,Int64}
#temp#@_10::Tuple{Int64,Int64}
#temp#@_11::Tuple{Int64,Int64}
#temp#@_12::SVector{1,Int64}
#temp#@_18::SVector{1,Int64}

Body:
begin
SSAValue(0) = $(Expr(:new, UnitRange{Int64}, 1, :((Base.select_value)((Base.sle_int)(1, 4)::Bool, 4, (Base.sub_int)(1, 1)::Int64)::Int64)))
#temp#@_6::Int64 = (Core.getfield)(SSAValue(0), :start)::Int64
# meta: location tuple.jl indexed_next 60
unless (#temp#@_6::Int64 === (Base.add_int)((Core.getfield)(SSAValue(0), :stop)::Int64, 1)::Int64)::Bool goto 7
#temp#@_8::Tuple{Int64,Int64} = (Base.throw)($(Expr(:invoke, MethodInstance for BoundsError(::Any, ::Int64), :(Base.BoundsError), SSAValue(0), 1))::BoundsError)::Union{}
goto 9
7:
#temp#@_8::Tuple{Int64,Int64} = (Core.tuple)(#temp#@_6::Int64, (Base.add_int)(#temp#@_6::Int64, 1)::Int64)::Tuple{Int64,Int64}
9:
# meta: pop location
SSAValue(1) = #temp#@_8::Tuple{Int64,Int64}
a::Int64 = (Core.getfield)(SSAValue(1), 1)::Int64
#temp#@_6::Int64 = (Core.getfield)(SSAValue(1), 2)::Int64
# meta: location tuple.jl indexed_next 60
unless (#temp#@_6::Int64 === (Base.add_int)((Core.getfield)(SSAValue(0), :stop)::Int64, 1)::Int64)::Bool goto 18
#temp#@_9::Tuple{Int64,Int64} = (Base.throw)($(Expr(:invoke, MethodInstance for BoundsError(::Any, ::Int64), :(Base.BoundsError), SSAValue(0), 2))::BoundsError)::Union{}
goto 20
18:
#temp#@_9::Tuple{Int64,Int64} = (Core.tuple)(#temp#@_6::Int64, (Base.add_int)(#temp#@_6::Int64, 1)::Int64)::Tuple{Int64,Int64}
20:
# meta: pop location
SSAValue(2) = #temp#@_9::Tuple{Int64,Int64}
b::Int64 = (Core.getfield)(SSAValue(2), 1)::Int64
#temp#@_6::Int64 = (Core.getfield)(SSAValue(2), 2)::Int64
# meta: location tuple.jl indexed_next 60
unless (#temp#@_6::Int64 === (Base.add_int)((Core.getfield)(SSAValue(0), :stop)::Int64, 1)::Int64)::Bool goto 29
#temp#@_10::Tuple{Int64,Int64} = (Base.throw)($(Expr(:invoke, MethodInstance for BoundsError(::Any, ::Int64), :(Base.BoundsError), SSAValue(0), 3))::BoundsError)::Union{}
goto 31
29:
#temp#@_10::Tuple{Int64,Int64} = (Core.tuple)(#temp#@_6::Int64, (Base.add_int)(#temp#@_6::Int64, 1)::Int64)::Tuple{Int64,Int64}
31:
# meta: pop location
SSAValue(3) = #temp#@_10::Tuple{Int64,Int64}
c::Int64 = (Core.getfield)(SSAValue(3), 1)::Int64
#temp#@_6::Int64 = (Core.getfield)(SSAValue(3), 2)::Int64
# meta: location tuple.jl indexed_next 60
unless (#temp#@_6::Int64 === (Base.add_int)((Core.getfield)(SSAValue(0), :stop)::Int64, 1)::Int64)::Bool goto 40
#temp#@_11::Tuple{Int64,Int64} = (Base.throw)($(Expr(:invoke, MethodInstance for BoundsError(::Any, ::Int64), :(Base.BoundsError), SSAValue(0), 4))::BoundsError)::Union{}
goto 42
40:
#temp#@_11::Tuple{Int64,Int64} = (Core.tuple)(#temp#@_6::Int64, (Base.add_int)(#temp#@_6::Int64, 1)::Int64)::Tuple{Int64,Int64}
42:
# meta: pop location
SSAValue(4) = #temp#@_11::Tuple{Int64,Int64}
d::Int64 = (Core.getfield)(SSAValue(4), 1)::Int64
#temp#@_6::Int64 = (Core.getfield)(SSAValue(4), 2)::Int64
#= line 3 =#
# meta: location /home/mose/.julia/v0.7/StaticArrays/src/linalg.jl * 26
# meta: location broadcast.jl broadcast 434
# meta: location /home/mose/.julia/v0.7/StaticArrays/src/broadcast.jl broadcast_c 33
# meta: location /home/mose/.julia/v0.7/StaticArrays/src/broadcast.jl _broadcast 52
# meta: location /home/mose/.julia/v0.7/StaticArrays/src/broadcast.jl @generated body
#= line 110 =#
SSAValue(25) = (Base.mul_int)((Base.getfield)((Core.getfield)(Main.v1, :data)::Tuple{Int64}, 1, false)::Int64, a::Int64)::Int64
goto 57
# meta: pop location
57:
# meta: pop locations (4)
# meta: location /home/mose/.julia/v0.7/StaticArrays/src/linalg.jl * 26
# meta: location broadcast.jl broadcast 434
# meta: location /home/mose/.julia/v0.7/StaticArrays/src/broadcast.jl broadcast_c 33
# meta: location /home/mose/.julia/v0.7/StaticArrays/src/broadcast.jl _broadcast 52
# meta: location /home/mose/.julia/v0.7/StaticArrays/src/broadcast.jl @generated body
#= line 110 =#
SSAValue(27) = (Base.mul_int)((Base.getfield)((Core.getfield)(Main.v2, :data)::Tuple{Int64}, 1, false)::Int64, b::Int64)::Int64
goto 68
# meta: pop location
68:
# meta: pop locations (4)
# meta: location /home/mose/.julia/v0.7/StaticArrays/src/linalg.jl * 26
# meta: location broadcast.jl broadcast 434
# meta: location /home/mose/.julia/v0.7/StaticArrays/src/broadcast.jl broadcast_c 33
# meta: location /home/mose/.julia/v0.7/StaticArrays/src/broadcast.jl _broadcast 52
# meta: location /home/mose/.julia/v0.7/StaticArrays/src/broadcast.jl @generated body
#= line 110 =#
SSAValue(29) = (Base.mul_int)((Base.getfield)((Core.getfield)(Main.v3, :data)::Tuple{Int64}, 1, false)::Int64, c::Int64)::Int64
goto 79
# meta: pop location
79:
# meta: pop locations (4)
# meta: location /home/mose/.julia/v0.7/StaticArrays/src/linalg.jl * 26
# meta: location broadcast.jl broadcast 434
# meta: location /home/mose/.julia/v0.7/StaticArrays/src/broadcast.jl broadcast_c 33
# meta: location /home/mose/.julia/v0.7/StaticArrays/src/broadcast.jl _broadcast 52
# meta: location /home/mose/.julia/v0.7/StaticArrays/src/broadcast.jl @generated body
#= line 110 =#
#temp#@_12::SVector{1,Int64} = $(Expr(:new, SVector{1,Int64}, :((StaticArrays.tuple)((Base.mul_int)((Base.getfield)((Core.getfield)(Main.v4, :data)::Tuple{Int64}, 1, false)::Int64, d)::Int64)::Tuple{Int64})))
goto 90
# meta: pop location
90:
# meta: pop locations (4)
# meta: location operators.jl + 469
# meta: location /home/mose/.julia/v0.7/StaticArrays/src/linalg.jl + 10
# meta: location /home/mose/.julia/v0.7/StaticArrays/src/mapreduce.jl map 15
# meta: location /home/mose/.julia/v0.7/StaticArrays/src/mapreduce.jl _map 20
# meta: location /home/mose/.julia/v0.7/StaticArrays/src/mapreduce.jl @generated body
#= line 29 =#
SSAValue(21) = (Base.add_int)(SSAValue(25), SSAValue(27))::Int64
goto 101
# meta: pop location
101:
# meta: pop locations (3)
# meta: location /home/mose/.julia/v0.7/StaticArrays/src/linalg.jl + 10
# meta: location /home/mose/.julia/v0.7/StaticArrays/src/mapreduce.jl map 15
# meta: location /home/mose/.julia/v0.7/StaticArrays/src/mapreduce.jl _map 20
# meta: location /home/mose/.julia/v0.7/StaticArrays/src/mapreduce.jl @generated body
#= line 29 =#
SSAValue(23) = (Base.add_int)(SSAValue(21), SSAValue(29))::Int64
goto 111
# meta: pop location
111:
# meta: pop locations (3)
# meta: location operators.jl afoldl 456
# meta: location /home/mose/.julia/v0.7/StaticArrays/src/linalg.jl + 10
# meta: location /home/mose/.julia/v0.7/StaticArrays/src/mapreduce.jl map 15
# meta: location /home/mose/.julia/v0.7/StaticArrays/src/mapreduce.jl _map 20
# meta: location /home/mose/.julia/v0.7/StaticArrays/src/mapreduce.jl @generated body
#= line 29 =#
#temp#@_18::SVector{1,Int64} = $(Expr(:new, SVector{1,Int64}, :((StaticArrays.tuple)((Base.add_int)(SSAValue(23), (Base.getfield)((Core.getfield)(#temp#@_12, :data)::Tuple{Int64}, 1, false)::Int64)::Int64)::Tuple{Int64})))
goto 122
# meta: pop location
122:
# meta: pop locations (5)
return #temp#@_18::SVector{1,Int64}
end::SVector{1,Int64}

First reported at JuliaArrays/StaticArrays.jl#321.

Issue 2:
Updated OP

While working through the issue, @jebej identified that the problem is fusing 12+ broadcasts in this comment (#22255 (comment)) which contains an MWE.

Original OP

In OrdinaryDiffEq.jl, I see a 10x performance regression due to using broadcast. With the testing code:

const ζ = 0.5
const ω₀ = 10.0

using OrdinaryDiffEq, DiffEqBase

const y₀ = Float64[0., sqrt(1-ζ^2)*ω₀]
const A = 1
const ϕ = 0

function f(t::Float64)
α = sqrt(1-ζ^2)*ω₀
x = A*exp(-ζ*ω₀*t)*sin(α*t + ϕ)
p = A*exp(-ζ*ω₀*t)*(-ζ*ω₀*sin(α*t + ϕ) + α*cos(α*t + ϕ))
return [x,p]
end

function df(t::Float64, y::Vector{Float64}, dy::Vector{Float64})
dy[1] = y[2]
dy[2] = -2*ζ*ω₀*y[2] - ω₀^2*y[1]
return nothing
end

const T = [0.,10.]
using BenchmarkTools
prob = ODEProblem(df,y₀,(T[1],T[2]))
@benchmark init($prob,Tsit5(),dense=false,dt=1/10)
@benchmark solve($prob,Tsit5(),dense=false,dt=1/10)

using ProfileView

@profile for i in 1:1000; solve(prob,Tsit5(),dense=false,dt=1/10); end
ProfileView.view()

I get a 10x regression by changing the inner loop from:

function perform_step!(integrator,cache::Tsit5Cache,f=integrator.f)
@unpack t,dt,uprev,u,k = integrator
uidx = eachindex(integrator.uprev)
@unpack c1,c2,c3,c4,c5,c6,a21,a31,a32,a41,a42,a43,a51,a52,a53,a54,a61,a62,a63,a64,a65,a71,a72,a73,a74,a75,a76,b1,b2,b3,b4,b5,b6,b7 = cache.tab
@unpack k1,k2,k3,k4,k5,k6,k7,utilde,tmp,atmp = cache
a = dt*a21
for i in uidx
tmp[i] = @muladd uprev[i]+a*k1[i]
end
f(@muladd(t+c1*dt),tmp,k2)
for i in uidx
tmp[i] = @muladd uprev[i]+dt*(a31*k1[i]+a32*k2[i])
end
f(@muladd(t+c2*dt),tmp,k3)
for i in uidx
tmp[i] = @muladd uprev[i]+dt*(a41*k1[i]+a42*k2[i]+a43*k3[i])
end
f(@muladd(t+c3*dt),tmp,k4)
for i in uidx
tmp[i] = @muladd uprev[i]+dt*(a51*k1[i]+a52*k2[i]+a53*k3[i]+a54*k4[i])
end
f(@muladd(t+c4*dt),tmp,k5)
for i in uidx
tmp[i] = @muladd uprev[i]+dt*(a61*k1[i]+a62*k2[i]+a63*k3[i]+a64*k4[i]+a65*k5[i])
end
f(t+dt,tmp,k6)
for i in uidx
u[i] = @muladd uprev[i]+dt*(a71*k1[i]+a72*k2[i]+a73*k3[i]+a74*k4[i]+a75*k5[i]+a76*k6[i])
end
f(t+dt,u,k7)
if integrator.opts.adaptive
for i in uidx
utilde[i] = @muladd uprev[i] + dt*(b1*k1[i] + b2*k2[i] + b3*k3[i] + b4*k4[i] + b5*k5[i] + b6*k6[i] + b7*k7[i])
atmp[i] = ((utilde[i]-u[i])./@muladd(integrator.opts.abstol+max(abs(uprev[i]),abs(u[i])).*integrator.opts.reltol))
end
integrator.EEst = integrator.opts.internalnorm(atmp)
end
@pack integrator = t,dt,u,k
end

to:

function perform_step!(integrator,cache::Tsit5Cache,f=integrator.f)
@unpack t,dt,uprev,u,k = integrator
@unpack c1,c2,c3,c4,c5,c6,a21,a31,a32,a41,a42,a43,a51,a52,a53,a54,a61,a62,a63,a64,a65,a71,a72,a73,a74,a75,a76,b1,b2,b3,b4,b5,b6,b7 = cache.tab
@unpack k1,k2,k3,k4,k5,k6,k7,utilde,tmp,atmp = cache
a = dt*a21
tmp .= @muladd uprev+a*k1
f(@muladd(t+c1*dt),tmp,k2)
tmp .= @muladd uprev+dt*(a31*k1+a32*k2)
f(@muladd(t+c2*dt),tmp,k3)
tmp .= @muladd uprev+dt*(a41*k1+a42*k2+a43*k3)
f(@muladd(t+c3*dt),tmp,k4)
tmp .= @muladd uprev+dt*(a51*k1+a52*k2+a53*k3+a54*k4)
f(@muladd(t+c4*dt),tmp,k5)
tmp .= @muladd uprev+dt*(a61*k1+a62*k2+a63*k3+a64*k4+a65*k5)
f(t+dt,tmp,k6)
u .= @muladd uprev+dt*(a71*k1+a72*k2+a73*k3+a74*k4+a75*k5+a76*k6)
f(t+dt,u,k7)
if integrator.opts.adaptive
utilde .= @muladd uprev + dt*(b1*k1 + b2*k2 + b3*k3 + b4*k4 + b5*k5 + b6*k6 + b7*k7)
atmp .= ((utilde.-u)./@muladd(integrator.opts.abstol+max.(abs.(uprev),abs.(u)).*integrator.opts.reltol))
integrator.EEst = integrator.opts.internalnorm(atmp)
end
@pack integrator = t,dt,u,k
end

I.e. all that's changed are loops to broadcast. The input array is y0 which is length 2. For reference, the @muladd macro acts like:

println(macroexpand(:(u .= @muladd uprev+dt*(a71*k1+a72*k2+a73*k3+a74*k4+a75*k5+a76*k6))))
#u .= (muladd).(dt, (muladd).(a71, k1, (muladd).(a72, k2, (muladd).(a73, k3, (muladd).(a74, k4, (muladd).(a75, k5, a76 .* k6))))), uprev)

println(macroexpand(:(atmp .= ((utilde.-u)./@muladd(integrator.opts.abstol+max.(abs.(uprev),abs.(u)).*integrator.opts.reltol)))))
#atmp .= (utilde .- u) ./ (muladd).(max.(abs.(uprev), abs.(u)), integrator.opts.reltol, integrator.opts.abstol)

The profile is here: https://ufile.io/2lu0f

The benchmark results are using loops:

BenchmarkTools.Trial:
memory estimate: 87.43 KiB
allocs estimate: 3757
--------------
minimum time: 281.032 μs (0.00% GC)
median time: 526.934 μs (0.00% GC)
mean time: 475.180 μs (2.88% GC)
maximum time: 5.601 ms (87.13% GC)
--------------
samples: 10000
evals/sample: 1

and using broadcast:

BenchmarkTools.Trial:
memory estimate: 854.34 KiB
allocs estimate: 37976
--------------
minimum time: 3.246 ms (0.00% GC)
median time: 6.185 ms (0.00% GC)
mean time: 5.762 ms (2.40% GC)
maximum time: 13.919 ms (26.41% GC)
--------------
samples: 867
evals/sample: 1

Am I hitting some broadcasting splatting penalty or something?