[flang-commits] [flang] 837bff1 - [Flang][Lower] Attach target_cpu and target_features attributes to MLIR functions (#78289)

via flang-commits flang-commits at lists.llvm.org
Tue Jan 30 05:45:59 PST 2024


Author: Sergio Afonso
Date: 2024-01-30T13:45:56Z
New Revision: 837bff11cb7d31f40805c73d4f539960a77eda33

URL: https://github.com/llvm/llvm-project/commit/837bff11cb7d31f40805c73d4f539960a77eda33
DIFF: https://github.com/llvm/llvm-project/commit/837bff11cb7d31f40805c73d4f539960a77eda33.diff

LOG: [Flang][Lower] Attach target_cpu and target_features attributes to MLIR functions (#78289)

This patch forwards the target CPU and features information from the
Flang frontend to MLIR func.func operation attributes, which are later
used to populate the target_cpu and target_features llvm.func
attributes.

This is achieved in two stages:

1. Introduce the `fir.target_cpu` and `fir.target_features` module
attributes with information from the target machine immediately after
the initial creation of the MLIR module in the lowering bridge.

2. Update the target rewrite flang pass to get this information from the
module and pass it along to all func.func MLIR operations, respectively
as attributes named `target_cpu` and `target_features`. These attributes
will be automatically picked up during Func to LLVM dialect lowering and
used to initialize the corresponding llvm.func named attributes.

The target rewrite and FIR to LLVM lowering passes are updated with the
ability to override these module attributes, and the `CodeGenSpecifics`
optimizer class is augmented to make this information available to
target-specific MLIR transformations.

This completes a full flow by which target CPU and features make it all
the way from compiler options to LLVM IR function attributes.

Added: 
    flang/test/Fir/target-rewrite-target-cpu.fir
    flang/test/Fir/target-rewrite-target-features.fir
    flang/test/Lower/target-features-amdgcn.f90
    flang/test/Lower/target-features-x86_64.f90

Modified: 
    flang/include/flang/Lower/Bridge.h
    flang/include/flang/Optimizer/CodeGen/CGPasses.td
    flang/include/flang/Optimizer/CodeGen/Target.h
    flang/include/flang/Optimizer/Dialect/Support/FIRContext.h
    flang/lib/Frontend/FrontendActions.cpp
    flang/lib/Lower/Bridge.cpp
    flang/lib/Optimizer/CodeGen/CodeGen.cpp
    flang/lib/Optimizer/CodeGen/Target.cpp
    flang/lib/Optimizer/CodeGen/TargetRewrite.cpp
    flang/lib/Optimizer/CodeGen/TypeConverter.cpp
    flang/lib/Optimizer/Dialect/Support/FIRContext.cpp
    flang/test/Driver/save-mlir-temps.f90
    flang/tools/bbc/bbc.cpp
    flang/tools/tco/tco.cpp
    flang/unittests/Optimizer/FIRContextTest.cpp

Removed: 
    


################################################################################
diff  --git a/flang/include/flang/Lower/Bridge.h b/flang/include/flang/Lower/Bridge.h
index fd2945a68e00..52110b861b68 100644
--- a/flang/include/flang/Lower/Bridge.h
+++ b/flang/include/flang/Lower/Bridge.h
@@ -24,7 +24,7 @@
 #include <set>
 
 namespace llvm {
-class DataLayout;
+class TargetMachine;
 } // namespace llvm
 
 namespace Fortran {
@@ -65,11 +65,11 @@ class LoweringBridge {
          const Fortran::lower::LoweringOptions &loweringOptions,
          const std::vector<Fortran::lower::EnvironmentDefault> &envDefaults,
          const Fortran::common::LanguageFeatureControl &languageFeatures,
-         const llvm::DataLayout *dataLayout = nullptr) {
+         const llvm::TargetMachine &targetMachine) {
     return LoweringBridge(ctx, semanticsContext, defaultKinds, intrinsics,
                           targetCharacteristics, allCooked, triple, kindMap,
                           loweringOptions, envDefaults, languageFeatures,
-                          dataLayout);
+                          targetMachine);
   }
 
   //===--------------------------------------------------------------------===//
@@ -148,7 +148,7 @@ class LoweringBridge {
       const Fortran::lower::LoweringOptions &loweringOptions,
       const std::vector<Fortran::lower::EnvironmentDefault> &envDefaults,
       const Fortran::common::LanguageFeatureControl &languageFeatures,
-      const llvm::DataLayout *dataLayout);
+      const llvm::TargetMachine &targetMachine);
   LoweringBridge() = delete;
   LoweringBridge(const LoweringBridge &) = delete;
 

diff  --git a/flang/include/flang/Optimizer/CodeGen/CGPasses.td b/flang/include/flang/Optimizer/CodeGen/CGPasses.td
index 9798019bfd6a..f524fb423734 100644
--- a/flang/include/flang/Optimizer/CodeGen/CGPasses.td
+++ b/flang/include/flang/Optimizer/CodeGen/CGPasses.td
@@ -29,6 +29,10 @@ def FIRToLLVMLowering : Pass<"fir-to-llvm-ir", "mlir::ModuleOp"> {
            "Override module's target triple.">,
     Option<"forcedDataLayout", "datalayout", "std::string", /*default=*/"",
            "Override module's data layout.">,
+    Option<"forcedTargetCPU", "target-cpu", "std::string", /*default=*/"",
+           "Override module's target CPU.">,
+    Option<"forcedTargetFeatures", "target-features", "std::string",
+           /*default=*/"", "Override module's target features.">,
     Option<"applyTBAA", "apply-tbaa", "bool", /*default=*/"false",
            "Attach TBAA tags to memory accessing operations.">
   ];
@@ -60,6 +64,10 @@ def TargetRewritePass : Pass<"target-rewrite", "mlir::ModuleOp"> {
   let options = [
     Option<"forcedTargetTriple", "target", "std::string", /*default=*/"",
            "Override module's target triple.">,
+    Option<"forcedTargetCPU", "target-cpu", "std::string", /*default=*/"",
+           "Override module's target CPU.">,
+    Option<"forcedTargetFeatures", "target-features", "std::string",
+           /*default=*/"", "Override module's target features.">,
     Option<"noCharacterConversion", "no-character-conversion",
            "bool", /*default=*/"false",
            "Disable target-specific conversion of CHARACTER.">,

diff  --git a/flang/include/flang/Optimizer/CodeGen/Target.h b/flang/include/flang/Optimizer/CodeGen/Target.h
index c3ef521ced12..3cf6a74a9adb 100644
--- a/flang/include/flang/Optimizer/CodeGen/Target.h
+++ b/flang/include/flang/Optimizer/CodeGen/Target.h
@@ -15,6 +15,7 @@
 
 #include "flang/Optimizer/Dialect/FIRType.h"
 #include "flang/Optimizer/Dialect/Support/KindMapping.h"
+#include "mlir/Dialect/LLVMIR/LLVMAttrs.h"
 #include "mlir/IR/BuiltinTypes.h"
 #include "llvm/TargetParser/Triple.h"
 #include <memory>
@@ -70,17 +71,19 @@ class CodeGenSpecifics {
   using TypeAndAttr = std::tuple<mlir::Type, Attributes>;
   using Marshalling = std::vector<TypeAndAttr>;
 
-  static std::unique_ptr<CodeGenSpecifics> get(mlir::MLIRContext *ctx,
-                                               llvm::Triple &&trp,
-                                               KindMapping &&kindMap,
-                                               const mlir::DataLayout &dl);
+  static std::unique_ptr<CodeGenSpecifics>
+  get(mlir::MLIRContext *ctx, llvm::Triple &&trp, KindMapping &&kindMap,
+      llvm::StringRef targetCPU, mlir::LLVM::TargetFeaturesAttr targetFeatures,
+      const mlir::DataLayout &dl);
 
   static TypeAndAttr getTypeAndAttr(mlir::Type t) { return TypeAndAttr{t, {}}; }
 
   CodeGenSpecifics(mlir::MLIRContext *ctx, llvm::Triple &&trp,
-                   KindMapping &&kindMap, const mlir::DataLayout &dl)
+                   KindMapping &&kindMap, llvm::StringRef targetCPU,
+                   mlir::LLVM::TargetFeaturesAttr targetFeatures,
+                   const mlir::DataLayout &dl)
       : context{*ctx}, triple{std::move(trp)}, kindMap{std::move(kindMap)},
-        dataLayout{&dl} {}
+        targetCPU{targetCPU}, targetFeatures{targetFeatures}, dataLayout{&dl} {}
   CodeGenSpecifics() = delete;
   virtual ~CodeGenSpecifics() {}
 
@@ -161,6 +164,12 @@ class CodeGenSpecifics {
   // Returns width in bits of C/C++ 'int' type size.
   virtual unsigned char getCIntTypeWidth() const = 0;
 
+  llvm::StringRef getTargetCPU() const { return targetCPU; }
+
+  mlir::LLVM::TargetFeaturesAttr getTargetFeatures() const {
+    return targetFeatures;
+  }
+
   const mlir::DataLayout &getDataLayout() const {
     assert(dataLayout && "dataLayout must be set");
     return *dataLayout;
@@ -170,6 +179,8 @@ class CodeGenSpecifics {
   mlir::MLIRContext &context;
   llvm::Triple triple;
   KindMapping kindMap;
+  llvm::StringRef targetCPU;
+  mlir::LLVM::TargetFeaturesAttr targetFeatures;
   const mlir::DataLayout *dataLayout = nullptr;
 };
 

diff  --git a/flang/include/flang/Optimizer/Dialect/Support/FIRContext.h b/flang/include/flang/Optimizer/Dialect/Support/FIRContext.h
index ad91da6a4432..059a10ce2fe5 100644
--- a/flang/include/flang/Optimizer/Dialect/Support/FIRContext.h
+++ b/flang/include/flang/Optimizer/Dialect/Support/FIRContext.h
@@ -17,6 +17,7 @@
 #ifndef FORTRAN_OPTIMIZER_SUPPORT_FIRCONTEXT_H
 #define FORTRAN_OPTIMIZER_SUPPORT_FIRCONTEXT_H
 
+#include "mlir/Dialect/LLVMIR/LLVMAttrs.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/TargetParser/Triple.h"
 
@@ -50,6 +51,19 @@ KindMapping getKindMapping(mlir::ModuleOp mod);
 /// If a ModuleOp cannot be reached, the function returns default KindMapping.
 KindMapping getKindMapping(mlir::Operation *op);
 
+/// Set the target CPU for the module. `cpu` must not be deallocated while
+/// module `mod` is still live.
+void setTargetCPU(mlir::ModuleOp mod, llvm::StringRef cpu);
+
+/// Get the target CPU string from the Module or return a null reference.
+llvm::StringRef getTargetCPU(mlir::ModuleOp mod);
+
+/// Set the target features for the module.
+void setTargetFeatures(mlir::ModuleOp mod, llvm::StringRef features);
+
+/// Get the target features from the Module.
+mlir::LLVM::TargetFeaturesAttr getTargetFeatures(mlir::ModuleOp mod);
+
 /// Helper for determining the target from the host, etc. Tools may use this
 /// function to provide a consistent interpretation of the `--target=<string>`
 /// command-line option.

diff  --git a/flang/lib/Frontend/FrontendActions.cpp b/flang/lib/Frontend/FrontendActions.cpp
index 65c4df7388f9..4738f7ba5704 100644
--- a/flang/lib/Frontend/FrontendActions.cpp
+++ b/flang/lib/Frontend/FrontendActions.cpp
@@ -285,8 +285,6 @@ 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(),
@@ -294,7 +292,7 @@ bool CodeGenAction::beginSourceFileAction() {
       ci.getParsing().allCooked(), ci.getInvocation().getTargetOpts().triple,
       kindMap, ci.getInvocation().getLoweringOpts(),
       ci.getInvocation().getFrontendOpts().envDefaults,
-      ci.getInvocation().getFrontendOpts().features, &dl);
+      ci.getInvocation().getFrontendOpts().features, targetMachine);
 
   // Fetch module from lb, so we can set
   mlirModule = std::make_unique<mlir::ModuleOp>(lb.getModule());

diff  --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp
index c3a14125bba8..d657075d53ef 100644
--- a/flang/lib/Lower/Bridge.cpp
+++ b/flang/lib/Lower/Bridge.cpp
@@ -64,6 +64,7 @@
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/FileSystem.h"
 #include "llvm/Support/Path.h"
+#include "llvm/Target/TargetMachine.h"
 #include <optional>
 
 #define DEBUG_TYPE "flang-lower-bridge"
@@ -5092,7 +5093,7 @@ Fortran::lower::LoweringBridge::LoweringBridge(
     const Fortran::lower::LoweringOptions &loweringOptions,
     const std::vector<Fortran::lower::EnvironmentDefault> &envDefaults,
     const Fortran::common::LanguageFeatureControl &languageFeatures,
-    const llvm::DataLayout *dataLayout)
+    const llvm::TargetMachine &targetMachine)
     : semanticsContext{semanticsContext}, defaultKinds{defaultKinds},
       intrinsics{intrinsics}, targetCharacteristics{targetCharacteristics},
       cooked{&cooked}, context{context}, kindMap{kindMap},
@@ -5148,6 +5149,8 @@ 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);
+  fir::setTargetCPU(*module.get(), targetMachine.getTargetCPU());
+  fir::setTargetFeatures(*module.get(), targetMachine.getTargetFeatureString());
+  fir::support::setMLIRDataLayout(*module.get(),
+                                  targetMachine.createDataLayout());
 }

diff  --git a/flang/lib/Optimizer/CodeGen/CodeGen.cpp b/flang/lib/Optimizer/CodeGen/CodeGen.cpp
index ba5946415b6f..8b0d47ec08ec 100644
--- a/flang/lib/Optimizer/CodeGen/CodeGen.cpp
+++ b/flang/lib/Optimizer/CodeGen/CodeGen.cpp
@@ -3879,6 +3879,12 @@ class FIRToLLVMLowering
       fir::support::setMLIRDataLayout(mod, dl);
     }
 
