KhronosGroup / KhronosGroup/SPIRV-LLVM-Translator

LLVM 12's SLP Vectorizer introduces unhandled llvm.masked.gather calls

Open
#1,139 6 comments 0 reactions 0 assignees View on GitHub
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

Open the contributing 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.