I have a feeling that iterators are harmful. Consider:
function baz1(n)
for i=1:n
i <1 && return 1
i>n && return 2
end
0
end
function baz2(n)
I = 1:n
state = start(I)
while !done(I, state)
(i, state) = next(I, state)
i <1 && return 1
i>n && return 2
end
0
end
function baz3(n)
i=1
while i<n
i <1 && return 1
i>n && return 2
i +=1
end
0
end
Now, baz1 and baz2 are equivalent according to docs (and tested with @code_llvm on both 0.6 and 0.7 nightly). Let’s look at the code:
julia> @code_llvm baz1(10)
; Function baz1
; Location: REPL[7]:2
define i64 @julia_baz1_63294(i64) {
top:
%1 = icmp sgt i64 %0, 0
%2 = select i1 %1, i64 %0, i64 0
%3 = add i64 %2, 1
br label %L3
L3: ; preds = %L12, %top
%"#temp#.0" = phi i64 [ 1, %top ], [ %6, %L12 ]
%4 = icmp eq i64 %"#temp#.0", %3
br i1 %4, label %L18, label %if
if: ; preds = %L3
; Location: REPL[7]:3
%5 = icmp sgt i64 %"#temp#.0", 0
br i1 %5, label %L12, label %L18
L18: ; preds = %L12, %if, %L3
%merge = phi i64 [ 0, %L3 ], [ 1, %if ], [ 2, %L12 ]
; Location: REPL[7]:6
ret i64 %merge
L12: ; preds = %if
; Location: REPL[7]:2
%6 = add nuw i64 %"#temp#.0", 1
; Location: REPL[7]:4
%7 = icmp sgt i64 %"#temp#.0", %0
br i1 %7, label %L18, label %L3
}
On the other hand,
julia> @code_llvm baz3(10)
; Function baz3
; Location: REPL[3]:2
define i64 @julia_baz3_63295(i64) {
top:
; Location: REPL[3]:3
br i1 undef, label %L17, label %L17
L17: ; preds = %top, %top
; Location: REPL[3]:8
ret i64 0
}
The relevance to bounds checks, and hence general performance, is obvious. I think something must be done to help llvm in “for i=a:b” loops, be it more annotations, a special case for iterators over unit ranges, or a new llvm pass.
Is there a way to obtain a better code_llvm that contains all optimization metadata (all the align / noalias / etc annotations)? Is there a way to obtain code_llvm at each pass?