+    if (!forcedTargetCPU.empty())
+      fir::setTargetCPU(mod, forcedTargetCPU);
+
+    if (!forcedTargetFeatures.empty())
+      fir::setTargetFeatures(mod, forcedTargetFeatures);
+
     // Run dynamic pass pipeline for converting Math dialect
     // operations into other dialects (llvm, func, etc.).
     // Some conversions of Math operations cannot be done

diff  --git a/flang/lib/Optimizer/CodeGen/Target.cpp b/flang/lib/Optimizer/CodeGen/Target.cpp
index f2c47ffa8894..19730f7a6433 100644
--- a/flang/lib/Optimizer/CodeGen/Target.cpp
+++ b/flang/lib/Optimizer/CodeGen/Target.cpp
@@ -1057,51 +1057,57 @@ struct TargetLoongArch64 : public GenericTarget<TargetLoongArch64> {
 // TODO: Add other targets to this file as needed.
 std::unique_ptr<fir::CodeGenSpecifics>
 fir::CodeGenSpecifics::get(mlir::MLIRContext *ctx, llvm::Triple &&trp,
-                           KindMapping &&kindMap, const mlir::DataLayout &dl) {
+                           KindMapping &&kindMap, llvm::StringRef targetCPU,
+                           mlir::LLVM::TargetFeaturesAttr targetFeatures,
+                           const mlir::DataLayout &dl) {
   switch (trp.getArch()) {
   default:
     break;
   case llvm::Triple::ArchType::x86:
     if (trp.isOSWindows())
       return std::make_unique<TargetI386Win>(ctx, std::move(trp),
-                                             std::move(kindMap), dl);
+                                             std::move(kindMap), targetCPU,
+                                             targetFeatures, dl);
     else
       return std::make_unique<TargetI386>(ctx, std::move(trp),
-                                          std::move(kindMap), dl);
+                                          std::move(kindMap), targetCPU,
+                                          targetFeatures, dl);
   case llvm::Triple::ArchType::x86_64:
     if (trp.isOSWindows())
       return std::make_unique<TargetX86_64Win>(ctx, std::move(trp),
-                                               std::move(kindMap), dl);
+                                               std::move(kindMap), targetCPU,
+                                               targetFeatures, dl);
     else
       return std::make_unique<TargetX86_64>(ctx, std::move(trp),
-                                            std::move(kindMap), dl);
+                                            std::move(kindMap), targetCPU,
+                                            targetFeatures, dl);
   case llvm::Triple::ArchType::aarch64:
