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

add mul!(C,::BiTriSym, ::*Diagonal) #1

Merged
merged 1 commit into from
May 3, 2019
Merged

add mul!(C,::BiTriSym, ::*Diagonal) #1

merged 1 commit into from
May 3, 2019

Conversation

dkarrasch
Copy link

as suggested in JuliaLang#31889 (comment)

@mcognetta mcognetta merged commit b59d135 into mcognetta:tri_times_diag May 3, 2019
@dkarrasch dkarrasch deleted the patch-1 branch May 14, 2019 08:22
mcognetta pushed a commit that referenced this pull request Jul 26, 2019
…#32605)

The bug here is a bit subtle, but perhaps best illustrated with
the included test case:
```
function f32579(x::Int64, b::Bool)
    if b
        x = nothing
    end
    if isa(x, Int64)
        y = x
    else
        y = x
    end
    if isa(y, Nothing)
        z = y
    else
        z = y
    end
    return z === nothing
end
```
The code just after SSA conversion looks like:
```
2  1 ─       goto JuliaLang#3 if not _3
3  2 ─ %2  = Main.nothing::Core.Compiler.Const(nothing, false)
5  3 ┄ %3  = φ (#2 => %2, #1 => _2)::Union{Nothing, Int64}
   │   %4  = (%3 isa Main.Int64)::Bool
   └──       goto JuliaLang#5 if not %4
6  4 ─ %6  = π (%3, Int64)
   └──       goto JuliaLang#6
8  5 ─ %8  = π (%3, Nothing)
10 6 ┄ %9  = φ (JuliaLang#4 => %6, JuliaLang#5 => %8)::Union{Nothing, Int64}
   │   %10 = (%9 isa Main.Nothing)::Bool
   └──       goto JuliaLang#8 if not %10
11 7 ─ %12 = π (%9, Nothing)
   └──       goto JuliaLang#9
13 8 ─ %14 = π (%9, Int64)
15 9 ┄ %15 = φ (JuliaLang#7 => %12, JuliaLang#8 => %14)::Union{Nothing, Int64}
   │   %16 = (%15 === Main.nothing)::Bool
   └──       return %16
```
Now, we have special code in SROA (despite it not really being an
SROA transform) that looks at `===` and replaces
it by a nest of phis of booleans. The reasoning for this transform
is that it eliminates a use of a value where we only care about the
type and not the content, thus making it more likely that the value
will subsequently be eligible for SROA. In addition, while it goes
along resolving which values feed into any particular phi, it
accumulates and type conditions it encounters along the way.

Thus in the example above, something like the following happens:
- We look at %14, which πs to %9 with an Int64 constraint, so we only
  consider the JuliaLang#4 predecessor for %9 (due to the constraint), until
  we get to %3, where we again only consider the #1 predecessor,
  where we find the argument (of type Int64) and conclude the result
  is always false
- Now we pop the next item of the stack from our original phi, look
  at %12, which πs to %9 with a Nothing constraint.

