[flang-commits] [flang] ce782eb - [Flang] Split PowerPC-specific code out of IntrinsicCall into PPCIntrinsicCall

Paul Scoropan via flang-commits flang-commits at lists.llvm.org
Fri Jun 16 10:26:46 PDT 2023


Author: Paul Scoropan
Date: 2023-06-16T17:26:41Z
New Revision: ce782ebdc791a3863380468d1a3fd9c682bf9594

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

LOG: [Flang] Split PowerPC-specific code out of IntrinsicCall into PPCIntrinsicCall

This patch moves PPC intrinsic generator code to PPCIntrinsicCall.cpp. In order to move PowerPC intrinsic code out of IntrinsicCall.cpp, we need to also move some declarations to IntrinsicCall.h. handlers[] and mathOperations[] were also chosen to be moved to the IntrinsicCall header. Similarly, ppcHandlers[] and ppcMathOperations[] were moved to the PPCIntrinsicCall header. There are future patches coming up that will introduce many new PPC intrinsics, these will now be defined in PPCIntrinsicCall.

Reviewed By: jeanPerier

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

Added: 
    flang/include/flang/Optimizer/Builder/PPCIntrinsicCall.h
    flang/lib/Optimizer/Builder/PPCIntrinsicCall.cpp

Modified: 
    flang/include/flang/Optimizer/Builder/IntrinsicCall.h
    flang/lib/Optimizer/Builder/CMakeLists.txt
    flang/lib/Optimizer/Builder/IntrinsicCall.cpp

Removed: 
    


################################################################################
diff  --git a/flang/include/flang/Optimizer/Builder/IntrinsicCall.h b/flang/include/flang/Optimizer/Builder/IntrinsicCall.h
index db08fbfe5469d..11a81fd2c4c4b 100644
--- a/flang/include/flang/Optimizer/Builder/IntrinsicCall.h
+++ b/flang/include/flang/Optimizer/Builder/IntrinsicCall.h
@@ -9,9 +9,16 @@
 #ifndef FORTRAN_LOWER_INTRINSICCALL_H
 #define FORTRAN_LOWER_INTRINSICCALL_H
 
+#include "flang/Optimizer/Builder/BoxValue.h"
 #include "flang/Optimizer/Builder/FIRBuilder.h"
+#include "flang/Optimizer/Builder/Runtime/Character.h"
+#include "flang/Optimizer/Builder/Runtime/Numeric.h"
 #include "flang/Optimizer/Builder/Runtime/RTBuilder.h"
+#include "flang/Runtime/entry-names.h"
 #include "flang/Runtime/iostat.h"