-    return std::make_unique<TargetAArch64>(ctx, std::move(trp),
-                                           std::move(kindMap), dl);
+    return std::make_unique<TargetAArch64>(
+        ctx, std::move(trp), std::move(kindMap), targetCPU, targetFeatures, dl);
   case llvm::Triple::ArchType::ppc64:
-    return std::make_unique<TargetPPC64>(ctx, std::move(trp),
-                                         std::move(kindMap), dl);
+    return std::make_unique<TargetPPC64>(
+        ctx, std::move(trp), std::move(kindMap), targetCPU, targetFeatures, dl);
   case llvm::Triple::ArchType::ppc64le:
-    return std::make_unique<TargetPPC64le>(ctx, std::move(trp),
-                                           std::move(kindMap), dl);
+    return std::make_unique<TargetPPC64le>(
+        ctx, std::move(trp), std::move(kindMap), targetCPU, targetFeatures, dl);
   case llvm::Triple::ArchType::sparc:
-    return std::make_unique<TargetSparc>(ctx, std::move(trp),
-                                         std::move(kindMap), dl);
+    return std::make_unique<TargetSparc>(
+        ctx, std::move(trp), std::move(kindMap), targetCPU, targetFeatures, dl);
   case llvm::Triple::ArchType::sparcv9:
-    return std::make_unique<TargetSparcV9>(ctx, std::move(trp),
-                                           std::move(kindMap), dl);
+    return std::make_unique<TargetSparcV9>(
+        ctx, std::move(trp), std::move(kindMap), targetCPU, targetFeatures, dl);
   case llvm::Triple::ArchType::riscv64:
-    return std::make_unique<TargetRISCV64>(ctx, std::move(trp),
-                                           std::move(kindMap), dl);
+    return std::make_unique<TargetRISCV64>(
+        ctx, std::move(trp), std::move(kindMap), targetCPU, targetFeatures, dl);
   case llvm::Triple::ArchType::amdgcn:
-    return std::make_unique<TargetAMDGPU>(ctx, std::move(trp),
-                                          std::move(kindMap), dl);
+    return std::make_unique<TargetAMDGPU>(
+        ctx, std::move(trp), std::move(kindMap), targetCPU, targetFeatures, dl);
   case llvm::Triple::ArchType::nvptx64:
-    return std::make_unique<TargetNVPTX>(ctx, std::move(trp),
-                                         std::move(kindMap), dl);
+    return std::make_unique<TargetNVPTX>(
+        ctx, std::move(trp), std::move(kindMap), targetCPU, targetFeatures, dl);
   case llvm::Triple::ArchType::loongarch64:
-    return std::make_unique<TargetLoongArch64>(ctx, std::move(trp),
-                                               std::move(kindMap), dl);
+    return std::make_unique<TargetLoongArch64>(
+        ctx, std::move(trp), std::move(kindMap), targetCPU, targetFeatures, dl);
   }
   TODO(mlir::UnknownLoc::get(ctx), "target not implemented");
 }

