JuliaGPU / JuliaGPU/GPUCompiler.jl
Killed exception argument stack slots are not cleaned-up
- 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