[flang-commits] [flang] 838a4d3 - [Flang] Add PowerPC intrinsics

Kelvin Li via flang-commits flang-commits at lists.llvm.org
Sat Feb 18 08:56:24 PST 2023


Author: Kelvin Li
Date: 2023-02-18T11:56:03-05:00
New Revision: 838a4d348d53234921480eda366fc82af325fe17

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

LOG: [Flang] Add PowerPC intrinsics

This patch adds a subset of PowerPC intrinsics - fmadd,
fmsub, fnmadd and fnmsub.

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

Added: 
    flang/module/__fortran_ppc_intrinsics.f90
    flang/test/Lower/ppc-intrinsics.f90

Modified: 
    flang/include/flang/Semantics/semantics.h
    flang/lib/Optimizer/Builder/IntrinsicCall.cpp
    flang/lib/Semantics/CMakeLists.txt
    flang/lib/Semantics/resolve-names.cpp
    flang/lib/Semantics/semantics.cpp
    flang/tools/f18/CMakeLists.txt

Removed: 
    


################################################################################
diff  --git a/flang/include/flang/Semantics/semantics.h b/flang/include/flang/Semantics/semantics.h
index d37c1f6922ad..1c4654f6438b 100644
--- a/flang/include/flang/Semantics/semantics.h
+++ b/flang/include/flang/Semantics/semantics.h
@@ -216,6 +216,9 @@ class SemanticsContext {
   void UseFortranBuiltinsModule();
   const Scope *GetBuiltinsScope() const { return builtinsScope_; }
 
+  void UsePPCFortranBuiltinsModule();
+  const Scope *GetPPCBuiltinsScope() const { return ppcBuiltinsScope_; }
+
   // Saves a module file's parse tree so that it remains available
   // during semantics.
   parser::Program &SaveParseTree(parser::Program &&);
@@ -276,6 +279,7 @@ class SemanticsContext {
   UnorderedSymbolSet errorSymbols_;
   std::set<std::string> tempNames_;
   const Scope *builtinsScope_{nullptr}; // module __Fortran_builtins
+  const Scope *ppcBuiltinsScope_{nullptr}; // module __Fortran_PPC_intrinsics
   std::list<parser::Program> modFileParseTrees_;
   std::unique_ptr<CommonBlockMap> commonBlockMap_;
   bool anyDefinedIntrinsicOperator_{false};

diff  --git a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
index 49e34e60d3a7..ed8c00b51e30 100644
--- a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
+++ b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
@@ -33,6 +33,7 @@
 #include "flang/Optimizer/Builder/Runtime/Transformational.h"
 #include "flang/Optimizer/Builder/Todo.h"
 #include "flang/Optimizer/Dialect/FIROpsSupport.h"
+#include "flang/Optimizer/Support/FIRContext.h"
 #include "flang/Optimizer/Support/FatalError.h"
 #include "flang/Optimizer/Support/Utils.h"
 #include "flang/Runtime/entry-names.h"
@@ -948,6 +949,16 @@ static mlir::FunctionType genF128F128F128FuncType(mlir::MLIRContext *context) {
   return mlir::FunctionType::get(context, {t, t}, {t});
 }
 
+static mlir::FunctionType genF32F32F32F32FuncType(mlir::MLIRContext *context) {
+  auto t = mlir::FloatType::getF32(context);
+  return mlir::FunctionType::get(context, {t, t, t}, {t});
+}
+
+static mlir::FunctionType genF64F64F64F64FuncType(mlir::MLIRContext *context) {
+  auto t = mlir::FloatType::getF64(context);
+  return mlir::FunctionType::get(context, {t, t, t}, {t});
+}
+
 template <int Bits>
 static mlir::FunctionType genIntF64FuncType(mlir::MLIRContext *context) {
   auto t = mlir::FloatType::getF64(context);
@@ -1329,6 +1340,21 @@ static constexpr MathOperation mathOperations[] = {
      genComplexMathOp<mlir::complex::TanhOp>},
 };
 
+static constexpr MathOperation ppcMathOperations[] = {
+    {"__ppc_fmadd", "llvm.fma.f32", genF32F32F32F32FuncType,
+     genMathOp<mlir::math::FmaOp>},
+    {"__ppc_fmadd", "llvm.fma.f64", genF64F64F64F64FuncType,
+     genMathOp<mlir::math::FmaOp>},
+    {"__ppc_fmsub", "llvm.ppc.fmsubs", genF32F32F32F32FuncType, genLibCall},
+    {"__ppc_fmsub", "llvm.ppc.fmsub", genF64F64F64F64FuncType, genLibCall},
+    {"__ppc_fnmadd", "llvm.ppc.fnmadds", genF32F32F32F32FuncType, genLibCall},
+    {"__ppc_fnmadd", "llvm.ppc.fnmadd", genF64F64F64F64FuncType, genLibCall},
+    {"__ppc_fnmsub", "llvm.ppc.fnmsub.f32", genF32F32F32F32FuncType,
+     genLibCall},
+    {"__ppc_fnmsub", "llvm.ppc.fnmsub.f64", genF64F64F64F64FuncType,
+     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".
@@ -1473,6 +1499,10 @@ 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.
@@ -1490,6 +1520,12 @@ searchMathOperation(fir::FirOpBuilder &builder, llvm::StringRef name,
                     const MathOperation **bestNearMatch,
                     FunctionDistance &bestMatchDistance) {
   auto range = mathOps.equal_range(name);
+  auto mod = builder.getModule();
+
+  // Search ppcMathOps only if targetting PowerPC arch
+  if (fir::getTargetTriple(mod).isPPC() && range.first == range.second) {
+    range = ppcMathOps.equal_range(name);
+  }
   for (auto iter = range.first; iter != range.second && iter; ++iter) {
     const auto &impl = *iter;
     auto implType = impl.typeGenerator(builder.getContext());
@@ -1619,7 +1655,7 @@ mlir::Value toValue(const fir::ExtendedValue &val, fir::FirOpBuilder &builder,
 
 static bool isIntrinsicModuleProcedure(llvm::StringRef name) {
   return name.startswith("c_") || name.startswith("compiler_") ||
-         name.startswith("ieee_");
+         name.startswith("ieee_") || name.startswith("__ppc_");
 }
 
 /// Return the generic name of an intrinsic module procedure specific name.

diff  --git a/flang/lib/Semantics/CMakeLists.txt b/flang/lib/Semantics/CMakeLists.txt
index 54d4787c958a..e8022e1261c8 100644
--- a/flang/lib/Semantics/CMakeLists.txt
+++ b/flang/lib/Semantics/CMakeLists.txt
@@ -57,4 +57,5 @@ add_flang_library(FortranSemantics
   Support
   FrontendOpenMP
   FrontendOpenACC
+  TargetParser
 )

diff  --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp
index fd425147c6c5..edd5a604632d 100644
--- a/flang/lib/Semantics/resolve-names.cpp
+++ b/flang/lib/Semantics/resolve-names.cpp
@@ -7184,6 +7184,12 @@ void ResolveNamesVisitor::HandleProcedureName(
     if (IsIntrinsic(name.source, flag)) {
       symbol =
           &MakeSymbol(InclusiveScope(), name.source, Attrs{Attr::INTRINSIC});
+    } else if (const auto ppcBuiltinScope =
+                   currScope().context().GetPPCBuiltinsScope()) {
+      // Check if it is a builtin from the predefined module
+      symbol = FindSymbol(*ppcBuiltinScope, name);
+      if (!symbol)
+        symbol = &MakeSymbol(context().globalScope(), name.source, Attrs{});
     } else {
       symbol = &MakeSymbol(context().globalScope(), name.source, Attrs{});
     }

diff  --git a/flang/lib/Semantics/semantics.cpp b/flang/lib/Semantics/semantics.cpp
index 20fd0ab6c6d4..65c44336a743 100644
--- a/flang/lib/Semantics/semantics.cpp
+++ b/flang/lib/Semantics/semantics.cpp
@@ -42,6 +42,8 @@
 #include "flang/Semantics/scope.h"
 #include "flang/Semantics/symbol.h"
 #include "llvm/Support/raw_ostream.h"
+#include "llvm/TargetParser/Host.h"
+#include "llvm/TargetParser/Triple.h"
 
 namespace Fortran::semantics {
 
@@ -468,6 +470,12 @@ void SemanticsContext::UseFortranBuiltinsModule() {
   }
 }
 
+void SemanticsContext::UsePPCFortranBuiltinsModule() {
+  if (ppcBuiltinsScope_ == nullptr) {
+    ppcBuiltinsScope_ = GetBuiltinModule("__fortran_ppc_intrinsics");
+  }
+}
+
 parser::Program &SemanticsContext::SaveParseTree(parser::Program &&tree) {
   return modFileParseTrees_.emplace_back(std::move(tree));
 }
@@ -480,11 +488,20 @@ bool Semantics::Perform() {
     const auto *frontModule{std::get_if<common::Indirection<parser::Module>>(
         &program_.v.front().u)};
     if (frontModule &&
-        std::get<parser::Statement<parser::ModuleStmt>>(frontModule->value().t)
-                .statement.v.source == "__fortran_builtins") {
+        (std::get<parser::Statement<parser::ModuleStmt>>(frontModule->value().t)
+                    .statement.v.source == "__fortran_builtins" ||
+            std::get<parser::Statement<parser::ModuleStmt>>(
+                frontModule->value().t)
+                    .statement.v.source == "__fortran_ppc_intrinsics")) {
       // Don't try to read the builtins module when we're actually building it.
     } else {
       context_.UseFortranBuiltinsModule();
+      llvm::Triple targetTriple{llvm::Triple(
+          llvm::Triple::normalize(llvm::sys::getDefaultTargetTriple()))};
+      // Only use __Fortran_PPC_intrinsics module when targetting PowerPC arch
+      if (targetTriple.isPPC()) {
+        context_.UsePPCFortranBuiltinsModule();
+      }
     }
   }
   return ValidateLabels(context_, program_) &&

diff  --git a/flang/module/__fortran_ppc_intrinsics.f90 b/flang/module/__fortran_ppc_intrinsics.f90
new file mode 100644
index 000000000000..9b8323973102
--- /dev/null
+++ b/flang/module/__fortran_ppc_intrinsics.f90
@@ -0,0 +1,55 @@
+!===-- module/__fortran_ppc_intrinsics.f90 ---------------------------------===!
+!
+! 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
+!
+!===------------------------------------------------------------------------===!
+
+module __Fortran_PPC_intrinsics
+
+  private
+
+! fmadd, fmsub, fnmadd, fnmsub
+  abstract interface
+    elemental real(4) function func_r4r4r4r4(a, x, y)
+      real(4), intent(in) :: a, x, y
+    end function func_r4r4r4r4
+    elemental real(8) function func_r8r8r8r8(a, x, y)
+      real(8), intent(in) :: a, x, y
+    end function func_r8r8r8r8
+  end interface
+
+  procedure(func_r4r4r4r4) :: __ppc_fmadd_r4
+  procedure(func_r8r8r8r8) :: __ppc_fmadd_r8
+  interface fmadd
+    procedure :: __ppc_fmadd_r4
+    procedure :: __ppc_fmadd_r8
+  end interface fmadd
+  public :: fmadd
+
+  procedure(func_r4r4r4r4) :: __ppc_fmsub_r4
+  procedure(func_r8r8r8r8) :: __ppc_fmsub_r8
+  interface fmsub
+    procedure :: __ppc_fmsub_r4
+    procedure :: __ppc_fmsub_r8
+  end interface fmsub
+  public :: fmsub
+
+  procedure(func_r4r4r4r4) :: __ppc_fnmadd_r4
+  procedure(func_r8r8r8r8) :: __ppc_fnmadd_r8
+  interface fnmadd
+    procedure :: __ppc_fnmadd_r4
+    procedure :: __ppc_fnmadd_r8
+  end interface fnmadd
+  public :: fnmadd
+
+  procedure(func_r4r4r4r4) :: __ppc_fnmsub_r4
+  procedure(func_r8r8r8r8) :: __ppc_fnmsub_r8
+  interface fnmsub
+    procedure :: __ppc_fnmsub_r4
+    procedure :: __ppc_fnmsub_r8
+  end interface fnmsub
+  public :: fnmsub
+
+end module __Fortran_PPC_intrinsics

diff  --git a/flang/test/Lower/ppc-intrinsics.f90 b/flang/test/Lower/ppc-intrinsics.f90
new file mode 100644
index 000000000000..293a35a63b06
--- /dev/null
+++ b/flang/test/Lower/ppc-intrinsics.f90
@@ -0,0 +1,67 @@
+! RUN: bbc -emit-fir %s -outline-intrinsics -o - | FileCheck --check-prefixes="CHECK-FIR" %s
+! RUN: %flang_fc1 -emit-llvm %s -o - | FileCheck --check-prefixes="CHECK-LLVMIR" %s
+! REQUIRES: target=powerpc{{.*}}
+
+! CHECK-LABEL: fmadd_testr
+subroutine fmadd_testr(a, x, y)
+  real :: a, x, y, z
+  z = fmadd(a, x, y)
+! CHECK-FIR: fir.call @fir.__ppc_fmadd.f32.f32.f32.f32
+! CHECK-LLVMIR: call contract float @llvm.fma.f32(float %{{[0-9]}}, float %{{[0-9]}}, float %{{[0-9]}})
+end
+
+! CHECK-LABEL: fmadd_testd
+subroutine fmadd_testd(a, x, y)
+  real(8) :: a, x, y, z
+  z = fmadd(a, x, y)
+! CHECK-FIR: fir.call @fir.__ppc_fmadd.f64.f64.f64.f64
+! CHECK-LLVMIR: call contract double @llvm.fma.f64(double %{{[0-9]}}, double %{{[0-9]}}, double %{{[0-9]}})
+end
+
+! CHECK-LABEL: fnmadd_testr
+subroutine fnmadd_testr(a, x, y)
+  real :: a, x, y, z
+  z = fnmadd(a, x, y)
+! CHECK-FIR: fir.call @fir.__ppc_fnmadd.f32.f32.f32.f32
+! CHECK-LLVMIR: call contract float @llvm.ppc.fnmadds(float %{{[0-9]}}, float %{{[0-9]}}, float %{{[0-9]}})
+end
+
+! CHECK-LABEL: fnmadd_testd
+subroutine fnmadd_testd(a, x, y)
+  real(8) :: a, x, y, z
+  z = fnmadd(a, x, y)
+! CHECK-FIR: fir.call @fir.__ppc_fnmadd.f64.f64.f64.f64
+! CHECK-LLVMIR: call contract double @llvm.ppc.fnmadd(double %{{[0-9]}}, double %{{[0-9]}}, double %{{[0-9]}})
+end
+
+! CHECK-LABEL: fmsub_testr
+subroutine fmsub_testr(a, x, y)
+  real :: a, x, y, z
+  z = fmsub(a, x, y)
+! CHECK-FIR: fir.call @fir.__ppc_fmsub.f32.f32.f32.f32
+! CHECK-LLVMIR: call contract float @llvm.ppc.fmsubs(float %{{[0-9]}}, float %{{[0-9]}}, float %{{[0-9]}})
+end
+
+! CHECK-LABEL: fmsub_testd
+subroutine fmsub_testd(a, x, y)
+  real(8) :: a, x, y, z
+  z = fmsub(a, x, y)
+! CHECK-FIR: fir.call @fir.__ppc_fmsub.f64.f64.f64.f64
+! CHECK-LLVMIR: call contract double @llvm.ppc.fmsub(double %{{[0-9]}}, double %{{[0-9]}}, double %{{[0-9]}})
+end
+
+! CHECK-LABEL: fnmsub_testr
+subroutine fnmsub_testr(a, x, y)
+  real :: a, x, y, z
+  z = fnmsub(a, x, y)
+! CHECK-FIR: fir.call @fir.__ppc_fnmsub.f32.f32.f32.f32
+! CHECK-LLVMIR: call contract float @llvm.ppc.fnmsub.f32(float %{{[0-9]}}, float %{{[0-9]}}, float %{{[0-9]}})
+end
+
+! CHECK-LABEL: fnmsub_testd
+subroutine fnmsub_testd(a, x, y)
+  real(8) :: a, x, y, z
+  z = fnmsub(a, x, y)
+! CHECK-FIR: fir.call @fir.__ppc_fnmsub.f64.f64.f64.f64
+! CHECK-LLVMIR: call contract double @llvm.ppc.fnmsub.f64(double %{{[0-9]}}, double %{{[0-9]}}, double %{{[0-9]}})
+end

diff  --git a/flang/tools/f18/CMakeLists.txt b/flang/tools/f18/CMakeLists.txt
index b046850557d0..71de5e71ae5e 100644
--- a/flang/tools/f18/CMakeLists.txt
+++ b/flang/tools/f18/CMakeLists.txt
@@ -8,6 +8,7 @@ set(MODULES
   "__fortran_builtins"
   "__fortran_ieee_exceptions"
   "__fortran_type_info"
+  "__fortran_ppc_intrinsics"
   "ieee_arithmetic"
   "ieee_exceptions"
   "ieee_features"
@@ -27,6 +28,8 @@ if (NOT CMAKE_CROSSCOMPILING)
     set(base ${FLANG_INTRINSIC_MODULES_DIR}/${filename})
     if(${filename} STREQUAL "__fortran_builtins")
       set(depends "")
+    elseif(${filename} STREQUAL "__fortran_ppc_intrinsics")
+      set(depends "")
     else()
       set(depends ${FLANG_INTRINSIC_MODULES_DIR}/__fortran_builtins.mod)
       if(NOT ${filename} STREQUAL "__fortran_type_info")


        


More information about the flang-commits mailing list