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 > >