-
Notifications
You must be signed in to change notification settings - Fork 13.7k
[RFC][flang][runtime] Add FortranFloat128Math wrapper library. #81971
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@llvm/pr-subscribers-clang @llvm/pr-subscribers-flang-runtime Author: Slava Zakharin (vzakhari) ChangesImplemented few entry points for REAL(16) math in FortranF128Math Patch is 27.69 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/81971.diff 13 Files Affected:
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_TO...
[truncated]
|
@llvm/pr-subscribers-flang-fir-hlfir Author: Slava Zakharin (vzakhari) ChangesImplemented few entry points for REAL(16) math in FortranF128Math Patch is 27.69 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/81971.diff 13 Files Affected:
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_TO...
[truncated]
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks a lot for plumbing-in the quadmath runtime and offering ways to customize the builds here. Looks great me!
3aee67f
to
32a034a
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks Slava.
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.
7068006
to
ca8b5e8
Compare
I have been doing some renaming and restructuring before uploading this for review, and I did not test the final version with Thank you all for the reviews! I am going to merge this as soon as CI completes. I decided to keep the |
Follow-up for llvm#81971 to fix the disabled LIT test and add LIT tests for lowering of the added math intrinsics.
Follow-up for llvm#81971 to fix the disabled LIT test and add LIT tests for lowering of the added math intrinsics.
Follow-up for llvm#81971 to fix the disabled LIT test and add LIT tests for lowering of the added math intrinsics.
Follow-up for llvm#81971 to fix the disabled LIT test and add LIT tests for lowering of the added math intrinsics.
I am seeing build errors on systems running cmake versions 3.22.1 and 3.24.3:
Systems running 3.28.1 build without problem. The problem can be resolved by removing the stray '-D' in the call to add_compile_definitions:
|
Remove an extra '-D' in the call to add_compile_definitions. The extra -D causes -D-DFLANG_RUNTIME_F128_MATH_LIB=libquadmath to appear in compile options which results in a compilation failure. This occurs only on systems using cmake versions 3.22.1 or 3.24.3. Using cmake 3.28.1 seems to automatically remove the duplicate -D. Fixes llvm#81971
Remove an extra '-D' in the call to add_compile_definitions. The extra -D causes -D-DFLANG_RUNTIME_F128_MATH_LIB=libquadmath to appear in compile options which results in a compilation failure. This occurs only on systems using cmake versions 3.22.1 or 3.24.3. Using cmake 3.28.1 seems to automatically remove the duplicate -D. Fixes #81971
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.