-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
optimizer: support callsite annotations of @inline
and @noinline
#40754
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would be great to also add callsite inlining in one go.
Yes, I would like to take a stab at callsite inlining after I finish the noinline, but callsite inlining is a little bit more complicated(although it would probably be more useful to more people) so I figured I would get noinline working first |
Just fixed problems with previous commit, julia> @inline inlined(x) = x
inlined (generic function with 1 method)
julia> call_inlined(x) = inlined(x)
call_inlined (generic function with 1 method)
julia> code_llvm(call_inlined, (Int, )) ; @ REPL[2]:1 within `call_inlined'
define i64 @julia_call_inlined_112(i64 signext %0) #0 {
top:
ret i64 %0
} julia> override_inlined(x) = @noinline inlined(x)
override_inlined (generic function with 1 method) julia> code_llvm(override_inlined, (Int, ))
; @ REPL[4]:1 within `override_inlined'
define i64 @julia_override_inlined_148(i64 signext %0) #0 {
top:
%1 = call i64 @j_inlined_150(i64 signext %0) #0
ret i64 %1
} |
@noinline
to work at a function callsite@noinline
to work at a function callsite
Will the call-site |
Yes the idea is to give the user the ability to opt out of inlining for any function call |
Can you add a test that ensures it overrides it then? (and probably adding tests for the other cases would be best as well - since I don't see any new tests added in here). |
Added :noinline as a meta expression head Added the IR_FLAG_NOINLINE flag added check for :noinline in convert_to_ircode assemble_inline_todo now skips inlining if the no inline flag is set @noinline check if being invoked at callsite or definition. Fixed typo Added tests to `@noinline` at callsite
Alright, I've added two tests, one to make sure we can overwrite |
This is an interesting case - is only inlining the first call a reasonable expectation to make, or would people be more likely to assume that everything in that statement won't be inlined (e.g. the calls to both I did a quick test with another simple construct (call chaining), and I think this behavior might also be somewhat surprising to people:
The Do any other languages have callsite inlining prevention that we can compare this behavior against?
That would probably be a good thing to add. |
I just found out the Intel Fortran Compiler has a very similar ability( see here) and inlines everything in the statement. My initial reasoning was that putting
It does seem like this approach might be the way to go as it would probably avoid confusion, especially since it also mirrors the behavior of the |
What should @noinline f() do
body
end do? Is it equivalent to (1) noinlined call g() = body
@noinline f(g) (2) noinlined do block @noinline g() = body
f(g) (3) both @noinline g() = body
@noinline f(g) ? Also, what about the calls inside the I think (1) is the most flexible (so no change in this PR, IIUC) and then provide no-arg version of @noinline f() do
@inline
body
end is equivalent to @inline g() = body
@noinline f(g) Or maybe extend the grammar to allow pre- @noinline f() @inline do
body
end ? A Ref #35116 |
Not sure if this part is out of the scope of this pull request, but I agree it would be nice to have this, so I just added your suggestion. to have As for the two different syntaxes, I'm actually not sure which one would be better. Would having the macro on the line after the @noinline f() @inline do
body
end vs @noinline f() do
@inline
body
end
? As of right now, @noinline f() do
body
end
is equivalent to g() = body
@noinline f(g)
where |
Thanks, yes, no-arg |
@noinline
to work at a function callsite@noinline
to work at a function callsite and both @noinline
and @inline
to work in do
blocks
I'll add a few tests soon but I don't think this pr would conflict with other meta macros. One effect of making this change is that I believe this syntax julia> function f(x)
@noinline
body
end will now be functionally equivalent to julia> @noinline function f(x)
body
end Is this desired? My guess is this is probably fine since both notations are pretty clear |
this, this , and this indicate that adding a This is an example of argument-less julia> function a(x)
@noinline
@nospecialize
x
end
a (generic function with 1 method)
julia> a("string")
"string"
julia> a(3.0)
3.0
julia> a(3)
3
julia> using MethodAnalysis
julia> methodinstances(a)
1-element Vector{Core.MethodInstance}:
MethodInstance for a(::Any)
julia> b(x) = a(x)
b (generic function with 1 method)
julia> code_typed(b, Tuple{Int})
1-element Vector{Any}:
CodeInfo(
1 ─ %1 = invoke Main.a(_2::Any)::Int64
└── return %1
) => Int64
|
Ah, thanks. I'm kinda puzzled that the meta macros to try to "pack" things in the meta expr julia> @macroexpand Base.@pure Base.@propagate_inbounds f() = nothing
:(f() = begin
$(Expr(:meta, :pure, :inline, :propagate_inbounds))
#= REPL[6]:1 =#
nothing
end)
julia> @macroexpand function f()
Base.@_pure_meta
Base.@_propagate_inbounds_meta
end
:(function f()
#= REPL[7]:1 =#
#= REPL[7]:2 =#
$(Expr(:meta, :pure))
#= REPL[7]:3 =#
$(Expr(:meta, :inline, :propagate_inbounds))
end) Though I agree that the code locations you quoted indicate that they can handle multiple meta exprs. |
I'm not exactly sure why this mechanism would be necessary either. I think it was a style choice to try to contain all the |
Slightly unrelated but do I need to change anything since the buildbot fails the |
@noinline
to work at a function callsite and both @noinline
and @inline
to work in do
blocks@noinline
to work at a function callsite and both @noinline
and @inline
to work in do
blocks
…1312) * supports `@inline`/`@noinline` annotations within a function body Separated from #40754 for the sake of easier review. The primary motivation for this change is to annotate `@inline`/`@noinline` to anonymous functions created from `do` block: ```julia f() do @inline # makes this anonymous function to be inlined ... # function body end ``` We can extend the grammar so that we have special "declaration-macro" supports for `do`-block functions like: ```julia f() @inline do # makes this anonymous function to be inlined ... # function body end ``` but I'm not sure which one is better. Following [the earlier discussion](#40754 (comment)), this commit implements the easiest solution. Co-authored-by: Joseph Tan <[email protected]> * Update base/expr.jl * Update base/expr.jl * Update NEWS.md Co-authored-by: Joseph Tan <[email protected]>
Enable `@inline`/`@noinline` annotations on function callsites. From #40754. Now `@inline` and `@noinline` can be applied to a code block and then the compiler will try to (not) inline calls within the block: ```julia @inline f(...) @noinline f(...) + g(...) @inline f(args...) = ... ``` Here are couple of notes on how those callsite annotations will work: - callsite annotation always has the precedence over the annotation applied to the definition of the called function, whichever we use `@inline`/`@noinline`: ```julia @inline function explicit_inline(args...) # body end let @noinline explicit_inline(args...) # this call will not be inlined end ``` - when callsite annotations are nested, the innermost annotations has the precedence ```julia @noinline let a0, b0 = ... a = @inline f(a0) # the compiler will try to inline this call b = notinlined(b0) # the compiler will NOT try to inline this call return a, b end ``` They're both tested and included in documentations. Co-authored-by: Joseph Tan <[email protected]>
Enable `@inline`/`@noinline` annotations on function callsites. From #40754. Now `@inline` and `@noinline` can be applied to a code block and then the compiler will try to (not) inline calls within the block: ```julia @inline f(...) # The compiler will try to inline `f` @inline f(...) + g(...) # The compiler will try to inline `f`, `g` and `+` @inline f(args...) = ... # Of course annotations on a definition is still allowed ``` Here are couple of notes on how those callsite annotations will work: - callsite annotation always has the precedence over the annotation applied to the definition of the called function, whichever we use `@inline`/`@noinline`: ```julia @inline function explicit_inline(args...) # body end let @noinline explicit_inline(args...) # this call will not be inlined end ``` - when callsite annotations are nested, the innermost annotations has the precedence ```julia @noinline let a0, b0 = ... a = @inline f(a0) # the compiler will try to inline this call b = notinlined(b0) # the compiler will NOT try to inline this call return a, b end ``` They're both tested and included in documentations. Co-authored-by: Joseph Tan <[email protected]>
In that case, should this be closed? |
Yea I think that would make sense. I'll close it |
Enable `@inline`/`@noinline` annotations on function callsites. From #40754. Now `@inline` and `@noinline` can be applied to a code block and then the compiler will try to (not) inline calls within the block: ```julia @inline f(...) # The compiler will try to inline `f` @inline f(...) + g(...) # The compiler will try to inline `f`, `g` and `+` @inline f(args...) = ... # Of course annotations on a definition is still allowed ``` Here are couple of notes on how those callsite annotations will work: - callsite annotation always has the precedence over the annotation applied to the definition of the called function, whichever we use `@inline`/`@noinline`: ```julia @inline function explicit_inline(args...) # body end let @noinline explicit_inline(args...) # this call will not be inlined end ``` - when callsite annotations are nested, the innermost annotations has the precedence ```julia @noinline let a0, b0 = ... a = @inline f(a0) # the compiler will try to inline this call b = notinlined(b0) # the compiler will NOT try to inline this call return a, b end ``` They're both tested and included in documentations. Co-Authored-By: Joseph Tan <[email protected]>
Enable `@inline`/`@noinline` annotations on function callsites. From #40754. Now `@inline` and `@noinline` can be applied to a code block and then the compiler will try to (not) inline calls within the block: ```julia @inline f(...) # The compiler will try to inline `f` @inline f(...) + g(...) # The compiler will try to inline `f`, `g` and `+` @inline f(args...) = ... # Of course annotations on a definition is still allowed ``` Here are couple of notes on how those callsite annotations will work: - callsite annotation always has the precedence over the annotation applied to the definition of the called function, whichever we use `@inline`/`@noinline`: ```julia @inline function explicit_inline(args...) # body end let @noinline explicit_inline(args...) # this call will not be inlined end ``` - when callsite annotations are nested, the innermost annotations has the precedence ```julia @noinline let a0, b0 = ... a = @inline f(a0) # the compiler will try to inline this call b = notinlined(b0) # the compiler will NOT try to inline this call return a, b end ``` They're both tested and included in documentations. Co-Authored-By: Joseph Tan <[email protected]>
Enable `@inline`/`@noinline` annotations on function callsites. From #40754. Now `@inline` and `@noinline` can be applied to a code block and then the compiler will try to (not) inline calls within the block: ```julia @inline f(...) # The compiler will try to inline `f` @inline f(...) + g(...) # The compiler will try to inline `f`, `g` and `+` @inline f(args...) = ... # Of course annotations on a definition is still allowed ``` Here are couple of notes on how those callsite annotations will work: - callsite annotation always has the precedence over the annotation applied to the definition of the called function, whichever we use `@inline`/`@noinline`: ```julia @inline function explicit_inline(args...) # body end let @noinline explicit_inline(args...) # this call will not be inlined end ``` - when callsite annotations are nested, the innermost annotations has the precedence ```julia @noinline let a0, b0 = ... a = @inline f(a0) # the compiler will try to inline this call b = notinlined(b0) # the compiler will NOT try to inline this call return a, b end ``` They're both tested and included in documentations. Co-Authored-By: Joseph Tan <[email protected]>
Enable `@inline`/`@noinline` annotations on function callsites. From #40754. Now `@inline` and `@noinline` can be applied to a code block and then the compiler will try to (not) inline calls within the block: ```julia @inline f(...) # The compiler will try to inline `f` @inline f(...) + g(...) # The compiler will try to inline `f`, `g` and `+` @inline f(args...) = ... # Of course annotations on a definition is still allowed ``` Here are couple of notes on how those callsite annotations will work: - callsite annotation always has the precedence over the annotation applied to the definition of the called function, whichever we use `@inline`/`@noinline`: ```julia @inline function explicit_inline(args...) # body end let @noinline explicit_inline(args...) # this call will not be inlined end ``` - when callsite annotations are nested, the innermost annotations has the precedence ```julia @noinline let a0, b0 = ... a = @inline f(a0) # the compiler will try to inline this call b = notinlined(b0) # the compiler will NOT try to inline this call return a, b end ``` They're both tested and included in documentations.
Enable `@inline`/`@noinline` annotations on function callsites. From #40754. Now `@inline` and `@noinline` can be applied to a code block and then the compiler will try to (not) inline calls within the block: ```julia @inline f(...) # The compiler will try to inline `f` @inline f(...) + g(...) # The compiler will try to inline `f`, `g` and `+` @inline f(args...) = ... # Of course annotations on a definition is still allowed ``` Here are couple of notes on how those callsite annotations will work: - callsite annotation always has the precedence over the annotation applied to the definition of the called function, whichever we use `@inline`/`@noinline`: ```julia @inline function explicit_inline(args...) # body end let @noinline explicit_inline(args...) # this call will not be inlined end ``` - when callsite annotations are nested, the innermost annotations has the precedence ```julia @noinline let a0, b0 = ... a = @inline f(a0) # the compiler will try to inline this call b = notinlined(b0) # the compiler will NOT try to inline this call return a, b end ``` They're both tested and included in documentations.
…liaLang#41312) * supports `@inline`/`@noinline` annotations within a function body Separated from JuliaLang#40754 for the sake of easier review. The primary motivation for this change is to annotate `@inline`/`@noinline` to anonymous functions created from `do` block: ```julia f() do @inline # makes this anonymous function to be inlined ... # function body end ``` We can extend the grammar so that we have special "declaration-macro" supports for `do`-block functions like: ```julia f() @inline do # makes this anonymous function to be inlined ... # function body end ``` but I'm not sure which one is better. Following [the earlier discussion](JuliaLang#40754 (comment)), this commit implements the easiest solution. Co-authored-by: Joseph Tan <[email protected]> * Update base/expr.jl * Update base/expr.jl * Update NEWS.md Co-authored-by: Joseph Tan <[email protected]>
Enable `@inline`/`@noinline` annotations on function callsites. From #40754. Now `@inline` and `@noinline` can be applied to a code block and then the compiler will try to (not) inline calls within the block: ```julia @inline f(...) # The compiler will try to inline `f` @inline f(...) + g(...) # The compiler will try to inline `f`, `g` and `+` @inline f(args...) = ... # Of course annotations on a definition is still allowed ``` Here are couple of notes on how those callsite annotations will work: - callsite annotation always has the precedence over the annotation applied to the definition of the called function, whichever we use `@inline`/`@noinline`: ```julia @inline function explicit_inline(args...) # body end let @noinline explicit_inline(args...) # this call will not be inlined end ``` - when callsite annotations are nested, the innermost annotations has the precedence ```julia @noinline let a0, b0 = ... a = @inline f(a0) # the compiler will try to inline this call b = notinlined(b0) # the compiler will NOT try to inline this call return a, b end ``` They're both tested and included in documentations.
Enable `@inline`/`@noinline` annotations on function callsites. From #40754. Now `@inline` and `@noinline` can be applied to a code block and then the compiler will try to (not) inline calls within the block: ```julia @inline f(...) # The compiler will try to inline `f` @inline f(...) + g(...) # The compiler will try to inline `f`, `g` and `+` @inline f(args...) = ... # Of course annotations on a definition is still allowed ``` Here are couple of notes on how those callsite annotations will work: - callsite annotation always has the precedence over the annotation applied to the definition of the called function, whichever we use `@inline`/`@noinline`: ```julia @inline function explicit_inline(args...) # body end let @noinline explicit_inline(args...) # this call will not be inlined end ``` - when callsite annotations are nested, the innermost annotations has the precedence ```julia @noinline let a0, b0 = ... a = @inline f(a0) # the compiler will try to inline this call b = notinlined(b0) # the compiler will NOT try to inline this call return a, b end ``` They're both tested and included in documentations.
Enable `@inline`/`@noinline` annotations on function callsites. From #40754. Now `@inline` and `@noinline` can be applied to a code block and then the compiler will try to (not) inline calls within the block: ```julia @inline f(...) # The compiler will try to inline `f` @inline f(...) + g(...) # The compiler will try to inline `f`, `g` and `+` @inline f(args...) = ... # Of course annotations on a definition is still allowed ``` Here are couple of notes on how those callsite annotations will work: - callsite annotation always has the precedence over the annotation applied to the definition of the called function, whichever we use `@inline`/`@noinline`: ```julia @inline function explicit_inline(args...) # body end let @noinline explicit_inline(args...) # this call will not be inlined end ``` - when callsite annotations are nested, the innermost annotations has the precedence ```julia @noinline let a0, b0 = ... a = @inline f(a0) # the compiler will try to inline this call b = notinlined(b0) # the compiler will NOT try to inline this call return a, b end ``` They're both tested and included in documentations.
Enable `@inline`/`@noinline` annotations on function callsites. From #40754. Now `@inline` and `@noinline` can be applied to a code block and then the compiler will try to (not) inline calls within the block: ```julia @inline f(...) # The compiler will try to inline `f` @inline f(...) + g(...) # The compiler will try to inline `f`, `g` and `+` @inline f(args...) = ... # Of course annotations on a definition is still allowed ``` Here are couple of notes on how those callsite annotations will work: - callsite annotation always has the precedence over the annotation applied to the definition of the called function, whichever we use `@inline`/`@noinline`: ```julia @inline function explicit_inline(args...) # body end let @noinline explicit_inline(args...) # this call will not be inlined end ``` - when callsite annotations are nested, the innermost annotations has the precedence ```julia @noinline let a0, b0 = ... a = @inline f(a0) # the compiler will try to inline this call b = notinlined(b0) # the compiler will NOT try to inline this call return a, b end ``` They're both tested and included in documentations.
Enable `@inline`/`@noinline` annotations on function callsites. From #40754. Now `@inline` and `@noinline` can be applied to a code block and then the compiler will try to (not) inline calls within the block: ```julia @inline f(...) # The compiler will try to inline `f` @inline f(...) + g(...) # The compiler will try to inline `f`, `g` and `+` @inline f(args...) = ... # Of course annotations on a definition is still allowed ``` Here are couple of notes on how those callsite annotations will work: - callsite annotation always has the precedence over the annotation applied to the definition of the called function, whichever we use `@inline`/`@noinline`: ```julia @inline function explicit_inline(args...) # body end let @noinline explicit_inline(args...) # this call will not be inlined end ``` - when callsite annotations are nested, the innermost annotations has the precedence ```julia @noinline let a0, b0 = ... a = @inline f(a0) # the compiler will try to inline this call b = notinlined(b0) # the compiler will NOT try to inline this call return a, b end ``` They're both tested and included in documentations.
Enable `@inline`/`@noinline` annotations on function callsites. From #40754. Now `@inline` and `@noinline` can be applied to a code block and then the compiler will try to (not) inline calls within the block: ```julia @inline f(...) # The compiler will try to inline `f` @inline f(...) + g(...) # The compiler will try to inline `f`, `g` and `+` @inline f(args...) = ... # Of course annotations on a definition is still allowed ``` Here are couple of notes on how those callsite annotations will work: - callsite annotation always has the precedence over the annotation applied to the definition of the called function, whichever we use `@inline`/`@noinline`: ```julia @inline function explicit_inline(args...) # body end let @noinline explicit_inline(args...) # this call will not be inlined end ``` - when callsite annotations are nested, the innermost annotations has the precedence ```julia @noinline let a0, b0 = ... a = @inline f(a0) # the compiler will try to inline this call b = notinlined(b0) # the compiler will NOT try to inline this call return a, b end ``` They're both tested and included in documentations.
Enable `@inline`/`@noinline` annotations on function callsites. From #40754. Now `@inline` and `@noinline` can be applied to a code block and then the compiler will try to (not) inline calls within the block: ```julia @inline f(...) # The compiler will try to inline `f` @inline f(...) + g(...) # The compiler will try to inline `f`, `g` and `+` @inline f(args...) = ... # Of course annotations on a definition is still allowed ``` Here are couple of notes on how those callsite annotations will work: - callsite annotation always has the precedence over the annotation applied to the definition of the called function, whichever we use `@inline`/`@noinline`: ```julia @inline function explicit_inline(args...) # body end let @noinline explicit_inline(args...) # this call will not be inlined end ``` - when callsite annotations are nested, the innermost annotations has the precedence ```julia @noinline let a0, b0 = ... a = @inline f(a0) # the compiler will try to inline this call b = notinlined(b0) # the compiler will NOT try to inline this call return a, b end ``` They're both tested and included in documentations.
Enable `@inline`/`@noinline` annotations on function callsites. From #40754. Now `@inline` and `@noinline` can be applied to a code block and then the compiler will try to (not) inline calls within the block: ```julia @inline f(...) # The compiler will try to inline `f` @inline f(...) + g(...) # The compiler will try to inline `f`, `g` and `+` @inline f(args...) = ... # Of course annotations on a definition is still allowed ``` Here are couple of notes on how those callsite annotations will work: - callsite annotation always has the precedence over the annotation applied to the definition of the called function, whichever we use `@inline`/`@noinline`: ```julia @inline function explicit_inline(args...) # body end let @noinline explicit_inline(args...) # this call will not be inlined end ``` - when callsite annotations are nested, the innermost annotations has the precedence ```julia @noinline let a0, b0 = ... a = @inline f(a0) # the compiler will try to inline this call b = notinlined(b0) # the compiler will NOT try to inline this call return a, b end ``` They're both tested and included in documentations.
Enable `@inline`/`@noinline` annotations on function callsites. From #40754. Now `@inline` and `@noinline` can be applied to a code block and then the compiler will try to (not) inline calls within the block: ```julia @inline f(...) # The compiler will try to inline `f` @inline f(...) + g(...) # The compiler will try to inline `f`, `g` and `+` @inline f(args...) = ... # Of course annotations on a definition is still allowed ``` Here are couple of notes on how those callsite annotations will work: - callsite annotation always has the precedence over the annotation applied to the definition of the called function, whichever we use `@inline`/`@noinline`: ```julia @inline function explicit_inline(args...) # body end let @noinline explicit_inline(args...) # this call will not be inlined end ``` - when callsite annotations are nested, the innermost annotations has the precedence ```julia @noinline let a0, b0 = ... a = @inline f(a0) # the compiler will try to inline this call b = notinlined(b0) # the compiler will NOT try to inline this call return a, b end ``` They're both tested and included in documentations.
Enable `@inline`/`@noinline` annotations on function callsites. From #40754. Now `@inline` and `@noinline` can be applied to a code block and then the compiler will try to (not) inline calls within the block: ```julia @inline f(...) # The compiler will try to inline `f` @inline f(...) + g(...) # The compiler will try to inline `f`, `g` and `+` @inline f(args...) = ... # Of course annotations on a definition is still allowed ``` Here are couple of notes on how those callsite annotations will work: - callsite annotation always has the precedence over the annotation applied to the definition of the called function, whichever we use `@inline`/`@noinline`: ```julia @inline function explicit_inline(args...) # body end let @noinline explicit_inline(args...) # this call will not be inlined end ``` - when callsite annotations are nested, the innermost annotations has the precedence ```julia @noinline let a0, b0 = ... a = @inline f(a0) # the compiler will try to inline this call b = notinlined(b0) # the compiler will NOT try to inline this call return a, b end ``` They're both tested and included in documentations.
Enable `@inline`/`@noinline` annotations on function callsites. From #40754. Now `@inline` and `@noinline` can be applied to a code block and then the compiler will try to (not) inline calls within the block: ```julia @inline f(...) # The compiler will try to inline `f` @inline f(...) + g(...) # The compiler will try to inline `f`, `g` and `+` @inline f(args...) = ... # Of course annotations on a definition is still allowed ``` Here are couple of notes on how those callsite annotations will work: - callsite annotation always has the precedence over the annotation applied to the definition of the called function, whichever we use `@inline`/`@noinline`: ```julia @inline function explicit_inline(args...) # body end let @noinline explicit_inline(args...) # this call will not be inlined end ``` - when callsite annotations are nested, the innermost annotations has the precedence ```julia @noinline let a0, b0 = ... a = @inline f(a0) # the compiler will try to inline this call b = notinlined(b0) # the compiler will NOT try to inline this call return a, b end ``` They're both tested and included in documentations.
Enable `@inline`/`@noinline` annotations on function callsites. From #40754. Now `@inline` and `@noinline` can be applied to a code block and then the compiler will try to (not) inline calls within the block: ```julia @inline f(...) # The compiler will try to inline `f` @inline f(...) + g(...) # The compiler will try to inline `f`, `g` and `+` @inline f(args...) = ... # Of course annotations on a definition is still allowed ``` Here are couple of notes on how those callsite annotations will work: - callsite annotation always has the precedence over the annotation applied to the definition of the called function, whichever we use `@inline`/`@noinline`: ```julia @inline function explicit_inline(args...) # body end let @noinline explicit_inline(args...) # this call will not be inlined end ``` - when callsite annotations are nested, the innermost annotations has the precedence ```julia @noinline let a0, b0 = ... a = @inline f(a0) # the compiler will try to inline this call b = notinlined(b0) # the compiler will NOT try to inline this call return a, b end ``` They're both tested and included in documentations.
Enable `@inline`/`@noinline` annotations on function callsites. From #40754. Now `@inline` and `@noinline` can be applied to a code block and then the compiler will try to (not) inline calls within the block: ```julia @inline f(...) # The compiler will try to inline `f` @inline f(...) + g(...) # The compiler will try to inline `f`, `g` and `+` @inline f(args...) = ... # Of course annotations on a definition is still allowed ``` Here are couple of notes on how those callsite annotations will work: - callsite annotation always has the precedence over the annotation applied to the definition of the called function, whichever we use `@inline`/`@noinline`: ```julia @inline function explicit_inline(args...) # body end let @noinline explicit_inline(args...) # this call will not be inlined end ``` - when callsite annotations are nested, the innermost annotations has the precedence ```julia @noinline let a0, b0 = ... a = @inline f(a0) # the compiler will try to inline this call b = notinlined(b0) # the compiler will NOT try to inline this call return a, b end ``` They're both tested and included in documentations.
…41328) * optimizer: supports callsite annotations of inlining, fixes #18773 Enable `@inline`/`@noinline` annotations on function callsites. From #40754. Now `@inline` and `@noinline` can be applied to a code block and then the compiler will try to (not) inline calls within the block: ```julia @inline f(...) # The compiler will try to inline `f` @inline f(...) + g(...) # The compiler will try to inline `f`, `g` and `+` @inline f(args...) = ... # Of course annotations on a definition is still allowed ``` Here are couple of notes on how those callsite annotations will work: - callsite annotation always has the precedence over the annotation applied to the definition of the called function, whichever we use `@inline`/`@noinline`: ```julia @inline function explicit_inline(args...) # body end let @noinline explicit_inline(args...) # this call will not be inlined end ``` - when callsite annotations are nested, the innermost annotations has the precedence ```julia @noinline let a0, b0 = ... a = @inline f(a0) # the compiler will try to inline this call b = notinlined(b0) # the compiler will NOT try to inline this call return a, b end ``` They're both tested and included in documentations. * set ssaflags on `CodeInfo` construction * try to keep source if it will be force-inlined * give inlining when source isn't available * style nits * Update base/compiler/ssair/inlining.jl Co-authored-by: Jameson Nash <[email protected]> * Update src/method.c Co-authored-by: Jameson Nash <[email protected]> * fixup - remove preprocessed flags from `jl_code_info_set_ir` - fix duplicated definition warning - add and fix comments * more clean up * add caveat about the recursive call limitation * update NEWS.md Co-authored-by: Jameson Nash <[email protected]>
…#18773 (JuliaLang#41328) * optimizer: supports callsite annotations of inlining, fixes JuliaLang#18773 Enable `@inline`/`@noinline` annotations on function callsites. From JuliaLang#40754. Now `@inline` and `@noinline` can be applied to a code block and then the compiler will try to (not) inline calls within the block: ```julia @inline f(...) # The compiler will try to inline `f` @inline f(...) + g(...) # The compiler will try to inline `f`, `g` and `+` @inline f(args...) = ... # Of course annotations on a definition is still allowed ``` Here are couple of notes on how those callsite annotations will work: - callsite annotation always has the precedence over the annotation applied to the definition of the called function, whichever we use `@inline`/`@noinline`: ```julia @inline function explicit_inline(args...) # body end let @noinline explicit_inline(args...) # this call will not be inlined end ``` - when callsite annotations are nested, the innermost annotations has the precedence ```julia @noinline let a0, b0 = ... a = @inline f(a0) # the compiler will try to inline this call b = notinlined(b0) # the compiler will NOT try to inline this call return a, b end ``` They're both tested and included in documentations. * set ssaflags on `CodeInfo` construction * try to keep source if it will be force-inlined * give inlining when source isn't available * style nits * Update base/compiler/ssair/inlining.jl Co-authored-by: Jameson Nash <[email protected]> * Update src/method.c Co-authored-by: Jameson Nash <[email protected]> * fixup - remove preprocessed flags from `jl_code_info_set_ir` - fix duplicated definition warning - add and fix comments * more clean up * add caveat about the recursive call limitation * update NEWS.md Co-authored-by: Jameson Nash <[email protected]>
…#18773 (JuliaLang#41328) * optimizer: supports callsite annotations of inlining, fixes JuliaLang#18773 Enable `@inline`/`@noinline` annotations on function callsites. From JuliaLang#40754. Now `@inline` and `@noinline` can be applied to a code block and then the compiler will try to (not) inline calls within the block: ```julia @inline f(...) # The compiler will try to inline `f` @inline f(...) + g(...) # The compiler will try to inline `f`, `g` and `+` @inline f(args...) = ... # Of course annotations on a definition is still allowed ``` Here are couple of notes on how those callsite annotations will work: - callsite annotation always has the precedence over the annotation applied to the definition of the called function, whichever we use `@inline`/`@noinline`: ```julia @inline function explicit_inline(args...) # body end let @noinline explicit_inline(args...) # this call will not be inlined end ``` - when callsite annotations are nested, the innermost annotations has the precedence ```julia @noinline let a0, b0 = ... a = @inline f(a0) # the compiler will try to inline this call b = notinlined(b0) # the compiler will NOT try to inline this call return a, b end ``` They're both tested and included in documentations. * set ssaflags on `CodeInfo` construction * try to keep source if it will be force-inlined * give inlining when source isn't available * style nits * Update base/compiler/ssair/inlining.jl Co-authored-by: Jameson Nash <[email protected]> * Update src/method.c Co-authored-by: Jameson Nash <[email protected]> * fixup - remove preprocessed flags from `jl_code_info_set_ir` - fix duplicated definition warning - add and fix comments * more clean up * add caveat about the recursive call limitation * update NEWS.md Co-authored-by: Jameson Nash <[email protected]>
EDIT: 2021/06/19
This PR:
@inline
and@noinline
@inline
and@noinline
annotation in a function body (typically at the top of its body)fix #18773
Current,
@noinline
only works for function definitions. This PR is my attempt to modify it to be able to direct the compiler to ignore inlining at a function call as discussed in issue #18773. Unfortunately, my current version produces significantly longer LLVM IR and native code and benchmarks much worse than if the function had been marked@noinline
at its definition as shown below.I suspect my modification to
inlining.jl
is flawed. Currently, my version just skips the body of the loop inassemble_inline_todo!
for function calls that have been marked as@noinline
(see here.) and as a result probably skips some other important step in the optimization process, but I can't seem to figure out what. I would really appreciate any pointers in the right direction.