Index: flang/include/flang/Optimizer/Builder/Runtime/Numeric.h =================================================================== --- flang/include/flang/Optimizer/Builder/Runtime/Numeric.h +++ flang/include/flang/Optimizer/Builder/Runtime/Numeric.h @@ -38,6 +38,10 @@ mlir::Value genScale(fir::FirOpBuilder &builder, mlir::Location loc, mlir::Value x, mlir::Value i); +/// Generate call to Selected_int_kind intrinsic runtime routine. +mlir::Value genSelectedIntKind(fir::FirOpBuilder &builder, mlir::Location loc, + mlir::Value x); + /// Generate call to Set_exponent intrinsic runtime routine. mlir::Value genSetExponent(fir::FirOpBuilder &builder, mlir::Location loc, mlir::Value x, mlir::Value i); Index: flang/include/flang/Runtime/numeric.h =================================================================== --- flang/include/flang/Runtime/numeric.h +++ flang/include/flang/Runtime/numeric.h @@ -439,6 +439,20 @@ CppTypeFor, std::int64_t); #endif +// SELECTED_INT_KIND +CppTypeFor RTNAME(SelectedIntKind1)( + CppTypeFor x); +CppTypeFor RTNAME(SelectedIntKind2)( + CppTypeFor x); +CppTypeFor RTNAME(SelectedIntKind4)( + CppTypeFor x); +CppTypeFor RTNAME(SelectedIntKind8)( + CppTypeFor x); +#ifdef __SIZEOF_INT128__ +CppTypeFor RTNAME(SelectedIntKind16)( + CppTypeFor x); +#endif + // SPACING CppTypeFor RTNAME(Spacing4)( CppTypeFor); Index: flang/lib/Lower/IntrinsicCall.cpp =================================================================== --- flang/lib/Lower/IntrinsicCall.cpp +++ flang/lib/Lower/IntrinsicCall.cpp @@ -531,6 +531,7 @@ llvm::ArrayRef args); mlir::Value genScale(mlir::Type, llvm::ArrayRef); fir::ExtendedValue genScan(mlir::Type, llvm::ArrayRef); + mlir::Value genSelectedIntKind(mlir::Type, llvm::ArrayRef); mlir::Value genSetExponent(mlir::Type resultType, llvm::ArrayRef args); mlir::Value genSign(mlir::Type, llvm::ArrayRef); @@ -890,6 +891,10 @@ {"back", asValue, handleDynamicOptional}, {"kind", asValue}}}, /*isElemental=*/true}, + {"selected_int_kind", + &I::genSelectedIntKind, + {{{"scalar", asValue}}}, + /*isElemental=*/false}, {"set_exponent", &I::genSetExponent}, {"sign", &I::genSign}, {"size", @@ -3623,6 +3628,17 @@ return readAndAddCleanUp(resultMutableBox, resultType, "SCAN"); } +// SELECTED_INT_KIND +mlir::Value +IntrinsicLibrary::genSelectedIntKind(mlir::Type resultType, + llvm::ArrayRef args) { + assert(args.size() == 1); + + return builder.createConvert( + loc, resultType, + fir::runtime::genSelectedIntKind(builder, loc, fir::getBase(args[0]))); +} + // SET_EXPONENT mlir::Value IntrinsicLibrary::genSetExponent(mlir::Type resultType, llvm::ArrayRef args) { Index: flang/lib/Optimizer/Builder/Runtime/Numeric.cpp =================================================================== --- flang/lib/Optimizer/Builder/Runtime/Numeric.cpp +++ flang/lib/Optimizer/Builder/Runtime/Numeric.cpp @@ -160,7 +160,20 @@ } }; -/// Placeholder for real*10 version of RRSpacing Intrinsic +/// Placeholder for integer*16 version of SelectedIntKind Intrinsic +struct ForcedSelectedIntKind16 { + static constexpr const char *name = + ExpandAndQuoteKey(RTNAME(SelectedIntKind16)); + static constexpr fir::runtime::FuncTypeBuilderFunc getTypeModel() { + return [](mlir::MLIRContext *ctx) { + auto int128Ty = mlir::IntegerType::get(ctx, 128); + auto int32Ty = mlir::IntegerType::get(ctx, 32); + return mlir::FunctionType::get(ctx, {int128Ty}, {int32Ty}); + }; + } +}; + +/// Placeholder for real*10 version of SetExponent Intrinsic struct ForcedSetExponent10 { static constexpr const char *name = ExpandAndQuoteKey(RTNAME(SetExponent10)); static constexpr fir::runtime::FuncTypeBuilderFunc getTypeModel() { @@ -172,7 +185,7 @@ } }; -/// Placeholder for real*10 version of RRSpacing Intrinsic +/// Placeholder for real*10 version of SetExponent Intrinsic struct ForcedSetExponent16 { static constexpr const char *name = ExpandAndQuoteKey(RTNAME(SetExponent16)); static constexpr fir::runtime::FuncTypeBuilderFunc getTypeModel() { @@ -360,6 +373,36 @@ return builder.create(loc, func, args).getResult(0); } +/// Generate call to Selected_int_kind intrinsic runtime routine. +mlir::Value fir::runtime::genSelectedIntKind(fir::FirOpBuilder &builder, + mlir::Location loc, + mlir::Value x) { + mlir::func::FuncOp func; + mlir::Type iTy = x.getType(); + + if (iTy.isInteger(8)) + func = + fir::runtime::getRuntimeFunc(loc, builder); + else if (iTy.isInteger(16)) + func = + fir::runtime::getRuntimeFunc(loc, builder); + else if (iTy.isInteger(32)) + func = + fir::runtime::getRuntimeFunc(loc, builder); + else if (iTy.isInteger(64)) + func = + fir::runtime::getRuntimeFunc(loc, builder); + else if (iTy.isInteger(128)) + func = fir::runtime::getRuntimeFunc(loc, builder); + else + fir::emitFatalError(loc, "unsupported INTEGER kind in SELECTED_INT_KIND"); + + auto funcTy = func.getFunctionType(); + auto args = fir::runtime::createArguments(builder, loc, funcTy, x); + + 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, Index: flang/runtime/numeric.cpp =================================================================== --- flang/runtime/numeric.cpp +++ flang/runtime/numeric.cpp @@ -115,6 +115,25 @@ return std::ldexp(x, p); // x*2**p } +// SELECTED_INT_KIND (16.9.169) +template +inline CppTypeFor SelectedIntKind(T x) { + if (x <= 2) { + return 1; + } else if (x <= 4) { + return 2; + } else if (x <= 9) { + return 4; + } else if (x <= 18) { + return 8; +#ifdef __SIZEOF_INT128__ + } else if (x <= 38) { + return 16; +#endif + } + return -1; +} + // SET_EXPONENT (16.9.171) template inline T SetExponent(T x, std::int64_t p) { if (std::isnan(x)) { @@ -839,6 +858,29 @@ } #endif +CppTypeFor RTNAME(SelectedIntKind1)( + CppTypeFor x) { + return SelectedIntKind(x); +} +CppTypeFor RTNAME(SelectedIntKind2)( + CppTypeFor x) { + return SelectedIntKind(x); +} +CppTypeFor RTNAME(SelectedIntKind4)( + CppTypeFor x) { + return SelectedIntKind(x); +} +CppTypeFor RTNAME(SelectedIntKind8)( + CppTypeFor x) { + return SelectedIntKind(x); +} +#ifdef __SIZEOF_INT128__ +CppTypeFor RTNAME(SelectedIntKind16)( + CppTypeFor x) { + return SelectedIntKind(x); +} +#endif + CppTypeFor RTNAME(Spacing4)( CppTypeFor x) { return Spacing<24>(x); Index: flang/test/Lower/Intrinsics/selected_int_kind.f90 =================================================================== --- /dev/null +++ flang/test/Lower/Intrinsics/selected_int_kind.f90 @@ -0,0 +1,76 @@ +! REQUIRES: shell +! RUN: bbc -emit-fir %s -o - | FileCheck %s + +! CHECK-LABEL: func.func @_QPselected_int_kind_test1( +! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref {fir.bindc_name = "a"}) { +! CHECK: %[[VAL_1:.*]] = fir.alloca i8 {bindc_name = "res", uniq_name = "_QFselected_int_kind_test1Eres"} +! CHECK: %[[VAL_2:.*]] = fir.load %[[VAL_0]] : !fir.ref +! CHECK: %[[VAL_3:.*]] = fir.call @_FortranASelectedIntKind1(%[[VAL_2]]) : (i8) -> i32 +! CHECK: %[[VAL_4:.*]] = fir.convert %[[VAL_3]] : (i32) -> i8 +! CHECK: fir.store %[[VAL_4]] to %[[VAL_1]] : !fir.ref +! CHECK: return +! CHECK: } + +subroutine selected_int_kind_test1(a) + integer(1) :: a, res + res = selected_int_kind(a) +end + +! CHECK-LABEL: func.func @_QPselected_int_kind_test2( +! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref {fir.bindc_name = "a"}) { +! CHECK: %[[VAL_1:.*]] = fir.alloca i16 {bindc_name = "res", uniq_name = "_QFselected_int_kind_test2Eres"} +! CHECK: %[[VAL_2:.*]] = fir.load %[[VAL_0]] : !fir.ref +! CHECK: %[[VAL_3:.*]] = fir.call @_FortranASelectedIntKind2(%[[VAL_2]]) : (i16) -> i32 +! CHECK: %[[VAL_4:.*]] = fir.convert %[[VAL_3]] : (i32) -> i16 +! CHECK: fir.store %[[VAL_4]] to %[[VAL_1]] : !fir.ref +! CHECK: return +! CHECK: } + +subroutine selected_int_kind_test2(a) + integer(2) :: a, res + res = selected_int_kind(a) +end + +! CHECK-LABEL: func.func @_QPselected_int_kind_test4( +! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref {fir.bindc_name = "a"}) { +! CHECK: %[[VAL_1:.*]] = fir.alloca i32 {bindc_name = "res", uniq_name = "_QFselected_int_kind_test4Eres"} +! CHECK: %[[VAL_2:.*]] = fir.load %[[VAL_0]] : !fir.ref +! CHECK: %[[VAL_3:.*]] = fir.call @_FortranASelectedIntKind4(%[[VAL_2]]) : (i32) -> i32 +! CHECK: fir.store %[[VAL_3]] to %[[VAL_1]] : !fir.ref +! CHECK: return +! CHECK: } + +subroutine selected_int_kind_test4(a) + integer(4) :: a, res + res = selected_int_kind(a) +end + +! CHECK-LABEL: func.func @_QPselected_int_kind_test8( +! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref {fir.bindc_name = "a"}) { +! CHECK: %[[VAL_1:.*]] = fir.alloca i64 {bindc_name = "res", uniq_name = "_QFselected_int_kind_test8Eres"} +! CHECK: %[[VAL_2:.*]] = fir.load %[[VAL_0]] : !fir.ref +! CHECK: %[[VAL_3:.*]] = fir.call @_FortranASelectedIntKind8(%[[VAL_2]]) : (i64) -> i32 +! CHECK: %[[VAL_4:.*]] = fir.convert %[[VAL_3]] : (i32) -> i64 +! CHECK: fir.store %[[VAL_4]] to %[[VAL_1]] : !fir.ref +! CHECK: return +! CHECK: } + +subroutine selected_int_kind_test8(a) + integer(8) :: a, res + res = selected_int_kind(a) +end + +! CHECK-LABEL: func.func @_QPselected_int_kind_test16( +! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref {fir.bindc_name = "a"}) { +! CHECK: %[[VAL_1:.*]] = fir.alloca i128 {bindc_name = "res", uniq_name = "_QFselected_int_kind_test16Eres"} +! CHECK: %[[VAL_2:.*]] = fir.load %[[VAL_0]] : !fir.ref +! CHECK: %[[VAL_3:.*]] = fir.call @_FortranASelectedIntKind16(%[[VAL_2]]) : (i128) -> i32 +! CHECK: %[[VAL_4:.*]] = fir.convert %[[VAL_3]] : (i32) -> i128 +! CHECK: fir.store %[[VAL_4]] to %[[VAL_1]] : !fir.ref +! CHECK: return +! CHECK: } + +subroutine selected_int_kind_test16(a) + integer(16) :: a, res + res = selected_int_kind(a) +end Index: flang/unittests/Runtime/Numeric.cpp =================================================================== --- flang/unittests/Runtime/Numeric.cpp +++ flang/unittests/Runtime/Numeric.cpp @@ -139,6 +139,14 @@ std::isnan(RTNAME(Scale8)(std::numeric_limits>::quiet_NaN(), 1))); } +TEST(Numeric, SelectedIntKind) { + EXPECT_EQ(RTNAME(SelectedIntKind1)(Int<1>{1}), 1); + EXPECT_EQ(RTNAME(SelectedIntKind2)(Int<2>{3}), 2); + EXPECT_EQ(RTNAME(SelectedIntKind4)(Int<4>{8}), 4); + EXPECT_EQ(RTNAME(SelectedIntKind8)(Int<8>{10}), 8); + EXPECT_EQ(RTNAME(SelectedIntKind8)(Int<8>{-10}), 1); +} + TEST(Numeric, SetExponent) { EXPECT_EQ(RTNAME(SetExponent4)(Real<4>{0}, 0), 0); EXPECT_EQ(RTNAME(SetExponent8)(Real<8>{0}, 666), 0);