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