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

Implement ReinterpretArray #23750

Merged
merged 3 commits into from
Oct 9, 2017
Merged

Implement ReinterpretArray #23750

merged 3 commits into from
Oct 9, 2017

Commits on Sep 29, 2017

  1. Fix performance problems with Ptr

    LLVM is unhappy with the way we treat `Ptr` currently, causing pretty terrible
    performance for ReinterpretArray. This patch does a few things to help LLVM along.
    
    - Stop folding a bitcast into load/store instructions. LLVM's mem2reg pass only
      works if the load/store instructions are the direct arguments of load/store
      instructions.
    - Several minor cleanups of the generated IR.
    - Emit pointer additions as getelemtptr rather than in the integer domain. Getelementptr
      has aliasing implications that the raw integer addition doesn't have (in essence,
      with getelemenptr, it is clear which of the operands is the pointer and which is
      the offset). This does mean significantly more inttoptr/ptrtoint casting, but
      instcombine will happily fold them (though it does make mem2reg more important so
      instcombine can be effective). At the implementation level, this is accomplished
      through through two new intrinsics for pointer addition and subtraction.
    - An LLVM patch to mem2reg that allows it to handle memcpy instructions. Since we emit
      variable assignment as memcpy, this allows mem2reg to fold many of these. As mentioned,
      this is important to allow instcombine to fold all the inttoptr/ptrtoint pairs in
      order to allow follow-on optimizations to actually analyze the pointers.
    Keno committed Sep 29, 2017
    Configuration menu
    Copy the full SHA
    820ec5f View commit details
    Browse the repository at this point in the history

