Oh, for comparison, this simper function contains no heap allocation at
all, so the compiler is definitely willing to do this under some
circumstances.

function foo()
  finger = Finger{1}(1,1)
  for _ in 1:1000
    finger = Finger{1}(finger.hi + finger.lo, finger.lo)
  end
  finger
end

On 22 September 2016 at 14:01, Jamie Brandon <ja...@scattered-thoughts.net>
wrote:

> I have a query compiler which emits Julia code. The code contains lots of
> calls to generated functions, which include sections like this:
>
>     hi = gallop(column, column[finger.lo], finger.lo, finger.hi, <=)
>     Finger{$(C+1)}(finger.lo, hi)
>
> Finger is an immutable, isbits type:
>
>   immutable Finger{C}
>     lo::Int64
>     hi::Int64
>   end
>
> When I run the generated code I see many millions of allocations. Using
> code_warntype I can see that all the generated functions have been inlined,
> every variable has a concrete inferred type and there are no generic calls.
> And yet I see many sections in the llvm code like this:
>
>   %235 = call %jl_value_t* @jl_gc_pool_alloc(i8* %ptls_i8, i32 1456, i32
> 32)
>   %236 = getelementptr inbounds %jl_value_t, %jl_value_t* %235, i64 -1,
> i32 0
>   store %jl_value_t* inttoptr (i64 139661604385936 to %jl_value_t*),
> %jl_value_t** %236, align 8
>   %237 = bitcast %jl_value_t* %235 to i64*
>   store i64 %229, i64* %237, align 8
>   %238 = getelementptr inbounds %jl_value_t, %jl_value_t* %235, i64 1
>   %239 = bitcast %jl_value_t* %238 to i64*
>   store i64 %234, i64* %239, align 8
>   store %jl_value_t* %235, %jl_value_t** %finger_2_2, align 8
>   %.pr = load %jl_value_t*, %jl_value_t** %finger_1_2, align 8
>
> The pointer on the third line is:
>
>   unsafe_pointer_to_objref(convert(Ptr{Any}, 139661604385936))
>   # => Data.Finger{1}
>
> So it appears that these fingers are still being heap-allocated.
>
> What could cause this? And more generally, how does one debug issues like
> this? Is there any way to introspect on the decision?
>

Reply via email to