Skip to content

Commit 56a6ae2

Browse files
author
Martin Wehking
authored
[SYCL][NVPTX] Create one bitcode library for NVPTX (#15048)
Create one single bitcode library for NVPTX by compiling each libdev file into bitcode first, linking these together and running opt on them. Strip away metadata by reusing prepare_builtins from libclc. Remove NVPTX bundles from the libdev object files and remove any unbundling action spawned by the Clang driver for the SYCL toolchain when compiling for the NVPTX backend. Make the driver link against the single bitcode libraries for NVPTX for the SYCL toolchain when device library linkage is not excluded. Ensure that the clang tests check for the correctness of the new clang driver actions and check if the driver still links the device code against the itt device libraries when device library linkage has been excluded. Refactor SYCLLibdevice.cmake by creating functions and grouping e.g. the same compilation flags for a filetype together in one variable. Reuse these variables and call functions to remove redundancies.
1 parent bfc4015 commit 56a6ae2

File tree

9 files changed

+598
-540
lines changed

9 files changed

+598
-540
lines changed

clang/lib/Driver/Driver.cpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5855,10 +5855,9 @@ class OffloadingActionBuilder final {
58555855
++NumOfDeviceLibLinked;
58565856
Arg *InputArg = MakeInputArg(Args, C.getDriver().getOpts(),
58575857
Args.MakeArgString(LibName));
5858-
if (TC->getTriple().isNVPTX() ||
5859-
(TC->getTriple().isSPIR() &&
5860-
TC->getTriple().getSubArch() ==
5861-
llvm::Triple::SPIRSubArch_fpga)) {
5858+
if (TC->getTriple().isSPIR() &&
5859+
TC->getTriple().getSubArch() ==
5860+
llvm::Triple::SPIRSubArch_fpga) {
58625861
auto *SYCLDeviceLibsInputAction =
58635862
C.MakeAction<InputAction>(*InputArg, types::TY_Object);
58645863
auto *SYCLDeviceLibsUnbundleAction =

clang/lib/Driver/ToolChains/SYCL.cpp

Lines changed: 41 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -212,31 +212,51 @@ SYCL::getDeviceLibraries(const Compilation &C, const llvm::Triple &TargetTriple,
212212
SmallVector<std::string, 8> LibraryList;
213213
const llvm::opt::ArgList &Args = C.getArgs();
214214

215+
// For NVPTX we only use one single bitcode library and ignore
216+
// manually specified SYCL device libraries.
217+
bool IgnoreSingleLibs = TargetTriple.isNVPTX();
218+
215219
struct DeviceLibOptInfo {
216220
StringRef DeviceLibName;
217221
StringRef DeviceLibOption;
218222
};
219223

220-
bool NoDeviceLibs = false;
221-
// Currently, all SYCL device libraries will be linked by default. Linkage
222-
// of "internal" libraries cannot be affected via -fno-sycl-device-lib.
224+
// Currently, all SYCL device libraries will be linked by default.
223225
llvm::StringMap<bool> DeviceLibLinkInfo = {
224226
{"libc", true}, {"libm-fp32", true}, {"libm-fp64", true},
225227
{"libimf-fp32", true}, {"libimf-fp64", true}, {"libimf-bf16", true},
226228
{"libm-bfloat16", true}, {"internal", true}};
229+
230+
// If -fno-sycl-device-lib is specified, its values will be used to exclude
231+
// linkage of libraries specified by DeviceLibLinkInfo. Linkage of "internal"
232+
// libraries cannot be affected via -fno-sycl-device-lib.
233+
bool ExcludeDeviceLibs = false;
234+
227235
if (Arg *A = Args.getLastArg(options::OPT_fsycl_device_lib_EQ,
228236
options::OPT_fno_sycl_device_lib_EQ)) {
229237
if (A->getValues().size() == 0)
230238
C.getDriver().Diag(diag::warn_drv_empty_joined_argument)
231239
<< A->getAsString(Args);
232240
else {
233241
if (A->getOption().matches(options::OPT_fno_sycl_device_lib_EQ))
234-
NoDeviceLibs = true;
242+
ExcludeDeviceLibs = true;
243+
244+
// When single libraries are ignored and a subset of library names
245+
// not containing the value "all" is specified by -fno-sycl-device-lib,
246+
// print an unused argument warning.
247+
bool PrintUnusedExcludeWarning = false;
235248

236249
for (StringRef Val : A->getValues()) {
237250
if (Val == "all") {
251+
PrintUnusedExcludeWarning = false;
252+
253+
// Make sure that internal libraries are still linked against
254+
// when -fno-sycl-device-lib contains "all" and single libraries
255+
// should be ignored.
256+
IgnoreSingleLibs = IgnoreSingleLibs && !ExcludeDeviceLibs;
257+
238258
for (const auto &K : DeviceLibLinkInfo.keys())
239-
DeviceLibLinkInfo[K] = true && (!NoDeviceLibs || K == "internal");
259+
DeviceLibLinkInfo[K] = (K == "internal") || !ExcludeDeviceLibs;
240260
break;
241261
}
242262
auto LinkInfoIter = DeviceLibLinkInfo.find(Val);
@@ -247,10 +267,20 @@ SYCL::getDeviceLibraries(const Compilation &C, const llvm::Triple &TargetTriple,
247267
C.getDriver().Diag(diag::err_drv_unsupported_option_argument)
248268
<< A->getSpelling() << Val;
249269
}
250-
DeviceLibLinkInfo[Val] = true && !NoDeviceLibs;
270+
DeviceLibLinkInfo[Val] = !ExcludeDeviceLibs;
271+
PrintUnusedExcludeWarning = IgnoreSingleLibs && ExcludeDeviceLibs;
251272
}
273+
if (PrintUnusedExcludeWarning)
274+
C.getDriver().Diag(diag::warn_drv_unused_argument) << A->getSpelling();
252275
}
253276
}
277+
278+
if (TargetTriple.isNVPTX() && IgnoreSingleLibs)
279+
LibraryList.push_back(Args.MakeArgString("devicelib--cuda.bc"));
280+
281+
if (IgnoreSingleLibs)
282+
return LibraryList;
283+
254284
using SYCLDeviceLibsList = SmallVector<DeviceLibOptInfo, 5>;
255285

256286
const SYCLDeviceLibsList SYCLDeviceWrapperLibs = {
@@ -304,10 +334,9 @@ SYCL::getDeviceLibraries(const Compilation &C, const llvm::Triple &TargetTriple,
304334
C.getDefaultToolChain().getTriple().isWindowsMSVCEnvironment();
305335
bool IsNewOffload = C.getDriver().getUseNewOffloadingDriver();
306336
StringRef LibSuffix = ".bc";
307-
if (TargetTriple.isNVPTX() ||
308-
(TargetTriple.isSPIR() &&
309-
TargetTriple.getSubArch() == llvm::Triple::SPIRSubArch_fpga))
310-
// For NVidia or FPGA, we are unbundling objects.
337+
if (TargetTriple.isSPIR() &&
338+
TargetTriple.getSubArch() == llvm::Triple::SPIRSubArch_fpga)
339+
// For FPGA, we are unbundling objects.
311340
LibSuffix = IsWindowsMSVCEnv ? ".obj" : ".o";
312341
if (IsNewOffload)
313342
// For new offload model, we use packaged .bc files.
@@ -323,7 +352,7 @@ SYCL::getDeviceLibraries(const Compilation &C, const llvm::Triple &TargetTriple,
323352
};
324353

325354
addLibraries(SYCLDeviceWrapperLibs);
326-
if (IsSpirvAOT || TargetTriple.isNVPTX())
355+
if (IsSpirvAOT)
327356
addLibraries(SYCLDeviceFallbackLibs);
328357

329358
bool NativeBfloatLibs;
@@ -551,7 +580,7 @@ const char *SYCL::Linker::constructLLVMLinkCommand(
551580
this->getToolChain().getTriple().getSubArch() ==
552581
llvm::Triple::SPIRSubArch_fpga;
553582
StringRef LibPostfix = ".bc";
554-
if (IsNVPTX || IsFPGA) {
583+
if (IsFPGA) {
555584
LibPostfix = ".o";
556585
if (HostTC->getTriple().isWindowsMSVCEnvironment() &&
557586
C.getDriver().IsCLMode())

clang/test/CodeGenSYCL/sycl-libdevice-cmath.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
// intrinsics. This allows the driver to link in the libdevice definitions for
66
// cosf etc. later in the driver flow.
77

8-
// RUN: %clang_cc1 %s -fsycl-is-device -triple nvptx64-nvidia-cuda -emit-llvm -o - | FileCheck %s
8+
// RUN: %clang_cc1 %s -fsycl-is-device -triple nvptx64-nvidia-cuda -emit-llvm -o - | FileCheck %s
99
// RUN: %clang_cc1 %s -fsycl-is-device -triple nvptx64-nvidia-cuda -ffast-math -emit-llvm -o - | FileCheck %s
1010

1111
#include "Inputs/sycl.hpp"
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// Tests specific to `-fsycl-targets=nvptx64-nvidia-nvptx`
2+
// Verify that the correct devicelib linking actions are spawned by the driver.
3+
// Check also if the correct warnings are generated.
4+
5+
// UNSUPPORTED: system-windows
6+
7+
// Check if internal libraries are still linked against when linkage of all
8+
// device libs is manually excluded.
9+
// RUN: %clangxx -ccc-print-phases -std=c++11 -fsycl -fno-sycl-device-lib=all \
10+
// RUN: -fsycl-targets=nvptx64-nvidia-cuda %s 2>&1 \
11+
// RUN: | FileCheck -check-prefix=CHK-NO-DEVLIB %s
12+
13+
// CHK-NO-DEVLIB-NOT: {{[0-9]+}}: input, "{{.*}}devicelib--cuda.bc", ir, (device-sycl, sm_50)
14+
// CHK-NO-DEVLIB: [[LIB1:[0-9]+]]: input, "{{.*}}libsycl-itt-user-wrappers.bc", ir, (device-sycl, sm_50)
15+
// CHK-NO-DEVLIB-NOT: {{[0-9]+}}: input, "{{.*}}devicelib--cuda.bc", ir, (device-sycl, sm_50)
16+
// CHK-NO-DEVLIB: [[LIB2:[0-9]+]]: input, "{{.*}}libsycl-itt-compiler-wrappers.bc", ir, (device-sycl, sm_50)
17+
// CHK-NO-DEVLIB-NOT: {{[0-9]+}}: input, "{{.*}}devicelib--cuda.bc", ir, (device-sycl, sm_50)
18+
// CHK-NO-DEVLIB: [[LIB3:[0-9]+]]: input, "{{.*}}libsycl-itt-stubs.bc", ir, (device-sycl, sm_50)
19+
// CHK-NO-DEVLIB-NOT: {{[0-9]+}}: input, "{{.*}}devicelib--cuda.bc", ir, (device-sycl, sm_50)
20+
// CHK-NO-DEVLIB: {{[0-9]+}}: linker, {{{.*}}[[LIB1]], [[LIB2]], [[LIB3]]{{.*}}}, ir, (device-sycl, sm_50)
21+
22+
// Check that the -fsycl-device-lib flag has no effect when "all" is specified.
23+
// RUN: %clangxx -ccc-print-phases -std=c++11 -fsycl -fsycl-device-lib=all \
24+
// RUN: -fsycl-targets=nvptx64-nvidia-cuda %s 2>&1 \
25+
// RUN: | FileCheck -check-prefix=CHK-ALL %s
26+
27+
// Check that the -fsycl-device-lib flag has no effect when subsets of libs
28+
// are specified.
29+
// RUN: %clangxx -ccc-print-phases -std=c++11 \
30+
// RUN: -fsycl -fsycl-device-lib=libc,libm-fp32,libm-fp64,libimf-fp32,libimf-fp64,libimf-bf16,libm-bfloat16 \
31+
// RUN: -fsycl-targets=nvptx64-nvidia-cuda %s 2>&1 \
32+
// RUN: | FileCheck -check-prefix=CHK-ALL %s
33+
34+
// Check that -fno-sycl-device-lib is ignored when it does not contain "all".
35+
// A warning should be printed that the flag got ignored.
36+
// RUN: %clangxx -ccc-print-phases -std=c++11 -fsycl \
37+
// RUN: -fno-sycl-device-lib=libc,libm-fp32,libm-fp64,libimf-fp32,libimf-fp64,libimf-bf16,libm-bfloat16 \
38+
// RUN: -fsycl-targets=nvptx64-nvidia-cuda %s 2>&1 \
39+
// RUN: | FileCheck -check-prefixes=CHK-UNUSED-WARN,CHK-ALL %s
40+
41+
// CHK-UNUSED-WARN: warning: argument unused during compilation: '-fno-sycl-device-lib='
42+
// CHK-ALL: [[DEVLIB:[0-9]+]]: input, "{{.*}}devicelib--cuda.bc", ir, (device-sycl, sm_50)
43+
// CHK-ALL: {{[0-9]+}}: linker, {{{.*}}[[DEVLIB]]{{.*}}}, ir, (device-sycl, sm_50)
44+

clang/test/Driver/sycl-offload-nvptx.cpp

Lines changed: 32 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -53,28 +53,22 @@
5353
// CHK-PHASES-NO-CC: 7: backend, {6}, assembler, (host-sycl)
5454
// CHK-PHASES-NO-CC: 8: assembler, {7}, object, (host-sycl)
5555
// CHK-PHASES-NO-CC: 9: linker, {4}, ir, (device-sycl, sm_50)
56-
// CHK-PHASES-NO-CC: 10: input, "{{.*}}libsycl-itt-user-wrappers.o{{.*}}", object
57-
// CHK-PHASES-NO-CC: 11: clang-offload-unbundler, {10}, object
58-
// CHK-PHASES-NO-CC: 12: offload, " (nvptx64-nvidia-cuda)" {11}, object
59-
// CHK-PHASES-NO-CC: 13: input, "{{.*}}libsycl-itt-compiler-wrappers.o{{.*}}", object
60-
// CHK-PHASES-NO-CC: 14: clang-offload-unbundler, {13}, object
61-
// CHK-PHASES-NO-CC: 15: offload, " (nvptx64-nvidia-cuda)" {14}, object
62-
// CHK-PHASES-NO-CC: 16: input, "{{.*}}libsycl-itt-stubs.o{{.*}}", object
63-
// CHK-PHASES-NO-CC: 17: clang-offload-unbundler, {16}, object
64-
// CHK-PHASES-NO-CC: 18: offload, " (nvptx64-nvidia-cuda)" {17}, object
65-
// CHK-PHASES-NO-CC: 19: input, "{{.*}}nvidiacl{{.*}}", ir, (device-sycl, sm_50)
66-
// CHK-PHASES-NO-CC: 20: input, "{{.*}}libdevice{{.*}}", ir, (device-sycl, sm_50)
67-
// CHK-PHASES-NO-CC: 21: linker, {9, 12, 15, 18, 19, 20}, ir, (device-sycl, sm_50)
68-
// CHK-PHASES-NO-CC: 22: sycl-post-link, {21}, ir, (device-sycl, sm_50)
69-
// CHK-PHASES-NO-CC: 23: file-table-tform, {22}, ir, (device-sycl, sm_50)
70-
// CHK-PHASES-NO-CC: 24: backend, {23}, assembler, (device-sycl, sm_50)
71-
// CHK-PHASES-NO-CC: 25: assembler, {24}, object, (device-sycl, sm_50)
72-
// CHK-PHASES-NO-CC: 26: linker, {24, 25}, cuda-fatbin, (device-sycl, sm_50)
73-
// CHK-PHASES-NO-CC: 27: foreach, {23, 26}, cuda-fatbin, (device-sycl, sm_50)
74-
// CHK-PHASES-NO-CC: 28: file-table-tform, {22, 27}, tempfiletable, (device-sycl, sm_50)
75-
// CHK-PHASES-NO-CC: 29: clang-offload-wrapper, {28}, object, (device-sycl, sm_50)
76-
// CHK-PHASES-NO-CC: 30: offload, "device-sycl (nvptx64-nvidia-cuda:sm_50)" {29}, object
77-
// CHK-PHASES-NO-CC: 31: linker, {8, 30}, image, (host-sycl)
56+
// CHK-PHASES-NO-CC: 10: input, "{{.*}}libsycl-itt-user-wrappers.bc", ir, (device-sycl, sm_50)
57+
// CHK-PHASES-NO-CC: 11: input, "{{.*}}libsycl-itt-compiler-wrappers.bc", ir, (device-sycl, sm_50)
58+
// CHK-PHASES-NO-CC: 12: input, "{{.*}}libsycl-itt-stubs.bc", ir, (device-sycl, sm_50)
59+
// CHK-PHASES-NO-CC: 13: input, "{{.*}}nvidiacl{{.*}}", ir, (device-sycl, sm_50)
60+
// CHK-PHASES-NO-CC: 14: input, "{{.*}}libdevice{{.*}}", ir, (device-sycl, sm_50)
61+
// CHK-PHASES-NO-CC: 15: linker, {9, 10, 11, 12, 13, 14}, ir, (device-sycl, sm_50)
62+
// CHK-PHASES-NO-CC: 16: sycl-post-link, {15}, ir, (device-sycl, sm_50)
63+
// CHK-PHASES-NO-CC: 17: file-table-tform, {16}, ir, (device-sycl, sm_50)
64+
// CHK-PHASES-NO-CC: 18: backend, {17}, assembler, (device-sycl, sm_50)
65+
// CHK-PHASES-NO-CC: 19: assembler, {18}, object, (device-sycl, sm_50)
66+
// CHK-PHASES-NO-CC: 20: linker, {18, 19}, cuda-fatbin, (device-sycl, sm_50)
67+
// CHK-PHASES-NO-CC: 21: foreach, {17, 20}, cuda-fatbin, (device-sycl, sm_50)
68+
// CHK-PHASES-NO-CC: 22: file-table-tform, {16, 21}, tempfiletable, (device-sycl, sm_50)
69+
// CHK-PHASES-NO-CC: 23: clang-offload-wrapper, {22}, object, (device-sycl, sm_50)
70+
// CHK-PHASES-NO-CC: 24: offload, "device-sycl (nvptx64-nvidia-cuda:sm_50)" {23}, object
71+
// CHK-PHASES-NO-CC: 25: linker, {8, 24}, image, (host-sycl)
7872
//
7973
/// Check phases specifying a compute capability.
8074
// RUN: %clangxx -ccc-print-phases --sysroot=%S/Inputs/SYCL -std=c++11 \
@@ -97,28 +91,22 @@
9791
// CHK-PHASES: 7: backend, {6}, assembler, (host-sycl)
9892
// CHK-PHASES: 8: assembler, {7}, object, (host-sycl)
9993
// CHK-PHASES: 9: linker, {4}, ir, (device-sycl, sm_35)
100-
// CHK-PHASES: 10: input, "{{.*}}libsycl-itt-user-wrappers.o", object
101-
// CHK-PHASES: 11: clang-offload-unbundler, {10}, object
102-
// CHK-PHASES: 12: offload, " (nvptx64-nvidia-cuda)" {11}, object
103-
// CHK-PHASES: 13: input, "{{.*}}libsycl-itt-compiler-wrappers.o", object
104-
// CHK-PHASES: 14: clang-offload-unbundler, {13}, object
105-
// CHK-PHASES: 15: offload, " (nvptx64-nvidia-cuda)" {14}, object
106-
// CHK-PHASES: 16: input, "{{.*}}libsycl-itt-stubs.o", object
107-
// CHK-PHASES: 17: clang-offload-unbundler, {16}, object
108-
// CHK-PHASES: 18: offload, " (nvptx64-nvidia-cuda)" {17}, object
109-
// CHK-PHASES: 19: input, "{{.*}}nvidiacl{{.*}}", ir, (device-sycl, sm_35)
110-
// CHK-PHASES: 20: input, "{{.*}}libdevice{{.*}}", ir, (device-sycl, sm_35)
111-
// CHK-PHASES: 21: linker, {9, 12, 15, 18, 19, 20}, ir, (device-sycl, sm_35)
112-
// CHK-PHASES: 22: sycl-post-link, {21}, ir, (device-sycl, sm_35)
113-
// CHK-PHASES: 23: file-table-tform, {22}, ir, (device-sycl, sm_35)
114-
// CHK-PHASES: 24: backend, {23}, assembler, (device-sycl, sm_35)
115-
// CHK-PHASES: 25: assembler, {24}, object, (device-sycl, sm_35)
116-
// CHK-PHASES: 26: linker, {24, 25}, cuda-fatbin, (device-sycl, sm_35)
117-
// CHK-PHASES: 27: foreach, {23, 26}, cuda-fatbin, (device-sycl, sm_35)
118-
// CHK-PHASES: 28: file-table-tform, {22, 27}, tempfiletable, (device-sycl, sm_35)
119-
// CHK-PHASES: 29: clang-offload-wrapper, {28}, object, (device-sycl, sm_35)
120-
// CHK-PHASES: 30: offload, "device-sycl (nvptx64-nvidia-cuda:sm_35)" {29}, object
121-
// CHK-PHASES: 31: linker, {8, 30}, image, (host-sycl)
94+
// CHK-PHASES: 10: input, "{{.*}}libsycl-itt-user-wrappers.bc", ir, (device-sycl, sm_35)
95+
// CHK-PHASES: 11: input, "{{.*}}libsycl-itt-compiler-wrappers.bc", ir, (device-sycl, sm_35)
96+
// CHK-PHASES: 12: input, "{{.*}}libsycl-itt-stubs.bc", ir, (device-sycl, sm_35)
97+
// CHK-PHASES: 13: input, "{{.*}}nvidiacl{{.*}}", ir, (device-sycl, sm_35)
98+
// CHK-PHASES: 14: input, "{{.*}}libdevice{{.*}}", ir, (device-sycl, sm_35)
99+
// CHK-PHASES: 15: linker, {9, 10, 11, 12, 13, 14}, ir, (device-sycl, sm_35)
100+
// CHK-PHASES: 16: sycl-post-link, {15}, ir, (device-sycl, sm_35)
101+
// CHK-PHASES: 17: file-table-tform, {16}, ir, (device-sycl, sm_35)
102+
// CHK-PHASES: 18: backend, {17}, assembler, (device-sycl, sm_35)
103+
// CHK-PHASES: 19: assembler, {18}, object, (device-sycl, sm_35)
104+
// CHK-PHASES: 20: linker, {18, 19}, cuda-fatbin, (device-sycl, sm_35)
105+
// CHK-PHASES: 21: foreach, {17, 20}, cuda-fatbin, (device-sycl, sm_35)
106+
// CHK-PHASES: 22: file-table-tform, {16, 21}, tempfiletable, (device-sycl, sm_35)
107+
// CHK-PHASES: 23: clang-offload-wrapper, {22}, object, (device-sycl, sm_35)
108+
// CHK-PHASES: 24: offload, "device-sycl (nvptx64-nvidia-cuda:sm_35)" {23}, object
109+
// CHK-PHASES: 25: linker, {8, 24}, image, (host-sycl)
122110

123111
/// Check calling preprocessor only
124112
// RUN: %clangxx -E -fsycl -fsycl-targets=nvptx64-nvidia-cuda -ccc-print-phases %s 2>&1 \

libclc/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,7 @@ if( ENABLE_RUNTIME_SUBNORMAL )
234234
foreach( file subnormal_use_default subnormal_disable )
235235
link_bc(
236236
TARGET ${file}
237+
RSP_DIR ${LIBCLC_ARCH_OBJFILE_DIR}
237238
INPUTS ${CMAKE_CURRENT_SOURCE_DIR}/generic/lib/${file}.ll
238239
)
239240
install( FILES $<TARGET_PROPERTY:${file},TARGET_FILE> ARCHIVE
@@ -408,7 +409,6 @@ foreach( t ${LIBCLC_TARGETS_TO_BUILD} )
408409
# Enable SPIR-V builtin function declarations, so they don't
409410
# have to be explicity declared in the soruce.
410411
list( APPEND flags -Xclang -fdeclare-spirv-builtins)
411-
412412
set( LIBCLC_ARCH_OBJFILE_DIR "${LIBCLC_OBJFILE_DIR}/${arch_suffix}" )
413413
file( MAKE_DIRECTORY ${LIBCLC_ARCH_OBJFILE_DIR} )
414414

0 commit comments

Comments
 (0)