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

Sergio Afonso via flang-commits flang-commits at lists.llvm.org
Fri Jan 19 08:31:55 PST 2024


https://github.com/skatrak updated https://github.com/llvm/llvm-project/pull/78289

>From ca41e03ee3bf1c5e465edf53a337cbc7498658da Mon Sep 17 00:00:00 2001
From: Sergio Afonso <safonsof at amd.com>
Date: Tue, 16 Jan 2024 13:38:49 +0000
Subject: [PATCH] [Flang][Lower] Attach target_cpu and target_features
 attributes to MLIR functions

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.
---
 flang/include/flang/Lower/Bridge.h            |  8 +--
 .../flang/Optimizer/CodeGen/CGPasses.td       |  8 +++
 .../include/flang/Optimizer/CodeGen/Target.h  | 23 +++++---
 .../Optimizer/Dialect/Support/FIRContext.h    | 14 +++++
 flang/lib/Frontend/FrontendActions.cpp        |  4 +-
 flang/lib/Lower/Bridge.cpp                    |  9 ++--
 flang/lib/Optimizer/CodeGen/CodeGen.cpp       |  6 +++
 flang/lib/Optimizer/CodeGen/Target.cpp        | 52 +++++++++++--------
 flang/lib/Optimizer/CodeGen/TargetRewrite.cpp | 27 ++++++++--
 flang/lib/Optimizer/CodeGen/TypeConverter.cpp |  6 +--
 .../Optimizer/Dialect/Support/FIRContext.cpp  | 36 +++++++++++++
 flang/test/Driver/save-mlir-temps.f90         |  6 +--
 flang/test/Fir/target-rewrite-target-cpu.fir  | 35 +++++++++++++
 .../Fir/target-rewrite-target-features.fir    | 39 ++++++++++++++
 flang/test/Lower/target-features-amdgcn.f90   | 21 ++++++++
 flang/test/Lower/target-features-x86_64.f90   | 19 +++++++
 flang/tools/bbc/bbc.cpp                       |  3 +-
 flang/tools/tco/tco.cpp                       |  9 ++++
 flang/unittests/Optimizer/FIRContextTest.cpp  | 16 ++++++
 19 files changed, 290 insertions(+), 51 deletions(-)
 create mode 100644 flang/test/Fir/target-rewrite-target-cpu.fir
 create mode 100644 flang/test/Fir/target-rewrite-target-features.fir
 create mode 100644 flang/test/Lower/target-features-amdgcn.f90
 create mode 100644 flang/test/Lower/target-features-x86_64.f90

diff --git a/flang/include/flang/Lower/Bridge.h b/flang/include/flang/Lower/Bridge.h
index 6c0d14d65edae1e..78baf63bd6984e3 100644
--- a/flang/include/flang/Lower/Bridge.h
+++ b/flang/include/flang/Lower/Bridge.h
@@ -23,7 +23,7 @@
 #include "mlir/IR/BuiltinOps.h"
 
 namespace llvm {
-class DataLayout;
+class TargetMachine;
 } // namespace llvm
 
 namespace Fortran {
@@ -64,11 +64,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);
   }
 
   //===--------------------------------------------------------------------===//
@@ -147,7 +147,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 9798019bfd6a982..f524fb423734449 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 c3ef521ced1200f..3cf6a74a9adb7a7 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 ad91da6a4432da0..059a10ce2fe5111 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 65c4df7388f97b2..4738f7ba57042fd 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 8006b9b426f4dc6..d79896ceb14ed5c 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"
@@ -5062,7 +5063,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},
@@ -5118,6 +5119,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 ba5946415b6f924..8b0d47ec08ec345 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 a4df0b09177ab75..04583522ef08f1d 100644
--- a/flang/lib/Optimizer/CodeGen/Target.cpp
+++ b/flang/lib/Optimizer/CodeGen/Target.cpp
@@ -1113,51 +1113,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 f324e18c65465f6..7bf31ec3869598d 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 62a8e4750dc8c94..8fa423f35806ef8 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 1b2d1c88c86b5b7..c4d00875c45e475 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 1c8935fbd7aac9b..e9478a6c521b2e5 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 000000000000000..8450aaf7d157569
--- /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 000000000000000..6e6efa2678f2d0e
--- /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 000000000000000..1f0439bba80a686
--- /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 000000000000000..1b628b6b5b9c85d
--- /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 b4ba837a3263f87..98d9258e023e558 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 d5f5cd0002ede3e..2153e0e3e62492b 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 88bb4363b2b4512..49e1ebf23d8aa6a 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