+#include "mlir/Dialect/Complex/IR/Complex.h"
+#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
+#include "mlir/Dialect/Math/IR/Math.h"
 #include <optional>
 
 namespace fir {
@@ -88,10 +95,6 @@ enum class LowerIntrinsicArgAs {
   Inquired
 };
 
-/// Enums used to templatize vector intrinsic function generators. Enum does
-/// not contain every vector intrinsic, only intrinsics that share generators.
-enum class VecOp { Add, And, Mul, Sub, Xor };
-
 /// Define how a given intrinsic argument must be lowered.
 struct ArgLoweringRule {
   LowerIntrinsicArgAs lowerAs;
@@ -108,6 +111,11 @@ struct ArgLoweringRule {
   bool handleDynamicOptional;
 };
 
+constexpr auto asValue = fir::LowerIntrinsicArgAs::Value;
+constexpr auto asAddr = fir::LowerIntrinsicArgAs::Addr;
+constexpr auto asBox = fir::LowerIntrinsicArgAs::Box;
+constexpr auto asInquired = fir::LowerIntrinsicArgAs::Inquired;
+
 /// Opaque class defining the argument lowering rules for all the argument of
 /// an intrinsic.
 struct IntrinsicArgumentLoweringRules;
@@ -314,10 +322,6 @@ struct IntrinsicLibrary {
   /// is ignored because this is already reflected in the result type.
   mlir::Value genConversion(mlir::Type, llvm::ArrayRef<mlir::Value>);
 
-  // PPC intrinsic handlers.
-  template <bool isImm>
-  void genMtfsf(llvm::ArrayRef<fir::ExtendedValue>);
-
   /// In the template helper below:
   ///  - "FN func" is a callback to generate the related intrinsic runtime call.
   ///  - "FD funcDim" is a callback to generate the "dim" runtime call.
@@ -339,11 +343,6 @@ struct IntrinsicLibrary {
                                   mlir::Type resultType,
                                   llvm::ArrayRef<fir::ExtendedValue> args);
 
-  template <VecOp>
-  fir::ExtendedValue
-  genVecAddAndMulSubXor(mlir::Type resultType,
-                        llvm::ArrayRef<fir::ExtendedValue> args);
-
   /// Define the 
diff erent FIR generators that can be mapped to intrinsic to
   /// generate the related code.
   using ElementalGenerator = decltype(&IntrinsicLibrary::genAbs);
@@ -559,6 +558,58 @@ static inline mlir::FunctionType genFuncType(mlir::MLIRContext *context,
   return mlir::FunctionType::get(context, argTypes, {resType});
 }
 
+//===----------------------------------------------------------------------===//
+// Helper functions for argument handling.
+//===----------------------------------------------------------------------===//
+static inline mlir::Type getConvertedElementType(mlir::MLIRContext *context,
+                                                 mlir::Type eleTy) {
+  if (eleTy.isa<mlir::IntegerType>() && !eleTy.isSignlessInteger()) {
+    const auto intTy{eleTy.dyn_cast<mlir::IntegerType>()};
+    auto newEleTy{mlir::IntegerType::get(context, intTy.getWidth())};
+    return newEleTy;
+  }
+  return eleTy;
+}
+
+static inline llvm::SmallVector<mlir::Value, 4>
+getBasesForArgs(llvm::ArrayRef<fir::ExtendedValue> args) {
+  llvm::SmallVector<mlir::Value, 4> baseVec;
+  for (auto arg : args)
+    baseVec.push_back(getBase(arg));
+  return baseVec;
+}
+
+static inline llvm::SmallVector<mlir::Type, 4>
+getTypesForArgs(llvm::ArrayRef<mlir::Value> args) {
+  llvm::SmallVector<mlir::Type, 4> typeVec;
+  for (auto arg : args)
+    typeVec.push_back(arg.getType());
+  return typeVec;
+}
+
+mlir::Value genLibCall(fir::FirOpBuilder &builder, mlir::Location loc,
+                       llvm::StringRef libFuncName,
+                       mlir::FunctionType libFuncType,
+                       llvm::ArrayRef<mlir::Value> args);
+
+template <typename T>
+mlir::Value genMathOp(fir::FirOpBuilder &builder, mlir::Location loc,
+                      llvm::StringRef mathLibFuncName,
+                      mlir::FunctionType mathLibFuncType,
+                      llvm::ArrayRef<mlir::Value> args);
+
+template <typename T>
+mlir::Value genComplexMathOp(fir::FirOpBuilder &builder, mlir::Location loc,
+                             llvm::StringRef mathLibFuncName,
+                             mlir::FunctionType mathLibFuncType,
+                             llvm::ArrayRef<mlir::Value> args);
+
+mlir::Value genLibSplitComplexArgsCall(fir::FirOpBuilder &builder,
+                                       mlir::Location loc,
+                                       llvm::StringRef libFuncName,
+                                       mlir::FunctionType libFuncType,
+                                       llvm::ArrayRef<mlir::Value> args);
+
 /// Return argument lowering rules for an intrinsic.
 /// Returns a nullptr if all the intrinsic arguments should be lowered by value.
 const IntrinsicArgumentLoweringRules *

diff  --git a/flang/include/flang/Optimizer/Builder/PPCIntrinsicCall.h b/flang/include/flang/Optimizer/Builder/PPCIntrinsicCall.h
new file mode 100644
index 0000000000000..d5d955c7a04c4
--- /dev/null
+++ b/flang/include/flang/Optimizer/Builder/PPCIntrinsicCall.h
@@ -0,0 +1,100 @@
+//==-- Builder/PPCIntrinsicCall.h - lowering of PowerPC intrinsics -*-C++-*-==//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef FORTRAN_LOWER_PPCINTRINSICCALL_H
+#define FORTRAN_LOWER_PPCINTRINSICCALL_H
+
+#include "flang/Common/static-multimap-view.h"
+#include "flang/Optimizer/Builder/IntrinsicCall.h"
+#include "mlir/Dialect/Math/IR/Math.h"
+
+namespace fir {
+
+/// Enums used to templatize vector intrinsic function generators. Enum does
+/// not contain every vector intrinsic, only intrinsics that share generators.
+enum class VecOp { Add, And, Mul, Sub, Xor };
+
+// Wrapper struct to encapsulate information for a vector type. Preserves
+// sign of eleTy if eleTy is signed/unsigned integer. Helps with vector type
+// conversions.
+struct VecTypeInfo {
+  mlir::Type eleTy;
+  uint64_t len;
+
+  mlir::Type toFirVectorType() { return fir::VectorType::get(len, eleTy); }
+
+  // We need a builder to do the signless element conversion.
+  mlir::Type toMlirVectorType(mlir::MLIRContext *context) {
+    // Will convert to eleTy to signless int if eleTy is signed/unsigned int.
+    auto convEleTy{getConvertedElementType(context, eleTy)};
+    return mlir::VectorType::get(len, convEleTy);
+  }
+
+  bool isFloat32() { return mlir::isa<mlir::Float32Type>(eleTy); }
+
+  bool isFloat64() { return mlir::isa<mlir::Float64Type>(eleTy); }
+
+  bool isFloat() { return isFloat32() || isFloat64(); }
+};
+
+//===----------------------------------------------------------------------===//
+// Helper functions for argument handling in vector intrinsics.
+//===----------------------------------------------------------------------===//
+
+// Returns a VecTypeInfo with element type and length of given fir vector type.
+// Preserves signness of fir vector type if element type of integer.
+static inline VecTypeInfo getVecTypeFromFirType(mlir::Type firTy) {
+  assert(firTy.isa<fir::VectorType>());
+  VecTypeInfo vecTyInfo;
+  vecTyInfo.eleTy = firTy.dyn_cast<fir::VectorType>().getEleTy();
+  vecTyInfo.len = firTy.dyn_cast<fir::VectorType>().getLen();
+  return vecTyInfo;
+}
+
+static inline VecTypeInfo getVecTypeFromFir(mlir::Value firVec) {
+  return getVecTypeFromFirType(firVec.getType());
+}
+
+// Converts array of fir vectors to mlir vectors.
+static inline llvm::SmallVector<mlir::Value, 4>
+convertVecArgs(fir::FirOpBuilder &builder, mlir::Location loc,
+               VecTypeInfo vecTyInfo, llvm::SmallVector<mlir::Value, 4> args) {
+  llvm::SmallVector<mlir::Value, 4> newArgs;
+  auto ty{vecTyInfo.toMlirVectorType(builder.getContext())};
+  assert(ty && "unknown mlir vector type");
+  for (size_t i = 0; i < args.size(); i++)
+    newArgs.push_back(builder.createConvert(loc, ty, args[i]));
+  return newArgs;
+}
+
+struct PPCIntrinsicLibrary : IntrinsicLibrary {
+
+  // Constructors.
+  explicit PPCIntrinsicLibrary(fir::FirOpBuilder &builder, mlir::Location loc)
+      : IntrinsicLibrary(builder, loc) {}
+  PPCIntrinsicLibrary() = delete;
+  PPCIntrinsicLibrary(const PPCIntrinsicLibrary &) = delete;
+
+  // PPC intrinsic handlers.
+  template <bool isImm>
+  void genMtfsf(llvm::ArrayRef<fir::ExtendedValue>);
+
+  template <VecOp>
+  fir::ExtendedValue
+  genVecAddAndMulSubXor(mlir::Type resultType,
+                        llvm::ArrayRef<fir::ExtendedValue> args);
+};
+
+const IntrinsicHandler *findPPCIntrinsicHandler(llvm::StringRef name);
+
+std::pair<const MathOperation *, const MathOperation *>
+checkPPCMathOperationsRange(llvm::StringRef name);
+
+} // namespace fir
+
+#endif // FORTRAN_LOWER_PPCINTRINSICCALL_H

diff  --git a/flang/lib/Optimizer/Builder/CMakeLists.txt b/flang/lib/Optimizer/Builder/CMakeLists.txt
index 7c035fb6ffa57..7665ca10e84be 100644
--- a/flang/lib/Optimizer/Builder/CMakeLists.txt
+++ b/flang/lib/Optimizer/Builder/CMakeLists.txt
@@ -11,6 +11,7 @@ add_flang_library(FIRBuilder
   IntrinsicCall.cpp
   LowLevelIntrinsics.cpp
   MutableBox.cpp
+  PPCIntrinsicCall.cpp
   Runtime/Allocatable.cpp
   Runtime/ArrayConstructor.cpp
   Runtime/Assign.cpp

diff  --git a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
index fe34a3c6976b4..d5b266bb5702d 100644
--- a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
+++ b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
@@ -20,6 +20,7 @@
 #include "flang/Optimizer/Builder/Complex.h"
 #include "flang/Optimizer/Builder/FIRBuilder.h"
 #include "flang/Optimizer/Builder/MutableBox.h"
+#include "flang/Optimizer/Builder/PPCIntrinsicCall.h"
 #include "flang/Optimizer/Builder/Runtime/Allocatable.h"
 #include "flang/Optimizer/Builder/Runtime/Character.h"
 #include "flang/Optimizer/Builder/Runtime/Command.h"
@@ -89,88 +90,6 @@ static bool isStaticallyPresent(const fir::ExtendedValue &exv) {
   return !isStaticallyAbsent(exv);
 }
 
-//===----------------------------------------------------------------------===//
-// Helper functions for argument handling in vector intrinsics.
-//===----------------------------------------------------------------------===//
-static mlir::Type getConvertedElementType(mlir::MLIRContext *context,
-                                          mlir::Type eleTy) {
-  if (eleTy.isa<mlir::IntegerType>() && !eleTy.isSignlessInteger()) {
-    const auto intTy{eleTy.dyn_cast<mlir::IntegerType>()};
-    auto newEleTy{mlir::IntegerType::get(context, intTy.getWidth())};
-    return newEleTy;
-  }
-  return eleTy;
-}
-
-// Wrapper struct to encapsulate information for a vector type. Preserves
-// sign of eleTy if eleTy is signed/unsigned integer. Helps with vector type
-// conversions.
-struct VecTypeInfo {
-  mlir::Type eleTy;
-  uint64_t len;
-
-  mlir::Type toFirVectorType() { return fir::VectorType::get(len, eleTy); }
-
-  // We need a builder to do the signless element conversion.
-  mlir::Type toMlirVectorType(mlir::MLIRContext *context) {
-    // Will convert to eleTy to signless int if eleTy is signed/unsigned int.
-    auto convEleTy{getConvertedElementType(context, eleTy)};
-    return mlir::VectorType::get(len, convEleTy);
-  }
-
-  bool isFloat32() { return mlir::isa<mlir::Float32Type>(eleTy); }
-
-  bool isFloat64() { return mlir::isa<mlir::Float64Type>(eleTy); }
-
-  bool isFloat() { return isFloat32() || isFloat64(); }
-};
-
-static llvm::SmallVector<mlir::Value, 4>
-getBasesForArgs(llvm::ArrayRef<fir::ExtendedValue> args) {
-  llvm::SmallVector<mlir::Value, 4> baseVec;
-  for (auto arg : args)
-    baseVec.push_back(getBase(arg));
-  return baseVec;
-}
-
-static llvm::SmallVector<mlir::Type, 4>
-getTypesForArgs(llvm::ArrayRef<mlir::Value> args) {
-  llvm::SmallVector<mlir::Type, 4> typeVec;
-  for (auto arg : args)
-    typeVec.push_back(arg.getType());
-  return typeVec;
-}
-
-// Returns a VecTypeInfo with element type and length of given fir vector type.
-// Preserves signness of fir vector type if element type of integer.
-static VecTypeInfo getVecTypeFromFirType(mlir::Type firTy) {
-  assert(firTy.isa<fir::VectorType>());
-  VecTypeInfo vecTyInfo;
-  vecTyInfo.eleTy = firTy.dyn_cast<fir::VectorType>().getEleTy();
-  vecTyInfo.len = firTy.dyn_cast<fir::VectorType>().getLen();
-  return vecTyInfo;
-}
-
-static VecTypeInfo getVecTypeFromFir(mlir::Value firVec) {
-  return getVecTypeFromFirType(firVec.getType());
-}
-
-// Converts array of fir vectors to mlir vectors.
-static llvm::SmallVector<mlir::Value, 4>
-convertVecArgs(fir::FirOpBuilder &builder, mlir::Location loc,
-               VecTypeInfo vecTyInfo, llvm::SmallVector<mlir::Value, 4> args) {
-  llvm::SmallVector<mlir::Value, 4> newArgs;
-  auto ty{vecTyInfo.toMlirVectorType(builder.getContext())};
-  assert(ty && "unknown mlir vector type");
-  for (size_t i = 0; i < args.size(); i++)
-    newArgs.push_back(builder.createConvert(loc, ty, args[i]));
-  return newArgs;
-}
-
-constexpr auto asValue = fir::LowerIntrinsicArgAs::Value;
-constexpr auto asAddr = fir::LowerIntrinsicArgAs::Addr;
-constexpr auto asBox = fir::LowerIntrinsicArgAs::Box;
-constexpr auto asInquired = fir::LowerIntrinsicArgAs::Inquired;
 using I = IntrinsicLibrary;
 
 /// Flag to indicate that an intrinsic argument has to be handled as
@@ -600,38 +519,6 @@ static constexpr IntrinsicHandler handlers[]{
      /*isElemental=*/true},
 };
 
-// PPC specific intrinsic handlers.
-static constexpr IntrinsicHandler ppcHandlers[]{
-    {"__ppc_mtfsf",
-     &I::genMtfsf<false>,
-     {{{"mask", asValue}, {"r", asValue}}},
-     /*isElemental=*/false},
-    {"__ppc_mtfsfi",
-     &I::genMtfsf<true>,
-     {{{"bf", asValue}, {"i", asValue}}},
-     /*isElemental=*/false},
-    {"__ppc_vec_add",
-     &I::genVecAddAndMulSubXor<VecOp::Add>,
-     {{{"arg1", asValue}, {"arg2", asValue}}},
-     /*isElemental=*/true},
-    {"__ppc_vec_and",
-     &I::genVecAddAndMulSubXor<VecOp::And>,
-     {{{"arg1", asValue}, {"arg2", asValue}}},
-     /*isElemental=*/true},
-    {"__ppc_vec_mul",
-     &I::genVecAddAndMulSubXor<VecOp::Mul>,
-     {{{"arg1", asValue}, {"arg2", asValue}}},
-     /*isElemental=*/true},
-    {"__ppc_vec_sub",
-     &I::genVecAddAndMulSubXor<VecOp::Sub>,
-     {{{"arg1", asValue}, {"arg2", asValue}}},
-     /*isElemental=*/true},
-    {"__ppc_vec_xor",
-     &I::genVecAddAndMulSubXor<VecOp::Xor>,
-     {{{"arg1", asValue}, {"arg2", asValue}}},
-     /*isElemental=*/true},
-};
-
 static const IntrinsicHandler *findIntrinsicHandler(llvm::StringRef name) {
   auto compare = [](const IntrinsicHandler &handler, llvm::StringRef name) {
     return name.compare(handler.name) > 0;
@@ -641,15 +528,6 @@ static const IntrinsicHandler *findIntrinsicHandler(llvm::StringRef name) {
                                                               : nullptr;
 }
 
-static const IntrinsicHandler *findPPCIntrinsicHandler(llvm::StringRef name) {
-  auto compare = [](const IntrinsicHandler &ppcHandler, llvm::StringRef name) {
-    return name.compare(ppcHandler.name) > 0;
-  };
-  auto result = llvm::lower_bound(ppcHandlers, name, compare);
-  return result != std::end(ppcHandlers) && result->name == name ? result
-                                                                 : nullptr;
-}
-
 /// To make fir output more readable for debug, one can outline all intrinsic
 /// implementation in wrappers (overrides the IntrinsicHandler::outline flag).
 static llvm::cl::opt<bool> outlineAllIntrinsics(
@@ -679,10 +557,10 @@ static llvm::cl::opt<bool>
                                       "dialect to lower complex operations"),
                        llvm::cl::init(false));
 
-static mlir::Value genLibCall(fir::FirOpBuilder &builder, mlir::Location loc,
-                              llvm::StringRef libFuncName,
-                              mlir::FunctionType libFuncType,
-                              llvm::ArrayRef<mlir::Value> args) {
+mlir::Value genLibCall(fir::FirOpBuilder &builder, mlir::Location loc,
+                       llvm::StringRef libFuncName,
+                       mlir::FunctionType libFuncType,
+                       llvm::ArrayRef<mlir::Value> args) {
   LLVM_DEBUG(llvm::dbgs() << "Generating '" << libFuncName
                           << "' call with type ";
              libFuncType.dump(); llvm::dbgs() << "\n");
@@ -738,9 +616,11 @@ static mlir::Value genLibCall(fir::FirOpBuilder &builder, mlir::Location loc,
   return libCall.getResult(0);
 }
 
-static mlir::Value genLibSplitComplexArgsCall(
-    fir::FirOpBuilder &builder, mlir::Location loc, llvm::StringRef libFuncName,
-    mlir::FunctionType libFuncType, llvm::ArrayRef<mlir::Value> args) {
+mlir::Value genLibSplitComplexArgsCall(fir::FirOpBuilder &builder,
+                                       mlir::Location loc,
+                                       llvm::StringRef libFuncName,
+                                       mlir::FunctionType libFuncType,
+                                       llvm::ArrayRef<mlir::Value> args) {
   assert(args.size() == 2 && "Incorrect #args to genLibSplitComplexArgsCall");
 
   auto getSplitComplexArgsType = [&builder, &args]() -> mlir::FunctionType {
@@ -787,10 +667,10 @@ static mlir::Value genLibSplitComplexArgsCall(
 }
 
 template <typename T>
-static mlir::Value genMathOp(fir::FirOpBuilder &builder, mlir::Location loc,
-                             llvm::StringRef mathLibFuncName,
-                             mlir::FunctionType mathLibFuncType,
-                             llvm::ArrayRef<mlir::Value> args) {
+mlir::Value genMathOp(fir::FirOpBuilder &builder, mlir::Location loc,
+                      llvm::StringRef mathLibFuncName,
+                      mlir::FunctionType mathLibFuncType,
+                      llvm::ArrayRef<mlir::Value> args) {
   // TODO: we have to annotate the math operations with flags
   //       that will allow to define FP accuracy/exception
   //       behavior per operation, so that after early multi-module
@@ -829,11 +709,10 @@ static mlir::Value genMathOp(fir::FirOpBuilder &builder, mlir::Location loc,
 }
 
 template <typename T>
-static mlir::Value genComplexMathOp(fir::FirOpBuilder &builder,
-                                    mlir::Location loc,
-                                    llvm::StringRef mathLibFuncName,
-                                    mlir::FunctionType mathLibFuncType,
-                                    llvm::ArrayRef<mlir::Value> args) {
+mlir::Value genComplexMathOp(fir::FirOpBuilder &builder, mlir::Location loc,
+                             llvm::StringRef mathLibFuncName,
+                             mlir::FunctionType mathLibFuncType,
+                             llvm::ArrayRef<mlir::Value> args) {
   mlir::Value result;
   if (disableMlirComplex ||
       (mathRuntimeVersion == preciseVersion && !mathLibFuncName.empty())) {
@@ -1136,64 +1015,6 @@ static constexpr MathOperation mathOperations[] = {
      genComplexMathOp<mlir::complex::TanhOp>},
 };
 
-static constexpr MathOperation ppcMathOperations[] = {
-    // fcfi is just another name for fcfid, there is no llvm.ppc.fcfi.
-    {"__ppc_fcfi", "llvm.ppc.fcfid", genFuncType<Ty::Real<8>, Ty::Real<8>>,
-     genLibCall},
-    {"__ppc_fcfid", "llvm.ppc.fcfid", genFuncType<Ty::Real<8>, Ty::Real<8>>,
-     genLibCall},
-    {"__ppc_fcfud", "llvm.ppc.fcfud", genFuncType<Ty::Real<8>, Ty::Real<8>>,
-     genLibCall},
-    {"__ppc_fctid", "llvm.ppc.fctid", genFuncType<Ty::Real<8>, Ty::Real<8>>,
-     genLibCall},
-    {"__ppc_fctidz", "llvm.ppc.fctidz", genFuncType<Ty::Real<8>, Ty::Real<8>>,
-     genLibCall},
-    {"__ppc_fctiw", "llvm.ppc.fctiw", genFuncType<Ty::Real<8>, Ty::Real<8>>,
-     genLibCall},
-    {"__ppc_fctiwz", "llvm.ppc.fctiwz", genFuncType<Ty::Real<8>, Ty::Real<8>>,
-     genLibCall},
-    {"__ppc_fctudz", "llvm.ppc.fctudz", genFuncType<Ty::Real<8>, Ty::Real<8>>,
-     genLibCall},
-    {"__ppc_fctuwz", "llvm.ppc.fctuwz", genFuncType<Ty::Real<8>, Ty::Real<8>>,
-     genLibCall},
-    {"__ppc_fmadd", "llvm.fma.f32",
-     genFuncType<Ty::Real<4>, Ty::Real<4>, Ty::Real<4>, Ty::Real<4>>,
-     genMathOp<mlir::math::FmaOp>},
-    {"__ppc_fmadd", "llvm.fma.f64",
-     genFuncType<Ty::Real<8>, Ty::Real<8>, Ty::Real<8>, Ty::Real<8>>,
-     genMathOp<mlir::math::FmaOp>},
-    {"__ppc_fmsub", "llvm.ppc.fmsubs",
-     genFuncType<Ty::Real<4>, Ty::Real<4>, Ty::Real<4>, Ty::Real<4>>,
-     genLibCall},
-    {"__ppc_fmsub", "llvm.ppc.fmsub",
-     genFuncType<Ty::Real<8>, Ty::Real<8>, Ty::Real<8>, Ty::Real<8>>,
-     genLibCall},
-    {"__ppc_fnabs", "llvm.ppc.fnabss", genFuncType<Ty::Real<4>, Ty::Real<4>>,
-     genLibCall},
-    {"__ppc_fnabs", "llvm.ppc.fnabs", genFuncType<Ty::Real<8>, Ty::Real<8>>,
-     genLibCall},
-    {"__ppc_fnmadd", "llvm.ppc.fnmadds",
-     genFuncType<Ty::Real<4>, Ty::Real<4>, Ty::Real<4>, Ty::Real<4>>,
-     genLibCall},
-    {"__ppc_fnmadd", "llvm.ppc.fnmadd",
-     genFuncType<Ty::Real<8>, Ty::Real<8>, Ty::Real<8>, Ty::Real<8>>,
-     genLibCall},
-    {"__ppc_fnmsub", "llvm.ppc.fnmsub.f32",
-     genFuncType<Ty::Real<4>, Ty::Real<4>, Ty::Real<4>, Ty::Real<4>>,
-     genLibCall},
-    {"__ppc_fnmsub", "llvm.ppc.fnmsub.f64",
-     genFuncType<Ty::Real<8>, Ty::Real<8>, Ty::Real<8>, Ty::Real<8>>,
-     genLibCall},
-    {"__ppc_fre", "llvm.ppc.fre", genFuncType<Ty::Real<8>, Ty::Real<8>>,
-     genLibCall},
-    {"__ppc_fres", "llvm.ppc.fres", genFuncType<Ty::Real<4>, Ty::Real<4>>,
-     genLibCall},
-    {"__ppc_frsqrte", "llvm.ppc.frsqrte", genFuncType<Ty::Real<8>, Ty::Real<8>>,
-     genLibCall},
-    {"__ppc_frsqrtes", "llvm.ppc.frsqrtes",
-     genFuncType<Ty::Real<4>, Ty::Real<4>>, genLibCall},
-};
-
 // This helper class computes a "distance" between two function types.
 // The distance measures how many narrowing conversions of actual arguments
 // and result of "from" must be made in order to use "to" instead of "from".
@@ -1338,10 +1159,6 @@ using RtMap = Fortran::common::StaticMultimapView<MathOperation>;
 static constexpr RtMap mathOps(mathOperations);
 static_assert(mathOps.Verify() && "map must be sorted");
 
-// PPC
-static constexpr RtMap ppcMathOps(ppcMathOperations);
-static_assert(ppcMathOps.Verify() && "map must be sorted");
-
 /// Look for a MathOperation entry specifying how to lower a mathematical
 /// operation defined by \p name with its result' and operands' types
 /// specified in the form of a FunctionType \p funcType.
@@ -1363,7 +1180,7 @@ searchMathOperation(fir::FirOpBuilder &builder, llvm::StringRef name,
 
   // Search ppcMathOps only if targetting PowerPC arch
   if (fir::getTargetTriple(mod).isPPC() && range.first == range.second) {
-    range = ppcMathOps.equal_range(name);
+    range = checkPPCMathOperationsRange(name);
   }
   for (auto iter = range.first; iter != range.second && iter; ++iter) {
     const auto &impl = *iter;
@@ -4604,73 +4421,6 @@ mlir::Value IntrinsicLibrary::genTrailz(mlir::Type resultType,
   return builder.createConvert(loc, resultType, result);
 }
 
-// VEC_ADD, VEC_AND, VEC_SUB, VEC_MUL, VEC_XOR
-template <VecOp vop>
-fir::ExtendedValue IntrinsicLibrary::genVecAddAndMulSubXor(
-    mlir::Type resultType, llvm::ArrayRef<fir::ExtendedValue> args) {
-  assert(args.size() == 2);
-  auto argBases{getBasesForArgs(args)};
-  auto argsTy{getTypesForArgs(argBases)};
-  assert(argsTy[0].isa<fir::VectorType>() && argsTy[1].isa<fir::VectorType>());
-
-  auto vecTyInfo{getVecTypeFromFir(argBases[0])};
-
-  const auto isInteger{vecTyInfo.eleTy.isa<mlir::IntegerType>()};
-  const auto isFloat{vecTyInfo.eleTy.isa<mlir::FloatType>()};
-  assert((isInteger || isFloat) && "unknown vector type");
-
-  auto vargs{convertVecArgs(builder, loc, vecTyInfo, argBases)};
-
-  mlir::Value r{nullptr};
-  switch (vop) {
-  case VecOp::Add:
-    if (isInteger)
-      r = builder.create<mlir::arith::AddIOp>(loc, vargs[0], vargs[1]);
-    else if (isFloat)
-      r = builder.create<mlir::arith::AddFOp>(loc, vargs[0], vargs[1]);
-    break;
-  case VecOp::Mul:
-    if (isInteger)
-      r = builder.create<mlir::arith::MulIOp>(loc, vargs[0], vargs[1]);
-    else if (isFloat)
-      r = builder.create<mlir::arith::MulFOp>(loc, vargs[0], vargs[1]);
-    break;
-  case VecOp::Sub:
-    if (isInteger)
-      r = builder.create<mlir::arith::SubIOp>(loc, vargs[0], vargs[1]);
-    else if (isFloat)
-      r = builder.create<mlir::arith::SubFOp>(loc, vargs[0], vargs[1]);
-    break;
-  case VecOp::And:
-  case VecOp::Xor: {
-    mlir::Value arg1{nullptr};
-    mlir::Value arg2{nullptr};
-    if (isInteger) {
-      arg1 = vargs[0];
-      arg2 = vargs[1];
-    } else if (isFloat) {
-      // bitcast the arguments to integer
-      auto wd{vecTyInfo.eleTy.dyn_cast<mlir::FloatType>().getWidth()};
-      auto ftype{builder.getIntegerType(wd)};
-      auto bcVecTy{mlir::VectorType::get(vecTyInfo.len, ftype)};
-      arg1 = builder.create<mlir::vector::BitCastOp>(loc, bcVecTy, vargs[0]);
-      arg2 = builder.create<mlir::vector::BitCastOp>(loc, bcVecTy, vargs[1]);
-    }
-    if (vop == VecOp::And)
-      r = builder.create<mlir::arith::AndIOp>(loc, arg1, arg2);
-    else if (vop == VecOp::Xor)
-      r = builder.create<mlir::arith::XOrIOp>(loc, arg1, arg2);
-
-    if (isFloat)
-      r = builder.create<mlir::vector::BitCastOp>(loc, vargs[0].getType(), r);
-
-    break;
-  }
-  }
-
-  return builder.createConvert(loc, argsTy[0], r);
-}
-
 static bool hasDefaultLowerBound(const fir::ExtendedValue &exv) {
   return exv.match(
       [](const fir::ArrayBoxValue &arr) { return arr.getLBounds().empty(); },
@@ -5376,33 +5126,6 @@ mlir::Value IntrinsicLibrary::genExtremum(mlir::Type,
   return result;
 }
 
-//===----------------------------------------------------------------------===//
-// PowerPC specific intrinsic handlers.
-//===----------------------------------------------------------------------===//
-template <bool isImm>
-void IntrinsicLibrary::genMtfsf(llvm::ArrayRef<fir::ExtendedValue> args) {
-  assert(args.size() == 2);
-  llvm::SmallVector<mlir::Value> scalarArgs;
-  for (const fir::ExtendedValue &arg : args)
-    if (arg.getUnboxed())
-      scalarArgs.emplace_back(fir::getBase(arg));
-    else
-      mlir::emitError(loc, "nonscalar intrinsic argument");
-
-  mlir::FunctionType libFuncType;
-  mlir::func::FuncOp funcOp;
-  if (isImm) {
-    libFuncType = genFuncType<Ty::Void, Ty::Integer<4>, Ty::Integer<4>>(
-        builder.getContext(), builder);
-    funcOp = builder.addNamedFunction(loc, "llvm.ppc.mtfsfi", libFuncType);
-  } else {
-    libFuncType = genFuncType<Ty::Void, Ty::Integer<4>, Ty::Real<8>>(
-        builder.getContext(), builder);
-    funcOp = builder.addNamedFunction(loc, "llvm.ppc.mtfsf", libFuncType);
-  }
-  builder.create<fir::CallOp>(loc, funcOp, scalarArgs);
-}
-
 //===----------------------------------------------------------------------===//
 // Argument lowering rules interface for intrinsic or intrinsic module
 // procedure.

diff  --git a/flang/lib/Optimizer/Builder/PPCIntrinsicCall.cpp b/flang/lib/Optimizer/Builder/PPCIntrinsicCall.cpp
new file mode 100644
index 0000000000000..616c89c8c78c4
--- /dev/null
+++ b/flang/lib/Optimizer/Builder/PPCIntrinsicCall.cpp
@@ -0,0 +1,235 @@
+//===-- PPCIntrinsicCall.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
+//
+//===----------------------------------------------------------------------===//
+//
+// Helper routines for constructing the FIR dialect of MLIR for PowerPC
+// intrinsics. Extensive use of MLIR interfaces and MLIR's coding style
+// (https://mlir.llvm.org/getting_started/DeveloperGuide/) is used in this
+// module.
+//
+//===----------------------------------------------------------------------===//
+
+#include "flang/Optimizer/Builder/PPCIntrinsicCall.h"
+#include "flang/Optimizer/Builder/FIRBuilder.h"
+#include "flang/Optimizer/Builder/IntrinsicCall.h"
+#include "flang/Optimizer/Builder/MutableBox.h"
+#include "mlir/Dialect/Vector/IR/VectorOps.h"
+
+namespace fir {
+
+using PI = PPCIntrinsicLibrary;
+
+// PPC specific intrinsic handlers.
+static constexpr IntrinsicHandler ppcHandlers[]{
+    {"__ppc_mtfsf",
+     static_cast<IntrinsicLibrary::SubroutineGenerator>(&PI::genMtfsf<false>),
+     {{{"mask", asValue}, {"r", asValue}}},
+     /*isElemental=*/false},
+    {"__ppc_mtfsfi",
+     static_cast<IntrinsicLibrary::SubroutineGenerator>(&PI::genMtfsf<true>),
+     {{{"bf", asValue}, {"i", asValue}}},
+     /*isElemental=*/false},
+    {"__ppc_vec_add",
+     static_cast<IntrinsicLibrary::ExtendedGenerator>(
+         &PI::genVecAddAndMulSubXor<VecOp::Add>),
+     {{{"arg1", asValue}, {"arg2", asValue}}},
+     /*isElemental=*/true},
+    {"__ppc_vec_and",
+     static_cast<IntrinsicLibrary::ExtendedGenerator>(
+         &PI::genVecAddAndMulSubXor<VecOp::And>),
+     {{{"arg1", asValue}, {"arg2", asValue}}},
+     /*isElemental=*/true},
+    {"__ppc_vec_mul",
+     static_cast<IntrinsicLibrary::ExtendedGenerator>(
+         &PI::genVecAddAndMulSubXor<VecOp::Mul>),
+     {{{"arg1", asValue}, {"arg2", asValue}}},
+     /*isElemental=*/true},
+    {"__ppc_vec_sub",
+     static_cast<IntrinsicLibrary::ExtendedGenerator>(
+         &PI::genVecAddAndMulSubXor<VecOp::Sub>),
+     {{{"arg1", asValue}, {"arg2", asValue}}},
+     /*isElemental=*/true},
+    {"__ppc_vec_xor",
+     static_cast<IntrinsicLibrary::ExtendedGenerator>(
+         &PI::genVecAddAndMulSubXor<VecOp::Xor>),
+     {{{"arg1", asValue}, {"arg2", asValue}}},
+     /*isElemental=*/true},
+};
+
+static constexpr MathOperation ppcMathOperations[] = {
+    // fcfi is just another name for fcfid, there is no llvm.ppc.fcfi.
+    {"__ppc_fcfi", "llvm.ppc.fcfid", genFuncType<Ty::Real<8>, Ty::Real<8>>,
+     genLibCall},
+    {"__ppc_fcfid", "llvm.ppc.fcfid", genFuncType<Ty::Real<8>, Ty::Real<8>>,
+     genLibCall},
+    {"__ppc_fcfud", "llvm.ppc.fcfud", genFuncType<Ty::Real<8>, Ty::Real<8>>,
+     genLibCall},
+    {"__ppc_fctid", "llvm.ppc.fctid", genFuncType<Ty::Real<8>, Ty::Real<8>>,
+     genLibCall},
+    {"__ppc_fctidz", "llvm.ppc.fctidz", genFuncType<Ty::Real<8>, Ty::Real<8>>,
+     genLibCall},
+    {"__ppc_fctiw", "llvm.ppc.fctiw", genFuncType<Ty::Real<8>, Ty::Real<8>>,
+     genLibCall},
+    {"__ppc_fctiwz", "llvm.ppc.fctiwz", genFuncType<Ty::Real<8>, Ty::Real<8>>,
+     genLibCall},
+    {"__ppc_fctudz", "llvm.ppc.fctudz", genFuncType<Ty::Real<8>, Ty::Real<8>>,
+     genLibCall},
+    {"__ppc_fctuwz", "llvm.ppc.fctuwz", genFuncType<Ty::Real<8>, Ty::Real<8>>,
+     genLibCall},
+    {"__ppc_fmadd", "llvm.fma.f32",
+     genFuncType<Ty::Real<4>, Ty::Real<4>, Ty::Real<4>, Ty::Real<4>>,
+     genMathOp<mlir::math::FmaOp>},
+    {"__ppc_fmadd", "llvm.fma.f64",
+     genFuncType<Ty::Real<8>, Ty::Real<8>, Ty::Real<8>, Ty::Real<8>>,
+     genMathOp<mlir::math::FmaOp>},
+    {"__ppc_fmsub", "llvm.ppc.fmsubs",
+     genFuncType<Ty::Real<4>, Ty::Real<4>, Ty::Real<4>, Ty::Real<4>>,
+     genLibCall},
+    {"__ppc_fmsub", "llvm.ppc.fmsub",
+     genFuncType<Ty::Real<8>, Ty::Real<8>, Ty::Real<8>, Ty::Real<8>>,
+     genLibCall},
+    {"__ppc_fnabs", "llvm.ppc.fnabss", genFuncType<Ty::Real<4>, Ty::Real<4>>,
+     genLibCall},
+    {"__ppc_fnabs", "llvm.ppc.fnabs", genFuncType<Ty::Real<8>, Ty::Real<8>>,
+     genLibCall},
+    {"__ppc_fnmadd", "llvm.ppc.fnmadds",
+     genFuncType<Ty::Real<4>, Ty::Real<4>, Ty::Real<4>, Ty::Real<4>>,
+     genLibCall},
+    {"__ppc_fnmadd", "llvm.ppc.fnmadd",
+     genFuncType<Ty::Real<8>, Ty::Real<8>, Ty::Real<8>, Ty::Real<8>>,
+     genLibCall},
+    {"__ppc_fnmsub", "llvm.ppc.fnmsub.f32",
+     genFuncType<Ty::Real<4>, Ty::Real<4>, Ty::Real<4>, Ty::Real<4>>,
+     genLibCall},
+    {"__ppc_fnmsub", "llvm.ppc.fnmsub.f64",
+     genFuncType<Ty::Real<8>, Ty::Real<8>, Ty::Real<8>, Ty::Real<8>>,
+     genLibCall},
+    {"__ppc_fre", "llvm.ppc.fre", genFuncType<Ty::Real<8>, Ty::Real<8>>,
+     genLibCall},
+    {"__ppc_fres", "llvm.ppc.fres", genFuncType<Ty::Real<4>, Ty::Real<4>>,
+     genLibCall},
+    {"__ppc_frsqrte", "llvm.ppc.frsqrte", genFuncType<Ty::Real<8>, Ty::Real<8>>,
+     genLibCall},
+    {"__ppc_frsqrtes", "llvm.ppc.frsqrtes",
+     genFuncType<Ty::Real<4>, Ty::Real<4>>, genLibCall},
+};
+
+const IntrinsicHandler *findPPCIntrinsicHandler(llvm::StringRef name) {
+  auto compare = [](const IntrinsicHandler &ppcHandler, llvm::StringRef name) {
+    return name.compare(ppcHandler.name) > 0;
+  };
+  auto result = llvm::lower_bound(ppcHandlers, name, compare);
+  return result != std::end(ppcHandlers) && result->name == name ? result
+                                                                 : nullptr;
+}
+
+using RtMap = Fortran::common::StaticMultimapView<MathOperation>;
+static constexpr RtMap ppcMathOps(ppcMathOperations);
+static_assert(ppcMathOps.Verify() && "map must be sorted");
+
+std::pair<const MathOperation *, const MathOperation *>
+checkPPCMathOperationsRange(llvm::StringRef name) {
+  return ppcMathOps.equal_range(name);
+}
+
+//===----------------------------------------------------------------------===//
+// PowerPC specific intrinsic handlers.
+//===----------------------------------------------------------------------===//
+
+// MTFSF, MTFSFI
+template <bool isImm>
+void PPCIntrinsicLibrary::genMtfsf(llvm::ArrayRef<fir::ExtendedValue> args) {
+  assert(args.size() == 2);
+  llvm::SmallVector<mlir::Value> scalarArgs;
+  for (const fir::ExtendedValue &arg : args)
+    if (arg.getUnboxed())
+      scalarArgs.emplace_back(fir::getBase(arg));
+    else
+      mlir::emitError(loc, "nonscalar intrinsic argument");
+
+  mlir::FunctionType libFuncType;
+  mlir::func::FuncOp funcOp;
+  if (isImm) {
+    libFuncType = genFuncType<Ty::Void, Ty::Integer<4>, Ty::Integer<4>>(
+        builder.getContext(), builder);
+    funcOp = builder.addNamedFunction(loc, "llvm.ppc.mtfsfi", libFuncType);
+  } else {
+    libFuncType = genFuncType<Ty::Void, Ty::Integer<4>, Ty::Real<8>>(
+        builder.getContext(), builder);
+    funcOp = builder.addNamedFunction(loc, "llvm.ppc.mtfsf", libFuncType);
+  }
+  builder.create<fir::CallOp>(loc, funcOp, scalarArgs);
+}
+
+// VEC_ADD, VEC_AND, VEC_SUB, VEC_MUL, VEC_XOR
+template <VecOp vop>
+fir::ExtendedValue PPCIntrinsicLibrary::genVecAddAndMulSubXor(
+    mlir::Type resultType, llvm::ArrayRef<fir::ExtendedValue> args) {
+  assert(args.size() == 2);
+  auto argBases{getBasesForArgs(args)};
+  auto argsTy{getTypesForArgs(argBases)};
+  assert(argsTy[0].isa<fir::VectorType>() && argsTy[1].isa<fir::VectorType>());
+
+  auto vecTyInfo{getVecTypeFromFir(argBases[0])};
+
+  const auto isInteger{vecTyInfo.eleTy.isa<mlir::IntegerType>()};
+  const auto isFloat{vecTyInfo.eleTy.isa<mlir::FloatType>()};
+  assert((isInteger || isFloat) && "unknown vector type");
+
+  auto vargs{convertVecArgs(builder, loc, vecTyInfo, argBases)};
+
+  mlir::Value r{nullptr};
+  switch (vop) {
+  case VecOp::Add:
+    if (isInteger)
+      r = builder.create<mlir::arith::AddIOp>(loc, vargs[0], vargs[1]);
+    else if (isFloat)
+      r = builder.create<mlir::arith::AddFOp>(loc, vargs[0], vargs[1]);
+    break;
+  case VecOp::Mul:
+    if (isInteger)
+      r = builder.create<mlir::arith::MulIOp>(loc, vargs[0], vargs[1]);
+    else if (isFloat)
+      r = builder.create<mlir::arith::MulFOp>(loc, vargs[0], vargs[1]);
+    break;
+  case VecOp::Sub:
+    if (isInteger)
+      r = builder.create<mlir::arith::SubIOp>(loc, vargs[0], vargs[1]);
+    else if (isFloat)
+      r = builder.create<mlir::arith::SubFOp>(loc, vargs[0], vargs[1]);
+    break;
+  case VecOp::And:
+  case VecOp::Xor: {
+    mlir::Value arg1{nullptr};
+    mlir::Value arg2{nullptr};
+    if (isInteger) {
+      arg1 = vargs[0];
+      arg2 = vargs[1];
+    } else if (isFloat) {
+      // bitcast the arguments to integer
+      auto wd{vecTyInfo.eleTy.dyn_cast<mlir::FloatType>().getWidth()};
+      auto ftype{builder.getIntegerType(wd)};
+      auto bcVecTy{mlir::VectorType::get(vecTyInfo.len, ftype)};
+      arg1 = builder.create<mlir::vector::BitCastOp>(loc, bcVecTy, vargs[0]);
+      arg2 = builder.create<mlir::vector::BitCastOp>(loc, bcVecTy, vargs[1]);
+    }
+    if (vop == VecOp::And)
+      r = builder.create<mlir::arith::AndIOp>(loc, arg1, arg2);
+    else if (vop == VecOp::Xor)
+      r = builder.create<mlir::arith::XOrIOp>(loc, arg1, arg2);
+
+    if (isFloat)
+      r = builder.create<mlir::vector::BitCastOp>(loc, vargs[0].getType(), r);
+
+    break;
+  }
+  }
+
+  return builder.createConvert(loc, argsTy[0], r);
+}
+
+} // namespace fir


        


More information about the flang-commits mailing list