Commits on Oct 3, 2017

  1. Implement ReinterpretArray

    This redoes `reinterpret` in julia rather than punning the memory
    of the actual array. The motivation for this is to avoid the API
    limitations of the current reinterpret implementation (Array only,
    preventing strong TBAA, alignment problems). The surface API
    essentially unchanged, though the shape argument to reinterpret
    is removed, since those concepts are now orthogonal. The return
    type from `reinterpret` is now `ReinterpretArray`, which implements
    the AbstractArray interface and does the reinterpreting lazily on
    demand. The compiler is able to fold away the abstraction and
    generate very tight IR:
    
    ```
    julia> ar = reinterpret(Complex{Int64}, rand(Int64, 1000));
    
    julia> typeof(ar)
    Base.ReinterpretArray{Complex{Int64},Int64,1,Array{Int64,1}}
    
    julia> f(ar) = @inbounds return ar[1]
    f (generic function with 1 method)
    
    julia> @code_llvm f(ar)
    
    ; Function f
    ; Location: REPL[2]
    define void @julia_f_63575({ i64, i64 } addrspace(11)* noalias nocapture sret, %jl_value_t addrspace(10)* dereferenceable(8)) #0 {
    top:
    ; Location: REPL[2]:1
    ; Function getindex; {
    ; Location: reinterpretarray.jl:31
      %2 = addrspacecast %jl_value_t addrspace(10)* %1 to %jl_value_t addrspace(11)*
      %3 = bitcast %jl_value_t addrspace(11)* %2 to %jl_value_t addrspace(10)* addrspace(11)*
      %4 = load %jl_value_t addrspace(10)*, %jl_value_t addrspace(10)* addrspace(11)* %3, align 8
      %5 = addrspacecast %jl_value_t addrspace(10)* %4 to %jl_value_t addrspace(11)*
      %6 = bitcast %jl_value_t addrspace(11)* %5 to i64* addrspace(11)*
      %7 = load i64*, i64* addrspace(11)* %6, align 8
      %8 = load i64, i64* %7, align 8
      %9 = getelementptr i64, i64* %7, i64 1
      %10 = load i64, i64* %9, align 8
      %.sroa.0.0..sroa_idx = getelementptr inbounds { i64, i64 }, { i64, i64 } addrspace(11)* %0, i64 0, i32 0
      store i64 %8, i64 addrspace(11)* %.sroa.0.0..sroa_idx, align 8
      %.sroa.3.0..sroa_idx13 = getelementptr inbounds { i64, i64 }, { i64, i64 } addrspace(11)* %0, i64 0, i32 1
      store i64 %10, i64 addrspace(11)* %.sroa.3.0..sroa_idx13, align 8
    ;}
      ret void
    }
    
    julia> g(a) = @inbounds return reinterpret(Complex{Int64}, a)[1]
    g (generic function with 1 method)
    
    julia> @code_llvm g(randn(1000))
    
    ; Function g
    ; Location: REPL[4]
    define void @julia_g_63642({ i64, i64 } addrspace(11)* noalias nocapture sret, %jl_value_t addrspace(10)* dereferenceable(40)) #0 {
    top:
    ; Location: REPL[4]:1
    ; Function getindex; {
    ; Location: reinterpretarray.jl:31
      %2 = addrspacecast %jl_value_t addrspace(10)* %1 to %jl_value_t addrspace(11)*
      %3 = bitcast %jl_value_t addrspace(11)* %2 to double* addrspace(11)*
      %4 = load double*, double* addrspace(11)* %3, align 8
      %5 = bitcast double* %4 to i64*
      %6 = load i64, i64* %5, align 8
      %7 = getelementptr double, double* %4, i64 1
      %8 = bitcast double* %7 to i64*
      %9 = load i64, i64* %8, align 8
      %.sroa.0.0..sroa_idx = getelementptr inbounds { i64, i64 }, { i64, i64 } addrspace(11)* %0, i64 0, i32 0
      store i64 %6, i64 addrspace(11)* %.sroa.0.0..sroa_idx, align 8
      %.sroa.3.0..sroa_idx13 = getelementptr inbounds { i64, i64 }, { i64, i64 } addrspace(11)* %0, i64 0, i32 1
      store i64 %9, i64 addrspace(11)* %.sroa.3.0..sroa_idx13, align 8
    ;}
      ret void
    }
    ```
    
    In addition, the new `reinterpret` implementation is able to handle any AbstractArray
    (whether useful or not is a separate decision):
    
    ```
    invoke(reinterpret, Tuple{Type{Complex{Float64}}, AbstractArray}, Complex{Float64}, speye(10))
    5×10 Base.ReinterpretArray{Complex{Float64},Float64,2,SparseMatrixCSC{Float64,Int64}}:
     1.0+0.0im  0.0+1.0im  0.0+0.0im  0.0+0.0im  0.0+0.0im  0.0+0.0im  0.0+0.0im  0.0+0.0im  0.0+0.0im  0.0+0.0im
     0.0+0.0im  0.0+0.0im  1.0+0.0im  0.0+1.0im  0.0+0.0im  0.0+0.0im  0.0+0.0im  0.0+0.0im  0.0+0.0im  0.0+0.0im
     0.0+0.0im  0.0+0.0im  0.0+0.0im  0.0+0.0im  1.0+0.0im  0.0+1.0im  0.0+0.0im  0.0+0.0im  0.0+0.0im  0.0+0.0im
     0.0+0.0im  0.0+0.0im  0.0+0.0im  0.0+0.0im  0.0+0.0im  0.0+0.0im  1.0+0.0im  0.0+1.0im  0.0+0.0im  0.0+0.0im
     0.0+0.0im  0.0+0.0im  0.0+0.0im  0.0+0.0im  0.0+0.0im  0.0+0.0im  0.0+0.0im  0.0+0.0im  1.0+0.0im  0.0+1.0im
    ```
    
    The remaining todo is to audit the uses of reinterpret in base. I've fixed up the uses themselves, but there's
    code deeper in the array code that needs to be broadened to allow ReinterpretArray.
    
    Fixes #22849
    Fixes #19238
    Keno committed Oct 3, 2017
    Configuration menu
    Copy the full SHA
    933218e View commit details
    Browse the repository at this point in the history

Commits on Oct 7, 2017

  1. Configuration menu
    Copy the full SHA
    0054051 View commit details
    Browse the repository at this point in the history