KhronosGroup / KhronosGroup/SPIRV-LLVM-Translator
LLVM 12's SLP Vectorizer introduces unhandled llvm.masked.gather calls
- Dominant language
- LLVM
- Stars
- 625
- Forks
- 279
- Avg merge
- 3d 5h
- Merged PRs (30d)
- 34
Description
My front-end is emitting the following IR, which works fine:
```llvm
target triple = "spir64-unknown-unknown"
declare void @a([2 x i64]*)
declare {}* @b()
define void @c([3 x i64]* %.7) {
%.1 = alloca [2 x i64], align 8
call void @a([2 x i64]* %.1)
%.4 = getelementptr [2 x i64], [2 x i64]* %.1, i32 0, i32 0
br label %d.f
g.f: ; preds = %d.f
%.5 = load i64, i64* %.4, align 4
%.6 = sub i64 %.5, 0
br label %e.f
i.f: ; preds = %e.f
%.8 = getelementptr [3 x i64], [3 x i64]* %.7, i32 0, i32 0
%.9 = load i64, i64* %.8, align 4
%.10 = icmp slt i64 %.9, 0
%.11 = xor i1 %.10, true
%.12 = load i64, i64* %.8, align 4
%.13 = select i1 %.11, i64 %.12, i64 0
%.14 = getelementptr [3 x i64], [3 x i64]* %.7, i32 0, i32 2
%.15 = load i64, i64* %.14, align 4
%.16 = icmp slt i64 %.15, 0
%.17 = xor i1 %.16, true
%.18 = load i64, i64* %.14, align 4
%.19 = select i1 %.17, i64 %.18, i64 0
%.20 = icmp sle i64 1, %.53
%.21 = icmp sle i64 %.53, %.13
%.22 = zext i1 %.20 to i8
%.23 = zext i1 %.21 to i8
%.24 = and i8 %.22, %.23
%.25 = trunc i8 %.24 to i1
%.26 = icmp sle i64 0, %.54
%.28 = zext i1 %.26 to i8
%.30 = and i8 %.28, 1
%.31 = trunc i8 %.30 to i1
%.32 = load i64, i64* %.4, align 4
%.33 = icmp sle i64 %.32, %.19
%.35 = zext i1 %.33 to i8
%.37 = trunc i8 %.35 to i1
%.41 = zext i1 %.31 to i8
%.42 = zext i1 %.37 to i8
%.43 = and i8 %.41, %.42
%.44 = trunc i8 %.43 to i1
%.45 = zext i1 %.25 to i8
%.46 = zext i1 %.44 to i8
%.47 = and i8 %.45, %.46
%.48 = trunc i8 %.47 to i1
br i1 %.48, label %h.f, label %.
.: ; preds = %i.f
ret void
h.f: ; preds = %i.f
%1 = call {}* @b()
unreachable
d.f: ; preds = %0
br label %g.f
e.f: ; preds = %g.f
%.51 = sdiv i64 %.6, 1
%.52 = sub i64 %.6, 0
%.53 = add i64 %.52, 0
%.54 = add i64 %.51, 1
br label %i.f
}
```
```
$ llvm-as unopt.ll -o unopt.bc
$ llvm-spirv --spirv-debug-info-version=ocl-100 unopt.bc
```
On LLVM 12 the SLP Vectorizer introduces calls to gather intrinsics that the translator does not handle:
```
$ opt -O3 unopt.bc
$ llvm-spirv --spirv-debug-info-version=ocl-100 opt.bc
InvalidFunctionCall: Unexpected llvm intrinsic:
llvm.masked.gather.v2i64.v2p0i64 [Src: ../lib/SPIRV/SPIRVWriter.cpp:2755 ]
```
```llvm
declare void @a([2 x i64]*) local_unnamed_addr
declare {}* @b() local_unnamed_addr
define void @c([3 x i64]* nocapture readonly %.7) local_unnamed_addr {
d.f:
%.1 = alloca [2 x i64], align 8
call void @a([2 x i64]* nonnull %.1)
%.4 = getelementptr inbounds [2 x i64], [2 x i64]* %.1, i64 0, i64 0
%.5 = load i64, i64* %.4, align 8
%.54 = add i64 %.5, 1
%.8 = getelementptr [3 x i64], [3 x i64]* %.7, i64 0, i64 0
%.14 = getelementptr [3 x i64], [3 x i64]* %.7, i64 0, i64 2
%0 = insertelement <2 x i64*> poison, i64* %.8, i32 0
%1 = insertelement <2 x i64*> %0, i64* %.14, i32 1
%2 = call <2 x i64> @llvm.masked.gather.v2i64.v2p0i64(<2 x i64*> %1, i32 4, <2 x i1> , <2 x i64> undef)
%3 = icmp sgt <2 x i64> %2, zeroinitializer
%4 = select <2 x i1> %3, <2 x i64> %2, <2 x i64> zeroinitializer
%5 = insertelement <2 x i64> poison, i64 %.5, i32 0
%6 = shufflevector <2 x i64> %5, <2 x i64> undef, <2 x i32> zeroinitializer
%7 = icmp sle <2 x i64> %6, %4
%8 = insertelement <2 x i64> %5, i64 %.54, i32 1
%9 = icmp sgt <2 x i64> %8,
%10 = and <2 x i1> %9, %7
%shift = shufflevector <2 x i1> %10, <2 x i1> poison, <2 x i32>
%11 = and <2 x i1> %10, %shift
%.473 = extractelement <2 x i1> %11, i32 0
br i1 %.473, label %h.f, label %.
.: ; preds = %d.f
ret void
h.f: ; preds = %d.f
%12 = call {}* @b()
unreachable
}
; Function Attrs: nofree nosync nounwind readonly willreturn
declare <2 x i64> @llvm.masked.gather.v2i64.v2p0i64(<2 x i64*>, i32 immarg, <2 x i1>, <2 x i64>) #0
attributes #0 = { nofree nosync nounwind readonly willreturn }
```
Is there any guarantee / expectation that code produced by LLVM's optimization passes is supported by the translator?
Contributor guide
Research direction
Reproduce the failure with unopt.bc and opt.bc using opt -O3 and llvm-spirv, then inspect SPIRVWriter.cpp around line 2755. Trace handling of llvm.masked.gather and establish the translator’s expected support boundary; done should clarify whether LLVM-generated gather calls are supported and provide a regression result.
Written by the indexing model from the issue text.
Assessment
- Domain
- compilers
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100