diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -7392,6 +7392,7 @@ } CmdArgs.push_back(TCArgs.MakeArgString(UB)); CmdArgs.push_back("-unbundle"); + CmdArgs.push_back("-allow-missing-bundles"); // All the inputs are encoded as commands. C.addCommand(std::make_unique( diff --git a/clang/test/Driver/clang-offload-bundler.c b/clang/test/Driver/clang-offload-bundler.c --- a/clang/test/Driver/clang-offload-bundler.c +++ b/clang/test/Driver/clang-offload-bundler.c @@ -33,6 +33,7 @@ // CK-HELP: {{.*}}one. The resulting file can also be unbundled into different files by // CK-HELP: {{.*}}this tool if -unbundle is provided. // CK-HELP: {{.*}}USAGE: clang-offload-bundler [options] +// CK-HELP: {{.*}}-allow-missing-bundles {{.*}}- Create empty files if bundles are missing when unbundling // CK-HELP: {{.*}}-inputs= - [,...] // CK-HELP: {{.*}}-outputs= - [,...] // CK-HELP: {{.*}}-targets= - [-,...] @@ -88,7 +89,7 @@ // RUN: not clang-offload-bundler -type=i -targets=openmp-powerpc64le-linux,openmp-powerpc64le-ibm-linux-gnu,openmp-x86_64-pc-linux-gnu -inputs=%t.i,%t.tgt1,%t.tgt2 -outputs=%t.bundle.i 2>&1 | FileCheck %s --check-prefix CK-ERR9A // RUN: not clang-offload-bundler -type=i -targets=host-%itanium_abi_triple,host-%itanium_abi_triple,openmp-x86_64-pc-linux-gnu -inputs=%t.i,%t.tgt1,%t.tgt2 -outputs=%t.bundle.i 2>&1 | FileCheck %s --check-prefix CK-ERR9B // CK-ERR9A: error: expecting exactly one host target but got 0 -// CK-ERR9B: error: expecting exactly one host target but got 2 +// CK-ERR9B: error: Duplicate targets are not allowed // // Check text bundle. This is a readable format, so we check for the format we expect to find. @@ -181,17 +182,17 @@ // RUN: diff %t.tgt2 %t.res.tgt2 // Check if we can unbundle a file with no magic strings. -// RUN: clang-offload-bundler -type=s -targets=host-%itanium_abi_triple,openmp-powerpc64le-ibm-linux-gnu,openmp-x86_64-pc-linux-gnu -outputs=%t.res.s,%t.res.tgt1,%t.res.tgt2 -inputs=%t.s -unbundle +// RUN: clang-offload-bundler -type=s -targets=host-%itanium_abi_triple,openmp-powerpc64le-ibm-linux-gnu,openmp-x86_64-pc-linux-gnu -outputs=%t.res.s,%t.res.tgt1,%t.res.tgt2 -inputs=%t.s -unbundle -allow-missing-bundles // RUN: diff %t.s %t.res.s // RUN: diff %t.empty %t.res.tgt1 // RUN: diff %t.empty %t.res.tgt2 -// RUN: clang-offload-bundler -type=s -targets=openmp-powerpc64le-ibm-linux-gnu,host-%itanium_abi_triple,openmp-x86_64-pc-linux-gnu -outputs=%t.res.tgt1,%t.res.s,%t.res.tgt2 -inputs=%t.s -unbundle +// RUN: clang-offload-bundler -type=s -targets=openmp-powerpc64le-ibm-linux-gnu,host-%itanium_abi_triple,openmp-x86_64-pc-linux-gnu -outputs=%t.res.tgt1,%t.res.s,%t.res.tgt2 -inputs=%t.s -unbundle -allow-missing-bundles // RUN: diff %t.s %t.res.s // RUN: diff %t.empty %t.res.tgt1 // RUN: diff %t.empty %t.res.tgt2 // Check that bindler prints an error if given host bundle does not exist in the fat binary. -// RUN: not clang-offload-bundler -type=s -targets=host-x86_64-xxx-linux-gnu,openmp-powerpc64le-ibm-linux-gnu -outputs=%t.res.s,%t.res.tgt1 -inputs=%t.bundle3.s -unbundle 2>&1 | FileCheck %s --check-prefix CK-NO-HOST-BUNDLE +// RUN: not clang-offload-bundler -type=s -targets=host-x86_64-xxx-linux-gnu,openmp-powerpc64le-ibm-linux-gnu -outputs=%t.res.s,%t.res.tgt1 -inputs=%t.bundle3.s -unbundle -allow-missing-bundles 2>&1 | FileCheck %s --check-prefix CK-NO-HOST-BUNDLE // CK-NO-HOST-BUNDLE: error: Can't find bundle for the host target // @@ -229,11 +230,11 @@ // RUN: diff %t.tgt1 %t.res.tgt1 // Check if we can unbundle a file with no magic strings. -// RUN: clang-offload-bundler -type=bc -targets=host-%itanium_abi_triple,openmp-powerpc64le-ibm-linux-gnu,openmp-x86_64-pc-linux-gnu -outputs=%t.res.bc,%t.res.tgt1,%t.res.tgt2 -inputs=%t.bc -unbundle +// RUN: clang-offload-bundler -type=bc -targets=host-%itanium_abi_triple,openmp-powerpc64le-ibm-linux-gnu,openmp-x86_64-pc-linux-gnu -outputs=%t.res.bc,%t.res.tgt1,%t.res.tgt2 -inputs=%t.bc -unbundle -allow-missing-bundles // RUN: diff %t.bc %t.res.bc // RUN: diff %t.empty %t.res.tgt1 // RUN: diff %t.empty %t.res.tgt2 -// RUN: clang-offload-bundler -type=bc -targets=openmp-powerpc64le-ibm-linux-gnu,host-%itanium_abi_triple,openmp-x86_64-pc-linux-gnu -outputs=%t.res.tgt1,%t.res.bc,%t.res.tgt2 -inputs=%t.bc -unbundle +// RUN: clang-offload-bundler -type=bc -targets=openmp-powerpc64le-ibm-linux-gnu,host-%itanium_abi_triple,openmp-x86_64-pc-linux-gnu -outputs=%t.res.tgt1,%t.res.bc,%t.res.tgt2 -inputs=%t.bc -unbundle -allow-missing-bundles // RUN: diff %t.bc %t.res.bc // RUN: diff %t.empty %t.res.tgt1 // RUN: diff %t.empty %t.res.tgt2 @@ -269,11 +270,11 @@ // RUN: diff %t.tgt1 %t.res.tgt1 // Check if we can unbundle a file with no magic strings. -// RUN: clang-offload-bundler -type=o -targets=host-%itanium_abi_triple,openmp-powerpc64le-ibm-linux-gnu,openmp-x86_64-pc-linux-gnu -outputs=%t.res.o,%t.res.tgt1,%t.res.tgt2 -inputs=%t.o -unbundle +// RUN: clang-offload-bundler -type=o -targets=host-%itanium_abi_triple,openmp-powerpc64le-ibm-linux-gnu,openmp-x86_64-pc-linux-gnu -outputs=%t.res.o,%t.res.tgt1,%t.res.tgt2 -inputs=%t.o -unbundle -allow-missing-bundles // RUN: diff %t.o %t.res.o // RUN: diff %t.empty %t.res.tgt1 // RUN: diff %t.empty %t.res.tgt2 -// RUN: clang-offload-bundler -type=o -targets=openmp-powerpc64le-ibm-linux-gnu,host-%itanium_abi_triple,openmp-x86_64-pc-linux-gnu -outputs=%t.res.tgt1,%t.res.o,%t.res.tgt2 -inputs=%t.o -unbundle +// RUN: clang-offload-bundler -type=o -targets=openmp-powerpc64le-ibm-linux-gnu,host-%itanium_abi_triple,openmp-x86_64-pc-linux-gnu -outputs=%t.res.tgt1,%t.res.o,%t.res.tgt2 -inputs=%t.o -unbundle -allow-missing-bundles // RUN: diff %t.o %t.res.o // RUN: diff %t.empty %t.res.tgt1 // RUN: diff %t.empty %t.res.tgt2 @@ -288,6 +289,36 @@ // RUN: diff %t.tgt1 %t.res.tgt1 // RUN: diff %t.tgt2 %t.res.tgt2 +// +// Check error due to missing bundles +// +// RUN: clang-offload-bundler -type=bc -targets=host-%itanium_abi_triple,hip-amdgcn-amd-amdhsa-gfx900 -inputs=%t.bc,%t.tgt1 -outputs=%t.hip.bundle.bc +// RUN: not clang-offload-bundler -type=bc -inputs=%t.hip.bundle.bc -outputs=%t.tmp.bc -unbundle \ +// RUN: -targets=hip-amdgcn-amd-amdhsa-gfx906 \ +// RUN: 2>&1 | FileCheck -check-prefix=MISS1 %s +// RUN: not clang-offload-bundler -type=bc -inputs=%t.hip.bundle.bc -outputs=%t.tmp.bc,%t.tmp2.bc -unbundle \ +// RUN: -targets=hip-amdgcn-amd-amdhsa-gfx906,hip-amdgcn-amd-amdhsa-gfx900 \ +// RUN: 2>&1 | FileCheck -check-prefix=MISS1 %s +// MISS1: error: Can't find bundles for hip-amdgcn-amd-amdhsa-gfx906 +// RUN: not clang-offload-bundler -type=bc -inputs=%t.hip.bundle.bc -outputs=%t.tmp.bc,%t.tmp2.bc -unbundle \ +// RUN: -targets=hip-amdgcn-amd-amdhsa-gfx906,hip-amdgcn-amd-amdhsa-gfx803 \ +// RUN: 2>&1 | FileCheck -check-prefix=MISS2 %s +// MISS2: error: Can't find bundles for hip-amdgcn-amd-amdhsa-gfx803 and hip-amdgcn-amd-amdhsa-gfx906 +// RUN: not clang-offload-bundler -type=bc -inputs=%t.hip.bundle.bc -outputs=%t.tmp.bc,%t.tmp2.bc,%t.tmp3.bc -unbundle \ +// RUN: -targets=hip-amdgcn-amd-amdhsa-gfx906,hip-amdgcn-amd-amdhsa-gfx803,hip-amdgcn-amd-amdhsa-gfx1010 \ +// RUN: 2>&1 | FileCheck -check-prefix=MISS3 %s +// MISS3: error: Can't find bundles for hip-amdgcn-amd-amdhsa-gfx1010, hip-amdgcn-amd-amdhsa-gfx803, and hip-amdgcn-amd-amdhsa-gfx906 + +// +// Check error due to duplicate targets +// +// RUN: not clang-offload-bundler -type=bc -targets=host-%itanium_abi_triple,hip-amdgcn-amd-amdhsa-gfx900,hip-amdgcn-amd-amdhsa-gfx900 \ +// RUN: -inputs=%t.bc,%t.tgt1,%t.tgt1 -outputs=%t.hip.bundle.bc 2>&1 | FileCheck -check-prefix=DUP %s +// RUN: not clang-offload-bundler -type=bc -inputs=%t.hip.bundle.bc -outputs=%t.tmp.bc,%t.tmp2.bc -unbundle \ +// RUN: -targets=hip-amdgcn-amd-amdhsa-gfx906,hip-amdgcn-amd-amdhsa-gfx906 \ +// RUN: 2>&1 | FileCheck -check-prefix=DUP %s +// DUP: error: Duplicate targets are not allowed + // Some code so that we can create a binary out of this file. int A = 0; void test_func(void) { diff --git a/clang/test/Driver/hip-toolchain-rdc-separate.hip b/clang/test/Driver/hip-toolchain-rdc-separate.hip --- a/clang/test/Driver/hip-toolchain-rdc-separate.hip +++ b/clang/test/Driver/hip-toolchain-rdc-separate.hip @@ -87,22 +87,22 @@ // LINK: [[BUNDLER:".*clang-offload-bundler"]] "-type=o" // LINK-SAME: "-targets=host-x86_64-unknown-linux-gnu,hip-amdgcn-amd-amdhsa-gfx803,hip-amdgcn-amd-amdhsa-gfx900" // LINK-SAME: "-inputs=[[A_O:.*a.o]]" "-outputs=[[A_OBJ_HOST:.*o]],{{.*o}},{{.*o}}" -// LINK: "-unbundle" +// LINK: "-unbundle" "-allow-missing-bundles" // LINK: [[BUNDLER:".*clang-offload-bundler"]] "-type=o" // LINK-SAME: "-targets=host-x86_64-unknown-linux-gnu,hip-amdgcn-amd-amdhsa-gfx803,hip-amdgcn-amd-amdhsa-gfx900" // LINK-SAME: "-inputs=[[B_O:.*b.o]]" "-outputs=[[B_OBJ_HOST:.*o]],{{.*o}},{{.*o}}" -// LINK: "-unbundle" +// LINK: "-unbundle" "-allow-missing-bundles" // LINK: [[BUNDLER:".*clang-offload-bundler"]] "-type=o" // LINK-SAME: "-targets=host-x86_64-unknown-linux-gnu,hip-amdgcn-amd-amdhsa-gfx803,hip-amdgcn-amd-amdhsa-gfx900" // LINK-SAME: "-inputs=[[A_O]]" "-outputs={{.*o}},[[A_BC1:.*o]],[[A_BC2:.*o]]" -// LINK: "-unbundle" +// LINK: "-unbundle" "-allow-missing-bundles" // LINK: [[BUNDLER:".*clang-offload-bundler"]] "-type=o" // LINK-SAME: "-targets=host-x86_64-unknown-linux-gnu,hip-amdgcn-amd-amdhsa-gfx803,hip-amdgcn-amd-amdhsa-gfx900" // LINK-SAME: "-inputs=[[B_O]]" "-outputs={{.*o}},[[B_BC1:.*o]],[[B_BC2:.*o]]" -// LINK: "-unbundle" +// LINK: "-unbundle" "-allow-missing-bundles" // LINK-NOT: "*.llvm-link" // LINK-NOT: ".*opt" diff --git a/clang/test/Driver/openmp-offload.c b/clang/test/Driver/openmp-offload.c --- a/clang/test/Driver/openmp-offload.c +++ b/clang/test/Driver/openmp-offload.c @@ -495,7 +495,7 @@ // CHK-UBJOBS-SAME: [[INPUT:[^\\/]+\.i]]" "-outputs= // CHK-UBJOBS-SAME: [[HOSTPP:[^\\/]+\.i]], // CHK-UBJOBS-SAME: [[T1PP:[^\\/]+\.i]], -// CHK-UBJOBS-SAME: [[T2PP:[^\\/]+\.i]]" "-unbundle" +// CHK-UBJOBS-SAME: [[T2PP:[^\\/]+\.i]]" "-unbundle" "-allow-missing-bundles" // CHK-UBJOBS: clang{{.*}}" "-cc1" "-triple" "powerpc64le-unknown-linux" {{.*}}"-emit-llvm-bc" {{.*}}"-fopenmp" {{.*}}"-disable-llvm-passes" {{.*}}"-fopenmp-targets=powerpc64le-ibm-linux-gnu,x86_64-pc-linux-gnu" {{.*}}"-o" " // CHK-UBJOBS-SAME: [[HOSTBC:[^\\/]+\.bc]]" "-x" "cpp-output" "{{.*}}[[HOSTPP]]" // CHK-UBJOBS: clang{{.*}}" "-cc1" "-triple" "powerpc64le-unknown-linux" {{.*}}"-emit-obj" {{.*}}"-fopenmp" {{.*}}"-o" " @@ -504,7 +504,7 @@ // CHK-UBJOBS-ST-SAME: [[INPUT:[^\\/]+\.i]]" "-outputs= // CHK-UBJOBS-ST-SAME: [[HOSTPP:[^\\/,]+\.i]], // CHK-UBJOBS-ST-SAME: [[T1PP:[^\\/,]+\.i]], -// CHK-UBJOBS-ST-SAME: [[T2PP:[^\\/,]+\.i]]" "-unbundle" +// CHK-UBJOBS-ST-SAME: [[T2PP:[^\\/,]+\.i]]" "-unbundle" "-allow-missing-bundles" // CHK-UBJOBS-ST: clang{{.*}}" "-cc1" "-triple" "powerpc64le-unknown-linux" {{.*}}"-emit-llvm-bc" {{.*}}"-fopenmp" {{.*}}"-disable-llvm-passes" {{.*}}"-fopenmp-targets=powerpc64le-ibm-linux-gnu,x86_64-pc-linux-gnu" {{.*}}"-o" " // CHK-UBJOBS-ST-SAME: [[HOSTBC:[^\\/]+\.bc]]" "-x" "cpp-output" "{{.*}}[[HOSTPP]]" // CHK-UBJOBS-ST: clang{{.*}}" "-cc1" "-triple" "powerpc64le-unknown-linux" {{.*}}"-S" {{.*}}"-fopenmp" {{.*}}"-o" " @@ -563,7 +563,7 @@ // CHK-UBJOBS2-SAME: [[INPUT:[^\\/]+\.o]]" "-outputs= // CHK-UBJOBS2-SAME: [[HOSTOBJ:[^\\/]+\.o]], // CHK-UBJOBS2-SAME: [[T1OBJ:[^\\/]+\.o]], -// CHK-UBJOBS2-SAME: [[T2OBJ:[^\\/]+\.o]]" "-unbundle" +// CHK-UBJOBS2-SAME: [[T2OBJ:[^\\/]+\.o]]" "-unbundle" "-allow-missing-bundles" // CHK-UBJOBS2: ld{{(\.exe)?}}" {{.*}}"-o" " // CHK-UBJOBS2-SAME: [[T1BIN:[^\\/]+\.out]]" {{.*}}"{{.*}}[[T1OBJ]]" // CHK-UBJOBS2: ld{{(\.exe)?}}" {{.*}}"-o" " @@ -579,7 +579,7 @@ // CHK-UBJOBS2-ST-SAME: [[INPUT:[^\\/]+\.o]]" "-outputs= // CHK-UBJOBS2-ST-SAME: [[HOSTOBJ:[^\\/,]+\.o]], // CHK-UBJOBS2-ST-SAME: [[T1OBJ:[^\\/,]+\.o]], -// CHK-UBJOBS2-ST-SAME: [[T2OBJ:[^\\/,]+\.o]]" "-unbundle" +// CHK-UBJOBS2-ST-SAME: [[T2OBJ:[^\\/,]+\.o]]" "-unbundle" "-allow-missing-bundles" // CHK-UBJOBS2-ST-NOT: clang-offload-bundler{{.*}}in.so // CHK-UBJOBS2-ST: ld{{(\.exe)?}}" {{.*}}"-o" " // CHK-UBJOBS2-ST-SAME: [[T1BIN:[^\\/]+\.out-openmp-powerpc64le-ibm-linux-gnu]]" {{.*}}"{{.*}}[[T1OBJ]]" @@ -609,7 +609,7 @@ // CHK-UBUJOBS-SAME: [[INPUT:[^\\/]+\.i]]" "-outputs= // CHK-UBUJOBS-SAME: [[HOSTPP:[^\\/]+\.i]], // CHK-UBUJOBS-SAME: [[T1PP:[^\\/]+\.i]], -// CHK-UBUJOBS-SAME: [[T2PP:[^\\/]+\.i]]" "-unbundle" +// CHK-UBUJOBS-SAME: [[T2PP:[^\\/]+\.i]]" "-unbundle" "-allow-missing-bundles" // CHK-UBUJOBS: clang{{.*}}" "-cc1" "-triple" "powerpc64le-unknown-linux" {{.*}}"-emit-llvm-bc" {{.*}}"-fopenmp" {{.*}}"-disable-llvm-passes" {{.*}}"-fopenmp-targets=powerpc64le-ibm-linux-gnu,x86_64-pc-linux-gnu" {{.*}}"-o" " // CHK-UBUJOBS-SAME: [[HOSTBC:[^\\/]+\.bc]]" "-x" "cpp-output" "{{.*}}[[HOSTPP]]" @@ -617,7 +617,7 @@ // CHK-UBUJOBS-ST-SAME: [[INPUT:[^\\/]+\.i]]" "-outputs= // CHK-UBUJOBS-ST-SAME: [[HOSTPP:[^\\/,]+\.i]], // CHK-UBUJOBS-ST-SAME: [[T1PP:[^\\/,]+\.i]], -// CHK-UBUJOBS-ST-SAME: [[T2PP:[^\\/,]+\.i]]" "-unbundle" +// CHK-UBUJOBS-ST-SAME: [[T2PP:[^\\/,]+\.i]]" "-unbundle" "-allow-missing-bundles" // CHK-UBUJOBS-ST: clang{{.*}}" "-cc1" "-triple" "powerpc64le-unknown-linux" {{.*}}"-emit-llvm-bc" {{.*}}"-fopenmp" {{.*}}"-disable-llvm-passes" {{.*}}"-fopenmp-targets=powerpc64le-ibm-linux-gnu,x86_64-pc-linux-gnu" {{.*}}"-o" " // CHK-UBUJOBS-ST-SAME: [[HOSTBC:[^\\/]+\.bc]]" "-x" "cpp-output" "{{.*}}[[HOSTPP]]" diff --git a/clang/tools/clang-offload-bundler/ClangOffloadBundler.cpp b/clang/tools/clang-offload-bundler/ClangOffloadBundler.cpp --- a/clang/tools/clang-offload-bundler/ClangOffloadBundler.cpp +++ b/clang/tools/clang-offload-bundler/ClangOffloadBundler.cpp @@ -43,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -95,6 +96,12 @@ "instead of actually executing them - for testing purposes.\n"), cl::init(false), cl::cat(ClangOffloadBundlerCategory)); +static cl::opt + AllowMissingBundles("allow-missing-bundles", + cl::desc("Create empty files if bundles are missing " + "when unbundling.\n"), + cl::init(false), cl::cat(ClangOffloadBundlerCategory)); + static cl::opt BundleAlignment("bundle-align", cl::desc("Alignment of bundle for binary files"), @@ -883,6 +890,25 @@ FoundHostBundle = true; } + if (!AllowMissingBundles && !Worklist.empty()) { + std::string ErrMsg = "Can't find bundles for"; + std::set Sorted; + for (auto &E : Worklist) + Sorted.insert(E.first()); + unsigned I = 0; + unsigned Last = Sorted.size() - 1; + for (auto &E : Sorted) { + if (I != 0 && Last > 1) + ErrMsg += ","; + ErrMsg += " "; + if (I == Last && I != 0) + ErrMsg += "and "; + ErrMsg += E.str(); + ++I; + } + return createStringError(inconvertibleErrorCode(), ErrMsg); + } + // If no bundles were found, assume the input file is the host bundle and // create empty files for the remaining targets. if (Worklist.size() == TargetNames.size()) { @@ -974,7 +1000,15 @@ // have exactly one host target. unsigned Index = 0u; unsigned HostTargetNum = 0u; + llvm::DenseSet ParsedTargets; for (StringRef Target : TargetNames) { + if (ParsedTargets.contains(Target)) { + reportError(createStringError(errc::invalid_argument, + "Duplicate targets are not allowed")); + return 1; + } + ParsedTargets.insert(Target); + StringRef Kind; StringRef Triple; getOffloadKindAndTriple(Target, Kind, Triple);