diff --git a/flang/include/flang/Lower/SymbolMap.h b/flang/include/flang/Lower/SymbolMap.h --- a/flang/include/flang/Lower/SymbolMap.h +++ b/flang/include/flang/Lower/SymbolMap.h @@ -145,7 +145,7 @@ bool hasConstantShape() const { if (auto eleTy = fir::dyn_cast_ptrEleTy(getAddr().getType())) if (auto arrTy = eleTy.dyn_cast()) - return arrTy.hasConstantShape(); + return !arrTy.hasDynamicExtents(); return false; } diff --git a/flang/include/flang/Optimizer/Dialect/FIRType.h b/flang/include/flang/Optimizer/Dialect/FIRType.h --- a/flang/include/flang/Optimizer/Dialect/FIRType.h +++ b/flang/include/flang/Optimizer/Dialect/FIRType.h @@ -155,7 +155,7 @@ /// Returns true iff `seqTy` has either an unknown shape or a non-constant shape /// (where rank > 0). inline bool sequenceWithNonConstantShape(fir::SequenceType seqTy) { - return seqTy.hasUnknownShape() || !seqTy.hasConstantShape(); + return seqTy.hasUnknownShape() || seqTy.hasDynamicExtents(); } /// Returns true iff the type `t` does not have a constant size. diff --git a/flang/include/flang/Optimizer/Dialect/FIRTypes.td b/flang/include/flang/Optimizer/Dialect/FIRTypes.td --- a/flang/include/flang/Optimizer/Dialect/FIRTypes.td +++ b/flang/include/flang/Optimizer/Dialect/FIRTypes.td @@ -459,15 +459,12 @@ // The number of dimensions of the sequence unsigned getDimension() const { return getShape().size(); } - // Is the interior of the sequence constant? Check if the array is - // one of constant shape (`array`), unknown shape - // (`array<*xT>`), or rows with shape and ending with column(s) of - // unknown extent (`array`). - bool hasConstantInterior() const; - - // Is the shape of the sequence constant? - bool hasConstantShape() const { - return getConstantRows() == getDimension(); + // Is the shape of the sequence dynamic? + bool hasDynamicExtents() const { + for(const auto d : getShape()) + if (d == getUnknownExtent()) + return true; + return false; } // Does the sequence have unknown shape? (`array<* x T>`) diff --git a/flang/lib/Lower/ConvertExpr.cpp b/flang/lib/Lower/ConvertExpr.cpp --- a/flang/lib/Lower/ConvertExpr.cpp +++ b/flang/lib/Lower/ConvertExpr.cpp @@ -4727,7 +4727,7 @@ fir::isRecordWithAllocatableMember(eleTy)) TODO(loc, "creating an array temp where the element type has " "allocatable members"); - mlir::Value temp = seqTy.hasConstantShape() + mlir::Value temp = !seqTy.hasDynamicExtents() ? builder.create(loc, type) : builder.create( loc, type, ".array.expr", llvm::None, shape); diff --git a/flang/lib/Optimizer/CodeGen/CodeGen.cpp b/flang/lib/Optimizer/CodeGen/CodeGen.cpp --- a/flang/lib/Optimizer/CodeGen/CodeGen.cpp +++ b/flang/lib/Optimizer/CodeGen/CodeGen.cpp @@ -332,20 +332,26 @@ mlir::ConversionPatternRewriter &rewriter) { mlir::Location loc = op.getLoc(); mlir::Type dataTy = op.getInType(); - mlir::Type scalarType = fir::unwrapSequenceType(dataTy); auto seqTy = dataTy.dyn_cast(); - if ((op.hasShapeOperands() && seqTy && !seqTy.hasConstantInterior()) || - (seqTy && fir::characterWithDynamicLen(scalarType))) { - fir::SequenceType::Extent constSize = 1; - for (auto extent : seqTy.getShape()) - if (extent != fir::SequenceType::getUnknownExtent()) - constSize *= extent; - if (constSize != 1) { - mlir::Value constVal{ - genConstantIndex(loc, ity, rewriter, constSize).getResult()}; - return constVal; + fir::SequenceType::Extent constSize = 1; + if (seqTy) { + int constRows = seqTy.getConstantRows(); + const fir::SequenceType::ShapeRef &shape = seqTy.getShape(); + if (constRows != static_cast(shape.size())) { + for (auto extent : shape) { + if (constRows-- > 0) + continue; + if (extent != fir::SequenceType::getUnknownExtent()) + constSize *= extent; + } } } + + if (constSize != 1) { + mlir::Value constVal{ + genConstantIndex(loc, ity, rewriter, constSize).getResult()}; + return constVal; + } return nullptr; } diff --git a/flang/lib/Optimizer/CodeGen/PreCGRewrite.cpp b/flang/lib/Optimizer/CodeGen/PreCGRewrite.cpp --- a/flang/lib/Optimizer/CodeGen/PreCGRewrite.cpp +++ b/flang/lib/Optimizer/CodeGen/PreCGRewrite.cpp @@ -81,7 +81,7 @@ return rewriteDynamicShape(embox, rewriter, shapeVal); if (auto boxTy = embox.getType().dyn_cast()) if (auto seqTy = boxTy.getEleTy().dyn_cast()) - if (seqTy.hasConstantShape()) + if (!seqTy.hasDynamicExtents()) return rewriteStaticShape(embox, rewriter, seqTy); return mlir::failure(); } diff --git a/flang/lib/Optimizer/CodeGen/TypeConverter.h b/flang/lib/Optimizer/CodeGen/TypeConverter.h --- a/flang/lib/Optimizer/CodeGen/TypeConverter.h +++ b/flang/lib/Optimizer/CodeGen/TypeConverter.h @@ -316,9 +316,9 @@ // degenerate the array and do not want a the type to become `T**` but // merely `T*`. if (auto seqTy = eleTy.dyn_cast()) { - if (!seqTy.hasConstantShape() || + if (seqTy.hasDynamicExtents() || characterWithDynamicLen(seqTy.getEleTy())) { - if (seqTy.hasConstantInterior()) + if (seqTy.getConstantRows() > 0) return convertType(seqTy); eleTy = seqTy.getEleTy(); } @@ -356,7 +356,7 @@ if (--i == 0) break; } - if (seq.hasConstantShape()) + if (!seq.hasDynamicExtents()) return baseTy; } return mlir::LLVM::LLVMPointerType::get(baseTy); diff --git a/flang/lib/Optimizer/Dialect/FIRType.cpp b/flang/lib/Optimizer/Dialect/FIRType.cpp --- a/flang/lib/Optimizer/Dialect/FIRType.cpp +++ b/flang/lib/Optimizer/Dialect/FIRType.cpp @@ -783,33 +783,18 @@ } unsigned fir::SequenceType::getConstantRows() const { + if (hasDynamicSize(getEleTy())) + return 0; auto shape = getShape(); unsigned count = 0; for (auto d : shape) { - if (d < 0) + if (d == getUnknownExtent()) break; ++count; } return count; } -// This test helps us determine if we can degenerate an array to a -// pointer to some interior section (possibly a single element) of the -// sequence. This is used to determine if we can lower to the LLVM IR. -bool fir::SequenceType::hasConstantInterior() const { - if (hasUnknownShape()) - return true; - auto rows = getConstantRows(); - auto dim = getDimension(); - if (rows == dim) - return true; - auto shape = getShape(); - for (unsigned i = rows, size = dim; i < size; ++i) - if (shape[i] != getUnknownExtent()) - return false; - return true; -} - mlir::LogicalResult fir::SequenceType::verify( llvm::function_ref emitError, llvm::ArrayRef shape, mlir::Type eleTy, diff --git a/flang/test/Fir/alloc.fir b/flang/test/Fir/alloc.fir --- a/flang/test/Fir/alloc.fir +++ b/flang/test/Fir/alloc.fir @@ -277,9 +277,9 @@ // CHECK-LABEL: define ptr @alloca_array_with_holes_nonchar( // CHECK-SAME: i64 %[[a:.*]], i64 %[[b:.*]]) -// CHECK: %[[prod1:.*]] = mul i64 60, %[[a]] +// CHECK: %[[prod1:.*]] = mul i64 15, %[[a]] // CHECK: %[[prod2:.*]] = mul i64 %[[prod1]], %[[b]] -// CHECK: alloca i32, i64 %[[prod2]] +// CHECK: alloca [4 x i32], i64 %[[prod2]] func.func @alloca_array_with_holes_nonchar(%0 : index, %1 : index) -> !fir.ref> { %a = fir.alloca !fir.array<4x?x3x?x5xi32>, %0, %1 return %a : !fir.ref> @@ -287,8 +287,8 @@ // CHECK-LABEL: define ptr @alloca_array_with_holes_char( // CHECK-SAME: i64 %[[e:.*]]) -// CHECK: %[[mul:.*]] = mul i64 12, %[[e]] -// CHECK: alloca [10 x i16], i64 %[[mul]] +// CHECK: %[[mul:.*]] = mul i64 4, %[[e]] +// CHECK: alloca [3 x [10 x i16]], i64 %[[mul]] func.func @alloca_array_with_holes_char(%e: index) -> !fir.ref>> { %1 = fir.alloca !fir.array<3x?x4x!fir.char<2,10>>, %e return %1 : !fir.ref>> @@ -306,7 +306,7 @@ // CHECK-LABEL: define ptr @allocmem_array_with_holes_nonchar( // CHECK-SAME: i64 %[[e1:.*]], i64 %[[e2:.*]]) -// CHECK: %[[a:.*]] = mul i64 240, %[[e1]] +// CHECK: %[[a:.*]] = mul i64 mul (i64 ptrtoint{{.*}} 15), %[[e1]] // CHECK: %[[b:.*]] = mul i64 %3, %[[e2]] // CHECK: call ptr @malloc(i64 %[[b]]) func.func @allocmem_array_with_holes_nonchar(%0 : index, %1 : index) -> !fir.heap> { @@ -316,7 +316,7 @@ // CHECK-LABEL: define ptr @allocmem_array_with_holes_char( // CHECK-SAME: i64 %[[e:.*]]) -// CHECK: %[[mul:.*]] = mul i64 mul (i64 ptrtoint (ptr getelementptr ([10 x i16], ptr null, i64 1) to i64), i64 12), %[[e]] +// CHECK: %[[mul:.*]] = mul i64 mul (i64 ptrtoint (ptr getelementptr ([3 x [10 x i16]], ptr null, i64 1) to i64), i64 4), %[[e]] // CHECK: call ptr @malloc(i64 %[[mul]]) func.func @allocmem_array_with_holes_char(%e: index) -> !fir.heap>> { %1 = fir.allocmem !fir.array<3x?x4x!fir.char<2,10>>, %e diff --git a/flang/test/Fir/convert-to-llvm.fir b/flang/test/Fir/convert-to-llvm.fir --- a/flang/test/Fir/convert-to-llvm.fir +++ b/flang/test/Fir/convert-to-llvm.fir @@ -1164,14 +1164,14 @@ } // CHECK-LABEL: llvm.func @alloca_array_with_holes -// CHECK-SAME: ([[A:%.*]]: i64, [[B:%.*]]: i64) -> !llvm.ptr +// CHECK-SAME: ([[A:%.*]]: i64, [[B:%.*]]: i64) -> !llvm.ptr> // CHECK-DAG: [[ONE:%.*]] = llvm.mlir.constant(1 : i64) : i64 -// CHECK-DAG: [[FIXED:%.*]] = llvm.mlir.constant(60 : i64) : i64 +// CHECK-DAG: [[FIXED:%.*]] = llvm.mlir.constant(15 : i64) : i64 // CHECK: [[PROD1:%.*]] = llvm.mul [[ONE]], [[FIXED]] : i64 // CHECK: [[PROD2:%.*]] = llvm.mul [[PROD1]], [[A]] : i64 // CHECK: [[PROD3:%.*]] = llvm.mul [[PROD2]], [[B]] : i64 -// CHECK: [[RES:%.*]] = llvm.alloca [[PROD3]] x i32 {in_type = !fir.array<4x?x3x?x5xi32> -// CHECK: llvm.return [[RES]] : !llvm.ptr +// CHECK: [[RES:%.*]] = llvm.alloca [[PROD3]] x !llvm.array<4 x i32> {in_type = !fir.array<4x?x3x?x5xi32> +// CHECK: llvm.return [[RES]] : !llvm.ptr> // ----- diff --git a/flang/test/Fir/types-to-llvm.fir b/flang/test/Fir/types-to-llvm.fir --- a/flang/test/Fir/types-to-llvm.fir +++ b/flang/test/Fir/types-to-llvm.fir @@ -49,7 +49,7 @@ // CHECK-SAME: !llvm.ptr>, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, ptr, array<1 x i{{.*}}>)>> func.func private @foo3(%arg0: !fir.ref>) // CHECK-LABEL: foo3 -// CHECK-SAME: !llvm.ptr +// CHECK-SAME: !llvm.ptr> func.func private @foo4(%arg0: !fir.ref>) // CHECK-LABEL: foo4 // CHECK-SAME: !llvm.ptr>>