From 0b9e33e0ce37ba714719d3314fe3606021736a5e Mon Sep 17 00:00:00 2001 From: Michael D Toguchi Date: Fri, 4 Sep 2020 19:44:33 -0700 Subject: [PATCH 1/2] [Driver][SYCL][FPGA] Enable dependency file usage from static archives for FPGA When performing compilations for FPGA, we want to be sure to take advantage of dependency information that could be part of the fat static archives. --- clang/include/clang/Driver/Types.def | 1 + clang/lib/Driver/Compilation.cpp | 3 +- clang/lib/Driver/Driver.cpp | 47 +++++++++++++++---- clang/lib/Driver/ToolChains/Clang.cpp | 9 ++-- clang/lib/Driver/ToolChains/SYCL.cpp | 9 +++- .../Driver/sycl-intelfpga-static-lib-win.cpp | 33 +++++++++++++ .../test/Driver/sycl-intelfpga-static-lib.cpp | 33 +++++++++++++ clang/test/Driver/sycl-offload-intelfpga.cpp | 24 ++++++---- 8 files changed, 133 insertions(+), 26 deletions(-) create mode 100644 clang/test/Driver/sycl-intelfpga-static-lib-win.cpp create mode 100644 clang/test/Driver/sycl-intelfpga-static-lib.cpp diff --git a/clang/include/clang/Driver/Types.def b/clang/include/clang/Driver/Types.def index 7b003aab3eb33..8e5b2afdcb976 100644 --- a/clang/include/clang/Driver/Types.def +++ b/clang/include/clang/Driver/Types.def @@ -111,4 +111,5 @@ TYPE("fpga_aocx", FPGA_AOCX, INVALID, "aocx", phases TYPE("fpga_aocr", FPGA_AOCR, INVALID, "aocr", phases::Compile, phases::Backend, phases::Assemble, phases::Link) TYPE("fpga_aoco", FPGA_AOCO, INVALID, "aoco", phases::Compile, phases::Backend, phases::Assemble, phases::Link) TYPE("fpga_dependencies", FPGA_Dependencies, INVALID, "d", phases::Compile, phases::Backend, phases::Assemble, phases::Link) +TYPE("fpga_dependencies_list", FPGA_Dependencies_List, INVALID, "txt", phases::Compile, phases::Backend, phases::Assemble, phases::Link) TYPE("none", Nothing, INVALID, nullptr, phases::Compile, phases::Backend, phases::Assemble, phases::Link) diff --git a/clang/lib/Driver/Compilation.cpp b/clang/lib/Driver/Compilation.cpp index c24a6f3765f26..46a82dce89c8a 100644 --- a/clang/lib/Driver/Compilation.cpp +++ b/clang/lib/Driver/Compilation.cpp @@ -150,7 +150,8 @@ bool Compilation::CleanupFileList(const TempFileList &Files, // Temporary file lists contain files that need to be cleaned. The // file containing the information is also removed if (File.second == types::TY_Tempfilelist || - File.second == types::TY_Tempfiletable) { + File.second == types::TY_Tempfiletable || + File.second == types::TY_FPGA_Dependencies_List) { // These are temporary files and need to be removed. bool IsTable = File.second == types::TY_Tempfiletable; diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp index 836219453b682..b3e3a6655ae62 100644 --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -3612,6 +3612,9 @@ class OffloadingActionBuilder final { /// List of objects to extract FPGA dependency info from ActionList FPGAObjectInputs; + /// List of static archives to extract FPGA dependency info from + ActionList FPGAArchiveInputs; + /// List of CUDA architectures to use in this compilation with NVPTX targets. SmallVector GpuArchList; @@ -4060,15 +4063,19 @@ class OffloadingActionBuilder final { // triple calls for it (provided a valid subarch). ActionList BEInputs; BEInputs.push_back(BuildCodeAction); - for (Action *A : FPGAObjectInputs) { - // Send any known objects through the unbundler to grab the - // dependency file associated. + auto unbundleAdd = [&](Action *A, types::ID T) { ActionList AL; AL.push_back(A); - Action *UnbundleAction = C.MakeAction( - AL, types::TY_FPGA_Dependencies); + Action *UnbundleAction = + C.MakeAction(AL, T); BEInputs.push_back(UnbundleAction); - } + }; + // Send any known objects/archives through the unbundler to grab the + // dependency file associated. + for (Action *A : FPGAObjectInputs) + unbundleAdd(A, types::TY_FPGA_Dependencies); + for (Action *A : FPGAArchiveInputs) + unbundleAdd(A, types::TY_FPGA_Dependencies_List); for (const auto &A : DeviceLibObjects) BEInputs.push_back(A); BuildCodeAction = @@ -4193,6 +4200,7 @@ class OffloadingActionBuilder final { Arg *SYCLAddTargets = Args.getLastArg(options::OPT_fsycl_add_targets_EQ); bool HasValidSYCLRuntime = C.getInputArgs().hasFlag(options::OPT_fsycl, options::OPT_fno_sycl, false); + bool SYCLfpgaTriple = false; if (SYCLTargets || SYCLAddTargets) { if (SYCLTargets) { llvm::StringMap FoundNormalizedTriples; @@ -4210,6 +4218,8 @@ class OffloadingActionBuilder final { FoundNormalizedTriples[NormalizedName] = Val; SYCLTripleList.push_back(TT); + if (TT.getSubArch() == llvm::Triple::SPIRSubArch_fpga) + SYCLfpgaTriple = true; } } if (SYCLAddTargets) { @@ -4233,6 +4243,8 @@ class OffloadingActionBuilder final { const char *SYCLTargetArch = SYCLfpga ? "spir64_fpga" : "spir64"; SYCLTripleList.push_back( C.getDriver().MakeSYCLDeviceTriple(SYCLTargetArch)); + if (SYCLfpga) + SYCLfpgaTriple = true; } // Set the FPGA output type based on command line (-fsycl-link). @@ -4240,6 +4252,21 @@ class OffloadingActionBuilder final { FPGAOutType = (A->getValue() == StringRef("early")) ? types::TY_FPGA_AOCR : types::TY_FPGA_AOCX; + // Populate FPGA static archives that could contain dep files to be + // incorporated into the aoc compilation + if (SYCLfpgaTriple) { + SmallVector LinkArgs(getLinkerArgs(C, Args)); + for (const StringRef &LA : LinkArgs) { + if (isStaticArchiveFile(LA) && hasOffloadSections(C, LA, Args)) { + const llvm::opt::OptTable &Opts = C.getDriver().getOpts(); + Arg *InputArg = MakeInputArg(Args, Opts, Args.MakeArgString(LA)); + Action *Current = + C.MakeAction(*InputArg, types::TY_Archive); + FPGAArchiveInputs.push_back(Current); + } + } + } + DeviceLinkerInputs.resize(ToolChains.size()); return initializeGpuArchMap(); } @@ -5975,12 +6002,14 @@ InputInfo Driver::BuildJobsForActionNoCache( // Do a check for a dependency file unbundle for FPGA. This is out of line // from a regular unbundle, so just create and return the name of the // unbundled file. - if (JA->getType() == types::TY_FPGA_Dependencies) { + if (JA->getType() == types::TY_FPGA_Dependencies || + JA->getType() == types::TY_FPGA_Dependencies_List) { + std::string Ext(types::getTypeTempSuffix(JA->getType())); std::string TmpFileName = - C.getDriver().GetTemporaryPath(llvm::sys::path::stem(BaseInput), "d"); + C.getDriver().GetTemporaryPath(llvm::sys::path::stem(BaseInput), Ext); const char *TmpFile = C.addTempFile(C.getArgs().MakeArgString(TmpFileName)); - Result = InputInfo(types::TY_FPGA_Dependencies, TmpFile, TmpFile); + Result = InputInfo(JA->getType(), TmpFile, TmpFile); UnbundlingResults.push_back(Result); } else { // Now that we have all the results generated, select the one that should diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 064acb6de4b17..14f3201c8914f 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -7378,7 +7378,8 @@ void OffloadBundler::ConstructJobMultipleOutputs( bool IsMSVCEnv = C.getDefaultToolChain().getTriple().isWindowsMSVCEnvironment(); types::ID InputType(Input.getType()); - bool IsFPGADepUnbundle = (JA.getType() == types::TY_FPGA_Dependencies); + bool IsFPGADepUnbundle = JA.getType() == types::TY_FPGA_Dependencies; + bool IsFPGADepLibUnbundle = JA.getType() == types::TY_FPGA_Dependencies_List; bool IsArchiveUnbundle = (!IsMSVCEnv && C.getDriver().getOffloadStaticLibSeen() && (types::isArchive(InputType) || InputType == types::TY_Object)); @@ -7394,7 +7395,7 @@ void OffloadBundler::ConstructJobMultipleOutputs( else TypeArg = "aoo"; } - if (InputType == types::TY_FPGA_AOCO || + if (InputType == types::TY_FPGA_AOCO || IsFPGADepLibUnbundle || (IsMSVCEnv && types::isArchive(InputType))) TypeArg = "aoo"; if (IsFPGADepUnbundle) @@ -7453,7 +7454,7 @@ void OffloadBundler::ConstructJobMultipleOutputs( Triples += Dep.DependentBoundArch; } } - if (IsFPGADepUnbundle) { + if (IsFPGADepUnbundle || IsFPGADepLibUnbundle) { // TODO - We are currently using the target triple inputs to slot a location // of the dependency information into the bundle. It would be good to // separate this out to an explicit option in the bundler for the dependency @@ -7474,7 +7475,7 @@ void OffloadBundler::ConstructJobMultipleOutputs( // When dealing with -fintelfpga, there is an additional unbundle step // that occurs for the dependency file. In that case, do not use the // dependent information, but just the output file. - if (IsFPGADepUnbundle) + if (IsFPGADepUnbundle || IsFPGADepLibUnbundle) UB += Outputs[0].getFilename(); else { for (unsigned I = 0; I < Outputs.size(); ++I) { diff --git a/clang/lib/Driver/ToolChains/SYCL.cpp b/clang/lib/Driver/ToolChains/SYCL.cpp index f3b58dd3d50f6..4687f1e0aaba5 100644 --- a/clang/lib/Driver/ToolChains/SYCL.cpp +++ b/clang/lib/Driver/ToolChains/SYCL.cpp @@ -225,7 +225,8 @@ void SYCL::fpga::BackendCompiler::ConstructJob(Compilation &C, // Add any FPGA library lists. These come in as special tempfile lists. CmdArgs.push_back(Args.MakeArgString(Twine("-library-list=") + Filename)); - else if (II.getType() == types::TY_FPGA_Dependencies) + else if (II.getType() == types::TY_FPGA_Dependencies || + II.getType() == types::TY_FPGA_Dependencies_List) FPGADepFiles.push_back(II); else CmdArgs.push_back(C.getArgs().MakeArgString(Filename)); @@ -277,9 +278,13 @@ void SYCL::fpga::BackendCompiler::ConstructJob(Compilation &C, if (!FPGADepFiles.empty()) { SmallString<128> DepOpt("-dep-files="); for (unsigned I = 0; I < FPGADepFiles.size(); ++I) { + SmallString<64> FileName; + if (FPGADepFiles[I].getType() == types::TY_FPGA_Dependencies_List) + FileName += "@"; + FileName += FPGADepFiles[I].getFilename(); if (I) DepOpt += ','; - DepOpt += FPGADepFiles[I].getFilename(); + DepOpt += FileName; } CmdArgs.push_back(C.getArgs().MakeArgString(DepOpt)); } diff --git a/clang/test/Driver/sycl-intelfpga-static-lib-win.cpp b/clang/test/Driver/sycl-intelfpga-static-lib-win.cpp new file mode 100644 index 0000000000000..2f61c8d9567d4 --- /dev/null +++ b/clang/test/Driver/sycl-intelfpga-static-lib-win.cpp @@ -0,0 +1,33 @@ +/// +/// tests specific to -fintelfpga -fsycl w/ static libs +/// +// REQUIRES: clang-driver +// REQUIRES: system-windows + +// make dummy archive +// Build a fat static lib that will be used for all tests +// RUN: echo "void foo(void) {}" > %t1.cpp +// RUN: %clang_cl --target=x86_64-pc-windows-msvc -fsycl -fintelfpga %t1.cpp -c -o %t1_bundle.obj +// RUN: lib -out:%t.lib %t1_bundle.obj + +/// Check phases with static lib +// RUN: %clang_cl --target=x86_64-pc-windows-msvc -fsycl -fintelfpga %t.lib -ccc-print-phases 2>&1 \ +// RUN: | FileCheck -check-prefix=CHECK_PHASES %s +// CHECK_PHASES: 0: input, "[[INPUT:.+\.lib]]", object, (host-sycl) +// CHECK_PHASES: 1: linker, {0}, image, (host-sycl) +// CHECK_PHASES: 2: input, "[[INPUT]]", archive +// CHECK_PHASES: 3: clang-offload-unbundler, {2}, archive +// CHECK_PHASES: 4: linker, {3}, ir, (device-sycl) +// CHECK_PHASES: 5: sycl-post-link, {4}, ir, (device-sycl) +// CHECK_PHASES: 6: llvm-spirv, {5}, spirv, (device-sycl) +// CHECK_PHASES: 7: input, "[[INPUT]]", archive +// CHECK_PHASES: 8: clang-offload-unbundler, {7}, fpga_dependencies_list +// CHECK_PHASES: 9: backend-compiler, {6, 8}, fpga_aocx, (device-sycl) +// CHECK_PHASES: 10: clang-offload-wrapper, {9}, object, (device-sycl) +// CHECK_PHASES: 11: offload, "host-sycl (x86_64-pc-windows-msvc)" {1}, "device-sycl (spir64_fpga-unknown-unknown-sycldevice)" {10}, image + +/// Check for unbundle and use of deps in static lib +// RUN: %clang_cl --target=x86_64-pc-windows-msvc -fsycl -fintelfpga %t.lib -### 2>&1 \ +// RUN: | FileCheck -check-prefix=CHECK_UNBUNDLE %s +// CHECK_UNBUNDLE: clang-offload-bundler" "-type=aoo" "-targets=sycl-fpga_dep" "-inputs={{.*}}" "-outputs=[[DEPFILES:.+\.txt]]" "-unbundle" +// CHECK_UNBUNDLE: aoc{{.*}} "-dep-files=@[[DEPFILES]]" diff --git a/clang/test/Driver/sycl-intelfpga-static-lib.cpp b/clang/test/Driver/sycl-intelfpga-static-lib.cpp new file mode 100644 index 0000000000000..510684ddaed7f --- /dev/null +++ b/clang/test/Driver/sycl-intelfpga-static-lib.cpp @@ -0,0 +1,33 @@ +/// +/// tests specific to -fintelfpga -fsycl w/ static libs +/// +// REQUIRES: clang-driver + +// make dummy archive +// Build a fat static lib that will be used for all tests +// RUN: echo "void foo(void) {}" > %t1.cpp +// RUN: %clangxx -target x86_64-unknown-linux-gnu -fintelfpga -fsycl %t1.cpp -c -o %t1_bundle.o +// RUN: llvm-ar cr %t.a %t1_bundle.o + +/// Check phases with static lib +// RUN: %clangxx -target x86_64-unknown-linux-gnu -fsycl -fintelfpga %t.a -ccc-print-phases 2>&1 \ +// RUN: | FileCheck -check-prefix=CHECK_PHASES %s +// CHECK_PHASES: 0: input, "[[INPUT:.+\.a]]", object, (host-sycl) +// CHECK_PHASES: 1: linker, {0}, image, (host-sycl) +// CHECK_PHASES: 2: input, "[[INPUT]]", archive +// CHECK_PHASES: 3: partial-link, {2}, object +// CHECK_PHASES: 4: clang-offload-unbundler, {3}, object +// CHECK_PHASES: 5: linker, {4}, ir, (device-sycl) +// CHECK_PHASES: 6: sycl-post-link, {5}, ir, (device-sycl) +// CHECK_PHASES: 7: llvm-spirv, {6}, spirv, (device-sycl) +// CHECK_PHASES: 8: input, "[[INPUT]]", archive +// CHECK_PHASES: 9: clang-offload-unbundler, {8}, fpga_dependencies_list +// CHECK_PHASES: 10: backend-compiler, {7, 9}, fpga_aocx, (device-sycl) +// CHECK_PHASES: 11: clang-offload-wrapper, {10}, object, (device-sycl) +// CHECK_PHASES: 12: offload, "host-sycl (x86_64-unknown-linux-gnu)" {1}, "device-sycl (spir64_fpga-unknown-unknown-sycldevice)" {11}, image + +/// Check for unbundle and use of deps in static lib +// RUN: %clangxx -target x86_64-unknown-linux-gnu -fsycl -fintelfpga %t.a -### 2>&1 \ +// RUN: | FileCheck -check-prefix=CHECK_UNBUNDLE %s +// CHECK_UNBUNDLE: clang-offload-bundler" "-type=aoo" "-targets=sycl-fpga_dep" "-inputs={{.*}}" "-outputs=[[DEPFILES:.+\.txt]]" "-unbundle" +// CHECK_UNBUNDLE: aoc{{.*}} "-dep-files=@[[DEPFILES]]" diff --git a/clang/test/Driver/sycl-offload-intelfpga.cpp b/clang/test/Driver/sycl-offload-intelfpga.cpp index de589affbc5e7..eec759afa5a22 100644 --- a/clang/test/Driver/sycl-offload-intelfpga.cpp +++ b/clang/test/Driver/sycl-offload-intelfpga.cpp @@ -368,11 +368,13 @@ // CHK-FPGA-AOCO-PHASES: 15: linker, {11, 14}, ir, (device-sycl) // CHK-FPGA-AOCO-PHASES: 16: sycl-post-link, {15}, ir, (device-sycl) // CHK-FPGA-AOCO-PHASES: 17: llvm-spirv, {16}, spirv, (device-sycl) -// CHK-FPGA-AOCO-PHASES: 18: input, "[[INPUTA]]", fpga_aoco -// CHK-FPGA-AOCO-PHASES: 19: clang-offload-unbundler, {18}, fpga_aoco -// CHK-FPGA-AOCO-PHASES: 20: backend-compiler, {17, 19}, fpga_aocx, (device-sycl) -// CHK-FPGA-AOCO-PHASES: 21: clang-offload-wrapper, {20}, object, (device-sycl) -// CHK-FPGA-AOCO-PHASES: 22: offload, "host-sycl (x86_64-unknown-linux-gnu)" {10}, "device-sycl (spir64_fpga-unknown-unknown-sycldevice)" {21}, image +// CHK-FPGA-AOCO-PHASES: 18: input, "[[INPUTA]]", archive +// CHK-FPGA-AOCO-PHASES: 19: clang-offload-unbundler, {18}, fpga_dependencies_list +// CHK-FPGA-AOCO-PHASES: 20: input, "[[INPUTA]]", fpga_aoco +// CHK-FPGA-AOCO-PHASES: 21: clang-offload-unbundler, {20}, fpga_aoco +// CHK-FPGA-AOCO-PHASES: 22: backend-compiler, {17, 19, 21}, fpga_aocx, (device-sycl) +// CHK-FPGA-AOCO-PHASES: 23: clang-offload-wrapper, {22}, object, (device-sycl) +// CHK-FPGA-AOCO-PHASES: 24: offload, "host-sycl (x86_64-unknown-linux-gnu)" {10}, "device-sycl (spir64_fpga-unknown-unknown-sycldevice)" {23}, image /// FPGA AOCO Windows phases check // RUN: %clang_cl -fsycl -fintelfpga -foffload-static-lib=%t_aoco_cl.a %s -### -ccc-print-phases 2>&1 \ @@ -394,11 +396,13 @@ // CHK-FPGA-AOCO-PHASES-WIN: 14: linker, {11, 13}, ir, (device-sycl) // CHK-FPGA-AOCO-PHASES-WIN: 15: sycl-post-link, {14}, ir, (device-sycl) // CHK-FPGA-AOCO-PHASES-WIN: 16: llvm-spirv, {15}, spirv, (device-sycl) -// CHK-FPGA-AOCO-PHASES-WIN: 17: input, "[[INPUTA]]", fpga_aoco -// CHK-FPGA-AOCO-PHASES-WIN: 18: clang-offload-unbundler, {17}, fpga_aoco -// CHK-FPGA-AOCO-PHASES-WIN: 19: backend-compiler, {16, 18}, fpga_aocx, (device-sycl) -// CHK-FPGA-AOCO-PHASES-WIN: 20: clang-offload-wrapper, {19}, object, (device-sycl) -// CHK-FPGA-AOCO-PHASES-WIN: 21: offload, "host-sycl (x86_64-pc-windows-msvc)" {10}, "device-sycl (spir64_fpga-unknown-unknown-sycldevice)" {20}, image +// CHK-FPGA-AOCO-PHASES-WIN: 17: input, "[[INPUTA]]", archive +// CHK-FPGA-AOCO-PHASES-WIN: 18: clang-offload-unbundler, {17}, fpga_dependencies_list +// CHK-FPGA-AOCO-PHASES-WIN: 19: input, "[[INPUTA]]", fpga_aoco +// CHK-FPGA-AOCO-PHASES-WIN: 20: clang-offload-unbundler, {19}, fpga_aoco +// CHK-FPGA-AOCO-PHASES-WIN: 21: backend-compiler, {16, 18, 20}, fpga_aocx, (device-sycl) +// CHK-FPGA-AOCO-PHASES-WIN: 22: clang-offload-wrapper, {21}, object, (device-sycl) +// CHK-FPGA-AOCO-PHASES-WIN: 23: offload, "host-sycl (x86_64-pc-windows-msvc)" {10}, "device-sycl (spir64_fpga-unknown-unknown-sycldevice)" {22}, image /// aoco test, checking tools // RUN: %clangxx -target x86_64-unknown-linux-gnu -fsycl -fintelfpga -foffload-static-lib=%t_aoco.a -### %s 2>&1 \ From 366b2bb45b19eda22bff380409be86b5d5ddc475 Mon Sep 17 00:00:00 2001 From: Michael D Toguchi Date: Thu, 10 Sep 2020 13:56:54 -0700 Subject: [PATCH 2/2] Improve string processing for dep file list to aoc --- clang/lib/Driver/ToolChains/SYCL.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/clang/lib/Driver/ToolChains/SYCL.cpp b/clang/lib/Driver/ToolChains/SYCL.cpp index 4687f1e0aaba5..ec1c9699c1980 100644 --- a/clang/lib/Driver/ToolChains/SYCL.cpp +++ b/clang/lib/Driver/ToolChains/SYCL.cpp @@ -278,13 +278,11 @@ void SYCL::fpga::BackendCompiler::ConstructJob(Compilation &C, if (!FPGADepFiles.empty()) { SmallString<128> DepOpt("-dep-files="); for (unsigned I = 0; I < FPGADepFiles.size(); ++I) { - SmallString<64> FileName; - if (FPGADepFiles[I].getType() == types::TY_FPGA_Dependencies_List) - FileName += "@"; - FileName += FPGADepFiles[I].getFilename(); if (I) DepOpt += ','; - DepOpt += FileName; + if (FPGADepFiles[I].getType() == types::TY_FPGA_Dependencies_List) + DepOpt += "@"; + DepOpt += FPGADepFiles[I].getFilename(); } CmdArgs.push_back(C.getArgs().MakeArgString(DepOpt)); }