diff --git a/flang/include/flang/Optimizer/Builder/Runtime/Inquiry.h b/flang/include/flang/Optimizer/Builder/Runtime/Inquiry.h index 5f14d7781004b..3707273e0cbd4 100644 --- a/flang/include/flang/Optimizer/Builder/Runtime/Inquiry.h +++ b/flang/include/flang/Optimizer/Builder/Runtime/Inquiry.h @@ -20,12 +20,14 @@ class FirOpBuilder; namespace fir::runtime { -/// Generate call to general `LboundDim` runtime routine. Calls to LBOUND -/// without a DIM argument get transformed into descriptor inquiries so they're -/// not handled in the runtime. +/// Generate call to `LboundDim` runtime routine. mlir::Value genLboundDim(fir::FirOpBuilder &builder, mlir::Location loc, mlir::Value array, mlir::Value dim); +/// Generate call to Lbound` runtime routine. +void genLbound(fir::FirOpBuilder &builder, mlir::Location loc, + mlir::Value resultAddr, mlir::Value arrayt, mlir::Value kind); + /// Generate call to general `Ubound` runtime routine. Calls to UBOUND /// with a DIM argument get transformed into an expression equivalent to /// SIZE() + LBOUND() - 1, so they don't have an intrinsic in the runtime. diff --git a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp index b3e1ee3da3a77..b287b826669da 100644 --- a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp +++ b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp @@ -6298,16 +6298,17 @@ IntrinsicLibrary::genLbound(mlir::Type resultType, llvm::ArrayRef args) { assert(args.size() == 2 || args.size() == 3); const fir::ExtendedValue &array = args[0]; - if (const auto *boxValue = array.getBoxOf()) - if (boxValue->hasAssumedRank()) - TODO(loc, "intrinsic: lbound with assumed rank argument"); + // Semantics builds signatures for LBOUND calls as either + // LBOUND(array, dim, [kind]) or LBOUND(array, [kind]). + const bool dimIsAbsent = args.size() == 2 || isStaticallyAbsent(args, 1); + if (array.hasAssumedRank() && dimIsAbsent) + return genAssumedRankBoundInquiry(builder, loc, resultType, args, + /*kindPos=*/1, fir::runtime::genLbound); mlir::Type indexType = builder.getIndexType(); - // Semantics builds signatures for LBOUND calls as either - // LBOUND(array, dim, [kind]) or LBOUND(array, [kind]). - if (args.size() == 2 || isStaticallyAbsent(args, 1)) { - // DIM is absent. + if (dimIsAbsent) { + // DIM is absent and the rank of array is a compile time constant. mlir::Type lbType = fir::unwrapSequenceType(resultType); unsigned rank = array.rank(); mlir::Type lbArrayType = fir::SequenceType::get( @@ -6332,13 +6333,16 @@ IntrinsicLibrary::genLbound(mlir::Type resultType, // DIM is present. mlir::Value dim = fir::getBase(args[1]); - // If it is a compile time constant, skip the runtime call. - if (std::optional cstDim = fir::getIntIfConstant(dim)) { - mlir::Value one = builder.createIntegerConstant(loc, resultType, 1); - mlir::Value zero = builder.createIntegerConstant(loc, indexType, 0); - mlir::Value lb = computeLBOUND(builder, loc, array, *cstDim - 1, zero, one); - return builder.createConvert(loc, resultType, lb); - } + // If it is a compile time constant and the rank is known, skip the runtime + // call. + if (!array.hasAssumedRank()) + if (std::optional cstDim = fir::getIntIfConstant(dim)) { + mlir::Value one = builder.createIntegerConstant(loc, resultType, 1); + mlir::Value zero = builder.createIntegerConstant(loc, indexType, 0); + mlir::Value lb = + computeLBOUND(builder, loc, array, *cstDim - 1, zero, one); + return builder.createConvert(loc, resultType, lb); + } fir::ExtendedValue box = createBoxForRuntimeBoundInquiry(loc, builder, array); return builder.createConvert( diff --git a/flang/lib/Optimizer/Builder/Runtime/Inquiry.cpp b/flang/lib/Optimizer/Builder/Runtime/Inquiry.cpp index 34c4020b5907c..e01a6f05b5fdd 100644 --- a/flang/lib/Optimizer/Builder/Runtime/Inquiry.cpp +++ b/flang/lib/Optimizer/Builder/Runtime/Inquiry.cpp @@ -29,6 +29,20 @@ mlir::Value fir::runtime::genLboundDim(fir::FirOpBuilder &builder, return builder.create(loc, lboundFunc, args).getResult(0); } +void fir::runtime::genLbound(fir::FirOpBuilder &builder, mlir::Location loc, + mlir::Value resultAddr, mlir::Value array, + mlir::Value kind) { + 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(4)); + auto args = fir::runtime::createArguments( + builder, loc, fTy, resultAddr, array, kind, sourceFile, sourceLine); + builder.create(loc, func, args).getResult(0); +} + /// Generate call to `Ubound` runtime routine. Calls to UBOUND with a DIM /// argument get transformed into an expression equivalent to /// SIZE() + LBOUND() - 1, so they don't have an intrinsic in the runtime. diff --git a/flang/test/Lower/HLFIR/assumed-rank-inquiries-3.f90 b/flang/test/Lower/HLFIR/assumed-rank-inquiries-3.f90 index bbeff5ff05191..e568b94f4f884 100644 --- a/flang/test/Lower/HLFIR/assumed-rank-inquiries-3.f90 +++ b/flang/test/Lower/HLFIR/assumed-rank-inquiries-3.f90 @@ -54,3 +54,58 @@ subroutine test_shape_2(x) ! CHECK: %[[VAL_13:.*]] = fir.box_rank %[[VAL_4]] : (!fir.box>>) -> index ! CHECK: %[[VAL_14:.*]] = fir.shape %[[VAL_13]] : (index) -> !fir.shape<1> ! CHECK: %[[VAL_15:.*]]:2 = hlfir.declare %[[VAL_12]](%[[VAL_14]]) {uniq_name = ".tmp.intrinsic_result"} : (!fir.ref>, !fir.shape<1>) -> (!fir.box>, !fir.ref>) + + +subroutine test_lbound(x) + real :: x(..) + call takes_integer_array(lbound(x)) +end subroutine +! CHECK-LABEL: func.func @_QPtest_lbound( +! CHECK: %[[VAL_1:.*]] = fir.alloca !fir.array<15xi32> +! CHECK: %[[VAL_4:.*]] = arith.constant 4 : i32 +! CHECK: %[[VAL_7:.*]] = fir.convert %[[VAL_1]] : (!fir.ref>) -> !fir.llvm_ptr +! CHECK: %[[VAL_8:.*]] = fir.convert %[[VAL_3:.*]] : (!fir.box>) -> !fir.box +! CHECK: %[[VAL_10:.*]] = fir.call @_FortranALbound(%[[VAL_7]], %[[VAL_8]], %[[VAL_4]], %{{.*}}, %{{.*}}) +! CHECK: %[[VAL_11:.*]] = fir.convert %[[VAL_1]] : (!fir.ref>) -> !fir.ref> +! CHECK: %[[VAL_12:.*]] = fir.box_rank %[[VAL_3]] : (!fir.box>) -> index +! CHECK: %[[VAL_13:.*]] = fir.shape %[[VAL_12]] : (index) -> !fir.shape<1> +! CHECK: %[[VAL_14:.*]]:2 = hlfir.declare %[[VAL_11]](%[[VAL_13]]) {uniq_name = ".tmp.intrinsic_result"} : (!fir.ref>, !fir.shape<1>) -> (!fir.box>, !fir.ref>) +! CHECK: %[[VAL_15:.*]] = arith.constant false +! CHECK: %[[VAL_16:.*]] = hlfir.as_expr %[[VAL_14]]#0 move %[[VAL_15]] : (!fir.box>, i1) -> !hlfir.expr +! CHECK: %[[VAL_17:.*]]:3 = hlfir.associate %[[VAL_16]](%[[VAL_13]]) {adapt.valuebyref} : (!hlfir.expr, !fir.shape<1>) -> (!fir.box>, !fir.ref>, i1) +! CHECK: fir.call @_QPtakes_integer_array(%[[VAL_17]]#1) fastmath : (!fir.ref>) -> () +! CHECK: hlfir.end_associate %[[VAL_17]]#1, %[[VAL_17]]#2 : !fir.ref>, i1 +! CHECK: hlfir.destroy %[[VAL_16]] : !hlfir.expr +! CHECK: return +! CHECK: } + +subroutine test_lbound_kind(x) + real :: x(..) + call takes_integer8_array(lbound(x, kind=8)) +end subroutine +! CHECK-LABEL: func.func @_QPtest_lbound_kind( +! CHECK: %[[VAL_1:.*]] = fir.alloca !fir.array<15xi64> +! CHECK: %[[VAL_4:.*]] = arith.constant 8 : i32 +! CHECK: %[[VAL_7:.*]] = fir.convert %[[VAL_1]] : (!fir.ref>) -> !fir.llvm_ptr +! CHECK: %[[VAL_8:.*]] = fir.convert %[[VAL_3:.*]] : (!fir.box>) -> !fir.box +! CHECK: %[[VAL_10:.*]] = fir.call @_FortranALbound(%[[VAL_7]], %[[VAL_8]], %[[VAL_4]], %{{.*}}, %{{.*}}) +! CHECK: %[[VAL_11:.*]] = fir.convert %[[VAL_1]] : (!fir.ref>) -> !fir.ref> +! CHECK: %[[VAL_12:.*]] = fir.box_rank %[[VAL_3]] : (!fir.box>) -> index +! CHECK: %[[VAL_13:.*]] = fir.shape %[[VAL_12]] : (index) -> !fir.shape<1> +! CHECK: %[[VAL_14:.*]]:2 = hlfir.declare %[[VAL_11]](%[[VAL_13]]) {uniq_name = ".tmp.intrinsic_result"} : (!fir.ref>, !fir.shape<1>) -> (!fir.box>, !fir.ref>) + +subroutine test_lbound_2(x) + real, pointer :: x(..) + call takes_integer_array(lbound(x)) +end subroutine +! CHECK-LABEL: func.func @_QPtest_lbound_2( +! CHECK: %[[VAL_1:.*]] = fir.alloca !fir.array<15xi32> +! CHECK: %[[VAL_4:.*]] = fir.load %[[VAL_3:.*]] : !fir.ref>>> +! CHECK: %[[VAL_5:.*]] = arith.constant 4 : i32 +! CHECK: %[[VAL_8:.*]] = fir.convert %[[VAL_1]] : (!fir.ref>) -> !fir.llvm_ptr +! CHECK: %[[VAL_9:.*]] = fir.convert %[[VAL_4]] : (!fir.box>>) -> !fir.box +! CHECK: %[[VAL_11:.*]] = fir.call @_FortranALbound(%[[VAL_8]], %[[VAL_9]], %[[VAL_5]], %{{.*}}, %{{.*}}) +! CHECK: %[[VAL_12:.*]] = fir.convert %[[VAL_1]] : (!fir.ref>) -> !fir.ref> +! CHECK: %[[VAL_13:.*]] = fir.box_rank %[[VAL_4]] : (!fir.box>>) -> index +! CHECK: %[[VAL_14:.*]] = fir.shape %[[VAL_13]] : (index) -> !fir.shape<1> +! CHECK: %[[VAL_15:.*]]:2 = hlfir.declare %[[VAL_12]](%[[VAL_14]]) {uniq_name = ".tmp.intrinsic_result"} : (!fir.ref>, !fir.shape<1>) -> (!fir.box>, !fir.ref>)