Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

try/catch block error on Julia 1.8 and earlier #971

Closed
jgreener64 opened this issue Jul 30, 2023 · 7 comments · Fixed by #972
Closed

try/catch block error on Julia 1.8 and earlier #971

jgreener64 opened this issue Jul 30, 2023 · 7 comments · Fixed by #972

Comments

@jgreener64
Copy link
Contributor

jgreener64 commented Jul 30, 2023

This works on Julia 1.9 and Enzyme main (6692fad):

using Enzyme

function f(x)
    try
        sqrt(-1.0)
        return 3x
    catch
        return 2x
    end
end

autodiff(Reverse, f, Active, Active(2.0))[1][1]
2.0

But on Julia 1.8.5 (and earlier?) it errors. I'm struggling to catch the segfault but it is probably the same one as at https://github.com/EnzymeAD/Enzyme.jl/actions/runs/5707501454/job/15464242433?pr=969:

signal (11): Segmentation fault
in expression starting at /home/runner/work/Enzyme.jl/Enzyme.jl/test/runtests.jl:258
unknown function (ip: 0x7ff1ebe36081)
autodiff at /home/runner/work/Enzyme.jl/Enzyme.jl/src/Enzyme.jl:222
unknown function (ip: 0x7ff1ebfd7282)
_jl_invoke at /cache/build/default-amdci4-2/julialang/julia-release-1-dot-8/src/gf.c:2377 [inlined]
ijl_apply_generic at /cache/build/default-amdci4-2/julialang/julia-release-1-dot-8/src/gf.c:2559
jl_apply at /cache/build/default-amdci4-2/julialang/julia-release-1-dot-8/src/julia.h:1843 [inlined]
do_call at /cache/build/default-amdci4-2/julialang/julia-release-1-dot-8/src/interpreter.c:126
eval_value at /cache/build/default-amdci4-2/julialang/julia-release-1-dot-8/src/interpreter.c:215
eval_stmt_value at /cache/build/default-amdci4-2/julialang/julia-release-1-dot-8/src/interpreter.c:166 [inlined]
eval_body at /cache/build/default-amdci4-2/julialang/julia-release-1-dot-8/src/interpreter.c:612
eval_body at /cache/build/default-amdci4-2/julialang/julia-release-1-dot-8/src/interpreter.c:522
eval_body at /cache/build/default-amdci4-2/julialang/julia-release-1-dot-8/src/interpreter.c:522
eval_body at /cache/build/default-amdci4-2/julialang/julia-release-1-dot-8/src/interpreter.c:522
jl_interpret_toplevel_thunk at /cache/build/default-amdci4-2/julialang/julia-release-1-dot-8/src/interpreter.c:750
jl_toplevel_eval_flex at /cache/build/default-amdci4-2/julialang/julia-release-1-dot-8/src/toplevel.c:906
jl_toplevel_eval_flex at /cache/build/default-amdci4-2/julialang/julia-release-1-dot-8/src/toplevel.c:850
ijl_toplevel_eval_in at /cache/build/default-amdci4-2/julialang/julia-release-1-dot-8/src/toplevel.c:965
eval at ./boot.jl:368 [inlined]
include_string at ./loading.jl:1428
_jl_invoke at /cache/build/default-amdci4-2/julialang/julia-release-1-dot-8/src/gf.c:2377 [inlined]
ijl_apply_generic at /cache/build/default-amdci4-2/julialang/julia-release-1-dot-8/src/gf.c:2559
_include at ./loading.jl:1488
include at ./client.jl:476
unknown function (ip: 0x7ff20faef5f2)
_jl_invoke at /cache/build/default-amdci4-2/julialang/julia-release-1-dot-8/src/gf.c:2377 [inlined]
ijl_apply_generic at /cache/build/default-amdci4-2/julialang/julia-release-1-dot-8/src/gf.c:2559
jl_apply at /cache/build/default-amdci4-2/julialang/julia-release-1-dot-8/src/julia.h:1843 [inlined]
do_call at /cache/build/default-amdci4-2/julialang/julia-release-1-dot-8/src/interpreter.c:126
eval_value at /cache/build/default-amdci4-2/julialang/julia-release-1-dot-8/src/interpreter.c:215
eval_stmt_value at /cache/build/default-amdci4-2/julialang/julia-release-1-dot-8/src/interpreter.c:166 [inlined]
eval_body at /cache/build/default-amdci4-2/julialang/julia-release-1-dot-8/src/interpreter.c:612
jl_interpret_toplevel_thunk at /cache/build/default-amdci4-2/julialang/julia-release-1-dot-8/src/interpreter.c:750
jl_toplevel_eval_flex at /cache/build/default-amdci4-2/julialang/julia-release-1-dot-8/src/toplevel.c:906
jl_toplevel_eval_flex at /cache/build/default-amdci4-2/julialang/julia-release-1-dot-8/src/toplevel.c:850
ijl_toplevel_eval_in at /cache/build/default-amdci4-2/julialang/julia-release-1-dot-8/src/toplevel.c:965
eval at ./boot.jl:368 [inlined]
exec_options at ./client.jl:276
_start at ./client.jl:522
jfptr__start_38041.clone_1 at /opt/hostedtoolcache/julia/1.8.5/x64/lib/julia/sys.so (unknown line)
_jl_invoke at /cache/build/default-amdci4-2/julialang/julia-release-1-dot-8/src/gf.c:2377 [inlined]
ijl_apply_generic at /cache/build/default-amdci4-2/julialang/julia-release-1-dot-8/src/gf.c:2559
jl_apply at /cache/build/default-amdci4-2/julialang/julia-release-1-dot-8/src/julia.h:1843 [inlined]
true_main at /cache/build/default-amdci4-2/julialang/julia-release-1-dot-8/src/jlapi.c:575
jl_repl_entrypoint at /cache/build/default-amdci4-2/julialang/julia-release-1-dot-8/src/jlapi.c:719
main at /cache/build/default-amdci4-2/julialang/julia-release-1-dot-8/cli/loader_exe.c:59
__libc_start_main at /lib/x86_64-linux-gnu/libc.so.6 (unknown line)
unknown function (ip: 0x401098)
Allocations: 344129554 (Pool: 343937740; Big: 191814); GC: 258
ERROR: LoadError: Package Enzyme errored during testing (received signal: 11)
Stacktrace:
 [1] pkgerror(msg::String)
   @ Pkg.Types /opt/hostedtoolcache/julia/1.8.5/x64/share/julia/stdlib/v1.8/Pkg/src/Types.jl:67
 [2] test(ctx::Pkg.Types.Context, pkgs::Vector{Pkg.Types.PackageSpec}; coverage::Bool, julia_args::Cmd, test_args::Cmd, test_fn::Nothing, force_latest_compatible_version::Bool, allow_earlier_backwards_compatible_versions::Bool, allow_reresolve::Bool)
   @ Pkg.Operations /opt/hostedtoolcache/julia/1.8.5/x64/share/julia/stdlib/v1.8/Pkg/src/Operations.jl:1813
 [3] test(ctx::Pkg.Types.Context, pkgs::Vector{Pkg.Types.PackageSpec}; coverage::Bool, test_fn::Nothing, julia_args::Vector{String}, test_args::Cmd, force_latest_compatible_version::Bool, allow_earlier_backwards_compatible_versions::Bool, allow_reresolve::Bool, kwargs::Base.Pairs{Symbol, IOContext{Base.PipeEndpoint}, Tuple{Symbol}, NamedTuple{(:io,), Tuple{IOContext{Base.PipeEndpoint}}}})
   @ Pkg.API /opt/hostedtoolcache/julia/1.8.5/x64/share/julia/stdlib/v1.8/Pkg/src/API.jl:434
 [4] test(pkgs::Vector{Pkg.Types.PackageSpec}; io::IOContext{Base.PipeEndpoint}, kwargs::Base.Pairs{Symbol, Any, Tuple{Symbol, Symbol, Symbol}, NamedTuple{(:coverage, :julia_args, :force_latest_compatible_version), Tuple{Bool, Vector{String}, Bool}}})
   @ Pkg.API /opt/hostedtoolcache/julia/1.8.5/x64/share/julia/stdlib/v1.8/Pkg/src/API.jl:156
 [5] test(; name::Nothing, uuid::Nothing, version::Nothing, url::Nothing, rev::Nothing, path::Nothing, mode::Pkg.Types.PackageMode, subdir::Nothing, kwargs::Base.Pairs{Symbol, Any, Tuple{Symbol, Symbol, Symbol}, NamedTuple{(:coverage, :julia_args, :force_latest_compatible_version), Tuple{Bool, Vector{String}, Bool}}})
   @ Pkg.API /opt/hostedtoolcache/julia/1.8.5/x64/share/julia/stdlib/v1.8/Pkg/src/API.jl:171
 [6] top-level scope
   @ ~/work/_actions/julia-actions/julia-runtest/v1/test_harness.jl:15
 [7] include(fname::String)
   @ Base.MainInclude ./client.jl:476
 [8] top-level scope
   @ none:1
