diff --git a/llvm/lib/Linker/IRMover.cpp b/llvm/lib/Linker/IRMover.cpp --- a/llvm/lib/Linker/IRMover.cpp +++ b/llvm/lib/Linker/IRMover.cpp @@ -20,6 +20,7 @@ #include "llvm/IR/TypeFinder.h" #include "llvm/Object/ModuleSymbolTable.h" #include "llvm/Support/Error.h" +#include "llvm/Support/Path.h" #include "llvm/Transforms/Utils/Cloning.h" #include using namespace llvm; @@ -1443,7 +1444,39 @@ if (DstM.getDataLayout().isDefault()) DstM.setDataLayout(SrcM->getDataLayout()); - if (SrcM->getDataLayout() != DstM.getDataLayout()) { + // Copy the target triple from the source to dest if the dest's is empty. + if (DstM.getTargetTriple().empty() && !SrcM->getTargetTriple().empty()) + DstM.setTargetTriple(SrcM->getTargetTriple()); + + Triple SrcTriple(SrcM->getTargetTriple()), DstTriple(DstM.getTargetTriple()); + + // During CUDA compilation we have to link with the bitcode supplied with + // CUDA. libdevice bitcode either has no data layout set (pre-CUDA-11), or has + // the layout that is different from the one used by LLVM/clang (it does not + // include i128). Issuing a warning is not very helpful as there's not much + // the user can do about it. + bool EnableDLWarning = true; + bool EnableTripleWarning = true; + if (SrcTriple.isNVPTX() && DstTriple.isNVPTX()) { + std::string ModuleId = SrcM->getModuleIdentifier(); + StringRef FileName = llvm::sys::path::filename(ModuleId); + bool SrcIsLibDevice = + FileName.startswith("libdevice") && FileName.endswith(".10.bc"); + bool SrcHasLibDeviceDL = + (SrcM->getDataLayoutStr().empty() || + SrcM->getDataLayoutStr() == "e-i64:64-v16:16-v32:32-n16:32:64"); + // libdevice bitcode uses nvptx64-nvidia-gpulibs or just + // 'nvptx-unknown-unknown' triple (before CUDA-10.x) and is compatible with + // all NVPTX variants. + bool SrcHasLibDeviceTriple = (SrcTriple.getVendor() == Triple::NVIDIA && + SrcTriple.getOSName() == "gpulibs") || + (SrcTriple.getVendorName() == "unknown" && + SrcTriple.getOSName() == "unknown"); + EnableTripleWarning = !(SrcIsLibDevice && SrcHasLibDeviceTriple); + EnableDLWarning = !(SrcIsLibDevice && SrcHasLibDeviceDL); + } + + if (EnableDLWarning && (SrcM->getDataLayout() != DstM.getDataLayout())) { emitWarning("Linking two modules of different data layouts: '" + SrcM->getModuleIdentifier() + "' is '" + SrcM->getDataLayoutStr() + "' whereas '" + @@ -1451,13 +1484,7 @@ DstM.getDataLayoutStr() + "'\n"); } - // Copy the target triple from the source to dest if the dest's is empty. - if (DstM.getTargetTriple().empty() && !SrcM->getTargetTriple().empty()) - DstM.setTargetTriple(SrcM->getTargetTriple()); - - Triple SrcTriple(SrcM->getTargetTriple()), DstTriple(DstM.getTargetTriple()); - - if (!SrcM->getTargetTriple().empty()&& + if (EnableTripleWarning && !SrcM->getTargetTriple().empty() && !SrcTriple.isCompatibleWith(DstTriple)) emitWarning("Linking two modules of different target triples: '" + SrcM->getModuleIdentifier() + "' is '" + diff --git a/llvm/test/Linker/Inputs/libdevice-cuda-10.ll b/llvm/test/Linker/Inputs/libdevice-cuda-10.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Linker/Inputs/libdevice-cuda-10.ll @@ -0,0 +1,2 @@ +target triple = "nvptx64-nvidia-gpulibs" + diff --git a/llvm/test/Linker/Inputs/libdevice-cuda-11.ll b/llvm/test/Linker/Inputs/libdevice-cuda-11.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Linker/Inputs/libdevice-cuda-11.ll @@ -0,0 +1,3 @@ +target datalayout = "e-i64:64-v16:16-v32:32-n16:32:64" +target triple = "nvptx64-nvidia-gpulibs" + diff --git a/llvm/test/Linker/Inputs/libdevice-cuda-9.ll b/llvm/test/Linker/Inputs/libdevice-cuda-9.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Linker/Inputs/libdevice-cuda-9.ll @@ -0,0 +1,2 @@ +target triple = "nvptx-unknown-unknown" + diff --git a/llvm/test/Linker/Inputs/not-a-libdevice.ll b/llvm/test/Linker/Inputs/not-a-libdevice.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Linker/Inputs/not-a-libdevice.ll @@ -0,0 +1,2 @@ +target triple = "nvptx64-nvidia-nosuchthing" +target datalayout = "e-i64:64-i128:128-v32:32-n16:32:64" diff --git a/llvm/test/Linker/cuda-libdevice.ll b/llvm/test/Linker/cuda-libdevice.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Linker/cuda-libdevice.ll @@ -0,0 +1,34 @@ +; Prepare bitcode files. +; RUN: rm -rf %t && mkdir -p %t +; RUN: llvm-as %s -o %t/main.bc +; RUN: llvm-as %p/Inputs/libdevice-cuda-9.ll -o %t/libdevice.compute_35.10.bc +; RUN: llvm-as %p/Inputs/libdevice-cuda-10.ll -o %t/libdevice.10.bc +; RUN: llvm-as %p/Inputs/libdevice-cuda-11.ll -o %t/libdevice.11.10.bc +; RUN: llvm-as %p/Inputs/libdevice-cuda-9.ll -o %t/correct-libdevice-wrong-filename.bc +; RUN: llvm-as %p/Inputs/not-a-libdevice.ll -o %t/libdevice-with-wrong-info.bc + +; No warnings expected when we link with libdevice variants +; RUN: llvm-link %t/main.bc %t/libdevice.compute_35.10.bc -S 2>&1 \ +; RUN: | FileCheck --check-prefixes COMMON,NOWARN %s +; RUN: llvm-link %t/main.bc %t/libdevice.10.bc -S 2>&1 \ +; RUN: | FileCheck --check-prefixes COMMON,NOWARN %s +; RUN: llvm-link %t/main.bc %t/libdevice.11.10.bc -S 2>&1 \ +; RUN: | FileCheck --check-prefixes COMMON,NOWARN %s + +; But make sure we still issue warnings if we see unexpected filename, or +; unexpected triple or datalayout within a libdevice filename. +; RUN: llvm-link %t/main.bc %t/correct-libdevice-wrong-filename.bc -S 2>&1 \ +; RUN: | FileCheck --check-prefixes COMMON,WARN-TRIPLE %s +; RUN: llvm-link %t/main.bc %t/libdevice-with-wrong-info.bc -S 2>&1 \ +; RUN: | FileCheck --check-prefixes COMMON,WARN-TRIPLE,WARN-DL %s + + +target triple = "nvptx64-nvidia-cuda" +target datalayout = "e-i64:64-i128:128-v16:16-v32:32-n16:32:64" + +; WARN-TRIPLE-DAG: warning: Linking two modules of different target triples: +; WARN-DL-DAG: warning: Linking two modules of different data layouts: + +; NOWARN-NOT: warning: +; COMMON-DAG: target triple = "nvptx64-nvidia-cuda" +; NOWARN-NOT: warning: