diff --git a/flang/include/flang/Optimizer/Builder/Runtime/Numeric.h b/flang/include/flang/Optimizer/Builder/Runtime/Numeric.h --- a/flang/include/flang/Optimizer/Builder/Runtime/Numeric.h +++ b/flang/include/flang/Optimizer/Builder/Runtime/Numeric.h @@ -38,6 +38,11 @@ mlir::Value genScale(fir::FirOpBuilder &builder, mlir::Location loc, mlir::Value x, mlir::Value i); +/// Generate call to Selected_real_kind intrinsic runtime routine. +mlir::Value genSelectedRealKind(fir::FirOpBuilder &builder, mlir::Location loc, + mlir::Value precision, mlir::Value range, + mlir::Value radix); + /// Generate call to Set_exponent intrinsic runtime routine. mlir::Value genSetExponent(fir::FirOpBuilder &builder, mlir::Location loc, mlir::Value x, mlir::Value i); diff --git a/flang/include/flang/Runtime/numeric.h b/flang/include/flang/Runtime/numeric.h --- a/flang/include/flang/Runtime/numeric.h +++ b/flang/include/flang/Runtime/numeric.h @@ -355,6 +355,10 @@ CppTypeFor, std::int64_t); #endif +// SELECTED_REAL_KIND +CppTypeFor RTNAME(SelectedRealKind)( + const char *, int, void *, int, void *, int, void *, int); + // SPACING CppTypeFor RTNAME(Spacing4)( CppTypeFor); diff --git a/flang/lib/Lower/IntrinsicCall.cpp b/flang/lib/Lower/IntrinsicCall.cpp --- a/flang/lib/Lower/IntrinsicCall.cpp +++ b/flang/lib/Lower/IntrinsicCall.cpp @@ -545,6 +545,7 @@ llvm::ArrayRef args); mlir::Value genScale(mlir::Type, llvm::ArrayRef); fir::ExtendedValue genScan(mlir::Type, llvm::ArrayRef); + mlir::Value genSelectedRealKind(mlir::Type, llvm::ArrayRef); mlir::Value genSetExponent(mlir::Type resultType, llvm::ArrayRef args); template @@ -919,6 +920,12 @@ {"back", asValue, handleDynamicOptional}, {"kind", asValue}}}, /*isElemental=*/true}, + {"selected_real_kind", + &I::genSelectedRealKind, + {{{"precision", asAddr, handleDynamicOptional}, + {"range", asAddr, handleDynamicOptional}, + {"radix", asAddr, handleDynamicOptional}}}, + /*isElemental=*/false}, {"set_exponent", &I::genSetExponent}, {"shifta", &I::genShift}, {"shiftl", &I::genShift}, @@ -3759,6 +3766,38 @@ return readAndAddCleanUp(resultMutableBox, resultType, "SCAN"); } +// SELECTED_INT_KIND +mlir::Value +IntrinsicLibrary::genSelectedRealKind(mlir::Type resultType, + llvm::ArrayRef args) { + assert(args.size() == 3); + + // Handle optional precision(P) argument + mlir::Value precision = + isStaticallyAbsent(args[0]) + ? builder.create( + loc, fir::ReferenceType::get(builder.getI1Type())) + : fir::getBase(args[0]); + + // Handle optional range(R) argument + mlir::Value range = + isStaticallyAbsent(args[1]) + ? builder.create( + loc, fir::ReferenceType::get(builder.getI1Type())) + : fir::getBase(args[1]); + + // Handle optional radix(RADIX) argument + mlir::Value radix = + isStaticallyAbsent(args[2]) + ? builder.create( + loc, fir::ReferenceType::get(builder.getI1Type())) + : fir::getBase(args[2]); + + return builder.createConvert( + loc, resultType, + fir::runtime::genSelectedRealKind(builder, loc, precision, range, radix)); +} + // SET_EXPONENT mlir::Value IntrinsicLibrary::genSetExponent(mlir::Type resultType, llvm::ArrayRef args) { diff --git a/flang/lib/Optimizer/Builder/Runtime/Numeric.cpp b/flang/lib/Optimizer/Builder/Runtime/Numeric.cpp --- a/flang/lib/Optimizer/Builder/Runtime/Numeric.cpp +++ b/flang/lib/Optimizer/Builder/Runtime/Numeric.cpp @@ -360,6 +360,38 @@ return builder.create(loc, func, args).getResult(0); } +/// Generate call to Selected_real_kind intrinsic runtime routine. +mlir::Value fir::runtime::genSelectedRealKind(fir::FirOpBuilder &builder, + mlir::Location loc, + mlir::Value precision, + mlir::Value range, + mlir::Value radix) { + mlir::func::FuncOp func = + fir::runtime::getRuntimeFunc(loc, builder); + auto fTy = func.getFunctionType(); + auto getArgKinds = [&](mlir::Value arg, int argKindIndex) -> mlir::Value { + if (fir::isa_ref_type(arg.getType())) { + mlir::Type eleTy = fir::unwrapRefType(arg.getType()); + return builder.createIntegerConstant(loc, fTy.getInput(argKindIndex), + eleTy.getIntOrFloatBitWidth() / 8); + } else { + return builder.createIntegerConstant(loc, fTy.getInput(argKindIndex), 0); + } + }; + + auto sourceFile = fir::factory::locationToFilename(builder, loc); + auto sourceLine = + fir::factory::locationToLineNo(builder, loc, fTy.getInput(1)); + mlir::Value pKind = getArgKinds(precision, 3); + mlir::Value rKind = getArgKinds(range, 5); + mlir::Value dKind = getArgKinds(radix, 7); + auto args = fir::runtime::createArguments(builder, loc, fTy, sourceFile, + sourceLine, precision, pKind, range, + rKind, radix, dKind); + + return builder.create(loc, func, args).getResult(0); +} + /// Generate call to Set_exponent instrinsic runtime routine. mlir::Value fir::runtime::genSetExponent(fir::FirOpBuilder &builder, mlir::Location loc, mlir::Value x, diff --git a/flang/runtime/numeric.cpp b/flang/runtime/numeric.cpp --- a/flang/runtime/numeric.cpp +++ b/flang/runtime/numeric.cpp @@ -16,6 +16,38 @@ namespace Fortran::runtime { +template +inline RES getIntArgValue(const char *source, int line, void *arg, int kind, + std::int64_t defaultValue, int resKind) { + RES res; + if (!arg) { + res = static_cast(defaultValue); + } else if (kind == 1) { + res = static_cast( + *static_cast *>(arg)); + } else if (kind == 2) { + res = static_cast( + *static_cast *>(arg)); + } else if (kind == 4) { + res = static_cast( + *static_cast *>(arg)); + } else if (kind == 8) { + res = static_cast( + *static_cast *>(arg)); +#ifdef __SIZEOF_INT128__ + } else if (kind == 16) { + if (resKind != 16) { + Terminator{source, line}.Crash("Unexpected integer kind in runtime"); + } + res = static_cast( + *static_cast *>(arg)); +#endif + } else { + Terminator{source, line}.Crash("Unexpected integer kind in runtime"); + } + return res; +} + // NINT (16.9.141) template inline RESULT Nint(ARG x) { if (x >= 0) { @@ -110,6 +142,54 @@ return std::ldexp(x, p); // x*2**p } +// SELECTED_REAL_KIND (16.9.170) +template +inline CppTypeFor SelectedRealKind(P p, R r, D d) { + if (d != 2) { + return -5; + } + + int error{0}; + int kind{0}; + if (p <= 3) { + kind = 2; + } else if (p <= 6) { + kind = 4; + } else if (p <= 15) { + kind = 8; +#if LDBL_MANT_DIG == 64 + } else if (p <= 18) { + kind = 10; + } else if (p <= 33) { + kind = 16; +#elif LDBL_MANT_DIG == 113 + } else if (p <= 33) { + kind = 16; +#endif + } else { + error -= 1; + } + + if (r <= 4) { + kind = kind < 2 ? 2 : kind; + } else if (r <= 37) { + kind = kind < 3 ? (p == 3 ? 4 : 3) : kind; + } else if (r <= 307) { + kind = kind < 8 ? 8 : kind; +#if LDBL_MANT_DIG == 64 + } else if (r <= 4931) { + kind = kind < 10 ? 10 : kind; +#elif LDBL_MANT_DIG == 113 + } else if (r <= 4931) { + kind = kind < 16 ? 16 : kind; +#endif + } else { + error -= 2; + } + + return error ? error : kind; +} + // SET_EXPONENT (16.9.171) template inline T SetExponent(T x, std::int64_t p) { if (std::isnan(x)) { @@ -714,6 +794,31 @@ } #endif +// SELECTED_REAL_KIND +CppTypeFor RTNAME(SelectedRealKind)( + const char *source, int line, void *precision, int pKind, void *range, + int rKind, void *radix, int dKind) { +#ifdef __SIZEOF_INT128__ + CppTypeFor p = + getIntArgValue>( + source, line, precision, pKind, /*defaultValue*/ 0, /*resKind*/ 16); + CppTypeFor r = + getIntArgValue>( + source, line, range, rKind, /*defaultValue*/ 0, /*resKind*/ 16); + CppTypeFor d = + getIntArgValue>( + source, line, radix, dKind, /*defaultValue*/ 2, /*resKind*/ 16); +#else + std::int64_t p = getIntArgValue( + source, line, precision, pKind, /*defaultValue*/ 0, /*resKind*/ 8); + std::int64_t r = getIntArgValue( + source, line, range, rKind, /*defaultValue*/ 0, /*resKind*/ 8); + std::int64_t d = getIntArgValue( + source, line, radix, dKind, /*defaultValue*/ 2, /*resKind*/ 8); +#endif + return SelectedRealKind(p, r, d); +} + CppTypeFor RTNAME(Spacing4)( CppTypeFor x) { return Spacing<24>(x); diff --git a/flang/test/Lower/Intrinsics/selected_real_kind.f90 b/flang/test/Lower/Intrinsics/selected_real_kind.f90 new file mode 100644 --- /dev/null +++ b/flang/test/Lower/Intrinsics/selected_real_kind.f90 @@ -0,0 +1,174 @@ +! REQUIRES: shell +! RUN: bbc -emit-fir %s -o - | FileCheck %s + +! CHECK-LABEL: func.func @_QPselected_real_kind_test1( +! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref {fir.bindc_name = "p"}, +! CHECK-SAME: %[[VAL_1:.*]]: !fir.ref {fir.bindc_name = "r"}, +! CHECK-SAME: %[[VAL_2:.*]]: !fir.ref {fir.bindc_name = "d"}) { +! CHECK: %[[VAL_3:.*]] = fir.alloca i8 {bindc_name = "res", uniq_name = "_QFselected_real_kind_test1Eres"} +! CHECK: %[[VAL_6:.*]] = arith.constant 1 : i32 +! CHECK: %[[VAL_7:.*]] = arith.constant 1 : i32 +! CHECK: %[[VAL_8:.*]] = arith.constant 1 : i32 +! CHECK: %[[VAL_10:.*]] = fir.convert %[[VAL_0]] : (!fir.ref) -> !fir.llvm_ptr +! CHECK: %[[VAL_11:.*]] = fir.convert %[[VAL_1]] : (!fir.ref) -> !fir.llvm_ptr +! CHECK: %[[VAL_12:.*]] = fir.convert %[[VAL_2]] : (!fir.ref) -> !fir.llvm_ptr +! CHECK: %[[VAL_13:.*]] = fir.call @_FortranASelectedRealKind(%{{.*}}, %{{.*}}, %[[VAL_10]], %[[VAL_6]], %[[VAL_11]], %[[VAL_7]], %[[VAL_12]], %[[VAL_8]]) : (!fir.ref, i32, !fir.llvm_ptr, i32, !fir.llvm_ptr, i32, !fir.llvm_ptr, i32) -> i32 +! CHECK: %[[VAL_14:.*]] = fir.convert %[[VAL_13]] : (i32) -> i8 +! CHECK: fir.store %[[VAL_14]] to %[[VAL_3]] : !fir.ref +! CHECK: return +! CHECK: } + +subroutine selected_real_kind_test1(p, r, d) + integer(1) :: p, r, d, res + res = selected_real_kind(P=p, R=r, RADIX=d) +end + +! CHECK-LABEL: func.func @_QPselected_real_kind_test2( +! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref {fir.bindc_name = "p"}, +! CHECK-SAME: %[[VAL_1:.*]]: !fir.ref {fir.bindc_name = "r"}, +! CHECK-SAME: %[[VAL_2:.*]]: !fir.ref {fir.bindc_name = "d"}) { +! CHECK: %[[VAL_3:.*]] = fir.alloca i16 {bindc_name = "res", uniq_name = "_QFselected_real_kind_test2Eres"} +! CHECK: %[[VAL_6:.*]] = arith.constant 2 : i32 +! CHECK: %[[VAL_7:.*]] = arith.constant 2 : i32 +! CHECK: %[[VAL_8:.*]] = arith.constant 2 : i32 +! CHECK: %[[VAL_10:.*]] = fir.convert %[[VAL_0]] : (!fir.ref) -> !fir.llvm_ptr +! CHECK: %[[VAL_11:.*]] = fir.convert %[[VAL_1]] : (!fir.ref) -> !fir.llvm_ptr +! CHECK: %[[VAL_12:.*]] = fir.convert %[[VAL_2]] : (!fir.ref) -> !fir.llvm_ptr +! CHECK: %[[VAL_13:.*]] = fir.call @_FortranASelectedRealKind(%{{.*}}, %{{.*}}, %[[VAL_10]], %[[VAL_6]], %[[VAL_11]], %[[VAL_7]], %[[VAL_12]], %[[VAL_8]]) : (!fir.ref, i32, !fir.llvm_ptr, i32, !fir.llvm_ptr, i32, !fir.llvm_ptr, i32) -> i32 +! CHECK: %[[VAL_14:.*]] = fir.convert %[[VAL_13]] : (i32) -> i16 +! CHECK: fir.store %[[VAL_14]] to %[[VAL_3]] : !fir.ref +! CHECK: return +! CHECK: } + +subroutine selected_real_kind_test2(p, r, d) + integer(2) :: p, r, d, res + res = selected_real_kind(P=p, R=r, RADIX=d) +end + +! CHECK-LABEL: func.func @_QPselected_real_kind_test4( +! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref {fir.bindc_name = "p"}, +! CHECK-SAME: %[[VAL_1:.*]]: !fir.ref {fir.bindc_name = "r"}, +! CHECK-SAME: %[[VAL_2:.*]]: !fir.ref {fir.bindc_name = "d"}) { +! CHECK: %[[VAL_3:.*]] = fir.alloca i32 {bindc_name = "res", uniq_name = "_QFselected_real_kind_test4Eres"} +! CHECK: %[[VAL_6:.*]] = arith.constant 4 : i32 +! CHECK: %[[VAL_7:.*]] = arith.constant 4 : i32 +! CHECK: %[[VAL_8:.*]] = arith.constant 4 : i32 +! CHECK: %[[VAL_10:.*]] = fir.convert %[[VAL_0]] : (!fir.ref) -> !fir.llvm_ptr +! CHECK: %[[VAL_11:.*]] = fir.convert %[[VAL_1]] : (!fir.ref) -> !fir.llvm_ptr +! CHECK: %[[VAL_12:.*]] = fir.convert %[[VAL_2]] : (!fir.ref) -> !fir.llvm_ptr +! CHECK: %[[VAL_13:.*]] = fir.call @_FortranASelectedRealKind(%{{.*}}, %{{.*}}, %[[VAL_10]], %[[VAL_6]], %[[VAL_11]], %[[VAL_7]], %[[VAL_12]], %[[VAL_8]]) : (!fir.ref, i32, !fir.llvm_ptr, i32, !fir.llvm_ptr, i32, !fir.llvm_ptr, i32) -> i32 +! CHECK: fir.store %[[VAL_13]] to %[[VAL_3]] : !fir.ref +! CHECK: return +! CHECK: } + +subroutine selected_real_kind_test4(p, r, d) + integer(4) :: p, r, d, res + res = selected_real_kind(P=p, R=r, RADIX=d) +end + +! CHECK-LABEL: func.func @_QPselected_real_kind_test8( +! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref {fir.bindc_name = "p"}, +! CHECK-SAME: %[[VAL_1:.*]]: !fir.ref {fir.bindc_name = "r"}, +! CHECK-SAME: %[[VAL_2:.*]]: !fir.ref {fir.bindc_name = "d"}) { +! CHECK: %[[VAL_3:.*]] = fir.alloca i64 {bindc_name = "res", uniq_name = "_QFselected_real_kind_test8Eres"} +! CHECK: %[[VAL_6:.*]] = arith.constant 8 : i32 +! CHECK: %[[VAL_7:.*]] = arith.constant 8 : i32 +! CHECK: %[[VAL_8:.*]] = arith.constant 8 : i32 +! CHECK: %[[VAL_10:.*]] = fir.convert %[[VAL_0]] : (!fir.ref) -> !fir.llvm_ptr +! CHECK: %[[VAL_11:.*]] = fir.convert %[[VAL_1]] : (!fir.ref) -> !fir.llvm_ptr +! CHECK: %[[VAL_12:.*]] = fir.convert %[[VAL_2]] : (!fir.ref) -> !fir.llvm_ptr +! CHECK: %[[VAL_13:.*]] = fir.call @_FortranASelectedRealKind(%{{.*}}, %{{.*}}, %[[VAL_10]], %[[VAL_6]], %[[VAL_11]], %[[VAL_7]], %[[VAL_12]], %[[VAL_8]]) : (!fir.ref, i32, !fir.llvm_ptr, i32, !fir.llvm_ptr, i32, !fir.llvm_ptr, i32) -> i32 +! CHECK: %[[VAL_14:.*]] = fir.convert %[[VAL_13]] : (i32) -> i64 +! CHECK: fir.store %[[VAL_14]] to %[[VAL_3]] : !fir.ref +! CHECK: return +! CHECK: } + +subroutine selected_real_kind_test8(p, r, d) + integer(8) :: p, r, d, res + res = selected_real_kind(P=p, R=r, RADIX=d) +end + +! CHECK-LABEL: func.func @_QPselected_real_kind_test16( +! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref {fir.bindc_name = "p"}, +! CHECK-SAME: %[[VAL_1:.*]]: !fir.ref {fir.bindc_name = "r"}, +! CHECK-SAME: %[[VAL_2:.*]]: !fir.ref {fir.bindc_name = "d"}) { +! CHECK: %[[VAL_3:.*]] = fir.alloca i128 {bindc_name = "res", uniq_name = "_QFselected_real_kind_test16Eres"} +! CHECK: %[[VAL_6:.*]] = arith.constant 16 : i32 +! CHECK: %[[VAL_7:.*]] = arith.constant 16 : i32 +! CHECK: %[[VAL_8:.*]] = arith.constant 16 : i32 +! CHECK: %[[VAL_10:.*]] = fir.convert %[[VAL_0]] : (!fir.ref) -> !fir.llvm_ptr +! CHECK: %[[VAL_11:.*]] = fir.convert %[[VAL_1]] : (!fir.ref) -> !fir.llvm_ptr +! CHECK: %[[VAL_12:.*]] = fir.convert %[[VAL_2]] : (!fir.ref) -> !fir.llvm_ptr +! CHECK: %[[VAL_13:.*]] = fir.call @_FortranASelectedRealKind(%{{.*}}, %{{.*}}, %[[VAL_10]], %[[VAL_6]], %[[VAL_11]], %[[VAL_7]], %[[VAL_12]], %[[VAL_8]]) : (!fir.ref, i32, !fir.llvm_ptr, i32, !fir.llvm_ptr, i32, !fir.llvm_ptr, i32) -> i32 +! CHECK: %[[VAL_14:.*]] = fir.convert %[[VAL_13]] : (i32) -> i128 +! CHECK: fir.store %[[VAL_14]] to %[[VAL_3]] : !fir.ref +! CHECK: return +! CHECK: } + +subroutine selected_real_kind_test16(p, r, d) + integer(16) :: p, r, d, res + res = selected_real_kind(P=p, R=r, RADIX=d) +end + +! CHECK-LABEL: func.func @_QPselected_real_kind_test_rd( +! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref {fir.bindc_name = "r"}, +! CHECK-SAME: %[[VAL_1:.*]]: !fir.ref {fir.bindc_name = "d"}) { +! CHECK: %[[VAL_2:.*]] = fir.alloca i32 {bindc_name = "res", uniq_name = "_QFselected_real_kind_test_rdEres"} +! CHECK: %[[VAL_3:.*]] = fir.absent !fir.ref +! CHECK: %[[VAL_6:.*]] = arith.constant 0 : i32 +! CHECK: %[[VAL_7:.*]] = arith.constant 4 : i32 +! CHECK: %[[VAL_8:.*]] = arith.constant 4 : i32 +! CHECK: %[[VAL_10:.*]] = fir.convert %[[VAL_3]] : (!fir.ref) -> !fir.llvm_ptr +! CHECK: %[[VAL_11:.*]] = fir.convert %[[VAL_0]] : (!fir.ref) -> !fir.llvm_ptr +! CHECK: %[[VAL_12:.*]] = fir.convert %[[VAL_1]] : (!fir.ref) -> !fir.llvm_ptr +! CHECK: %[[VAL_13:.*]] = fir.call @_FortranASelectedRealKind(%{{.*}}, %{{.*}}, %[[VAL_10]], %[[VAL_6]], %[[VAL_11]], %[[VAL_7]], %[[VAL_12]], %[[VAL_8]]) : (!fir.ref, i32, !fir.llvm_ptr, i32, !fir.llvm_ptr, i32, !fir.llvm_ptr, i32) -> i32 +! CHECK: fir.store %[[VAL_13]] to %[[VAL_2]] : !fir.ref +! CHECK: return +! CHECK: } + +subroutine selected_real_kind_test_rd(r, d) + integer :: r, d, res + res = selected_real_kind(R=r, RADIX=d) +end + +! CHECK-LABEL: func.func @_QPselected_real_kind_test_pd( +! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref {fir.bindc_name = "p"}, +! CHECK-SAME: %[[VAL_1:.*]]: !fir.ref {fir.bindc_name = "d"}) { +! CHECK: %[[VAL_2:.*]] = fir.alloca i32 {bindc_name = "res", uniq_name = "_QFselected_real_kind_test_pdEres"} +! CHECK: %[[VAL_3:.*]] = fir.absent !fir.ref +! CHECK: %[[VAL_6:.*]] = arith.constant 4 : i32 +! CHECK: %[[VAL_7:.*]] = arith.constant 0 : i32 +! CHECK: %[[VAL_8:.*]] = arith.constant 4 : i32 +! CHECK: %[[VAL_10:.*]] = fir.convert %[[VAL_0]] : (!fir.ref) -> !fir.llvm_ptr +! CHECK: %[[VAL_11:.*]] = fir.convert %[[VAL_3]] : (!fir.ref) -> !fir.llvm_ptr +! CHECK: %[[VAL_12:.*]] = fir.convert %[[VAL_1]] : (!fir.ref) -> !fir.llvm_ptr +! CHECK: %[[VAL_13:.*]] = fir.call @_FortranASelectedRealKind(%{{.*}}, %{{.*}}, %[[VAL_10]], %[[VAL_6]], %[[VAL_11]], %[[VAL_7]], %[[VAL_12]], %[[VAL_8]]) : (!fir.ref, i32, !fir.llvm_ptr, i32, !fir.llvm_ptr, i32, !fir.llvm_ptr, i32) -> i32 +! CHECK: fir.store %[[VAL_13]] to %[[VAL_2]] : !fir.ref +! CHECK: return +! CHECK: } + +subroutine selected_real_kind_test_pd(p, d) + integer :: p, d, res + res = selected_real_kind(P=p, RADIX=d) +end + +! CHECK-LABEL: func.func @_QPselected_real_kind_test_pr( +! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref {fir.bindc_name = "p"}, +! CHECK-SAME: %[[VAL_1:.*]]: !fir.ref {fir.bindc_name = "r"}) { +! CHECK: %[[VAL_2:.*]] = fir.alloca i32 {bindc_name = "res", uniq_name = "_QFselected_real_kind_test_prEres"} +! CHECK: %[[VAL_3:.*]] = fir.absent !fir.ref +! CHECK: %[[VAL_6:.*]] = arith.constant 4 : i32 +! CHECK: %[[VAL_7:.*]] = arith.constant 4 : i32 +! CHECK: %[[VAL_8:.*]] = arith.constant 0 : i32 +! CHECK: %[[VAL_10:.*]] = fir.convert %[[VAL_0]] : (!fir.ref) -> !fir.llvm_ptr +! CHECK: %[[VAL_11:.*]] = fir.convert %[[VAL_1]] : (!fir.ref) -> !fir.llvm_ptr +! CHECK: %[[VAL_12:.*]] = fir.convert %[[VAL_3]] : (!fir.ref) -> !fir.llvm_ptr +! CHECK: %[[VAL_13:.*]] = fir.call @_FortranASelectedRealKind(%{{.*}}, %{{.*}}, %[[VAL_10]], %[[VAL_6]], %[[VAL_11]], %[[VAL_7]], %[[VAL_12]], %[[VAL_8]]) : (!fir.ref, i32, !fir.llvm_ptr, i32, !fir.llvm_ptr, i32, !fir.llvm_ptr, i32) -> i32 +! CHECK: fir.store %[[VAL_13]] to %[[VAL_2]] : !fir.ref +! CHECK: return +! CHECK: } + +subroutine selected_real_kind_test_pr(p, r) + integer :: p, r, res + res = selected_real_kind(P=p, R=r) +end diff --git a/flang/unittests/Runtime/Numeric.cpp b/flang/unittests/Runtime/Numeric.cpp --- a/flang/unittests/Runtime/Numeric.cpp +++ b/flang/unittests/Runtime/Numeric.cpp @@ -130,6 +130,58 @@ RTNAME(SetExponent8)(std::numeric_limits>::quiet_NaN(), 1))); } +TEST(Numeric, SelectedRealKind) { + std::int8_t p_s = 1; + std::int16_t p[11] = {-10, 1, 1, 4, 50, 1, 1, 4, 1, 1, 50}; + std::int32_t r[11] = {-1, 1, 1, 1, 2, 1, 20, 20, 100, 5000, 5000}; + std::int64_t d[11] = {2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2}; + EXPECT_EQ(RTNAME(SelectedRealKind)( + __FILE__, __LINE__, &p[0], 2, &r[0], 4, &d[0], 8), + 2); + EXPECT_EQ(RTNAME(SelectedRealKind)( + __FILE__, __LINE__, &p[1], 2, &r[1], 4, &d[1], 8), + -5); + EXPECT_EQ(RTNAME(SelectedRealKind)( + __FILE__, __LINE__, &p[2], 2, &r[2], 4, &d[2], 8), + 2); + EXPECT_EQ(RTNAME(SelectedRealKind)( + __FILE__, __LINE__, &p[3], 2, &r[3], 4, &d[3], 8), + 4); + EXPECT_EQ(RTNAME(SelectedRealKind)( + __FILE__, __LINE__, &p[4], 2, &r[4], 4, &d[4], 8), + -1); + EXPECT_EQ(RTNAME(SelectedRealKind)( + __FILE__, __LINE__, &p[5], 2, &r[5], 4, &d[5], 8), + 2); + EXPECT_EQ(RTNAME(SelectedRealKind)( + __FILE__, __LINE__, &p[6], 2, &r[6], 4, &d[6], 8), + 3); + EXPECT_EQ(RTNAME(SelectedRealKind)( + __FILE__, __LINE__, &p[7], 2, &r[7], 4, &d[7], 8), + 4); + EXPECT_EQ(RTNAME(SelectedRealKind)( + __FILE__, __LINE__, &p[8], 2, &r[8], 4, &d[8], 8), + 8); + EXPECT_EQ(RTNAME(SelectedRealKind)( + __FILE__, __LINE__, &p[9], 2, &r[9], 4, &d[9], 8), + -2); + EXPECT_EQ(RTNAME(SelectedRealKind)( + __FILE__, __LINE__, &p[10], 2, &r[10], 4, &d[10], 8), + -3); + EXPECT_EQ( + RTNAME(SelectedRealKind)(__FILE__, __LINE__, &p_s, 1, &r[0], 4, &d[0], 8), + 2); + EXPECT_EQ(RTNAME(SelectedRealKind)( + __FILE__, __LINE__, nullptr, 0, &r[0], 4, &d[0], 8), + 2); + EXPECT_EQ(RTNAME(SelectedRealKind)( + __FILE__, __LINE__, &p[0], 2, nullptr, 0, &d[0], 8), + 2); + EXPECT_EQ(RTNAME(SelectedRealKind)( + __FILE__, __LINE__, &p[0], 2, &r[0], 4, nullptr, 0), + 2); +} + TEST(Numeric, Spacing) { EXPECT_EQ(RTNAME(Spacing8)(Real<8>{0}), std::numeric_limits>::min()); EXPECT_EQ(RTNAME(Spacing4)(Real<4>{3.0}), std::ldexp(Real<4>{1.0}, -22));