in expression starting at /home/runner/work/_actions/julia-actions/julia-runtest/v1/test_harness.jl:7
@wsmoses
Copy link
Member

wsmoses commented Jul 31, 2023

Looks like what's happening here is that we prove that sqrt result is not needed for the derivative and it is dead code eliminated. We should run a postprocessing to emit a new "unreachable reached" error on such unreachables, so that the same error is throw condition is applied.

@wsmoses
Copy link
Member

wsmoses commented Jul 31, 2023

That error message will be somethign along the lines of "the original primal code is guaranteed to hit this error condition, thus differentiating it does not make sense"

@vchuravy
Copy link
Member

We should probably handle exceptional Control-Flow better, gradients could propagate through PhiC nodes.

@jgreener64
Copy link
Contributor Author

This fixes the issue for Julia 1.7 and 1.8 but on Julia 1.6.7 it returns the wrong answer:

using Enzyme

function f(x)
    try
        sqrt(-1.0)
        return 3x
    catch
        return 2x
    end
end

autodiff(Reverse, f, Active, Active(2.0))[1][1]
0.0

@vchuravy vchuravy reopened this Aug 1, 2023
@wsmoses
Copy link
Member

wsmoses commented Aug 6, 2023

julia> autodiff(Reverse, f, Active, Active(2.0))[1][1]
after simplification :
; Function Attrs: willreturn
define double @preprocess_julia_f_4904_inner.1(double %0) local_unnamed_addr #16 !dbg !102 {
entry:
  %phic.i = alloca double, align 8
  %phic.i.0.sroa_cast2 = bitcast double* %phic.i to i8*
  call void @llvm.lifetime.start.p0i8(i64 8, i8* %phic.i.0.sroa_cast2)
  %1 = call {}*** @julia.ptls_states() #17
  %2 = call i64 @jl_excstack_state() #18, !dbg !103
  %3 = call i32 @julia.except_enter() #19, !dbg !103
  %4 = icmp eq i32 %3, 0, !dbg !103
  br i1 %4, label %try.i, label %julia_f_4904_inner.exit, !dbg !103

