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