[flang-commits] [flang] b7c07ce - [flang] Improve runtime interface with C99 complex
Jean Perier via flang-commits
flang-commits at lists.llvm.org
Thu Sep 30 23:47:47 PDT 2021
Author: Jean Perier
Date: 2021-10-01T08:45:24+02:00
New Revision: b7c07ce15ffe6da9dcd69d457a3eca987452edc7
URL: https://github.com/llvm/llvm-project/commit/b7c07ce15ffe6da9dcd69d457a3eca987452edc7
DIFF: https://github.com/llvm/llvm-project/commit/b7c07ce15ffe6da9dcd69d457a3eca987452edc7.diff
LOG: [flang] Improve runtime interface with C99 complex
Follow up of https://reviews.llvm.org/D83397.
In folding, make pgmath usage conditional to C99 complex
support in C++. Disable warning in such case.
In lowering, use an empty class type to indicate C99 complex
type in runtime interface.
Add a unit test enforcing C99 complex can be processed
by FIR runtime interface builder.
Differential Revision: https://reviews.llvm.org/D110860
Added:
flang/unittests/Lower/CMakeLists.txt
flang/unittests/Lower/RTBuilder.cpp
Modified:
flang/include/flang/Evaluate/pgmath.h.inc
flang/lib/Evaluate/CMakeLists.txt
flang/lib/Lower/RTBuilder.h
flang/unittests/CMakeLists.txt
Removed:
################################################################################
diff --git a/flang/include/flang/Evaluate/pgmath.h.inc b/flang/include/flang/Evaluate/pgmath.h.inc
index 02d8ae3c4cd53..f22e6cfeb3a39 100644
--- a/flang/include/flang/Evaluate/pgmath.h.inc
+++ b/flang/include/flang/Evaluate/pgmath.h.inc
@@ -22,6 +22,7 @@
// Control Macros
#ifdef PGMATH_DECLARE
#undef PGMATH_DECLARE
+#define DEFINE_C_COMPLEX_TYPES
#define PGMATH_DECLARE(x) extern "C" x;
#define PGMATH_FAST
#define PGMATH_PRECISE
@@ -33,6 +34,8 @@
#ifdef PGMATH_USE_ALL_TYPES
#define PGMATH_USE_S(name, func) PGMATH_USE_ALL_TYPES(name, func)
#define PGMATH_USE_D(name, func) PGMATH_USE_ALL_TYPES(name, func)
+#define PGMATH_USE_C(name, func) PGMATH_USE_ALL_TYPES(name, func)
+#define PGMATH_USE_Z(name, func) PGMATH_USE_ALL_TYPES(name, func)
#define PGMATH_USE_OTHER(name, func) PGMATH_USE_ALL_TYPES(name, func)
#endif
@@ -56,14 +59,53 @@
#define PGMATH_USE_OTHER(name, x)
#endif
+// Handle the C99 _Complex vs C++ std::complex call interface issue.
+// _Complex and std::complex are layout compatible (they are the same when
+// in memory), but they are not guaranteed to be compatible in call interface
+// (they may be passed/returned
diff erently). For instance on X86 32 bits,
+// float _complex is returned in a pair of register, but std::complex<float>
+// is returned in memory.
+// Pgmath is defined in C using _Complex (and windows _Fcomplex/_DComplex
+// equivalents). Since this file defines the call interface with the runtime
+// for both folding and code generation (through template introspection), it
+// is crucial to make a distinction between std::complex and _Complex here.
+// Unfortunately, _Complex support is not standard in C++.
+// Reserve pgmath usage at compile time (folding) when _Complex is available
+// (cmake is responsible to detect this).
+// For code generation, define type c_float_complex_t that can be used in
+// introspection to indicate that the C99 _Complex ABI has to be used for the
+// related value.
+#ifdef DEFINE_C_COMPLEX_TYPES
+#ifdef PGMATH_LINKING
+#ifdef _WIN32
+using c_float_complex_t = _Fcomplex;
+using c_double_complex_t = _Dcomplex;
+#else
+using c_float_complex_t = float _Complex;
+using c_double_complex_t = double _Complex;
+#endif
+#else
+struct c_float_complex_t {};
+struct c_double_complex_t {};
+#endif
+#endif
+
#define PGMATH_REAL_IMPL(impl, func) \
PGMATH_DECLARE(float __##impl##s_##func##_1(float)) \
PGMATH_DECLARE(double __##impl##d_##func##_1(double)) \
PGMATH_USE_S(func, __##impl##s_##func##_1) \
PGMATH_USE_D(func, __##impl##d_##func##_1)
+#define PGMATH_COMPLEX_IMPL(impl, func) \
+ PGMATH_DECLARE(c_float_complex_t __##impl##c_##func##_1(c_float_complex_t)) \
+ PGMATH_DECLARE( \
+ c_double_complex_t __##impl##z_##func##_1(c_double_complex_t)) \
+ PGMATH_USE_C(func, __##impl##c_##func##_1) \
+ PGMATH_USE_Z(func, __##impl##z_##func##_1)
+
#define PGMATH_ALL_FP_IMPL(impl, func) \
PGMATH_REAL_IMPL(impl, func) \
+ PGMATH_FAST_COMPLEX_IMPL(impl, func)
#define PGMATH_REAL2_IMPL(impl, func) \
PGMATH_DECLARE(float __##impl##s_##func##_1(float, float)) \
@@ -71,8 +113,17 @@
PGMATH_USE_S(func, __##impl##s_##func##_1) \
PGMATH_USE_D(func, __##impl##d_##func##_1)
+#define PGMATH_COMPLEX2_IMPL(impl, func) \
+ PGMATH_DECLARE(c_float_complex_t __##impl##c_##func##_1( \
+ c_float_complex_t, c_float_complex_t)) \
+ PGMATH_DECLARE(c_double_complex_t __##impl##z_##func##_1( \
+ c_double_complex_t, c_double_complex_t)) \
+ PGMATH_USE_C(func, __##impl##c_##func##_1) \
+ PGMATH_USE_Z(func, __##impl##z_##func##_1)
+
#define PGMATH_ALL_FP2_IMPL(impl, func) \
PGMATH_REAL2_IMPL(func) \
+ PGMATH_COMPLEX2_IMPL(func)
#undef PGMATH_FAST_REAL
#undef PGMATH_FAST_COMPLEX
@@ -82,8 +133,10 @@
#undef PGMATH_FAST_ALL_FP2
#ifdef PGMATH_FAST
#define PGMATH_FAST_REAL(func) PGMATH_REAL_IMPL(f, func)
+#define PGMATH_FAST_COMPLEX(func) PGMATH_COMPLEX_IMPL(f, func)
#define PGMATH_FAST_ALL_FP(func) PGMATH_ALL_IMPL(f, func)
#define PGMATH_FAST_REAL2(func) PGMATH_REAL2_IMPL(f, func)
+#define PGMATH_FAST_COMPLEX2(func) PGMATH_COMPLEX2_IMPL(f, func)
#define PGMATH_FAST_ALL_FP2(func) PGMATH_ALL_FP2_IMPL(f, func)
#else
#define PGMATH_FAST_REAL(func)
@@ -102,8 +155,10 @@
#undef PGMATH_RELAXED_ALL_FP2
#ifdef PGMATH_RELAXED
#define PGMATH_RELAXED_REAL(func) PGMATH_REAL_IMPL(r, func)
+#define PGMATH_RELAXED_COMPLEX(func) PGMATH_COMPLEX_IMPL(r, func)
#define PGMATH_RELAXED_ALL_FP(func) PGMATH_ALL_IMPL(r, func)
#define PGMATH_RELAXED_REAL2(func) PGMATH_REAL2_IMPL(r, func)
+#define PGMATH_RELAXED_COMPLEX2(func) PGMATH_COMPLEX2_IMPL(r, func)
#define PGMATH_RELAXED_ALL_FP2(func) PGMATH_ALL_FP2_IMPL(r, func)
#else
#define PGMATH_RELAXED_REAL(func)
@@ -122,8 +177,10 @@
#undef PGMATH_PRECISE_ALL_FP2
#ifdef PGMATH_PRECISE
#define PGMATH_PRECISE_REAL(func) PGMATH_REAL_IMPL(p, func)
+#define PGMATH_PRECISE_COMPLEX(func) PGMATH_COMPLEX_IMPL(p, func)
#define PGMATH_PRECISE_ALL_FP(func) PGMATH_ALL_IMPL(p, func)
#define PGMATH_PRECISE_REAL2(func) PGMATH_REAL2_IMPL(p, func)
+#define PGMATH_PRECISE_COMPLEX2(func) PGMATH_COMPLEX2_IMPL(p, func)
#define PGMATH_PRECISE_ALL_FP2(func) PGMATH_ALL_FP2_IMPL(p, func)
#else
#define PGMATH_PRECISE_REAL(func)
@@ -139,16 +196,28 @@
PGMATH_PRECISE_REAL(func) \
PGMATH_RELAXED_REAL(func)
+#define PGMATH_COMPLEX(func) \
+ PGMATH_FAST_COMPLEX(func) \
+ PGMATH_PRECISE_COMPLEX(func) \
+ PGMATH_RELAXED_COMPLEX(func)
+
#define PGMATH_ALL(func) \
PGMATH_REAL(func) \
+ PGMATH_COMPLEX(func)
#define PGMATH_REAL2(func) \
PGMATH_FAST_REAL2(func) \
PGMATH_PRECISE_REAL2(func) \
PGMATH_RELAXED_REAL2(func)
+#define PGMATH_COMPLEX2(func) \
+ PGMATH_FAST_COMPLEX2(func) \
+ PGMATH_PRECISE_COMPLEX2(func) \
+ PGMATH_RELAXED_COMPLEX2(func)
+
#define PGMATH_ALL2(func) \
PGMATH_REAL2(func) \
+ PGMATH_COMPLEX2(func)
// Marcos to declare __mth_i libpgmath variants
#define PGMATH_MTH_VERSION_REAL(func) \
@@ -207,12 +276,19 @@ PGMATH_ALL2(pow)
#define PGMATH_DELCARE_POW(impl) \
PGMATH_DECLARE(float __##impl##s_powi_1(float, int)) \
PGMATH_DECLARE(double __##impl##d_powi_1(double, int)) \
+ PGMATH_DECLARE(c_float_complex_t __##impl##c_powi_1(c_float_complex_t, int)) \
+ PGMATH_DECLARE( \
+ c_double_complex_t __##impl##z_powi_1(c_double_complex_t, int)) \
PGMATH_USE_S(pow, __##impl##s_powi_1) \
PGMATH_USE_D(pow, __##impl##d_powi_1) \
PGMATH_USE_C(pow, __##impl##c_powi_1) \
PGMATH_USE_Z(pow, __##impl##z_powi_1) \
PGMATH_DECLARE(float __##impl##s_powk_1(float, int64_t)) \
PGMATH_DECLARE(double __##impl##d_powk_1(double, int64_t)) \
+ PGMATH_DECLARE( \
+ c_float_complex_t __##impl##c_powk_1(c_float_complex_t, int64_t)) \
+ PGMATH_DECLARE( \
+ c_double_complex_t __##impl##z_powk_1(c_double_complex_t, int64_t)) \
PGMATH_USE_S(pow, __##impl##s_powk_1) \
PGMATH_USE_D(pow, __##impl##d_powk_1) \
PGMATH_USE_C(pow, __##impl##c_powk_1) \
@@ -237,6 +313,7 @@ PGMATH_USE_OTHER(pow, __mth_i_kpowk)
PGMATH_ALL(sin)
PGMATH_ALL(sinh)
PGMATH_MTH_VERSION_REAL(sqrt)
+PGMATH_COMPLEX(sqrt) // real versions are __mth_i...
PGMATH_ALL(tan)
PGMATH_ALL(tanh)
@@ -250,3 +327,5 @@ PGMATH_ALL(tanh)
#undef PGMATH_USE_Z
#undef PGMATH_USE_OTHER
#undef PGMATH_USE_ALL_TYPES
+#undef PGMATH_LINKING
+#undef DEFINE_C_COMPLEX_TYPES
diff --git a/flang/lib/Evaluate/CMakeLists.txt b/flang/lib/Evaluate/CMakeLists.txt
index 2b8eafafd333d..1bb82ac848310 100644
--- a/flang/lib/Evaluate/CMakeLists.txt
+++ b/flang/lib/Evaluate/CMakeLists.txt
@@ -2,8 +2,18 @@ if (LIBPGMATH_DIR)
# If pgmath library is found, it can be used for constant folding.
find_library(LIBPGMATH pgmath PATHS ${LIBPGMATH_DIR})
if(LIBPGMATH)
- add_compile_definitions(LINK_WITH_LIBPGMATH)
- message(STATUS "Found libpgmath: ${LIBPGMATH}")
+ # pgmath uses _Complex, so only enable linking pgmath with flang in environments
+ # that support it (MSVC is OK, pgmath uses _Fcomplex/_Dcomplex there).
+ if (CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU|MSVC")
+ check_cxx_compiler_flag("-Werror -Wc99-extensions" HAS_WC99_EXTENSIONS_FLAG)
+ if (HAS_WC99_EXTENSIONS_FLAG)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-c99-extensions")
+ endif()
+ add_compile_definitions(LINK_WITH_LIBPGMATH)
+ message(STATUS "Found libpgmath: ${LIBPGMATH}")
+ else()
+ message(STATUS "Libpgmath will not be used because C99 complex is not supported.")
+ endif()
else()
message(STATUS "Libpgmath not found in: ${LIBPGMATH_DIR}")
endif()
diff --git a/flang/lib/Lower/RTBuilder.h b/flang/lib/Lower/RTBuilder.h
index 4b4e63dc3bb30..9f23ea0d31e60 100644
--- a/flang/lib/Lower/RTBuilder.h
+++ b/flang/lib/Lower/RTBuilder.h
@@ -27,6 +27,13 @@
// List the runtime headers we want to be able to dissect
#include "flang/Runtime/io-api.h"
+// Incomplete type indicating C99 complex ABI in interfaces. Beware, _Complex
+// and std::complex are layout compatible, but not compatible in all ABI call
+// interface (e.g. X86 32 bits). _Complex is not standard C++, so do not use
+// it here.
+struct c_float_complex_t;
+struct c_double_complex_t;
+
namespace Fortran::lower {
using TypeBuilderFunc = mlir::Type (*)(mlir::MLIRContext *);
@@ -156,7 +163,18 @@ constexpr TypeBuilderFunc getModel<bool &>() {
return fir::ReferenceType::get(f(context));
};
}
-
+template <>
+constexpr TypeBuilderFunc getModel<c_float_complex_t>() {
+ return [](mlir::MLIRContext *context) -> mlir::Type {
+ return fir::ComplexType::get(context, sizeof(float));
+ };
+}
+template <>
+constexpr TypeBuilderFunc getModel<c_double_complex_t>() {
+ return [](mlir::MLIRContext *context) -> mlir::Type {
+ return fir::ComplexType::get(context, sizeof(double));
+ };
+}
template <>
constexpr TypeBuilderFunc getModel<const Fortran::runtime::Descriptor &>() {
return [](mlir::MLIRContext *context) -> mlir::Type {
diff --git a/flang/unittests/CMakeLists.txt b/flang/unittests/CMakeLists.txt
index 5acebce7192af..95e3f6d611dd6 100644
--- a/flang/unittests/CMakeLists.txt
+++ b/flang/unittests/CMakeLists.txt
@@ -39,5 +39,6 @@ endfunction()
add_subdirectory(Optimizer)
add_subdirectory(Decimal)
add_subdirectory(Evaluate)
+add_subdirectory(Lower)
add_subdirectory(Runtime)
add_subdirectory(Frontend)
diff --git a/flang/unittests/Lower/CMakeLists.txt b/flang/unittests/Lower/CMakeLists.txt
new file mode 100644
index 0000000000000..a3f61f0be5ed9
--- /dev/null
+++ b/flang/unittests/Lower/CMakeLists.txt
@@ -0,0 +1,15 @@
+get_property(dialect_libs GLOBAL PROPERTY MLIR_DIALECT_LIBS)
+
+set(LIBS
+ FIROptimizer
+ MLIRLLVMIR
+ ${dialect_libs}
+)
+
+add_flang_unittest(FlangLoweringTests
+ RTBuilder.cpp
+)
+
+target_link_libraries(FlangLoweringTests
+ PRIVATE
+ ${LIBS})
diff --git a/flang/unittests/Lower/RTBuilder.cpp b/flang/unittests/Lower/RTBuilder.cpp
new file mode 100644
index 0000000000000..9c7238c2cc4d1
--- /dev/null
+++ b/flang/unittests/Lower/RTBuilder.cpp
@@ -0,0 +1,36 @@
+//===- RTBuilder.cpp -- Runtime Interface unit tests ----------------------===//
+//
+// 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 "../../lib/Lower/RTBuilder.h"
+#include "gtest/gtest.h"
+#include "flang/Optimizer/Support/InitFIR.h"
+
+// Check that it is possible to make a
diff erence between complex runtime
+// function using C99 complex and C++ std::complex. This is important since
+// they are layout compatible but not link time compatible (returned
diff erently
+// in X86 32 ABI for instance). At high level fir, we need to convey that the
+// signature are
diff erent regardless of the target ABI.
+
+// Fake runtime header to be introspected.
+c_float_complex_t c99_cacosf(c_float_complex_t);
+
+TEST(RTBuilderTest, ComplexRuntimeInterface) {
+ mlir::DialectRegistry registry;
+ fir::support::registerDialects(registry);
+ mlir::MLIRContext ctx(registry);
+ fir::support::loadDialects(ctx);
+ mlir::Type c99_cacosf_signature{
+ Fortran::lower::RuntimeTableKey<decltype(c99_cacosf)>::getTypeModel()(
+ &ctx)};
+ auto c99_cacosf_funcTy = c99_cacosf_signature.cast<mlir::FunctionType>();
+ EXPECT_EQ(c99_cacosf_funcTy.getNumInputs(), 1u);
+ EXPECT_EQ(c99_cacosf_funcTy.getNumResults(), 1u);
+ auto cplx_ty = fir::ComplexType::get(&ctx, 4);
+ EXPECT_EQ(c99_cacosf_funcTy.getInput(0), cplx_ty);
+ EXPECT_EQ(c99_cacosf_funcTy.getResult(0), cplx_ty);
+}
More information about the flang-commits
mailing list