try.i:                                            ; preds = %entry
  store volatile double %0, double* %phic.i, align 8, !dbg !103, !tbaa !70, !noalias !105
  %5 = call fastcc nonnull {} addrspace(10)* @julia_throw_complex_domainerror_4907() #20, !dbg !108
  unreachable, !dbg !108

julia_f_4904_inner.exit:                          ; preds = %entry
  %phic.i.0.phic.i.0.phic.i.0.phic.i.0.phic.i.0.phic.i.0.phic.i.0.phic.i.0.phic.i.0.phic.i.0. = load volatile double, double* %phic.i, align 8, !dbg !110
  call void @jl_pop_handler(i32 1) #21, !dbg !110
  %6 = fmul double %phic.i.0.phic.i.0.phic.i.0.phic.i.0.phic.i.0.phic.i.0.phic.i.0.phic.i.0.phic.i.0.phic.i.0., 2.000000e+00, !dbg !111
  call void @jl_restore_excstack(i64 %2) #21, !dbg !114
  %phic.i.0.sroa_cast3 = bitcast double* %phic.i to i8*, !dbg !114
  call void @llvm.lifetime.end.p0i8(i64 8, i8* %phic.i.0.sroa_cast3), !dbg !114
  ret double %6, !dbg !115
}

; Function Attrs: willreturn
define internal { double } @diffejulia_f_4904_inner.1(double %0, double %differeturn) local_unnamed_addr #16 !dbg !116 {
entry:
  %"'de" = alloca double, align 8
  %1 = getelementptr double, double* %"'de", i64 0
  store double 0.000000e+00, double* %1, align 8
  %phic.i = alloca double, align 8
  %2 = call {}*** @julia.ptls_states() #17
  %3 = call i64 @jl_excstack_state() #18, !dbg !117
  %4 = call i32 @julia.except_enter() #19, !dbg !117
  %5 = icmp eq i32 %4, 0, !dbg !117
  br i1 %5, label %try.i, label %julia_f_4904_inner.exit, !dbg !117

try.i:                                            ; preds = %entry
  store volatile double %0, double* %phic.i, align 8, !dbg !117, !tbaa !70, !noalias !119
  %6 = call fastcc nonnull {} addrspace(10)* @julia_throw_complex_domainerror_4907() #20, !dbg !122
  unreachable

julia_f_4904_inner.exit:                          ; preds = %entry
  %phic.i.0.phic.i.0.phic.i.0.phic.i.0.phic.i.0.phic.i.0.phic.i.0.phic.i.0.phic.i.0.phic.i.0. = load volatile double, double* %phic.i, align 8, !dbg !124, !alias.scope !125, !noalias !128
  call void @jl_pop_handler(i32 1) #21, !dbg !124
  call void @jl_restore_excstack(i64 %3) #21, !dbg !130
  br label %invertjulia_f_4904_inner.exit, !dbg !131

invertentry:                                      ; preds = %invertjulia_f_4904_inner.exit
  %7 = load double, double* %"'de", align 8
  %8 = insertvalue { double } undef, double %7, 0
  ret { double } %8

invertjulia_f_4904_inner.exit:                    ; preds = %julia_f_4904_inner.exit
  br label %invertentry
}

0.0

@jgreener64
Copy link
Contributor Author

Correction to the above, the wrong answer is also returned on Julia 1.7.3.

@wsmoses
Copy link
Member

wsmoses commented Sep 21, 2024

Pre 1.10 is now not supported, closing

@wsmoses wsmoses closed this as completed Sep 21, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants