[flang-commits] [flang] e59e848 - [flang] Updating drivers to create data layout before semantics (#73301)
via flang-commits
flang-commits at lists.llvm.org
Wed Dec 6 05:20:11 PST 2023
Author: jeanPerier
Date: 2023-12-06T14:20:06+01:00
New Revision: e59e848805f57bd52ebbb0f7f7d4d951e6af597c
URL: https://github.com/llvm/llvm-project/commit/e59e848805f57bd52ebbb0f7f7d4d951e6af597c
DIFF: https://github.com/llvm/llvm-project/commit/e59e848805f57bd52ebbb0f7f7d4d951e6af597c.diff
LOG: [flang] Updating drivers to create data layout before semantics (#73301)
Preliminary patch to change lowering/code generation to use
llvm::DataLayout information instead of generating "sizeof" GEP (see
https://github.com/llvm/llvm-project/issues/71507).
Fortran Semantic analysis needs to know about the target type size and
alignment to deal with common blocks, and intrinsics like
C_SIZEOF/TRANSFER. This information should be obtained from the
llvm::DataLayout so that it is consistent during the whole compilation
flow.
This change is changing flang-new and bbc drivers to:
1. Create the llvm::TargetMachine so that the data layout of the target
can be obtained before semantics.
2. Sharing bbc/flang-new set-up of the
SemanticConstext.targetCharateristics from the llvm::TargetMachine. For
now, the actual part that set-up the Fortran type size and alignment
from the llvm::DataLayout is left TODO so that this change is mostly an
NFC impacting the drivers.
3. Let the lowering bridge set-up the mlir::Module datalayout attributes
since it is doing it for the target attribute, and that allows the llvm
data layout information to be available during lowering.
For flang-new, the changes are code shuffling: the `llvm::TargetMachine`
instance is moved to `CompilerInvocation` class so that it can be used
to set-up the semantic contexts. `setMLIRDataLayout` is moved to
`flang/Optimizer/Support/DataLayout.h` (it will need to be used from
codegen pass for fir-opt target independent testing.)), and the code
setting-up semantics targetCharacteristics is moved to
`Tools/TargetSetup.h` so that it can be shared with bbc.
As a consequence, LLVM targets must be registered when running
semantics, and it is not possible to run semantics for a target that is
not registered with the -triple option (hence the power pc specific
modules can only be built if the PowerPC target is available.
Added:
flang/include/flang/Optimizer/Support/DataLayout.h
flang/include/flang/Tools/TargetSetup.h
flang/lib/Optimizer/Support/DataLayout.cpp
flang/test/Fir/tco-default-datalayout.fir
flang/test/Fir/tco-explicit-datalayout.fir
flang/test/Lower/bbc-host-datalayout.f90
flang/test/Lower/bbc-target-datalayout.f90
Modified:
flang/include/flang/Frontend/CompilerInstance.h
flang/include/flang/Frontend/CompilerInvocation.h
flang/include/flang/Frontend/FrontendActions.h
flang/include/flang/Lower/Bridge.h
flang/lib/Frontend/CompilerInstance.cpp
flang/lib/Frontend/CompilerInvocation.cpp
flang/lib/Frontend/FrontendActions.cpp
flang/lib/Lower/Bridge.cpp
flang/lib/Optimizer/Support/CMakeLists.txt
flang/test/Semantics/realkinds-aarch64-01.f90
flang/tools/bbc/CMakeLists.txt
flang/tools/bbc/bbc.cpp
flang/tools/f18/CMakeLists.txt
flang/tools/tco/tco.cpp
flang/unittests/Frontend/FrontendActionTest.cpp
Removed:
################################################################################
diff --git a/flang/include/flang/Frontend/CompilerInstance.h b/flang/include/flang/Frontend/CompilerInstance.h
index 8ed416c2bbbf3..4fcc59f7cf577 100644
--- a/flang/include/flang/Frontend/CompilerInstance.h
+++ b/flang/include/flang/Frontend/CompilerInstance.h
@@ -21,6 +21,7 @@
#include "flang/Semantics/runtime-type-info.h"
#include "flang/Semantics/semantics.h"
#include "llvm/Support/raw_ostream.h"
+#include "llvm/Target/TargetMachine.h"
namespace Fortran::frontend {
@@ -57,6 +58,8 @@ class CompilerInstance {
std::unique_ptr<Fortran::semantics::SemanticsContext> semaContext;
+ std::unique_ptr<llvm::TargetMachine> targetMachine;
+
/// The stream for diagnostics from Semantics
llvm::raw_ostream *semaOutputStream = &llvm::errs();
@@ -231,6 +234,26 @@ class CompilerInstance {
createDefaultOutputFile(bool binary = true, llvm::StringRef baseInput = "",
llvm::StringRef extension = "");
+ /// {
+ /// @name Target Machine
+ /// {
+
+ /// Get the target machine.
+ const llvm::TargetMachine &getTargetMachine() const {
+ assert(targetMachine && "target machine was not set");
+ return *targetMachine;
+ }
+ llvm::TargetMachine &getTargetMachine() {
+ assert(targetMachine && "target machine was not set");
+ return *targetMachine;
+ }
+
+ /// Sets up LLVM's TargetMachine.
+ bool setUpTargetMachine();
+
+ /// Produces the string which represents target feature
+ std::string getTargetFeatures();
+
private:
/// Create a new output file
///
diff --git a/flang/include/flang/Frontend/CompilerInvocation.h b/flang/include/flang/Frontend/CompilerInvocation.h
index 6324bcdc1863c..4924d090eaf9c 100644
--- a/flang/include/flang/Frontend/CompilerInvocation.h
+++ b/flang/include/flang/Frontend/CompilerInvocation.h
@@ -26,6 +26,10 @@
#include "llvm/Option/ArgList.h"
#include <memory>
+namespace llvm {
+class TargetMachine;
+}
+
namespace Fortran::frontend {
/// Fill out Opts based on the options given in Args.
@@ -161,7 +165,8 @@ class CompilerInvocation : public CompilerInvocationBase {
/// Creates and configures semantics context based on the compilation flags.
std::unique_ptr<Fortran::semantics::SemanticsContext>
- getSemanticsCtx(Fortran::parser::AllCookedSources &allCookedSources);
+ getSemanticsCtx(Fortran::parser::AllCookedSources &allCookedSources,
+ const llvm::TargetMachine &);
std::string &getModuleDir() { return moduleDir; }
const std::string &getModuleDir() const { return moduleDir; }
diff --git a/flang/include/flang/Frontend/FrontendActions.h b/flang/include/flang/Frontend/FrontendActions.h
index 8272e0729ce3f..e2e859f3a81bd 100644
--- a/flang/include/flang/Frontend/FrontendActions.h
+++ b/flang/include/flang/Frontend/FrontendActions.h
@@ -21,7 +21,6 @@
#include "mlir/IR/BuiltinOps.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/IR/Module.h"
-#include "llvm/Target/TargetMachine.h"
#include <memory>
namespace Fortran::frontend {
@@ -204,8 +203,6 @@ class CodeGenAction : public FrontendAction {
void executeAction() override;
/// Runs prescan, parsing, sema and lowers to MLIR.
bool beginSourceFileAction() override;
- /// Sets up LLVM's TargetMachine.
- bool setUpTargetMachine();
/// Runs the optimization (aka middle-end) pipeline on the LLVM module
/// associated with this action.
void runOptimizationPipeline(llvm::raw_pwrite_stream &os);
@@ -234,7 +231,6 @@ class CodeGenAction : public FrontendAction {
BackendActionTy action;
- std::unique_ptr<llvm::TargetMachine> tm;
/// }
public:
~CodeGenAction() override;
diff --git a/flang/include/flang/Lower/Bridge.h b/flang/include/flang/Lower/Bridge.h
index d363068acfdbb..6c0d14d65edae 100644
--- a/flang/include/flang/Lower/Bridge.h
+++ b/flang/include/flang/Lower/Bridge.h
@@ -22,6 +22,10 @@
#include "flang/Optimizer/Dialect/Support/KindMapping.h"
#include "mlir/IR/BuiltinOps.h"
+namespace llvm {
+class DataLayout;
+} // namespace llvm
+
namespace Fortran {
namespace common {
class IntrinsicTypeDefaultKinds;
@@ -59,10 +63,12 @@ class LoweringBridge {
llvm::StringRef triple, fir::KindMapping &kindMap,
const Fortran::lower::LoweringOptions &loweringOptions,
const std::vector<Fortran::lower::EnvironmentDefault> &envDefaults,
- const Fortran::common::LanguageFeatureControl &languageFeatures) {
+ const Fortran::common::LanguageFeatureControl &languageFeatures,
+ const llvm::DataLayout *dataLayout = nullptr) {
return LoweringBridge(ctx, semanticsContext, defaultKinds, intrinsics,
targetCharacteristics, allCooked, triple, kindMap,
- loweringOptions, envDefaults, languageFeatures);
+ loweringOptions, envDefaults, languageFeatures,
+ dataLayout);
}
//===--------------------------------------------------------------------===//
@@ -140,7 +146,8 @@ class LoweringBridge {
fir::KindMapping &kindMap,
const Fortran::lower::LoweringOptions &loweringOptions,
const std::vector<Fortran::lower::EnvironmentDefault> &envDefaults,
- const Fortran::common::LanguageFeatureControl &languageFeatures);
+ const Fortran::common::LanguageFeatureControl &languageFeatures,
+ const llvm::DataLayout *dataLayout);
LoweringBridge() = delete;
LoweringBridge(const LoweringBridge &) = delete;
diff --git a/flang/include/flang/Optimizer/Support/DataLayout.h b/flang/include/flang/Optimizer/Support/DataLayout.h
new file mode 100644
index 0000000000000..88ff575a8ff08
--- /dev/null
+++ b/flang/include/flang/Optimizer/Support/DataLayout.h
@@ -0,0 +1,39 @@
+//===-- Optimizer/Support/DataLayout.h --------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef FORTRAN_OPTIMIZER_SUPPORT_DATALAYOUT_H
+#define FORTRAN_OPTIMIZER_SUPPORT_DATALAYOUT_H
+
+namespace mlir {
+class ModuleOp;
+}
+namespace llvm {
+class DataLayout;
+}
+
+namespace fir::support {
+/// Create an mlir::DataLayoutSpecInterface attribute from an llvm::DataLayout
+/// and set it on the provided mlir::ModuleOp.
+/// Also set the llvm.data_layout attribute with the string representation of
+/// the llvm::DataLayout on the module.
+/// These attributes are replaced if they were already set.
+void setMLIRDataLayout(mlir::ModuleOp mlirModule, const llvm::DataLayout &dl);
+
+/// Create an mlir::DataLayoutSpecInterface from the llvm.data_layout attribute
+/// if one is provided. If such attribute is not available, create a default
+/// target independent layout when allowDefaultLayout is true. Otherwise do
+/// nothing.
+void setMLIRDataLayoutFromAttributes(mlir::ModuleOp mlirModule,
+ bool allowDefaultLayout);
+} // namespace fir::support
+
+#endif // FORTRAN_OPTIMIZER_SUPPORT_DATALAYOUT_H
diff --git a/flang/include/flang/Tools/TargetSetup.h b/flang/include/flang/Tools/TargetSetup.h
new file mode 100644
index 0000000000000..238d66c9241dd
--- /dev/null
+++ b/flang/include/flang/Tools/TargetSetup.h
@@ -0,0 +1,40 @@
+//===-- Tools/TargetSetup.h ------------------------------------- *-C++-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef FORTRAN_TOOLS_TARGET_SETUP_H
+#define FORTRAN_TOOLS_TARGET_SETUP_H
+
+#include "flang/Evaluate/target.h"
+#include "llvm/Target/TargetMachine.h"
+
+namespace Fortran::tools {
+
+[[maybe_unused]] inline static void setUpTargetCharacteristics(
+ Fortran::evaluate::TargetCharacteristics &targetCharacteristics,
+ const llvm::TargetMachine &targetMachine,
+ const std::string &compilerVersion, const std::string &compilerOptions) {
+
+ const llvm::Triple &targetTriple{targetMachine.getTargetTriple()};
+ // FIXME: Handle real(3) ?
+ if (targetTriple.getArch() != llvm::Triple::ArchType::x86_64)
+ targetCharacteristics.DisableType(
+ Fortran::common::TypeCategory::Real, /*kind=*/10);
+
+ targetCharacteristics.set_compilerOptionsString(compilerOptions)
+ .set_compilerVersionString(compilerVersion);
+
+ if (targetTriple.isPPC())
+ targetCharacteristics.set_isPPC(true);
+
+ // TODO: use target machine data layout to set-up the target characteristics
+ // type size and alignment info.
+}
+
+} // namespace Fortran::tools
+
+#endif // FORTRAN_TOOLS_TARGET_SETUP_H
diff --git a/flang/lib/Frontend/CompilerInstance.cpp b/flang/lib/Frontend/CompilerInstance.cpp
index 328b3774bc291..a6b8f1a9d29ee 100644
--- a/flang/lib/Frontend/CompilerInstance.cpp
+++ b/flang/lib/Frontend/CompilerInstance.cpp
@@ -17,11 +17,15 @@
#include "flang/Parser/parsing.h"
#include "flang/Parser/provenance.h"
#include "flang/Semantics/semantics.h"
+#include "clang/Basic/DiagnosticFrontend.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/MC/TargetRegistry.h"
#include "llvm/Support/Errc.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
+#include "llvm/TargetParser/TargetParser.h"
#include "llvm/TargetParser/Triple.h"
using namespace Fortran::frontend;
@@ -156,8 +160,10 @@ bool CompilerInstance::executeAction(FrontendAction &act) {
invoc.setFortranOpts();
// Set the encoding to read all input files in based on user input.
allSources->set_encoding(invoc.getFortranOpts().encoding);
+ if (!setUpTargetMachine())
+ return false;
// Create the semantics context
- semaContext = invoc.getSemanticsCtx(*allCookedSources);
+ semaContext = invoc.getSemanticsCtx(*allCookedSources, getTargetMachine());
// Set options controlling lowering to FIR.
invoc.setLoweringOptions();
@@ -197,3 +203,129 @@ CompilerInstance::createDiagnostics(clang::DiagnosticOptions *opts,
}
return diags;
}
+
+// Get feature string which represents combined explicit target features
+// for AMD GPU and the target features specified by the user
+static std::string
+getExplicitAndImplicitAMDGPUTargetFeatures(clang::DiagnosticsEngine &diags,
+ const TargetOptions &targetOpts,
+ const llvm::Triple triple) {
+ llvm::StringRef cpu = targetOpts.cpu;
+ llvm::StringMap<bool> implicitFeaturesMap;
+ std::string errorMsg;
+ // Get the set of implicit target features
+ llvm::AMDGPU::fillAMDGPUFeatureMap(cpu, triple, implicitFeaturesMap);
+
+ // Add target features specified by the user
+ for (auto &userFeature : targetOpts.featuresAsWritten) {
+ std::string userKeyString = userFeature.substr(1);
+ implicitFeaturesMap[userKeyString] = (userFeature[0] == '+');
+ }
+
+ if (!llvm::AMDGPU::insertWaveSizeFeature(cpu, triple, implicitFeaturesMap,
+ errorMsg)) {
+ unsigned diagID = diags.getCustomDiagID(clang::DiagnosticsEngine::Error,
+ "Unsupported feature ID: %0");
+ diags.Report(diagID) << errorMsg.data();
+ return std::string();
+ }
+
+ llvm::SmallVector<std::string> featuresVec;
+ for (auto &implicitFeatureItem : implicitFeaturesMap) {
+ featuresVec.push_back((llvm::Twine(implicitFeatureItem.second ? "+" : "-") +
+ implicitFeatureItem.first().str())
+ .str());
+ }
+ llvm::sort(featuresVec);
+ return llvm::join(featuresVec, ",");
+}
+
+// Get feature string which represents combined explicit target features
+// for NVPTX and the target features specified by the user/
+// TODO: Have a more robust target conf like `clang/lib/Basic/Targets/NVPTX.cpp`
+static std::string
+getExplicitAndImplicitNVPTXTargetFeatures(clang::DiagnosticsEngine &diags,
+ const TargetOptions &targetOpts,
+ const llvm::Triple triple) {
+ llvm::StringRef cpu = targetOpts.cpu;
+ llvm::StringMap<bool> implicitFeaturesMap;
+ std::string errorMsg;
+ bool ptxVer = false;
+
+ // Add target features specified by the user
+ for (auto &userFeature : targetOpts.featuresAsWritten) {
+ llvm::StringRef userKeyString(llvm::StringRef(userFeature).drop_front(1));
+ implicitFeaturesMap[userKeyString.str()] = (userFeature[0] == '+');
+ // Check if the user provided a PTX version
+ if (userKeyString.startswith("ptx"))
+ ptxVer = true;
+ }
+
+ // Set the default PTX version to `ptx61` if none was provided.
+ // TODO: set the default PTX version based on the chip.
+ if (!ptxVer)
+ implicitFeaturesMap["ptx61"] = true;
+
+ // Set the compute capability.
+ implicitFeaturesMap[cpu.str()] = true;
+
+ llvm::SmallVector<std::string> featuresVec;
+ for (auto &implicitFeatureItem : implicitFeaturesMap) {
+ featuresVec.push_back((llvm::Twine(implicitFeatureItem.second ? "+" : "-") +
+ implicitFeatureItem.first().str())
+ .str());
+ }
+ llvm::sort(featuresVec);
+ return llvm::join(featuresVec, ",");
+}
+
+std::string CompilerInstance::getTargetFeatures() {
+ const TargetOptions &targetOpts = getInvocation().getTargetOpts();
+ const llvm::Triple triple(targetOpts.triple);
+
+ // Clang does not append all target features to the clang -cc1 invocation.
+ // Some target features are parsed implicitly by clang::TargetInfo child
+ // class. Clang::TargetInfo classes are the basic clang classes and
+ // they cannot be reused by Flang.
+ // That's why we need to extract implicit target features and add
+ // them to the target features specified by the user
+ if (triple.isAMDGPU()) {
+ return getExplicitAndImplicitAMDGPUTargetFeatures(getDiagnostics(),
+ targetOpts, triple);
+ } else if (triple.isNVPTX()) {
+ return getExplicitAndImplicitNVPTXTargetFeatures(getDiagnostics(),
+ targetOpts, triple);
+ }
+ return llvm::join(targetOpts.featuresAsWritten.begin(),
+ targetOpts.featuresAsWritten.end(), ",");
+}
+
+bool CompilerInstance::setUpTargetMachine() {
+ const TargetOptions &targetOpts = getInvocation().getTargetOpts();
+ const std::string &theTriple = targetOpts.triple;
+
+ // Create `Target`
+ std::string error;
+ const llvm::Target *theTarget =
+ llvm::TargetRegistry::lookupTarget(theTriple, error);
+ if (!theTarget) {
+ getDiagnostics().Report(clang::diag::err_fe_unable_to_create_target)
+ << error;
+ return false;
+ }
+
+ // Create `TargetMachine`
+ const auto &CGOpts = getInvocation().getCodeGenOpts();
+ std::optional<llvm::CodeGenOptLevel> OptLevelOrNone =
+ llvm::CodeGenOpt::getLevel(CGOpts.OptimizationLevel);
+ assert(OptLevelOrNone && "Invalid optimization level!");
+ llvm::CodeGenOptLevel OptLevel = *OptLevelOrNone;
+ std::string featuresStr = getTargetFeatures();
+ targetMachine.reset(theTarget->createTargetMachine(
+ theTriple, /*CPU=*/targetOpts.cpu,
+ /*Features=*/featuresStr, llvm::TargetOptions(),
+ /*Reloc::Model=*/CGOpts.getRelocationModel(),
+ /*CodeModel::Model=*/std::nullopt, OptLevel));
+ assert(targetMachine && "Failed to create TargetMachine");
+ return true;
+}
diff --git a/flang/lib/Frontend/CompilerInvocation.cpp b/flang/lib/Frontend/CompilerInvocation.cpp
index c623969a21e5e..b3f32bb241d06 100644
--- a/flang/lib/Frontend/CompilerInvocation.cpp
+++ b/flang/lib/Frontend/CompilerInvocation.cpp
@@ -18,6 +18,7 @@
#include "flang/Frontend/PreprocessorOptions.h"
#include "flang/Frontend/TargetOptions.h"
#include "flang/Semantics/semantics.h"
+#include "flang/Tools/TargetSetup.h"
#include "flang/Version.inc"
#include "clang/Basic/AllDiagnostics.h"
#include "clang/Basic/DiagnosticDriver.h"
@@ -1347,7 +1348,8 @@ void CompilerInvocation::setFortranOpts() {
std::unique_ptr<Fortran::semantics::SemanticsContext>
CompilerInvocation::getSemanticsCtx(
- Fortran::parser::AllCookedSources &allCookedSources) {
+ Fortran::parser::AllCookedSources &allCookedSources,
+ const llvm::TargetMachine &targetMachine) {
auto &fortranOptions = getFortranOpts();
auto semanticsContext = std::make_unique<semantics::SemanticsContext>(
@@ -1360,21 +1362,10 @@ CompilerInvocation::getSemanticsCtx(
.set_moduleFileSuffix(getModuleFileSuffix())
.set_underscoring(getCodeGenOpts().Underscoring);
- llvm::Triple targetTriple{llvm::Triple(this->targetOpts.triple)};
- // FIXME: Handle real(3) ?
- if (targetTriple.getArch() != llvm::Triple::ArchType::x86_64) {
- semanticsContext->targetCharacteristics().DisableType(
- Fortran::common::TypeCategory::Real, /*kind=*/10);
- }
-
- std::string version = Fortran::common::getFlangFullVersion();
- semanticsContext->targetCharacteristics()
- .set_compilerOptionsString(allCompilerInvocOpts)
- .set_compilerVersionString(version);
-
- if (targetTriple.isPPC())
- semanticsContext->targetCharacteristics().set_isPPC(true);
-
+ std::string compilerVersion = Fortran::common::getFlangFullVersion();
+ Fortran::tools::setUpTargetCharacteristics(
+ semanticsContext->targetCharacteristics(), targetMachine, compilerVersion,
+ allCompilerInvocOpts);
return semanticsContext;
}
diff --git a/flang/lib/Frontend/FrontendActions.cpp b/flang/lib/Frontend/FrontendActions.cpp
index 1be95cc27f42c..b114c552b552d 100644
--- a/flang/lib/Frontend/FrontendActions.cpp
+++ b/flang/lib/Frontend/FrontendActions.cpp
@@ -21,6 +21,7 @@
#include "flang/Lower/Support/Verifier.h"
#include "flang/Optimizer/Dialect/Support/FIRContext.h"
#include "flang/Optimizer/Dialect/Support/KindMapping.h"
+#include "flang/Optimizer/Support/DataLayout.h"
#include "flang/Optimizer/Support/InitFIR.h"
#include "flang/Optimizer/Support/Utils.h"
#include "flang/Optimizer/Transforms/Passes.h"
@@ -53,7 +54,6 @@
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/Verifier.h"
#include "llvm/IRReader/IRReader.h"
-#include "llvm/MC/TargetRegistry.h"
#include "llvm/Object/OffloadBinary.h"
#include "llvm/Passes/PassBuilder.h"
#include "llvm/Passes/PassPlugin.h"
@@ -65,7 +65,6 @@
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/ToolOutputFile.h"
#include "llvm/Target/TargetMachine.h"
-#include "llvm/TargetParser/TargetParser.h"
#include "llvm/Transforms/Utils/ModuleUtils.h"
#include <memory>
#include <system_error>
@@ -139,111 +138,6 @@ bool PrescanAndSemaDebugAction::beginSourceFileAction() {
(generateRtTypeTables() || true);
}
-// Get feature string which represents combined explicit target features
-// for AMD GPU and the target features specified by the user
-static std::string
-getExplicitAndImplicitAMDGPUTargetFeatures(CompilerInstance &ci,
- const TargetOptions &targetOpts,
- const llvm::Triple triple) {
- llvm::StringRef cpu = targetOpts.cpu;
- llvm::StringMap<bool> implicitFeaturesMap;
- std::string errorMsg;
- // Get the set of implicit target features
- llvm::AMDGPU::fillAMDGPUFeatureMap(cpu, triple, implicitFeaturesMap);
-
- // Add target features specified by the user
- for (auto &userFeature : targetOpts.featuresAsWritten) {
- std::string userKeyString = userFeature.substr(1);
- implicitFeaturesMap[userKeyString] = (userFeature[0] == '+');
- }
-
- if (!llvm::AMDGPU::insertWaveSizeFeature(cpu, triple, implicitFeaturesMap,
- errorMsg)) {
- unsigned diagID = ci.getDiagnostics().getCustomDiagID(
- clang::DiagnosticsEngine::Error, "Unsupported feature ID: %0");
- ci.getDiagnostics().Report(diagID) << errorMsg.data();
- return std::string();
- }
-
- llvm::SmallVector<std::string> featuresVec;
- for (auto &implicitFeatureItem : implicitFeaturesMap) {
- featuresVec.push_back((llvm::Twine(implicitFeatureItem.second ? "+" : "-") +
- implicitFeatureItem.first().str())
- .str());
- }
- llvm::sort(featuresVec);
- return llvm::join(featuresVec, ",");
-}
-
-// Get feature string which represents combined explicit target features
-// for NVPTX and the target features specified by the user/
-// TODO: Have a more robust target conf like `clang/lib/Basic/Targets/NVPTX.cpp`
-static std::string
-getExplicitAndImplicitNVPTXTargetFeatures(CompilerInstance &ci,
- const TargetOptions &targetOpts,
- const llvm::Triple triple) {
- llvm::StringRef cpu = targetOpts.cpu;
- llvm::StringMap<bool> implicitFeaturesMap;
- std::string errorMsg;
- bool ptxVer = false;
-
- // Add target features specified by the user
- for (auto &userFeature : targetOpts.featuresAsWritten) {
- llvm::StringRef userKeyString(llvm::StringRef(userFeature).drop_front(1));
- implicitFeaturesMap[userKeyString.str()] = (userFeature[0] == '+');
- // Check if the user provided a PTX version
- if (userKeyString.startswith("ptx"))
- ptxVer = true;
- }
-
- // Set the default PTX version to `ptx61` if none was provided.
- // TODO: set the default PTX version based on the chip.
- if (!ptxVer)
- implicitFeaturesMap["ptx61"] = true;
-
- // Set the compute capability.
- implicitFeaturesMap[cpu.str()] = true;
-
- llvm::SmallVector<std::string> featuresVec;
- for (auto &implicitFeatureItem : implicitFeaturesMap) {
- featuresVec.push_back((llvm::Twine(implicitFeatureItem.second ? "+" : "-") +
- implicitFeatureItem.first().str())
- .str());
- }
- llvm::sort(featuresVec);
- return llvm::join(featuresVec, ",");
-}
-
-// Produces the string which represents target feature
-static std::string getTargetFeatures(CompilerInstance &ci) {
- const TargetOptions &targetOpts = ci.getInvocation().getTargetOpts();
- const llvm::Triple triple(targetOpts.triple);
-
- // Clang does not append all target features to the clang -cc1 invocation.
- // Some target features are parsed implicitly by clang::TargetInfo child
- // class. Clang::TargetInfo classes are the basic clang classes and
- // they cannot be reused by Flang.
- // That's why we need to extract implicit target features and add
- // them to the target features specified by the user
- if (triple.isAMDGPU()) {
- return getExplicitAndImplicitAMDGPUTargetFeatures(ci, targetOpts, triple);
- } else if (triple.isNVPTX()) {
- return getExplicitAndImplicitNVPTXTargetFeatures(ci, targetOpts, triple);
- }
- return llvm::join(targetOpts.featuresAsWritten.begin(),
- targetOpts.featuresAsWritten.end(), ",");
-}
-
-static void setMLIRDataLayout(mlir::ModuleOp &mlirModule,
- const llvm::DataLayout &dl) {
- mlir::MLIRContext *context = mlirModule.getContext();
- mlirModule->setAttr(
- mlir::LLVM::LLVMDialect::getDataLayoutAttrName(),
- mlir::StringAttr::get(context, dl.getStringRepresentation()));
- mlir::DataLayoutSpecInterface dlSpec = mlir::translateDataLayout(dl, context);
- mlirModule->setAttr(mlir::DLTIDialect::kDataLayoutAttrName, dlSpec);
-}
-
static void addDependentLibs(mlir::ModuleOp &mlirModule, CompilerInstance &ci) {
const std::vector<std::string> &libs =
ci.getInvocation().getCodeGenOpts().DependentLibs;
@@ -352,6 +246,8 @@ bool CodeGenAction::beginSourceFileAction() {
fir::support::loadDialects(*mlirCtx);
fir::support::registerLLVMTranslation(*mlirCtx);
+ const llvm::TargetMachine &targetMachine = ci.getTargetMachine();
+
// If the input is an MLIR file, just parse it and return.
if (this->getCurrentInput().getKind().getLanguage() == Language::MLIR) {
llvm::SourceMgr sourceMgr;
@@ -369,10 +265,8 @@ bool CodeGenAction::beginSourceFileAction() {
}
mlirModule = std::make_unique<mlir::ModuleOp>(module.release());
- if (!setUpTargetMachine())
- return false;
- const llvm::DataLayout &dl = tm->createDataLayout();
- setMLIRDataLayout(*mlirModule, dl);
+ const llvm::DataLayout &dl = targetMachine.createDataLayout();
+ fir::support::setMLIRDataLayout(*mlirModule, dl);
return true;
}
@@ -394,6 +288,8 @@ bool CodeGenAction::beginSourceFileAction() {
ci.getSemanticsContext().defaultKinds();
fir::KindMapping kindMap(mlirCtx.get(), llvm::ArrayRef<fir::KindTy>{
fir::fromDefaultKinds(defKinds)});
+ const llvm::DataLayout &dl = targetMachine.createDataLayout();
+
lower::LoweringBridge lb = Fortran::lower::LoweringBridge::create(
*mlirCtx, ci.getSemanticsContext(), defKinds,
ci.getSemanticsContext().intrinsics(),
@@ -401,27 +297,22 @@ bool CodeGenAction::beginSourceFileAction() {
ci.getParsing().allCooked(), ci.getInvocation().getTargetOpts().triple,
kindMap, ci.getInvocation().getLoweringOpts(),
ci.getInvocation().getFrontendOpts().envDefaults,
- ci.getInvocation().getFrontendOpts().features);
+ ci.getInvocation().getFrontendOpts().features, &dl);
// Fetch module from lb, so we can set
mlirModule = std::make_unique<mlir::ModuleOp>(lb.getModule());
- if (!setUpTargetMachine())
- return false;
-
if (ci.getInvocation().getFrontendOpts().features.IsEnabled(
Fortran::common::LanguageFeature::OpenMP)) {
setOffloadModuleInterfaceAttributes(*mlirModule,
ci.getInvocation().getLangOpts());
- setOffloadModuleInterfaceTargetAttribute(*mlirModule, tm->getTargetCPU(),
- tm->getTargetFeatureString());
+ setOffloadModuleInterfaceTargetAttribute(
+ *mlirModule, targetMachine.getTargetCPU(),
+ targetMachine.getTargetFeatureString());
setOpenMPVersionAttribute(*mlirModule,
ci.getInvocation().getLangOpts().OpenMPVersion);
}
- const llvm::DataLayout &dl = tm->createDataLayout();
- setMLIRDataLayout(*mlirModule, dl);
-
// Create a parse tree and lower it to FIR
Fortran::parser::Program &parseTree{*ci.getParsing().parseTree()};
lb.lower(parseTree, ci.getSemanticsContext());
@@ -830,7 +721,7 @@ getVScaleRange(CompilerInstance &ci,
return std::pair<unsigned, unsigned>(
langOpts.VScaleMin ? langOpts.VScaleMin : 1, langOpts.VScaleMax);
- std::string featuresStr = getTargetFeatures(ci);
+ std::string featuresStr = ci.getTargetFeatures();
if (featuresStr.find("+sve") != std::string::npos)
return std::pair<unsigned, unsigned>(1, 16);
@@ -911,38 +802,6 @@ void CodeGenAction::generateLLVMIR() {
}
}
-bool CodeGenAction::setUpTargetMachine() {
- CompilerInstance &ci = this->getInstance();
-
- const TargetOptions &targetOpts = ci.getInvocation().getTargetOpts();
- const std::string &theTriple = targetOpts.triple;
-
- // Create `Target`
- std::string error;
- const llvm::Target *theTarget =
- llvm::TargetRegistry::lookupTarget(theTriple, error);
- if (!theTarget) {
- ci.getDiagnostics().Report(clang::diag::err_fe_unable_to_create_target)
- << error;
- return false;
- }
-
- // Create `TargetMachine`
- const auto &CGOpts = ci.getInvocation().getCodeGenOpts();
- std::optional<llvm::CodeGenOptLevel> OptLevelOrNone =
- llvm::CodeGenOpt::getLevel(CGOpts.OptimizationLevel);
- assert(OptLevelOrNone && "Invalid optimization level!");
- llvm::CodeGenOptLevel OptLevel = *OptLevelOrNone;
- std::string featuresStr = getTargetFeatures(ci);
- tm.reset(theTarget->createTargetMachine(
- theTriple, /*CPU=*/targetOpts.cpu,
- /*Features=*/featuresStr, llvm::TargetOptions(),
- /*Reloc::Model=*/CGOpts.getRelocationModel(),
- /*CodeModel::Model=*/std::nullopt, OptLevel));
- assert(tm && "Failed to create TargetMachine");
- return true;
-}
-
static std::unique_ptr<llvm::raw_pwrite_stream>
getOutputStream(CompilerInstance &ci, llvm::StringRef inFile,
BackendActionTy action) {
@@ -1020,6 +879,7 @@ void CodeGenAction::runOptimizationPipeline(llvm::raw_pwrite_stream &os) {
auto &diags = getInstance().getDiagnostics();
llvm::OptimizationLevel level = mapToLevel(opts);
+ llvm::TargetMachine *targetMachine = &getInstance().getTargetMachine();
// Create the analysis managers.
llvm::LoopAnalysisManager lam;
llvm::FunctionAnalysisManager fam;
@@ -1033,7 +893,7 @@ void CodeGenAction::runOptimizationPipeline(llvm::raw_pwrite_stream &os) {
llvm::StandardInstrumentations si(llvmModule->getContext(),
opts.DebugPassManager);
si.registerCallbacks(pic, &mam);
- llvm::PassBuilder pb(tm.get(), pto, pgoOpt, &pic);
+ llvm::PassBuilder pb(targetMachine, pto, pgoOpt, &pic);
// Attempt to load pass plugins and register their callbacks with PB.
for (auto &pluginFile : opts.LLVMPassPlugins) {
@@ -1299,9 +1159,8 @@ void CodeGenAction::executeAction() {
// Set the triple based on the targetmachine (this comes compiler invocation
// and the command-line target option if specified, or the default if not
// given on the command-line).
- if (!setUpTargetMachine())
- return;
- const std::string &theTriple = tm->getTargetTriple().str();
+ llvm::TargetMachine &targetMachine = ci.getTargetMachine();
+ const std::string &theTriple = targetMachine.getTargetTriple().str();
if (llvmModule->getTargetTriple() != theTriple) {
diags.Report(clang::diag::warn_fe_override_module) << theTriple;
@@ -1311,7 +1170,7 @@ void CodeGenAction::executeAction() {
// Note that this overwrites any datalayout stored in the LLVM-IR. This avoids
// an assert for incompatible data layout when the code-generation happens.
llvmModule->setTargetTriple(theTriple);
- llvmModule->setDataLayout(tm->createDataLayout());
+ llvmModule->setDataLayout(targetMachine.createDataLayout());
// Embed offload objects specified with -fembed-offload-object
if (!codeGenOpts.OffloadObjects.empty())
@@ -1361,7 +1220,7 @@ void CodeGenAction::executeAction() {
if (action == BackendActionTy::Backend_EmitAssembly ||
action == BackendActionTy::Backend_EmitObj) {
generateMachineCodeOrAssemblyImpl(
- diags, *tm, action, *llvmModule, codeGenOpts,
+ diags, targetMachine, action, *llvmModule, codeGenOpts,
ci.isOutputStreamNull() ? *os : ci.getOutputStream());
return;
}
diff --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp
index 1258e3b3ad425..7e64adc3c144c 100644
--- a/flang/lib/Lower/Bridge.cpp
+++ b/flang/lib/Lower/Bridge.cpp
@@ -44,6 +44,7 @@
#include "flang/Optimizer/Dialect/FIROps.h"
#include "flang/Optimizer/Dialect/Support/FIRContext.h"
#include "flang/Optimizer/HLFIR/HLFIROps.h"
+#include "flang/Optimizer/Support/DataLayout.h"
#include "flang/Optimizer/Support/FatalError.h"
#include "flang/Optimizer/Support/InternalNames.h"
#include "flang/Optimizer/Transforms/Passes.h"
@@ -5089,7 +5090,8 @@ Fortran::lower::LoweringBridge::LoweringBridge(
fir::KindMapping &kindMap,
const Fortran::lower::LoweringOptions &loweringOptions,
const std::vector<Fortran::lower::EnvironmentDefault> &envDefaults,
- const Fortran::common::LanguageFeatureControl &languageFeatures)
+ const Fortran::common::LanguageFeatureControl &languageFeatures,
+ const llvm::DataLayout *dataLayout)
: semanticsContext{semanticsContext}, defaultKinds{defaultKinds},
intrinsics{intrinsics}, targetCharacteristics{targetCharacteristics},
cooked{&cooked}, context{context}, kindMap{kindMap},
@@ -5145,4 +5147,6 @@ Fortran::lower::LoweringBridge::LoweringBridge(
assert(module.get() && "module was not created");
fir::setTargetTriple(*module.get(), triple);
fir::setKindMapping(*module.get(), kindMap);
+ if (dataLayout)
+ fir::support::setMLIRDataLayout(*module.get(), *dataLayout);
}
diff --git a/flang/lib/Optimizer/Support/CMakeLists.txt b/flang/lib/Optimizer/Support/CMakeLists.txt
index 2d03bc52c83f0..55f5718a90b85 100644
--- a/flang/lib/Optimizer/Support/CMakeLists.txt
+++ b/flang/lib/Optimizer/Support/CMakeLists.txt
@@ -2,6 +2,7 @@ get_property(dialect_libs GLOBAL PROPERTY MLIR_DIALECT_LIBS)
get_property(extension_libs GLOBAL PROPERTY MLIR_EXTENSION_LIBS)
add_flang_library(FIRSupport
+ DataLayout.cpp
InitFIR.cpp
InternalNames.cpp
@@ -20,6 +21,7 @@ add_flang_library(FIRSupport
MLIROpenMPToLLVMIRTranslation
MLIRLLVMToLLVMIRTranslation
MLIRTargetLLVMIRExport
+ MLIRTargetLLVMIRImport
LINK_COMPONENTS
TargetParser
diff --git a/flang/lib/Optimizer/Support/DataLayout.cpp b/flang/lib/Optimizer/Support/DataLayout.cpp
new file mode 100644
index 0000000000000..5cd9c01e8ce00
--- /dev/null
+++ b/flang/lib/Optimizer/Support/DataLayout.cpp
@@ -0,0 +1,47 @@
+//===-- Optimizer/Support/DataLayout.cpp ----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "flang/Optimizer/Support/DataLayout.h"
+#include "flang/Optimizer/Dialect/Support/FIRContext.h"
+#include "flang/Optimizer/Support/FatalError.h"
+#include "mlir/Dialect/DLTI/DLTI.h"
+#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
+#include "mlir/IR/BuiltinOps.h"
+#include "mlir/Interfaces/DataLayoutInterfaces.h"
+#include "mlir/Support/LLVM.h"
+#include "mlir/Target/LLVMIR/Import.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/MC/TargetRegistry.h"
+#include "llvm/Support/TargetSelect.h"
+#include "llvm/Target/TargetMachine.h"
+
+void fir::support::setMLIRDataLayout(mlir::ModuleOp mlirModule,
+ const llvm::DataLayout &dl) {
+ mlir::MLIRContext *context = mlirModule.getContext();
+ mlirModule->setAttr(
+ mlir::LLVM::LLVMDialect::getDataLayoutAttrName(),
+ mlir::StringAttr::get(context, dl.getStringRepresentation()));
+ mlir::DataLayoutSpecInterface dlSpec = mlir::translateDataLayout(dl, context);
+ mlirModule->setAttr(mlir::DLTIDialect::kDataLayoutAttrName, dlSpec);
+}
+
+void fir::support::setMLIRDataLayoutFromAttributes(mlir::ModuleOp mlirModule,
+ bool allowDefaultLayout) {
+ if (mlirModule.getDataLayoutSpec())
+ return; // Already set.
+ if (auto dataLayoutString = mlirModule->getAttrOfType<mlir::StringAttr>(
+ mlir::LLVM::LLVMDialect::getDataLayoutAttrName())) {
+ llvm::DataLayout llvmDataLayout(dataLayoutString);
+ fir::support::setMLIRDataLayout(mlirModule, llvmDataLayout);
+ return;
+ }
+ if (!allowDefaultLayout)
+ return;
+ llvm::DataLayout llvmDataLayout("");
+ fir::support::setMLIRDataLayout(mlirModule, llvmDataLayout);
+}
diff --git a/flang/test/Fir/tco-default-datalayout.fir b/flang/test/Fir/tco-default-datalayout.fir
new file mode 100644
index 0000000000000..0741e820a8d19
--- /dev/null
+++ b/flang/test/Fir/tco-default-datalayout.fir
@@ -0,0 +1,12 @@
+// Test that tco tool sets a target independent data layout when none is
+// provided. LLVM default data layout aligns i64 with 32 bits.
+// RUN: tco -emit-fir %s | FileCheck %s
+
+module {
+}
+// CHECK: module attributes {
+// CHECK-SAME: dlti.dl_spec = #dlti.dl_spec<
+// ...
+// CHECK-SAME: #dlti.dl_entry<i64, dense<[32, 64]> : vector<2xi64>>,
+// ...
+// CHECK-SAME: llvm.data_layout = ""
diff --git a/flang/test/Fir/tco-explicit-datalayout.fir b/flang/test/Fir/tco-explicit-datalayout.fir
new file mode 100644
index 0000000000000..50d8d835a602f
--- /dev/null
+++ b/flang/test/Fir/tco-explicit-datalayout.fir
@@ -0,0 +1,13 @@
+// Test that tco tool preserves incoming llvm.data_layout and creates a
+// related dlti.dl_spec attribute. This tests a weird datalayout where
+// i64 would be 128 bit aligned.
+// RUN: tco -emit-fir %s | FileCheck %s
+
+module attributes {llvm.data_layout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:128-i128:128-f80:128-n8:16:32:64-S128"} {
+}
+// CHECK: module attributes {
+// CHECK-SAME: dlti.dl_spec = #dlti.dl_spec<
+// ...
+// CHECK-SAME: #dlti.dl_entry<i64, dense<128> : vector<2xi64>>,
+// ...
+// CHECK-SAME: llvm.data_layout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:128-i128:128-f80:128-n8:16:32:64-S128"
diff --git a/flang/test/Lower/bbc-host-datalayout.f90 b/flang/test/Lower/bbc-host-datalayout.f90
new file mode 100644
index 0000000000000..1795022e3bf7f
--- /dev/null
+++ b/flang/test/Lower/bbc-host-datalayout.f90
@@ -0,0 +1,9 @@
+! Test bbc set-up of the target data layout from the host.
+! RUN: bbc %s -o - | FileCheck %s
+subroutine test
+end subroutine
+
+! CHECK: module attributes {
+! CHECK-SAME: dlti.dl_spec = #dlti.dl_spec<
+! CHECK-SAME: llvm.data_layout = "{{[^"]}}
+! CHECK-SAME: llvm.target_triple = "{{[^"]}}
diff --git a/flang/test/Lower/bbc-target-datalayout.f90 b/flang/test/Lower/bbc-target-datalayout.f90
new file mode 100644
index 0000000000000..adc1ee77bdfba
--- /dev/null
+++ b/flang/test/Lower/bbc-target-datalayout.f90
@@ -0,0 +1,10 @@
+! Test bbc target override.
+! REQUIRES: x86-registered-target
+! RUN: bbc %s -target x86_64-unknown-linux-gnu -o - | FileCheck %s
+subroutine test
+end subroutine
+
+! CHECK: module attributes {
+! CHECK-SAME: dlti.dl_spec = #dlti.dl_spec<
+! CHECK-SAME: llvm.data_layout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
+! CHECK-SAME: llvm.target_triple = "x86_64-unknown-linux-gnu"
diff --git a/flang/test/Semantics/realkinds-aarch64-01.f90 b/flang/test/Semantics/realkinds-aarch64-01.f90
index c316e25103243..e22920ff991e9 100644
--- a/flang/test/Semantics/realkinds-aarch64-01.f90
+++ b/flang/test/Semantics/realkinds-aarch64-01.f90
@@ -1,3 +1,4 @@
+! REQUIRES: aarch64-registered-target
! RUN: %python %S/test_modfile.py %s %flang_fc1 -triple aarch64-unknown-linux-gnu
module m1
diff --git a/flang/tools/bbc/CMakeLists.txt b/flang/tools/bbc/CMakeLists.txt
index cbae4ecd56c96..f21fa3b7bae35 100644
--- a/flang/tools/bbc/CMakeLists.txt
+++ b/flang/tools/bbc/CMakeLists.txt
@@ -1,5 +1,8 @@
set(LLVM_LINK_COMPONENTS
Passes
+AllTargetsCodeGens
+AllTargetsDescs
+AllTargetsInfos
TargetParser
)
diff --git a/flang/tools/bbc/bbc.cpp b/flang/tools/bbc/bbc.cpp
index 0c35d5c8438c1..0122cf33b0b67 100644
--- a/flang/tools/bbc/bbc.cpp
+++ b/flang/tools/bbc/bbc.cpp
@@ -16,6 +16,7 @@
#include "flang/Common/Fortran-features.h"
#include "flang/Common/OpenMP-features.h"
+#include "flang/Common/Version.h"
#include "flang/Common/default-kinds.h"
#include "flang/Lower/Bridge.h"
#include "flang/Lower/PFTBuilder.h"
@@ -39,6 +40,7 @@
#include "flang/Semantics/semantics.h"
#include "flang/Semantics/unparse-with-symbols.h"
#include "flang/Tools/CrossToolHelpers.h"
+#include "flang/Tools/TargetSetup.h"
#include "flang/Version.inc"
#include "mlir/Dialect/OpenMP/OpenMPDialect.h"
#include "mlir/IR/AsmState.h"
@@ -50,6 +52,7 @@
#include "mlir/Pass/PassRegistry.h"
#include "mlir/Transforms/GreedyPatternRewriteDriver.h"
#include "mlir/Transforms/Passes.h"
+#include "llvm/MC/TargetRegistry.h"
#include "llvm/Passes/OptimizationLevel.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/ErrorOr.h"
@@ -63,6 +66,7 @@
#include "llvm/Support/raw_ostream.h"
#include "llvm/TargetParser/Host.h"
#include "llvm/TargetParser/Triple.h"
+#include <memory>
//===----------------------------------------------------------------------===//
// Some basic command-line options
@@ -202,6 +206,10 @@ static llvm::cl::opt<bool> enableCUDA("fcuda",
static llvm::cl::opt<bool> fixedForm("ffixed-form",
llvm::cl::desc("enable fixed form"),
llvm::cl::init(false));
+static llvm::cl::opt<std::string>
+ targetTripleOverride("target",
+ llvm::cl::desc("Override host target triple"),
+ llvm::cl::init(""));
#define FLANG_EXCLUDE_CODEGEN
#include "flang/Tools/CLOptions.inc"
@@ -221,6 +229,27 @@ static void registerAllPasses() {
fir::registerOptTransformPasses();
}
+/// Create a target machine that is at least sufficient to get data-layout
+/// information required by flang semantics and lowering. Note that it may not
+/// contain all the CPU feature information to get optimized assembly generation
+/// from LLVM IR. Drivers that needs to generate assembly from LLVM IR should
+/// create a target machine according to their specific options.
+static std::unique_ptr<llvm::TargetMachine>
+createTargetMachine(llvm::StringRef targetTriple, std::string &error) {
+ std::string triple{targetTriple};
+ if (triple.empty())
+ triple = llvm::sys::getDefaultTargetTriple();
+
+ const llvm::Target *theTarget =
+ llvm::TargetRegistry::lookupTarget(triple, error);
+ if (!theTarget)
+ return nullptr;
+ return std::unique_ptr<llvm::TargetMachine>{
+ theTarget->createTargetMachine(triple, /*CPU=*/"",
+ /*Features=*/"", llvm::TargetOptions(),
+ /*Reloc::Model=*/std::nullopt)};
+}
+
//===----------------------------------------------------------------------===//
// Translate Fortran input to FIR, a dialect of MLIR.
//===----------------------------------------------------------------------===//
@@ -229,7 +258,8 @@ static mlir::LogicalResult convertFortranSourceToMLIR(
std::string path, Fortran::parser::Options options,
const ProgramName &programPrefix,
Fortran::semantics::SemanticsContext &semanticsContext,
- const mlir::PassPipelineCLParser &passPipeline) {
+ const mlir::PassPipelineCLParser &passPipeline,
+ const llvm::TargetMachine &targetMachine) {
// prep for prescan and parse
Fortran::parser::Parsing parsing{semanticsContext.allCookedSources()};
@@ -295,6 +325,8 @@ static mlir::LogicalResult convertFortranSourceToMLIR(
auto &defKinds = semanticsContext.defaultKinds();
fir::KindMapping kindMap(
&ctx, llvm::ArrayRef<fir::KindTy>{fir::fromDefaultKinds(defKinds)});
+ const llvm::DataLayout &dataLayout = targetMachine.createDataLayout();
+ std::string targetTriple = targetMachine.getTargetTriple().normalize();
// Use default lowering options for bbc.
Fortran::lower::LoweringOptions loweringOptions{};
loweringOptions.setPolymorphicTypeImpl(enablePolymorphic);
@@ -302,8 +334,9 @@ static mlir::LogicalResult convertFortranSourceToMLIR(
loweringOptions.setLowerToHighLevelFIR(useHLFIR || emitHLFIR);
auto burnside = Fortran::lower::LoweringBridge::create(
ctx, semanticsContext, defKinds, semanticsContext.intrinsics(),
- semanticsContext.targetCharacteristics(), parsing.allCooked(), "",
- kindMap, loweringOptions, {}, semanticsContext.languageFeatures());
+ semanticsContext.targetCharacteristics(), parsing.allCooked(),
+ targetTriple, kindMap, loweringOptions, {},
+ semanticsContext.languageFeatures(), &dataLayout);
burnside.lower(parseTree, semanticsContext);
mlir::ModuleOp mlirModule = burnside.getModule();
if (enableOpenMP) {
@@ -388,6 +421,8 @@ static mlir::LogicalResult convertFortranSourceToMLIR(
int main(int argc, char **argv) {
[[maybe_unused]] llvm::InitLLVM y(argc, argv);
+ llvm::InitializeAllTargets();
+ llvm::InitializeAllTargetMCs();
registerAllPasses();
mlir::registerMLIRContextCLOptions();
@@ -453,17 +488,21 @@ int main(int argc, char **argv) {
.set_warnOnNonstandardUsage(warnStdViolation)
.set_warningsAreErrors(warnIsError);
- llvm::Triple targetTriple{llvm::Triple(
- llvm::Triple::normalize(llvm::sys::getDefaultTargetTriple()))};
- // FIXME: Handle real(3) ?
- if (targetTriple.getArch() != llvm::Triple::ArchType::x86 &&
- targetTriple.getArch() != llvm::Triple::ArchType::x86_64) {
- semanticsContext.targetCharacteristics().DisableType(
- Fortran::common::TypeCategory::Real, /*kind=*/10);
+ std::string error;
+ // Create host target machine.
+ std::unique_ptr<llvm::TargetMachine> targetMachine =
+ createTargetMachine(targetTripleOverride, error);
+ if (!targetMachine) {
+ llvm::errs() << "failed to create target machine: " << error << "\n";
+ return mlir::failed(mlir::failure());
}
- if (targetTriple.isPPC())
- semanticsContext.targetCharacteristics().set_isPPC(true);
-
- return mlir::failed(convertFortranSourceToMLIR(
- inputFilename, options, programPrefix, semanticsContext, passPipe));
+ std::string compilerVersion = Fortran::common::getFlangToolFullVersion("bbc");
+ std::string compilerOptions = "";
+ Fortran::tools::setUpTargetCharacteristics(
+ semanticsContext.targetCharacteristics(), *targetMachine, compilerVersion,
+ compilerOptions);
+
+ return mlir::failed(
+ convertFortranSourceToMLIR(inputFilename, options, programPrefix,
+ semanticsContext, passPipe, *targetMachine));
}
diff --git a/flang/tools/f18/CMakeLists.txt b/flang/tools/f18/CMakeLists.txt
index 270124bce3240..ba6c6642c0b62 100644
--- a/flang/tools/f18/CMakeLists.txt
+++ b/flang/tools/f18/CMakeLists.txt
@@ -49,9 +49,14 @@ if (NOT CMAKE_CROSSCOMPILING)
# The module contains PPC vector types that needs the PPC target.
set(opts "")
- if(${filename} STREQUAL "__ppc_intrinsics" OR
- ${filename} STREQUAL "mma")
- set(opts "--target=ppc64le")
+ if(${filename} STREQUAL "__ppc_intrinsics" OR
+ ${filename} STREQUAL "mma")
+ if (PowerPC IN_LIST LLVM_TARGETS_TO_BUILD)
+ set(opts "--target=ppc64le")
+ else()
+ # Do not compile PPC module if the target is not available.
+ continue()
+ endif()
endif()
add_custom_command(OUTPUT ${base}.mod
diff --git a/flang/tools/tco/tco.cpp b/flang/tools/tco/tco.cpp
index a649535a39b74..d5f5cd0002ede 100644
--- a/flang/tools/tco/tco.cpp
+++ b/flang/tools/tco/tco.cpp
@@ -14,6 +14,7 @@
#include "flang/Optimizer/CodeGen/CodeGen.h"
#include "flang/Optimizer/Dialect/Support/FIRContext.h"
#include "flang/Optimizer/Dialect/Support/KindMapping.h"
+#include "flang/Optimizer/Support/DataLayout.h"
#include "flang/Optimizer/Support/InitFIR.h"
#include "flang/Optimizer/Support/InternalNames.h"
#include "flang/Optimizer/Transforms/Passes.h"
@@ -61,9 +62,8 @@ static cl::opt<bool> codeGenLLVM(
#include "flang/Tools/CLOptions.inc"
-static void printModuleBody(mlir::ModuleOp mod, raw_ostream &output) {
- for (auto &op : *mod.getBody())
- output << op << '\n';
+static void printModule(mlir::ModuleOp mod, raw_ostream &output) {
+ output << mod << '\n';
}
// compile a .fir file
@@ -104,6 +104,10 @@ compileFIR(const mlir::PassPipelineCLParser &passPipeline) {
fir::KindMapping kindMap{&context};
fir::setTargetTriple(*owningRef, targetTriple);
fir::setKindMapping(*owningRef, kindMap);
+ // tco is a testing tool, so it will happily use the target independent
+ // data layout if none is on the module.
+ fir::support::setMLIRDataLayoutFromAttributes(*owningRef,
+ /*allowDefaultLayout=*/true);
mlir::PassManager pm((*owningRef)->getName(),
mlir::OpPassManager::Nesting::Implicit);
pm.enableVerifier(/*verifyPasses=*/true);
@@ -135,13 +139,13 @@ compileFIR(const mlir::PassPipelineCLParser &passPipeline) {
if (mlir::succeeded(pm.run(*owningRef))) {
// passes ran successfully, so keep the output
if ((emitFir || passPipeline.hasAnyOccurrences()) && !codeGenLLVM)
- printModuleBody(*owningRef, out.os());
+ printModule(*owningRef, out.os());
out.keep();
return mlir::success();
}
// pass manager failed
- printModuleBody(*owningRef, errs());
+ printModule(*owningRef, errs());
errs() << "\n\nFAILED: " << inputFilename << '\n';
return mlir::failure();
}
diff --git a/flang/unittests/Frontend/FrontendActionTest.cpp b/flang/unittests/Frontend/FrontendActionTest.cpp
index 2ef63e864b929..d57154cb1001c 100644
--- a/flang/unittests/Frontend/FrontendActionTest.cpp
+++ b/flang/unittests/Frontend/FrontendActionTest.cpp
@@ -64,6 +64,13 @@ class FrontendActionTest : public ::testing::Test {
compInst.createDiagnostics();
invoc = std::make_shared<CompilerInvocation>();
+ // Set-up default target triple and initialize LLVM Targets so that the
+ // target data layout can be passed to the frontend.
+ invoc->getTargetOpts().triple =
+ llvm::Triple::normalize(llvm::sys::getDefaultTargetTriple());
+ llvm::InitializeAllTargets();
+ llvm::InitializeAllTargetMCs();
+
compInst.setInvocation(std::move(invoc));
compInst.getFrontendOpts().inputs.push_back(
FrontendInputFile(inputFilePath, Language::Fortran));
@@ -174,13 +181,7 @@ TEST_F(FrontendActionTest, EmitLLVM) {
// Set-up the action kind.
compInst.getInvocation().getFrontendOpts().programAction = EmitLLVM;
- // Set-up default target triple.
- compInst.getInvocation().getTargetOpts().triple =
- llvm::Triple::normalize(llvm::sys::getDefaultTargetTriple());
-
// Initialise LLVM backend
- llvm::InitializeAllTargets();
- llvm::InitializeAllTargetMCs();
llvm::InitializeAllAsmPrinters();
// Set-up the output stream. We are using output buffer wrapped as an output
@@ -209,13 +210,7 @@ TEST_F(FrontendActionTest, EmitAsm) {
// Set-up the action kind.
compInst.getInvocation().getFrontendOpts().programAction = EmitAssembly;
- // Set-up default target triple.
- compInst.getInvocation().getTargetOpts().triple =
- llvm::Triple::normalize(llvm::sys::getDefaultTargetTriple());
-
// Initialise LLVM backend
- llvm::InitializeAllTargets();
- llvm::InitializeAllTargetMCs();
llvm::InitializeAllAsmPrinters();
// Set-up the output stream. We are using output buffer wrapped as an output
More information about the flang-commits
mailing list