At this point we used to terminate the search because we already looked
at %9. However, crucially, we looked at %9 only with an Int64 constraint,
so we missed the fact that `nothing` was in fact a possible value for this
phi. The result was a missing entry in the generated phi node:
```
1 ─       goto JuliaLang#3 if not b
2 ─ %2  = Main.nothing::Core.Compiler.Const(nothing, false)
3 ┄ %3  = φ (#1 => false)::Bool
│   %4  = φ (#2 => %2, #1 => _2)::Union{Nothing, Int64}
│   %5  = (%4 isa Main.Int64)::Bool
└──       goto JuliaLang#5 if not %5
4 ─ %7  = π (%4, Int64)
└──       goto JuliaLang#6
5 ─ %9  = π (%4, Nothing)
6 ┄ %10 = φ (JuliaLang#4 => %3, JuliaLang#5 => %3)::Bool
│   %11 = φ (JuliaLang#4 => %7, JuliaLang#5 => %9)::Union{Nothing, Int64}
│   %12 = (%11 isa Main.Nothing)::Bool
└──       goto JuliaLang#8 if not %12
7 ─       goto JuliaLang#9
8 ─       nothing::Nothing
9 ┄ %16 = φ (JuliaLang#7 => %10, JuliaLang#8 => %10)::Bool
└──       return %16
```
(note the missing #2 predecessor in phi node %3), which would result
in an undefined value at runtime, though in this case LLVM would
have taken advantage of that to just return 0:
```
define i8 @julia_f32579_16051(i64, i8) {
top:
;  @ REPL[1]:15 within `f32579'
  ret i8 0
}
```
Compare this now to the optimized IR with this patch:
```
1 ─       goto JuliaLang#3 if not b
2 ─ %2  = Main.nothing::Core.Compiler.Const(nothing, false)
3 ┄ %3  = φ (#2 => true, #1 => false)::Bool
│   %4  = φ (#2 => %2, #1 => _2)::Union{Nothing, Int64}
│   %5  = (%4 isa Main.Int64)::Bool
└──       goto JuliaLang#5 if not %5
4 ─ %7  = π (%4, Int64)
└──       goto JuliaLang#6
5 ─ %9  = π (%4, Nothing)
6 ┄ %10 = φ (JuliaLang#4 => %3, JuliaLang#5 => %3)::Bool
│   %11 = φ (JuliaLang#4 => %7, JuliaLang#5 => %9)::Union{Nothing, Int64}
│   %12 = (%11 isa Main.Nothing)::Bool
└──       goto JuliaLang#8 if not %12
7 ─       goto JuliaLang#9
8 ─       nothing::Nothing
9 ┄ %16 = φ (JuliaLang#7 => %10, JuliaLang#8 => %10)::Bool
└──       return %16
```
The %3 phi node has its missing entry and the generated LLVM code
correctly returns `b`:
```
define i8 @julia_f32579_16112(i64, i8) {
top:
  %2 = and i8 %1, 1
;  @ REPL[1]:15 within `f32579'
  ret i8 %2
}
```
mcognetta pushed a commit that referenced this pull request Aug 8, 2020
This reuses the machinery that gives good stacktraces when a user
calls wait on a Task. Since bind internally uses _wait2, this
machinery is bypassed currently.

Currently, julia throws an uninformative stacktrace in this situation:

julia> c = Channel(_ -> error("foo"))
Channel{Any}(sz_max:0,sz_curr:0)

julia> for i in c end
ERROR: foo
Stacktrace:
 [1] iterate(::Channel{Any}) at ./channels.jl:459
 [2] top-level scope at ./REPL[2]:1

With this change, the stacktrace is much more informative:

julia> for i in c end
ERROR: TaskFailedException:
foo
Stacktrace:
 [1] error(::String) at ./error.jl:33
 [2] (::var"#1#2")(::Channel{Any}) at ./REPL[4]:1
 [3] (::Base.var"JuliaLang#652#653"{var"#1#2",Channel{Any}})() at ./channels.jl:129
Stacktrace:
 [1] check_channel_state at ./channels.jl:167 [inlined]
 [2] take_unbuffered(::Channel{Any}) at ./channels.jl:405
 [3] take! at ./channels.jl:383 [inlined]
 [4] iterate(::Channel{Any}, ::Nothing) at ./channels.jl:449
 [5] iterate(::Channel{Any}) at ./channels.jl:448
 [6] top-level scope at ./REPL[5]:1
mcognetta pushed a commit that referenced this pull request Jul 13, 2022
…Lang#45790)

Currently the `@nospecialize`-d `push!(::Vector{Any}, ...)` can only
take a single item and we will end up with runtime dispatch when we try
to call it with multiple items:
```julia
julia> code_typed(push!, (Vector{Any}, Any))
1-element Vector{Any}:
 CodeInfo(
1 ─      $(Expr(:foreigncall, :(:jl_array_grow_end), Nothing, svec(Any, UInt64), 0, :(:ccall), Core.Argument(2), 0x0000000000000001, 0x0000000000000001))::Nothing
│   %2 = Base.arraylen(a)::Int64
│        Base.arrayset(true, a, item, %2)::Vector{Any}
└──      return a
) => Vector{Any}

julia> code_typed(push!, (Vector{Any}, Any, Any))
1-element Vector{Any}:
 CodeInfo(
1 ─ %1 = Base.append!(a, iter)::Vector{Any}
└──      return %1
) => Vector{Any}
```

This commit adds a new specialization that it can take arbitrary-length
items. Our compiler should still be able to optimize the single-input 
case as before via the dispatch mechanism.
```julia
julia> code_typed(push!, (Vector{Any}, Any))
1-element Vector{Any}:
 CodeInfo(
1 ─      $(Expr(:foreigncall, :(:jl_array_grow_end), Nothing, svec(Any, UInt64), 0, :(:ccall), Core.Argument(2), 0x0000000000000001, 0x0000000000000001))::Nothing
│   %2 = Base.arraylen(a)::Int64
│        Base.arrayset(true, a, item, %2)::Vector{Any}
└──      return a
) => Vector{Any}

julia> code_typed(push!, (Vector{Any}, Any, Any))
1-element Vector{Any}:
 CodeInfo(
1 ─ %1  = Base.arraylen(a)::Int64
│         $(Expr(:foreigncall, :(:jl_array_grow_end), Nothing, svec(Any, UInt64), 0, :(:ccall), Core.Argument(2), 0x0000000000000002, 0x0000000000000002))::Nothing
└──       goto JuliaLang#7 if not true
2 ┄ %4  = φ (#1 => 1, JuliaLang#6 => %14)::Int64
│   %5  = φ (#1 => 1, JuliaLang#6 => %15)::Int64
│   %6  = Base.getfield(x, %4, true)::Any
│   %7  = Base.add_int(%1, %4)::Int64
│         Base.arrayset(true, a, %6, %7)::Vector{Any}
│   %9  = (%5 === 2)::Bool
└──       goto JuliaLang#4 if not %9
3 ─       goto JuliaLang#5
4 ─ %12 = Base.add_int(%5, 1)::Int64
└──       goto JuliaLang#5
5 ┄ %14 = φ (JuliaLang#4 => %12)::Int64
│   %15 = φ (JuliaLang#4 => %12)::Int64
│   %16 = φ (JuliaLang#3 => true, JuliaLang#4 => false)::Bool
│   %17 = Base.not_int(%16)::Bool
└──       goto JuliaLang#7 if not %17
6 ─       goto #2
7 ┄       return a
) => Vector{Any}
```

This commit also adds the equivalent implementations for `pushfirst!`.
mcognetta pushed a commit that referenced this pull request Jul 13, 2022
When calling `jl_error()` or `jl_errorf()`, we must check to see if we
are so early in the bringup process that it is dangerous to attempt to
construct a backtrace because the data structures used to provide line
information are not properly setup.

This can be easily triggered by running:

```
julia -C invalid
```

On an `i686-linux-gnu` build, this will hit the "Invalid CPU Name"
branch in `jitlayers.cpp`, which calls `jl_errorf()`.  This in turn
calls `jl_throw()`, which will eventually call `jl_DI_for_fptr` as part
of the backtrace printing process, which fails as the object maps are
not fully initialized.  See the below `gdb` stacktrace for details:

```
$ gdb -batch -ex 'r' -ex 'bt' --args ./julia -C invalid
...
fatal: error thrown and no exception handler available.
ErrorException("Invalid CPU name "invalid".")

Thread 1 "julia" received signal SIGSEGV, Segmentation fault.
0xf75bd665 in std::_Rb_tree<unsigned int, std::pair<unsigned int const, JITDebugInfoRegistry::ObjectInfo>, std::_Select1st<std::pair<unsigned int const, JITDebugInfoRegistry::ObjectInfo> >, std::greater<unsigned int>, std::allocator<std::pair<unsigned int const, JITDebugInfoRegistry::ObjectInfo> > >::lower_bound (__k=<optimized out>, this=0x248) at /usr/local/i686-linux-gnu/include/c++/9.1.0/bits/stl_tree.h:1277
1277    /usr/local/i686-linux-gnu/include/c++/9.1.0/bits/stl_tree.h: No such file or directory.
 #0  0xf75bd665 in std::_Rb_tree<unsigned int, std::pair<unsigned int const, JITDebugInfoRegistry::ObjectInfo>, std::_Select1st<std::pair<unsigned int const, JITDebugInfoRegistry::ObjectInfo> >, std::greater<unsigned int>, std::allocator<std::pair<unsigned int const, JITDebugInfoRegistry::ObjectInfo> > >::lower_bound (__k=<optimized out>, this=0x248) at /usr/local/i686-linux-gnu/include/c++/9.1.0/bits/stl_tree.h:1277
 #1  std::map<unsigned int, JITDebugInfoRegistry::ObjectInfo, std::greater<unsigned int>, std::allocator<std::pair<unsigned int const, JITDebugInfoRegistry::ObjectInfo> > >::lower_bound (__x=<optimized out>, this=0x248) at /usr/local/i686-linux-gnu/include/c++/9.1.0/bits/stl_map.h:1258
 #2  jl_DI_for_fptr (fptr=4155049385, symsize=symsize@entry=0xffffcfa8, slide=slide@entry=0xffffcfa0, Section=Section@entry=0xffffcfb8, context=context@entry=0xffffcf94) at /cache/build/default-amdci5-4/julialang/julia-master/src/debuginfo.cpp:1181
 JuliaLang#3  0xf75c056a in jl_getFunctionInfo_impl (frames_out=0xffffd03c, pointer=4155049385, skipC=0, noInline=0) at /cache/build/default-amdci5-4/julialang/julia-master/src/debuginfo.cpp:1210
 JuliaLang#4  0xf7a6ca98 in jl_print_native_codeloc (ip=4155049385) at /cache/build/default-amdci5-4/julialang/julia-master/src/stackwalk.c:636
 JuliaLang#5  0xf7a6cd54 in jl_print_bt_entry_codeloc (bt_entry=0xf0798018) at /cache/build/default-amdci5-4/julialang/julia-master/src/stackwalk.c:657
 JuliaLang#6  jlbacktrace () at /cache/build/default-amdci5-4/julialang/julia-master/src/stackwalk.c:1090
 JuliaLang#7  0xf7a3cd2b in ijl_no_exc_handler (e=0xf0794010) at /cache/build/default-amdci5-4/julialang/julia-master/src/task.c:605
 JuliaLang#8  0xf7a3d10a in throw_internal (ct=ct@entry=0xf070c010, exception=<optimized out>, exception@entry=0xf0794010) at /cache/build/default-amdci5-4/julialang/julia-master/src/task.c:638
 JuliaLang#9  0xf7a3d330 in ijl_throw (e=0xf0794010) at /cache/build/default-amdci5-4/julialang/julia-master/src/task.c:654
 JuliaLang#10 0xf7a905aa in ijl_errorf (fmt=fmt@entry=0xf7647cd4 "Invalid CPU name \"%s\".") at /cache/build/default-amdci5-4/julialang/julia-master/src/rtutils.c:77
 JuliaLang#11 0xf75a4b22 in (anonymous namespace)::createTargetMachine () at /cache/build/default-amdci5-4/julialang/julia-master/src/jitlayers.cpp:823
 JuliaLang#12 JuliaOJIT::JuliaOJIT (this=<optimized out>) at /cache/build/default-amdci5-4/julialang/julia-master/src/jitlayers.cpp:1044
 JuliaLang#13 0xf7531793 in jl_init_llvm () at /cache/build/default-amdci5-4/julialang/julia-master/src/codegen.cpp:8585
 JuliaLang#14 0xf75318a8 in jl_init_codegen_impl () at /cache/build/default-amdci5-4/julialang/julia-master/src/codegen.cpp:8648
 JuliaLang#15 0xf7a51a52 in jl_restore_system_image_from_stream (f=<optimized out>) at /cache/build/default-amdci5-4/julialang/julia-master/src/staticdata.c:2131
 JuliaLang#16 0xf7a55c03 in ijl_restore_system_image_data (buf=0xe859c1c0 <jl_system_image_data> "8'\031\003", len=125161105) at /cache/build/default-amdci5-4/julialang/julia-master/src/staticdata.c:2184
 JuliaLang#17 0xf7a55cf9 in jl_load_sysimg_so () at /cache/build/default-amdci5-4/julialang/julia-master/src/staticdata.c:424
 JuliaLang#18 ijl_restore_system_image (fname=0x80a0900 "/build/bk_download/julia-d78fdad601/lib/julia/sys.so") at /cache/build/default-amdci5-4/julialang/julia-master/src/staticdata.c:2157
 JuliaLang#19 0xf7a3bdfc in _finish_julia_init (rel=rel@entry=JL_IMAGE_JULIA_HOME, ct=<optimized out>, ptls=<optimized out>) at /cache/build/default-amdci5-4/julialang/julia-master/src/init.c:741
 JuliaLang#20 0xf7a3c8ac in julia_init (rel=<optimized out>) at /cache/build/default-amdci5-4/julialang/julia-master/src/init.c:728
 JuliaLang#21 0xf7a7f61d in jl_repl_entrypoint (argc=<optimized out>, argv=0xffffddf4) at /cache/build/default-amdci5-4/julialang/julia-master/src/jlapi.c:705
 JuliaLang#22 0x080490a7 in main (argc=3, argv=0xffffddf4) at /cache/build/default-amdci5-4/julialang/julia-master/cli/loader_exe.c:59
```

To prevent this, we simply avoid calling `jl_errorf` this early in the
process, punting the problem to a later PR that can update guard
conditions within `jl_error*`.
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 this pull request may close these issues.

2 participants