Skip to content
This repository has been archived by the owner on May 27, 2021. It is now read-only.

Commit

Permalink
Adapt to nonrecursive codegen.
Browse files Browse the repository at this point in the history
  • Loading branch information
maleadt committed Mar 4, 2020
1 parent 2a6699d commit 34dc9b4
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 199 deletions.
35 changes: 12 additions & 23 deletions .gitlab-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,6 @@ variables:
# Julia versions

# the "primary" target, where we require a new GPU to make sure all tests are run
julia:1.3:
extends:
- .julia:1.3
- .test
tags:
- nvidia
- sm_75
variables:
CI_THOROUGH: 'true'

julia:nightly:
extends:
- .julia:nightly
Expand All @@ -34,14 +24,13 @@ julia:nightly:
CI_THOROUGH: 'true'
allow_failure: true

julia:1.3-debug:
julia:nightly-debug:
extends:
- .julia:source
- .test
tags:
- nvidia
variables:
CI_CLONE_ARGS: '-b release-1.3'
CI_BUILD_ARGS: 'debug'
allow_failure: true

Expand All @@ -53,7 +42,7 @@ julia:1.3-debug:

cuda:10.1:
extends:
- .julia:1.3
- .julia:nightly
- .test
variables:
JULIA_CUDA_VERSION: '10.1'
Expand All @@ -62,7 +51,7 @@ cuda:10.1:

cuda:10.0:
extends:
- .julia:1.3
- .julia:nightly
- .test
variables:
JULIA_CUDA_VERSION: '10.0'
Expand All @@ -71,7 +60,7 @@ cuda:10.0:

cuda:9.2:
extends:
- .julia:1.3
- .julia:nightly
- .test
variables:
JULIA_CUDA_VERSION: '9.2'
Expand All @@ -80,7 +69,7 @@ cuda:9.2:

cuda:9.0:
extends:
- .julia:1.3
- .julia:nightly
- .test
variables:
JULIA_CUDA_VERSION: '9.0'
Expand All @@ -89,7 +78,7 @@ cuda:9.0:

cuda:local:
extends:
- .julia:1.3
- .julia:nightly
- .test
image: nvidia/cuda:10.1-devel-ubuntu18.04
variables:
Expand All @@ -99,7 +88,7 @@ cuda:local:

cuda:none:
extends:
- .julia:1.3
- .julia:nightly
- .test
variables:
JULIA_CUDA_USE_BINARYBUILDER: 'false'
Expand All @@ -121,7 +110,7 @@ platform:arm64:
variables:
JULIA_CUDA_USE_BINARYBUILDER: 'false'
extends:
- .julia:1.3
- .julia:nightly
- .test
tags:
- nvidia-arm64
Expand All @@ -131,7 +120,7 @@ platform:arm64:

debug:
extends:
- .julia:1.3
- .julia:nightly
- .test
tags:
- nvidia
Expand All @@ -150,7 +139,7 @@ debug:

cuarrays:
extends:
- .julia:1.3
- .julia:nightly
- .test
tags:
- nvidia
Expand All @@ -174,12 +163,12 @@ cuarrays:

coverage:
extends:
- .julia:1.3
- .julia:nightly
- .coverage

