diff --git a/clang/include/clang/Driver/Action.h b/clang/include/clang/Driver/Action.h index 8ccbb6c2bbfa2..27c95c6f89d41 100644 --- a/clang/include/clang/Driver/Action.h +++ b/clang/include/clang/Driver/Action.h @@ -73,9 +73,10 @@ class Action { OffloadBundlingJobClass, OffloadUnbundlingJobClass, OffloadWrapperJobClass, + StaticLibJobClass, JobClassFirst = PreprocessJobClass, - JobClassLast = OffloadWrapperJobClass + JobClassLast = StaticLibJobClass }; // The offloading kind determines if this action is binded to a particular @@ -637,6 +638,17 @@ class OffloadWrapperJobAction : public JobAction { } }; +class StaticLibJobAction : public JobAction { + void anchor() override; + +public: + StaticLibJobAction(ActionList &Inputs, types::ID Type); + + static bool classof(const Action *A) { + return A->getKind() == StaticLibJobClass; + } +}; + } // namespace driver } // namespace clang diff --git a/clang/include/clang/Driver/Driver.h b/clang/include/clang/Driver/Driver.h index 90a0c871140a5..b024d6a0d3a3a 100644 --- a/clang/include/clang/Driver/Driver.h +++ b/clang/include/clang/Driver/Driver.h @@ -548,6 +548,9 @@ class Driver { /// handle this action. bool ShouldUseFlangCompiler(const JobAction &JA) const; + /// ShouldEmitStaticLibrary - Should the linker emit a static library. + bool ShouldEmitStaticLibrary(const llvm::opt::ArgList &Args) const; + /// Returns true if we are performing any kind of LTO. bool isUsingLTO() const { return LTOMode != LTOK_None; } diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index 8ad582c84c604..c6474c1e5ccde 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -605,6 +605,8 @@ def hip_link : Flag<["--"], "hip-link">, def no_offload_arch_EQ : Joined<["--"], "no-offload-arch=">, Flags<[DriverOption]>, HelpText<"Remove CUDA/HIP offloading device architecture (e.g. sm_35, gfx906) from the list of devices to compile for. " "'all' resets the list to its default value.">; +def emit_static_lib : Flag<["--"], "emit-static-lib">, + HelpText<"Enable linker job to emit a static library.">; def no_cuda_gpu_arch_EQ : Joined<["--"], "no-cuda-gpu-arch=">, Flags<[DriverOption]>, Alias; def cuda_noopt_device_debug : Flag<["--"], "cuda-noopt-device-debug">, diff --git a/clang/include/clang/Driver/ToolChain.h b/clang/include/clang/Driver/ToolChain.h index f33ed991f493d..7495e08fe6e64 100644 --- a/clang/include/clang/Driver/ToolChain.h +++ b/clang/include/clang/Driver/ToolChain.h @@ -139,6 +139,7 @@ class ToolChain { mutable std::unique_ptr Flang; mutable std::unique_ptr Assemble; mutable std::unique_ptr Link; + mutable std::unique_ptr StaticLibTool; mutable std::unique_ptr IfsMerge; mutable std::unique_ptr OffloadBundler; mutable std::unique_ptr OffloadWrapper; @@ -147,6 +148,7 @@ class ToolChain { Tool *getFlang() const; Tool *getAssemble() const; Tool *getLink() const; + Tool *getStaticLibTool() const; Tool *getIfsMerge() const; Tool *getClangAs() const; Tool *getOffloadBundler() const; @@ -174,6 +176,7 @@ class ToolChain { virtual Tool *buildAssembler() const; virtual Tool *buildLinker() const; + virtual Tool *buildStaticLibTool() const; virtual Tool *getTool(Action::ActionClass AC) const; /// \name Utilities for implementing subclasses. @@ -326,6 +329,9 @@ class ToolChain { /// the linker suffix or name. std::string GetLinkerPath() const; + /// Returns the linker path for emitting a static library. + std::string GetStaticLibToolPath() const; + /// Dispatch to the specific toolchain for verbose printing. /// /// This is used when handling the verbose option to print detailed, diff --git a/clang/lib/Driver/Action.cpp b/clang/lib/Driver/Action.cpp index 0eb4c7257e7a8..2ec063d873be7 100644 --- a/clang/lib/Driver/Action.cpp +++ b/clang/lib/Driver/Action.cpp @@ -43,6 +43,8 @@ const char *Action::getClassName(ActionClass AC) { return "clang-offload-unbundler"; case OffloadWrapperJobClass: return "clang-offload-wrapper"; + case StaticLibJobClass: + return "static-lib-linker"; } llvm_unreachable("invalid class"); @@ -415,3 +417,8 @@ void OffloadWrapperJobAction::anchor() {} OffloadWrapperJobAction::OffloadWrapperJobAction(ActionList &Inputs, types::ID Type) : JobAction(OffloadWrapperJobClass, Inputs, Type) {} + +void StaticLibJobAction::anchor() {} + +StaticLibJobAction::StaticLibJobAction(ActionList &Inputs, types::ID Type) + : JobAction(StaticLibJobClass, Inputs, Type) {} diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp index de732918fc763..0cf99377f2b5f 100644 --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -3542,7 +3542,13 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args, if (!LinkerInputs.empty()) { if (Action *Wrapper = OffloadBuilder.makeHostLinkAction()) LinkerInputs.push_back(Wrapper); - Action *LA = C.MakeAction(LinkerInputs, types::TY_Image); + Action *LA; + // Check if this Linker Job should emit a static library. + if (ShouldEmitStaticLibrary(Args)) { + LA = C.MakeAction(LinkerInputs, types::TY_Image); + } else { + LA = C.MakeAction(LinkerInputs, types::TY_Image); + } LA = OffloadBuilder.processHostLinkAction(LA); Actions.push_back(LA); } @@ -5044,6 +5050,13 @@ bool Driver::ShouldUseFlangCompiler(const JobAction &JA) const { return true; } +bool Driver::ShouldEmitStaticLibrary(const ArgList &Args) const { + // Only emit static library if the flag is set explicitly. + if (Args.hasArg(options::OPT_emit_static_lib)) + return true; + return false; +} + /// GetReleaseVersion - Parse (([0-9]+)(.([0-9]+)(.([0-9]+)?))?)? and return the /// grouped values as integers. Numbers which are not provided are set to 0. /// diff --git a/clang/lib/Driver/ToolChain.cpp b/clang/lib/Driver/ToolChain.cpp index c21bc0dc2a799..b8c12fc9241a6 100644 --- a/clang/lib/Driver/ToolChain.cpp +++ b/clang/lib/Driver/ToolChain.cpp @@ -275,6 +275,10 @@ Tool *ToolChain::buildLinker() const { llvm_unreachable("Linking is not supported by this toolchain"); } +Tool *ToolChain::buildStaticLibTool() const { + llvm_unreachable("Creating static lib is not supported by this toolchain"); +} + Tool *ToolChain::getAssemble() const { if (!Assemble) Assemble.reset(buildAssembler()); @@ -293,6 +297,12 @@ Tool *ToolChain::getLink() const { return Link.get(); } +Tool *ToolChain::getStaticLibTool() const { + if (!StaticLibTool) + StaticLibTool.reset(buildStaticLibTool()); + return StaticLibTool.get(); +} + Tool *ToolChain::getIfsMerge() const { if (!IfsMerge) IfsMerge.reset(new tools::ifstool::Merger(*this)); @@ -322,6 +332,9 @@ Tool *ToolChain::getTool(Action::ActionClass AC) const { case Action::LinkJobClass: return getLink(); + case Action::StaticLibJobClass: + return getStaticLibTool(); + case Action::InputClass: case Action::BindArchClass: case Action::OffloadClass: @@ -565,6 +578,11 @@ std::string ToolChain::GetLinkerPath() const { return GetProgramPath(getDefaultLinker()); } +std::string ToolChain::GetStaticLibToolPath() const { + // TODO: Add support for static lib archiving on Windows + return GetProgramPath("llvm-ar"); +} + types::ID ToolChain::LookupTypeForExtension(StringRef Ext) const { types::ID id = types::lookupTypeForExtension(Ext); diff --git a/clang/lib/Driver/ToolChains/Gnu.cpp b/clang/lib/Driver/ToolChains/Gnu.cpp index 619407a7c57bf..4e577ee163df4 100644 --- a/clang/lib/Driver/ToolChains/Gnu.cpp +++ b/clang/lib/Driver/ToolChains/Gnu.cpp @@ -341,6 +341,43 @@ static bool getStatic(const ArgList &Args) { !Args.hasArg(options::OPT_static_pie); } +void tools::gnutools::StaticLibTool::ConstructJob( + Compilation &C, const JobAction &JA, const InputInfo &Output, + const InputInfoList &Inputs, const ArgList &Args, + const char *LinkingOutput) const { + const Driver &D = getToolChain().getDriver(); + + // Silence warning for "clang -g foo.o -o foo" + Args.ClaimAllArgs(options::OPT_g_Group); + // and "clang -emit-llvm foo.o -o foo" + Args.ClaimAllArgs(options::OPT_emit_llvm); + // and for "clang -w foo.o -o foo". Other warning options are already + // handled somewhere else. + Args.ClaimAllArgs(options::OPT_w); + // Silence warnings when linking C code with a C++ '-stdlib' argument. + Args.ClaimAllArgs(options::OPT_stdlib_EQ); + + // GNU ar tool command "ar ". + ArgStringList CmdArgs; + // Create and insert file members with a deterministic index. + CmdArgs.push_back("rcsD"); + CmdArgs.push_back(Output.getFilename()); + AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA); + + // Delete old output archive file if it already exists before generating a new + // archive file. + auto OutputFileName = Output.getFilename(); + if (Output.isFilename() && llvm::sys::fs::exists(OutputFileName)) { + if (std::error_code EC = llvm::sys::fs::remove(OutputFileName)) { + D.Diag(diag::err_drv_unable_to_remove_file) << EC.message(); + return; + } + } + + const char *Exec = Args.MakeArgString(getToolChain().GetStaticLibToolPath()); + C.addCommand(std::make_unique(JA, *this, Exec, CmdArgs, Inputs)); +} + void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, diff --git a/clang/lib/Driver/ToolChains/Gnu.h b/clang/lib/Driver/ToolChains/Gnu.h index 8ef9b4fdb6cd9..ff300faa410df 100644 --- a/clang/lib/Driver/ToolChains/Gnu.h +++ b/clang/lib/Driver/ToolChains/Gnu.h @@ -72,6 +72,20 @@ class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool { const llvm::opt::ArgList &TCArgs, const char *LinkingOutput) const override; }; + +class LLVM_LIBRARY_VISIBILITY StaticLibTool : public GnuTool { +public: + StaticLibTool(const ToolChain &TC) + : GnuTool("GNU::StaticLibTool", "static-lib-linker", TC) {} + + bool hasIntegratedCPP() const override { return false; } + bool isLinkJob() const override { return true; } + + void ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const override; +}; } // end namespace gnutools /// gcc - Generic GCC tool implementations. diff --git a/clang/lib/Driver/ToolChains/Linux.cpp b/clang/lib/Driver/ToolChains/Linux.cpp index 222c351016a79..5e74a2b3c5ffe 100644 --- a/clang/lib/Driver/ToolChains/Linux.cpp +++ b/clang/lib/Driver/ToolChains/Linux.cpp @@ -363,6 +363,10 @@ bool Linux::HasNativeLLVMSupport() const { return true; } Tool *Linux::buildLinker() const { return new tools::gnutools::Linker(*this); } +Tool *Linux::buildStaticLibTool() const { + return new tools::gnutools::StaticLibTool(*this); +} + Tool *Linux::buildAssembler() const { return new tools::gnutools::Assembler(*this); } diff --git a/clang/lib/Driver/ToolChains/Linux.h b/clang/lib/Driver/ToolChains/Linux.h index fba5c24441e48..6b16b0e64990d 100644 --- a/clang/lib/Driver/ToolChains/Linux.h +++ b/clang/lib/Driver/ToolChains/Linux.h @@ -57,6 +57,7 @@ class LLVM_LIBRARY_VISIBILITY Linux : public Generic_ELF { protected: Tool *buildAssembler() const override; Tool *buildLinker() const override; + Tool *buildStaticLibTool() const override; std::string getMultiarchTriple(const Driver &D, const llvm::Triple &TargetTriple, diff --git a/clang/test/Driver/bindings.c b/clang/test/Driver/bindings.c index 880667b739348..d7f323419d39e 100644 --- a/clang/test/Driver/bindings.c +++ b/clang/test/Driver/bindings.c @@ -23,3 +23,7 @@ // CHECK14: "clang", inputs: ["{{.*}}bindings.c"], output: "{{.*}}.s" // CHECK14: "darwin::Assembler", inputs: ["{{.*}}.s"], output: "{{.*}}.o" // CHECK14: "darwin::Linker", inputs: ["{{.*}}.o"], output: "a.out" + +// GNU StaticLibTool binding +// RUN: %clang -target x86_64-linux-gnu -ccc-print-bindings --emit-static-lib %s 2>&1 | FileCheck %s --check-prefix=CHECK15 +// CHECK15: "x86_64-unknown-linux-gnu" - "GNU::StaticLibTool", inputs: ["{{.*}}.o"], output: "a.out" diff --git a/clang/test/Driver/hip-link-save-temps.hip b/clang/test/Driver/hip-link-save-temps.hip index 62d8d60af3c09..15ab210a84f75 100644 --- a/clang/test/Driver/hip-link-save-temps.hip +++ b/clang/test/Driver/hip-link-save-temps.hip @@ -18,6 +18,24 @@ // RUN: --offload-arch=gfx906 %T/obj1.o %T/obj2.o 2>&1 | \ // RUN: FileCheck -check-prefixes=CHECK,NOUT %s +// -fgpu-rdc link with output and --emit-static-lib +// RUN: touch %T/obj1.o +// RUN: touch %T/obj2.o +// RUN: %clang -### -target x86_64-linux-gnu -nogpulib -save-temps \ +// RUN: --hip-link -o libTest.a -fgpu-rdc --cuda-gpu-arch=gfx900 \ +// RUN: --emit-static-lib \ +// RUN: --offload-arch=gfx906 %T/obj1.o %T/obj2.o 2>&1 | \ +// RUN: FileCheck -check-prefixes=CHECK,SLO %s + +// -fgpu-rdc link without output and --emit-static-lib +// RUN: touch %T/obj1.o +// RUN: touch %T/obj2.o +// RUN: %clang -### -target x86_64-linux-gnu -nogpulib -save-temps \ +// RUN: --hip-link -fgpu-rdc --cuda-gpu-arch=gfx900 \ +// RUN: --emit-static-lib \ +// RUN: --offload-arch=gfx906 %T/obj1.o %T/obj2.o 2>&1 | \ +// RUN: FileCheck -check-prefixes=CHECK,SLNO %s + // CHECK: "{{.*clang-offload-bundler.*}}" {{.*}} "-outputs=obj1-host-x86_64-unknown-linux-gnu.o,obj1-hip-amdgcn-amd-amdhsa-gfx900.o,obj1-hip-amdgcn-amd-amdhsa-gfx906.o" "-unbundle" // CHECK: "{{.*clang-offload-bundler.*}}" {{.*}} "-outputs=obj2-host-x86_64-unknown-linux-gnu.o,obj2-hip-amdgcn-amd-amdhsa-gfx900.o,obj2-hip-amdgcn-amd-amdhsa-gfx906.o" "-unbundle" // CHECK-NOT: llvm-link @@ -31,3 +49,5 @@ // CHECK-SAME: "[[OBJBUNDLE:.*.o]]" "{{.*}}.mcin" "--filetype=obj" // OUT: "{{.*ld.*}}" {{.*}} "-o" "executable" {{.*}} "[[OBJBUNDLE]]" // NOUT: "{{.*ld.*}}" {{.*}} "-o" "a.out" {{.*}} "[[OBJBUNDLE]]" +// SLO: "{{.*llvm-ar.*}}" "rcsD" "libTest.a" {{.*}} "[[OBJBUNDLE]]" +// SLNO: "{{.*llvm-ar.*}}" "rcsD" "a.out" {{.*}} "[[OBJBUNDLE]]" diff --git a/clang/test/Driver/hip-link-static-library.hip b/clang/test/Driver/hip-link-static-library.hip new file mode 100644 index 0000000000000..55c5a5acc5ca6 --- /dev/null +++ b/clang/test/Driver/hip-link-static-library.hip @@ -0,0 +1,27 @@ +// REQUIRES: clang-driver +// REQUIRES: x86-registered-target +// REQUIRES: amdgpu-registered-target + +// RUN: touch %t.o +// RUN: %clang --hip-link -ccc-print-bindings -target x86_64-linux-gnu \ +// RUN: --emit-static-lib \ +// RUN: --cuda-gpu-arch=gfx803 --cuda-gpu-arch=gfx900 -fgpu-rdc %t.o\ +// RUN: 2>&1 | FileCheck %s + +// CHECK: # "x86_64-unknown-linux-gnu" - "offload bundler", inputs: ["[[IN:.*o]]"], outputs: ["[[HOSTOBJ:.*o]]", "{{.*o}}", "{{.*o}}"] +// CHECK: # "amdgcn-amd-amdhsa" - "offload bundler", inputs: ["[[IN]]"], outputs: ["{{.*o}}", "[[DOBJ1:.*o]]", "[[DOBJ2:.*o]]"] +// CHECK: # "amdgcn-amd-amdhsa" - "AMDGCN::Linker", inputs: ["[[DOBJ1]]"], output: "[[IMG1:.*out]]" +// CHECK-NOT: offload bundler +// CHECK: # "amdgcn-amd-amdhsa" - "AMDGCN::Linker", inputs: ["[[DOBJ2]]"], output: "[[IMG2:.*out]]" +// CHECK-NOT: offload bundler +// CHECK: # "amdgcn-amd-amdhsa" - "AMDGCN::Linker", inputs: ["[[IMG1]]", "[[IMG2]]"], output: "[[FATBINOBJ:.*o]]" +// CHECK-NOT: offload bundler +// CHECK: # "x86_64-unknown-linux-gnu" - "GNU::StaticLibTool", inputs: ["[[HOSTOBJ]]", "[[FATBINOBJ]]"], output: "a.out" + +// RUN: %clang --hip-link -ccc-print-bindings -target x86_64-linux-gnu \ +// RUN: --emit-static-lib \ +// RUN: --cuda-gpu-arch=gfx803 --cuda-gpu-arch=gfx900 %t.o\ +// RUN: 2>&1 | FileCheck -check-prefix=NORDC %s + +// NORDC-NOT: offload bundler +// NORDC: # "x86_64-unknown-linux-gnu" - "GNU::StaticLibTool", inputs: ["{{.*o}}"], output: "a.out" diff --git a/clang/test/Driver/hip-toolchain-rdc-static-lib.hip b/clang/test/Driver/hip-toolchain-rdc-static-lib.hip new file mode 100644 index 0000000000000..56b54afbf29f7 --- /dev/null +++ b/clang/test/Driver/hip-toolchain-rdc-static-lib.hip @@ -0,0 +1,84 @@ +// REQUIRES: clang-driver +// REQUIRES: x86-registered-target +// REQUIRES: amdgpu-registered-target + +// RUN: %clang -### -target x86_64-linux-gnu \ +// RUN: -x hip --cuda-gpu-arch=gfx803 --cuda-gpu-arch=gfx900 \ +// RUN: --emit-static-lib -nogpulib \ +// RUN: -fuse-ld=lld -fgpu-rdc -nogpuinc \ +// RUN: %S/Inputs/hip_multiple_inputs/a.cu \ +// RUN: %S/Inputs/hip_multiple_inputs/b.hip \ +// RUN: 2>&1 | FileCheck %s + +// emit objects for host side path +// CHECK: [[CLANG:".*clang.*"]] "-cc1" "-triple" "x86_64-unknown-linux-gnu" +// CHECK-SAME: "-aux-triple" "amdgcn-amd-amdhsa" +// CHECK-SAME: "-emit-obj" +// CHECK-SAME: {{.*}} "-main-file-name" "a.cu" +// CHECK-SAME: {{.*}} "-o" [[A_OBJ_HOST:".*o"]] "-x" "hip" +// CHECK-SAME: {{.*}} [[A_SRC:".*a.cu"]] + +// CHECK: [[CLANG]] "-cc1" "-triple" "x86_64-unknown-linux-gnu" +// CHECK-SAME: "-aux-triple" "amdgcn-amd-amdhsa" +// CHECK-SAME: "-emit-obj" +// CHECK-SAME: {{.*}} "-main-file-name" "b.hip" +// CHECK-SAME: {{.*}} "-o" [[B_OBJ_HOST:".*o"]] "-x" "hip" +// CHECK-SAME: {{.*}} [[B_SRC:".*b.hip"]] + +// generate image for device side path on gfx803 +// CHECK: [[CLANG]] "-cc1" "-triple" "amdgcn-amd-amdhsa" +// CHECK-SAME: "-aux-triple" "x86_64-unknown-linux-gnu" +// CHECK-SAME: "-emit-llvm-bc" +// CHECK-SAME: {{.*}} "-main-file-name" "a.cu" +// CHECK-SAME: "-fcuda-is-device" "-fgpu-rdc" +// CHECK-SAME: "-target-cpu" "gfx803" +// CHECK-SAME: {{.*}} "-o" [[A_BC1:".*bc"]] "-x" "hip" +// CHECK-SAME: {{.*}} [[A_SRC]] + +// CHECK: [[CLANG]] "-cc1" "-triple" "amdgcn-amd-amdhsa" +// CHECK-SAME: "-aux-triple" "x86_64-unknown-linux-gnu" +// CHECK-SAME: "-emit-llvm-bc" +// CHECK-SAME: {{.*}} "-main-file-name" "b.hip" +// CHECK-SAME: "-fcuda-is-device" "-fgpu-rdc" +// CHECK-SAME: "-target-cpu" "gfx803" +// CHECK-SAME: {{.*}} "-o" [[B_BC1:".*bc"]] "-x" "hip" +// CHECK-SAME: {{.*}} [[B_SRC]] + +// CHECK-NOT: "*.llvm-link" +// CHECK-NOT: ".*opt" +// CHECK-NOT: ".*llc" +// CHECK: [[LLD: ".*lld"]] {{.*}} "-o" "[[IMG_DEV1:.*out]]" [[A_BC1]] [[B_BC1]] + +// generate image for device side path on gfx900 +// CHECK: [[CLANG]] "-cc1" "-triple" "amdgcn-amd-amdhsa" +// CHECK-SAME: "-aux-triple" "x86_64-unknown-linux-gnu" +// CHECK-SAME: "-emit-llvm-bc" +// CHECK-SAME: {{.*}} "-main-file-name" "a.cu" +// CHECK-SAME: "-fcuda-is-device" "-fgpu-rdc" +// CHECK-SAME: "-target-cpu" "gfx900" +// CHECK-SAME: {{.*}} "-o" [[A_BC2:".*bc"]] "-x" "hip" +// CHECK-SAME: {{.*}} [[A_SRC]] + +// CHECK: [[CLANG]] "-cc1" "-triple" "amdgcn-amd-amdhsa" +// CHECK-SAME: "-aux-triple" "x86_64-unknown-linux-gnu" +// CHECK-SAME: "-emit-llvm-bc" +// CHECK-SAME: {{.*}} "-main-file-name" "b.hip" +// CHECK-SAME: "-fcuda-is-device" "-fgpu-rdc" +// CHECK-SAME: "-target-cpu" "gfx900" +// CHECK-SAME: {{.*}} "-o" [[B_BC2:".*bc"]] "-x" "hip" +// CHECK-SAME: {{.*}} [[B_SRC]] + +// CHECK-NOT: "*.llvm-link" +// CHECK-NOT: ".*opt" +// CHECK-NOT: ".*llc" +// CHECK: [[LLD]] {{.*}} "-o" "[[IMG_DEV2:.*out]]" [[A_BC2]] [[B_BC2]] + +// combine images generated into hip fat binary object +// CHECK: [[BUNDLER:".*clang-offload-bundler"]] "-type=o" +// CHECK-SAME: "-targets={{.*}},hip-amdgcn-amd-amdhsa-gfx803,hip-amdgcn-amd-amdhsa-gfx900" +// CHECK-SAME: "-inputs={{.*}},[[IMG_DEV1]],[[IMG_DEV2]]" "-outputs=[[BUNDLE:.*hipfb]]" + +// CHECK: [[MC:".*llvm-mc"]] "-triple" "amdgcn-amd-amdhsa" +// CHECK-SAME: "-o" [[OBJBUNDLE:".*o"]] "{{.*}}.mcin" "--filetype=obj" + +// CHECK: [[AR:".*llvm-ar.*"]] "rcsD" "{{.*}}.out" [[A_OBJ_HOST]] [[B_OBJ_HOST]] [[OBJBUNDLE]]