diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 8aa2c595e2dea..832d05350c6ec 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -9306,8 +9306,10 @@ void LinkerWrapper::ConstructJob(Compilation &C, const JobAction &JA, LinkerArgs.emplace_back("-lompdevice"); // For SPIR-V some functions will be defined by the runtime so allow - // unresolved symbols. - if (TC->getTriple().isSPIRV()) + // unresolved symbols in `spirv-link`. `spirv-link` isn't called in LTO + // mode so restrict this flag to normal compilation. + if (TC->getTriple().isSPIRV() && !C.getDriver().isUsingLTO() && + !C.getDriver().isUsingOffloadLTO()) LinkerArgs.emplace_back("--allow-partial-linkage"); // Forward all of these to the appropriate toolchain. diff --git a/clang/lib/Driver/ToolChains/SPIRV.cpp b/clang/lib/Driver/ToolChains/SPIRV.cpp index c1ccb1e7d8508..a59bd05cac0cf 100644 --- a/clang/lib/Driver/ToolChains/SPIRV.cpp +++ b/clang/lib/Driver/ToolChains/SPIRV.cpp @@ -147,17 +147,31 @@ void SPIRV::Linker::ConstructJob(Compilation &C, const JobAction &JA, const ToolChain &ToolChain = getToolChain(); std::string Linker = ToolChain.GetProgramPath(getShortName()); ArgStringList CmdArgs; - AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA); + AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); - // Use of --sycl-link will call the clang-sycl-linker instead of - // the default linker (spirv-link). - if (Args.hasArg(options::OPT_sycl_link)) + // TODO: Consider moving SPIR-V linking to a separate tool. + if (C.getDriver().isUsingLTO()) { + // Implement limited LTO support through llvm-lto. + if (Args.hasArg(options::OPT_sycl_link)) { + // For unsupported cases, throw the same error as when LTO isn't supported + // at all. + C.getDriver().Diag(clang::diag::err_drv_no_linker_llvm_support) + << ToolChain.getTriple().getTriple(); + return; + } + Linker = ToolChain.GetProgramPath("llvm-lto"); + // Disable internalization, otherwise GlobalDCE will optimize everything + // out. + CmdArgs.push_back("-enable-lto-internalization=false"); + } else if (Args.hasArg(options::OPT_sycl_link)) { + // Use of --sycl-link will call the clang-sycl-linker instead of + // the default linker (spirv-link). Linker = ToolChain.GetProgramPath("clang-sycl-linker"); - else if (!llvm::sys::fs::can_execute(Linker) && - !C.getArgs().hasArg(clang::options::OPT__HASH_HASH_HASH)) { + } else if (!llvm::sys::fs::can_execute(Linker) && + !C.getArgs().hasArg(clang::options::OPT__HASH_HASH_HASH)) { C.getDriver().Diag(clang::diag::err_drv_no_spv_tools) << getShortName(); return; } @@ -171,7 +185,7 @@ SPIRVToolChain::SPIRVToolChain(const Driver &D, const llvm::Triple &Triple, : ToolChain(D, Triple, Args) { // TODO: Revisit need/use of --sycl-link option once SYCL toolchain is // available and SYCL linking support is moved there. - NativeLLVMSupport = Args.hasArg(options::OPT_sycl_link); + NativeLLVMSupport = Args.hasArg(options::OPT_sycl_link) || D.isUsingLTO(); // Lookup binaries into the driver directory. getProgramPaths().push_back(getDriver().Dir); diff --git a/clang/test/Driver/spirv-lto.c b/clang/test/Driver/spirv-lto.c new file mode 100644 index 0000000000000..64f5f30a8a1eb --- /dev/null +++ b/clang/test/Driver/spirv-lto.c @@ -0,0 +1,35 @@ +// Check SPIR-V support for LTO +// RUN: mkdir -p %t +// RUN: touch %t/a.c +// RUN: touch %t/b.c +// RUN: touch %t/a.o +// RUN: touch %t/b.o + +// RUN: %clang -### --target=spirv64 -flto %t/a.c %t/b.c -Xlinker --disable-verify 2>&1 | FileCheck --check-prefix=CHECK-POSITIVE-TOOL %s +// RUN: %clang -ccc-print-phases --target=spirv64 -flto %t/a.c %t/b.c 2>&1 | FileCheck --check-prefix=CHECK-POSITIVE-PHASES %s +// RUN: not %clang -### --target=spirv64 -flto %t/a.c %t/b.c --sycl-link 2>&1 | FileCheck --check-prefix=CHECK-ERROR %s + +// RUN: %clang -### --target=spirv64 -flto %t/a.o %t/b.o -Xlinker --disable-verify 2>&1 | FileCheck --check-prefix=CHECK-POSITIVE-TOOL-OBJ %s +// RUN: %clang -ccc-print-phases --target=spirv64 -flto %t/a.o %t/b.o 2>&1 | FileCheck --check-prefix=CHECK-POSITIVE-PHASES-OBJ %s +// RUN: not %clang -### --target=spirv64 -flto %t/a.o %t/b.o --sycl-link 2>&1 | FileCheck --check-prefix=CHECK-ERROR %s + +// CHECK-POSITIVE-TOOL: llvm-lto{{.*}} "{{.*}}a-{{.*}}.o" "{{.*}}b-{{.*}}.o" "--disable-verify" "-o" "a.out" "-enable-lto-internalization=false" + +// CHECK-POSITIVE-PHASES: 0: input, "{{.*}}a.c", c +// CHECK-POSITIVE-PHASES: 1: preprocessor, {0}, cpp-output +// CHECK-POSITIVE-PHASES: 2: compiler, {1}, ir +// CHECK-POSITIVE-PHASES: 3: backend, {2}, lto-bc +// CHECK-POSITIVE-PHASES: 4: input, "{{.*}}b.c", c +// CHECK-POSITIVE-PHASES: 5: preprocessor, {4}, cpp-output +// CHECK-POSITIVE-PHASES: 6: compiler, {5}, ir +// CHECK-POSITIVE-PHASES: 7: backend, {6}, lto-bc +// CHECK-POSITIVE-PHASES: 8: linker, {3, 7}, image + +// CHECK-POSITIVE-TOOL-OBJ: llvm-lto{{.*}} "{{.*}}a.o" "{{.*}}b.o" "--disable-verify" "-o" "a.out" "-enable-lto-internalization=false" + +// CHECK-POSITIVE-PHASES-OBJ: 0: input, "{{.*}}a.o", object +// CHECK-POSITIVE-PHASES-OBJ: 1: input, "{{.*}}b.o", object +// CHECK-POSITIVE-PHASES-OBJ: 2: linker, {0, 1}, image + +// CHECK-ERROR: 'spirv64': unable to pass LLVM bit-code files to linker +