[flang][lowering] Handle zero extent case in LBOUND
authorJean Perier <jperier@nvidia.com>
Fri, 25 Mar 2022 17:01:50 +0000 (18:01 +0100)
committerJean Perier <jperier@nvidia.com>
Fri, 25 Mar 2022 17:05:54 +0000 (18:05 +0100)
Follow up of https://reviews.llvm.org/D121488. Ensure lower bounds
are `1` when the related dimension extent is zero. Note that lower
bounds from descriptors are now guaranteed to fulfill this property
after the runtime/codegen patches.

Also fixes explicit shape array extent lowering when instantiating
variables to deal with negative extent cases (issue found while testing
LBOUND edge case). This notably caused allocation crashes when dealing
with automatic arrays with reversed bounds or negative size
specification expression. The standard specifies that the extent of such
arrays is zero. This change has some ripple effect in the current lit
tests.

Add move two helpers as part of this change:
- Add a helper to tell if a fir::ExtendedValue describes an assumed size
  array (last dimension extent is unknown to the compiler, both at compile
  time and runtime).

- Move and share getIntIfConstant from Character.cpp so that it can be
  used elsewhere (NFC).

Differential Revision: https://reviews.llvm.org/D122467

flang/include/flang/Optimizer/Builder/BoxValue.h
flang/include/flang/Optimizer/Builder/FIRBuilder.h
flang/lib/Lower/ConvertVariable.cpp
flang/lib/Lower/IntrinsicCall.cpp
flang/lib/Optimizer/Builder/BoxValue.cpp
flang/lib/Optimizer/Builder/Character.cpp
flang/lib/Optimizer/Builder/FIRBuilder.cpp
flang/test/Lower/array-expression.f90
flang/test/Lower/call-parenthesized-arg.f90
flang/test/Lower/character-local-variables.f90
flang/test/Lower/forall/test9.f90

index c81b7e6..55aaa6d 100644 (file)
@@ -468,6 +468,9 @@ public:
                  [](const auto &box) -> unsigned { return box.rank(); });
   }
 
+  /// Is this an assumed size array ?
+  bool isAssumedSize() const;
+
   /// LLVM style debugging of extended values
   LLVM_DUMP_METHOD void dump() const { llvm::errs() << *this << '\n'; }
 
index c2d4254..fae5cfa 100644 (file)
@@ -539,6 +539,9 @@ mlir::Value genLenOfCharacter(fir::FirOpBuilder &builder, mlir::Location loc,
 mlir::Value createZeroValue(fir::FirOpBuilder &builder, mlir::Location loc,
                             mlir::Type type);
 
+/// Unwrap integer constant from an mlir::Value.
+llvm::Optional<std::int64_t> getIntIfConstant(mlir::Value value);
+
 } // namespace fir::factory
 
 #endif // FORTRAN_OPTIMIZER_BUILDER_FIRBUILDER_H
index 361f23b..87ed228 100644 (file)
@@ -1035,7 +1035,8 @@ static mlir::Value computeExtent(fir::FirOpBuilder &builder, mlir::Location loc,
   // Let the folder deal with the common `ub - <const> + 1` case.
   auto diff = builder.create<mlir::arith::SubIOp>(loc, idxTy, ub, lb);
   mlir::Value one = builder.createIntegerConstant(loc, idxTy, 1);
-  return builder.create<mlir::arith::AddIOp>(loc, idxTy, diff, one);
+  auto rawExtent = builder.create<mlir::arith::AddIOp>(loc, idxTy, diff, one);
+  return Fortran::lower::genMaxWithZero(builder, loc, rawExtent);
 }
 
 /// Lower explicit lower bounds into \p result. Does nothing if this is not an
