Julia: jl_invoke & LLVM-related compilation segfault on -O1

Created on 21 Aug 2019  Â·  3Comments  Â·  Source: JuliaLang/julia

Reported initially at https://github.com/timholy/Revise.jl/issues/334. Happens reliably on every Julia version tested (1.1, 1.2, and master) with -O1. Here is a slightly-boiled down version that does not require Revise or very much of LoweredCodeUtils & JuliaInterpreter:

$ julia-master --startup-file=no -O1
               _
   _       _ _(_)_     |  Documentation: https://docs.julialang.org
  (_)     | (_) (_)    |
   _ _   _| |_  __ _   |  Type "?" for help, "]?" for Pkg help.
  | | | | | | |/ _` |  |
  | | |_| | | | (_| |  |  Version 1.4.0-DEV.10 (2019-08-19)
 _/ |\__'_|_|_|\__'_|  |  Commit 9a9ce76643* (1 day old master)
|__/                   |

julia> include("/tmp/methoddef.jl")
methoddef! (generic function with 1 method)

julia> ex = quote
       function test()
           println("testing...")
       end
       end
quote
    #= REPL[2]:2 =#
    function test()
        #= REPL[2]:3 =#
        println("testing...")
    end
end

julia> module TestModule end
Main.TestModule

julia> frame = JuliaInterpreter.prepare_thunk(TestModule, ex)
Frame for Main.TestModule
  1 2  1 ─      $(Expr(:thunk, CodeInfo(
  2 2  1 ─     return $(Expr(:method, :test))
  3 2  )))
â‹®

julia> recurse = JuliaInterpreter.finish_and_return!
finish_and_return! (generic function with 4 methods)

julia> signatures = Any[]
0-element Array{Any,1}

julia> stmt = JuliaInterpreter.pc_expr(frame, 2)
:($(Expr(:method, :test)))

julia> methoddef!(recurse, signatures, frame, stmt, 2; define=false)

signal (11): Segmentation fault
in expression starting at REPL[8]:1
_ZNK4llvm7PHINode24getIncomingValueForBlockEPKNS_10BasicBlockE at /home/tim/src/julia-master/usr/bin/../lib/libLLVM-6.0.so (unknown line)
_ZN12_GLOBAL__N_114CodeGenPrepare20splitBranchConditionERN4llvm8FunctionE at /home/tim/src/julia-master/usr/bin/../lib/libLLVM-6.0.so (unknown line)
_ZN12_GLOBAL__N_114CodeGenPrepare13runOnFunctionERN4llvm8FunctionE.part.1098 at /home/tim/src/julia-master/usr/bin/../lib/libLLVM-6.0.so (unknown line)
_ZN4llvm13FPPassManager13runOnFunctionERNS_8FunctionE at /home/tim/src/julia-master/usr/bin/../lib/libLLVM-6.0.so (unknown line)
_ZN4llvm13FPPassManager11runOnModuleERNS_6ModuleE at /home/tim/src/julia-master/usr/bin/../lib/libLLVM-6.0.so (unknown line)
_ZN4llvm6legacy15PassManagerImpl3runERNS_6ModuleE at /home/tim/src/julia-master/usr/bin/../lib/libLLVM-6.0.so (unknown line)
operator() at /home/tim/src/julia-master/src/jitlayers.cpp:370
addModule at /home/tim/src/julia-master/usr/include/llvm/ExecutionEngine/Orc/IRCompileLayer.h:57 [inlined]
addModule at /home/tim/src/julia-master/src/jitlayers.cpp:508
jl_add_to_ee at /home/tim/src/julia-master/src/jitlayers.cpp:760 [inlined]
jl_finalize_function at /home/tim/src/julia-master/src/jitlayers.cpp:768
getAddressForFunction at /home/tim/src/julia-master/src/codegen.cpp:1325
jl_generate_fptr at /home/tim/src/julia-master/src/codegen.cpp:1417
jl_compile_method_internal at /home/tim/src/julia-master/src/gf.c:1923
_jl_invoke at /home/tim/src/julia-master/src/gf.c:2159 [inlined]
jl_invoke at /home/tim/src/julia-master/src/gf.c:2167
#methoddef! at ./none:0
unknown function (ip: 0x7f32fe42331c)
_jl_invoke at /home/tim/src/julia-master/src/gf.c:2160 [inlined]
jl_apply_generic at /home/tim/src/julia-master/src/gf.c:2324
jl_apply at /home/tim/src/julia-master/src/julia.h:1631 [inlined]
do_call at /home/tim/src/julia-master/src/interpreter.c:328
eval_value at /home/tim/src/julia-master/src/interpreter.c:417
eval_stmt_value at /home/tim/src/julia-master/src/interpreter.c:368 [inlined]
eval_body at /home/tim/src/julia-master/src/interpreter.c:778
jl_interpret_toplevel_thunk_callback at /home/tim/src/julia-master/src/interpreter.c:888
unknown function (ip: 0xfffffffffffffffe)
unknown function (ip: 0x7f3305b3170f)
unknown function (ip: 0x4)
jl_interpret_toplevel_thunk at /home/tim/src/julia-master/src/interpreter.c:897
jl_toplevel_eval_flex at /home/tim/src/julia-master/src/toplevel.c:814
jl_toplevel_eval_flex at /home/tim/src/julia-master/src/toplevel.c:764
jl_toplevel_eval_in at /home/tim/src/julia-master/src/toplevel.c:843
eval at ./boot.jl:330
_jl_invoke at /home/tim/src/julia-master/src/gf.c:2154 [inlined]
jl_apply_generic at /home/tim/src/julia-master/src/gf.c:2324
eval_user_input at /home/tim/src/julia-master/usr/share/julia/stdlib/v1.4/REPL/src/REPL.jl:86
macro expansion at /home/tim/src/julia-master/usr/share/julia/stdlib/v1.4/REPL/src/REPL.jl:118 [inlined]
#26 at ./task.jl:333
_jl_invoke at /home/tim/src/julia-master/src/gf.c:2154 [inlined]
jl_apply_generic at /home/tim/src/julia-master/src/gf.c:2324
jl_apply at /home/tim/src/julia-master/src/julia.h:1631 [inlined]
start_task at /home/tim/src/julia-master/src/task.c:655
unknown function (ip: 0xffffffffffffffff)
Allocations: 7954783 (Pool: 7952695; Big: 2088); GC: 9
/home/tim/bin/julia-master: line 2:  1450 Segmentation fault      (core dumped) ~/src/julia-master/julia "$@"
$

where the contents of /tmp/methoddef.jl are

import JuliaInterpreter, LoweredCodeUtils
using JuliaInterpreter: Frame, pc_expr
using Base.Meta: isexpr

function methoddef!(@nospecialize(recurse), signatures, frame::Frame, @nospecialize(stmt), pc::Int; define=true)
    framecode = frame.framecode
    nextstmt = pc_expr(frame, pc+1)
    while true  # methods containing inner methods may need multiple trips through this loop
        sigt, pc = LoweredCodeUtils.signature(recurse, frame, stmt, pc)
        stmt = pc_expr(frame, pc)
        while !isexpr(stmt, :method, 3)
            pc = LoweredCodeUtils.next_or_nothing(frame, pc)
            pc === nothing && return nothing   # this was just `function foo end`
            stmt = pc_expr(frame, pc)
        end
    end
end

Both the backtrace and putting @show debugging into methoddef! indicate that the method never gets called, it seems to segfault during compilation. Only happens with -O1.

For reference, this is LoweredCodeUtils v0.3.7 and JuliaInterpreter 0.7.0.

bug codegen external dependencies

Most helpful comment

All 3 comments

Investigative report.

  • Either turn of fast-isel for x86_64 as well
  • pass JULIA_LLVM_ARGS="-disable-cgp-branch-opts=true"

I am working on a fix for LLVM as well, but coming up with minimal test case is hard since bugpoint crashes.

Reproducing command is:
~/builds/julia-debug/usr/tools/llc -fast-isel=true -O1 -mtriple=x86_64-unkown-linux-gnu -debug-only=codegenprepare -start-before=codegenprepare -stop-after=codegenprepare --filetype=obj

GCP crashes on:

Before branch condition splitting

pass19:                                           ; preds = %idxend17
  %244 = icmp eq i8 %166, 2, !dbg !109
  %245 = select i1 %244, i8 2, i8 -128, !dbg !109
  %246 = and i8 %tindex_phi14, -128, !dbg !109
  %247 = or i8 %246, %245, !dbg !109
  %248 = icmp sgt i8 %247, -1, !dbg !109
  %249 = and i8 %245, 3, !dbg !109
  %cond5896 = icmp eq i8 %249, 2, !dbg !109
  %cond58 = and i1 %cond5896, %248, !dbg !109
  br i1 %cond58, label %L34, label %L34, !dbg !109

Manual reduced example:

; RUN: llc -fast-isel=true -O1 -mtriple=x86_64-unkown-linux-gnu -start-before=codegenprepare -stop-after=codegenprepare < %s | FileCheck %s

define void @foo(i32) {
entry:
    br label %for

for:
    %I = phi i32 [1, %entry], [%i, %for.cond], [%i, %for.cond] 
    %i = add i32 %I, 1
    %cond0 = icmp eq i32 0, %0 
    br i1 %cond0, label %exit, label %for.cond

for.cond:
    %N = and i32 %0, 127
    %cond1 = icmp eq i32 %i, %0 
    %cond2 = icmp eq i32 %i, %N 
    %cond = and i1 %cond1, %cond2
    br i1 %cond, label %for, label %for

exit:
    ret void
}

Closed by #34190

Was this page helpful?
0 / 5 - 0 ratings

Related issues

StefanKarpinski picture StefanKarpinski  Â·  138Comments

StefanKarpinski picture StefanKarpinski  Â·  145Comments

jiahao picture jiahao  Â·  417Comments

StefanKarpinski picture StefanKarpinski  Â·  216Comments

mbauman picture mbauman  Â·  276Comments