Function definition
julia> function mycopyto!(dest::AbstractArray, src::AbstractArray)
iterdest, itersrc = eachindex(dest), eachindex(src)
@inbounds for I in iterdest
if isassigned(src, I) # this shouldn't be checking bounds
dest[I] = src[I]
else
dest[I] = zero(eltype(dest))
end
end
return dest
end
mycopyto! (generic function with 1 method)
julia> @code_llvm mycopyto!(view(zeros(4,4), 1:4, 1:4), view(zeros(4,4), 1:4, 1:4))
The relevant bit of the @code_llvm
output (full output later):
; @ REPL[1]:4 within `mycopyto!`
; ┌ @ multidimensional.jl:1568 within `isassigned` @ subarray.jl:412
br label %L36
L36: ; preds = %L590, %L36.preheader
%value_phi25 = phi i64 [ %value_phi276, %L590 ], [ 1, %L36.preheader ]
%value_phi26 = phi i64 [ %value_phi277, %L590 ], [ 1, %L36.preheader ]
; │┌ @ abstractarray.jl:681 within `checkbounds`
; ││┌ @ abstractarray.jl:725 within `checkbounds_indices`
; │││┌ @ abstractarray.jl:754 within `checkindex`
; ││││┌ @ int.jl:86 within `-`
%12 = add i64 %value_phi25, -1
; ││││└
; ││││┌ @ int.jl:513 within `<`
%13 = icmp uge i64 %12, %7
; │││└└
; │││ @ abstractarray.jl:725 within `checkbounds_indices` @ abstractarray.jl:725
; │││┌ @ abstractarray.jl:754 within `checkindex`
; ││││┌ @ int.jl:86 within `-`
%14 = add i64 %value_phi26, -1
; ││││└
; ││││┌ @ int.jl:513 within `<`
%15 = icmp uge i64 %14, %9
; │└└└└
%.not417.not.not = or i1 %13, %15
; └
It appears that the bounds check still exists, despite the inline and inbounds annotations.
Full code llvm:
julia> @code_llvm mycopyto!(view(zeros(4,4),1:4, 1:4), view(zeros(4,4), 1:4, 1:4));
; Function Signature: mycopyto!(Base.SubArray{Float64, 2, Array{Float64, 2}, Tuple{Base.UnitRange{Int64}, Base.UnitRange{Int64}}, false}, Base.SubArray{Float64, 2, Array{Float64, 2}, Tuple{Base.UnitRange{Int64}, Base.UnitRange{Int64}}, false})
; @ REPL[1]:1 within `mycopyto!`
define void @"julia_mycopyto!_1916"(ptr noalias nocapture noundef nonnull sret({ ptr, [2 x [2 x i64]], i64, i64 }) align 8 dereferenceable(56) %sret_return, ptr noalias nocapture noundef nonnull align 8 dereferenceable(8) %return_roots, ptr nocapture noundef nonnull readonly align 8 dereferenceable(56) %"dest::SubArray", ptr nocapture noundef nonnull readonly align 8 dereferenceable(56) %"src::SubArray") #0 {
top:
; @ REPL[1]:2 within `mycopyto!`
; ┌ @ abstractarray.jl:378 within `eachindex` @ multidimensional.jl:406
; │┌ @ subarray.jl:528 within `axes`
; ││┌ @ Base.jl:49 within `getproperty`
%"dest::SubArray.indices_ptr" = getelementptr inbounds { ptr, [2 x [2 x i64]], i64, i64 }, ptr %"dest::SubArray", i64 0, i32 1
; ││└
%"dest::SubArray.indices_ptr[2]_ptr" = getelementptr inbounds { ptr, [2 x [2 x i64]], i64, i64 }, ptr %"dest::SubArray", i64 0, i32 1, i64 1
; ││┌ @ subarray.jl:533 within `_indices_sub`
; │││┌ @ abstractarray.jl:98 within `axes`
; ││││┌ @ range.jl:670 within `size`
; │││││┌ @ range.jl:759 within `length`
; ││││││┌ @ range.jl:840 within `last`
; │││││││┌ @ Base.jl:49 within `getproperty`
%"dest::SubArray.indices_ptr[1]_ptr.stop_ptr" = getelementptr inbounds { ptr, [2 x [2 x i64]], i64, i64 }, ptr %"dest::SubArray", i64 0, i32 1, i64 0, i64 1
; ││││││└└
; ││││││ @ range.jl:762 within `length`
; ││││││┌ @ int.jl:86 within `-`
%"dest::SubArray.indices_ptr[1]_ptr.stop_ptr.unbox" = load i64, ptr %"dest::SubArray.indices_ptr[1]_ptr.stop_ptr", align 8
%"dest::SubArray.indices_ptr[1]_ptr.start_ptr.unbox" = load i64, ptr %"dest::SubArray.indices_ptr", align 8
%0 = sub i64 %"dest::SubArray.indices_ptr[1]_ptr.stop_ptr.unbox", %"dest::SubArray.indices_ptr[1]_ptr.start_ptr.unbox"
; ││││││└
; ││││││┌ @ int.jl:87 within `+`
%1 = add i64 %0, 1
; │││└└└└
; │││ @ subarray.jl:533 within `_indices_sub` @ subarray.jl:533
; │││┌ @ abstractarray.jl:98 within `axes`
; ││││┌ @ range.jl:670 within `size`
; │││││┌ @ range.jl:759 within `length`
; ││││││┌ @ range.jl:840 within `last`
; │││││││┌ @ Base.jl:49 within `getproperty`
%"dest::SubArray.indices_ptr[2]_ptr.stop_ptr" = getelementptr inbounds { ptr, [2 x [2 x i64]], i64, i64 }, ptr %"dest::SubArray", i64 0, i32 1, i64 1, i64 1
; ││││││└└
; ││││││ @ range.jl:762 within `length`
; ││││││┌ @ int.jl:86 within `-`
%"dest::SubArray.indices_ptr[2]_ptr.stop_ptr.unbox" = load i64, ptr %"dest::SubArray.indices_ptr[2]_ptr.stop_ptr", align 8
%"dest::SubArray.indices_ptr[2]_ptr.start_ptr.unbox" = load i64, ptr %"dest::SubArray.indices_ptr[2]_ptr", align 8
%2 = sub i64 %"dest::SubArray.indices_ptr[2]_ptr.stop_ptr.unbox", %"dest::SubArray.indices_ptr[2]_ptr.start_ptr.unbox"
; ││││││└
; ││││││┌ @ int.jl:87 within `+`
%3 = add i64 %2, 1
; └└└└└└└
; @ REPL[1]:3 within `mycopyto!`
; ┌ @ multidimensional.jl:416 within `iterate`
; │┌ @ tuple.jl:383 within `map`
; ││┌ @ range.jl:1420 within `in`
; │││┌ @ int.jl:514 within `<=`
%4 = icmp ugt i64 %0, 9223372036854775806
%5 = icmp ugt i64 %2, 9223372036854775806
; └└└└
%.not411.not.not.not.not = or i1 %4, %5
br i1 %.not411.not.not.not.not, label %L623, label %L36.preheader
L36.preheader: ; preds = %top
%"src::SubArray.indices_ptr" = getelementptr inbounds { ptr, [2 x [2 x i64]], i64, i64 }, ptr %"src::SubArray", i64 0, i32 1
%"src::SubArray.indices_ptr[2]_ptr" = getelementptr inbounds { ptr, [2 x [2 x i64]], i64, i64 }, ptr %"src::SubArray", i64 0, i32 1, i64 1
%"src::SubArray.indices_ptr[1]_ptr.stop_ptr" = getelementptr inbounds { ptr, [2 x [2 x i64]], i64, i64 }, ptr %"src::SubArray", i64 0, i32 1, i64 0, i64 1
%"src::SubArray.indices_ptr[1]_ptr.stop_ptr.unbox" = load i64, ptr %"src::SubArray.indices_ptr[1]_ptr.stop_ptr", align 8
%"src::SubArray.indices_ptr[1]_ptr.start_ptr.unbox" = load i64, ptr %"src::SubArray.indices_ptr", align 8
%6 = add i64 %"src::SubArray.indices_ptr[1]_ptr.stop_ptr.unbox", 1
%7 = sub i64 %6, %"src::SubArray.indices_ptr[1]_ptr.start_ptr.unbox"
%"src::SubArray.indices_ptr[2]_ptr.stop_ptr" = getelementptr inbounds { ptr, [2 x [2 x i64]], i64, i64 }, ptr %"src::SubArray", i64 0, i32 1, i64 1, i64 1
%"src::SubArray.indices_ptr[2]_ptr.stop_ptr.unbox" = load i64, ptr %"src::SubArray.indices_ptr[2]_ptr.stop_ptr", align 8
%"src::SubArray.indices_ptr[2]_ptr.start_ptr.unbox" = load i64, ptr %"src::SubArray.indices_ptr[2]_ptr", align 8
%8 = add i64 %"src::SubArray.indices_ptr[2]_ptr.stop_ptr.unbox", 1
%9 = sub i64 %8, %"src::SubArray.indices_ptr[2]_ptr.start_ptr.unbox"
%"src::SubArray.parent155" = load atomic ptr, ptr %"src::SubArray" unordered, align 8
%10 = getelementptr inbounds i8, ptr %"src::SubArray.parent155", i64 16
%"dest::SubArray.parent" = load atomic ptr, ptr %"dest::SubArray" unordered, align 8
%11 = getelementptr inbounds i8, ptr %"dest::SubArray.parent", i64 16
; @ REPL[1]:4 within `mycopyto!`
; ┌ @ multidimensional.jl:1568 within `isassigned` @ subarray.jl:412
br label %L36
L36: ; preds = %L590, %L36.preheader
%value_phi25 = phi i64 [ %value_phi276, %L590 ], [ 1, %L36.preheader ]
%value_phi26 = phi i64 [ %value_phi277, %L590 ], [ 1, %L36.preheader ]
; │┌ @ abstractarray.jl:681 within `checkbounds`
; ││┌ @ abstractarray.jl:725 within `checkbounds_indices`
; │││┌ @ abstractarray.jl:754 within `checkindex`
; ││││┌ @ int.jl:86 within `-`
%12 = add i64 %value_phi25, -1
; ││││└
; ││││┌ @ int.jl:513 within `<`
%13 = icmp uge i64 %12, %7
; │││└└
; │││ @ abstractarray.jl:725 within `checkbounds_indices` @ abstractarray.jl:725
; │││┌ @ abstractarray.jl:754 within `checkindex`
; ││││┌ @ int.jl:86 within `-`
%14 = add i64 %value_phi26, -1
; ││││└
; ││││┌ @ int.jl:513 within `<`
%15 = icmp uge i64 %14, %9
; │└└└└
%.not417.not.not = or i1 %13, %15
; └
; @ REPL[1] within `mycopyto!`
%16 = add i64 %value_phi25, -2
; @ REPL[1]:4 within `mycopyto!`
br i1 %.not417.not.not, label %L491, label %L211
L211: ; preds = %L36
; @ REPL[1]:5 within `mycopyto!`
; ┌ @ abstractarray.jl:1310 within `getindex`
; │┌ @ abstractarray.jl:1356 within `_getindex`
; ││┌ @ subarray.jl:317 within `getindex` @ array.jl:915
; │││┌ @ abstractarray.jl:1345 within `_to_linear_index`
; ││││┌ @ abstractarray.jl:2975 within `_sub2ind`
; │││││┌ @ abstractarray.jl:98 within `axes`
; ││││││┌ @ array.jl:194 within `size`
%"src::SubArray.parent155.size174.sroa.0.0.copyload" = load i64, ptr %10, align 8
; │││└└└└
; │││ @ subarray.jl:317 within `getindex`
; │││┌ @ subarray.jl:295 within `reindex` @ subarray.jl:295
; ││││┌ @ views.jl:150 within `maybeview`
; │││││┌ @ array.jl:3058 within `getindex`
; ││││││┌ @ range.jl:932 within `_getindex`
; │││││││┌ @ int.jl:87 within `+`
%17 = add i64 %value_phi26, -2
; │││└└└└└
; │││ @ subarray.jl:317 within `getindex` @ array.jl:915
; │││┌ @ abstractarray.jl:1345 within `_to_linear_index`
; ││││┌ @ abstractarray.jl:2975 within `_sub2ind` @ abstractarray.jl:2991
; │││││┌ @ abstractarray.jl:3007 within `_sub2ind_recurse` @ abstractarray.jl:3007
; ││││││┌ @ abstractarray.jl:3014 within `offsetin`
; │││││││┌ @ int.jl:86 within `-`
%18 = add i64 %17, %"src::SubArray.indices_ptr[2]_ptr.start_ptr.unbox"
; ││││││└└
; ││││││┌ @ int.jl:88 within `*`
%19 = mul i64 %"src::SubArray.parent155.size174.sroa.0.0.copyload", %18
; │││└└└└
; │││ @ subarray.jl:317 within `getindex` @ array.jl:915 @ essentials.jl:887
%20 = load ptr, ptr %"src::SubArray.parent155", align 8
; │││ @ subarray.jl:317 within `getindex` @ array.jl:915
; │││┌ @ abstractarray.jl:1345 within `_to_linear_index`
; ││││┌ @ abstractarray.jl:2975 within `_sub2ind` @ abstractarray.jl:2991
; │││││┌ @ abstractarray.jl:3007 within `_sub2ind_recurse` @ abstractarray.jl:3007
; ││││││┌ @ int.jl:87 within `+`
%21 = add i64 %16, %"src::SubArray.indices_ptr[1]_ptr.start_ptr.unbox"
; │││└└└└
; │││ @ subarray.jl:317 within `getindex` @ array.jl:915 @ essentials.jl:887
%22 = add i64 %21, %19
%23 = getelementptr inbounds double, ptr %20, i64 %22
%24 = load double, ptr %23, align 8
; └└└
; ┌ @ abstractarray.jl:1411 within `setindex!`
; │┌ @ abstractarray.jl:1441 within `_setindex!`
; ││┌ @ subarray.jl:368 within `setindex!` @ array.jl:979
; │││┌ @ Base.jl:49 within `getproperty`
%25 = load ptr, ptr %"dest::SubArray.parent", align 8
; │││└
; │││┌ @ abstractarray.jl:1345 within `_to_linear_index`
; ││││┌ @ abstractarray.jl:2975 within `_sub2ind`
; │││││┌ @ abstractarray.jl:98 within `axes`
; ││││││┌ @ array.jl:194 within `size`
%"dest::SubArray.parent.size263.sroa.0.0.copyload" = load i64, ptr %11, align 8
; │││││└└
; │││││ @ abstractarray.jl:2975 within `_sub2ind` @ abstractarray.jl:2991
; │││││┌ @ abstractarray.jl:3007 within `_sub2ind_recurse` @ abstractarray.jl:3007
; ││││││┌ @ abstractarray.jl:3014 within `offsetin`
; │││││││┌ @ int.jl:86 within `-`
%26 = add i64 %17, %"dest::SubArray.indices_ptr[2]_ptr.start_ptr.unbox"
; ││││││└└
; ││││││┌ @ int.jl:88 within `*`
%27 = mul i64 %"dest::SubArray.parent.size263.sroa.0.0.copyload", %26
; ││││││└
; ││││││┌ @ int.jl:87 within `+`
%28 = add i64 %16, %"dest::SubArray.indices_ptr[1]_ptr.start_ptr.unbox"
; │││└└└└
%29 = add i64 %28, %27
%30 = getelementptr inbounds double, ptr %25, i64 %29
store double %24, ptr %30, align 8
; └└└
br label %L590
L491: ; preds = %L36
; @ REPL[1]:7 within `mycopyto!`
; ┌ @ abstractarray.jl:1411 within `setindex!`
; │┌ @ abstractarray.jl:1441 within `_setindex!`
; ││┌ @ subarray.jl:368 within `setindex!` @ array.jl:979
; │││┌ @ Base.jl:49 within `getproperty`
%31 = load ptr, ptr %"dest::SubArray.parent", align 8
; │││└
; │││┌ @ abstractarray.jl:1345 within `_to_linear_index`
; ││││┌ @ abstractarray.jl:2975 within `_sub2ind`
; │││││┌ @ abstractarray.jl:98 within `axes`
; ││││││┌ @ array.jl:194 within `size`
%"dest::SubArray.parent366.size386.sroa.0.0.copyload" = load i64, ptr %11, align 8
; │││└└└└
; │││ @ subarray.jl:368 within `setindex!`
; │││┌ @ subarray.jl:295 within `reindex` @ subarray.jl:295
; ││││┌ @ views.jl:150 within `maybeview`
; │││││┌ @ array.jl:3058 within `getindex`
; ││││││┌ @ range.jl:932 within `_getindex`
; │││││││┌ @ int.jl:87 within `+`
%32 = add i64 %value_phi26, -2
; │││└└└└└
; │││ @ subarray.jl:368 within `setindex!` @ array.jl:979
; │││┌ @ abstractarray.jl:1345 within `_to_linear_index`
; ││││┌ @ abstractarray.jl:2975 within `_sub2ind` @ abstractarray.jl:2991
; │││││┌ @ abstractarray.jl:3007 within `_sub2ind_recurse` @ abstractarray.jl:3007
; ││││││┌ @ abstractarray.jl:3014 within `offsetin`
; │││││││┌ @ int.jl:86 within `-`
%33 = add i64 %32, %"dest::SubArray.indices_ptr[2]_ptr.start_ptr.unbox"
; ││││││└└
; ││││││┌ @ int.jl:88 within `*`
%34 = mul i64 %"dest::SubArray.parent366.size386.sroa.0.0.copyload", %33
; ││││││└
; ││││││┌ @ int.jl:87 within `+`
%35 = add i64 %16, %"dest::SubArray.indices_ptr[1]_ptr.start_ptr.unbox"
; │││└└└└
%36 = add i64 %35, %34
%37 = getelementptr inbounds double, ptr %31, i64 %36
store i64 0, ptr %37, align 8
; │└└
br label %L590
L590: ; preds = %L491, %L211
; └
; @ REPL[1]:9 within `mycopyto!`
; ┌ @ multidimensional.jl:422 within `iterate`
; │┌ @ multidimensional.jl:446 within `__inc`
; ││┌ @ int.jl:87 within `+`
%38 = add i64 %value_phi25, 1
; ││└
; ││ @ multidimensional.jl:447 within `__inc`
; ││┌ @ operators.jl:277 within `!=`
; │││┌ @ promotion.jl:620 within `==`
%.not = icmp eq i64 %value_phi25, %1
; ││└└
%39 = icmp eq i64 %value_phi26, %3
%narrow.not.not = select i1 %.not, i1 %39, i1 false
%value_phi276 = select i1 %.not, i64 1, i64 %38
%40 = zext i1 %.not to i64
%value_phi277 = add i64 %value_phi26, %40
; └└
br i1 %narrow.not.not, label %L623, label %L36
L623: ; preds = %L590, %top
; @ REPL[1]:10 within `mycopyto!`
%41 = load ptr, ptr %"dest::SubArray", align 8
store ptr %41, ptr %return_roots, align 8
call void @llvm.memcpy.p0.p0.i64(ptr noundef nonnull align 8 dereferenceable(56) %sret_return, ptr noundef nonnull align 8 dereferenceable(56) %"dest::SubArray", i64 56, i1 false)
ret void
}
My version info:
julia> versioninfo()
Julia Version 1.11.0-DEV.1517
Commit 667cdde7847 (2024-02-08 12:39 UTC)
Build Info:
Official https://julialang.org/ release
Platform Info:
OS: Linux (x86_64-linux-gnu)
CPU: 8 × 11th Gen Intel(R) Core(TM) i5-1135G7 @ 2.40GHz
WORD_SIZE: 64
LLVM: libLLVM-16.0.6 (ORCJIT, tigerlake)
Threads: 1 default, 0 interactive, 1 GC (on 8 virtual cores)
Environment:
LD_LIBRARY_PATH = :/usr/lib/x86_64-linux-gnu/gtk-3.0/modules
JULIA_EDITOR = subl