Skip to content

Commit

Permalink
implement with fewer afoldl methods (JuliaLang#39414)
Browse files Browse the repository at this point in the history
With constant-propagation, inference (and Varargs runtime) is likely
better able to handle this version now (and it removes the n^2 behavior
definitions for semi-low argument counts).

Now we also need to force Vararg specialization up to 16 arguments
manually, so we do that explicitly (and slightly hack-y).

Fixes regression in JuliaLang#39175
  • Loading branch information
vtjnash committed Jan 27, 2021
1 parent 527d6b6 commit 5cd1e3e
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 9 deletions.
38 changes: 29 additions & 9 deletions base/operators.jl
Original file line number Diff line number Diff line change
Expand Up @@ -577,17 +577,37 @@ xor(x::Integer) = x

const = xor

# foldl for argument lists. expand recursively up to a point, then
# switch to a loop. this allows small cases like `a+b+c+d` to be inlined
# foldl for argument lists. expand fully up to a point, then
# switch to a loop. this allows small cases like `a+b+c+d` to be managed
# efficiently, without a major slowdown for `+(x...)` when `x` is big.
afoldl(op,a) = a
afoldl(op,a,b) = op(a,b)
afoldl(op,a,b,c...) = afoldl(op, op(a,b), c...)
function afoldl(op,a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,qs...)
y = op(op(op(op(op(op(op(op(op(op(op(op(op(op(op(a,b),c),d),e),f),g),h),i),j),k),l),m),n),o),p)
for x in qs; y = op(y,x); end
y
# n.b.: keep this method count small, so it can be inferred without hitting the
# method count limit in inference
afoldl(op, a) = a
function afoldl(op, a, bs...)
l = length(bs)
i = 0; y = a; l == i && return y
#@nexprs 15 i -> (y = op(y, bs[i]); l == i && return y)
i = 1; y = op(y, bs[i]); l == i && return y
i = 2; y = op(y, bs[i]); l == i && return y
i = 3; y = op(y, bs[i]); l == i && return y
i = 4; y = op(y, bs[i]); l == i && return y
i = 5; y = op(y, bs[i]); l == i && return y
i = 6; y = op(y, bs[i]); l == i && return y
i = 7; y = op(y, bs[i]); l == i && return y
i = 8; y = op(y, bs[i]); l == i && return y
i = 9; y = op(y, bs[i]); l == i && return y
i = 10; y = op(y, bs[i]); l == i && return y
i = 11; y = op(y, bs[i]); l == i && return y
i = 12; y = op(y, bs[i]); l == i && return y
i = 13; y = op(y, bs[i]); l == i && return y
i = 14; y = op(y, bs[i]); l == i && return y
i = 15; y = op(y, bs[i]); l == i && return y
for i in (i + 1):l
y = op(y, bs[i])
end
return y
end
typeof(afoldl).name.mt.max_args = 18

for op in (:+, :*, :&, :|, :xor, :min, :max, :kron)
@eval begin
Expand Down
2 changes: 2 additions & 0 deletions test/operators.jl
Original file line number Diff line number Diff line change
Expand Up @@ -277,3 +277,5 @@ end

a = rand(3, 3)
@test transpose(a) === a'

@test [Base.afoldl(+, 1:i...) for i = 1:40] == [i * (i + 1) ÷ 2 for i = 1:40]

0 comments on commit 5cd1e3e

Please sign in to comment.