From 07b89273949a8455aa805472e779f17e051736dd Mon Sep 17 00:00:00 2001 From: Jean Perier Date: Fri, 18 Nov 2022 10:08:56 +0100 Subject: [PATCH] [flang] Lower ArrayRef to hlfir.designate Also add support for fir.boxchar in HLFIRTools so that character designator with none constant lengths can be processed/converted to fir::ExtendedValue. Differential Revision: https://reviews.llvm.org/D138190 --- flang/include/flang/Optimizer/Builder/HLFIRTools.h | 19 ++- flang/lib/Lower/ConvertExprToHLFIR.cpp | 182 ++++++++++++++++++++- flang/lib/Optimizer/Builder/HLFIRTools.cpp | 66 +++++++- flang/test/Lower/HLFIR/designators.f90 | 114 +++++++++++++ 4 files changed, 371 insertions(+), 10 deletions(-) create mode 100644 flang/test/Lower/HLFIR/designators.f90 diff --git a/flang/include/flang/Optimizer/Builder/HLFIRTools.h b/flang/include/flang/Optimizer/Builder/HLFIRTools.h index 5a69315..0bc868e 100644 --- a/flang/include/flang/Optimizer/Builder/HLFIRTools.h +++ b/flang/include/flang/Optimizer/Builder/HLFIRTools.h @@ -88,6 +88,10 @@ public: fir::isRecordWithTypeParameters(eleTy); } + bool isCharacter() const { + return getFortranElementType().isa(); + } + fir::FortranVariableOpInterface getIfVariableInterface() const { return this->getDefiningOp(); } @@ -135,9 +139,11 @@ translateToExtendedValue(mlir::Location loc, fir::FirOpBuilder &builder, Entity entity); /// Function to translate FortranVariableOpInterface to fir::ExtendedValue. -/// It does not generate any IR, and is a simple packaging operation. +/// It may generates IR to unbox fir.boxchar, but has otherwise no side effects +/// on the IR. fir::ExtendedValue -translateToExtendedValue(fir::FortranVariableOpInterface fortranVariable); +translateToExtendedValue(mlir::Location loc, fir::FirOpBuilder &builder, + fir::FortranVariableOpInterface fortranVariable); /// Generate declaration for a fir::ExtendedValue in memory. EntityWithAttributes genDeclare(mlir::Location loc, fir::FirOpBuilder &builder, @@ -151,6 +157,15 @@ EntityWithAttributes genDeclare(mlir::Location loc, fir::FirOpBuilder &builder, Entity loadTrivialScalar(mlir::Location loc, fir::FirOpBuilder &builder, Entity entity); +/// Compute the lower and upper bounds of an entity. +llvm::SmallVector> +genBounds(mlir::Location loc, fir::FirOpBuilder &builder, Entity entity); + +/// Read length parameters into result if this entity has any. +void genLengthParameters(mlir::Location loc, fir::FirOpBuilder &builder, + Entity entity, + llvm::SmallVectorImpl &result); + } // namespace hlfir #endif // FORTRAN_OPTIMIZER_BUILDER_HLFIRTOOLS_H diff --git a/flang/lib/Lower/ConvertExprToHLFIR.cpp b/flang/lib/Lower/ConvertExprToHLFIR.cpp index d09cd7c..3153c5a 100644 --- a/flang/lib/Lower/ConvertExprToHLFIR.cpp +++ b/flang/lib/Lower/ConvertExprToHLFIR.cpp @@ -11,11 +11,13 @@ //===----------------------------------------------------------------------===// #include "flang/Lower/ConvertExprToHLFIR.h" +#include "flang/Evaluate/shape.h" #include "flang/Lower/AbstractConverter.h" #include "flang/Lower/ConvertConstant.h" #include "flang/Lower/StatementContext.h" #include "flang/Lower/SymbolMap.h" #include "flang/Optimizer/Builder/Todo.h" +#include "flang/Optimizer/HLFIR/HLFIROps.h" namespace { @@ -34,51 +36,199 @@ public: Fortran::evaluate::TypeCategory::Character, 1>>::u); hlfir::EntityWithAttributes gen(const CharacterDesignators &designatorVariant) { - return std::visit([&](const auto &x) { return gen(x); }, designatorVariant); + return std::visit( + [&](const auto &x) -> hlfir::EntityWithAttributes { return gen(x); }, + designatorVariant); } // Character designators variant contains complex parts using RealDesignators = decltype(Fortran::evaluate::Designator>::u); hlfir::EntityWithAttributes gen(const RealDesignators &designatorVariant) { - return std::visit([&](const auto &x) { return gen(x); }, designatorVariant); + return std::visit( + [&](const auto &x) -> hlfir::EntityWithAttributes { return gen(x); }, + designatorVariant); } // All other designators are similar using OtherDesignators = decltype(Fortran::evaluate::Designator>::u); hlfir::EntityWithAttributes gen(const OtherDesignators &designatorVariant) { - return std::visit([&](const auto &x) { return gen(x); }, designatorVariant); + return std::visit( + [&](const auto &x) -> hlfir::EntityWithAttributes { return gen(x); }, + designatorVariant); } private: - hlfir::EntityWithAttributes + /// Struct that is filled while visiting a part-ref (in the "visit" member + /// function) before the top level "gen" generates an hlfir.declare for the + /// part ref. It contains the lowered pieces of the part-ref that will + /// become the operands of an hlfir.declare. + struct PartInfo { + fir::FortranVariableOpInterface base; + llvm::SmallVector subscripts; + mlir::Value resultShape; + llvm::SmallVector typeParams; + }; + + /// Generate an hlfir.declare for a part-ref given a filled PartInfo and the + /// FIR type for this part-ref. + fir::FortranVariableOpInterface genDeclare(mlir::Type resultValueType, + PartInfo &partInfo) { + // Compute hlfir.declare result type. + // TODO: ensure polymorphic aspect of base of component will be + // preserved, as well as pointer/allocatable component aspects. + mlir::Type resultType; + /// Array sections may be non contiguous, so the output must be a box even + /// when the extents are static. This can be refined later for cases where + /// the output is know to be simply contiguous and that do not have lower + /// bounds. + auto charType = resultValueType.dyn_cast(); + if (charType && charType.hasDynamicLen()) + resultType = + fir::BoxCharType::get(charType.getContext(), charType.getFKind()); + else if (resultValueType.isa() || + fir::hasDynamicSize(resultValueType)) + resultType = fir::BoxType::get(resultValueType); + else + resultType = fir::ReferenceType::get(resultValueType); + + llvm::Optional complexPart; + llvm::SmallVector substring; + auto designate = getBuilder().create( + getLoc(), resultType, partInfo.base.getBase(), "", + /*componentShape=*/mlir::Value{}, partInfo.subscripts, substring, + complexPart, partInfo.resultShape, partInfo.typeParams); + return mlir::cast( + designate.getOperation()); + } + + fir::FortranVariableOpInterface gen(const Fortran::evaluate::SymbolRef &symbolRef) { if (llvm::Optional varDef = getSymMap().lookupVariableDefinition(symbolRef)) return *varDef; TODO(getLoc(), "lowering symbol to HLFIR"); } + hlfir::EntityWithAttributes gen(const Fortran::evaluate::Component &component) { TODO(getLoc(), "lowering component to HLFIR"); } + hlfir::EntityWithAttributes gen(const Fortran::evaluate::ArrayRef &arrayRef) { - TODO(getLoc(), "lowering ArrayRef to HLFIR"); + PartInfo partInfo; + mlir::Type resultType = visit(arrayRef, partInfo); + return genDeclare(resultType, partInfo); } + hlfir::EntityWithAttributes gen(const Fortran::evaluate::CoarrayRef &coarrayRef) { TODO(getLoc(), "lowering CoarrayRef to HLFIR"); } + hlfir::EntityWithAttributes gen(const Fortran::evaluate::ComplexPart &complexPart) { TODO(getLoc(), "lowering complex part to HLFIR"); } + hlfir::EntityWithAttributes gen(const Fortran::evaluate::Substring &substring) { TODO(getLoc(), "lowering substrings to HLFIR"); } + mlir::Type visit(const Fortran::evaluate::SymbolRef &symbolRef, + PartInfo &partInfo) { + partInfo.base = gen(symbolRef); + hlfir::genLengthParameters(getLoc(), getBuilder(), partInfo.base, + partInfo.typeParams); + return partInfo.base.getElementOrSequenceType(); + } + + mlir::Type visit(const Fortran::evaluate::ArrayRef &arrayRef, + PartInfo &partInfo) { + mlir::Type baseType; + if (const auto *component = arrayRef.base().UnwrapComponent()) + baseType = visit(*component, partInfo); + baseType = visit(arrayRef.base().GetLastSymbol(), partInfo); + + fir::FirOpBuilder &builder = getBuilder(); + mlir::Location loc = getLoc(); + mlir::Type idxTy = builder.getIndexType(); + llvm::SmallVector> bounds; + auto getBounds = [&](unsigned i) { + if (bounds.empty()) + bounds = hlfir::genBounds(loc, builder, partInfo.base); + return bounds[i]; + }; + auto frontEndResultShape = + Fortran::evaluate::GetShape(converter.getFoldingContext(), arrayRef); + llvm::SmallVector resultExtents; + fir::SequenceType::Shape resultTypeShape; + for (auto subscript : llvm::enumerate(arrayRef.subscript())) { + if (const auto *triplet = + std::get_if(&subscript.value().u)) { + mlir::Value lb, ub; + if (const auto &lbExpr = triplet->lower()) + lb = genSubscript(*lbExpr); + else + lb = getBounds(subscript.index()).first; + if (const auto &ubExpr = triplet->upper()) + ub = genSubscript(*ubExpr); + else + ub = getBounds(subscript.index()).second; + lb = builder.createConvert(loc, idxTy, lb); + ub = builder.createConvert(loc, idxTy, ub); + mlir::Value stride = genSubscript(triplet->stride()); + stride = builder.createConvert(loc, idxTy, stride); + mlir::Value extent; + // Use constant extent if possible. The main advantage to do this now + // is to get the best FIR array types as possible while lowering. + if (frontEndResultShape) + if (auto maybeI64 = Fortran::evaluate::ToInt64( + frontEndResultShape->at(resultExtents.size()))) { + resultTypeShape.push_back(*maybeI64); + extent = builder.createIntegerConstant(loc, idxTy, *maybeI64); + } + if (!extent) { + extent = builder.genExtentFromTriplet(loc, lb, ub, stride, idxTy); + resultTypeShape.push_back(fir::SequenceType::getUnknownExtent()); + } + partInfo.subscripts.emplace_back( + hlfir::DesignateOp::Triplet{lb, ub, stride}); + resultExtents.push_back(extent); + } else { + const auto &expr = + std::get( + subscript.value().u) + .value(); + if (expr.Rank() > 0) + TODO(getLoc(), "vector subscripts in HLFIR"); + partInfo.subscripts.push_back(genSubscript(expr)); + } + } + + assert(resultExtents.size() == resultTypeShape.size() && + "inconsistent hlfir.designate shape"); + mlir::Type resultType = baseType.cast().getEleTy(); + if (!resultTypeShape.empty()) { + resultType = fir::SequenceType::get(resultTypeShape, resultType); + partInfo.resultShape = builder.genShape(loc, resultExtents); + } + return resultType; + } + + mlir::Type visit(const Fortran::evaluate::Component &component, + PartInfo &partInfo) { + TODO(getLoc(), "lowering component to HLFIR"); + } + + /// Lower a subscript expression. If it is a scalar subscript that is + /// a variable, it is loaded into an integer value. + template + hlfir::EntityWithAttributes + genSubscript(const Fortran::evaluate::Expr &expr); + mlir::Location getLoc() const { return loc; } Fortran::lower::AbstractConverter &getConverter() { return converter; } fir::FirOpBuilder &getBuilder() { return converter.getFirOpBuilder(); } @@ -220,6 +370,28 @@ private: mlir::Location loc; }; +template +hlfir::EntityWithAttributes +HlfirDesignatorBuilder::genSubscript(const Fortran::evaluate::Expr &expr) { + auto loweredExpr = + HlfirBuilder(getLoc(), getConverter(), getSymMap(), getStmtCtx()) + .gen(expr); + if (!loweredExpr.isArray()) { + fir::FirOpBuilder &builder = getBuilder(); + if (loweredExpr.isVariable()) + return hlfir::EntityWithAttributes{ + hlfir::loadTrivialScalar(loc, builder, loweredExpr).getBase()}; + // Skip constant conversions that litters designators and makes generated + // IR harder to read: directly use index constants for constant subscripts. + mlir::Type idxTy = builder.getIndexType(); + if (loweredExpr.getType() != idxTy) + if (auto cstIndex = fir::factory::getIntIfConstant(loweredExpr)) + return hlfir::EntityWithAttributes{ + builder.createIntegerConstant(getLoc(), idxTy, *cstIndex)}; + } + return loweredExpr; +} + } // namespace hlfir::EntityWithAttributes Fortran::lower::convertExprToHLFIR( diff --git a/flang/lib/Optimizer/Builder/HLFIRTools.cpp b/flang/lib/Optimizer/Builder/HLFIRTools.cpp index cd88118..026e3fd 100644 --- a/flang/lib/Optimizer/Builder/HLFIRTools.cpp +++ b/flang/lib/Optimizer/Builder/HLFIRTools.cpp @@ -69,10 +69,10 @@ getExplicitTypeParams(fir::FortranVariableOpInterface var) { } std::pair> -hlfir::translateToExtendedValue(mlir::Location loc, fir::FirOpBuilder &, +hlfir::translateToExtendedValue(mlir::Location loc, fir::FirOpBuilder &builder, hlfir::Entity entity) { if (auto variable = entity.getIfVariableInterface()) - return {hlfir::translateToExtendedValue(variable), {}}; + return {hlfir::translateToExtendedValue(loc, builder, variable), {}}; if (entity.isVariable()) TODO(loc, "HLFIR variable to fir::ExtendedValue without a " "FortranVariableOpInterface"); @@ -90,7 +90,8 @@ mlir::Value hlfir::Entity::getFirBase() const { } fir::ExtendedValue -hlfir::translateToExtendedValue(fir::FortranVariableOpInterface variable) { +hlfir::translateToExtendedValue(mlir::Location loc, fir::FirOpBuilder &builder, + fir::FortranVariableOpInterface variable) { /// When going towards FIR, use the original base value to avoid /// introducing descriptors at runtime when they are not required. mlir::Value firBase = Entity{variable}.getFirBase(); @@ -106,6 +107,13 @@ hlfir::translateToExtendedValue(fir::FortranVariableOpInterface variable) { return fir::CharArrayBoxValue(firBase, variable.getExplicitCharLen(), getExplicitExtents(variable), getExplicitLbounds(variable)); + if (auto boxCharType = firBase.getType().dyn_cast()) { + auto unboxed = builder.create( + loc, fir::ReferenceType::get(boxCharType.getEleTy()), + builder.getIndexType(), firBase); + return fir::CharBoxValue(unboxed.getResult(0), + variable.getExplicitCharLen()); + } return fir::CharBoxValue(firBase, variable.getExplicitCharLen()); } if (variable.isArray()) @@ -165,3 +173,55 @@ hlfir::Entity hlfir::loadTrivialScalar(mlir::Location loc, } return entity; } + +static mlir::Value genUBound(mlir::Location loc, fir::FirOpBuilder &builder, + mlir::Value lb, mlir::Value extent, + mlir::Value one) { + if (auto constantLb = fir::factory::getIntIfConstant(lb)) + if (*constantLb == 1) + return extent; + extent = builder.createConvert(loc, one.getType(), extent); + lb = builder.createConvert(loc, one.getType(), lb); + auto add = builder.create(loc, lb, extent); + return builder.create(loc, add, one); +} + +llvm::SmallVector> +hlfir::genBounds(mlir::Location loc, fir::FirOpBuilder &builder, + Entity entity) { + if (entity.getType().isa()) + TODO(loc, "bounds of expressions in hlfir"); + auto [exv, cleanup] = translateToExtendedValue(loc, builder, entity); + assert(!cleanup && "translation of entity should not yield cleanup"); + if (const auto *mutableBox = exv.getBoxOf()) + exv = fir::factory::genMutableBoxRead(builder, loc, *mutableBox); + mlir::Type idxTy = builder.getIndexType(); + mlir::Value one = builder.createIntegerConstant(loc, idxTy, 1); + llvm::SmallVector> result; + for (unsigned dim = 0; dim < exv.rank(); ++dim) { + mlir::Value extent = fir::factory::readExtent(builder, loc, exv, dim); + mlir::Value lb = fir::factory::readLowerBound(builder, loc, exv, dim, one); + mlir::Value ub = genUBound(loc, builder, lb, extent, one); + result.push_back({lb, ub}); + } + return result; +} + +void hlfir::genLengthParameters(mlir::Location loc, fir::FirOpBuilder &builder, + Entity entity, + llvm::SmallVectorImpl &result) { + if (!entity.hasLengthParameters()) + return; + if (entity.getType().isa()) + // Going through fir::ExtendedValue would create a temp, + // which is not desired for an inquiry. + TODO(loc, "inquire type parameters of hlfir.expr"); + + if (entity.isCharacter()) { + auto [exv, cleanup] = translateToExtendedValue(loc, builder, entity); + assert(!cleanup && "translation of entity should not yield cleanup"); + result.push_back(fir::factory::readCharLen(builder, loc, exv)); + return; + } + TODO(loc, "inquire PDTs length parameters in HLFIR"); +} diff --git a/flang/test/Lower/HLFIR/designators.f90 b/flang/test/Lower/HLFIR/designators.f90 new file mode 100644 index 0000000..a2aaad5 --- /dev/null +++ b/flang/test/Lower/HLFIR/designators.f90 @@ -0,0 +1,114 @@ +! Test lowering of designators to HLFIR +! RUN: bbc -emit-fir -hlfir -o - %s 2>&1 | FileCheck %s + +subroutine array_ref(x, n) + real :: x(:) + integer(8) :: n + print *, x(n) +end subroutine +! CHECK-LABEL: func.func @_QParray_ref( +! CHECK: %[[VAL_2:.*]]:2 = hlfir.declare %{{.*}} {uniq_name = "_QFarray_refEn"} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: %[[VAL_3:.*]]:2 = hlfir.declare %{{.*}} {uniq_name = "_QFarray_refEx"} : (!fir.box>) -> (!fir.box>, !fir.box>) +! CHECK: %[[VAL_9:.*]] = fir.load %[[VAL_2]]#0 : !fir.ref +! CHECK: %[[VAL_10:.*]] = hlfir.designate %[[VAL_3]]#0 (%[[VAL_9]]) : (!fir.box>, i64) -> !fir.ref + +subroutine char_array_ref(x, n) + character(*) :: x(:) + print *, x(10) +end subroutine +! CHECK-LABEL: func.func @_QPchar_array_ref( +! CHECK: %[[VAL_2:.*]]:2 = hlfir.declare %{{.*}} {uniq_name = "_QFchar_array_refEn"} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: %[[VAL_3:.*]]:2 = hlfir.declare %{{.*}} {uniq_name = "_QFchar_array_refEx"} : (!fir.box>>) -> (!fir.box>>, !fir.box>>) +! CHECK: %[[VAL_9:.*]] = fir.box_elesize %[[VAL_3]]#1 : (!fir.box>>) -> index +! CHECK: %[[VAL_10:.*]] = arith.constant 10 : index +! CHECK: %[[VAL_11:.*]] = hlfir.designate %[[VAL_3]]#0 (%[[VAL_10]]) typeparams %[[VAL_9]] : (!fir.box>>, index, index) -> !fir.boxchar<1> + +subroutine char_array_ref_cst_len(x, n) + character(5) :: x(:) + print *, x(10) +end subroutine +! CHECK-LABEL: func.func @_QPchar_array_ref_cst_len( +! CHECK: %[[VAL_2:.*]]:2 = hlfir.declare %{{.*}} {uniq_name = "_QFchar_array_ref_cst_lenEn"} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: %[[VAL_3:.*]] = arith.constant 5 : index +! CHECK: %[[VAL_4:.*]]:2 = hlfir.declare %{{.*}} typeparams %[[VAL_3]] {uniq_name = "_QFchar_array_ref_cst_lenEx"} : (!fir.box>>, index) -> (!fir.box>>, !fir.box>>) +! CHECK: %[[VAL_10:.*]] = arith.constant 10 : index +! CHECK: %[[VAL_11:.*]] = hlfir.designate %[[VAL_4]]#0 (%[[VAL_10]]) typeparams %[[VAL_3]] : (!fir.box>>, index, index) -> !fir.ref> + +subroutine array_section(x) + real :: x(10) + print *, x(2:8:3) +end subroutine +! CHECK-LABEL: func.func @_QParray_section( +! CHECK: %[[VAL_1:.*]] = arith.constant 10 : index +! CHECK: %[[VAL_2:.*]] = fir.shape %[[VAL_1]] : (index) -> !fir.shape<1> +! CHECK: %[[VAL_3:.*]]:2 = hlfir.declare %{{.*}}(%[[VAL_2]]) {uniq_name = "_QFarray_sectionEx"} : (!fir.ref>, !fir.shape<1>) -> (!fir.ref>, !fir.ref>) +! CHECK: %[[VAL_9:.*]] = arith.constant 2 : index +! CHECK: %[[VAL_10:.*]] = arith.constant 8 : index +! CHECK: %[[VAL_11:.*]] = arith.constant 3 : index +! CHECK: %[[VAL_12:.*]] = arith.constant 3 : index +! CHECK: %[[VAL_13:.*]] = fir.shape %[[VAL_12]] : (index) -> !fir.shape<1> +! CHECK: %[[VAL_14:.*]] = hlfir.designate %[[VAL_3]]#0 (%[[VAL_9]]:%[[VAL_10]]:%[[VAL_11]]) shape %[[VAL_13]] : (!fir.ref>, index, index, index, !fir.shape<1>) -> !fir.box> + +subroutine array_section_2(x, n) + real :: x(:) + integer(8) :: n + print *, x(n::3) +end subroutine +! CHECK-LABEL: func.func @_QParray_section_2( +! CHECK: %[[VAL_2:.*]]:2 = hlfir.declare %{{.*}} {uniq_name = "_QFarray_section_2En"} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: %[[VAL_3:.*]]:2 = hlfir.declare %{{.*}} {uniq_name = "_QFarray_section_2Ex"} : (!fir.box>) -> (!fir.box>, !fir.box>) +! CHECK: %[[VAL_9:.*]] = fir.load %[[VAL_2]]#0 : !fir.ref +! CHECK: %[[VAL_10:.*]] = arith.constant 0 : index +! CHECK: %[[VAL_11:.*]]:3 = fir.box_dims %[[VAL_3]]#1, %[[VAL_10]] : (!fir.box>, index) -> (index, index, index) +! CHECK: %[[VAL_12:.*]] = fir.convert %[[VAL_9]] : (i64) -> index +! CHECK: %[[VAL_13:.*]] = arith.constant 3 : index +! CHECK: %[[VAL_14:.*]] = arith.constant 0 : index +! CHECK: %[[VAL_15:.*]] = arith.subi %[[VAL_11]]#1, %[[VAL_12]] : index +! CHECK: %[[VAL_16:.*]] = arith.addi %[[VAL_15]], %[[VAL_13]] : index +! CHECK: %[[VAL_17:.*]] = arith.divsi %[[VAL_16]], %[[VAL_13]] : index +! CHECK: %[[VAL_18:.*]] = arith.cmpi sgt, %[[VAL_17]], %[[VAL_14]] : index +! CHECK: %[[VAL_19:.*]] = arith.select %[[VAL_18]], %[[VAL_17]], %[[VAL_14]] : index +! CHECK: %[[VAL_20:.*]] = fir.shape %[[VAL_19]] : (index) -> !fir.shape<1> +! CHECK: %[[VAL_21:.*]] = hlfir.designate %[[VAL_3]]#0 (%[[VAL_12]]:%[[VAL_11]]#1:%[[VAL_13]]) shape %[[VAL_20]] : (!fir.box>, index, index, index, !fir.shape<1>) -> !fir.box> + +subroutine char_array_section(x, n) + character(*) :: x(:) + print *, x(::3) +end subroutine +! CHECK-LABEL: func.func @_QPchar_array_section( +! CHECK: %[[VAL_2:.*]]:2 = hlfir.declare %{{.*}} {uniq_name = "_QFchar_array_sectionEn"} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: %[[VAL_3:.*]]:2 = hlfir.declare %{{.*}} {uniq_name = "_QFchar_array_sectionEx"} : (!fir.box>>) -> (!fir.box>>, !fir.box>>) +! CHECK: %[[VAL_9:.*]] = fir.box_elesize %[[VAL_3]]#1 : (!fir.box>>) -> index +! CHECK: %[[VAL_10:.*]] = arith.constant 1 : index +! CHECK: %[[VAL_11:.*]] = arith.constant 0 : index +! CHECK: %[[VAL_12:.*]]:3 = fir.box_dims %[[VAL_3]]#1, %[[VAL_11]] : (!fir.box>>, index) -> (index, index, index) +! CHECK: %[[VAL_13:.*]] = arith.constant 3 : index +! CHECK: %[[VAL_14:.*]] = arith.constant 0 : index +! CHECK: %[[VAL_15:.*]] = arith.subi %[[VAL_12]]#1, %[[VAL_10]] : index +! CHECK: %[[VAL_16:.*]] = arith.addi %[[VAL_15]], %[[VAL_13]] : index +! CHECK: %[[VAL_17:.*]] = arith.divsi %[[VAL_16]], %[[VAL_13]] : index +! CHECK: %[[VAL_18:.*]] = arith.cmpi sgt, %[[VAL_17]], %[[VAL_14]] : index +! CHECK: %[[VAL_19:.*]] = arith.select %[[VAL_18]], %[[VAL_17]], %[[VAL_14]] : index +! CHECK: %[[VAL_20:.*]] = fir.shape %[[VAL_19]] : (index) -> !fir.shape<1> +! CHECK: %[[VAL_21:.*]] = hlfir.designate %[[VAL_3]]#0 (%[[VAL_10]]:%[[VAL_12]]#1:%[[VAL_13]]) shape %[[VAL_20]] typeparams %[[VAL_9]] : (!fir.box>>, index, index, index, !fir.shape<1>, index) -> !fir.box>> + +subroutine char_array_section_cst_len(x, n) + character(5) :: x(:) + print *, x(::3) +end subroutine +! CHECK-LABEL: func.func @_QPchar_array_section_cst_len( +! CHECK: %[[VAL_2:.*]]:2 = hlfir.declare %{{.*}} {uniq_name = "_QFchar_array_section_cst_lenEn"} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: %[[VAL_3:.*]] = arith.constant 5 : index +! CHECK: %[[VAL_4:.*]]:2 = hlfir.declare %{{.*}} typeparams %[[VAL_3]] {uniq_name = "_QFchar_array_section_cst_lenEx"} : (!fir.box>>, index) -> (!fir.box>>, !fir.box>>) +! CHECK: %[[VAL_10:.*]] = arith.constant 1 : index +! CHECK: %[[VAL_11:.*]] = arith.constant 0 : index +! CHECK: %[[VAL_12:.*]]:3 = fir.box_dims %[[VAL_4]]#1, %[[VAL_11]] : (!fir.box>>, index) -> (index, index, index) +! CHECK: %[[VAL_13:.*]] = arith.constant 3 : index +! CHECK: %[[VAL_14:.*]] = arith.constant 0 : index +! CHECK: %[[VAL_15:.*]] = arith.subi %[[VAL_12]]#1, %[[VAL_10]] : index +! CHECK: %[[VAL_16:.*]] = arith.addi %[[VAL_15]], %[[VAL_13]] : index +! CHECK: %[[VAL_17:.*]] = arith.divsi %[[VAL_16]], %[[VAL_13]] : index +! CHECK: %[[VAL_18:.*]] = arith.cmpi sgt, %[[VAL_17]], %[[VAL_14]] : index +! CHECK: %[[VAL_19:.*]] = arith.select %[[VAL_18]], %[[VAL_17]], %[[VAL_14]] : index +! CHECK: %[[VAL_20:.*]] = fir.shape %[[VAL_19]] : (index) -> !fir.shape<1> +! CHECK: %[[VAL_21:.*]] = hlfir.designate %[[VAL_4]]#0 (%[[VAL_10]]:%[[VAL_12]]#1:%[[VAL_13]]) shape %[[VAL_20]] typeparams %[[VAL_3]] : (!fir.box>>, index, index, index, !fir.shape<1>, index) -> !fir.box>> -- 2.7.4