https://github.com/vzakhari updated https://github.com/llvm/llvm-project/pull/81971
>From c798a2b74df57a1375882fb13a88ccf946f4bfbf Mon Sep 17 00:00:00 2001 From: Slava Zakharin <szakha...@nvidia.com> Date: Thu, 15 Feb 2024 20:01:35 -0800 Subject: [PATCH 1/2] [RFC][flang][runtime] Add FortranFloat128Math wrapper library. Implemented few entry points for REAL(16) math in FortranF128Math static library. It is a thin wrapper around GNU libquadmath. Flang driver can always link it, and the dependencies will be brought in as needed. The final Fortran program/library that uses any of the entry points will depend on the underlying third-party library - this dependency has to be resolved somehow. I added FLANG_RUNTIME_F128_MATH_LIB CMake control so that the compiler driver and the runtime library can be built using the same third-party library: this way the linker knows which dependency to link in (under --as-needed). The compiler distribution should specify which third-party library is required for linking/running the apps that use REAL(16). The compiler package may provide a version of the third-party library or at least a stub library that can be used for linking, but the final program execution will still require the actual library. --- clang/include/clang/Driver/Driver.h | 10 ++ clang/lib/Driver/ToolChains/CommonArgs.cpp | 8 ++ flang/CMakeLists.txt | 17 +++ .../flang/Optimizer/Builder/IntrinsicCall.h | 19 ++-- flang/lib/Optimizer/Builder/IntrinsicCall.cpp | 101 ++++++++++++------ flang/runtime/CMakeLists.txt | 20 ++++ flang/runtime/Float128Math/CMakeLists.txt | 56 ++++++++++ flang/runtime/Float128Math/cabs.cpp | 24 +++++ flang/runtime/Float128Math/math-entries.h | 77 +++++++++++++ flang/runtime/Float128Math/sin.cpp | 22 ++++ flang/runtime/Float128Math/sqrt.cpp | 22 ++++ .../Lower/Intrinsics/missing-math-runtime.f90 | 6 +- flang/tools/flang-driver/driver.cpp | 3 + 13 files changed, 345 insertions(+), 40 deletions(-) create mode 100644 flang/runtime/Float128Math/CMakeLists.txt create mode 100644 flang/runtime/Float128Math/cabs.cpp create mode 100644 flang/runtime/Float128Math/math-entries.h create mode 100644 flang/runtime/Float128Math/sin.cpp create mode 100644 flang/runtime/Float128Math/sqrt.cpp diff --git a/clang/include/clang/Driver/Driver.h b/clang/include/clang/Driver/Driver.h index 908bc87c14b1ca..a5ca637853a6ae 100644 --- a/clang/include/clang/Driver/Driver.h +++ b/clang/include/clang/Driver/Driver.h @@ -251,6 +251,11 @@ class Driver { /// from non-system headers are emitted. HeaderIncludeFilteringKind CCPrintHeadersFiltering = HIFIL_None; + /// Name of the library that provides implementations of + /// IEEE-754 128-bit float math functions used by Fortran F128 + /// runtime library. It should be linked as needed by the linker job. + std::string FlangF128MathLibrary; + /// Set CC_LOG_DIAGNOSTICS mode, which causes the frontend to log diagnostics /// to CCLogDiagnosticsFilename or to stderr, in a stable machine readable /// format. @@ -440,6 +445,11 @@ class Driver { bool offloadHostOnly() const { return Offload == OffloadHost; } bool offloadDeviceOnly() const { return Offload == OffloadDevice; } + void setFlangF128MathLibrary(std::string name) { + FlangF128MathLibrary = std::move(name); + } + StringRef getFlangF128MathLibrary() const { return FlangF128MathLibrary; } + /// Compute the desired OpenMP runtime from the flags provided. OpenMPRuntimeKind getOpenMPRuntime(const llvm::opt::ArgList &Args) const; diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp index 0fd7b8424eb4ba..63d8e2f68f389f 100644 --- a/clang/lib/Driver/ToolChains/CommonArgs.cpp +++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp @@ -1285,6 +1285,14 @@ void tools::addFortranRuntimeLibs(const ToolChain &TC, const ArgList &Args, // add the correct libraries to link against as dependents in the object // file. if (!TC.getTriple().isKnownWindowsMSVCEnvironment()) { + StringRef f128LibName = TC.getDriver().getFlangF128MathLibrary(); + f128LibName.consume_front_insensitive("lib"); + if (!f128LibName.empty()) { + CmdArgs.push_back("-lFortranFloat128"); + addAsNeededOption(TC, Args, CmdArgs, /*as_needed=*/true); + CmdArgs.push_back(Args.MakeArgString("-l" + f128LibName)); + addAsNeededOption(TC, Args, CmdArgs, /*as_needed=*/false); + } CmdArgs.push_back("-lFortranRuntime"); CmdArgs.push_back("-lFortranDecimal"); } diff --git a/flang/CMakeLists.txt b/flang/CMakeLists.txt index f8ad39ba712f8c..21617aeea0215e 100644 --- a/flang/CMakeLists.txt +++ b/flang/CMakeLists.txt @@ -33,6 +33,17 @@ endif() option(FLANG_ENABLE_WERROR "Fail and stop building flang if a warning is triggered." OFF) +# The out of tree builds of the compiler and the Fortran runtime +# must use the same setting of FLANG_RUNTIME_F128_MATH_LIB +# to be composable. Failure to synchronize this setting may result +# in linking errors or fatal failures in F128 runtime functions. +set(FLANG_RUNTIME_F128_MATH_LIB "" CACHE STRING + "Specifies the target library used for implementing IEEE-754 128-bit float \ + math in F18 runtime, e.g. it might be libquadmath for targets where \ + REAL(16) is mapped to __float128, or libm for targets where REAL(16) \ + is mapped to long double, etc." + ) + # Check for a standalone build and configure as appropriate from # there. if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) @@ -321,6 +332,12 @@ if (FLANG_REPOSITORY_STRING) add_definitions(-DFLANG_REPOSITORY_STRING="${FLANG_REPOSITORY_STRING}") endif() +if (FLANG_RUNTIME_F128_MATH_LIB) + add_compile_definitions( + -DFLANG_RUNTIME_F128_MATH_LIB="${FLANG_RUNTIME_F128_MATH_LIB}" + ) +endif() + include(TestBigEndian) test_big_endian(IS_BIGENDIAN) if (IS_BIGENDIAN) diff --git a/flang/include/flang/Optimizer/Builder/IntrinsicCall.h b/flang/include/flang/Optimizer/Builder/IntrinsicCall.h index 3f1e22ecca4ccc..7cb99d61a686ed 100644 --- a/flang/include/flang/Optimizer/Builder/IntrinsicCall.h +++ b/flang/include/flang/Optimizer/Builder/IntrinsicCall.h @@ -494,12 +494,13 @@ struct RuntimeFunction { fir::runtime::FuncTypeBuilderFunc typeGenerator; }; -/// Callback type for generating lowering for a math operation. -using MathGeneratorTy = mlir::Value (*)(fir::FirOpBuilder &, mlir::Location, - llvm::StringRef, mlir::FunctionType, - llvm::ArrayRef<mlir::Value>); - struct MathOperation { + // Callback type for generating lowering for a math operation. + using MathGeneratorTy = mlir::Value (*)(fir::FirOpBuilder &, mlir::Location, + const MathOperation &, + mlir::FunctionType, + llvm::ArrayRef<mlir::Value>); + // Overrides fir::runtime::FuncTypeBuilderFunc to add FirOpBuilder argument. using FuncTypeBuilderFunc = mlir::FunctionType (*)(mlir::MLIRContext *, fir::FirOpBuilder &); @@ -681,25 +682,25 @@ getTypesForArgs(llvm::ArrayRef<mlir::Value> args) { } mlir::Value genLibCall(fir::FirOpBuilder &builder, mlir::Location loc, - llvm::StringRef libFuncName, + const MathOperation &mathOp, mlir::FunctionType libFuncType, llvm::ArrayRef<mlir::Value> args); template <typename T> mlir::Value genMathOp(fir::FirOpBuilder &builder, mlir::Location loc, - llvm::StringRef mathLibFuncName, + const MathOperation &mathOp, mlir::FunctionType mathLibFuncType, llvm::ArrayRef<mlir::Value> args); template <typename T> mlir::Value genComplexMathOp(fir::FirOpBuilder &builder, mlir::Location loc, - llvm::StringRef mathLibFuncName, + const MathOperation &mathOp, mlir::FunctionType mathLibFuncType, llvm::ArrayRef<mlir::Value> args); mlir::Value genLibSplitComplexArgsCall(fir::FirOpBuilder &builder, mlir::Location loc, - llvm::StringRef libFuncName, + const MathOperation &mathOp, mlir::FunctionType libFuncType, llvm::ArrayRef<mlir::Value> args); diff --git a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp index a3536895ca3b7c..bba53bb57bee51 100644 --- a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp +++ b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp @@ -657,10 +657,61 @@ static llvm::cl::opt<bool> "instead of libm complex operations"), llvm::cl::init(false)); +/// Return a string containing the given Fortran intrinsic name +/// with the type of its arguments specified in funcType +/// surrounded by the given prefix/suffix. +static std::string +prettyPrintIntrinsicName(fir::FirOpBuilder &builder, mlir::Location loc, + llvm::StringRef prefix, llvm::StringRef name, + llvm::StringRef suffix, mlir::FunctionType funcType) { + std::string output = prefix.str(); + llvm::raw_string_ostream sstream(output); + if (name == "pow") { + assert(funcType.getNumInputs() == 2 && "power operator has two arguments"); + std::string displayName{" ** "}; + sstream << numericMlirTypeToFortran(builder, funcType.getInput(0), loc, + displayName) + << displayName + << numericMlirTypeToFortran(builder, funcType.getInput(1), loc, + displayName); + } else { + sstream << name.upper() << "("; + if (funcType.getNumInputs() > 0) + sstream << numericMlirTypeToFortran(builder, funcType.getInput(0), loc, + name); + for (mlir::Type argType : funcType.getInputs().drop_front()) { + sstream << ", " << numericMlirTypeToFortran(builder, argType, loc, name); + } + sstream << ")"; + } + sstream << suffix; + return output; +} + +// Generate a call to the Fortran runtime library providing +// support for 128-bit float math via a third-party library. +// If the compiler is built without FLANG_RUNTIME_F128_MATH_LIB, +// this function will report an error. +static mlir::Value genLibF128Call(fir::FirOpBuilder &builder, + mlir::Location loc, + const MathOperation &mathOp, + mlir::FunctionType libFuncType, + llvm::ArrayRef<mlir::Value> args) { +#ifndef FLANG_RUNTIME_F128_MATH_LIB + std::string message = prettyPrintIntrinsicName( + builder, loc, "compiler is built without support for '", mathOp.key, "'", + libFuncType); + fir::emitFatalError(loc, message, /*genCrashDiag=*/false); +#else // FLANG_RUNTIME_F128_MATH_LIB + return genLibCall(builder, loc, libFuncName, libFuncType, args); +#endif // FLANG_RUNTIME_F128_MATH_LIB +} + mlir::Value genLibCall(fir::FirOpBuilder &builder, mlir::Location loc, - llvm::StringRef libFuncName, + const MathOperation &mathOp, mlir::FunctionType libFuncType, llvm::ArrayRef<mlir::Value> args) { + llvm::StringRef libFuncName = mathOp.runtimeFunc; LLVM_DEBUG(llvm::dbgs() << "Generating '" << libFuncName << "' call with type "; libFuncType.dump(); llvm::dbgs() << "\n"); @@ -718,7 +769,7 @@ mlir::Value genLibCall(fir::FirOpBuilder &builder, mlir::Location loc, mlir::Value genLibSplitComplexArgsCall(fir::FirOpBuilder &builder, mlir::Location loc, - llvm::StringRef libFuncName, + const MathOperation &mathOp, mlir::FunctionType libFuncType, llvm::ArrayRef<mlir::Value> args) { assert(args.size() == 2 && "Incorrect #args to genLibSplitComplexArgsCall"); @@ -762,13 +813,12 @@ mlir::Value genLibSplitComplexArgsCall(fir::FirOpBuilder &builder, cplx2, /*isImagPart=*/true); splitArgs.push_back(imag2); - return genLibCall(builder, loc, libFuncName, getSplitComplexArgsType(), - splitArgs); + return genLibCall(builder, loc, mathOp, getSplitComplexArgsType(), splitArgs); } template <typename T> mlir::Value genMathOp(fir::FirOpBuilder &builder, mlir::Location loc, - llvm::StringRef mathLibFuncName, + const MathOperation &mathOp, mlir::FunctionType mathLibFuncType, llvm::ArrayRef<mlir::Value> args) { // TODO: we have to annotate the math operations with flags @@ -791,13 +841,14 @@ mlir::Value genMathOp(fir::FirOpBuilder &builder, mlir::Location loc, // can be also lowered to libm calls for "fast" and "relaxed" // modes. mlir::Value result; + llvm::StringRef mathLibFuncName = mathOp.runtimeFunc; if (mathRuntimeVersion == preciseVersion && // Some operations do not have to be lowered as conservative // calls, since they do not affect strict FP behavior. // For example, purely integer operations like exponentiation // with integer operands fall into this class. !mathLibFuncName.empty()) { - result = genLibCall(builder, loc, mathLibFuncName, mathLibFuncType, args); + result = genLibCall(builder, loc, mathOp, mathLibFuncType, args); } else { LLVM_DEBUG(llvm::dbgs() << "Generating '" << mathLibFuncName << "' operation with type "; @@ -810,7 +861,7 @@ mlir::Value genMathOp(fir::FirOpBuilder &builder, mlir::Location loc, template <typename T> mlir::Value genComplexMathOp(fir::FirOpBuilder &builder, mlir::Location loc, - llvm::StringRef mathLibFuncName, + const MathOperation &mathOp, mlir::FunctionType mathLibFuncType, llvm::ArrayRef<mlir::Value> args) { mlir::Value result; @@ -819,11 +870,12 @@ mlir::Value genComplexMathOp(fir::FirOpBuilder &builder, mlir::Location loc, // If we have libm functions, we can attempt to generate the more precise // version of the complex math operation. + llvm::StringRef mathLibFuncName = mathOp.runtimeFunc; if (!mathLibFuncName.empty()) { // If we enabled MLIR complex or can use approximate operations, we should // NOT use libm. if (!forceMlirComplex && !canUseApprox) { - result = genLibCall(builder, loc, mathLibFuncName, mathLibFuncType, args); + result = genLibCall(builder, loc, mathOp, mathLibFuncType, args); LLVM_DEBUG(result.dump(); llvm::dbgs() << "\n"); return result; } @@ -863,6 +915,10 @@ mlir::Value genComplexMathOp(fir::FirOpBuilder &builder, mlir::Location loc, /// TODO: support remaining Fortran math intrinsics. /// See https://gcc.gnu.org/onlinedocs/gcc-12.1.0/gfortran/\ /// Intrinsic-Procedures.html for a reference. +constexpr auto FuncTypeReal16Real16 = genFuncType<Ty::Real<16>, Ty::Real<16>>; +constexpr auto FuncTypeReal16Complex16 = + genFuncType<Ty::Real<16>, Ty::Complex<16>>; + static constexpr MathOperation mathOperations[] = { {"abs", "fabsf", genFuncType<Ty::Real<4>, Ty::Real<4>>, genMathOp<mlir::math::AbsFOp>}, @@ -874,6 +930,7 @@ static constexpr MathOperation mathOperations[] = { genComplexMathOp<mlir::complex::AbsOp>}, {"abs", "cabs", genFuncType<Ty::Real<8>, Ty::Complex<8>>, genComplexMathOp<mlir::complex::AbsOp>}, + {"abs", RTNAME_STRING(CAbsF128), FuncTypeReal16Complex16, genLibF128Call}, {"acos", "acosf", genFuncType<Ty::Real<4>, Ty::Real<4>>, genLibCall}, {"acos", "acos", genFuncType<Ty::Real<8>, Ty::Real<8>>, genLibCall}, {"acos", "cacosf", genFuncType<Ty::Complex<4>, Ty::Complex<4>>, genLibCall}, @@ -1110,6 +1167,7 @@ static constexpr MathOperation mathOperations[] = { genMathOp<mlir::math::SinOp>}, {"sin", "sin", genFuncType<Ty::Real<8>, Ty::Real<8>>, genMathOp<mlir::math::SinOp>}, + {"sin", RTNAME_STRING(SinF128), FuncTypeReal16Real16, genLibF128Call}, {"sin", "csinf", genFuncType<Ty::Complex<4>, Ty::Complex<4>>, genComplexMathOp<mlir::complex::SinOp>}, {"sin", "csin", genFuncType<Ty::Complex<8>, Ty::Complex<8>>, @@ -1122,6 +1180,7 @@ static constexpr MathOperation mathOperations[] = { genMathOp<mlir::math::SqrtOp>}, {"sqrt", "sqrt", genFuncType<Ty::Real<8>, Ty::Real<8>>, genMathOp<mlir::math::SqrtOp>}, + {"sqrt", RTNAME_STRING(SqrtF128), FuncTypeReal16Real16, genLibF128Call}, {"sqrt", "csqrtf", genFuncType<Ty::Complex<4>, Ty::Complex<4>>, genComplexMathOp<mlir::complex::SqrtOp>}, {"sqrt", "csqrt", genFuncType<Ty::Complex<8>, Ty::Complex<8>>, @@ -1345,27 +1404,9 @@ static void checkPrecisionLoss(llvm::StringRef name, // lowering and could be used here. Emit an error and continue // generating the code with the narrowing cast so that the user // can get a complete list of the problematic intrinsic calls. - std::string message("not yet implemented: no math runtime available for '"); - llvm::raw_string_ostream sstream(message); - if (name == "pow") { - assert(funcType.getNumInputs() == 2 && "power operator has two arguments"); - std::string displayName{" ** "}; - sstream << numericMlirTypeToFortran(builder, funcType.getInput(0), loc, - displayName) - << displayName - << numericMlirTypeToFortran(builder, funcType.getInput(1), loc, - displayName); - } else { - sstream << name.upper() << "("; - if (funcType.getNumInputs() > 0) - sstream << numericMlirTypeToFortran(builder, funcType.getInput(0), loc, - name); - for (mlir::Type argType : funcType.getInputs().drop_front()) { - sstream << ", " << numericMlirTypeToFortran(builder, argType, loc, name); - } - sstream << ")"; - } - sstream << "'"; + std::string message = prettyPrintIntrinsicName( + builder, loc, "not yet implemented: no math runtime available for '", + name, "'", funcType); mlir::emitError(loc, message); } @@ -1887,7 +1928,7 @@ IntrinsicLibrary::getRuntimeCallGenerator(llvm::StringRef name, for (auto [fst, snd] : llvm::zip(actualFuncType.getInputs(), args)) convertedArguments.push_back(builder.createConvert(loc, fst, snd)); mlir::Value result = mathOp->funcGenerator( - builder, loc, mathOp->runtimeFunc, actualFuncType, convertedArguments); + builder, loc, *mathOp, actualFuncType, convertedArguments); mlir::Type soughtType = soughtFuncType.getResult(0); return builder.createConvert(loc, soughtType, result); }; diff --git a/flang/runtime/CMakeLists.txt b/flang/runtime/CMakeLists.txt index dfa9da502db0a8..ac89184a7cbffc 100644 --- a/flang/runtime/CMakeLists.txt +++ b/flang/runtime/CMakeLists.txt @@ -46,6 +46,23 @@ if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) endif () include_directories(BEFORE ${FLANG_SOURCE_DIR}/include) + + # The out of tree builds of the compiler and the Fortran runtime + # must use the same setting of FLANG_RUNTIME_F128_MATH_LIB + # to be composable. Failure to synchronize this setting may result + # in linking errors or fatal failures in F128 runtime functions. + set(FLANG_RUNTIME_F128_MATH_LIB "" CACHE STRING + "Specifies the target library used for implementing IEEE-754 128-bit float \ + math in F18 runtime, e.g. it might be libquadmath for targets where \ + REAL(16) is mapped to __float128, or libm for targets where REAL(16) \ + is mapped to long double, etc." + ) + + if (NOT FLANG_RUNTIME_F128_MATH_LIB STREQUAL "") + add_compile_definitions( + -DFLANG_RUNTIME_F128_MATH_LIB="${FLANG_RUNTIME_F128_MATH_LIB}" + ) + endif() endif() include(CheckCXXSymbolExists) @@ -83,6 +100,9 @@ add_definitions(-U_GLIBCXX_ASSERTIONS) add_definitions(-U_LIBCPP_ENABLE_ASSERTIONS) add_subdirectory(FortranMain) +if (NOT ${FLANG_RUNTIME_F128_MATH_LIB} STREQUAL "") + add_subdirectory(Float128Math) +endif() set(sources ISO_Fortran_binding.cpp diff --git a/flang/runtime/Float128Math/CMakeLists.txt b/flang/runtime/Float128Math/CMakeLists.txt new file mode 100644 index 00000000000000..f8da4d7ca1a9fe --- /dev/null +++ b/flang/runtime/Float128Math/CMakeLists.txt @@ -0,0 +1,56 @@ +#===-- runtime/Float128Math/CMakeLists.txt ---------------------------------===# +# +# 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 +# +#===------------------------------------------------------------------------===# + +# FortranFloat128 implements IEEE-754 128-bit float math functions. +# It is a thin wapper and it currently relies on third-party +# libraries available for the target. +# It is distributed as a static library only. +# Fortran programs/libraries that end up linking any of the provided +# will have a dependency on the third-party library that is being +# used for building this FortranFloat128Math library. + +if (${FLANG_RUNTIME_F128_MATH_LIB} STREQUAL "libquadmath" OR + ${FLANG_RUNTIME_F128_MATH_LIB} STREQUAL "quadmath") + check_include_file(quadmath.h FOUND_QUADMATH_HEADER) + if(FOUND_QUADMATH_HEADER) + add_compile_definitions(HAS_QUADMATHLIB) + else() + message(FATAL_ERROR + "FLANG_RUNTIME_F128_MATH_LIB setting requires quadmath.h " + "to be available: ${FLANG_RUNTIME_F128_MATH_LIB}" + ) + endif() +else() + message(FATAL_ERROR + "Unsupported third-party library for Fortran F128 math runtime: " + "${FLANG_RUNTIME_F128_MATH_LIB}" + ) +endif() + +set(sources + cabs.cpp + sin.cpp + sqrt.cpp + ) + +include_directories(AFTER "${CMAKE_CURRENT_SOURCE_DIR}/..") +add_flang_library(FortranFloat128Math STATIC INSTALL_WITH_TOOLCHAIN ${sources}) + +if (DEFINED MSVC) + set(CMAKE_MSVC_RUNTIME_LIBRARY MultiThreaded) + add_flang_library(FortranFloat128Math.static STATIC INSTALL_WITH_TOOLCHAIN + ${sources} + ) + set(CMAKE_MSVC_RUNTIME_LIBRARY MultiThreadedDebug) + add_flang_library(FortranFloat128Math.static_dbg STATIC INSTALL_WITH_TOOLCHAIN + ${sources} + ) + add_dependencies(FortranFloat128Math FortranFloat128Math.static + FortranFloat128Math.static_dbg + ) +endif() diff --git a/flang/runtime/Float128Math/cabs.cpp b/flang/runtime/Float128Math/cabs.cpp new file mode 100644 index 00000000000000..63f2bdf8e177ae --- /dev/null +++ b/flang/runtime/Float128Math/cabs.cpp @@ -0,0 +1,24 @@ +//===-- runtime/Float128Math/cabs.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 "math-entries.h" + +namespace Fortran::runtime { +extern "C" { + +#if LDBL_MANT_DIG == 113 || HAS_FLOAT128 +// FIXME: the argument should be CppTypeFor<TypeCategory::Complex, 16>, +// and it should be translated into the underlying library's +// corresponding complex128 type. +CppTypeFor<TypeCategory::Real, 16> RTDEF(CAbsF128)(ComplexF128 x) { + return CAbs<RTNAME(CAbsF128)>::invoke(x); +} +#endif + +} // extern "C" +} // namespace Fortran::runtime diff --git a/flang/runtime/Float128Math/math-entries.h b/flang/runtime/Float128Math/math-entries.h new file mode 100644 index 00000000000000..91c14b008b5768 --- /dev/null +++ b/flang/runtime/Float128Math/math-entries.h @@ -0,0 +1,77 @@ +//===-- runtime/Float128Math/math-entries.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 +// +//===----------------------------------------------------------------------===// + +#ifndef FORTRAN_RUNTIME_FLOAT128MATH_MATH_ENTRIES_H_ +#define FORTRAN_RUNTIME_FLOAT128MATH_MATH_ENTRIES_H_ +#include "terminator.h" +#include "tools.h" +#include "flang/Common/float128.h" +#include "flang/Runtime/entry-names.h" +#include <type_traits> + +namespace Fortran::runtime { + +// Define a class template to gracefully fail, when +// there is no specialized template that implements +// the required function via using the third-party +// implementation. +#define DEFINE_FALLBACK(caller) \ + template <auto F> struct caller { \ + template <typename... ATs> \ + [[noreturn]] static std::invoke_result_t<decltype(F), ATs...> invoke( \ + ATs... args) { \ + Terminator terminator{__FILE__, __LINE__}; \ + terminator.Crash("Float128 variant of '%s' is unsupported", #caller); \ + } \ + }; + +// Define template specialization that is calling the third-party +// implementation. The template is specialized by a function pointer +// that is the FortranFloat128Math entry point. The signatures +// of the caller and the callee must match. +// +// Defining the specialization for any target library requires +// adding the generic template via DEFINE_FALLBACK, so that +// a build with another target library that does not define +// the same alias can gracefully fail in runtime. +#define DEFINE_SIMPLE_ALIAS(caller, callee) \ + template <typename RT, typename... ATs, RT (*p)(ATs...)> struct caller<p> { \ + static RT invoke(ATs... args) { \ + static_assert(std::is_invocable_r_v<RT, decltype(callee), ATs...>); \ + if constexpr (std::is_same_v<RT, void>) { \ + callee(args...); \ + } else { \ + return callee(args...); \ + } \ + } \ + }; + +// Define fallback callers. +DEFINE_FALLBACK(CAbs) +DEFINE_FALLBACK(Sin) +DEFINE_FALLBACK(Sqrt) + +// Define ComplexF128 type that is compatible with +// the type of results/arguments of libquadmath. +// TODO: this may need more work for other libraries/compilers. +#if !defined(_ARCH_PPC) || defined(__LONG_DOUBLE_IEEE128__) +typedef _Complex float __attribute__((mode(TC))) ComplexF128; +#else +typedef _Complex float __attribute__((mode(KC))) ComplexF128; +#endif + +#if HAS_QUADMATHLIB +// Define wrapper callers for libquadmath. +#include "quadmath.h" +DEFINE_SIMPLE_ALIAS(CAbs, cabsq) +DEFINE_SIMPLE_ALIAS(Sin, sinq) +DEFINE_SIMPLE_ALIAS(Sqrt, sqrtq) +#endif +} // namespace Fortran::runtime + +#endif // FORTRAN_RUNTIME_FLOAT128MATH_MATH_ENTRIES_H_ diff --git a/flang/runtime/Float128Math/sin.cpp b/flang/runtime/Float128Math/sin.cpp new file mode 100644 index 00000000000000..013eb9d119a6a3 --- /dev/null +++ b/flang/runtime/Float128Math/sin.cpp @@ -0,0 +1,22 @@ +//===-- runtime/Float128Math/sin.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 "math-entries.h" + +namespace Fortran::runtime { +extern "C" { + +#if LDBL_MANT_DIG == 113 || HAS_FLOAT128 +CppTypeFor<TypeCategory::Real, 16> RTDEF(SinF128)( + CppTypeFor<TypeCategory::Real, 16> x) { + return Sin<RTNAME(SinF128)>::invoke(x); +} +#endif + +} // extern "C" +} // namespace Fortran::runtime diff --git a/flang/runtime/Float128Math/sqrt.cpp b/flang/runtime/Float128Math/sqrt.cpp new file mode 100644 index 00000000000000..aafbd850ca973a --- /dev/null +++ b/flang/runtime/Float128Math/sqrt.cpp @@ -0,0 +1,22 @@ +//===-- runtime/Float128Math/sqrt.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 "math-entries.h" + +namespace Fortran::runtime { +extern "C" { + +#if LDBL_MANT_DIG == 113 || HAS_FLOAT128 +CppTypeFor<TypeCategory::Real, 16> RTDEF(SqrtF128)( + CppTypeFor<TypeCategory::Real, 16> x) { + return Sqrt<RTNAME(SqrtF128)>::invoke(x); +} +#endif + +} // extern "C" +} // namespace Fortran::runtime diff --git a/flang/test/Lower/Intrinsics/missing-math-runtime.f90 b/flang/test/Lower/Intrinsics/missing-math-runtime.f90 index 98d3abb17f3a8f..ff767ba18faaec 100644 --- a/flang/test/Lower/Intrinsics/missing-math-runtime.f90 +++ b/flang/test/Lower/Intrinsics/missing-math-runtime.f90 @@ -1,10 +1,14 @@ ! There is no quad math runtime available in lowering ! for now. Test that the TODO are emitted correctly. +! FIXME: the lit config has to flip a feature flag so that +! the tests can use different checks depending on whether +! REAL(16) math support is enabled or not. +! XFAIL: * ! RUN: bbc -emit-fir %s -o /dev/null 2>&1 | FileCheck %s complex(16) :: a real(16) :: b -! CHECK: not yet implemented: no math runtime available for 'ABS(COMPLEX(KIND=16))' +! CHECK: compiler is built without support for 'ABS(COMPLEX(KIND=16))' b = abs(a) end diff --git a/flang/tools/flang-driver/driver.cpp b/flang/tools/flang-driver/driver.cpp index c4e56a862c8613..52136df10c0b02 100644 --- a/flang/tools/flang-driver/driver.cpp +++ b/flang/tools/flang-driver/driver.cpp @@ -130,6 +130,9 @@ int main(int argc, const char **argv) { llvm::sys::getDefaultTargetTriple(), diags, "flang LLVM compiler"); theDriver.setTargetAndMode(targetandMode); +#ifdef FLANG_RUNTIME_F128_MATH_LIB + theDriver.setFlangF128MathLibrary(FLANG_RUNTIME_F128_MATH_LIB); +#endif std::unique_ptr<clang::driver::Compilation> c( theDriver.BuildCompilation(args)); llvm::SmallVector<std::pair<int, const clang::driver::Command *>, 4> >From ca8b5e868225cd2cd5be5a5bc3c65234899eb576 Mon Sep 17 00:00:00 2001 From: Slava Zakharin <szakha...@nvidia.com> Date: Mon, 19 Feb 2024 20:47:35 -0800 Subject: [PATCH 2/2] Fixed FLANG_RUNTIME_F128_MATH_LIB build. --- flang/lib/Optimizer/Builder/IntrinsicCall.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp index bba53bb57bee51..3a82be895d37c4 100644 --- a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp +++ b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp @@ -703,7 +703,7 @@ static mlir::Value genLibF128Call(fir::FirOpBuilder &builder, libFuncType); fir::emitFatalError(loc, message, /*genCrashDiag=*/false); #else // FLANG_RUNTIME_F128_MATH_LIB - return genLibCall(builder, loc, libFuncName, libFuncType, args); + return genLibCall(builder, loc, mathOp, libFuncType, args); #endif // FLANG_RUNTIME_F128_MATH_LIB } _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits