[flang-commits] [flang] c68d289 - [flang][fir] Update flang test tool support classes.

Eric Schweitz via flang-commits flang-commits at lists.llvm.org
Fri Feb 19 16:02:54 PST 2021


Author: Eric Schweitz
Date: 2021-02-19T16:02:39-08:00
New Revision: c68d2895a1f4019b387c69d1e5eec31b0eb5e7b0

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

LOG: [flang][fir] Update flang test tool support classes.

This updates the various classes that support the compliation of
Fortran. These classes are shared by the test tools.

Authors: Eric Schweitz, Sameeran Joshi, et.al.

Differential Revision: https://reviews.llvm.org/D97073

Added: 
    flang/include/flang/Optimizer/Support/FIRContext.h
    flang/lib/Optimizer/Support/FIRContext.cpp
    flang/unittests/Optimizer/FIRContextTest.cpp

Modified: 
    flang/include/flang/Optimizer/Support/InternalNames.h
    flang/include/flang/Optimizer/Support/KindMapping.h
    flang/lib/Optimizer/CMakeLists.txt
    flang/lib/Optimizer/Support/InternalNames.cpp
    flang/lib/Optimizer/Support/KindMapping.cpp
    flang/unittests/Optimizer/CMakeLists.txt
    flang/unittests/Optimizer/InternalNamesTest.cpp
    flang/unittests/Optimizer/KindMappingTest.cpp

Removed: 
    


################################################################################
diff  --git a/flang/include/flang/Optimizer/Support/FIRContext.h b/flang/include/flang/Optimizer/Support/FIRContext.h
new file mode 100644
index 0000000000000..7f236081e2710
--- /dev/null
+++ b/flang/include/flang/Optimizer/Support/FIRContext.h
@@ -0,0 +1,56 @@
+//===-- Optimizer/Support/FIRContext.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/
+//
+//===----------------------------------------------------------------------===//
+/// Setters and getters for associating context with an instance of a ModuleOp.
+/// The context is typically set by the tool and needed in later stages to
+/// determine how to correctly generate code.
+//===----------------------------------------------------------------------===//
+
+#ifndef FORTRAN_OPTIMIZER_SUPPORT_FIRCONTEXT_H
+#define FORTRAN_OPTIMIZER_SUPPORT_FIRCONTEXT_H
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Triple.h"
+
+namespace mlir {
+class ModuleOp;
+}
+
+namespace fir {
+class KindMapping;
+struct NameUniquer;
+
+/// Set the target triple for the module. `triple` must not be deallocated while
+/// module `mod` is still live.
+void setTargetTriple(mlir::ModuleOp mod, llvm::StringRef triple);
+
+/// Get the Triple instance from the Module or return the default Triple.
+llvm::Triple getTargetTriple(mlir::ModuleOp mod);
+
+/// Set the kind mapping for the module. `kindMap` must not be deallocated while
+/// module `mod` is still live.
+void setKindMapping(mlir::ModuleOp mod, KindMapping &kindMap);
+
+/// Get the KindMapping instance from the Module. If none was set, returns a
+/// default.
+KindMapping getKindMapping(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.
+/// An empty string ("") or "default" will specify that the default triple
+/// should be used. "native" will specify that the host machine be used to
+/// construct the triple.
+std::string determineTargetTriple(llvm::StringRef triple);
+
+} // namespace fir
+
+#endif // FORTRAN_OPTIMIZER_SUPPORT_FIRCONTEXT_H

diff  --git a/flang/include/flang/Optimizer/Support/InternalNames.h b/flang/include/flang/Optimizer/Support/InternalNames.h
index b2d741c9e403d..fa98cc2a8e490 100644
--- a/flang/include/flang/Optimizer/Support/InternalNames.h
+++ b/flang/include/flang/Optimizer/Support/InternalNames.h
@@ -6,8 +6,8 @@
 //
 //===----------------------------------------------------------------------===//
 
-#ifndef OPTIMIZER_SUPPORT_INTERNALNAMES_H
-#define OPTIMIZER_SUPPORT_INTERNALNAMES_H
+#ifndef FORTRAN_OPTIMIZER_SUPPORT_INTERNALNAMES_H
+#define FORTRAN_OPTIMIZER_SUPPORT_INTERNALNAMES_H
 
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/Optional.h"
@@ -59,58 +59,58 @@ struct NameUniquer {
     llvm::SmallVector<std::int64_t, 4> kinds;
   };
 
-  NameUniquer() = default;
-
   /// Unique a common block name
-  std::string doCommonBlock(llvm::StringRef name);
+  static std::string doCommonBlock(llvm::StringRef name);
 
   /// Unique a block data unit name
-  std::string doBlockData(llvm::StringRef name);
+  static std::string doBlockData(llvm::StringRef name);
 
   /// Unique a (global) constant name
-  std::string doConstant(llvm::ArrayRef<llvm::StringRef> modules,
-                         llvm::Optional<llvm::StringRef> host,
-                         llvm::StringRef name);
+  static std::string doConstant(llvm::ArrayRef<llvm::StringRef> modules,
+                                llvm::Optional<llvm::StringRef> host,
+                                llvm::StringRef name);
 
   /// Unique a dispatch table name
-  std::string doDispatchTable(llvm::ArrayRef<llvm::StringRef> modules,
-                              llvm::Optional<llvm::StringRef> host,
-                              llvm::StringRef name,
-                              llvm::ArrayRef<std::int64_t> kinds);
+  static std::string doDispatchTable(llvm::ArrayRef<llvm::StringRef> modules,
+                                     llvm::Optional<llvm::StringRef> host,
+                                     llvm::StringRef name,
+                                     llvm::ArrayRef<std::int64_t> kinds);
 
   /// Unique a compiler generated name
-  std::string doGenerated(llvm::StringRef name);
+  static std::string doGenerated(llvm::StringRef name);
 
   /// Unique an intrinsic type descriptor
-  std::string doIntrinsicTypeDescriptor(llvm::ArrayRef<llvm::StringRef> modules,
-                                        llvm::Optional<llvm::StringRef> host,
-                                        IntrinsicType type, std::int64_t kind);
+  static std::string
+  doIntrinsicTypeDescriptor(llvm::ArrayRef<llvm::StringRef> modules,
+                            llvm::Optional<llvm::StringRef> host,
+                            IntrinsicType type, std::int64_t kind);
 
   /// Unique a procedure name
-  std::string doProcedure(llvm::ArrayRef<llvm::StringRef> modules,
-                          llvm::Optional<llvm::StringRef> host,
-                          llvm::StringRef name);
+  static std::string doProcedure(llvm::ArrayRef<llvm::StringRef> modules,
+                                 llvm::Optional<llvm::StringRef> host,
+                                 llvm::StringRef name);
 
   /// Unique a derived type name
-  std::string doType(llvm::ArrayRef<llvm::StringRef> modules,
-                     llvm::Optional<llvm::StringRef> host, llvm::StringRef name,
-                     llvm::ArrayRef<std::int64_t> kinds);
+  static std::string doType(llvm::ArrayRef<llvm::StringRef> modules,
+                            llvm::Optional<llvm::StringRef> host,
+                            llvm::StringRef name,
+                            llvm::ArrayRef<std::int64_t> kinds);
 
   /// Unique a (derived) type descriptor name
-  std::string doTypeDescriptor(llvm::ArrayRef<llvm::StringRef> modules,
-                               llvm::Optional<llvm::StringRef> host,
-                               llvm::StringRef name,
-                               llvm::ArrayRef<std::int64_t> kinds);
-  std::string doTypeDescriptor(llvm::ArrayRef<std::string> modules,
-                               llvm::Optional<std::string> host,
-                               llvm::StringRef name,
-                               llvm::ArrayRef<std::int64_t> kinds);
+  static std::string doTypeDescriptor(llvm::ArrayRef<llvm::StringRef> modules,
+                                      llvm::Optional<llvm::StringRef> host,
+                                      llvm::StringRef name,
+                                      llvm::ArrayRef<std::int64_t> kinds);
+  static std::string doTypeDescriptor(llvm::ArrayRef<std::string> modules,
+                                      llvm::Optional<std::string> host,
+                                      llvm::StringRef name,
+                                      llvm::ArrayRef<std::int64_t> kinds);
 
   /// Unique a (global) variable name. A variable with save attribute
   /// defined inside a subprogram also needs to be handled here
-  std::string doVariable(llvm::ArrayRef<llvm::StringRef> modules,
-                         llvm::Optional<llvm::StringRef> host,
-                         llvm::StringRef name);
+  static std::string doVariable(llvm::ArrayRef<llvm::StringRef> modules,
+                                llvm::Optional<llvm::StringRef> host,
+                                llvm::StringRef name);
 
   /// Entry point for the PROGRAM (called by the runtime)
   /// Can be overridden with the `--main-entry-name=<name>` option.
@@ -121,12 +121,17 @@ struct NameUniquer {
   deconstruct(llvm::StringRef uniquedName);
 
 private:
-  std::string intAsString(std::int64_t i);
-  std::string doKind(std::int64_t kind);
-  std::string doKinds(llvm::ArrayRef<std::int64_t> kinds);
-  std::string toLower(llvm::StringRef name);
+  static std::string intAsString(std::int64_t i);
+  static std::string doKind(std::int64_t kind);
+  static std::string doKinds(llvm::ArrayRef<std::int64_t> kinds);
+  static std::string toLower(llvm::StringRef name);
+
+  NameUniquer() = delete;
+  NameUniquer(const NameUniquer &) = delete;
+  NameUniquer(NameUniquer &&) = delete;
+  NameUniquer &operator=(const NameUniquer &) = delete;
 };
 
 } // namespace fir
 
