8686#include " llvm/Support/ErrorHandling.h"
8787#include " llvm/Support/ExitCodes.h"
8888#include " llvm/Support/FileSystem.h"
89+ #include " llvm/Support/FileUtilities.h"
8990#include " llvm/Support/FormatVariadic.h"
9091#include " llvm/Support/Host.h"
92+ #include " llvm/Support/LineIterator.h"
9193#include " llvm/Support/MD5.h"
9294#include " llvm/Support/Path.h"
9395#include " llvm/Support/PrettyStackTrace.h"
@@ -1659,6 +1661,9 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) {
16591661 if (checkForSYCLDefaultDevice (*C, *TranslatedArgs))
16601662 setSYCLDefaultTriple (true );
16611663
1664+ // Check missing targets in archives/objects based on inputs from the user.
1665+ checkForOffloadMismatch (*C, *TranslatedArgs);
1666+
16621667 // Populate the tool chains for the offloading devices, if any.
16631668 CreateOffloadingDeviceToolChains (*C, Inputs);
16641669
@@ -3166,6 +3171,72 @@ static bool hasFPGABinary(Compilation &C, std::string Object, types::ID Type) {
31663171 return runBundler (BundlerArgs, C);
31673172}
31683173
3174+ static SmallVector<std::string, 4 > getOffloadSections (Compilation &C,
3175+ const StringRef &File) {
3176+ // Do not do the check if the file doesn't exist
3177+ if (!llvm::sys::fs::exists (File))
3178+ return {};
3179+
3180+ bool IsArchive = isStaticArchiveFile (File);
3181+ if (!(IsArchive || isObjectFile (File.str ())))
3182+ return {};
3183+
3184+ // Use the bundler to grab the list of sections from the given archive
3185+ // or object.
3186+ StringRef ExecPath (C.getArgs ().MakeArgString (C.getDriver ().Dir ));
3187+ llvm::ErrorOr<std::string> BundlerBinary =
3188+ llvm::sys::findProgramByName (" clang-offload-bundler" , ExecPath);
3189+ const char *Input = C.getArgs ().MakeArgString (Twine (" -input=" ) + File.str ());
3190+ // Always use -type=ao for bundle checking. The 'bundles' are
3191+ // actually archives.
3192+ SmallVector<StringRef, 6 > BundlerArgs = {
3193+ BundlerBinary.get (), IsArchive ? " -type=ao" : " -type=o" , Input, " -list" };
3194+ // Since this is run in real time and not in the toolchain, output the
3195+ // command line if requested.
3196+ bool OutputOnly = C.getArgs ().hasArg (options::OPT__HASH_HASH_HASH);
3197+ if (C.getArgs ().hasArg (options::OPT_v) || OutputOnly) {
3198+ for (StringRef A : BundlerArgs)
3199+ if (OutputOnly)
3200+ llvm::errs () << " \" " << A << " \" " ;
3201+ else
3202+ llvm::errs () << A << " " ;
3203+ llvm::errs () << ' \n ' ;
3204+ }
3205+ if (BundlerBinary.getError ())
3206+ return {};
3207+ llvm::SmallString<64 > OutputFile (
3208+ C.getDriver ().GetTemporaryPath (" bundle-list" , " txt" ));
3209+ llvm::FileRemover OutputRemover (OutputFile.c_str ());
3210+ llvm::Optional<llvm::StringRef> Redirects[] = {
3211+ {" " },
3212+ OutputFile.str (),
3213+ OutputFile.str (),
3214+ };
3215+
3216+ std::string ErrorMessage;
3217+ if (llvm::sys::ExecuteAndWait (BundlerBinary.get (), BundlerArgs, {}, Redirects,
3218+ /* SecondsToWait*/ 0 , /* MemoryLimit*/ 0 ,
3219+ &ErrorMessage)) {
3220+ // Could not get the information, return false
3221+ return {};
3222+ }
3223+
3224+ llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> OutputBuf =
3225+ llvm::MemoryBuffer::getFile (OutputFile.c_str ());
3226+ if (!OutputBuf) {
3227+ // Could not capture output, return false
3228+ return {};
3229+ }
3230+
3231+ SmallVector<std::string, 4 > Sections;
3232+ for (llvm::line_iterator LineIt (**OutputBuf); !LineIt.is_at_end (); ++LineIt)
3233+ Sections.push_back (LineIt->str ());
3234+ if (Sections.empty ())
3235+ return {};
3236+
3237+ return Sections;
3238+ }
3239+
31693240static bool hasSYCLDefaultSection (Compilation &C, const StringRef &File) {
31703241 // Do not do the check if the file doesn't exist
31713242 if (!llvm::sys::fs::exists (File))
@@ -3180,20 +3251,21 @@ static bool hasSYCLDefaultSection(Compilation &C, const StringRef &File) {
31803251 // file and the target triple being looked for.
31813252 const char *Targets =
31823253 C.getArgs ().MakeArgString (Twine (" -targets=sycl-" ) + TT.str ());
3183- const char *Inputs =
3184- C.getArgs ().MakeArgString (Twine (" -input=" ) + File.str ());
3185- // Always use -type=ao for bundle checking. The 'bundles' are
3186- // actually archives.
3254+ const char *Inputs = C.getArgs ().MakeArgString (Twine (" -input=" ) + File.str ());
31873255 SmallVector<StringRef, 6 > BundlerArgs = {" clang-offload-bundler" ,
31883256 IsArchive ? " -type=ao" : " -type=o" ,
31893257 Targets, Inputs, " -check-section" };
31903258 return runBundler (BundlerArgs, C);
31913259}
31923260
3193- static bool hasOffloadSections (Compilation &C, const StringRef &Archive ,
3261+ static bool hasOffloadSections (Compilation &C, const StringRef &File ,
31943262 DerivedArgList &Args) {
31953263 // Do not do the check if the file doesn't exist
3196- if (!llvm::sys::fs::exists (Archive))
3264+ if (!llvm::sys::fs::exists (File))
3265+ return false ;
3266+
3267+ bool IsArchive = isStaticArchiveFile (File);
3268+ if (!(IsArchive || isObjectFile (File.str ())))
31973269 return false ;
31983270
31993271 llvm::Triple TT (C.getDefaultToolChain ().getTriple ());
@@ -3202,10 +3274,9 @@ static bool hasOffloadSections(Compilation &C, const StringRef &Archive,
32023274 // TODO - Improve checking to check for explicit offload target instead
32033275 // of the generic host availability.
32043276 const char *Targets = Args.MakeArgString (Twine (" -targets=host-" ) + TT.str ());
3205- const char *Inputs = Args.MakeArgString (Twine (" -input=" ) + Archive.str ());
3206- // Always use -type=ao for bundle checking. The 'bundles' are
3207- // actually archives.
3208- SmallVector<StringRef, 6 > BundlerArgs = {" clang-offload-bundler" , " -type=ao" ,
3277+ const char *Inputs = Args.MakeArgString (Twine (" -input=" ) + File.str ());
3278+ SmallVector<StringRef, 6 > BundlerArgs = {" clang-offload-bundler" ,
3279+ IsArchive ? " -type=ao" : " -type=o" ,
32093280 Targets, Inputs, " -check-section" };
32103281 return runBundler (BundlerArgs, C);
32113282}
@@ -3456,6 +3527,73 @@ bool Driver::checkForOffloadStaticLib(Compilation &C,
34563527 return false ;
34573528}
34583529
3530+ // Goes through all of the arguments, including inputs expected for the
3531+ // linker directly, to determine if the targets contained in the objects and
3532+ // archives match target expectations being performed.
3533+ void Driver::checkForOffloadMismatch (Compilation &C,
3534+ DerivedArgList &Args) const {
3535+ // Check only if enabled with -fsycl
3536+ if (!Args.hasFlag (options::OPT_fsycl, options::OPT_fno_sycl, false ))
3537+ return ;
3538+
3539+ SmallVector<const char *, 16 > OffloadLibArgs (getLinkerArgs (C, Args, true ));
3540+ // Gather all of the sections seen in the offload objects/archives
3541+ SmallVector<std::string, 4 > UniqueSections;
3542+ for (StringRef OLArg : OffloadLibArgs) {
3543+ SmallVector<std::string, 4 > Sections (getOffloadSections (C, OLArg));
3544+ for (auto Section : Sections) {
3545+ // We only care about sections that start with 'sycl-'. Also remove
3546+ // the prefix before adding it.
3547+ std::string Prefix (" sycl-" );
3548+ if (Section.compare (0 , Prefix.length (), Prefix) != 0 )
3549+ continue ;
3550+ std::string Arch = Section.substr (Prefix.length ());
3551+ // There are a few different variants for FPGA, if we see one, just
3552+ // use the default FPGA triple to reduce possible match confusion.
3553+ if (Arch.compare (0 , 4 , " fpga" ) == 0 )
3554+ Arch = C.getDriver ().MakeSYCLDeviceTriple (" spir64_fpga" ).str ();
3555+ if (std::find (UniqueSections.begin (), UniqueSections.end (), Arch) ==
3556+ UniqueSections.end ())
3557+ UniqueSections.push_back (Arch);
3558+ }
3559+ }
3560+
3561+ if (!UniqueSections.size ())
3562+ return ;
3563+
3564+ // Put together list of user defined and implied targets, we will diagnose
3565+ // each target individually.
3566+ SmallVector<StringRef, 4 > Targets;
3567+ if (const Arg *A = Args.getLastArg (options::OPT_fsycl_targets_EQ)) {
3568+ for (const char *Val : A->getValues ())
3569+ Targets.push_back (Val);
3570+ } else { // Implied targets
3571+ // No -fsycl-targets given, check based on -fintelfpga or default device
3572+ bool SYCLfpga = C.getInputArgs ().hasArg (options::OPT_fintelfpga);
3573+ // -fsycl -fintelfpga implies spir64_fpga
3574+ Targets.push_back (SYCLfpga ? " spir64_fpga" : getDefaultSYCLArch (C));
3575+ }
3576+
3577+ for (auto SyclTarget : Targets) {
3578+ // Match found sections with user and implied targets.
3579+ llvm::Triple TT (C.getDriver ().MakeSYCLDeviceTriple (SyclTarget));
3580+ // If any matching section is found, we are good.
3581+ if (std::find (UniqueSections.begin (), UniqueSections.end (), TT.str ()) !=
3582+ UniqueSections.end ())
3583+ continue ;
3584+ // Didn't find any matches, return the full list for the diagnostic.
3585+ SmallString<128 > ArchListStr;
3586+ int Cnt = 0 ;
3587+ for (std::string Section : UniqueSections) {
3588+ if (Cnt)
3589+ ArchListStr += " , " ;
3590+ ArchListStr += Section;
3591+ Cnt++;
3592+ }
3593+ Diag (diag::warn_drv_sycl_target_missing) << SyclTarget << ArchListStr;
3594+ }
3595+ }
3596+
34593597// / Check whether the given input tree contains any clang-offload-dependency
34603598// / actions.
34613599static bool ContainsOffloadDepsAction (const Action *A) {
@@ -5350,7 +5488,6 @@ class OffloadingActionBuilder final {
53505488 } else
53515489 continue ;
53525490
5353- A->claim ();
53545491 auto ParsedArg = Opts.ParseOneArg (Args, Index);
53555492
53565493 // TODO: Support --no-cuda-gpu-arch, --{,no-}cuda-gpu-arch=all.
@@ -5380,6 +5517,7 @@ class OffloadingActionBuilder final {
53805517 }
53815518 ParsedArg->claim ();
53825519 GpuArchList.emplace_back (*TargetBE, ArchStr);
5520+ A->claim ();
53835521 }
53845522 }
53855523
0 commit comments