From cfe00782808f30bb84076a49b083b102dd419f64 Mon Sep 17 00:00:00 2001 From: Shuhei Kadowaki Date: Sat, 11 Sep 2021 16:17:11 +0900 Subject: [PATCH] add supports for new `@inline` and `@noinline` features xrefs: - - Built on top of . --- README.md | 6 ++++++ src/Compat.jl | 44 ++++++++++++++++++++++++++++++++++++++++++++ test/runtests.jl | 41 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 91 insertions(+) diff --git a/README.md b/README.md index 6f14b2385..2e1d6dfd4 100644 --- a/README.md +++ b/README.md @@ -54,6 +54,10 @@ changes in `julia`. ## Supported features +* `Compat.@inline` and `Compat.@noinline` can be used at function callsites to encourage the compiler to (not) inline the function calls on Julia versions that support these features, and otherwise do not have any effects ([#41312]) (since Compat 3.36) + +* `Compat.@inline` and `Compat.@noinline` can be used within function body to hint to the compiler the inlineability of the defined function ([#41312]) (since Compat 3.36) + * `Compat.@constprop :aggressive ex` and `Compat.@constprop :none ex` allow control over constant-propagation during inference on Julia versions that support this feature, and otherwise just pass back `ex`. ([#42125]) (since Compat 3.36) * `Returns(value)` returns `value` for any arguments ([#39794]) (since Compat 3.35) @@ -276,3 +280,5 @@ Note that you should specify the correct minimum version for `Compat` in the [#34331]: https://github.com/JuliaLang/julia/pull/34331 [#39794]: https://github.com/JuliaLang/julia/pull/39794 [#42125]: https://github.com/JuliaLang/julia/pull/42125 +[#41312]: https://github.com/JuliaLang/julia/pull/41312 +[#41328]: https://github.com/JuliaLang/julia/pull/41328 diff --git a/src/Compat.jl b/src/Compat.jl index b88961e31..250af0a8a 100644 --- a/src/Compat.jl +++ b/src/Compat.jl @@ -8,6 +8,50 @@ using LinearAlgebra: Adjoint, Diagonal, Transpose, UniformScaling, RealHermSymCo include("compatmacro.jl") +# NOTE these `@inline` and `@noinline` definitions overwrite the definitions implicitly +# imported from Base and so should happen before any usages of them within this module + +# https://github.com/JuliaLang/julia/pull/41312: `@inline`/`@noinline` annotations within a function body +@static if !hasmethod(getfield(Base, Symbol("@inline")), (LineNumberNode,Module)) + macro inline() Expr(:meta, :inline) end + macro noinline() Expr(:meta, :noinline) end +end + +# https://github.com/JuliaLang/julia/pull/41328: callsite annotations of inlining +@static if !isdefined(Base, :annotate_meta_def_or_block) + macro inline(ex) annotate_meta_def_or_nothing(ex, :inline) end + macro noinline(ex) annotate_meta_def_or_nothing(ex, :noinline) end + function annotate_meta_def_or_nothing(@nospecialize(ex), meta::Symbol) + inner = unwrap_macrocalls(ex) + if is_function_def(inner) + # annotation on a definition + return esc(Base.pushmeta!(ex, meta)) + else + # do nothing + return esc(ex) + end + end + unwrap_macrocalls(@nospecialize(x)) = x + function unwrap_macrocalls(ex::Expr) + inner = ex + while inner.head === :macrocall + inner = inner.args[end]::Expr + end + return inner + end + is_function_def(@nospecialize(ex)) = + return Meta.isexpr(ex, :function) || is_short_function_def(ex) || Meta.isexpr(ex, :->) + function is_short_function_def(@nospecialize(ex)) + Meta.isexpr(ex, :(=)) || return false + while length(ex.args) >= 1 && isa(ex.args[1], Expr) + (ex.args[1].head === :call) && return true + (ex.args[1].head === :where || ex.args[1].head === :(::)) || return false + ex = ex.args[1] + end + return false + end +end + # https://github.com/JuliaLang/julia/pull/29440 if VERSION < v"1.1.0-DEV.389" Base.:(:)(I::CartesianIndex{N}, J::CartesianIndex{N}) where N = diff --git a/test/runtests.jl b/test/runtests.jl index 00c934bda..e8bff1b94 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1171,3 +1171,44 @@ end ) @test aggf("hi") == nonef("hi") == :hi end + +# https://github.com/JuliaLang/julia/pull/41312 +@testset "`@inline`/`@noinline` annotations within a function body" begin + callf(f, args...) = f(args...) + function foo1(a) + Compat.@inline + sum(sincos(a)) + end + foo2(a) = (Compat.@inline; sum(sincos(a))) + foo3(a) = callf(a) do a + Compat.@inline + sum(sincos(a)) + end + function foo4(a) + Compat.@noinline + sum(sincos(a)) + end + foo5(a) = (Compat.@noinline; sum(sincos(a))) + foo6(a) = callf(a) do a + Compat.@noinline + sum(sincos(a)) + end + + @test foo1(42) == foo2(42) == foo3(42) == foo4(42) == foo5(42) == foo6(42) +end + +# https://github.com/JuliaLang/julia/pull/41328 +@testset "callsite annotations of inlining" begin + function foo1(a) + Compat.@inline begin + return sum(sincos(a)) + end + end + function foo2(a) + Compat.@noinline begin + return sum(sincos(a)) + end + end + + @test foo1(42) == foo2(42) +end