documentation:
extends:
- .julia:1.3
- .julia:nightly
- .documentation
tags:
- nvidia
Expand Down
177 changes: 49 additions & 128 deletions src/compiler/irgen.jl
Original file line number Diff line number Diff line change
Expand Up @@ -58,47 +58,10 @@ function compile_method_instance(job::CompilerJob, method_instance::Core.MethodI
end

# set-up the compiler interface
last_method_instance = nothing
call_stack = Vector{Core.MethodInstance}()
dependencies = MultiDict{Core.MethodInstance,LLVM.Function}()
function hook_module_setup(ref::Ptr{Cvoid})
ref = convert(LLVM.API.LLVMModuleRef, ref)
ir = LLVM.Module(ref)
module_setup(ir)
end
function hook_module_activation(ref::Ptr{Cvoid})
ref = convert(LLVM.API.LLVMModuleRef, ref)
ir = LLVM.Module(ref)
postprocess(ir)

# find the function that this module defines
llvmfs = filter(llvmf -> !isdeclaration(llvmf) &&
linkage(llvmf) == LLVM.API.LLVMExternalLinkage,
collect(functions(ir)))

llvmf = nothing
if length(llvmfs) == 1
llvmf = first(llvmfs)
elseif length(llvmfs) > 1
llvmfs = filter!(llvmf -> startswith(LLVM.name(llvmf), "julia_"), llvmfs)
if length(llvmfs) == 1
llvmf = first(llvmfs)
end
end

@compiler_assert llvmf !== nothing job

insert!(dependencies, last_method_instance, llvmf)
end
function hook_emit_function(method_instance, code, world)
call_stack = [method_instance]
function hook_emit_function(method_instance, code)
push!(call_stack, method_instance)

# check for recursion
if method_instance in call_stack[1:end-1]
throw(KernelError(job, "recursion is currently not supported";
bt=backtrace(job, call_stack)))
end

# check for Base functions that exist in CUDAnative too
# FIXME: this might be too coarse
method = method_instance.def
Expand All @@ -115,17 +78,14 @@ function compile_method_instance(job::CompilerJob, method_instance::Core.MethodI
end
end
end
function hook_emitted_function(method, code, world)
function hook_emitted_function(method, code)
@compiler_assert last(call_stack) == method job
last_method_instance = pop!(call_stack)
pop!(call_stack)
end
param_kwargs = [:cached => false,
:track_allocations => false,
param_kwargs = [:track_allocations => false,
:code_coverage => false,
:static_alloc => false,
:prefer_specsig => true,
:module_setup => hook_module_setup,
:module_activation => hook_module_activation,
:emit_function => hook_emit_function,
:emitted_function => hook_emitted_function]
if LLVM.version() >= v"8.0" && VERSION >= v"1.3.0-DEV.547"
Expand All @@ -150,99 +110,60 @@ function compile_method_instance(job::CompilerJob, method_instance::Core.MethodI
end
params = Base.CodegenParams(;param_kwargs...)

# get the code
ref = ccall(:jl_get_llvmf_defn, LLVM.API.LLVMValueRef,
(Any, UInt, Bool, Bool, Base.CodegenParams),
method_instance, world, #=wrapper=#false, #=optimize=#false, params)
if ref == C_NULL
throw(InternalCompilerError(job, "the Julia compiler could not generate LLVM IR"))
# generate IR
native_code = ccall(:jl_create_native, Ptr{Cvoid},
(Vector{Core.MethodInstance}, Base.CodegenParams),
[method_instance], params)
@assert native_code != C_NULL
llvm_mod_ref = ccall(:jl_get_llvm_module, LLVM.API.LLVMModuleRef,
(Ptr{Cvoid},), native_code)
@assert llvm_mod_ref != C_NULL
llvm_mod = LLVM.Module(llvm_mod_ref)

# get the top-level code
code = Core.Compiler.inf_for_methodinstance(method_instance, world, world)

# get the top-level function index
llvm_func_idx = Ref{Int32}(-1)
llvm_specfunc_idx = Ref{Int32}(-1)
ccall(:jl_breakpoint, Nothing, ())
ccall(:jl_get_function_id, Nothing,
(Ptr{Cvoid}, Any, Ptr{Int32}, Ptr{Int32}),
native_code, code, llvm_func_idx, llvm_specfunc_idx)
@assert llvm_func_idx[] != -1
@assert llvm_specfunc_idx[] != -1

# get the top-level function)
llvm_func_ref = ccall(:jl_get_llvm_function, LLVM.API.LLVMValueRef,
(Ptr{Cvoid}, UInt32), native_code, llvm_func_idx[]-1)
@assert llvm_func_ref != C_NULL
llvm_func = LLVM.Function(llvm_func_ref)
llvm_specfunc_ref = ccall(:jl_get_llvm_function, LLVM.API.LLVMValueRef,
(Ptr{Cvoid}, UInt32), native_code, llvm_specfunc_idx[]-1)
@assert llvm_specfunc_ref != C_NULL
llvm_specfunc = LLVM.Function(llvm_specfunc_ref)

# configure the module
# NOTE: NVPTX::TargetMachine's data layout doesn't match the NVPTX user guide,
# so we specify it ourselves
if Int === Int64
triple!(llvm_mod, "nvptx64-nvidia-cuda")
datalayout!(llvm_mod, "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v16:16:16-v32:32:32-v64:64:64-v128:128:128-n16:32:64")
else
triple!(llvm_mod, "nvptx-nvidia-cuda")
datalayout!(llvm_mod, "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v16:16:16-v32:32:32-v64:64:64-v128:128:128-n16:32:64")
end
llvmf = LLVM.Function(ref)
ir = LLVM.parent(llvmf)
postprocess(ir)

return llvmf, dependencies
return llvm_specfunc, llvm_mod
end

function irgen(job::CompilerJob, method_instance::Core.MethodInstance, world)
entry, dependencies = @timeit_debug to "emission" compile_method_instance(job, method_instance, world)
mod = LLVM.parent(entry)

# link in dependent modules
@timeit_debug to "linking" begin
# we disable Julia's compilation cache not to poison it with GPU-specific code.
# as a result, we might get multiple modules for a single method instance.
cache = Dict{String,String}()

for called_method_instance in keys(dependencies)
llvmfs = dependencies[called_method_instance]

# link the first module
llvmf = popfirst!(llvmfs)
llvmfn = LLVM.name(llvmf)
link!(mod, LLVM.parent(llvmf))

# process subsequent duplicate modules
for dup_llvmf in llvmfs
if Base.JLOptions().debug_level >= 2
# link them too, to ensure accurate backtrace reconstruction
link!(mod, LLVM.parent(dup_llvmf))
else
# don't link them, but note the called function name in a cache
dup_llvmfn = LLVM.name(dup_llvmf)
cache[dup_llvmfn] = llvmfn
end
end
end

# resolve function declarations with cached entries
for llvmf in filter(isdeclaration, collect(functions(mod)))
llvmfn = LLVM.name(llvmf)
if haskey(cache, llvmfn)
def_llvmfn = cache[llvmfn]
replace_uses!(llvmf, functions(mod)[def_llvmfn])

@compiler_assert isempty(uses(llvmf)) job
unsafe_delete!(LLVM.parent(llvmf), llvmf)
end
end
end
entry, mod = @timeit_debug to "emission" compile_method_instance(job, method_instance, world)

# clean up incompatibilities
@timeit_debug to "clean-up" for llvmf in functions(mod)
llvmfn = LLVM.name(llvmf)

# only occurs in debug builds
delete!(function_attributes(llvmf), EnumAttribute("sspstrong", 0, JuliaContext()))

# rename functions
if !isdeclaration(llvmf)
# Julia disambiguates local functions by prefixing with `#\d#`.
# since we don't use a global function namespace, get rid of those tags.
if occursin(r"^julia_#\d+#", llvmfn)
llvmfn′ = replace(llvmfn, r"#\d+#"=>"")
if !haskey(functions(mod), llvmfn′)
LLVM.name!(llvmf, llvmfn′)
llvmfn = llvmfn′
end
end

# anonymous functions are just named `#\d`, make that somewhat more readable
m = match(r"_#(\d+)_", llvmfn)
if m !== nothing
llvmfn′ = replace(llvmfn, m.match=>"_anonymous$(m.captures[1])_")
LLVM.name!(llvmf, llvmfn′)
llvmfn = llvmfn′
end

# finally, make function names safe for ptxas
# (LLVM should to do this, but fails, see eg. D17738 and D19126)
llvmfn′ = safe_name(llvmfn)
if llvmfn != llvmfn′
LLVM.name!(llvmf, llvmfn′)
llvmfn = llvmfn′
end
end
end

# add the global exception indicator flag
Expand Down
4 changes: 2 additions & 2 deletions test/base.jl
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ function post17057_parent(arr::Ptr{Int64})
end

# bug: default module activation segfaulted on NULL child function if cached=false
params = Base.CodegenParams(cached=false)
params = Base.CodegenParams()
if VERSION >= v"1.1.0-DEV.762"
_dump_function(post17057_parent, Tuple{Ptr{Int64}},
#=native=#false, #=wrapper=#false, #=strip=#false,
Expand All @@ -31,4 +31,4 @@ end

############################################################################################

end
end
Loading

0 comments on commit 34dc9b4

Please sign in to comment.