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,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 Selected_real_kind intrinsic runtime routine. mlir::Value genSelectedRealKind(fir::FirOpBuilder &builder, mlir::Location loc, mlir::Value precision, mlir::Value range, 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_INT_KIND +CppTypeFor RTNAME(SelectedIntKind)( + const char *, int, void *, int); + // SELECTED_REAL_KIND CppTypeFor RTNAME(SelectedRealKind)( const char *, int, void *, int, void *, int, void *, int); 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 genSelectedIntKind(mlir::Type, llvm::ArrayRef); mlir::Value genSelectedRealKind(mlir::Type, llvm::ArrayRef); mlir::Value genSetExponent(mlir::Type resultType, llvm::ArrayRef args); @@ -920,6 +921,10 @@ {"back", asValue, handleDynamicOptional}, {"kind", asValue}}}, /*isElemental=*/true}, + {"selected_int_kind", + &I::genSelectedIntKind, + {{{"scalar", asAddr}}}, + /*isElemental=*/false}, {"selected_real_kind", &I::genSelectedRealKind, {{{"precision", asAddr, handleDynamicOptional}, @@ -3768,6 +3773,17 @@ // 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]))); +} + +// SELECTED_REAL_KIND +mlir::Value IntrinsicLibrary::genSelectedRealKind(mlir::Type resultType, llvm::ArrayRef args) { assert(args.size() == 3); 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,27 @@ 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 = + fir::runtime::getRuntimeFunc(loc, builder); + auto fTy = func.getFunctionType(); + auto sourceFile = fir::factory::locationToFilename(builder, loc); + auto sourceLine = + fir::factory::locationToLineNo(builder, loc, fTy.getInput(1)); + if (!fir::isa_ref_type(x.getType())) + fir::emitFatalError(loc, "argument address for runtime not found"); + mlir::Type eleTy = fir::unwrapRefType(x.getType()); + mlir::Value xKind = builder.createIntegerConstant( + loc, fTy.getInput(3), eleTy.getIntOrFloatBitWidth() / 8); + auto args = fir::runtime::createArguments(builder, loc, fTy, sourceFile, + sourceLine, x, xKind); + + 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, diff --git a/flang/runtime/numeric.cpp b/flang/runtime/numeric.cpp --- a/flang/runtime/numeric.cpp +++ b/flang/runtime/numeric.cpp @@ -142,6 +142,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; +} + // SELECTED_REAL_KIND (16.9.170) template inline CppTypeFor SelectedRealKind(P p, R r, D d) { @@ -794,6 +813,20 @@ } #endif +// SELECTED_INT_KIND +CppTypeFor RTNAME(SelectedIntKind)( + const char *source, int line, void *x, int xKind) { +#ifdef __SIZEOF_INT128__ + CppTypeFor r = + getIntArgValue>( + source, line, x, xKind, /*defaultValue*/ 0, /*resKind*/ 16); +#else + std::int64_t r = getIntArgValue( + source, line, x, xKind, /*defaultValue*/ 0, /*resKind*/ 8); +#endif + return SelectedIntKind(r); +} + // SELECTED_REAL_KIND CppTypeFor RTNAME(SelectedRealKind)( const char *source, int line, void *precision, int pKind, void *range, diff --git a/flang/test/Lower/Intrinsics/selected_int_kind.f90 b/flang/test/Lower/Intrinsics/selected_int_kind.f90 new file mode 100644 --- /dev/null +++ b/flang/test/Lower/Intrinsics/selected_int_kind.f90 @@ -0,0 +1,81 @@ +! 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_4:.*]] = arith.constant 1 : i32 +! CHECK: %[[VAL_6:.*]] = fir.convert %[[VAL_0]] : (!fir.ref) -> !fir.llvm_ptr +! CHECK: %[[VAL_7:.*]] = fir.call @_FortranASelectedIntKind(%{{.*}}, %{{.*}}, %[[VAL_6]], %[[VAL_4]]) : (!fir.ref, i32, !fir.llvm_ptr, i32) -> i32 +! CHECK: %[[VAL_8:.*]] = fir.convert %[[VAL_7]] : (i32) -> i8 +! CHECK: fir.store %[[VAL_8]] 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_4:.*]] = arith.constant 2 : i32 +! CHECK: %[[VAL_6:.*]] = fir.convert %[[VAL_0]] : (!fir.ref) -> !fir.llvm_ptr +! CHECK: %[[VAL_7:.*]] = fir.call @_FortranASelectedIntKind(%{{.*}}, %{{.*}}, %[[VAL_6]], %[[VAL_4]]) : (!fir.ref, i32, !fir.llvm_ptr, i32) -> i32 +! CHECK: %[[VAL_8:.*]] = fir.convert %[[VAL_7]] : (i32) -> i16 +! CHECK: fir.store %[[VAL_8]] 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_4:.*]] = arith.constant 4 : i32 +! CHECK: %[[VAL_6:.*]] = fir.convert %[[VAL_0]] : (!fir.ref) -> !fir.llvm_ptr +! CHECK: %[[VAL_7:.*]] = fir.call @_FortranASelectedIntKind(%{{.*}}, %{{.*}}, %[[VAL_6]], %[[VAL_4]]) : (!fir.ref, i32, !fir.llvm_ptr, i32) -> i32 +! CHECK: fir.store %[[VAL_7]] 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_4:.*]] = arith.constant 8 : i32 +! CHECK: %[[VAL_6:.*]] = fir.convert %[[VAL_0]] : (!fir.ref) -> !fir.llvm_ptr +! CHECK: %[[VAL_7:.*]] = fir.call @_FortranASelectedIntKind(%{{.*}}, %{{.*}}, %[[VAL_6]], %[[VAL_4]]) : (!fir.ref, i32, !fir.llvm_ptr, i32) -> i32 +! CHECK: %[[VAL_8:.*]] = fir.convert %[[VAL_7]] : (i32) -> i64 +! CHECK: fir.store %[[VAL_8]] 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_4:.*]] = arith.constant 16 : i32 +! CHECK: %[[VAL_6:.*]] = fir.convert %[[VAL_0]] : (!fir.ref) -> !fir.llvm_ptr +! CHECK: %[[VAL_7:.*]] = fir.call @_FortranASelectedIntKind(%{{.*}}, %{{.*}}, %[[VAL_6]], %[[VAL_4]]) : (!fir.ref, i32, !fir.llvm_ptr, i32) -> i32 +! CHECK: %[[VAL_8:.*]] = fir.convert %[[VAL_7]] : (i32) -> i128 +! CHECK: fir.store %[[VAL_8]] to %[[VAL_1]] : !fir.ref +! CHECK: return +! CHECK: } + +subroutine selected_int_kind_test16(a) + integer(16) :: a, res + res = selected_int_kind(a) +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,21 @@ RTNAME(SetExponent8)(std::numeric_limits>::quiet_NaN(), 1))); } +TEST(Numeric, SelectedIntKind) { + std::int8_t r0 = 1; + std::int16_t r1 = 3; + std::int32_t r2 = 8; + std::int64_t r3 = 10; + std::int32_t r4 = -10; + std::int32_t r5 = 100; + EXPECT_EQ(RTNAME(SelectedIntKind)(__FILE__, __LINE__, &r0, 1), 1); + EXPECT_EQ(RTNAME(SelectedIntKind)(__FILE__, __LINE__, &r1, 2), 2); + EXPECT_EQ(RTNAME(SelectedIntKind)(__FILE__, __LINE__, &r2, 4), 4); + EXPECT_EQ(RTNAME(SelectedIntKind)(__FILE__, __LINE__, &r3, 8), 8); + EXPECT_EQ(RTNAME(SelectedIntKind)(__FILE__, __LINE__, &r4, 4), 1); + EXPECT_EQ(RTNAME(SelectedIntKind)(__FILE__, __LINE__, &r5, 4), -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};