-
Notifications
You must be signed in to change notification settings - Fork 12k
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
[flang] IEEE_REM #115936
[flang] IEEE_REM #115936
Conversation
Implement the IEEE 60559:2020 remainder function.
@llvm/pr-subscribers-flang-runtime Author: None (vdonaldson) ChangesImplement the IEEE 60559:2020 remainder function. Full diff: https://github.com/llvm/llvm-project/pull/115936.diff 7 Files Affected:
diff --git a/flang/include/flang/Optimizer/Builder/IntrinsicCall.h b/flang/include/flang/Optimizer/Builder/IntrinsicCall.h
index f5fb272b4cc3ed..e83d1a42e34133 100644
--- a/flang/include/flang/Optimizer/Builder/IntrinsicCall.h
+++ b/flang/include/flang/Optimizer/Builder/IntrinsicCall.h
@@ -290,6 +290,7 @@ struct IntrinsicLibrary {
mlir::Value genIeeeQuietCompare(mlir::Type resultType,
llvm::ArrayRef<mlir::Value>);
mlir::Value genIeeeReal(mlir::Type, llvm::ArrayRef<mlir::Value>);
+ mlir::Value genIeeeRem(mlir::Type, llvm::ArrayRef<mlir::Value>);
mlir::Value genIeeeRint(mlir::Type, llvm::ArrayRef<mlir::Value>);
template <bool isFlag>
void genIeeeSetFlagOrHaltingMode(llvm::ArrayRef<fir::ExtendedValue>);
diff --git a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
index 7c7c8ee539111d..a2b327f45c6939 100644
--- a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
+++ b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
@@ -97,7 +97,6 @@ static bool isStaticallyPresent(const fir::ExtendedValue &exv) {
/// IEEE module procedure names not yet implemented for genModuleProcTODO.
static constexpr char ieee_get_underflow_mode[] = "ieee_get_underflow_mode";
-static constexpr char ieee_rem[] = "ieee_rem";
static constexpr char ieee_set_underflow_mode[] = "ieee_set_underflow_mode";
using I = IntrinsicLibrary;
@@ -362,7 +361,7 @@ static constexpr IntrinsicHandler handlers[]{
{"ieee_quiet_lt", &I::genIeeeQuietCompare<mlir::arith::CmpFPredicate::OLT>},
{"ieee_quiet_ne", &I::genIeeeQuietCompare<mlir::arith::CmpFPredicate::UNE>},
{"ieee_real", &I::genIeeeReal},
- {"ieee_rem", &I::genModuleProcTODO<ieee_rem>},
+ {"ieee_rem", &I::genIeeeRem},
{"ieee_rint", &I::genIeeeRint},
{"ieee_round_eq", &I::genIeeeTypeCompare<mlir::arith::CmpIPredicate::eq>},
{"ieee_round_ne", &I::genIeeeTypeCompare<mlir::arith::CmpIPredicate::ne>},
@@ -1298,6 +1297,14 @@ static constexpr MathOperation mathOperations[] = {
genFuncType<Ty::Complex<8>, Ty::Complex<8>, Ty::Integer<8>>, genLibCall},
{"pow", RTNAME_STRING(cqpowk), FuncTypeComplex16Complex16Integer8,
genLibF128Call},
+ {"remainder", "remainderf",
+ genFuncType<Ty::Real<4>, Ty::Real<4>, Ty::Real<4>>, genLibCall},
+ {"remainder", "remainder",
+ genFuncType<Ty::Real<8>, Ty::Real<8>, Ty::Real<8>>, genLibCall},
+ {"remainder", "remainderl",
+ genFuncType<Ty::Real<10>, Ty::Real<10>, Ty::Real<10>>, genLibCall},
+ {"remainder", RTNAME_STRING(RemainderF128), FuncTypeReal16Real16Real16,
+ genLibF128Call},
{"sign", "copysignf", genFuncType<Ty::Real<4>, Ty::Real<4>, Ty::Real<4>>,
genMathOp<mlir::math::CopySignOp>},
{"sign", "copysign", genFuncType<Ty::Real<8>, Ty::Real<8>, Ty::Real<8>>,
@@ -5030,6 +5037,32 @@ mlir::Value IntrinsicLibrary::genIeeeReal(mlir::Type resultType,
return ifOp1.getResult(0);
}
+// IEEE_REM
+mlir::Value IntrinsicLibrary::genIeeeRem(mlir::Type resultType,
+ llvm::ArrayRef<mlir::Value> args) {
+ // Return the remainder of X divided by Y.
+ // Signal IEEE_UNDERFLOW if X is subnormal and Y is infinite.
+ // Signal IEEE_INVALID if X is infinite or Y is zero and neither is a NaN.
+ assert(args.size() == 2);
+ mlir::Value x = args[0];
+ mlir::Value y = args[1];
+ if (mlir::dyn_cast<mlir::FloatType>(resultType).getWidth() < 32) {
+ mlir::Type f32Ty = mlir::FloatType::getF32(builder.getContext());
+ x = builder.create<fir::ConvertOp>(loc, f32Ty, x);
+ y = builder.create<fir::ConvertOp>(loc, f32Ty, y);
+ } else {
+ x = builder.create<fir::ConvertOp>(loc, resultType, x);
+ y = builder.create<fir::ConvertOp>(loc, resultType, y);
+ }
+ // remainder calls do not signal IEEE_UNDERFLOW.
+ mlir::Value underflow = builder.create<mlir::arith::AndIOp>(
+ loc, genIsFPClass(builder.getI1Type(), x, subnormalTest),
+ genIsFPClass(builder.getI1Type(), y, infiniteTest));
+ mlir::Value result = genRuntimeCall("remainder", x.getType(), {x, y});
+ genRaiseExcept(_FORTRAN_RUNTIME_IEEE_UNDERFLOW, underflow);
+ return builder.create<fir::ConvertOp>(loc, resultType, result);
+}
+
// IEEE_RINT
mlir::Value IntrinsicLibrary::genIeeeRint(mlir::Type resultType,
llvm::ArrayRef<mlir::Value> args) {
diff --git a/flang/module/ieee_arithmetic.f90 b/flang/module/ieee_arithmetic.f90
index 0e8d5f1af01e7b..45016e84de7a37 100644
--- a/flang/module/ieee_arithmetic.f90
+++ b/flang/module/ieee_arithmetic.f90
@@ -161,6 +161,11 @@ end function ieee_round_ne
! Define specifics with 1 or 2 INTEGER, LOGICAL, or REAL arguments for
! generic G.
+!
+! The result type of most function specifics is either a fixed type or
+! the type of the first argument. The result type of a SPECIFICS_rRR
+! function call is the highest precision argument type.
+
#define SPECIFICS_I(G) \
G(1) G(2) G(4) G(8) G(16)
#define SPECIFICS_L(G) \
@@ -234,6 +239,13 @@ end function ieee_round_ne
G(8,2) G(8,3) G(8,4) G(8,8) G(8,10) G(8,16) \
G(10,2) G(10,3) G(10,4) G(10,8) G(10,10) G(10,16) \
G(16,2) G(16,3) G(16,4) G(16,8) G(16,10) G(16,16)
+#define SPECIFICS_rRR(G) \
+ G(2,2,2) G(2,2,3) G(4,2,4) G(8,2,8) G(10,2,10) G(16,2,16) \
+ G(2,3,2) G(3,3,3) G(4,3,4) G(8,3,8) G(10,3,10) G(16,3,16) \
+ G(4,4,2) G(4,4,3) G(4,4,4) G(8,4,8) G(10,4,10) G(16,4,16) \
+ G(8,8,2) G(8,8,3) G(8,8,4) G(8,8,8) G(10,8,10) G(16,8,16) \
+ G(10,10,2) G(10,10,3) G(10,10,4) G(10,10,8) G(10,10,10) G(16,10,16) \
+ G(16,16,2) G(16,16,3) G(16,16,4) G(16,16,8) G(16,16,10) G(16,16,16)
#else
#define SPECIFICS_RR(G) \
G(2,2) G(2,3) G(2,4) G(2,8) G(2,16) \
@@ -241,6 +253,12 @@ end function ieee_round_ne
G(4,2) G(4,3) G(4,4) G(4,8) G(4,16) \
G(8,2) G(8,3) G(8,4) G(8,8) G(8,16) \
G(16,2) G(16,3) G(16,4) G(16,8) G(16,16)
+#define SPECIFICS_rRR(G) \
+ G(2,2,2) G(2,2,3) G(4,2,4) G(8,2,8) G(16,2,16) \
+ G(2,3,2) G(3,3,3) G(4,3,4) G(8,3,8) G(16,3,16) \
+ G(4,4,2) G(4,4,3) G(4,4,4) G(8,4,8) G(16,4,16) \
+ G(8,8,2) G(8,8,3) G(8,8,4) G(8,8,8) G(16,8,16) \
+ G(16,16,2) G(16,16,3) G(16,16,4) G(16,16,8) G(16,16,16)
#endif
#else
#if __x86_64__
@@ -250,12 +268,23 @@ end function ieee_round_ne
G(4,2) G(4,3) G(4,4) G(4,8) G(4,10) \
G(8,2) G(8,3) G(8,4) G(8,8) G(8,10) \
G(10,2) G(10,3) G(10,4) G(10,8) G(10,10)
+#define SPECIFICS_rRR(G) \
+ G(2,2,2) G(2,2,3) G(4,2,4) G(8,2,8) G(10,2,10) \
+ G(2,3,2) G(3,3,3) G(4,3,4) G(8,3,8) G(10,3,10) \
+ G(4,4,2) G(4,4,3) G(4,4,4) G(8,4,8) G(10,4,10) \
+ G(8,8,2) G(8,8,3) G(8,8,4) G(8,8,8) G(10,8,10) \
+ G(10,10,2) G(10,10,3) G(10,10,4) G(10,10,8) G(10,10,10)
#else
#define SPECIFICS_RR(G) \
G(2,2) G(2,3) G(2,4) G(2,8) \
G(3,2) G(3,3) G(3,4) G(3,8) \
G(4,2) G(4,3) G(4,4) G(4,8) \
G(8,2) G(8,3) G(8,4) G(8,8)
+#define SPECIFICS_rRR(G) \
+ G(2,2,2) G(2,2,3) G(4,2,4) G(8,2,8) \
+ G(2,3,2) G(3,3,3) G(4,3,4) G(8,3,8) \
+ G(4,4,2) G(4,4,3) G(4,4,4) G(8,4,8) \
+ G(8,8,2) G(8,8,3) G(8,8,4) G(8,8,8)
#endif
#endif
@@ -467,16 +496,16 @@ end function ieee_quiet_ne_a##AKIND;
public :: ieee_quiet_ne
#undef IEEE_QUIET_NE_R
-#define IEEE_REM_RR(XKIND, YKIND) \
- elemental real(XKIND) function ieee_rem_a##XKIND##_a##YKIND(x, y); \
+#define IEEE_REM_rRR(RKIND, XKIND, YKIND) \
+ elemental real(RKIND) function ieee_rem_a##XKIND##_a##YKIND(x, y); \
real(XKIND), intent(in) :: x; \
real(YKIND), intent(in) :: y; \
end function ieee_rem_a##XKIND##_a##YKIND;
interface ieee_rem
- SPECIFICS_RR(IEEE_REM_RR)
+ SPECIFICS_rRR(IEEE_REM_rRR)
end interface ieee_rem
public :: ieee_rem
-#undef IEEE_REM_RR
+#undef IEEE_REM_rRR
#define IEEE_RINT_R(XKIND) \
elemental real(XKIND) function ieee_rint_a##XKIND(x, round); \
diff --git a/flang/runtime/Float128Math/CMakeLists.txt b/flang/runtime/Float128Math/CMakeLists.txt
index c8a51cc2508b9f..703f85fcaf8dac 100644
--- a/flang/runtime/Float128Math/CMakeLists.txt
+++ b/flang/runtime/Float128Math/CMakeLists.txt
@@ -51,6 +51,7 @@ set(sources
norm2.cpp
pow.cpp
random.cpp
+ remainder.cpp
round.cpp
rrspacing.cpp
scale.cpp
diff --git a/flang/runtime/Float128Math/math-entries.h b/flang/runtime/Float128Math/math-entries.h
index 4600c726d72825..a94503fe8e67a0 100644
--- a/flang/runtime/Float128Math/math-entries.h
+++ b/flang/runtime/Float128Math/math-entries.h
@@ -96,6 +96,7 @@ DEFINE_FALLBACK_F128(Nearbyint)
DEFINE_FALLBACK_F128(Nextafter)
DEFINE_FALLBACK_F128(Pow)
DEFINE_FALLBACK_F128(Qnan)
+DEFINE_FALLBACK_F128(Remainder)
DEFINE_FALLBACK_F128(Round)
DEFINE_FALLBACK_F128(Sin)
DEFINE_FALLBACK_F128(Sinh)
@@ -144,6 +145,7 @@ DEFINE_SIMPLE_ALIAS(Lround, lroundq)
DEFINE_SIMPLE_ALIAS(Nearbyint, nearbyintq)
DEFINE_SIMPLE_ALIAS(Nextafter, nextafterq)
DEFINE_SIMPLE_ALIAS(Pow, powq)
+DEFINE_SIMPLE_ALIAS(Remainder, remainderq)
DEFINE_SIMPLE_ALIAS(Round, roundq)
DEFINE_SIMPLE_ALIAS(Sin, sinq)
DEFINE_SIMPLE_ALIAS(Sinh, sinhq)
@@ -196,6 +198,7 @@ DEFINE_SIMPLE_ALIAS(Lround, std::lround)
DEFINE_SIMPLE_ALIAS(Nearbyint, std::nearbyint)
DEFINE_SIMPLE_ALIAS(Nextafter, std::nextafter)
DEFINE_SIMPLE_ALIAS(Pow, std::pow)
+DEFINE_SIMPLE_ALIAS(Remainder, std::remainder)
DEFINE_SIMPLE_ALIAS(Round, std::round)
DEFINE_SIMPLE_ALIAS(Sin, std::sin)
DEFINE_SIMPLE_ALIAS(Sinh, std::sinh)
diff --git a/flang/runtime/Float128Math/remainder.cpp b/flang/runtime/Float128Math/remainder.cpp
new file mode 100644
index 00000000000000..e5c2793dab71af
--- /dev/null
+++ b/flang/runtime/Float128Math/remainder.cpp
@@ -0,0 +1,23 @@
+//===-- runtime/Float128Math/remainder.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 HAS_LDBL128 || HAS_FLOAT128
+CppTypeFor<TypeCategory::Real, 16> RTDEF(RemainderF128)(
+ CppTypeFor<TypeCategory::Real, 16> x,
+ CppTypeFor<TypeCategory::Real, 16> y) {
+ return Remainder<true>::invoke(x, y);
+}
+#endif
+
+} // extern "C"
+} // namespace Fortran::runtime
diff --git a/flang/test/Lower/Intrinsics/ieee_rem.f90 b/flang/test/Lower/Intrinsics/ieee_rem.f90
new file mode 100644
index 00000000000000..f6deebf44715bd
--- /dev/null
+++ b/flang/test/Lower/Intrinsics/ieee_rem.f90
@@ -0,0 +1,86 @@
+! RUN: bbc -emit-hlfir -o - %s | FileCheck %s
+
+! CHECK-LABEL: c.func @_QQmain
+ use ieee_arithmetic, only: ieee_rem
+
+ ! CHECK: %[[V_0:[0-9]+]] = fir.alloca f16 {bindc_name = "x2", uniq_name = "_QFEx2"}
+ ! CHECK: %[[V_1:[0-9]+]]:2 = hlfir.declare %[[V_0]] {uniq_name = "_QFEx2"} : (!fir.ref<f16>) -> (!fir.ref<f16>, !fir.ref<f16>)
+ ! CHECK: %[[V_2:[0-9]+]] = fir.alloca f32 {bindc_name = "x4", uniq_name = "_QFEx4"}
+ ! CHECK: %[[V_3:[0-9]+]]:2 = hlfir.declare %[[V_2]] {uniq_name = "_QFEx4"} : (!fir.ref<f32>) -> (!fir.ref<f32>, !fir.ref<f32>)
+ ! CHECK: %[[V_4:[0-9]+]] = fir.alloca f64 {bindc_name = "x8", uniq_name = "_QFEx8"}
+ ! CHECK: %[[V_5:[0-9]+]]:2 = hlfir.declare %[[V_4]] {uniq_name = "_QFEx8"} : (!fir.ref<f64>) -> (!fir.ref<f64>, !fir.ref<f64>)
+ ! CHECK: %[[V_6:[0-9]+]] = fir.alloca f16 {bindc_name = "y2", uniq_name = "_QFEy2"}
+ ! CHECK: %[[V_7:[0-9]+]]:2 = hlfir.declare %[[V_6]] {uniq_name = "_QFEy2"} : (!fir.ref<f16>) -> (!fir.ref<f16>, !fir.ref<f16>)
+ ! CHECK: %[[V_8:[0-9]+]] = fir.alloca f32 {bindc_name = "y4", uniq_name = "_QFEy4"}
+ ! CHECK: %[[V_9:[0-9]+]]:2 = hlfir.declare %[[V_8]] {uniq_name = "_QFEy4"} : (!fir.ref<f32>) -> (!fir.ref<f32>, !fir.ref<f32>)
+ ! CHECK: %[[V_10:[0-9]+]] = fir.alloca f64 {bindc_name = "y8", uniq_name = "_QFEy8"}
+ ! CHECK: %[[V_11:[0-9]+]]:2 = hlfir.declare %[[V_10]] {uniq_name = "_QFEy8"} : (!fir.ref<f64>) -> (!fir.ref<f64>, !fir.ref<f64>)
+ real(2) :: x2, y2
+ real(4) :: x4, y4
+ real(8) :: x8, y8
+
+ ! CHECK: hlfir.assign %cst{{[_0-9]*}} to %[[V_3]]#0 : f32, !fir.ref<f32>
+ x4 = 3.3_4
+ ! CHECK: hlfir.assign %cst{{[_0-9]*}} to %[[V_9]]#0 : f32, !fir.ref<f32>
+ y4 = -0.0_4
+ ! CHECK: %[[V_12:[0-9]+]] = fir.load %[[V_3]]#0 : !fir.ref<f32>
+ ! CHECK: %[[V_13:[0-9]+]] = fir.load %[[V_9]]#0 : !fir.ref<f32>
+ ! CHECK: %[[V_14:[0-9]+]] = fir.convert %[[V_12]] : (f32) -> f32
+ ! CHECK: %[[V_15:[0-9]+]] = fir.convert %[[V_13]] : (f32) -> f32
+ ! CHECK: %[[V_16:[0-9]+]] = "llvm.intr.is.fpclass"(%[[V_15]]) <{bit = 516 : i32}> : (f32) -> i1
+ ! CHECK: %[[V_17:[0-9]+]] = "llvm.intr.is.fpclass"(%[[V_14]]) <{bit = 144 : i32}> : (f32) -> i1
+ ! CHECK: %[[V_18:[0-9]+]] = arith.andi %[[V_17]], %[[V_16]] : i1
+ ! CHECK: %[[V_19:[0-9]+]] = fir.call @remainderf(%[[V_14]], %[[V_15]]) fastmath<contract> : (f32, f32) -> f32
+ ! CHECK: fir.if %[[V_18]] {
+ ! CHECK: %[[V_40:[0-9]+]] = fir.call @_FortranAMapException(%c16{{.*}}) fastmath<contract> : (i32) -> i32
+ ! CHECK: %[[V_41:[0-9]+]] = fir.call @feraiseexcept(%[[V_40]]) fastmath<contract> : (i32) -> i32
+ ! CHECK: }
+ ! CHECK: %[[V_20:[0-9]+]] = fir.convert %[[V_19]] : (f32) -> f32
+ ! CHECK: hlfir.assign %[[V_20]] to %[[V_3]]#0 : f32, !fir.ref<f32>
+ x4 = ieee_rem(x4, y4)
+! print*, x4
+
+ ! CHECK: hlfir.assign %cst{{[_0-9]*}} to %[[V_1]]#0 : f16, !fir.ref<f16>
+ x2 = 3.0_2
+ ! CHECK: hlfir.assign %cst{{[_0-9]*}} to %[[V_11]]#0 : f64, !fir.ref<f64>
+ y8 = 2.0_8
+ ! CHECK: %[[V_21:[0-9]+]] = fir.load %[[V_1]]#0 : !fir.ref<f16>
+ ! CHECK: %[[V_22:[0-9]+]] = fir.load %[[V_11]]#0 : !fir.ref<f64>
+ ! CHECK: %[[V_23:[0-9]+]] = fir.convert %[[V_21]] : (f16) -> f64
+ ! CHECK: %[[V_24:[0-9]+]] = fir.convert %[[V_22]] : (f64) -> f64
+ ! CHECK: %[[V_25:[0-9]+]] = "llvm.intr.is.fpclass"(%[[V_24]]) <{bit = 516 : i32}> : (f64) -> i1
+ ! CHECK: %[[V_26:[0-9]+]] = "llvm.intr.is.fpclass"(%[[V_23]]) <{bit = 144 : i32}> : (f64) -> i1
+ ! CHECK: %[[V_27:[0-9]+]] = arith.andi %[[V_26]], %[[V_25]] : i1
+ ! CHECK: %[[V_28:[0-9]+]] = fir.call @remainder(%[[V_23]], %[[V_24]]) fastmath<contract> : (f64, f64) -> f64
+ ! CHECK: fir.if %[[V_27]] {
+ ! CHECK: %[[V_40:[0-9]+]] = fir.call @_FortranAMapException(%c16{{.*}}) fastmath<contract> : (i32) -> i32
+ ! CHECK: %[[V_41:[0-9]+]] = fir.call @feraiseexcept(%[[V_40]]) fastmath<contract> : (i32) -> i32
+ ! CHECK: }
+ ! CHECK: %[[V_29:[0-9]+]] = fir.convert %[[V_28]] : (f64) -> f64
+ ! CHECK: %[[V_30:[0-9]+]] = fir.convert %[[V_29]] : (f64) -> f16
+ ! CHECK: hlfir.assign %[[V_30]] to %[[V_1]]#0 : f16, !fir.ref<f16>
+ x2 = ieee_rem(x2, y8)
+! print*, x2
+
+ ! CHECK: hlfir.assign %cst{{[_0-9]*}} to %[[V_5]]#0 : f64, !fir.ref<f64>
+ x8 = huge(x8)
+ ! CHECK: hlfir.assign %cst{{[_0-9]*}} to %[[V_7]]#0 : f16, !fir.ref<f16>
+ y2 = tiny(y2)
+ ! CHECK: %[[V_31:[0-9]+]] = fir.load %[[V_5]]#0 : !fir.ref<f64>
+ ! CHECK: %[[V_32:[0-9]+]] = fir.load %[[V_7]]#0 : !fir.ref<f16>
+ ! CHECK: %[[V_33:[0-9]+]] = fir.convert %[[V_31]] : (f64) -> f64
+ ! CHECK: %[[V_34:[0-9]+]] = fir.convert %[[V_32]] : (f16) -> f64
+ ! CHECK: %[[V_35:[0-9]+]] = "llvm.intr.is.fpclass"(%[[V_34]]) <{bit = 516 : i32}> : (f64) -> i1
+ ! CHECK: %[[V_36:[0-9]+]] = "llvm.intr.is.fpclass"(%[[V_33]]) <{bit = 144 : i32}> : (f64) -> i1
+ ! CHECK: %[[V_37:[0-9]+]] = arith.andi %[[V_36]], %[[V_35]] : i1
+ ! CHECK: %[[V_38:[0-9]+]] = fir.call @remainder(%[[V_33]], %[[V_34]]) fastmath<contract> : (f64, f64) -> f64
+ ! CHECK: fir.if %[[V_37]] {
+ ! CHECK: %[[V_40:[0-9]+]] = fir.call @_FortranAMapException(%c16{{.*}}) fastmath<contract> : (i32) -> i32
+ ! CHECK: %[[V_41:[0-9]+]] = fir.call @feraiseexcept(%[[V_40]]) fastmath<contract> : (i32) -> i32
+ ! CHECK: }
+ ! CHECK: %[[V_39:[0-9]+]] = fir.convert %[[V_38]] : (f64) -> f64
+ ! CHECK: hlfir.assign %[[V_39]] to %[[V_5]]#0 : f64, !fir.ref<f64>
+ x8 = ieee_rem(x8, y2)
+! print*, x8
+
+end
|
@llvm/pr-subscribers-flang-fir-hlfir Author: None (vdonaldson) ChangesImplement the IEEE 60559:2020 remainder function. Full diff: https://github.com/llvm/llvm-project/pull/115936.diff 7 Files Affected:
diff --git a/flang/include/flang/Optimizer/Builder/IntrinsicCall.h b/flang/include/flang/Optimizer/Builder/IntrinsicCall.h
index f5fb272b4cc3ed..e83d1a42e34133 100644
--- a/flang/include/flang/Optimizer/Builder/IntrinsicCall.h
+++ b/flang/include/flang/Optimizer/Builder/IntrinsicCall.h
@@ -290,6 +290,7 @@ struct IntrinsicLibrary {
mlir::Value genIeeeQuietCompare(mlir::Type resultType,
llvm::ArrayRef<mlir::Value>);
mlir::Value genIeeeReal(mlir::Type, llvm::ArrayRef<mlir::Value>);
+ mlir::Value genIeeeRem(mlir::Type, llvm::ArrayRef<mlir::Value>);
mlir::Value genIeeeRint(mlir::Type, llvm::ArrayRef<mlir::Value>);
template <bool isFlag>
void genIeeeSetFlagOrHaltingMode(llvm::ArrayRef<fir::ExtendedValue>);
diff --git a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
index 7c7c8ee539111d..a2b327f45c6939 100644
--- a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
+++ b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
@@ -97,7 +97,6 @@ static bool isStaticallyPresent(const fir::ExtendedValue &exv) {
/// IEEE module procedure names not yet implemented for genModuleProcTODO.
static constexpr char ieee_get_underflow_mode[] = "ieee_get_underflow_mode";
-static constexpr char ieee_rem[] = "ieee_rem";
static constexpr char ieee_set_underflow_mode[] = "ieee_set_underflow_mode";
using I = IntrinsicLibrary;
@@ -362,7 +361,7 @@ static constexpr IntrinsicHandler handlers[]{
{"ieee_quiet_lt", &I::genIeeeQuietCompare<mlir::arith::CmpFPredicate::OLT>},
{"ieee_quiet_ne", &I::genIeeeQuietCompare<mlir::arith::CmpFPredicate::UNE>},
{"ieee_real", &I::genIeeeReal},
- {"ieee_rem", &I::genModuleProcTODO<ieee_rem>},
+ {"ieee_rem", &I::genIeeeRem},
{"ieee_rint", &I::genIeeeRint},
{"ieee_round_eq", &I::genIeeeTypeCompare<mlir::arith::CmpIPredicate::eq>},
{"ieee_round_ne", &I::genIeeeTypeCompare<mlir::arith::CmpIPredicate::ne>},
@@ -1298,6 +1297,14 @@ static constexpr MathOperation mathOperations[] = {
genFuncType<Ty::Complex<8>, Ty::Complex<8>, Ty::Integer<8>>, genLibCall},
{"pow", RTNAME_STRING(cqpowk), FuncTypeComplex16Complex16Integer8,
genLibF128Call},
+ {"remainder", "remainderf",
+ genFuncType<Ty::Real<4>, Ty::Real<4>, Ty::Real<4>>, genLibCall},
+ {"remainder", "remainder",
+ genFuncType<Ty::Real<8>, Ty::Real<8>, Ty::Real<8>>, genLibCall},
+ {"remainder", "remainderl",
+ genFuncType<Ty::Real<10>, Ty::Real<10>, Ty::Real<10>>, genLibCall},
+ {"remainder", RTNAME_STRING(RemainderF128), FuncTypeReal16Real16Real16,
+ genLibF128Call},
{"sign", "copysignf", genFuncType<Ty::Real<4>, Ty::Real<4>, Ty::Real<4>>,
genMathOp<mlir::math::CopySignOp>},
{"sign", "copysign", genFuncType<Ty::Real<8>, Ty::Real<8>, Ty::Real<8>>,
@@ -5030,6 +5037,32 @@ mlir::Value IntrinsicLibrary::genIeeeReal(mlir::Type resultType,
return ifOp1.getResult(0);
}
+// IEEE_REM
+mlir::Value IntrinsicLibrary::genIeeeRem(mlir::Type resultType,
+ llvm::ArrayRef<mlir::Value> args) {
+ // Return the remainder of X divided by Y.
+ // Signal IEEE_UNDERFLOW if X is subnormal and Y is infinite.
+ // Signal IEEE_INVALID if X is infinite or Y is zero and neither is a NaN.
+ assert(args.size() == 2);
+ mlir::Value x = args[0];
+ mlir::Value y = args[1];
+ if (mlir::dyn_cast<mlir::FloatType>(resultType).getWidth() < 32) {
+ mlir::Type f32Ty = mlir::FloatType::getF32(builder.getContext());
+ x = builder.create<fir::ConvertOp>(loc, f32Ty, x);
+ y = builder.create<fir::ConvertOp>(loc, f32Ty, y);
+ } else {
+ x = builder.create<fir::ConvertOp>(loc, resultType, x);
+ y = builder.create<fir::ConvertOp>(loc, resultType, y);
+ }
+ // remainder calls do not signal IEEE_UNDERFLOW.
+ mlir::Value underflow = builder.create<mlir::arith::AndIOp>(
+ loc, genIsFPClass(builder.getI1Type(), x, subnormalTest),
+ genIsFPClass(builder.getI1Type(), y, infiniteTest));
+ mlir::Value result = genRuntimeCall("remainder", x.getType(), {x, y});
+ genRaiseExcept(_FORTRAN_RUNTIME_IEEE_UNDERFLOW, underflow);
+ return builder.create<fir::ConvertOp>(loc, resultType, result);
+}
+
// IEEE_RINT
mlir::Value IntrinsicLibrary::genIeeeRint(mlir::Type resultType,
llvm::ArrayRef<mlir::Value> args) {
diff --git a/flang/module/ieee_arithmetic.f90 b/flang/module/ieee_arithmetic.f90
index 0e8d5f1af01e7b..45016e84de7a37 100644
--- a/flang/module/ieee_arithmetic.f90
+++ b/flang/module/ieee_arithmetic.f90
@@ -161,6 +161,11 @@ end function ieee_round_ne
! Define specifics with 1 or 2 INTEGER, LOGICAL, or REAL arguments for
! generic G.
+!
+! The result type of most function specifics is either a fixed type or
+! the type of the first argument. The result type of a SPECIFICS_rRR
+! function call is the highest precision argument type.
+
#define SPECIFICS_I(G) \
G(1) G(2) G(4) G(8) G(16)
#define SPECIFICS_L(G) \
@@ -234,6 +239,13 @@ end function ieee_round_ne
G(8,2) G(8,3) G(8,4) G(8,8) G(8,10) G(8,16) \
G(10,2) G(10,3) G(10,4) G(10,8) G(10,10) G(10,16) \
G(16,2) G(16,3) G(16,4) G(16,8) G(16,10) G(16,16)
+#define SPECIFICS_rRR(G) \
+ G(2,2,2) G(2,2,3) G(4,2,4) G(8,2,8) G(10,2,10) G(16,2,16) \
+ G(2,3,2) G(3,3,3) G(4,3,4) G(8,3,8) G(10,3,10) G(16,3,16) \
+ G(4,4,2) G(4,4,3) G(4,4,4) G(8,4,8) G(10,4,10) G(16,4,16) \
+ G(8,8,2) G(8,8,3) G(8,8,4) G(8,8,8) G(10,8,10) G(16,8,16) \
+ G(10,10,2) G(10,10,3) G(10,10,4) G(10,10,8) G(10,10,10) G(16,10,16) \
+ G(16,16,2) G(16,16,3) G(16,16,4) G(16,16,8) G(16,16,10) G(16,16,16)
#else
#define SPECIFICS_RR(G) \
G(2,2) G(2,3) G(2,4) G(2,8) G(2,16) \
@@ -241,6 +253,12 @@ end function ieee_round_ne
G(4,2) G(4,3) G(4,4) G(4,8) G(4,16) \
G(8,2) G(8,3) G(8,4) G(8,8) G(8,16) \
G(16,2) G(16,3) G(16,4) G(16,8) G(16,16)
+#define SPECIFICS_rRR(G) \
+ G(2,2,2) G(2,2,3) G(4,2,4) G(8,2,8) G(16,2,16) \
+ G(2,3,2) G(3,3,3) G(4,3,4) G(8,3,8) G(16,3,16) \
+ G(4,4,2) G(4,4,3) G(4,4,4) G(8,4,8) G(16,4,16) \
+ G(8,8,2) G(8,8,3) G(8,8,4) G(8,8,8) G(16,8,16) \
+ G(16,16,2) G(16,16,3) G(16,16,4) G(16,16,8) G(16,16,16)
#endif
#else
#if __x86_64__
@@ -250,12 +268,23 @@ end function ieee_round_ne
G(4,2) G(4,3) G(4,4) G(4,8) G(4,10) \
G(8,2) G(8,3) G(8,4) G(8,8) G(8,10) \
G(10,2) G(10,3) G(10,4) G(10,8) G(10,10)
+#define SPECIFICS_rRR(G) \
+ G(2,2,2) G(2,2,3) G(4,2,4) G(8,2,8) G(10,2,10) \
+ G(2,3,2) G(3,3,3) G(4,3,4) G(8,3,8) G(10,3,10) \
+ G(4,4,2) G(4,4,3) G(4,4,4) G(8,4,8) G(10,4,10) \
+ G(8,8,2) G(8,8,3) G(8,8,4) G(8,8,8) G(10,8,10) \
+ G(10,10,2) G(10,10,3) G(10,10,4) G(10,10,8) G(10,10,10)
#else
#define SPECIFICS_RR(G) \
G(2,2) G(2,3) G(2,4) G(2,8) \
G(3,2) G(3,3) G(3,4) G(3,8) \
G(4,2) G(4,3) G(4,4) G(4,8) \
G(8,2) G(8,3) G(8,4) G(8,8)
+#define SPECIFICS_rRR(G) \
+ G(2,2,2) G(2,2,3) G(4,2,4) G(8,2,8) \
+ G(2,3,2) G(3,3,3) G(4,3,4) G(8,3,8) \
+ G(4,4,2) G(4,4,3) G(4,4,4) G(8,4,8) \
+ G(8,8,2) G(8,8,3) G(8,8,4) G(8,8,8)
#endif
#endif
@@ -467,16 +496,16 @@ end function ieee_quiet_ne_a##AKIND;
public :: ieee_quiet_ne
#undef IEEE_QUIET_NE_R
-#define IEEE_REM_RR(XKIND, YKIND) \
- elemental real(XKIND) function ieee_rem_a##XKIND##_a##YKIND(x, y); \
+#define IEEE_REM_rRR(RKIND, XKIND, YKIND) \
+ elemental real(RKIND) function ieee_rem_a##XKIND##_a##YKIND(x, y); \
real(XKIND), intent(in) :: x; \
real(YKIND), intent(in) :: y; \
end function ieee_rem_a##XKIND##_a##YKIND;
interface ieee_rem
- SPECIFICS_RR(IEEE_REM_RR)
+ SPECIFICS_rRR(IEEE_REM_rRR)
end interface ieee_rem
public :: ieee_rem
-#undef IEEE_REM_RR
+#undef IEEE_REM_rRR
#define IEEE_RINT_R(XKIND) \
elemental real(XKIND) function ieee_rint_a##XKIND(x, round); \
diff --git a/flang/runtime/Float128Math/CMakeLists.txt b/flang/runtime/Float128Math/CMakeLists.txt
index c8a51cc2508b9f..703f85fcaf8dac 100644
--- a/flang/runtime/Float128Math/CMakeLists.txt
+++ b/flang/runtime/Float128Math/CMakeLists.txt
@@ -51,6 +51,7 @@ set(sources
norm2.cpp
pow.cpp
random.cpp
+ remainder.cpp
round.cpp
rrspacing.cpp
scale.cpp
diff --git a/flang/runtime/Float128Math/math-entries.h b/flang/runtime/Float128Math/math-entries.h
index 4600c726d72825..a94503fe8e67a0 100644
--- a/flang/runtime/Float128Math/math-entries.h
+++ b/flang/runtime/Float128Math/math-entries.h
@@ -96,6 +96,7 @@ DEFINE_FALLBACK_F128(Nearbyint)
DEFINE_FALLBACK_F128(Nextafter)
DEFINE_FALLBACK_F128(Pow)
DEFINE_FALLBACK_F128(Qnan)
+DEFINE_FALLBACK_F128(Remainder)
DEFINE_FALLBACK_F128(Round)
DEFINE_FALLBACK_F128(Sin)
DEFINE_FALLBACK_F128(Sinh)
@@ -144,6 +145,7 @@ DEFINE_SIMPLE_ALIAS(Lround, lroundq)
DEFINE_SIMPLE_ALIAS(Nearbyint, nearbyintq)
DEFINE_SIMPLE_ALIAS(Nextafter, nextafterq)
DEFINE_SIMPLE_ALIAS(Pow, powq)
+DEFINE_SIMPLE_ALIAS(Remainder, remainderq)
DEFINE_SIMPLE_ALIAS(Round, roundq)
DEFINE_SIMPLE_ALIAS(Sin, sinq)
DEFINE_SIMPLE_ALIAS(Sinh, sinhq)
@@ -196,6 +198,7 @@ DEFINE_SIMPLE_ALIAS(Lround, std::lround)
DEFINE_SIMPLE_ALIAS(Nearbyint, std::nearbyint)
DEFINE_SIMPLE_ALIAS(Nextafter, std::nextafter)
DEFINE_SIMPLE_ALIAS(Pow, std::pow)
+DEFINE_SIMPLE_ALIAS(Remainder, std::remainder)
DEFINE_SIMPLE_ALIAS(Round, std::round)
DEFINE_SIMPLE_ALIAS(Sin, std::sin)
DEFINE_SIMPLE_ALIAS(Sinh, std::sinh)
diff --git a/flang/runtime/Float128Math/remainder.cpp b/flang/runtime/Float128Math/remainder.cpp
new file mode 100644
index 00000000000000..e5c2793dab71af
--- /dev/null
+++ b/flang/runtime/Float128Math/remainder.cpp
@@ -0,0 +1,23 @@
+//===-- runtime/Float128Math/remainder.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 HAS_LDBL128 || HAS_FLOAT128
+CppTypeFor<TypeCategory::Real, 16> RTDEF(RemainderF128)(
+ CppTypeFor<TypeCategory::Real, 16> x,
+ CppTypeFor<TypeCategory::Real, 16> y) {
+ return Remainder<true>::invoke(x, y);
+}
+#endif
+
+} // extern "C"
+} // namespace Fortran::runtime
diff --git a/flang/test/Lower/Intrinsics/ieee_rem.f90 b/flang/test/Lower/Intrinsics/ieee_rem.f90
new file mode 100644
index 00000000000000..f6deebf44715bd
--- /dev/null
+++ b/flang/test/Lower/Intrinsics/ieee_rem.f90
@@ -0,0 +1,86 @@
+! RUN: bbc -emit-hlfir -o - %s | FileCheck %s
+
+! CHECK-LABEL: c.func @_QQmain
+ use ieee_arithmetic, only: ieee_rem
+
+ ! CHECK: %[[V_0:[0-9]+]] = fir.alloca f16 {bindc_name = "x2", uniq_name = "_QFEx2"}
+ ! CHECK: %[[V_1:[0-9]+]]:2 = hlfir.declare %[[V_0]] {uniq_name = "_QFEx2"} : (!fir.ref<f16>) -> (!fir.ref<f16>, !fir.ref<f16>)
+ ! CHECK: %[[V_2:[0-9]+]] = fir.alloca f32 {bindc_name = "x4", uniq_name = "_QFEx4"}
+ ! CHECK: %[[V_3:[0-9]+]]:2 = hlfir.declare %[[V_2]] {uniq_name = "_QFEx4"} : (!fir.ref<f32>) -> (!fir.ref<f32>, !fir.ref<f32>)
+ ! CHECK: %[[V_4:[0-9]+]] = fir.alloca f64 {bindc_name = "x8", uniq_name = "_QFEx8"}
+ ! CHECK: %[[V_5:[0-9]+]]:2 = hlfir.declare %[[V_4]] {uniq_name = "_QFEx8"} : (!fir.ref<f64>) -> (!fir.ref<f64>, !fir.ref<f64>)
+ ! CHECK: %[[V_6:[0-9]+]] = fir.alloca f16 {bindc_name = "y2", uniq_name = "_QFEy2"}
+ ! CHECK: %[[V_7:[0-9]+]]:2 = hlfir.declare %[[V_6]] {uniq_name = "_QFEy2"} : (!fir.ref<f16>) -> (!fir.ref<f16>, !fir.ref<f16>)
+ ! CHECK: %[[V_8:[0-9]+]] = fir.alloca f32 {bindc_name = "y4", uniq_name = "_QFEy4"}
+ ! CHECK: %[[V_9:[0-9]+]]:2 = hlfir.declare %[[V_8]] {uniq_name = "_QFEy4"} : (!fir.ref<f32>) -> (!fir.ref<f32>, !fir.ref<f32>)
+ ! CHECK: %[[V_10:[0-9]+]] = fir.alloca f64 {bindc_name = "y8", uniq_name = "_QFEy8"}
+ ! CHECK: %[[V_11:[0-9]+]]:2 = hlfir.declare %[[V_10]] {uniq_name = "_QFEy8"} : (!fir.ref<f64>) -> (!fir.ref<f64>, !fir.ref<f64>)
+ real(2) :: x2, y2
+ real(4) :: x4, y4
+ real(8) :: x8, y8
+
+ ! CHECK: hlfir.assign %cst{{[_0-9]*}} to %[[V_3]]#0 : f32, !fir.ref<f32>
+ x4 = 3.3_4
+ ! CHECK: hlfir.assign %cst{{[_0-9]*}} to %[[V_9]]#0 : f32, !fir.ref<f32>
+ y4 = -0.0_4
+ ! CHECK: %[[V_12:[0-9]+]] = fir.load %[[V_3]]#0 : !fir.ref<f32>
+ ! CHECK: %[[V_13:[0-9]+]] = fir.load %[[V_9]]#0 : !fir.ref<f32>
+ ! CHECK: %[[V_14:[0-9]+]] = fir.convert %[[V_12]] : (f32) -> f32
+ ! CHECK: %[[V_15:[0-9]+]] = fir.convert %[[V_13]] : (f32) -> f32
+ ! CHECK: %[[V_16:[0-9]+]] = "llvm.intr.is.fpclass"(%[[V_15]]) <{bit = 516 : i32}> : (f32) -> i1
+ ! CHECK: %[[V_17:[0-9]+]] = "llvm.intr.is.fpclass"(%[[V_14]]) <{bit = 144 : i32}> : (f32) -> i1
+ ! CHECK: %[[V_18:[0-9]+]] = arith.andi %[[V_17]], %[[V_16]] : i1
+ ! CHECK: %[[V_19:[0-9]+]] = fir.call @remainderf(%[[V_14]], %[[V_15]]) fastmath<contract> : (f32, f32) -> f32
+ ! CHECK: fir.if %[[V_18]] {
+ ! CHECK: %[[V_40:[0-9]+]] = fir.call @_FortranAMapException(%c16{{.*}}) fastmath<contract> : (i32) -> i32
+ ! CHECK: %[[V_41:[0-9]+]] = fir.call @feraiseexcept(%[[V_40]]) fastmath<contract> : (i32) -> i32
+ ! CHECK: }
+ ! CHECK: %[[V_20:[0-9]+]] = fir.convert %[[V_19]] : (f32) -> f32
+ ! CHECK: hlfir.assign %[[V_20]] to %[[V_3]]#0 : f32, !fir.ref<f32>
+ x4 = ieee_rem(x4, y4)
+! print*, x4
+
+ ! CHECK: hlfir.assign %cst{{[_0-9]*}} to %[[V_1]]#0 : f16, !fir.ref<f16>
+ x2 = 3.0_2
+ ! CHECK: hlfir.assign %cst{{[_0-9]*}} to %[[V_11]]#0 : f64, !fir.ref<f64>
+ y8 = 2.0_8
+ ! CHECK: %[[V_21:[0-9]+]] = fir.load %[[V_1]]#0 : !fir.ref<f16>
+ ! CHECK: %[[V_22:[0-9]+]] = fir.load %[[V_11]]#0 : !fir.ref<f64>
+ ! CHECK: %[[V_23:[0-9]+]] = fir.convert %[[V_21]] : (f16) -> f64
+ ! CHECK: %[[V_24:[0-9]+]] = fir.convert %[[V_22]] : (f64) -> f64
+ ! CHECK: %[[V_25:[0-9]+]] = "llvm.intr.is.fpclass"(%[[V_24]]) <{bit = 516 : i32}> : (f64) -> i1
+ ! CHECK: %[[V_26:[0-9]+]] = "llvm.intr.is.fpclass"(%[[V_23]]) <{bit = 144 : i32}> : (f64) -> i1
+ ! CHECK: %[[V_27:[0-9]+]] = arith.andi %[[V_26]], %[[V_25]] : i1
+ ! CHECK: %[[V_28:[0-9]+]] = fir.call @remainder(%[[V_23]], %[[V_24]]) fastmath<contract> : (f64, f64) -> f64
+ ! CHECK: fir.if %[[V_27]] {
+ ! CHECK: %[[V_40:[0-9]+]] = fir.call @_FortranAMapException(%c16{{.*}}) fastmath<contract> : (i32) -> i32
+ ! CHECK: %[[V_41:[0-9]+]] = fir.call @feraiseexcept(%[[V_40]]) fastmath<contract> : (i32) -> i32
+ ! CHECK: }
+ ! CHECK: %[[V_29:[0-9]+]] = fir.convert %[[V_28]] : (f64) -> f64
+ ! CHECK: %[[V_30:[0-9]+]] = fir.convert %[[V_29]] : (f64) -> f16
+ ! CHECK: hlfir.assign %[[V_30]] to %[[V_1]]#0 : f16, !fir.ref<f16>
+ x2 = ieee_rem(x2, y8)
+! print*, x2
+
+ ! CHECK: hlfir.assign %cst{{[_0-9]*}} to %[[V_5]]#0 : f64, !fir.ref<f64>
+ x8 = huge(x8)
+ ! CHECK: hlfir.assign %cst{{[_0-9]*}} to %[[V_7]]#0 : f16, !fir.ref<f16>
+ y2 = tiny(y2)
+ ! CHECK: %[[V_31:[0-9]+]] = fir.load %[[V_5]]#0 : !fir.ref<f64>
+ ! CHECK: %[[V_32:[0-9]+]] = fir.load %[[V_7]]#0 : !fir.ref<f16>
+ ! CHECK: %[[V_33:[0-9]+]] = fir.convert %[[V_31]] : (f64) -> f64
+ ! CHECK: %[[V_34:[0-9]+]] = fir.convert %[[V_32]] : (f16) -> f64
+ ! CHECK: %[[V_35:[0-9]+]] = "llvm.intr.is.fpclass"(%[[V_34]]) <{bit = 516 : i32}> : (f64) -> i1
+ ! CHECK: %[[V_36:[0-9]+]] = "llvm.intr.is.fpclass"(%[[V_33]]) <{bit = 144 : i32}> : (f64) -> i1
+ ! CHECK: %[[V_37:[0-9]+]] = arith.andi %[[V_36]], %[[V_35]] : i1
+ ! CHECK: %[[V_38:[0-9]+]] = fir.call @remainder(%[[V_33]], %[[V_34]]) fastmath<contract> : (f64, f64) -> f64
+ ! CHECK: fir.if %[[V_37]] {
+ ! CHECK: %[[V_40:[0-9]+]] = fir.call @_FortranAMapException(%c16{{.*}}) fastmath<contract> : (i32) -> i32
+ ! CHECK: %[[V_41:[0-9]+]] = fir.call @feraiseexcept(%[[V_40]]) fastmath<contract> : (i32) -> i32
+ ! CHECK: }
+ ! CHECK: %[[V_39:[0-9]+]] = fir.convert %[[V_38]] : (f64) -> f64
+ ! CHECK: hlfir.assign %[[V_39]] to %[[V_5]]#0 : f64, !fir.ref<f64>
+ x8 = ieee_rem(x8, y2)
+! print*, x8
+
+end
|
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.
All builds and tests correctly and looks good.
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.
LGTM, thanks!
Implement the IEEE 60559:2020 remainder function.