@@ -1068,13 +1069,13 @@ static void lowerExplicitLowerBounds(
 /// Lower explicit extents into \p result if this is an explicit-shape or
 /// assumed-size array. Does nothing if this is not an explicit-shape or
 /// assumed-size array.
-static void lowerExplicitExtents(Fortran::lower::AbstractConverter &converter,
-                                 mlir::Location loc,
-                                 const Fortran::lower::BoxAnalyzer &box,
-                                 llvm::ArrayRef<mlir::Value> lowerBounds,
-                                 llvm::SmallVectorImpl<mlir::Value> &result,
-                                 Fortran::lower::SymMap &symMap,
-                                 Fortran::lower::StatementContext &stmtCtx) {
+static void
+lowerExplicitExtents(Fortran::lower::AbstractConverter &converter,
+                     mlir::Location loc, const Fortran::lower::BoxAnalyzer &box,
+                     llvm::SmallVectorImpl<mlir::Value> &lowerBounds,
+                     llvm::SmallVectorImpl<mlir::Value> &result,
+                     Fortran::lower::SymMap &symMap,
+                     Fortran::lower::StatementContext &stmtCtx) {
   if (!box.isArray())
     return;
   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
@@ -1090,7 +1091,7 @@ static void lowerExplicitExtents(Fortran::lower::AbstractConverter &converter,
       mlir::Value ub = builder.createConvert(
           loc, idxTy, genScalarValue(converter, loc, expr, symMap, stmtCtx));
       if (lowerBounds.empty())
-        result.emplace_back(ub);
+        result.emplace_back(Fortran::lower::genMaxWithZero(builder, loc, ub));
       else
         result.emplace_back(
             computeExtent(builder, loc, lowerBounds[spec.index()], ub));
@@ -1194,7 +1195,7 @@ void Fortran::lower::mapSymbolAttributes(
     mlir::Value dummyArg = symMap.lookupSymbol(sym).getAddr();
     if (lowerToBoxValue(sym, dummyArg)) {
       llvm::SmallVector<mlir::Value> lbounds;
-      llvm::SmallVector<mlir::Value> extents;
+      llvm::SmallVector<mlir::Value> explicitExtents;
       llvm::SmallVector<mlir::Value> explicitParams;
       // Lower lower bounds, explicit type parameters and explicit
       // extents if any.
@@ -1204,10 +1205,10 @@ void Fortran::lower::mapSymbolAttributes(
           explicitParams.push_back(len);
       // TODO: derived type length parameters.
       lowerExplicitLowerBounds(converter, loc, ba, lbounds, symMap, stmtCtx);
-      lowerExplicitExtents(converter, loc, ba, lbounds, extents, symMap,
+      lowerExplicitExtents(converter, loc, ba, lbounds, explicitExtents, symMap,
                            stmtCtx);
-      symMap.addBoxSymbol(sym, dummyArg, lbounds, explicitParams, extents,
-                          replace);
+      symMap.addBoxSymbol(sym, dummyArg, lbounds, explicitParams,
+                          explicitExtents, replace);
       return;
     }
   }
@@ -1229,7 +1230,8 @@ void Fortran::lower::mapSymbolAttributes(
       if (auto high = spec->ubound().GetExplicit()) {
         Fortran::lower::SomeExpr highEx{*high};
         mlir::Value ub = genValue(highEx);
-        shapes.emplace_back(builder.createConvert(loc, idxTy, ub));
+        ub = builder.createConvert(loc, idxTy, ub);
+        shapes.emplace_back(genMaxWithZero(builder, loc, ub));
       } else if (spec->ubound().isColon()) {
         assert(box && "assumed bounds require a descriptor");
         mlir::Value dim =
@@ -1276,16 +1278,15 @@ void Fortran::lower::mapSymbolAttributes(
         } else {
           TODO(loc, "assumed rank lowering");
         }
+        lbounds.emplace_back(lb);
 
         if (auto high = spec->ubound().GetExplicit()) {
           auto expr = Fortran::lower::SomeExpr{*high};
           ub = builder.createConvert(loc, idxTy, genValue(expr));
-          lbounds.emplace_back(lb);
           extents.emplace_back(computeExtent(builder, loc, lb, ub));
         } else {
           // An assumed size array. The extent is not computed.
           assert(spec->ubound().isStar() && "expected assumed size");
-          lbounds.emplace_back(lb);
           extents.emplace_back(builder.create<fir::UndefOp>(loc, idxTy));
         }
       }
index 2b92e52..4685ac4 100644 (file)
@@ -3267,21 +3267,82 @@ IntrinsicLibrary::genSize(mlir::Type resultType,
       .getResults()[0];
 }
 
+static bool hasDefaultLowerBound(const fir::ExtendedValue &exv) {
+  return exv.match(
+      [](const fir::ArrayBoxValue &arr) { return arr.getLBounds().empty(); },
+      [](const fir::CharArrayBoxValue &arr) {
+        return arr.getLBounds().empty();
+      },
+      [](const fir::BoxValue &arr) { return arr.getLBounds().empty(); },
+      [](const auto &) { return false; });
+}
+
+/// Compute the lower bound in dimension \p dim (zero based) of \p array
+/// taking care of returning one when the related extent is zero.
+static mlir::Value computeLBOUND(fir::FirOpBuilder &builder, mlir::Location loc,
+                                 const fir::ExtendedValue &array, unsigned dim,
+                                 mlir::Value zero, mlir::Value one) {
+  assert(dim < array.rank() && "invalid dimension");
+  if (hasDefaultLowerBound(array))
+    return one;
+  mlir::Value lb = fir::factory::readLowerBound(builder, loc, array, dim, one);
+  if (dim + 1 == array.rank() && array.isAssumedSize())
+    return lb;
+  mlir::Value extent = fir::factory::readExtent(builder, loc, array, dim);
+  zero = builder.createConvert(loc, extent.getType(), zero);
+  auto dimIsEmpty = builder.create<mlir::arith::CmpIOp>(
+      loc, mlir::arith::CmpIPredicate::eq, extent, zero);
+  one = builder.createConvert(loc, lb.getType(), one);
+  return builder.create<mlir::arith::SelectOp>(loc, dimIsEmpty, one, lb);
+}
+
 // LBOUND
 fir::ExtendedValue
 IntrinsicLibrary::genLbound(mlir::Type resultType,
                             llvm::ArrayRef<fir::ExtendedValue> args) {
-  // Calls to LBOUND that don't have the DIM argument, or for which
-  // the DIM is a compile time constant, are folded to descriptor inquiries by
-  // semantics.  This function covers the situations where a call to the
-  // runtime is required.
-  assert(args.size() == 3);
-  assert(!isAbsent(args[1]));
-  if (const auto *boxValue = args[0].getBoxOf<fir::BoxValue>())
+  assert(args.size() > 0);
+  const fir::ExtendedValue &array = args[0];
+  if (const auto *boxValue = array.getBoxOf<fir::BoxValue>())
     if (boxValue->hasAssumedRank())
       TODO(loc, "LBOUND intrinsic with assumed rank argument");
 
-  const fir::ExtendedValue &array = args[0];
+  //===----------------------------------------------------------------------===//
+  mlir::Type indexType = builder.getIndexType();
+
+  if (isAbsent(args, 1)) {
+    mlir::Type lbType = fir::unwrapSequenceType(resultType);
+    unsigned rank = array.rank();
+    mlir::Type lbArrayType = fir::SequenceType::get(
+        {static_cast<fir::SequenceType::Extent>(array.rank())}, lbType);
+    mlir::Value lbArray = builder.createTemporary(loc, lbArrayType);
+    mlir::Type lbAddrType = builder.getRefType(lbType);
+    mlir::Value one = builder.createIntegerConstant(loc, lbType, 1);
+    mlir::Value zero = builder.createIntegerConstant(loc, indexType, 0);
+    for (unsigned dim = 0; dim < rank; ++dim) {
+      mlir::Value lb = computeLBOUND(builder, loc, array, dim, zero, one);
+      lb = builder.createConvert(loc, lbType, lb);
+      auto index = builder.createIntegerConstant(loc, indexType, dim);
+      auto lbAddr =
+          builder.create<fir::CoordinateOp>(loc, lbAddrType, lbArray, index);
+      builder.create<fir::StoreOp>(loc, lb, lbAddr);
+    }
+    mlir::Value lbArrayExtent =
+        builder.createIntegerConstant(loc, indexType, rank);
+    llvm::SmallVector<mlir::Value> extents{lbArrayExtent};
+    return fir::ArrayBoxValue{lbArray, extents};
+  }
+  // DIM is present.
+  mlir::Value dim = fir::getBase(args[1]);
+
+  // If it is a compile time constant, skip the runtime call.
+  if (llvm::Optional<std::int64_t> cstDim =
+          fir::factory::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);
+  }
+
   mlir::Value box = array.match(
       [&](const fir::BoxValue &boxValue) -> mlir::Value {
         // This entity is mapped to a fir.box that may not contain the local
@@ -3301,7 +3362,6 @@ IntrinsicLibrary::genLbound(mlir::Type resultType,
         return builder.createBox(loc, array);
       });
 
-  mlir::Value dim = fir::getBase(args[1]);
   return builder.createConvert(
       loc, resultType,
       fir::runtime::genLboundDim(builder, loc, fir::getBase(box), dim));
index dc64276..951bc3e 100644 (file)
@@ -230,3 +230,19 @@ mlir::Value fir::getExtentAtDimension(const fir::ExtendedValue &exv,
     return extents[dim];
   return {};
 }
+
+static inline bool isUndefOp(mlir::Value v) {
+  return mlir::isa_and_nonnull<fir::UndefOp>(v.getDefiningOp());
+}
+
+bool fir::ExtendedValue::isAssumedSize() const {
+  return match(
+      [](const fir::ArrayBoxValue &box) -> bool {
+        return !box.getExtents().empty() && isUndefOp(box.getExtents().back());
+        ;
+      },
+      [](const fir::CharArrayBoxValue &box) -> bool {
+        return !box.getExtents().empty() && isUndefOp(box.getExtents().back());
+      },
+      [](const auto &box) -> bool { return false; });
+}
index 97ccea0..4a90a69 100644 (file)
@@ -94,15 +94,6 @@ LLVM_ATTRIBUTE_UNUSED static bool needToMaterialize(mlir::Value str) {
   return str.getType().isa<fir::SequenceType>() || fir::isa_char(str.getType());
 }
 
-/// Unwrap integer constant from mlir::Value.
-static llvm::Optional<std::int64_t> getIntIfConstant(mlir::Value value) {
-  if (auto *definingOp = value.getDefiningOp())
-    if (auto cst = mlir::dyn_cast<mlir::arith::ConstantOp>(definingOp))
-      if (auto intAttr = cst.getValue().dyn_cast<mlir::IntegerAttr>())
-        return intAttr.getInt();
-  return {};
-}
-
 /// This is called only if `str` does not reside in memory. Such a bare string
 /// value will be converted into a memory-based temporary and an extended
 /// boxchar value returned.
index d30eadf..b53d79e 100644 (file)
@@ -1135,3 +1135,11 @@ mlir::Value fir::factory::createZeroValue(fir::FirOpBuilder &builder,
   fir::emitFatalError(loc, "internal: trying to generate zero value of non "
                            "numeric or logical type");
 }
+
+llvm::Optional<std::int64_t> fir::factory::getIntIfConstant(mlir::Value value) {
+  if (auto *definingOp = value.getDefiningOp())
+    if (auto cst = mlir::dyn_cast<mlir::arith::ConstantOp>(definingOp))
+      if (auto intAttr = cst.getValue().dyn_cast<mlir::IntegerAttr>())
+        return intAttr.getInt();
+  return {};
+}
index d268301..8bc5a5d 100644 (file)
@@ -115,10 +115,16 @@ end subroutine test5
 ! CHECK-SAME:    %[[VAL_0:.*]]: !fir.ref<!fir.array<?xf32>>{{.*}}, %[[VAL_1:.*]]: !fir.ref<!fir.array<?xf32>>{{.*}}, %[[VAL_2:.*]]: !fir.ref<f32>{{.*}}, %[[VAL_3:.*]]: !fir.ref<i32>{{.*}}, %[[VAL_4:.*]]: !fir.ref<i32>{{.*}}) {
 ! CHECK:         %[[VAL_5:.*]] = fir.load %[[VAL_3]] : !fir.ref<i32>
 ! CHECK:         %[[VAL_6:.*]] = fir.convert %[[VAL_5]] : (i32) -> i64
-! CHECK:         %[[VAL_7:.*]] = fir.convert %[[VAL_6]] : (i64) -> index
+! CHECK:         %[[VAL_7A:.*]] = fir.convert %[[VAL_6]] : (i64) -> index
+! CHECK:         %[[C0:.*]] = arith.constant 0 : index 
+! CHECK:         %[[CMP:.*]] = arith.cmpi sgt, %[[VAL_7A]], %[[C0]] : index 
+! CHECK:         %[[VAL_7:.*]] = arith.select %[[CMP]], %[[VAL_7A]], %[[C0]] : index 
 ! CHECK:         %[[VAL_8:.*]] = fir.load %[[VAL_4]] : !fir.ref<i32>
 ! CHECK:         %[[VAL_9:.*]] = fir.convert %[[VAL_8]] : (i32) -> i64
-! CHECK:         %[[VAL_10:.*]] = fir.convert %[[VAL_9]] : (i64) -> index
+! CHECK:         %[[VAL_10A:.*]] = fir.convert %[[VAL_9]] : (i64) -> index
+! CHECK:         %[[C0_2:.*]] = arith.constant 0 : index 
+! CHECK:         %[[CMP_2:.*]] = arith.cmpi sgt, %[[VAL_10A]], %[[C0_2]] : index 
+! CHECK:         %[[VAL_10:.*]] = arith.select %[[CMP_2]], %[[VAL_10A]], %[[C0_2]] : index 
 ! CHECK:         %[[VAL_11:.*]] = arith.constant 3 : i64
 ! CHECK:         %[[VAL_12:.*]] = fir.convert %[[VAL_11]] : (i64) -> index
 ! CHECK:         %[[VAL_13:.*]] = arith.constant 4 : i64
@@ -248,10 +254,16 @@ end subroutine test6b
 ! CHECK-SAME:    %[[VAL_0:.*]]: !fir.ref<!fir.array<?xf32>>{{.*}}, %[[VAL_1:.*]]: !fir.ref<!fir.array<?xf32>>{{.*}}, %[[VAL_2:.*]]: !fir.ref<i32>{{.*}}) {
 ! CHECK:         %[[VAL_3:.*]] = fir.load %[[VAL_2]] : !fir.ref<i32>
 ! CHECK:         %[[VAL_4:.*]] = fir.convert %[[VAL_3]] : (i32) -> i64
-! CHECK:         %[[VAL_5:.*]] = fir.convert %[[VAL_4]] : (i64) -> index
+! CHECK:         %[[VAL_5A:.*]] = fir.convert %[[VAL_4]] : (i64) -> index
+! CHECK:         %[[C0:.*]] = arith.constant 0 : index 
+! CHECK:         %[[CMP:.*]] = arith.cmpi sgt, %[[VAL_5A]], %[[C0]] : index 
+! CHECK:         %[[VAL_5:.*]] = arith.select %[[CMP]], %[[VAL_5A]], %[[C0]] : index 
 ! CHECK:         %[[VAL_6:.*]] = fir.load %[[VAL_2]] : !fir.ref<i32>
 ! CHECK:         %[[VAL_7:.*]] = fir.convert %[[VAL_6]] : (i32) -> i64
-! CHECK:         %[[VAL_8:.*]] = fir.convert %[[VAL_7]] : (i64) -> index
+! CHECK:         %[[VAL_8A:.*]] = fir.convert %[[VAL_7]] : (i64) -> index
+! CHECK:         %[[C0_2:.*]] = arith.constant 0 : index 
+! CHECK:         %[[CMP_2:.*]] = arith.cmpi sgt, %[[VAL_8A]], %[[C0_2]] : index 
+! CHECK:         %[[VAL_8:.*]] = arith.select %[[CMP_2]], %[[VAL_8A]], %[[C0_2]] : index 
 ! CHECK:         %[[VAL_9:.*]] = fir.shape %[[VAL_5]] : (index) -> !fir.shape<1>
 ! CHECK:         %[[VAL_10:.*]] = fir.array_load %[[VAL_0]](%[[VAL_9]]) : (!fir.ref<!fir.array<?xf32>>, !fir.shape<1>) -> !fir.array<?xf32>
 ! CHECK:         %[[VAL_11:.*]] = fir.shape %[[VAL_5]] : (index) -> !fir.shape<1>
@@ -1052,7 +1064,10 @@ end subroutine test19g
 ! CHECK:         %[[VAL_12:.*]] = fir.convert %[[VAL_11]]#0 : (!fir.ref<!fir.char<1,?>>) -> !fir.ref<!fir.array<?x!fir.char<1,?>>>
 ! CHECK:         %[[VAL_13:.*]] = fir.load %[[VAL_3]] : !fir.ref<i32>
 ! CHECK:         %[[VAL_14:.*]] = fir.convert %[[VAL_13]] : (i32) -> i64
-! CHECK:         %[[VAL_15:.*]] = fir.convert %[[VAL_14]] : (i64) -> index
+! CHECK:         %[[VAL_15A:.*]] = fir.convert %[[VAL_14]] : (i64) -> index
+! CHECK:         %[[C0:.*]] = arith.constant 0 : index 
+! CHECK:         %[[CMP:.*]] = arith.cmpi sgt, %[[VAL_15A]], %[[C0]] : index 
+! CHECK:         %[[VAL_15:.*]] = arith.select %[[CMP]], %[[VAL_15A]], %[[C0]] : index 
 ! CHECK:         %[[VAL_16:.*]] = fir.shape %[[VAL_10]] : (index) -> !fir.shape<1>
 ! CHECK:         %[[VAL_17:.*]] = fir.array_load %[[VAL_9]](%[[VAL_16]]) typeparams %[[VAL_8]] : (!fir.ref<!fir.array<70x!fir.char<1,?>>>, !fir.shape<1>, i32) -> !fir.array<70x!fir.char<1,?>>
 ! CHECK:         %[[VAL_18:.*]] = arith.constant 1 : i64
index 3454b8b..92b6706 100644 (file)
@@ -172,7 +172,10 @@ subroutine foo_char_array_box(x, n)
   ! CHECK: %[[VAL_3:.*]] = fir.convert %[[VAL_2]]#0 : (!fir.ref<!fir.char<1,?>>) -> !fir.ref<!fir.array<?x!fir.char<1,10>>>
   ! CHECK: %[[VAL_4:.*]] = fir.load %[[VAL_1]] : !fir.ref<i32>
   ! CHECK: %[[VAL_5:.*]] = fir.convert %[[VAL_4]] : (i32) -> i64
-  ! CHECK: %[[VAL_6:.*]] = fir.convert %[[VAL_5]] : (i64) -> index
+  ! CHECK: %[[VAL_6A:.*]] = fir.convert %[[VAL_5]] : (i64) -> index
+  ! CHECK: %[[C0:.*]] = arith.constant 0 : index 
+  ! CHECK: %[[CMP:.*]] = arith.cmpi sgt, %[[VAL_6A]], %[[C0]] : index 
+  ! CHECK: %[[VAL_6:.*]] = arith.select %[[CMP]], %[[VAL_6A]], %[[C0]] : index 
   ! CHECK: %[[VAL_7:.*]] = fir.shape %[[VAL_6]] : (index) -> !fir.shape<1>
   ! CHECK: %[[VAL_8:.*]] = fir.embox %[[VAL_3]](%[[VAL_7]]) : (!fir.ref<!fir.array<?x!fir.char<1,10>>>, !fir.shape<1>) -> !fir.box<!fir.array<?x!fir.char<1,10>>>
   ! CHECK: %[[VAL_9:.*]] = fir.convert %[[VAL_8]] : (!fir.box<!fir.array<?x!fir.char<1,10>>>) -> !fir.box<!fir.array<?x!fir.char<1,?>>>
index 555f11e..c281d82 100644 (file)
@@ -43,7 +43,9 @@ subroutine dyn_array_cst_len(n)
   character(10) :: c(n)
   ! CHECK: %[[n:.*]] = fir.load %[[arg0]] : !fir.ref<i32>
   ! CHECK: %[[ni:.*]] = fir.convert %[[n]] : (i32) -> index
-  ! CHECK: fir.alloca !fir.array<?x!fir.char<1,10>>, %[[ni]] {{{.*}}uniq_name = "_QFdyn_array_cst_lenEc"}
+  ! CHECK: %[[is_positive:.*]] = arith.cmpi sgt, %[[ni]], %c0{{.*}} : index
+  ! CHECK: %[[extent:.*]] = arith.select %[[is_positive]], %[[ni]], %c0{{.*}} : index
+  ! CHECK: fir.alloca !fir.array<?x!fir.char<1,10>>, %[[extent]] {{{.*}}uniq_name = "_QFdyn_array_cst_lenEc"}
 end subroutine
 
 ! CHECK: func @_QPdyn_array_dyn_len
@@ -56,7 +58,9 @@ subroutine dyn_array_dyn_len(l, n)
   ! CHECK-DAG: %[[l:.*]] = arith.select %[[is_positive]], %[[lexpr]], %c0{{.*}} : i32
   ! CHECK-DAG: %[[n:.*]] = fir.load %[[arg1]] : !fir.ref<i32>
   ! CHECK: %[[ni:.*]] = fir.convert %[[n]] : (i32) -> index
-  ! CHECK: fir.alloca !fir.array<?x!fir.char<1,?>>(%[[l]] : i32), %[[ni]] {{{.*}}uniq_name = "_QFdyn_array_dyn_lenEc"}
+  ! CHECK: %[[is_positive:.*]] = arith.cmpi sgt, %[[ni]], %c0{{.*}} : index
+  ! CHECK: %[[extent:.*]] = arith.select %[[is_positive]], %[[ni]], %c0{{.*}} : index
+  ! CHECK: fir.alloca !fir.array<?x!fir.char<1,?>>(%[[l]] : i32), %[[extent]] {{{.*}}uniq_name = "_QFdyn_array_dyn_lenEc"}
 end subroutine
 
 ! CHECK-LABEL: func @_QPcst_array_cst_len_lb
@@ -84,7 +88,9 @@ subroutine dyn_array_cst_len_lb(n)
   ! CHECK-DAG: %[[cm10:.*]] = arith.constant -10 : index
   ! CHECK-DAG: %[[n:.*]] = fir.load %[[arg0]] : !fir.ref<i64>
   ! CHECK-DAG: %[[ni:.*]] = fir.convert %[[n]] : (i64) -> index
-  ! CHECK: %[[extent:.*]] = arith.addi %[[ni]], %[[cm10]] : index
+  ! CHECK: %[[raw_extent:.*]] = arith.addi %[[ni]], %[[cm10]] : index
+  ! CHECK: %[[is_positive:.*]] = arith.cmpi sgt, %[[raw_extent]], %c0{{.*}} : index
+  ! CHECK: %[[extent:.*]] = arith.select %[[is_positive]], %[[raw_extent]], %c0{{.*}} : index
   ! CHECK: fir.alloca !fir.array<?x!fir.char<1,10>>, %[[extent]] {{{.*}}uniq_name = "_QFdyn_array_cst_len_lbEc"}
 end subroutine
 
@@ -99,7 +105,9 @@ subroutine dyn_array_dyn_len_lb(l, n)
   ! CHECK-DAG: %[[l:.*]] = arith.select %[[is_positive]], %[[lexpr]], %c0{{.*}} : i64
   ! CHECK-DAG: %[[n:.*]] = fir.load %[[arg1]] : !fir.ref<i64>
   ! CHECK-DAG: %[[ni:.*]] = fir.convert %[[n]] : (i64) -> index
-  ! CHECK: %[[extent:.*]] = arith.addi %[[ni]], %[[cm10]] : index
+  ! CHECK: %[[raw_extent:.*]] = arith.addi %[[ni]], %[[cm10]] : index
+  ! CHECK: %[[is_positive:.*]] = arith.cmpi sgt, %[[raw_extent]], %c0{{.*}} : index
+  ! CHECK: %[[extent:.*]] = arith.select %[[is_positive]], %[[raw_extent]], %c0{{.*}} : index
   ! CHECK: fir.alloca !fir.array<?x!fir.char<1,?>>(%[[l]] : i64), %[[extent]] {{{.*}}uniq_name = "_QFdyn_array_dyn_len_lbEc"}
 end subroutine
 
index 1d20cad..6ac862b 100644 (file)
@@ -20,10 +20,16 @@ end subroutine test9
 ! CHECK:         %[[VAL_3:.*]] = fir.alloca i32 {adapt.valuebyref, bindc_name = "i"}
 ! CHECK:         %[[VAL_4:.*]] = fir.load %[[VAL_2]] : !fir.ref<i32>
 ! CHECK:         %[[VAL_5:.*]] = fir.convert %[[VAL_4]] : (i32) -> i64
-! CHECK:         %[[VAL_6:.*]] = fir.convert %[[VAL_5]] : (i64) -> index
+! CHECK:         %[[VAL_6A:.*]] = fir.convert %[[VAL_5]] : (i64) -> index
+! CHECK:         %[[C0:.*]] = arith.constant 0 : index
+! CHECK:         %[[CMP:.*]] = arith.cmpi sgt, %[[VAL_6A]], %[[C0]] : index
+! CHECK:         %[[VAL_6:.*]] = arith.select %[[CMP]], %[[VAL_6A]], %[[C0]] : index
 ! CHECK:         %[[VAL_7:.*]] = fir.load %[[VAL_2]] : !fir.ref<i32>
 ! CHECK:         %[[VAL_8:.*]] = fir.convert %[[VAL_7]] : (i32) -> i64
-! CHECK:         %[[VAL_9:.*]] = fir.convert %[[VAL_8]] : (i64) -> index
+! CHECK:         %[[VAL_9A:.*]] = fir.convert %[[VAL_8]] : (i64) -> index
+! CHECK:         %[[C0_2:.*]] = arith.constant 0 : index
+! CHECK:         %[[CMP_2:.*]] = arith.cmpi sgt, %[[VAL_9A]], %[[C0_2]] : index
+! CHECK:         %[[VAL_9:.*]] = arith.select %[[CMP_2]], %[[VAL_9A]], %[[C0_2]] : index
 ! CHECK:         %[[VAL_10:.*]] = arith.constant 1 : i32
 ! CHECK:         %[[VAL_11:.*]] = fir.convert %[[VAL_10]] : (i32) -> index
 ! CHECK:         %[[VAL_12:.*]] = fir.load %[[VAL_2]] : !fir.ref<i32>