bool hasConstantShape() const {
if (auto eleTy = fir::dyn_cast_ptrEleTy(getAddr().getType()))
if (auto arrTy = eleTy.dyn_cast<fir::SequenceType>())
- return arrTy.hasConstantShape();
+ return !arrTy.hasDynamicExtents();
return false;
}
/// 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.
// 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<C...xCxT>`), unknown shape
- // (`array<*xT>`), or rows with shape and ending with column(s) of
- // unknown extent (`array<C...xCx?...x?xT>`).
- 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>`)
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<fir::AllocMemOp>(loc, type)
: builder.create<fir::AllocMemOp>(
loc, type, ".array.expr", llvm::None, shape);
mlir::ConversionPatternRewriter &rewriter) {
mlir::Location loc = op.getLoc();
mlir::Type dataTy = op.getInType();
- mlir::Type scalarType = fir::unwrapSequenceType(dataTy);
auto seqTy = dataTy.dyn_cast<fir::SequenceType>();
- 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<int>(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;
}
return rewriteDynamicShape(embox, rewriter, shapeVal);
if (auto boxTy = embox.getType().dyn_cast<fir::BoxType>())
if (auto seqTy = boxTy.getEleTy().dyn_cast<fir::SequenceType>())
- if (seqTy.hasConstantShape())
+ if (!seqTy.hasDynamicExtents())
return rewriteStaticShape(embox, rewriter, seqTy);
return mlir::failure();
}
// degenerate the array and do not want a the type to become `T**` but
// merely `T*`.
if (auto seqTy = eleTy.dyn_cast<fir::SequenceType>()) {
- if (!seqTy.hasConstantShape() ||
+ if (seqTy.hasDynamicExtents() ||
characterWithDynamicLen(seqTy.getEleTy())) {
- if (seqTy.hasConstantInterior())
+ if (seqTy.getConstantRows() > 0)
return convertType(seqTy);
eleTy = seqTy.getEleTy();
}
if (--i == 0)
break;
}
- if (seq.hasConstantShape())
+ if (!seq.hasDynamicExtents())
return baseTy;
}
return mlir::LLVM::LLVMPointerType::get(baseTy);
}
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<mlir::InFlightDiagnostic()> emitError,
llvm::ArrayRef<int64_t> shape, mlir::Type eleTy,
// 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<!fir.array<4x?x3x?x5xi32>> {
%a = fir.alloca !fir.array<4x?x3x?x5xi32>, %0, %1
return %a : !fir.ref<!fir.array<4x?x3x?x5xi32>>
// 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<!fir.array<3x?x4x!fir.char<2,10>>> {
%1 = fir.alloca !fir.array<3x?x4x!fir.char<2,10>>, %e
return %1 : !fir.ref<!fir.array<3x?x4x!fir.char<2,10>>>
// 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<!fir.array<4x?x3x?x5xi32>> {
// 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<!fir.array<3x?x4x!fir.char<2,10>>> {
%1 = fir.allocmem !fir.array<3x?x4x!fir.char<2,10>>, %e
}
// CHECK-LABEL: llvm.func @alloca_array_with_holes
-// CHECK-SAME: ([[A:%.*]]: i64, [[B:%.*]]: i64) -> !llvm.ptr<i32>
+// CHECK-SAME: ([[A:%.*]]: i64, [[B:%.*]]: i64) -> !llvm.ptr<array<4 x i32>>
// 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<i32>
+// CHECK: [[RES:%.*]] = llvm.alloca [[PROD3]] x !llvm.array<4 x i32> {in_type = !fir.array<4x?x3x?x5xi32>
+// CHECK: llvm.return [[RES]] : !llvm.ptr<array<4 x i32>>
// -----
// CHECK-SAME: !llvm.ptr<struct<(ptr<struct<"_QMs1Ta1", (i32, f32)>>, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, ptr<i{{.*}}>, array<1 x i{{.*}}>)>>
func.func private @foo3(%arg0: !fir.ref<!fir.array<10x?x11xf32>>)
// CHECK-LABEL: foo3
-// CHECK-SAME: !llvm.ptr<f32>
+// CHECK-SAME: !llvm.ptr<array<10 x f32>>
func.func private @foo4(%arg0: !fir.ref<!fir.array<10x11x?x?xf32>>)
// CHECK-LABEL: foo4
// CHECK-SAME: !llvm.ptr<array<11 x array<10 x f32>>>