Skip to content

Commit 7003f7d

Browse files
authored
[clang-sycl-linker] Replace llvm-link with API calls (#133797)
This PR has the following changes: Replace llvm-link with calls to linkInModule to link device files Add -print-linked-module option to dump linked module for testing Added a test to verify that linking is working as expected. We will eventually move to using thin LTO for linking device inputs. Thanks --------- Signed-off-by: Arvind Sudarsanam <[email protected]>
1 parent 01889de commit 7003f7d

File tree

10 files changed

+201
-111
lines changed

10 files changed

+201
-111
lines changed

clang/test/Driver/Inputs/SYCL/bar.ll

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
target triple = "spirv64"
2+
3+
define spir_func i32 @bar_func1(i32 %a, i32 %b) {
4+
entry:
5+
%res = add nsw i32 %b, %a
6+
ret i32 %res
7+
}

clang/test/Driver/Inputs/SYCL/baz.ll

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
target triple = "spirv64"
2+
3+
define spir_func i32 @bar_func1(i32 %a, i32 %b) {
4+
entry:
5+
%mul = shl nsw i32 %a, 1
6+
%res = add nsw i32 %mul, %b
7+
ret i32 %res
8+
}
9+
10+
define spir_func i32 @baz_func1(i32 %a) {
11+
entry:
12+
%add = add nsw i32 %a, 5
13+
%res = tail call spir_func i32 @bar_func1(i32 %a, i32 %add)
14+
ret i32 %res
15+
}

clang/test/Driver/Inputs/SYCL/foo.ll

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
target triple = "spirv64"
2+
3+
define spir_func i32 @foo_func1(i32 %a, i32 %b) {
4+
entry:
5+
%call = tail call spir_func i32 @addFive(i32 %b)
6+
%res = tail call spir_func i32 @bar_func1(i32 %a, i32 %call)
7+
ret i32 %res
8+
}
9+
10+
declare spir_func i32 @bar_func1(i32, i32)
11+
12+
declare spir_func i32 @addFive(i32)
13+
14+
define spir_func i32 @foo_func2(i32 %c, i32 %d, i32 %e) {
15+
entry:
16+
%call = tail call spir_func i32 @foo_func1(i32 %c, i32 %d)
17+
%res = mul nsw i32 %call, %e
18+
ret i32 %res
19+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
target triple = "spirv64"
2+
3+
define spir_func i32 @addFive(i32 %a) {
4+
entry:
5+
%res = add nsw i32 %a, 5
6+
ret i32 %res
7+
}
8+
9+
define spir_func i32 @unusedFunc(i32 %a) {
10+
entry:
11+
%res = mul nsw i32 %a, 5
12+
ret i32 %res
13+
}
Lines changed: 18 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,41 @@
11
// Tests the clang-sycl-linker tool.
22
//
3-
// Test a simple case without arguments.
4-
// RUN: %clangxx -emit-llvm -c %s -o %t_1.bc
5-
// RUN: %clangxx -emit-llvm -c %s -o %t_2.bc
6-
// RUN: clang-sycl-linker --dry-run -triple spirv64 %t_1.bc %t_2.bc -o a.spv 2>&1 \
7-
// RUN: | FileCheck %s --check-prefix=SIMPLE
8-
// SIMPLE: "{{.*}}llvm-link{{.*}}" {{.*}}.bc {{.*}}.bc -o [[FIRSTLLVMLINKOUT:.*]].bc --suppress-warnings
9-
// SIMPLE-NEXT: "{{.*}}llvm-spirv{{.*}}" {{.*}}-o a.spv [[FIRSTLLVMLINKOUT]].bc
3+
// Test the dry run of a simple case to link two input files.
4+
// RUN: %clangxx -emit-llvm -c -target spirv64 %s -o %t_1.bc
5+
// RUN: %clangxx -emit-llvm -c -target spirv64 %s -o %t_2.bc
6+
// RUN: clang-sycl-linker --dry-run -v -triple=spirv64 %t_1.bc %t_2.bc -o a.spv 2>&1 \
7+
// RUN: | FileCheck %s --check-prefix=SIMPLE-FO
8+
// SIMPLE-FO: sycl-device-link: inputs: {{.*}}.bc, {{.*}}.bc libfiles: output: [[LLVMLINKOUT:.*]].bc
9+
// SIMPLE-FO-NEXT: "{{.*}}llvm-spirv{{.*}}" {{.*}}-o a.spv [[LLVMLINKOUT]].bc
1010
//
11-
// Test that llvm-link is not called when only one input is present.
12-
// RUN: clang-sycl-linker --dry-run -triple spirv64 %t_1.bc -o a.spv 2>&1 \
13-
// RUN: | FileCheck %s --check-prefix=SIMPLE-NO-LINK
14-
// SIMPLE-NO-LINK: "{{.*}}llvm-spirv{{.*}}" {{.*}}-o a.spv {{.*}}.bc
15-
//
16-
// Test a simple case with device library files specified.
11+
// Test the dry run of a simple case with device library files specified.
1712
// RUN: touch %T/lib1.bc
1813
// RUN: touch %T/lib2.bc
19-
// RUN: clang-sycl-linker --dry-run -triple spirv64 %t_1.bc %t_2.bc --library-path=%T --device-libs=lib1.bc,lib2.bc -o a.spv 2>&1 \
14+
// RUN: clang-sycl-linker --dry-run -v -triple=spirv64 %t_1.bc %t_2.bc --library-path=%T --device-libs=lib1.bc,lib2.bc -o a.spv 2>&1 \
2015
// RUN: | FileCheck %s --check-prefix=DEVLIBS
21-
// DEVLIBS: "{{.*}}llvm-link{{.*}}" {{.*}}.bc {{.*}}.bc -o [[FIRSTLLVMLINKOUT:.*]].bc --suppress-warnings
22-
// DEVLIBS-NEXT: "{{.*}}llvm-link{{.*}}" -only-needed [[FIRSTLLVMLINKOUT]].bc {{.*}}lib1.bc {{.*}}lib2.bc -o [[SECONDLLVMLINKOUT:.*]].bc --suppress-warnings
23-
// DEVLIBS-NEXT: "{{.*}}llvm-spirv{{.*}}" {{.*}}-o a.spv [[SECONDLLVMLINKOUT]].bc
16+
// DEVLIBS: sycl-device-link: inputs: {{.*}}.bc libfiles: {{.*}}lib1.bc, {{.*}}lib2.bc output: [[LLVMLINKOUT:.*]].bc
17+
// DEVLIBS-NEXT: "{{.*}}llvm-spirv{{.*}}" {{.*}}-o a.spv [[LLVMLINKOUT]].bc
2418
//
25-
// Test a simple case with .o (fat object) as input.
26-
// TODO: Remove this test once fat object support is added.
27-
// RUN: %clangxx -c %s -o %t.o
28-
// RUN: not clang-sycl-linker --dry-run -triple spirv64 %t.o -o a.spv 2>&1 \
19+
// Test a simple case with a random file (not bitcode) as input.
20+
// RUN: touch %t.o
21+
// RUN: not clang-sycl-linker -triple spirv64 %t.o -o a.spv 2>&1 \
2922
// RUN: | FileCheck %s --check-prefix=FILETYPEERROR
3023
// FILETYPEERROR: Unsupported file type
3124
//
3225
// Test to see if device library related errors are emitted.
33-
// RUN: not clang-sycl-linker --dry-run -triple spirv64 %t_1.bc %t_2.bc --library-path=%T --device-libs= -o a.spv 2>&1 \
26+
// RUN: not clang-sycl-linker --dry-run -triple=spirv64 %t_1.bc %t_2.bc --library-path=%T --device-libs= -o a.spv 2>&1 \
3427
// RUN: | FileCheck %s --check-prefix=DEVLIBSERR1
3528
// DEVLIBSERR1: Number of device library files cannot be zero
36-
// RUN: not clang-sycl-linker --dry-run -triple spirv64 %t_1.bc %t_2.bc --library-path=%T --device-libs=lib1.bc,lib2.bc,lib3.bc -o a.spv 2>&1 \
29+
// RUN: not clang-sycl-linker --dry-run -triple=spirv64 %t_1.bc %t_2.bc --library-path=%T --device-libs=lib1.bc,lib2.bc,lib3.bc -o a.spv 2>&1 \
3730
// RUN: | FileCheck %s --check-prefix=DEVLIBSERR2
3831
// DEVLIBSERR2: '{{.*}}lib3.bc' SYCL device library file is not found
3932
//
4033
// Test if correct set of llvm-spirv options are emitted for windows environment.
41-
// RUN: clang-sycl-linker --dry-run -triple spirv64 --is-windows-msvc-env %t_1.bc %t_2.bc -o a.spv 2>&1 \
34+
// RUN: clang-sycl-linker --dry-run -v -triple=spirv64 --is-windows-msvc-env %t_1.bc %t_2.bc -o a.spv 2>&1 \
4235
// RUN: | FileCheck %s --check-prefix=LLVMOPTSWIN
4336
// LLVMOPTSWIN: -spirv-debug-info-version=ocl-100 -spirv-allow-extra-diexpressions -spirv-allow-unknown-intrinsics=llvm.genx. -spirv-ext=
4437
//
4538
// Test if correct set of llvm-spirv options are emitted for linux environment.
46-
// RUN: clang-sycl-linker --dry-run -triple spirv64 %t_1.bc %t_2.bc -o a.spv 2>&1 \
39+
// RUN: clang-sycl-linker --dry-run -v -triple=spirv64 %t_1.bc %t_2.bc -o a.spv 2>&1 \
4740
// RUN: | FileCheck %s --check-prefix=LLVMOPTSLIN
4841
// LLVMOPTSLIN: -spirv-debug-info-version=nonsemantic-shader-200 -spirv-allow-unknown-intrinsics=llvm.genx. -spirv-ext=
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# RUN: llvm-as %S/Inputs/SYCL/foo.ll -o %t.foo.bc
2+
# RUN: llvm-as %S/Inputs/SYCL/bar.ll -o %t.bar.bc
3+
# RUN: llvm-as %S/Inputs/SYCL/baz.ll -o %t.baz.bc
4+
# RUN: llvm-as %S/Inputs/SYCL/libsycl.ll -o %t.libsycl.bc
5+
# RUN: clang-sycl-linker %t.foo.bc %t.bar.bc -triple=spirv64 --dry-run -o a.spv --print-linked-module 2>&1 | FileCheck %s --check-prefix=CHECK-SIMPLE
6+
7+
# RUN: not clang-sycl-linker %t.bar.bc %t.baz.bc -triple=spirv64 --dry-run -o a.spv --print-linked-module 2>&1 | FileCheck %s --check-prefix=CHECK-MULTIPLE-DEFS
8+
9+
# RUN: clang-sycl-linker %t.foo.bc %t.bar.bc -device-libs=%t.libsycl.bc -library-path= -triple=spirv64 --dry-run -o a.spv --print-linked-module 2>&1 | FileCheck %s --check-prefix=CHECK-DEVICE-LIB
10+
11+
; CHECK-SIMPLE: define {{.*}}foo_func1{{.*}}
12+
; CHECK-SIMPLE: define {{.*}}foo_func2{{.*}}
13+
; CHECK-SIMPLE: define {{.*}}bar_func1{{.*}}
14+
; CHECK-SIMPLE-NOT: define {{.*}}addFive{{.*}}
15+
; CHECK-SIMPLE-NOT: define {{.*}}unusedFunc{{.*}}
16+
17+
; CHECK-MULTIPLE-DEFS: error: Linking globals named {{.*}}bar_func1{{.*}} symbol multiply defined!
18+
19+
; CHECK-DEVICE-LIB: define {{.*}}foo_func1{{.*}}
20+
; CHECK-DEVICE-LIB: define {{.*}}foo_func2{{.*}}
21+
; CHECK-DEVICE-LIB: define {{.*}}bar_func1{{.*}}
22+
; CHECK-DEVICE-LIB: define {{.*}}addFive{{.*}}
23+
; CHECK-DEVICE-LIB-NOT: define {{.*}}unusedFunc{{.*}}

clang/test/Driver/sycl-link-spirv-target.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,6 @@
44
// Test that -Xlinker options are being passed to clang-sycl-linker.
55
// RUN: touch %t.bc
66
// RUN: %clangxx -### --target=spirv64 --sycl-link -Xlinker --llvm-spirv-path=/tmp \
7-
// RUN: -Xlinker --library-path=/tmp -Xlinker --device-libs=lib1.bc,lib2.bc %t.bc 2>&1 \
7+
// RUN: -Xlinker -triple=spirv64 -Xlinker --library-path=/tmp -Xlinker --device-libs=lib1.bc,lib2.bc %t.bc 2>&1 \
88
// RUN: | FileCheck %s -check-prefix=XLINKEROPTS
9-
// XLINKEROPTS: "{{.*}}clang-sycl-linker{{.*}}" "--llvm-spirv-path=/tmp" "--library-path=/tmp" "--device-libs=lib1.bc,lib2.bc" "{{.*}}.bc" "-o" "a.out"
9+
// XLINKEROPTS: "{{.*}}clang-sycl-linker{{.*}}" "--llvm-spirv-path=/tmp" "-triple=spirv64" "--library-path=/tmp" "--device-libs=lib1.bc,lib2.bc" "{{.*}}.bc" "-o" "a.out"

clang/tools/clang-sycl-linker/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
set(LLVM_LINK_COMPONENTS
22
${LLVM_TARGETS_TO_BUILD}
33
BinaryFormat
4+
BitWriter
5+
Core
6+
IRReader
7+
Linker
48
Option
59
Object
610
TargetParser

0 commit comments

Comments
 (0)