I’m assuming including the Expr(:meta,:inline) is the correct thing to do 
for generated functions?

The trick is to interpolate the Expr(:meta, :inline) into the Expr returned 
by mysub2ind_gen, so something like:

julia> function mysub2ind_gen(N)
           ex = :(I[$N] - 1)
           for i = N-1:-1:1
               ex = :(I[$i] - 1 + dims[$i]*$ex)
           end
           quote
               $(Expr(:meta, :inline))
               $ex + 1
           end
       end

julia> mysub2ind_gen(3)
quote  # none, line 7:
    $(Expr(:meta, :inline)) # none, line 8:
    ((I[1] - 1) + dims[1] * ((I[2] - 1) + dims[2] * (I[3] - 1))) + 1
end

Note the $(...) surrounding the :meta node, which matches the output from 
my first message’s code_wartype output for foo3.

— Mike
​
On Thursday, 11 February 2016 13:46:53 UTC+2, Andy Ferris wrote:
>
> Thank you Mike for clearing that up. Actually, the docs say @inline simply 
> inserts that :meta: http://docs.julialang.org/en/release-0.4/devdocs/meta/. 
> Maybe that's too simplistic.
>
> Actually, I *was* looking at this because I wanted to make inline 
> generated functions and see how they behave with code_native/code_llvm. But 
> as you can see from 
> https://groups.google.com/forum/#!topic/julia-users/4pkWhcap1Zg I have 
> been struggling to see the code from generated functions, so I did as Tim 
> Holy suggested and stuck the code into a function and saw how it compiled 
> (since I couldn't figure out another way). I'm assuming including the 
> Expr(:meta,:inline) is the correct thing to do for generated functions?
>
> Andy
>
>
>
> On Thursday, February 11, 2016 at 5:46:40 PM UTC+10, Michael Hatherly 
> wrote:
>>
>> Manually adding an Expr(:meta, :inline) to the function is not 
>> equivalent to using @inline since it does not “splice” it into the 
>> function’s ast but rather just creates a new Expr object at runtime each 
>> time the function is called. Have a look at the difference in code_typed 
>> output between foo2 and the following function
>>
>> @inline function foo3{T}(x::T)
>>     x.data[1]
>> end
>>
>> julia> code_warntype(foo3, (Bar,))
>> Variables:
>>   #self#::#foo3
>>   x::Bar
>>
>> Body:
>>   begin 
>>       $(Expr(:meta, :inline)) # none, line 2:
>>       return 
>> (Base.getfield)((top(getfield))(x::Bar,:data)::Tuple{Int64,Float64,Bool},1)::Int64
>>   end::Int64
>>
>> You should always use @inline unless you’re manually building an entire 
>> Expr to be returned by a macro or generated function.
>>
>> — Mike
>> ​
>>
>> On Thursday, 11 February 2016 08:37:17 UTC+2, Andy Ferris wrote:
>>>
>>> Hi,
>>>
>>> I have been playing with inlining and I'm confused by the following - my 
>>> inline function `foo2` is clearly less efficient than my normal function 
>>> `foo`.
>>>
>>> Does anyone have insight to what is going on? Would this have to do with 
>>> running everything in Main from the REPL (so that it would be OK in 
>>> practice)? Is the inline tag doing something else I wouldn't expect? 
>>> Running `code_warntype` indicates both have strongly typed outputs.
>>>
>>> Thanks,
>>> Andy
>>>
>>>
>>> julia> immutable Bar
>>>           data::Tuple{Int64,Float64,Bool}
>>>        end
>>>
>>>
>>> julia> function foo{T}(x::T)
>>>            x.data[1]
>>>        end
>>> foo (generic function with 1 method)
>>>
>>>
>>> julia> function foo2{T}(x::T)
>>>            Expr(:meta,:inline)
>>>            x.data[1]
>>>        end
>>> foo2 (generic function with 1 method)
>>>
>>>
>>> julia> code_native(foo,(Bar,))
>>> .text
>>> Filename: none
>>> Source line: 2
>>> pushq %rbp
>>> movq %rsp, %rbp
>>> Source line: 2
>>> movq (%rdi), %rax
>>> Source line: 2
>>> popq %rbp
>>> ret
>>>
>>>
>>> julia> code_native(foo2,(Bar,))
>>> .text
>>> Filename: none
>>> Source line: 2
>>> pushq %rbp
>>> movq %rsp, %rbp
>>> Source line: 2
>>> pushq %r14
>>> pushq %rbx
>>> subq $32, %rsp
>>> movq $4, -48(%rbp)
>>> movabsq $jl_pgcstack, %r14
>>> movq (%r14), %rax
>>> movq %rax, -40(%rbp)
>>> leaq -48(%rbp), %rax
>>> movq %rax, (%r14)
>>> xorps %xmm0, %xmm0
>>> movups %xmm0, -32(%rbp)
>>> movq (%rdi), %rbx
>>> movabsq $140270402987792, %rax  # imm = 0x7F933F8AE710
>>> Source line: 2
>>> movq %rax, -32(%rbp)
>>> Source line: 2
>>> leaq -32(%rbp), %rsi
>>> Source line: 2
>>> movabsq $jl_f_new_expr, %rax
>>> movabsq $140270402996640, %rcx  # imm = 0x7F933F8B09A0
>>> movq %rcx, -24(%rbp)
>>> xorl %edi, %edi
>>> movl $2, %edx
>>> callq *%rax
>>> Source line: 3
>>> movq -40(%rbp), %rax
>>> movq %rax, (%r14)
>>> movq %rbx, %rax
>>> addq $32, %rsp
>>> popq %rbx
>>> popq %r14
>>> popq %rbp
>>> ret
>>>
>>>
>>> Also:
>>>
>>> julia> code_llvm(foo,(bar,))
>>>
>>> define i64 @julia_foo_26276(%bar*) {
>>> top:
>>>   %1 = bitcast %bar* %0 to i64*
>>>   %2 = load i64* %1, align 8
>>>   ret i64 %2
>>> }
>>>
>>>
>>> julia> code_llvm(foo2,(bar,))
>>>
>>> define i64 @julia_foo2_26277(%bar*) {
>>> top:
>>>   %1 = alloca [4 x %jl_value_t*], align 8
>>>   %.sub5 = bitcast [4 x %jl_value_t*]* %1 to %jl_value_t**
>>>   %2 = getelementptr [4 x %jl_value_t*]* %1, i64 0, i64 2
>>>   store %jl_value_t* inttoptr (i64 4 to %jl_value_t*), %jl_value_t** 
>>> %.sub5, align 8
>>>   %3 = getelementptr [4 x %jl_value_t*]* %1, i64 0, i64 1
>>>   %4 = load %jl_value_t*** @jl_pgcstack, align 8
>>>   %.c = bitcast %jl_value_t** %4 to %jl_value_t*
>>>   store %jl_value_t* %.c, %jl_value_t** %3, align 8
>>>   store %jl_value_t** %.sub5, %jl_value_t*** @jl_pgcstack, align 8
>>>   store %jl_value_t* null, %jl_value_t** %2, align 8
>>>   %5 = getelementptr [4 x %jl_value_t*]* %1, i64 0, i64 3
>>>   store %jl_value_t* null, %jl_value_t** %5, align 8
>>>   %6 = bitcast %bar* %0 to i64*
>>>   %7 = load i64* %6, align 8
>>>   store %jl_value_t* inttoptr (i64 140270402987792 to %jl_value_t*), 
>>> %jl_value_t** %2, align 8
>>>   store %jl_value_t* inttoptr (i64 140270402996640 to %jl_value_t*), 
>>> %jl_value_t** %5, align 8
>>>   %8 = call %jl_value_t* @jl_f_new_expr(%jl_value_t* null, %jl_value_t** 
>>> %2, i32 2)
>>>   %9 = load %jl_value_t** %3, align 8
>>>   %10 = bitcast %jl_value_t* %9 to %jl_value_t**
>>>   store %jl_value_t** %10, %jl_value_t*** @jl_pgcstack, align 8
>>>   ret i64 %7
>>> }
>>>
>>>
>>> julia> code_warntype(foo,(bar,))
>>> Variables:
>>>   x::bar
>>>
>>> Body:
>>>   begin  # none, line 2:
>>>       return 
>>> (Base.getfield)((top(getfield))(x::bar,:data)::Tuple{Int64,Float64,Bool},1)::Int64
>>>   end::Int64
>>>
>>>
>>> julia> code_warntype(foo2,(bar,))
>>> Variables:
>>>   x::bar
>>>   ##args#10160::Tuple{Symbol,Symbol}
>>>
>>> Body:
>>>   begin  # none, line 2:
>>>       (Base._expr)(:meta,:inline)::Expr # none, line 3:
>>>       return 
>>> (Base.getfield)((top(getfield))(x::bar,:data)::Tuple{Int64,Float64,Bool},1)::Int64
>>>   end::Int64
>>>
>>>

Reply via email to