xref: /llvm-project/flang/lib/Frontend/CompilerInstance.cpp (revision d1d952c206efc3a651270c69331b180330ac3efc)
1257b2971SCaroline Concatto //===--- CompilerInstance.cpp ---------------------------------------------===//
2257b2971SCaroline Concatto //
3257b2971SCaroline Concatto // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4257b2971SCaroline Concatto // See https://llvm.org/LICENSE.txt for license information.
5257b2971SCaroline Concatto // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6257b2971SCaroline Concatto //
7257b2971SCaroline Concatto //===----------------------------------------------------------------------===//
81e462fafSAndrzej Warzynski //
91e462fafSAndrzej Warzynski // Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/
101e462fafSAndrzej Warzynski //
111e462fafSAndrzej Warzynski //===----------------------------------------------------------------------===//
12257b2971SCaroline Concatto 
13257b2971SCaroline Concatto #include "flang/Frontend/CompilerInstance.h"
146d48a1a5SFaris Rehman #include "flang/Common/Fortran-features.h"
15257b2971SCaroline Concatto #include "flang/Frontend/CompilerInvocation.h"
168d51d37eSAndrzej Warzynski #include "flang/Frontend/TextDiagnosticPrinter.h"
17d28de0d7SCaroline Concatto #include "flang/Parser/parsing.h"
184c5906cfSCaroline Concatto #include "flang/Parser/provenance.h"
197d246cb1SAndrzej Warzynski #include "flang/Semantics/semantics.h"
20*310c281bSmacurtis-amd #include "flang/Support/Timing.h"
21*310c281bSmacurtis-amd #include "mlir/Support/RawOstreamExtras.h"
22e59e8488SjeanPerier #include "clang/Basic/DiagnosticFrontend.h"
23e59e8488SjeanPerier #include "llvm/ADT/StringExtras.h"
24e59e8488SjeanPerier #include "llvm/MC/TargetRegistry.h"
25*310c281bSmacurtis-amd #include "llvm/Pass.h"
264c5906cfSCaroline Concatto #include "llvm/Support/Errc.h"
274c5906cfSCaroline Concatto #include "llvm/Support/Error.h"
284c5906cfSCaroline Concatto #include "llvm/Support/FileSystem.h"
294c5906cfSCaroline Concatto #include "llvm/Support/Path.h"
30257b2971SCaroline Concatto #include "llvm/Support/raw_ostream.h"
31e59e8488SjeanPerier #include "llvm/TargetParser/TargetParser.h"
3262c7f035SArchibald Elliott #include "llvm/TargetParser/Triple.h"
33257b2971SCaroline Concatto 
34257b2971SCaroline Concatto using namespace Fortran::frontend;
35257b2971SCaroline Concatto 
364c5906cfSCaroline Concatto CompilerInstance::CompilerInstance()
371e462fafSAndrzej Warzynski     : invocation(new CompilerInvocation()),
381e462fafSAndrzej Warzynski       allSources(new Fortran::parser::AllSources()),
391e462fafSAndrzej Warzynski       allCookedSources(new Fortran::parser::AllCookedSources(*allSources)),
401e462fafSAndrzej Warzynski       parsing(new Fortran::parser::Parsing(*allCookedSources)) {
41d28de0d7SCaroline Concatto   // TODO: This is a good default during development, but ultimately we should
42d28de0d7SCaroline Concatto   // give the user the opportunity to specify this.
431e462fafSAndrzej Warzynski   allSources->set_encoding(Fortran::parser::Encoding::UTF_8);
44d28de0d7SCaroline Concatto }
45257b2971SCaroline Concatto 
464c5906cfSCaroline Concatto CompilerInstance::~CompilerInstance() {
471e462fafSAndrzej Warzynski   assert(outputFiles.empty() && "Still output files in flight?");
484c5906cfSCaroline Concatto }
494c5906cfSCaroline Concatto 
501e462fafSAndrzej Warzynski void CompilerInstance::setInvocation(
514c5906cfSCaroline Concatto     std::shared_ptr<CompilerInvocation> value) {
521e462fafSAndrzej Warzynski   invocation = std::move(value);
534c5906cfSCaroline Concatto }
544c5906cfSCaroline Concatto 
551e462fafSAndrzej Warzynski void CompilerInstance::setSemaOutputStream(raw_ostream &value) {
561e462fafSAndrzej Warzynski   ownedSemaOutputStream.release();
571e462fafSAndrzej Warzynski   semaOutputStream = &value;
587d246cb1SAndrzej Warzynski }
597d246cb1SAndrzej Warzynski 
601e462fafSAndrzej Warzynski void CompilerInstance::setSemaOutputStream(std::unique_ptr<raw_ostream> value) {
611e462fafSAndrzej Warzynski   ownedSemaOutputStream.swap(value);
621e462fafSAndrzej Warzynski   semaOutputStream = ownedSemaOutputStream.get();
637d246cb1SAndrzej Warzynski }
647d246cb1SAndrzej Warzynski 
654c5906cfSCaroline Concatto // Helper method to generate the path of the output file. The following logic
664c5906cfSCaroline Concatto // applies:
674c5906cfSCaroline Concatto // 1. If the user specifies the output file via `-o`, then use that (i.e.
684c5906cfSCaroline Concatto //    the outputFilename parameter).
694c5906cfSCaroline Concatto // 2. If the user does not specify the name of the output file, derive it from
704c5906cfSCaroline Concatto //    the input file (i.e. inputFilename + extension)
714c5906cfSCaroline Concatto // 3. If the output file is not specified and the input file is `-`, then set
724c5906cfSCaroline Concatto //    the output file to `-` as well.
731e462fafSAndrzej Warzynski static std::string getOutputFilePath(llvm::StringRef outputFilename,
741e462fafSAndrzej Warzynski                                      llvm::StringRef inputFilename,
751e462fafSAndrzej Warzynski                                      llvm::StringRef extension) {
764c5906cfSCaroline Concatto 
774c5906cfSCaroline Concatto   // Output filename _is_ specified. Just use that.
784c5906cfSCaroline Concatto   if (!outputFilename.empty())
794c5906cfSCaroline Concatto     return std::string(outputFilename);
804c5906cfSCaroline Concatto 
814c5906cfSCaroline Concatto   // Output filename _is not_ specified. Derive it from the input file name.
824c5906cfSCaroline Concatto   std::string outFile = "-";
834c5906cfSCaroline Concatto   if (!extension.empty() && (inputFilename != "-")) {
844c5906cfSCaroline Concatto     llvm::SmallString<128> path(inputFilename);
854c5906cfSCaroline Concatto     llvm::sys::path::replace_extension(path, extension);
86f0346a58SKazu Hirata     outFile = std::string(path);
874c5906cfSCaroline Concatto   }
884c5906cfSCaroline Concatto 
894c5906cfSCaroline Concatto   return outFile;
904c5906cfSCaroline Concatto }
914c5906cfSCaroline Concatto 
924c5906cfSCaroline Concatto std::unique_ptr<llvm::raw_pwrite_stream>
931e462fafSAndrzej Warzynski CompilerInstance::createDefaultOutputFile(bool binary, llvm::StringRef baseName,
941e462fafSAndrzej Warzynski                                           llvm::StringRef extension) {
954c5906cfSCaroline Concatto 
964c5906cfSCaroline Concatto   // Get the path of the output file
974c5906cfSCaroline Concatto   std::string outputFilePath =
981e462fafSAndrzej Warzynski       getOutputFilePath(getFrontendOpts().outputFile, baseName, extension);
994c5906cfSCaroline Concatto 
1004c5906cfSCaroline Concatto   // Create the output file
101787c443aSAndrzej Warzynski   llvm::Expected<std::unique_ptr<llvm::raw_pwrite_stream>> os =
1021e462fafSAndrzej Warzynski       createOutputFileImpl(outputFilePath, binary);
1034c5906cfSCaroline Concatto 
104787c443aSAndrzej Warzynski   // If successful, add the file to the list of tracked output files and
105787c443aSAndrzej Warzynski   // return.
106787c443aSAndrzej Warzynski   if (os) {
1071e462fafSAndrzej Warzynski     outputFiles.emplace_back(OutputFile(outputFilePath));
108787c443aSAndrzej Warzynski     return std::move(*os);
1094c5906cfSCaroline Concatto   }
1104c5906cfSCaroline Concatto 
111787c443aSAndrzej Warzynski   // If unsuccessful, issue an error and return Null
1121e462fafSAndrzej Warzynski   unsigned diagID = getDiagnostics().getCustomDiagID(
113787c443aSAndrzej Warzynski       clang::DiagnosticsEngine::Error, "unable to open output file '%0': '%1'");
1141e462fafSAndrzej Warzynski   getDiagnostics().Report(diagID)
115787c443aSAndrzej Warzynski       << outputFilePath << llvm::errorToErrorCode(os.takeError()).message();
116316be03fSAndrzej Warzynski   return nullptr;
117316be03fSAndrzej Warzynski }
118fd21d1e1SAndrzej Warzynski 
119787c443aSAndrzej Warzynski llvm::Expected<std::unique_ptr<llvm::raw_pwrite_stream>>
1201e462fafSAndrzej Warzynski CompilerInstance::createOutputFileImpl(llvm::StringRef outputFilePath,
1211e462fafSAndrzej Warzynski                                        bool binary) {
122787c443aSAndrzej Warzynski 
123787c443aSAndrzej Warzynski   // Creates the file descriptor for the output file
124787c443aSAndrzej Warzynski   std::unique_ptr<llvm::raw_fd_ostream> os;
125787c443aSAndrzej Warzynski 
126787c443aSAndrzej Warzynski   std::error_code error;
12774d5c3c0SPeter Steinfeld   os.reset(new llvm::raw_fd_ostream(
12874d5c3c0SPeter Steinfeld       outputFilePath, error,
129787c443aSAndrzej Warzynski       (binary ? llvm::sys::fs::OF_None : llvm::sys::fs::OF_TextWithCRLF)));
130787c443aSAndrzej Warzynski   if (error) {
131787c443aSAndrzej Warzynski     return llvm::errorCodeToError(error);
132787c443aSAndrzej Warzynski   }
133787c443aSAndrzej Warzynski 
134787c443aSAndrzej Warzynski   // For seekable streams, just return the stream corresponding to the output
135787c443aSAndrzej Warzynski   // file.
1364c5906cfSCaroline Concatto   if (!binary || os->supportsSeeking())
1374c5906cfSCaroline Concatto     return std::move(os);
1384c5906cfSCaroline Concatto 
139787c443aSAndrzej Warzynski   // For non-seekable streams, we need to wrap the output stream into something
140787c443aSAndrzej Warzynski   // that supports 'pwrite' and takes care of the ownership for us.
141787c443aSAndrzej Warzynski   return std::make_unique<llvm::buffer_unique_ostream>(std::move(os));
1424c5906cfSCaroline Concatto }
1434c5906cfSCaroline Concatto 
1441e462fafSAndrzej Warzynski void CompilerInstance::clearOutputFiles(bool eraseFiles) {
1451e462fafSAndrzej Warzynski   for (OutputFile &of : outputFiles)
1461e462fafSAndrzej Warzynski     if (!of.filename.empty() && eraseFiles)
1471e462fafSAndrzej Warzynski       llvm::sys::fs::remove(of.filename);
1484c5906cfSCaroline Concatto 
1491e462fafSAndrzej Warzynski   outputFiles.clear();
1504c5906cfSCaroline Concatto }
1514c5906cfSCaroline Concatto 
1521e462fafSAndrzej Warzynski bool CompilerInstance::executeAction(FrontendAction &act) {
153*310c281bSmacurtis-amd   CompilerInvocation &invoc = this->getInvocation();
1544c5906cfSCaroline Concatto 
155686a951dSPeixin-Qiao   llvm::Triple targetTriple{llvm::Triple(invoc.getTargetOpts().triple)};
156686a951dSPeixin-Qiao 
157aba24c15SAndrzej Warzynski   // Set some sane defaults for the frontend.
1581e462fafSAndrzej Warzynski   invoc.setDefaultFortranOpts();
159aba24c15SAndrzej Warzynski   // Update the fortran options based on user-based input.
1601e462fafSAndrzej Warzynski   invoc.setFortranOpts();
16110826ea7SFaris Rehman   // Set the encoding to read all input files in based on user input.
1621e462fafSAndrzej Warzynski   allSources->set_encoding(invoc.getFortranOpts().encoding);
163e59e8488SjeanPerier   if (!setUpTargetMachine())
164e59e8488SjeanPerier     return false;
165ae4d7ac9SAndrzej Warzyński   // Create the semantics context
166e59e8488SjeanPerier   semaContext = invoc.getSemanticsCtx(*allCookedSources, getTargetMachine());
167f1eb945fSSlava Zakharin   // Set options controlling lowering to FIR.
168f1eb945fSSlava Zakharin   invoc.setLoweringOptions();
169aba24c15SAndrzej Warzynski 
170*310c281bSmacurtis-amd   if (invoc.getEnableTimers()) {
171*310c281bSmacurtis-amd     llvm::TimePassesIsEnabled = true;
172*310c281bSmacurtis-amd 
173*310c281bSmacurtis-amd     timingStreamMLIR = std::make_unique<Fortran::support::string_ostream>();
174*310c281bSmacurtis-amd     timingStreamLLVM = std::make_unique<Fortran::support::string_ostream>();
175*310c281bSmacurtis-amd     timingStreamCodeGen = std::make_unique<Fortran::support::string_ostream>();
176*310c281bSmacurtis-amd 
177*310c281bSmacurtis-amd     timingMgr.setEnabled(true);
178*310c281bSmacurtis-amd     timingMgr.setDisplayMode(mlir::DefaultTimingManager::DisplayMode::Tree);
179*310c281bSmacurtis-amd     timingMgr.setOutput(
180*310c281bSmacurtis-amd         Fortran::support::createTimingFormatterText(*timingStreamMLIR));
181*310c281bSmacurtis-amd 
182*310c281bSmacurtis-amd     // Creating a new TimingScope will automatically start the timer. Since this
183*310c281bSmacurtis-amd     // is the top-level timer, this is ok because it will end up capturing the
184*310c281bSmacurtis-amd     // time for all the bookkeeping and other tasks that take place between
185*310c281bSmacurtis-amd     // parsing, lowering etc. for which finer-grained timers will be created.
186*310c281bSmacurtis-amd     timingScopeRoot = timingMgr.getRootScope();
187*310c281bSmacurtis-amd   }
188*310c281bSmacurtis-amd 
189aba24c15SAndrzej Warzynski   // Run the frontend action `act` for every input file.
1901e462fafSAndrzej Warzynski   for (const FrontendInputFile &fif : getFrontendOpts().inputs) {
1911e462fafSAndrzej Warzynski     if (act.beginSourceFile(*this, fif)) {
1921e462fafSAndrzej Warzynski       if (llvm::Error err = act.execute()) {
1934c5906cfSCaroline Concatto         consumeError(std::move(err));
1944c5906cfSCaroline Concatto       }
1951e462fafSAndrzej Warzynski       act.endSourceFile();
1964c5906cfSCaroline Concatto     }
1974c5906cfSCaroline Concatto   }
198*310c281bSmacurtis-amd 
199*310c281bSmacurtis-amd   if (timingMgr.isEnabled()) {
200*310c281bSmacurtis-amd     timingScopeRoot.stop();
201*310c281bSmacurtis-amd 
202*310c281bSmacurtis-amd     // Write the timings to the associated output stream and clear all timers.
203*310c281bSmacurtis-amd     // We need to provide another stream because the TimingManager will attempt
204*310c281bSmacurtis-amd     // to print in its destructor even if it has been cleared. By the time that
205*310c281bSmacurtis-amd     // destructor runs, the output streams will have been destroyed, so give it
206*310c281bSmacurtis-amd     // a null stream.
207*310c281bSmacurtis-amd     timingMgr.print();
208*310c281bSmacurtis-amd     timingMgr.setOutput(
209*310c281bSmacurtis-amd         Fortran::support::createTimingFormatterText(mlir::thread_safe_nulls()));
210*310c281bSmacurtis-amd 
211*310c281bSmacurtis-amd     // This prints the timings in "reverse" order, starting from code
212*310c281bSmacurtis-amd     // generation, followed by LLVM-IR optimizations, then MLIR optimizations
213*310c281bSmacurtis-amd     // and transformations and the frontend. If any of the steps are disabled,
214*310c281bSmacurtis-amd     // for instance because code generation was not performed, the strings
215*310c281bSmacurtis-amd     // will be empty.
216*310c281bSmacurtis-amd     if (!timingStreamCodeGen->str().empty())
217*310c281bSmacurtis-amd       llvm::errs() << timingStreamCodeGen->str() << "\n";
218*310c281bSmacurtis-amd 
219*310c281bSmacurtis-amd     if (!timingStreamLLVM->str().empty())
220*310c281bSmacurtis-amd       llvm::errs() << timingStreamLLVM->str() << "\n";
221*310c281bSmacurtis-amd 
222*310c281bSmacurtis-amd     if (!timingStreamMLIR->str().empty())
223*310c281bSmacurtis-amd       llvm::errs() << timingStreamMLIR->str() << "\n";
224*310c281bSmacurtis-amd   }
225*310c281bSmacurtis-amd 
2261e462fafSAndrzej Warzynski   return !getDiagnostics().getClient()->getNumErrors();
2274c5906cfSCaroline Concatto }
228257b2971SCaroline Concatto 
2291e462fafSAndrzej Warzynski void CompilerInstance::createDiagnostics(clang::DiagnosticConsumer *client,
2301e462fafSAndrzej Warzynski                                          bool shouldOwnClient) {
2311e462fafSAndrzej Warzynski   diagnostics =
2321e462fafSAndrzej Warzynski       createDiagnostics(&getDiagnosticOpts(), client, shouldOwnClient);
233257b2971SCaroline Concatto }
234257b2971SCaroline Concatto 
235257b2971SCaroline Concatto clang::IntrusiveRefCntPtr<clang::DiagnosticsEngine>
2361e462fafSAndrzej Warzynski CompilerInstance::createDiagnostics(clang::DiagnosticOptions *opts,
2371e462fafSAndrzej Warzynski                                     clang::DiagnosticConsumer *client,
2381e462fafSAndrzej Warzynski                                     bool shouldOwnClient) {
239257b2971SCaroline Concatto   clang::IntrusiveRefCntPtr<clang::DiagnosticIDs> diagID(
240257b2971SCaroline Concatto       new clang::DiagnosticIDs());
241257b2971SCaroline Concatto   clang::IntrusiveRefCntPtr<clang::DiagnosticsEngine> diags(
242257b2971SCaroline Concatto       new clang::DiagnosticsEngine(diagID, opts));
243257b2971SCaroline Concatto 
244257b2971SCaroline Concatto   // Create the diagnostic client for reporting errors or for
245257b2971SCaroline Concatto   // implementing -verify.
246257b2971SCaroline Concatto   if (client) {
247257b2971SCaroline Concatto     diags->setClient(client, shouldOwnClient);
248257b2971SCaroline Concatto   } else {
2498d51d37eSAndrzej Warzynski     diags->setClient(new TextDiagnosticPrinter(llvm::errs(), opts));
250257b2971SCaroline Concatto   }
251257b2971SCaroline Concatto   return diags;
252257b2971SCaroline Concatto }
253e59e8488SjeanPerier 
254e59e8488SjeanPerier // Get feature string which represents combined explicit target features
255e59e8488SjeanPerier // for AMD GPU and the target features specified by the user
256e59e8488SjeanPerier static std::string
257e59e8488SjeanPerier getExplicitAndImplicitAMDGPUTargetFeatures(clang::DiagnosticsEngine &diags,
258e59e8488SjeanPerier                                            const TargetOptions &targetOpts,
259e59e8488SjeanPerier                                            const llvm::Triple triple) {
260e59e8488SjeanPerier   llvm::StringRef cpu = targetOpts.cpu;
261e59e8488SjeanPerier   llvm::StringMap<bool> implicitFeaturesMap;
262e59e8488SjeanPerier   // Get the set of implicit target features
263e59e8488SjeanPerier   llvm::AMDGPU::fillAMDGPUFeatureMap(cpu, triple, implicitFeaturesMap);
264e59e8488SjeanPerier 
265e59e8488SjeanPerier   // Add target features specified by the user
266e59e8488SjeanPerier   for (auto &userFeature : targetOpts.featuresAsWritten) {
267e59e8488SjeanPerier     std::string userKeyString = userFeature.substr(1);
268e59e8488SjeanPerier     implicitFeaturesMap[userKeyString] = (userFeature[0] == '+');
269e59e8488SjeanPerier   }
270e59e8488SjeanPerier 
2719739df2cSStanislav Mekhanoshin   auto HasError =
2729739df2cSStanislav Mekhanoshin       llvm::AMDGPU::insertWaveSizeFeature(cpu, triple, implicitFeaturesMap);
2739739df2cSStanislav Mekhanoshin   if (HasError.first) {
274e59e8488SjeanPerier     unsigned diagID = diags.getCustomDiagID(clang::DiagnosticsEngine::Error,
275e59e8488SjeanPerier                                             "Unsupported feature ID: %0");
2769739df2cSStanislav Mekhanoshin     diags.Report(diagID) << HasError.second;
277e59e8488SjeanPerier     return std::string();
278e59e8488SjeanPerier   }
279e59e8488SjeanPerier 
280e59e8488SjeanPerier   llvm::SmallVector<std::string> featuresVec;
281e59e8488SjeanPerier   for (auto &implicitFeatureItem : implicitFeaturesMap) {
282e59e8488SjeanPerier     featuresVec.push_back((llvm::Twine(implicitFeatureItem.second ? "+" : "-") +
283e59e8488SjeanPerier                            implicitFeatureItem.first().str())
284e59e8488SjeanPerier                               .str());
285e59e8488SjeanPerier   }
286e59e8488SjeanPerier   llvm::sort(featuresVec);
287e59e8488SjeanPerier   return llvm::join(featuresVec, ",");
288e59e8488SjeanPerier }
289e59e8488SjeanPerier 
290e59e8488SjeanPerier // Get feature string which represents combined explicit target features
291e59e8488SjeanPerier // for NVPTX and the target features specified by the user/
292e59e8488SjeanPerier // TODO: Have a more robust target conf like `clang/lib/Basic/Targets/NVPTX.cpp`
293e59e8488SjeanPerier static std::string
294e59e8488SjeanPerier getExplicitAndImplicitNVPTXTargetFeatures(clang::DiagnosticsEngine &diags,
295e59e8488SjeanPerier                                           const TargetOptions &targetOpts,
296e59e8488SjeanPerier                                           const llvm::Triple triple) {
297e59e8488SjeanPerier   llvm::StringRef cpu = targetOpts.cpu;
298e59e8488SjeanPerier   llvm::StringMap<bool> implicitFeaturesMap;
299e59e8488SjeanPerier   std::string errorMsg;
300e59e8488SjeanPerier   bool ptxVer = false;
301e59e8488SjeanPerier 
302e59e8488SjeanPerier   // Add target features specified by the user
303e59e8488SjeanPerier   for (auto &userFeature : targetOpts.featuresAsWritten) {
304e59e8488SjeanPerier     llvm::StringRef userKeyString(llvm::StringRef(userFeature).drop_front(1));
305e59e8488SjeanPerier     implicitFeaturesMap[userKeyString.str()] = (userFeature[0] == '+');
306e59e8488SjeanPerier     // Check if the user provided a PTX version
30711efcceaSKazu Hirata     if (userKeyString.starts_with("ptx"))
308e59e8488SjeanPerier       ptxVer = true;
309e59e8488SjeanPerier   }
310e59e8488SjeanPerier 
311e59e8488SjeanPerier   // Set the default PTX version to `ptx61` if none was provided.
312e59e8488SjeanPerier   // TODO: set the default PTX version based on the chip.
313e59e8488SjeanPerier   if (!ptxVer)
314e59e8488SjeanPerier     implicitFeaturesMap["ptx61"] = true;
315e59e8488SjeanPerier 
316e59e8488SjeanPerier   // Set the compute capability.
317e59e8488SjeanPerier   implicitFeaturesMap[cpu.str()] = true;
318e59e8488SjeanPerier 
319e59e8488SjeanPerier   llvm::SmallVector<std::string> featuresVec;
320e59e8488SjeanPerier   for (auto &implicitFeatureItem : implicitFeaturesMap) {
321e59e8488SjeanPerier     featuresVec.push_back((llvm::Twine(implicitFeatureItem.second ? "+" : "-") +
322e59e8488SjeanPerier                            implicitFeatureItem.first().str())
323e59e8488SjeanPerier                               .str());
324e59e8488SjeanPerier   }
325e59e8488SjeanPerier   llvm::sort(featuresVec);
326e59e8488SjeanPerier   return llvm::join(featuresVec, ",");
327e59e8488SjeanPerier }
328e59e8488SjeanPerier 
329e59e8488SjeanPerier std::string CompilerInstance::getTargetFeatures() {
330e59e8488SjeanPerier   const TargetOptions &targetOpts = getInvocation().getTargetOpts();
331e59e8488SjeanPerier   const llvm::Triple triple(targetOpts.triple);
332e59e8488SjeanPerier 
333e59e8488SjeanPerier   // Clang does not append all target features to the clang -cc1 invocation.
334e59e8488SjeanPerier   // Some target features are parsed implicitly by clang::TargetInfo child
335e59e8488SjeanPerier   // class. Clang::TargetInfo classes are the basic clang classes and
336e59e8488SjeanPerier   // they cannot be reused by Flang.
337e59e8488SjeanPerier   // That's why we need to extract implicit target features and add
338e59e8488SjeanPerier   // them to the target features specified by the user
339e59e8488SjeanPerier   if (triple.isAMDGPU()) {
340e59e8488SjeanPerier     return getExplicitAndImplicitAMDGPUTargetFeatures(getDiagnostics(),
341e59e8488SjeanPerier                                                       targetOpts, triple);
342e59e8488SjeanPerier   } else if (triple.isNVPTX()) {
343e59e8488SjeanPerier     return getExplicitAndImplicitNVPTXTargetFeatures(getDiagnostics(),
344e59e8488SjeanPerier                                                      targetOpts, triple);
345e59e8488SjeanPerier   }
346e59e8488SjeanPerier   return llvm::join(targetOpts.featuresAsWritten.begin(),
347e59e8488SjeanPerier                     targetOpts.featuresAsWritten.end(), ",");
348e59e8488SjeanPerier }
349e59e8488SjeanPerier 
350e59e8488SjeanPerier bool CompilerInstance::setUpTargetMachine() {
351e59e8488SjeanPerier   const TargetOptions &targetOpts = getInvocation().getTargetOpts();
352e59e8488SjeanPerier   const std::string &theTriple = targetOpts.triple;
353e59e8488SjeanPerier 
354e59e8488SjeanPerier   // Create `Target`
355e59e8488SjeanPerier   std::string error;
356e59e8488SjeanPerier   const llvm::Target *theTarget =
357e59e8488SjeanPerier       llvm::TargetRegistry::lookupTarget(theTriple, error);
358e59e8488SjeanPerier   if (!theTarget) {
359e59e8488SjeanPerier     getDiagnostics().Report(clang::diag::err_fe_unable_to_create_target)
360e59e8488SjeanPerier         << error;
361e59e8488SjeanPerier     return false;
362e59e8488SjeanPerier   }
363e59e8488SjeanPerier   // Create `TargetMachine`
364e59e8488SjeanPerier   const auto &CGOpts = getInvocation().getCodeGenOpts();
365e59e8488SjeanPerier   std::optional<llvm::CodeGenOptLevel> OptLevelOrNone =
366e59e8488SjeanPerier       llvm::CodeGenOpt::getLevel(CGOpts.OptimizationLevel);
367e59e8488SjeanPerier   assert(OptLevelOrNone && "Invalid optimization level!");
368e59e8488SjeanPerier   llvm::CodeGenOptLevel OptLevel = *OptLevelOrNone;
369e59e8488SjeanPerier   std::string featuresStr = getTargetFeatures();
3709e6b46a9SDavid Truby   std::optional<llvm::CodeModel::Model> cm = getCodeModel(CGOpts.CodeModel);
3718e14c6c1SKelvin Li 
3728e14c6c1SKelvin Li   llvm::TargetOptions tOpts = llvm::TargetOptions();
3738e14c6c1SKelvin Li   tOpts.EnableAIXExtendedAltivecABI = targetOpts.EnableAIXExtendedAltivecABI;
3748e14c6c1SKelvin Li 
375e59e8488SjeanPerier   targetMachine.reset(theTarget->createTargetMachine(
376e59e8488SjeanPerier       theTriple, /*CPU=*/targetOpts.cpu,
3778e14c6c1SKelvin Li       /*Features=*/featuresStr, /*Options=*/tOpts,
378e59e8488SjeanPerier       /*Reloc::Model=*/CGOpts.getRelocationModel(),
3799e6b46a9SDavid Truby       /*CodeModel::Model=*/cm, OptLevel));
380e59e8488SjeanPerier   assert(targetMachine && "Failed to create TargetMachine");
3819e6b46a9SDavid Truby   if (cm.has_value()) {
3829e6b46a9SDavid Truby     const llvm::Triple triple(theTriple);
3839e6b46a9SDavid Truby     if ((cm == llvm::CodeModel::Medium || cm == llvm::CodeModel::Large) &&
3849e6b46a9SDavid Truby         triple.getArch() == llvm::Triple::x86_64) {
3859e6b46a9SDavid Truby       targetMachine->setLargeDataThreshold(CGOpts.LargeDataThreshold);
3869e6b46a9SDavid Truby     }
3879e6b46a9SDavid Truby   }
388e59e8488SjeanPerier   return true;
389e59e8488SjeanPerier }
390