Why does not g()
yield as efficient code as f()
in this example:
julia> f() = 2 < 1 ? throw("This Should Never Happen") : 42
f (generic function with 1 method)
julia> g() = 2 < 1 ? throw(ErrorException("This Should Never Happen")) : 42
g (generic function with 1 method)
julia> (f(), g())
(42, 42)
julia> code_llvm(f, ())
define i64 @julia_f_67922() #0 !dbg !5 {
top:
ret i64 42
}
julia> code_llvm(g, ())
define i64 @julia_g_67923() #0 !dbg !5 {
top:
%0 = call i8**** @jl_get_ptls_states() #5
%1 = alloca [4 x i8**], align 8
%.sub = getelementptr inbounds [4 x i8**], [4 x i8**]* %1, i64 0, i64 0
%2 = getelementptr [4 x i8**], [4 x i8**]* %1, i64 0, i64 2
%3 = bitcast [4 x i8**]* %1 to i64*
%4 = bitcast i8*** %2 to i8*
call void @llvm.memset.p0i8.i64(i8* %4, i8 0, i64 16, i32 8, i1 false)
store i64 4, i64* %3, align 8
%5 = bitcast i8**** %0 to i64*
%6 = load i64, i64* %5, align 8
%7 = getelementptr [4 x i8**], [4 x i8**]* %1, i64 0, i64 1
%8 = bitcast i8*** %7 to i64*
store i64 %6, i64* %8, align 8
store i8*** %.sub, i8**** %0, align 8
%9 = load i64, i64* %8, align 8
store i64 %9, i64* %5, align 8
ret i64 42
}
(Background: I’m writing code that will run in a tight loop, and I need it to be fast, but I would still like to check some compile-time constants (types, etc). My thought was that this would work fine, since the tests will be done at compile time, and therefore not generate any extra work at run-time. However, when I look at the output of code_llvm
or code_native
, it seems that tests that could throw certain exceptions still generate extra code, even though the exception can never be thrown.)
I’d like to throw exceptions, rather than strings, because that seems to be the correct coding style, but I will not do so at the expense of slower functions.
The example was tested on julia 0.5.1 and 0.6.0-pre.alpha.76.