diff  --git a/flang/lib/Optimizer/CodeGen/TargetRewrite.cpp b/flang/lib/Optimizer/CodeGen/TargetRewrite.cpp
index f324e18c6546..7bf31ec38695 100644
--- a/flang/lib/Optimizer/CodeGen/TargetRewrite.cpp
+++ b/flang/lib/Optimizer/CodeGen/TargetRewrite.cpp
@@ -90,6 +90,12 @@ class TargetRewrite : public fir::impl::TargetRewritePassBase<TargetRewrite> {
     if (!forcedTargetTriple.empty())
       fir::setTargetTriple(mod, forcedTargetTriple);
 
+    if (!forcedTargetCPU.empty())
+      fir::setTargetCPU(mod, forcedTargetCPU);
+
+    if (!forcedTargetFeatures.empty())
+      fir::setTargetFeatures(mod, forcedTargetFeatures);
+
     // TargetRewrite will require querying the type storage sizes, if it was
     // not set already, create a DataLayoutSpec for the ModuleOp now.
     std::optional<mlir::DataLayout> dl =
@@ -102,9 +108,9 @@ class TargetRewrite : public fir::impl::TargetRewritePassBase<TargetRewrite> {
       return;
     }
 
-    auto specifics =
-        fir::CodeGenSpecifics::get(mod.getContext(), fir::getTargetTriple(mod),
-                                   fir::getKindMapping(mod), *dl);
+    auto specifics = fir::CodeGenSpecifics::get(
+        mod.getContext(), fir::getTargetTriple(mod), fir::getKindMapping(mod),
+        fir::getTargetCPU(mod), fir::getTargetFeatures(mod), *dl);
 
     setMembers(specifics.get(), &rewriter, &*dl);
 
@@ -666,8 +672,21 @@ class TargetRewrite : public fir::impl::TargetRewritePassBase<TargetRewrite> {
   /// As the type signature is being changed, this must also update the
   /// function itself to use any new arguments, etc.
   mlir::LogicalResult convertTypes(mlir::ModuleOp mod) {
-    for (auto fn : mod.getOps<mlir::func::FuncOp>())
+    mlir::MLIRContext *ctx = mod->getContext();
+    auto targetCPU = specifics->getTargetCPU();
+    mlir::StringAttr targetCPUAttr =
+        targetCPU.empty() ? nullptr : mlir::StringAttr::get(ctx, targetCPU);
+    auto targetFeaturesAttr = specifics->getTargetFeatures();
+
+    for (auto fn : mod.getOps<mlir::func::FuncOp>()) {
+      if (targetCPUAttr)
+        fn->setAttr("target_cpu", targetCPUAttr);
+
+      if (targetFeaturesAttr)
+        fn->setAttr("target_features", targetFeaturesAttr);
+
       convertSignature(fn);
+    }
     return mlir::success();
   }
 

diff  --git a/flang/lib/Optimizer/CodeGen/TypeConverter.cpp b/flang/lib/Optimizer/CodeGen/TypeConverter.cpp
index 62a8e4750dc8..8fa423f35806 100644
--- a/flang/lib/Optimizer/CodeGen/TypeConverter.cpp
+++ b/flang/lib/Optimizer/CodeGen/TypeConverter.cpp
@@ -32,9 +32,9 @@ LLVMTypeConverter::LLVMTypeConverter(mlir::ModuleOp module, bool applyTBAA,
                                      const mlir::DataLayout &dl)
     : mlir::LLVMTypeConverter(module.getContext()),
       kindMapping(getKindMapping(module)),
-      specifics(CodeGenSpecifics::get(module.getContext(),
-                                      getTargetTriple(module),
-                                      getKindMapping(module), dl)),
+      specifics(CodeGenSpecifics::get(
+          module.getContext(), getTargetTriple(module), getKindMapping(module),
+          getTargetCPU(module), getTargetFeatures(module), dl)),
       tbaaBuilder(std::make_unique<TBAABuilder>(module->getContext(), applyTBAA,
                                                 forceUnifiedTBAATree)) {
   LLVM_DEBUG(llvm::dbgs() << "FIR type converter\n");

diff  --git a/flang/lib/Optimizer/Dialect/Support/FIRContext.cpp b/flang/lib/Optimizer/Dialect/Support/FIRContext.cpp
index 1b2d1c88c86b..c4d00875c45e 100644
--- a/flang/lib/Optimizer/Dialect/Support/FIRContext.cpp
+++ b/flang/lib/Optimizer/Dialect/Support/FIRContext.cpp
@@ -60,6 +60,42 @@ fir::KindMapping fir::getKindMapping(mlir::Operation *op) {
   return getKindMapping(moduleOp);
 }
 
+static constexpr const char *targetCpuName = "fir.target_cpu";
+
+void fir::setTargetCPU(mlir::ModuleOp mod, llvm::StringRef cpu) {
+  if (cpu.empty())
+    return;
+
+  auto *ctx = mod.getContext();
+  mod->setAttr(targetCpuName, mlir::StringAttr::get(ctx, cpu));
+}
+
+llvm::StringRef fir::getTargetCPU(mlir::ModuleOp mod) {
+  if (auto attr = mod->getAttrOfType<mlir::StringAttr>(targetCpuName))
+    return attr.getValue();
+
+  return {};
+}
+
+static constexpr const char *targetFeaturesName = "fir.target_features";
+
+void fir::setTargetFeatures(mlir::ModuleOp mod, llvm::StringRef features) {
+  if (features.empty())
+    return;
+
+  auto *ctx = mod.getContext();
+  mod->setAttr(targetFeaturesName,
+               mlir::LLVM::TargetFeaturesAttr::get(ctx, features));
+}
+
+mlir::LLVM::TargetFeaturesAttr fir::getTargetFeatures(mlir::ModuleOp mod) {
+  if (auto attr = mod->getAttrOfType<mlir::LLVM::TargetFeaturesAttr>(
+          targetFeaturesName))
+    return attr;
+
+  return {};
+}
+
 std::string fir::determineTargetTriple(llvm::StringRef triple) {
   // Treat "" or "default" as stand-ins for the default machine.
   if (triple.empty() || triple == "default")

diff  --git a/flang/test/Driver/save-mlir-temps.f90 b/flang/test/Driver/save-mlir-temps.f90
index 1c8935fbd7aa..e9478a6c521b 100644
--- a/flang/test/Driver/save-mlir-temps.f90
+++ b/flang/test/Driver/save-mlir-temps.f90
@@ -51,9 +51,9 @@
 ! Content to check from the MLIR outputs
 !--------------------------
 ! MLIR-FIR-NOT: llvm.func
-! MLIR-FIR: func.func @{{.*}}main(){{.*}}{
+! MLIR-FIR: func.func @{{.*}}main(){{.*}}
 
-! MLIR-FIR-NOT: func.func
-! MLIR-LLVMIR: llvm.func @{{.*}}main(){{.*}}{
+! MLIR-LLVMIR-NOT: func.func
+! MLIR-LLVMIR: llvm.func @{{.*}}main(){{.*}}
 
 end program

diff  --git a/flang/test/Fir/target-rewrite-target-cpu.fir b/flang/test/Fir/target-rewrite-target-cpu.fir
new file mode 100644
index 000000000000..8450aaf7d157
--- /dev/null
+++ b/flang/test/Fir/target-rewrite-target-cpu.fir
@@ -0,0 +1,35 @@
+// RUN: fir-opt --target-rewrite %s | FileCheck %s --check-prefixes=ALL_MLIR,UNCHANGED_MLIR
+// RUN: fir-opt --target-rewrite="target-cpu=gfx90a" %s | FileCheck %s --check-prefixes=ALL_MLIR,CHANGED_MLIR
+
+// RUN: tco %s | FileCheck %s --check-prefixes=ALL_LLVM,UNCHANGED_LLVM
+// RUN: tco -target-cpu=gfx90a %s | FileCheck %s --check-prefixes=ALL_LLVM,CHANGED_LLVM
+
+
+// Check MLIR output from the 'fir-opt' tool
+
+// ALL_MLIR: module attributes {
+// ALL_MLIR-SAME: fir.target_cpu =
+
+// UNCHANGED_MLIR-SAME: "x86_64"
+// CHANGED_MLIR-SAME: "gfx90a"
+
+// ALL_MLIR: func.func @dummyfunc() attributes {
+// ALL_MLIR-SAME: target_cpu =
+
+// UNCHANGED_MLIR-SAME: "x86_64"
+// CHANGED_MLIR-SAME: "gfx90a"
+
+
+// Check LLVM output from the 'tco' tool
+
+// ALL_LLVM: define void @dummyfunc() #[[ATTRS:.*]] {
+// ALL_LLVM: attributes #[[ATTRS]] = {
+
+// UNCHANGED_LLVM-SAME: "target-cpu"="x86_64"
+// CHANGED_LLVM-SAME: "target-cpu"="gfx90a"
+
+module attributes {fir.target_cpu = "x86_64"}  {
+  func.func @dummyfunc() -> () {
+    return
+  }
+}

diff  --git a/flang/test/Fir/target-rewrite-target-features.fir b/flang/test/Fir/target-rewrite-target-features.fir
new file mode 100644
index 000000000000..6e6efa2678f2
--- /dev/null
+++ b/flang/test/Fir/target-rewrite-target-features.fir
@@ -0,0 +1,39 @@
+// RUN: fir-opt --target-rewrite %s | FileCheck %s --check-prefixes=ALL_MLIR,UNCHANGED_MLIR
+// RUN: fir-opt --target-rewrite="target-features=+gfx9-insts,+wavefrontsize64" %s | FileCheck %s --check-prefixes=ALL_MLIR,CHANGED_MLIR
+
+// RUN: tco %s | FileCheck %s --check-prefixes=ALL_LLVM,UNCHANGED_LLVM
+// RUN: tco -target-features=+gfx9-insts,+wavefrontsize64 %s | FileCheck %s --check-prefixes=ALL_LLVM,CHANGED_LLVM
+
+
+// Check MLIR output from the 'fir-opt' tool
+
+// ALL_MLIR: module attributes {
+// ALL_MLIR-SAME: fir.target_features = #llvm.target_features<[
+
+// UNCHANGED_MLIR-SAME: "+sse"
+// CHANGED_MLIR-SAME: "+gfx9-insts", "+wavefrontsize64"
+
+// ALL_MLIR-SAME: ]>
+
+// ALL_MLIR: func.func @dummyfunc() attributes {
+// ALL_MLIR-SAME: target_features = #llvm.target_features<[
+
+// UNCHANGED_MLIR-SAME: "+sse"
+// CHANGED_MLIR-SAME: "+gfx9-insts", "+wavefrontsize64"
+
+// ALL_MLIR-SAME: ]>
+
+
+// Check LLVM output from the 'tco' tool
+
+// ALL_LLVM: define void @dummyfunc() #[[ATTRS:.*]] {
+// ALL_LLVM: attributes #[[ATTRS]] = {
+
+// UNCHANGED_LLVM-SAME: "target-features"="+sse"
+// CHANGED_LLVM-SAME: "target-features"="+gfx9-insts,+wavefrontsize64"
+
+module attributes {fir.target_features = #llvm.target_features<["+sse"]>}  {
+  func.func @dummyfunc() -> () {
+    return
+  }
+}

diff  --git a/flang/test/Lower/target-features-amdgcn.f90 b/flang/test/Lower/target-features-amdgcn.f90
new file mode 100644
index 000000000000..1f0439bba80a
--- /dev/null
+++ b/flang/test/Lower/target-features-amdgcn.f90
@@ -0,0 +1,21 @@
+! REQUIRES: amdgpu-registered-target
+! RUN: %flang_fc1 -emit-fir %s -o - | FileCheck %s --check-prefixes=ALL,NONE
+! RUN: %flang_fc1 -emit-fir -triple amdgcn-amd-amdhsa %s -o - | FileCheck %s --check-prefixes=ALL,TRIPLE
+! RUN: %flang_fc1 -emit-fir -target-cpu gfx90a %s -o - | FileCheck %s --check-prefixes=ALL,CPU
+! RUN: %flang_fc1 -emit-fir -triple amdgcn-amd-amdhsa -target-cpu gfx90a %s -o - | FileCheck %s --check-prefixes=ALL,BOTH
+
+! ALL: module attributes {
+
+! NONE-NOT: fir.target_cpu
+! NONE-NOT: fir.target_features
+
+! TRIPLE-SAME: fir.target_cpu = "generic-hsa"
+! TRIPLE-NOT: fir.target_features
+
+! CPU-SAME: fir.target_cpu = "gfx90a"
+! CPU-NOT: fir.target_features
+
+! BOTH-SAME: fir.target_cpu = "gfx90a"
+! BOTH-SAME: fir.target_features = #llvm.target_features<[
+! BOTH-SAME: "+gfx90a-insts"
+! BOTH-SAME: ]>

diff  --git a/flang/test/Lower/target-features-x86_64.f90 b/flang/test/Lower/target-features-x86_64.f90
new file mode 100644
index 000000000000..1b628b6b5b9c
--- /dev/null
+++ b/flang/test/Lower/target-features-x86_64.f90
@@ -0,0 +1,19 @@
+! REQUIRES: x86-registered-target
+! RUN: %flang_fc1 -emit-fir -triple x86_64-unknown-linux-gnu %s -o - | FileCheck %s --check-prefixes=ALL,NONE
+! RUN: %flang_fc1 -emit-fir -triple x86_64-unknown-linux-gnu -target-cpu x86-64 %s -o - | FileCheck %s --check-prefixes=ALL,CPU
+! RUN: %flang_fc1 -emit-fir -triple x86_64-unknown-linux-gnu -target-feature +sse %s -o - | FileCheck %s --check-prefixes=ALL,FEATURE
+! RUN: %flang_fc1 -emit-fir -triple x86_64-unknown-linux-gnu -target-cpu x86-64 -target-feature +sse %s -o - | FileCheck %s --check-prefixes=ALL,BOTH
+
+! ALL: module attributes {
+
+! NONE-NOT: fir.target_cpu
+! NONE-NOT: fir.target_features
+
+! CPU-SAME: fir.target_cpu = "x86-64"
+! CPU-NOT: fir.target_features
+
+! FEATURE-NOT: fir.target_cpu
+! FEATURE-SAME: fir.target_features = #llvm.target_features<["+sse"]>
+
+! BOTH-SAME: fir.target_cpu = "x86-64"
+! BOTH-SAME: fir.target_features = #llvm.target_features<["+sse"]>

diff  --git a/flang/tools/bbc/bbc.cpp b/flang/tools/bbc/bbc.cpp
index b4ba837a3263..98d9258e023e 100644
--- a/flang/tools/bbc/bbc.cpp
+++ b/flang/tools/bbc/bbc.cpp
@@ -331,7 +331,6 @@ 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{};
@@ -342,7 +341,7 @@ static mlir::LogicalResult convertFortranSourceToMLIR(
       ctx, semanticsContext, defKinds, semanticsContext.intrinsics(),
       semanticsContext.targetCharacteristics(), parsing.allCooked(),
       targetTriple, kindMap, loweringOptions, {},
-      semanticsContext.languageFeatures(), &dataLayout);
+      semanticsContext.languageFeatures(), targetMachine);
   burnside.lower(parseTree, semanticsContext);
   mlir::ModuleOp mlirModule = burnside.getModule();
   if (enableOpenMP) {

diff  --git a/flang/tools/tco/tco.cpp b/flang/tools/tco/tco.cpp
index d5f5cd0002ed..2153e0e3e624 100644
--- a/flang/tools/tco/tco.cpp
+++ b/flang/tools/tco/tco.cpp
@@ -55,6 +55,13 @@ static cl::opt<std::string> targetTriple("target",
                                          cl::desc("specify a target triple"),
                                          cl::init("native"));
 
+static cl::opt<std::string>
+    targetCPU("target-cpu", cl::desc("specify a target CPU"), cl::init(""));
+
+static cl::opt<std::string>
+    targetFeatures("target-features", cl::desc("specify the target features"),
+                   cl::init(""));
+
 static cl::opt<bool> codeGenLLVM(
     "code-gen-llvm",
     cl::desc("Run only CodeGen passes and translate FIR to LLVM IR"),
@@ -104,6 +111,8 @@ compileFIR(const mlir::PassPipelineCLParser &passPipeline) {
   fir::KindMapping kindMap{&context};
   fir::setTargetTriple(*owningRef, targetTriple);
   fir::setKindMapping(*owningRef, kindMap);
+  fir::setTargetCPU(*owningRef, targetCPU);
+  fir::setTargetFeatures(*owningRef, targetFeatures);
   // 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,

diff  --git a/flang/unittests/Optimizer/FIRContextTest.cpp b/flang/unittests/Optimizer/FIRContextTest.cpp
index 88bb4363b2b4..49e1ebf23d8a 100644
--- a/flang/unittests/Optimizer/FIRContextTest.cpp
+++ b/flang/unittests/Optimizer/FIRContextTest.cpp
@@ -8,6 +8,8 @@
 
 #include "flang/Optimizer/Dialect/Support/FIRContext.h"
 #include "gtest/gtest.h"
+#include "mlir/Dialect/LLVMIR/LLVMAttrs.h"
+#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
 #include "mlir/IR/BuiltinAttributes.h"
 #include "mlir/IR/BuiltinOps.h"
 #include "flang/Optimizer/Dialect/Support/KindMapping.h"
@@ -19,6 +21,7 @@ using namespace fir;
 struct StringAttributesTests : public testing::Test {
 public:
   void SetUp() {
+    context.loadDialect<mlir::LLVM::LLVMDialect>();
     kindMap = new KindMapping(&context, kindMapInit, "r42a10c14d28i40l41");
     mod = mlir::ModuleOp::create(mlir::UnknownLoc::get(&context));
   }
@@ -30,12 +33,16 @@ struct StringAttributesTests : public testing::Test {
   std::string kindMapInit =
       "i10:80,l3:24,a1:8,r54:Double,r62:X86_FP80,r11:PPC_FP128";
   std::string target = "powerpc64le-unknown-linux-gnu";
+  std::string targetCPU = "gfx90a";
+  std::string targetFeatures = "+gfx9-insts,+wavefrontsize64";
   mlir::ModuleOp mod;
 };
 
 TEST_F(StringAttributesTests, moduleStringAttrTest) {
   setTargetTriple(mod, target);
   setKindMapping(mod, *kindMap);
+  setTargetCPU(mod, targetCPU);
+  setTargetFeatures(mod, targetFeatures);
 
   auto triple = getTargetTriple(mod);
   EXPECT_EQ(triple.getArch(), llvm::Triple::ArchType::ppc64le);
@@ -52,6 +59,15 @@ TEST_F(StringAttributesTests, moduleStringAttrTest) {
   EXPECT_TRUE(mapStr.find("r11:PPC_FP128") != std::string::npos);
   EXPECT_TRUE(mapStr.find("r54:Double") != std::string::npos);
   EXPECT_TRUE(mapStr.find("r62:X86_FP80") != std::string::npos);
+
+  EXPECT_EQ(getTargetCPU(mod), targetCPU);
+
+  auto features = getTargetFeatures(mod);
+  auto featuresList = features.getFeatures();
+  EXPECT_EQ(features.getFeaturesString(), targetFeatures);
+  EXPECT_EQ(featuresList.size(), 2u);
+  EXPECT_EQ(featuresList[0].str(), "+gfx9-insts");
+  EXPECT_EQ(featuresList[1].str(), "+wavefrontsize64");
 }
 
 // main() from gtest_main


        


More information about the flang-commits mailing list