-#endif // OPTIMIZER_SUPPORT_INTERNALNAMES_H
+#endif // FORTRAN_OPTIMIZER_SUPPORT_INTERNALNAMES_H

diff  --git a/flang/include/flang/Optimizer/Support/KindMapping.h b/flang/include/flang/Optimizer/Support/KindMapping.h
index faef765841ab9..cdde38599782a 100644
--- a/flang/include/flang/Optimizer/Support/KindMapping.h
+++ b/flang/include/flang/Optimizer/Support/KindMapping.h
@@ -10,8 +10,8 @@
 //
 //===----------------------------------------------------------------------===//
 
-#ifndef OPTIMIZER_SUPPORT_KINDMAPPING_H
-#define OPTIMIZER_SUPPORT_KINDMAPPING_H
+#ifndef FORTRAN_OPTIMIZER_SUPPORT_KINDMAPPING_H
+#define FORTRAN_OPTIMIZER_SUPPORT_KINDMAPPING_H
 
 #include "mlir/IR/OpDefinition.h"
 #include "llvm/ADT/DenseMap.h"
@@ -52,15 +52,24 @@ class KindMapping {
   using LLVMTypeID = llvm::Type::TypeID;
   using MatchResult = mlir::ParseResult;
 
-  /// KindMapping constructors take an optional `defs` argument to specify the
+  /// KindMapping constructor with both the kind map and default kinds read from
+  /// command-line options.
+  explicit KindMapping(mlir::MLIRContext *context);
+  /// KindMapping constructor taking a `defs` argument to specify the default
+  /// kinds for intrinsic types. To set the default kinds, an ArrayRef of 6
+  /// KindTy must be passed. The kinds must be the given in the following order:
+  /// CHARACTER, COMPLEX, DOUBLE PRECISION, INTEGER, LOGICAL, and REAL.  The
+  /// kind map is read from command-line options, if given.
+  explicit KindMapping(mlir::MLIRContext *context, llvm::ArrayRef<KindTy> defs);
+  /// KindMapping constructor taking an optional `defs` argument to specify the
   /// default kinds for intrinsic types. To set the default kinds, an ArrayRef
   /// of 6 KindTy must be passed. The kinds must be the given in the following
   /// order: CHARACTER, COMPLEX, DOUBLE PRECISION, INTEGER, LOGICAL, and REAL.
-  /// If `defs` is not specified, default default kinds will be used.
-  explicit KindMapping(mlir::MLIRContext *context,
-                       llvm::ArrayRef<KindTy> defs = llvm::None);
   explicit KindMapping(mlir::MLIRContext *context, llvm::StringRef map,
                        llvm::ArrayRef<KindTy> defs = llvm::None);
+  explicit KindMapping(mlir::MLIRContext *context, llvm::StringRef map,
+                       llvm::StringRef defs)
+      : KindMapping{context, map, toDefaultKinds(defs)} {}
 
   /// Get the size in bits of !fir.char<kind>
   Bitsize getCharacterBitsize(KindTy kind) const;
@@ -85,6 +94,12 @@ class KindMapping {
   /// Get the float semantics of !fir.real<kind>
   const llvm::fltSemantics &getFloatSemantics(KindTy kind) const;
 
+  /// Get the default kind map as a string.
+  static constexpr const char *getDefaultMap() { return ""; }
+
+  /// Convert the current kind map to a string.
+  std::string mapToString() const;
+
   //===--------------------------------------------------------------------===//
   // Default kinds of intrinsic types
   //===--------------------------------------------------------------------===//
@@ -96,6 +111,16 @@ class KindMapping {
   KindTy defaultLogicalKind() const;
   KindTy defaultRealKind() const;
 
+  /// Get the default kinds as a string.
+  static constexpr const char *getDefaultKinds() { return "a1c4d8i4l4r4"; }
+
+  /// Convert the current default kinds to a string.
+  std::string defaultsToString() const;
+
+  /// Translate a default kinds string into a default kind vector. This vector
+  /// can be passed to the KindMapping ctor.
+  static std::vector<KindTy> toDefaultKinds(llvm::StringRef defs);
+
 private:
   MatchResult badMapString(const llvm::Twine &ptr);
   MatchResult parse(llvm::StringRef kindMap);
@@ -109,4 +134,4 @@ class KindMapping {
 
 } // namespace fir
 
-#endif // OPTIMIZER_SUPPORT_KINDMAPPING_H
+#endif // FORTRAN_OPTIMIZER_SUPPORT_KINDMAPPING_H

diff  --git a/flang/lib/Optimizer/CMakeLists.txt b/flang/lib/Optimizer/CMakeLists.txt
index 9903f3a3d9450..9088d08f16c98 100644
--- a/flang/lib/Optimizer/CMakeLists.txt
+++ b/flang/lib/Optimizer/CMakeLists.txt
@@ -6,6 +6,7 @@ add_flang_library(FIROptimizer
   Dialect/FIROps.cpp
   Dialect/FIRType.cpp
 
+  Support/FIRContext.cpp
   Support/InternalNames.cpp
   Support/KindMapping.cpp
 

diff  --git a/flang/lib/Optimizer/Support/FIRContext.cpp b/flang/lib/Optimizer/Support/FIRContext.cpp
new file mode 100644
index 0000000000000..b4910dff9f7df
--- /dev/null
+++ b/flang/lib/Optimizer/Support/FIRContext.cpp
@@ -0,0 +1,62 @@
+//===-- FIRContext.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
+//
+//===----------------------------------------------------------------------===//
+//
+// Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/
+//
+//===----------------------------------------------------------------------===//
+
+#include "flang/Optimizer/Support/FIRContext.h"
+#include "flang/Optimizer/Support/KindMapping.h"
+#include "mlir/IR/BuiltinAttributes.h"
+#include "mlir/IR/BuiltinOps.h"
+#include "llvm/Support/Host.h"
+
+static constexpr const char *tripleName = "fir.triple";
+
+void fir::setTargetTriple(mlir::ModuleOp mod, llvm::StringRef triple) {
+  auto target = fir::determineTargetTriple(triple);
+  mod->setAttr(tripleName, mlir::StringAttr::get(mod.getContext(), target));
+}
+
+llvm::Triple fir::getTargetTriple(mlir::ModuleOp mod) {
+  if (auto target = mod->getAttrOfType<mlir::StringAttr>(tripleName))
+    return llvm::Triple(target.getValue());
+  return llvm::Triple(llvm::sys::getDefaultTargetTriple());
+}
+
+static constexpr const char *kindMapName = "fir.kindmap";
+static constexpr const char *defKindName = "fir.defaultkind";
+
+void fir::setKindMapping(mlir::ModuleOp mod, fir::KindMapping &kindMap) {
+  auto ctx = mod.getContext();
+  mod->setAttr(kindMapName, mlir::StringAttr::get(ctx, kindMap.mapToString()));
+  auto defs = kindMap.defaultsToString();
+  mod->setAttr(defKindName, mlir::StringAttr::get(ctx, defs));
+}
+
+fir::KindMapping fir::getKindMapping(mlir::ModuleOp mod) {
+  auto ctx = mod.getContext();
+  if (auto defs = mod->getAttrOfType<mlir::StringAttr>(defKindName)) {
+    auto defVals = fir::KindMapping::toDefaultKinds(defs.getValue());
+    if (auto maps = mod->getAttrOfType<mlir::StringAttr>(kindMapName))
+      return fir::KindMapping(ctx, maps.getValue(), defVals);
+    return fir::KindMapping(ctx, defVals);
+  }
+  return fir::KindMapping(ctx);
+}
+
+std::string fir::determineTargetTriple(llvm::StringRef triple) {
+  // Treat "" or "default" as stand-ins for the default machine.
+  if (triple.empty() || triple == "default")
+    return llvm::sys::getDefaultTargetTriple();
+  // Treat "native" as stand-in for the host machine.
+  if (triple == "native")
+    return llvm::sys::getProcessTriple();
+  // TODO: normalize the triple?
+  return triple.str();
+}

diff  --git a/flang/lib/Optimizer/Support/InternalNames.cpp b/flang/lib/Optimizer/Support/InternalNames.cpp
index 5b12787860abe..a7493d7494fee 100644
--- a/flang/lib/Optimizer/Support/InternalNames.cpp
+++ b/flang/lib/Optimizer/Support/InternalNames.cpp
@@ -5,6 +5,10 @@
 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 //
 //===----------------------------------------------------------------------===//
+//
+// Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/
+//
+//===----------------------------------------------------------------------===//
 
 #include "flang/Optimizer/Support/InternalNames.h"
 #include "flang/Optimizer/Dialect/FIRType.h"

diff  --git a/flang/lib/Optimizer/Support/KindMapping.cpp b/flang/lib/Optimizer/Support/KindMapping.cpp
index 6cb8d5e5c78eb..a8abcb24073a6 100644
--- a/flang/lib/Optimizer/Support/KindMapping.cpp
+++ b/flang/lib/Optimizer/Support/KindMapping.cpp
@@ -24,9 +24,27 @@ using KindTy = fir::KindMapping::KindTy;
 using LLVMTypeID = fir::KindMapping::LLVMTypeID;
 using MatchResult = fir::KindMapping::MatchResult;
 
-static llvm::cl::opt<std::string> clKindMapping(
-    "kind-mapping", llvm::cl::desc("kind mapping string to set kind precision"),
-    llvm::cl::value_desc("kind-mapping-string"), llvm::cl::init(""));
+static llvm::cl::opt<std::string>
+    clKindMapping("kind-mapping",
+                  llvm::cl::desc("kind mapping string to set kind precision"),
+                  llvm::cl::value_desc("kind-mapping-string"),
+                  llvm::cl::init(fir::KindMapping::getDefaultMap()));
+
+static llvm::cl::opt<std::string>
+    clDefaultKinds("default-kinds",
+                   llvm::cl::desc("string to set default kind values"),
+                   llvm::cl::value_desc("default-kind-string"),
+                   llvm::cl::init(fir::KindMapping::getDefaultKinds()));
+
+// Keywords for the floating point types.
+
+static constexpr const char *kwHalf = "Half";
+static constexpr const char *kwBFloat = "BFloat";
+static constexpr const char *kwFloat = "Float";
+static constexpr const char *kwDouble = "Double";
+static constexpr const char *kwX86FP80 = "X86_FP80";
+static constexpr const char *kwFP128 = "FP128";
+static constexpr const char *kwPPCFP128 = "PPC_FP128";
 
 /// Integral types default to the kind value being the size of the value in
 /// bytes. The default is to scale from bytes to bits.
@@ -104,32 +122,50 @@ static const llvm::fltSemantics &getFloatSemanticsOfKind(KindTy kind,
   }
 }
 
-static MatchResult parseCode(char &code, const char *&ptr) {
+/// Parse an intrinsic type code. The codes are ('a', CHARACTER), ('c',
+/// COMPLEX), ('i', INTEGER), ('l', LOGICAL), and ('r', REAL).
+static MatchResult parseCode(char &code, const char *&ptr, const char *endPtr) {
+  if (ptr >= endPtr)
+    return mlir::failure();
   if (*ptr != 'a' && *ptr != 'c' && *ptr != 'i' && *ptr != 'l' && *ptr != 'r')
     return mlir::failure();
   code = *ptr++;
   return mlir::success();
 }
 
+/// Same as `parseCode` but adds the ('d', DOUBLE PRECISION) code.
+static MatchResult parseDefCode(char &code, const char *&ptr,
+                                const char *endPtr) {
+  if (ptr >= endPtr)
+    return mlir::failure();
+  if (*ptr == 'd') {
+    code = *ptr++;
+    return mlir::success();
+  }
+  return parseCode(code, ptr, endPtr);
+}
+
 template <char ch>
-static MatchResult parseSingleChar(const char *&ptr) {
-  if (*ptr != ch)
+static MatchResult parseSingleChar(const char *&ptr, const char *endPtr) {
+  if (ptr >= endPtr || *ptr != ch)
     return mlir::failure();
   ++ptr;
   return mlir::success();
 }
 
-static MatchResult parseColon(const char *&ptr) {
-  return parseSingleChar<':'>(ptr);
+static MatchResult parseColon(const char *&ptr, const char *endPtr) {
+  return parseSingleChar<':'>(ptr, endPtr);
 }
 
-static MatchResult parseComma(const char *&ptr) {
-  return parseSingleChar<','>(ptr);
+static MatchResult parseComma(const char *&ptr, const char *endPtr) {
+  return parseSingleChar<','>(ptr, endPtr);
 }
 
-static MatchResult parseInt(unsigned &result, const char *&ptr) {
+/// Recognize and parse an unsigned integer.
+static MatchResult parseInt(unsigned &result, const char *&ptr,
+                            const char *endPtr) {
   const char *beg = ptr;
-  while (*ptr >= '0' && *ptr <= '9')
+  while (ptr < endPtr && *ptr >= '0' && *ptr <= '9')
     ptr++;
   if (beg == ptr)
     return mlir::failure();
@@ -141,9 +177,9 @@ static MatchResult parseInt(unsigned &result, const char *&ptr) {
   return mlir::success();
 }
 
-static mlir::LogicalResult matchString(const char *&ptr,
+static mlir::LogicalResult matchString(const char *&ptr, const char *endPtr,
                                        llvm::StringRef literal) {
-  llvm::StringRef s(ptr);
+  llvm::StringRef s(ptr, endPtr - ptr);
   if (s.startswith(literal)) {
     ptr += literal.size();
     return mlir::success();
@@ -151,32 +187,35 @@ static mlir::LogicalResult matchString(const char *&ptr,
   return mlir::failure();
 }
 
-static MatchResult parseTypeID(LLVMTypeID &result, const char *&ptr) {
-  if (mlir::succeeded(matchString(ptr, "Half"))) {
+/// Recognize and parse the various floating-point keywords. These follow the
+/// LLVM naming convention.
+static MatchResult parseTypeID(LLVMTypeID &result, const char *&ptr,
+                               const char *endPtr) {
+  if (mlir::succeeded(matchString(ptr, endPtr, kwHalf))) {
     result = LLVMTypeID::HalfTyID;
     return mlir::success();
   }
-  if (mlir::succeeded(matchString(ptr, "BFloat"))) {
+  if (mlir::succeeded(matchString(ptr, endPtr, kwBFloat))) {
     result = LLVMTypeID::BFloatTyID;
     return mlir::success();
   }
-  if (mlir::succeeded(matchString(ptr, "Float"))) {
+  if (mlir::succeeded(matchString(ptr, endPtr, kwFloat))) {
     result = LLVMTypeID::FloatTyID;
     return mlir::success();
   }
-  if (mlir::succeeded(matchString(ptr, "Double"))) {
+  if (mlir::succeeded(matchString(ptr, endPtr, kwDouble))) {
     result = LLVMTypeID::DoubleTyID;
     return mlir::success();
   }
-  if (mlir::succeeded(matchString(ptr, "X86_FP80"))) {
+  if (mlir::succeeded(matchString(ptr, endPtr, kwX86FP80))) {
     result = LLVMTypeID::X86_FP80TyID;
     return mlir::success();
   }
-  if (mlir::succeeded(matchString(ptr, "FP128"))) {
+  if (mlir::succeeded(matchString(ptr, endPtr, kwFP128))) {
     result = LLVMTypeID::FP128TyID;
     return mlir::success();
   }
-  if (mlir::succeeded(matchString(ptr, "PPC_FP128"))) {
+  if (mlir::succeeded(matchString(ptr, endPtr, kwPPCFP128))) {
     result = LLVMTypeID::PPC_FP128TyID;
     return mlir::success();
   }
@@ -196,6 +235,9 @@ fir::KindMapping::KindMapping(mlir::MLIRContext *context,
                               llvm::ArrayRef<KindTy> defs)
     : KindMapping{context, clKindMapping, defs} {}
 
+fir::KindMapping::KindMapping(mlir::MLIRContext *context)
+    : KindMapping{context, clKindMapping, clDefaultKinds} {}
+
 MatchResult fir::KindMapping::badMapString(const llvm::Twine &ptr) {
   auto unknown = mlir::UnknownLoc::get(context);
   mlir::emitError(unknown, ptr);
@@ -206,28 +248,29 @@ MatchResult fir::KindMapping::parse(llvm::StringRef kindMap) {
   if (kindMap.empty())
     return mlir::success();
   const char *srcPtr = kindMap.begin();
+  const char *endPtr = kindMap.end();
   while (true) {
     char code = '\0';
     KindTy kind = 0;
-    if (parseCode(code, srcPtr) || parseInt(kind, srcPtr))
+    if (parseCode(code, srcPtr, endPtr) || parseInt(kind, srcPtr, endPtr))
       return badMapString(srcPtr);
     if (code == 'a' || code == 'i' || code == 'l') {
       Bitsize bits = 0;
-      if (parseColon(srcPtr) || parseInt(bits, srcPtr))
+      if (parseColon(srcPtr, endPtr) || parseInt(bits, srcPtr, endPtr))
         return badMapString(srcPtr);
       intMap[std::pair<char, KindTy>{code, kind}] = bits;
     } else if (code == 'r' || code == 'c') {
       LLVMTypeID id{};
-      if (parseColon(srcPtr) || parseTypeID(id, srcPtr))
+      if (parseColon(srcPtr, endPtr) || parseTypeID(id, srcPtr, endPtr))
         return badMapString(srcPtr);
       floatMap[std::pair<char, KindTy>{code, kind}] = id;
     } else {
       return badMapString(srcPtr);
     }
-    if (parseComma(srcPtr))
+    if (parseComma(srcPtr, endPtr))
       break;
   }
-  if (*srcPtr)
+  if (srcPtr > endPtr)
     return badMapString(srcPtr);
   return mlir::success();
 }
@@ -263,6 +306,51 @@ fir::KindMapping::getFloatSemantics(KindTy kind) const {
   return getFloatSemanticsOfKind<'r'>(kind, floatMap);
 }
 
+std::string fir::KindMapping::mapToString() const {
+  std::string result;
+  bool addComma = false;
+  for (auto [k, v] : intMap) {
+    if (addComma)
+      result.append(",");
+    else
+      addComma = true;
+    result += k.first + std::to_string(k.second) + ":" + std::to_string(v);
+  }
+  for (auto [k, v] : floatMap) {
+    if (addComma)
+      result.append(",");
+    else
+      addComma = true;
+    result.append(k.first + std::to_string(k.second) + ":");
+    switch (v) {
+    default:
+      llvm_unreachable("unhandled type-id");
+    case LLVMTypeID::HalfTyID:
+      result.append(kwHalf);
+      break;
+    case LLVMTypeID::BFloatTyID:
+      result.append(kwBFloat);
+      break;
+    case LLVMTypeID::FloatTyID:
+      result.append(kwFloat);
+      break;
+    case LLVMTypeID::DoubleTyID:
+      result.append(kwDouble);
+      break;
+    case LLVMTypeID::X86_FP80TyID:
+      result.append(kwX86FP80);
+      break;
+    case LLVMTypeID::FP128TyID:
+      result.append(kwFP128);
+      break;
+    case LLVMTypeID::PPC_FP128TyID:
+      result.append(kwPPCFP128);
+      break;
+    }
+  }
+  return result;
+}
+
 mlir::LogicalResult
 fir::KindMapping::setDefaultKinds(llvm::ArrayRef<KindTy> defs) {
   if (defs.empty()) {
@@ -289,6 +377,52 @@ fir::KindMapping::setDefaultKinds(llvm::ArrayRef<KindTy> defs) {
   return mlir::success();
 }
 
+std::string fir::KindMapping::defaultsToString() const {
+  return std::string("a") + std::to_string(defaultMap.find('a')->second) +
+         std::string("c") + std::to_string(defaultMap.find('c')->second) +
+         std::string("d") + std::to_string(defaultMap.find('d')->second) +
+         std::string("i") + std::to_string(defaultMap.find('i')->second) +
+         std::string("l") + std::to_string(defaultMap.find('l')->second) +
+         std::string("r") + std::to_string(defaultMap.find('r')->second);
+}
+
+/// Convert a default intrinsic code into the proper position in the array. The
+/// default kinds have a precise ordering.
+static int codeToIndex(char code) {
+  switch (code) {
+  case 'a':
+    return 0;
+  case 'c':
+    return 1;
+  case 'd':
+    return 2;
+  case 'i':
+    return 3;
+  case 'l':
+    return 4;
+  case 'r':
+    return 5;
+  }
+  llvm_unreachable("invalid default kind intrinsic code");
+}
+
+std::vector<KindTy> fir::KindMapping::toDefaultKinds(llvm::StringRef defs) {
+  std::vector<KindTy> result(6);
+  char code;
+  KindTy kind;
+  if (defs.empty())
+    defs = clDefaultKinds;
+  const char *srcPtr = defs.begin();
+  const char *endPtr = defs.end();
+  while (srcPtr < endPtr) {
+    if (parseDefCode(code, srcPtr, endPtr) || parseInt(kind, srcPtr, endPtr))
+      llvm::report_fatal_error("invalid default kind code");
+    result[codeToIndex(code)] = kind;
+  }
+  assert(srcPtr == endPtr);
+  return result;
+}
+
 KindTy fir::KindMapping::defaultCharacterKind() const {
   auto iter = defaultMap.find('a');
   assert(iter != defaultMap.end());

diff  --git a/flang/unittests/Optimizer/CMakeLists.txt b/flang/unittests/Optimizer/CMakeLists.txt
index a021ce0a00a27..3996c69b1a982 100644
--- a/flang/unittests/Optimizer/CMakeLists.txt
+++ b/flang/unittests/Optimizer/CMakeLists.txt
@@ -6,6 +6,7 @@ set(LIBS
 )
 
 add_flang_unittest(FlangOptimizerTests
+  FIRContextTest.cpp
   InternalNamesTest.cpp
   KindMappingTest.cpp
 )

diff  --git a/flang/unittests/Optimizer/FIRContextTest.cpp b/flang/unittests/Optimizer/FIRContextTest.cpp
new file mode 100644
index 0000000000000..5976f2c4979f3
--- /dev/null
+++ b/flang/unittests/Optimizer/FIRContextTest.cpp
@@ -0,0 +1,57 @@
+//===- FIRContextTest.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/FIRContext.h"
+#include "flang/Optimizer/Support/KindMapping.h"
+#include "mlir/IR/BuiltinAttributes.h"
+#include "mlir/IR/BuiltinOps.h"
+#include "llvm/Support/Host.h"
+#include "gtest/gtest.h"
+#include <string>
+
+using namespace fir;
+
+struct StringAttributesTests : public testing::Test {
+public:
+  void SetUp() {
+    kindMap = new KindMapping(&context, kindMapInit, "r42a10c14d28i40l41");
+    mod = mlir::ModuleOp::create(mlir::UnknownLoc::get(&context));
+  }
+
+  void TearDown() { delete kindMap; }
+
+  mlir::MLIRContext context;
+  KindMapping *kindMap{};
+  std::string kindMapInit =
+      "i10:80,l3:24,a1:8,r54:Double,r62:X86_FP80,r11:PPC_FP128";
+  std::string target = "powerpc64le-unknown-linux-gnu";
+  mlir::ModuleOp mod;
+};
+
+TEST_F(StringAttributesTests, moduleStringAttrTest) {
+  setTargetTriple(mod, target);
+  setKindMapping(mod, *kindMap);
+
+  auto triple = getTargetTriple(mod);
+  EXPECT_EQ(triple.getArch(), llvm::Triple::ArchType::ppc64le);
+  EXPECT_EQ(triple.getOS(), llvm::Triple::OSType::Linux);
+
+  auto map = getKindMapping(mod);
+  EXPECT_EQ(map.defaultsToString(), "a10c14d28i40l41r42");
+
+  auto mapStr = map.mapToString();
+  EXPECT_EQ(mapStr.size(), kindMapInit.size());
+  EXPECT_TRUE(mapStr.find("a1:8") != std::string::npos);
+  EXPECT_TRUE(mapStr.find("l3:24") != std::string::npos);
+  EXPECT_TRUE(mapStr.find("i10:80") != std::string::npos);
+  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);
+}
+
+// main() from gtest_main

diff  --git a/flang/unittests/Optimizer/InternalNamesTest.cpp b/flang/unittests/Optimizer/InternalNamesTest.cpp
index 0f22fee47950c..831d7997e3f82 100644
--- a/flang/unittests/Optimizer/InternalNamesTest.cpp
+++ b/flang/unittests/Optimizer/InternalNamesTest.cpp
@@ -47,9 +47,8 @@ void validateDeconstructedName(
 }
 
 TEST(InternalNamesTest, doBlockDataTest) {
-  NameUniquer obj;
-  std::string actual = obj.doBlockData("blockdatatest");
-  std::string actualBlank = obj.doBlockData("");
+  std::string actual = NameUniquer::doBlockData("blockdatatest");
+  std::string actualBlank = NameUniquer::doBlockData("");
   std::string expectedMangledName = "_QLblockdatatest";
   std::string expectedMangledNameBlank = "_QL";
   ASSERT_EQ(actual, expectedMangledName);
@@ -57,9 +56,8 @@ TEST(InternalNamesTest, doBlockDataTest) {
 }
 
 TEST(InternalNamesTest, doCommonBlockTest) {
-  NameUniquer obj;
-  std::string actual = obj.doCommonBlock("hello");
-  std::string actualBlank = obj.doCommonBlock("");
+  std::string actual = NameUniquer::doCommonBlock("hello");
+  std::string actualBlank = NameUniquer::doCommonBlock("");
   std::string expectedMangledName = "_QBhello";
   std::string expectedMangledNameBlank = "_QB";
   ASSERT_EQ(actual, expectedMangledName);
@@ -67,108 +65,105 @@ TEST(InternalNamesTest, doCommonBlockTest) {
 }
 
 TEST(InternalNamesTest, doGeneratedTest) {
-  NameUniquer obj;
-  std::string actual = obj.doGenerated("@MAIN");
+  std::string actual = NameUniquer::doGenerated("@MAIN");
   std::string expectedMangledName = "_QQ at MAIN";
   ASSERT_EQ(actual, expectedMangledName);
 
-  std::string actual1 = obj.doGenerated("@_ZNSt8ios_base4InitC1Ev");
+  std::string actual1 = NameUniquer::doGenerated("@_ZNSt8ios_base4InitC1Ev");
   std::string expectedMangledName1 = "_QQ at _ZNSt8ios_base4InitC1Ev";
   ASSERT_EQ(actual1, expectedMangledName1);
 
-  std::string actual2 = obj.doGenerated("_QQ at MAIN");
+  std::string actual2 = NameUniquer::doGenerated("_QQ at MAIN");
   std::string expectedMangledName2 = "_QQ_QQ at MAIN";
   ASSERT_EQ(actual2, expectedMangledName2);
 }
 
 TEST(InternalNamesTest, doConstantTest) {
-  NameUniquer obj;
-  std::string actual = obj.doConstant({"mod1", "mod2"}, {"foo"}, "Hello");
+  std::string actual =
+      NameUniquer::doConstant({"mod1", "mod2"}, {"foo"}, "Hello");
   std::string expectedMangledName = "_QMmod1Smod2FfooEChello";
   ASSERT_EQ(actual, expectedMangledName);
 }
 
 TEST(InternalNamesTest, doProcedureTest) {
-  NameUniquer obj;
-  std::string actual = obj.doProcedure({"mod1", "mod2"}, {}, "HeLLo");
+  std::string actual = NameUniquer::doProcedure({"mod1", "mod2"}, {}, "HeLLo");
   std::string expectedMangledName = "_QMmod1Smod2Phello";
   ASSERT_EQ(actual, expectedMangledName);
 }
 
 TEST(InternalNamesTest, doTypeTest) {
-  NameUniquer obj;
-  std::string actual = obj.doType({}, {}, "mytype", {4, -1});
+  std::string actual = NameUniquer::doType({}, {}, "mytype", {4, -1});
   std::string expectedMangledName = "_QTmytypeK4KN1";
   ASSERT_EQ(actual, expectedMangledName);
 }
 
 TEST(InternalNamesTest, doIntrinsicTypeDescriptorTest) {
   using IntrinsicType = fir::NameUniquer::IntrinsicType;
-  NameUniquer obj;
   std::string actual =
-      obj.doIntrinsicTypeDescriptor({}, {}, IntrinsicType::REAL, 42);
+      NameUniquer::doIntrinsicTypeDescriptor({}, {}, IntrinsicType::REAL, 42);
   std::string expectedMangledName = "_QCrealK42";
   ASSERT_EQ(actual, expectedMangledName);
 
-  actual = obj.doIntrinsicTypeDescriptor({}, {}, IntrinsicType::REAL, {});
+  actual =
+      NameUniquer::doIntrinsicTypeDescriptor({}, {}, IntrinsicType::REAL, {});
   expectedMangledName = "_QCrealK0";
   ASSERT_EQ(actual, expectedMangledName);
 
-  actual = obj.doIntrinsicTypeDescriptor({}, {}, IntrinsicType::INTEGER, 3);
+  actual =
+      NameUniquer::doIntrinsicTypeDescriptor({}, {}, IntrinsicType::INTEGER, 3);
   expectedMangledName = "_QCintegerK3";
   ASSERT_EQ(actual, expectedMangledName);
 
-  actual = obj.doIntrinsicTypeDescriptor({}, {}, IntrinsicType::LOGICAL, 2);
+  actual =
+      NameUniquer::doIntrinsicTypeDescriptor({}, {}, IntrinsicType::LOGICAL, 2);
   expectedMangledName = "_QClogicalK2";
   ASSERT_EQ(actual, expectedMangledName);
 
-  actual = obj.doIntrinsicTypeDescriptor({}, {}, IntrinsicType::CHARACTER, 4);
+  actual = NameUniquer::doIntrinsicTypeDescriptor(
+      {}, {}, IntrinsicType::CHARACTER, 4);
   expectedMangledName = "_QCcharacterK4";
   ASSERT_EQ(actual, expectedMangledName);
 
-  actual = obj.doIntrinsicTypeDescriptor({}, {}, IntrinsicType::COMPLEX, 4);
+  actual =
+      NameUniquer::doIntrinsicTypeDescriptor({}, {}, IntrinsicType::COMPLEX, 4);
   expectedMangledName = "_QCcomplexK4";
   ASSERT_EQ(actual, expectedMangledName);
 }
 
 TEST(InternalNamesTest, doDispatchTableTest) {
-  NameUniquer obj;
-  std::string actual = obj.doDispatchTable({}, {}, "MyTYPE", {2, 8, 18});
+  std::string actual =
+      NameUniquer::doDispatchTable({}, {}, "MyTYPE", {2, 8, 18});
   std::string expectedMangledName = "_QDTmytypeK2K8K18";
   ASSERT_EQ(actual, expectedMangledName);
 }
 
 TEST(InternalNamesTest, doTypeDescriptorTest) {
-  NameUniquer obj;
-  std::string actual = obj.doTypeDescriptor(
+  std::string actual = NameUniquer::doTypeDescriptor(
       {StringRef("moD1")}, {StringRef("foo")}, "MyTYPE", {2, 8});
   std::string expectedMangledName = "_QMmod1FfooCTmytypeK2K8";
   ASSERT_EQ(actual, expectedMangledName);
 }
 
 TEST(InternalNamesTest, doVariableTest) {
-  NameUniquer obj;
-  std::string actual = obj.doVariable(
+  std::string actual = NameUniquer::doVariable(
       {"mod1", "mod2"}, {""}, "intvar"); // Function is present and is blank.
   std::string expectedMangledName = "_QMmod1Smod2FEintvar";
   ASSERT_EQ(actual, expectedMangledName);
 
-  std::string actual2 = obj.doVariable(
+  std::string actual2 = NameUniquer::doVariable(
       {"mod1", "mod2"}, {}, "intVariable"); // Function is not present.
   std::string expectedMangledName2 = "_QMmod1Smod2Eintvariable";
   ASSERT_EQ(actual2, expectedMangledName2);
 }
 
 TEST(InternalNamesTest, doProgramEntry) {
-  NameUniquer obj;
-  llvm::StringRef actual = obj.doProgramEntry();
+  llvm::StringRef actual = NameUniquer::doProgramEntry();
   std::string expectedMangledName = "_QQmain";
   ASSERT_EQ(actual.str(), expectedMangledName);
 }
 
 TEST(InternalNamesTest, deconstructTest) {
-  NameUniquer obj;
-  std::pair actual = obj.deconstruct("_QBhello");
+  std::pair actual = NameUniquer::deconstruct("_QBhello");
   auto expectedNameKind = NameUniquer::NameKind::COMMON;
   struct DeconstructedName expectedComponents {
     {}, {}, "hello", {}
@@ -178,39 +173,38 @@ TEST(InternalNamesTest, deconstructTest) {
 
 TEST(InternalNamesTest, complexdeconstructTest) {
   using NameKind = fir::NameUniquer::NameKind;
-  NameUniquer obj;
-  std::pair actual = obj.deconstruct("_QMmodSs1modSs2modFsubPfun");
+  std::pair actual = NameUniquer::deconstruct("_QMmodSs1modSs2modFsubPfun");
   auto expectedNameKind = NameKind::PROCEDURE;
   struct DeconstructedName expectedComponents = {
       {"mod", "s1mod", "s2mod"}, {"sub"}, "fun", {}};
   validateDeconstructedName(actual, expectedNameKind, expectedComponents);
 
-  actual = obj.deconstruct("_QPsub");
+  actual = NameUniquer::deconstruct("_QPsub");
   expectedNameKind = NameKind::PROCEDURE;
   expectedComponents = {{}, {}, "sub", {}};
   validateDeconstructedName(actual, expectedNameKind, expectedComponents);
 
-  actual = obj.deconstruct("_QBvariables");
+  actual = NameUniquer::deconstruct("_QBvariables");
   expectedNameKind = NameKind::COMMON;
   expectedComponents = {{}, {}, "variables", {}};
   validateDeconstructedName(actual, expectedNameKind, expectedComponents);
 
-  actual = obj.deconstruct("_QMmodEintvar");
+  actual = NameUniquer::deconstruct("_QMmodEintvar");
   expectedNameKind = NameKind::VARIABLE;
   expectedComponents = {{"mod"}, {}, "intvar", {}};
   validateDeconstructedName(actual, expectedNameKind, expectedComponents);
 
-  actual = obj.deconstruct("_QMmodECpi");
+  actual = NameUniquer::deconstruct("_QMmodECpi");
   expectedNameKind = NameKind::CONSTANT;
   expectedComponents = {{"mod"}, {}, "pi", {}};
   validateDeconstructedName(actual, expectedNameKind, expectedComponents);
 
-  actual = obj.deconstruct("_QTyourtypeK4KN6");
+  actual = NameUniquer::deconstruct("_QTyourtypeK4KN6");
   expectedNameKind = NameKind::DERIVED_TYPE;
   expectedComponents = {{}, {}, "yourtype", {4, -6}};
   validateDeconstructedName(actual, expectedNameKind, expectedComponents);
 
-  actual = obj.deconstruct("_QDTt");
+  actual = NameUniquer::deconstruct("_QDTt");
   expectedNameKind = NameKind::DISPATCH_TABLE;
   expectedComponents = {{}, {}, "t", {}};
   validateDeconstructedName(actual, expectedNameKind, expectedComponents);

diff  --git a/flang/unittests/Optimizer/KindMappingTest.cpp b/flang/unittests/Optimizer/KindMappingTest.cpp
index d99b8179f55ee..6a11d61817159 100644
--- a/flang/unittests/Optimizer/KindMappingTest.cpp
+++ b/flang/unittests/Optimizer/KindMappingTest.cpp
@@ -176,19 +176,19 @@ TEST(KindMappingDeathTests, mapTest) {
 }
 
 TEST_F(KindDefaultsTests, getIntegerBitsizeTest) {
-   EXPECT_EQ(defaultDefaultKinds->defaultCharacterKind(), 1u);
-   EXPECT_EQ(defaultDefaultKinds->defaultComplexKind(), 4u);
-   EXPECT_EQ(defaultDefaultKinds->defaultDoubleKind(), 8u);
-   EXPECT_EQ(defaultDefaultKinds->defaultIntegerKind(), 4u);
-   EXPECT_EQ(defaultDefaultKinds->defaultLogicalKind(), 4u);
-   EXPECT_EQ(defaultDefaultKinds->defaultRealKind(), 4u);
-
-   EXPECT_EQ(overrideDefaultKinds->defaultCharacterKind(), 20u);
-   EXPECT_EQ(overrideDefaultKinds->defaultComplexKind(), 121u);
-   EXPECT_EQ(overrideDefaultKinds->defaultDoubleKind(), 32u);
-   EXPECT_EQ(overrideDefaultKinds->defaultIntegerKind(), 133u);
-   EXPECT_EQ(overrideDefaultKinds->defaultLogicalKind(), 44u);
-   EXPECT_EQ(overrideDefaultKinds->defaultRealKind(), 145u);
+  EXPECT_EQ(defaultDefaultKinds->defaultCharacterKind(), 1u);
+  EXPECT_EQ(defaultDefaultKinds->defaultComplexKind(), 4u);
+  EXPECT_EQ(defaultDefaultKinds->defaultDoubleKind(), 8u);
+  EXPECT_EQ(defaultDefaultKinds->defaultIntegerKind(), 4u);
+  EXPECT_EQ(defaultDefaultKinds->defaultLogicalKind(), 4u);
+  EXPECT_EQ(defaultDefaultKinds->defaultRealKind(), 4u);
+
+  EXPECT_EQ(overrideDefaultKinds->defaultCharacterKind(), 20u);
+  EXPECT_EQ(overrideDefaultKinds->defaultComplexKind(), 121u);
+  EXPECT_EQ(overrideDefaultKinds->defaultDoubleKind(), 32u);
+  EXPECT_EQ(overrideDefaultKinds->defaultIntegerKind(), 133u);
+  EXPECT_EQ(overrideDefaultKinds->defaultLogicalKind(), 44u);
+  EXPECT_EQ(overrideDefaultKinds->defaultRealKind(), 145u);
 }
 
 // main() from gtest_main


        


More information about the flang-commits mailing list