JuliaGPU / JuliaGPU/GPUCompiler.jl

Killed exception argument stack slots are not cleaned-up

Open
#46 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Julia
Stars
187
Forks
68
Avg merge
1d 12h
Merged PRs (30d)
28

Description

Dead simple kernel without inbounds:

```julia
julia> function kernel(eds)
eds[1] = 1
return nothing
end

julia> CUDA.code_llvm(kernel, Tuple{CuDeviceArray{Int,2,AS.Global}}; debuginfo=:none)

define dso_local void @julia_kernel_1546({ [2 x i64], i64 }* nocapture nonnull readonly dereferenceable(24)) local_unnamed_addr {
top:
%1 = alloca [1 x i64], align 8
%2 = getelementptr inbounds [1 x i64], [1 x i64]* %1, i64 0, i64 0
store i64 1, i64* %2, align 8
%3 = getelementptr inbounds { [2 x i64], i64 }, { [2 x i64], i64 }* %0, i64 0, i32 0, i64 0
%4 = getelementptr inbounds { [2 x i64], i64 }, { [2 x i64], i64 }* %0, i64 0, i32 0, i64 1
%5 = load i64, i64* %3, align 8
%6 = load i64, i64* %4, align 8
%7 = mul i64 %6, %5
%8 = icmp slt i64 %7, 1
br i1 %8, label %L14, label %L17

L14: ; preds = %top
call fastcc void @julia_throw_boundserror_1548()
call void asm sideeffect "exit;", ""() #2
br label %L17

L17: ; preds = %L14, %top
%9 = getelementptr inbounds { [2 x i64], i64 }, { [2 x i64], i64 }* %0, i64 0, i32 1
%10 = bitcast i64* %9 to i64 addrspace(1)**
%11 = load i64 addrspace(1)*, i64 addrspace(1)** %10, align 8
store i64 1, i64 addrspace(1)* %11, align 8
ret void
}
```

Nasty, unused alloca that trashes performance (causes local memory access by every CUDA thread).

Unoptimized IR confirms this is the BoundsError:

```
julia> CUDA.code_llvm(kernel, Tuple{CuDeviceArray{Int,2,AS.Global}}; debuginfo=:none, optimize=false)

define dso_local void @julia_kernel_1561({ [2 x i64], i64 } addrspace(11)* nocapture nonnull readonly dereferenceable(24)) local_unnamed_addr {
top:
%1 = alloca [1 x i64]
...
L2: ; preds = %top
%7 = getelementptr inbounds [1 x i64], [1 x i64]* %1, i32 0, i32 0
store i64 1, i64* %7, align 8
...
L14: ; preds = %L2
%26 = addrspacecast [1 x i64]* %1 to [1 x i64] addrspace(11)*
%27 = call fastcc nonnull %jl_value_t addrspace(10)* @julia_throw_boundserror_1563({ [2 x i64], i64 } addrspace(11)* nocapture readonly %0, [1 x i64] addrspace(11)* nocapture readonly %26)
call void asm sideeffect "exit;", ""()
br label %L13
...
}
```

Doing an additional SROA cleans that up:

```
$ opt -sroa --filter-print-funcs=julia_kernel_1574 --print-before-all --print-after-all test.ll -o /dev/null
*** IR Dump Before SROA ***
define dso_local void @julia_kernel_1574({ [2 x i64], i64 }* nocapture nonnull readonly dereferenceable(24) %0) local_unnamed_addr {
top:
%1 = alloca [1 x i64], align 8
%2 = getelementptr inbounds [1 x i64], [1 x i64]* %1, i64 0, i64 0
store i64 1, i64* %2, align 8
%3 = getelementptr inbounds { [2 x i64], i64 }, { [2 x i64], i64 }* %0, i64 0, i32 0, i64 0
%4 = getelementptr inbounds { [2 x i64], i64 }, { [2 x i64], i64 }* %0, i64 0, i32 0, i64 1
%5 = load i64, i64* %3, align 8
%6 = load i64, i64* %4, align 8
%7 = mul i64 %6, %5
%8 = icmp slt i64 %7, 1
br i1 %8, label %L14, label %L17
L14: ; preds = %top
call fastcc void @julia_throw_boundserror_1576()
call void asm sideeffect "exit;", ""() #2
br label %L17
L17: ; preds = %L14, %top
%9 = getelementptr inbounds { [2 x i64], i64 }, { [2 x i64], i64 }* %0, i64 0, i32 1
%10 = bitcast i64* %9 to i64 addrspace(1)**
%11 = load i64 addrspace(1)*, i64 addrspace(1)** %10, align 8
store i64 1, i64 addrspace(1)* %11, align 8
ret void
}
*** IR Dump After SROA ***
define dso_local void @julia_kernel_1574({ [2 x i64], i64 }* nocapture nonnull readonly dereferenceable(24) %0) local_unnamed_addr {
top:
%1 = getelementptr inbounds { [2 x i64], i64 }, { [2 x i64], i64 }* %0, i64 0, i32 0, i64 0
%2 = getelementptr inbounds { [2 x i64], i64 }, { [2 x i64], i64 }* %0, i64 0, i32 0, i64 1
%3 = load i64, i64* %1, align 8
%4 = load i64, i64* %2, align 8
%5 = mul i64 %4, %3
%6 = icmp slt i64 %5, 1
br i1 %6, label %L14, label %L17
L14: ; preds = %top
call fastcc void @julia_throw_boundserror_1576()
call void asm sideeffect "exit;", ""() #2
br label %L17
L17: ; preds = %L14, %top
%7 = getelementptr inbounds { [2 x i64], i64 }, { [2 x i64], i64 }* %0, i64 0, i32 1
%8 = bitcast i64* %7 to i64 addrspace(1)**
%9 = load i64 addrspace(1)*, i64 addrspace(1)** %8, align 8
store i64 1, i64 addrspace(1)* %9, align 8
ret void
}
```

TODO: shouldn't Base's pipeline catch this? If not, add this to the GPU-specific pipeline.

Contributor guide

No contributing guide indexed for this repository

Research direction

Start by comparing the Base compiler pipeline with the GPU-specific pipeline, using the kernel's optimized and unoptimized LLVM IR as the reproduction. Check whether SROA is expected to remove the unused exception argument alloca; done means the generated GPU IR no longer retains the unnecessary local-memory allocation, with the responsible pipeline identified.

Written by the indexing model from the issue text.

Assessment

Tech stack
julia
Domain
compilers
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.