[flang-commits] [flang] d88dfd2 - [flang] Handle dynamic array lowering
Valentin Clement via flang-commits
flang-commits at lists.llvm.org
Tue Mar 1 13:30:00 PST 2022
Author: Valentin Clement
Date: 2022-03-01T22:29:49+01:00
New Revision: d88dfd2b311d5f7f8ab9faa0edfd380c1fd2d2b2
URL: https://github.com/llvm/llvm-project/commit/d88dfd2b311d5f7f8ab9faa0edfd380c1fd2d2b2
DIFF: https://github.com/llvm/llvm-project/commit/d88dfd2b311d5f7f8ab9faa0edfd380c1fd2d2b2.diff
LOG: [flang] Handle dynamic array lowering
This patch enables dynamic array lowering
and use the funcationality inside some IO tests.
This patch is part of the upstreaming effort from fir-dev branch.
Depends on D120743
Reviewed By: PeteSteinfeld, schweitz
Differential Revision: https://reviews.llvm.org/D120744
Co-authored-by: Eric Schweitz <eschweitz at nvidia.com>
Co-authored-by: Jean Perier <jperier at nvidia.com>
Co-authored-by: V Donaldson <vdonaldson at nvidia.com>
Added:
Modified:
flang/lib/Lower/Bridge.cpp
flang/lib/Lower/ConvertExpr.cpp
flang/lib/Lower/ConvertVariable.cpp
flang/test/Lower/io-statement-1.f90
flang/test/Lower/io-statement-2.f90
Removed:
################################################################################
diff --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp
index f7e142ef451e..6a3e8244bd5b 100644
--- a/flang/lib/Lower/Bridge.cpp
+++ b/flang/lib/Lower/Bridge.cpp
@@ -1087,10 +1087,6 @@ class FirConverter : public Fortran::lower::AbstractConverter {
TODO(toLocation(), "CaseStmt lowering");
}
- void genFIR(const Fortran::parser::ContinueStmt &) {
- TODO(toLocation(), "ContinueStmt lowering");
- }
-
void genFIR(const Fortran::parser::ElseIfStmt &) {
TODO(toLocation(), "ElseIfStmt lowering");
}
@@ -1120,6 +1116,7 @@ class FirConverter : public Fortran::lower::AbstractConverter {
}
// Nop statements - No code, or code is generated at the construct level.
+ void genFIR(const Fortran::parser::ContinueStmt &) {} // nop
void genFIR(const Fortran::parser::EndFunctionStmt &) {} // nop
void genFIR(const Fortran::parser::EndSubroutineStmt &) {} // nop
diff --git a/flang/lib/Lower/ConvertExpr.cpp b/flang/lib/Lower/ConvertExpr.cpp
index 85ea688ca436..66fc8fbd5156 100644
--- a/flang/lib/Lower/ConvertExpr.cpp
+++ b/flang/lib/Lower/ConvertExpr.cpp
@@ -23,6 +23,7 @@
#include "flang/Lower/StatementContext.h"
#include "flang/Lower/SymbolMap.h"
#include "flang/Lower/Todo.h"
+#include "flang/Optimizer/Builder/Character.h"
#include "flang/Optimizer/Builder/Complex.h"
#include "flang/Optimizer/Builder/Factory.h"
#include "flang/Optimizer/Builder/MutableBox.h"
@@ -850,6 +851,13 @@ class ScalarExprLowering {
return builder.createConvert(loc, ty, lb);
}
+ static bool isSlice(const Fortran::evaluate::ArrayRef &aref) {
+ for (const Fortran::evaluate::Subscript &sub : aref.subscript())
+ if (std::holds_alternative<Fortran::evaluate::Triplet>(sub.u))
+ return true;
+ return false;
+ }
+
/// Lower an ArrayRef to a fir.coordinate_of given its lowered base.
ExtValue genCoordinateOp(const ExtValue &array,
const Fortran::evaluate::ArrayRef &aref) {
@@ -862,7 +870,7 @@ class ScalarExprLowering {
if ((array.rank() > 1 && fir::hasDynamicSize(baseType)) ||
fir::characterWithDynamicLen(fir::unwrapSequenceType(baseType)))
if (!array.getBoxOf<fir::BoxValue>())
- TODO(getLoc(), "genOffsetAndCoordinateOp");
+ return genOffsetAndCoordinateOp(array, aref);
// Generate a fir.coordinate_of with zero based array indexes.
llvm::SmallVector<mlir::Value> args;
for (const auto &subsc : llvm::enumerate(aref.subscript())) {
@@ -883,13 +891,104 @@ class ScalarExprLowering {
return fir::factory::arrayElementToExtendedValue(builder, loc, array, addr);
}
+ /// Lower an ArrayRef to a fir.coordinate_of using an element offset instead
+ /// of array indexes.
+ /// This generates offset computation from the indexes and length parameters,
+ /// and use the offset to access the element with a fir.coordinate_of. This
+ /// must only be used if it is not possible to generate a normal
+ /// fir.coordinate_of using array indexes (i.e. when the shape information is
+ /// unavailable in the IR).
+ ExtValue genOffsetAndCoordinateOp(const ExtValue &array,
+ const Fortran::evaluate::ArrayRef &aref) {
+ mlir::Location loc = getLoc();
+ mlir::Value addr = fir::getBase(array);
+ mlir::Type arrTy = fir::dyn_cast_ptrEleTy(addr.getType());
+ auto eleTy = arrTy.cast<fir::SequenceType>().getEleTy();
+ mlir::Type seqTy = builder.getRefType(builder.getVarLenSeqTy(eleTy));
+ mlir::Type refTy = builder.getRefType(eleTy);
+ mlir::Value base = builder.createConvert(loc, seqTy, addr);
+ mlir::IndexType idxTy = builder.getIndexType();
+ mlir::Value one = builder.createIntegerConstant(loc, idxTy, 1);
+ mlir::Value zero = builder.createIntegerConstant(loc, idxTy, 0);
+ auto getLB = [&](const auto &arr, unsigned dim) -> mlir::Value {
+ return arr.getLBounds().empty() ? one : arr.getLBounds()[dim];
+ };
+ auto genFullDim = [&](const auto &arr, mlir::Value delta) -> mlir::Value {
+ mlir::Value total = zero;
+ assert(arr.getExtents().size() == aref.subscript().size());
+ delta = builder.createConvert(loc, idxTy, delta);
+ unsigned dim = 0;
+ for (auto [ext, sub] : llvm::zip(arr.getExtents(), aref.subscript())) {
+ ExtValue subVal = genSubscript(sub);
+ assert(fir::isUnboxedValue(subVal));
+ mlir::Value val =
+ builder.createConvert(loc, idxTy, fir::getBase(subVal));
+ mlir::Value lb = builder.createConvert(loc, idxTy, getLB(arr, dim));
+ mlir::Value
diff = builder.create<mlir::arith::SubIOp>(loc, val, lb);
+ mlir::Value prod =
+ builder.create<mlir::arith::MulIOp>(loc, delta,
diff );
+ total = builder.create<mlir::arith::AddIOp>(loc, prod, total);
+ if (ext)
+ delta = builder.create<mlir::arith::MulIOp>(loc, delta, ext);
+ ++dim;
+ }
+ mlir::Type origRefTy = refTy;
+ if (fir::factory::CharacterExprHelper::isCharacterScalar(refTy)) {
+ fir::CharacterType chTy =
+ fir::factory::CharacterExprHelper::getCharacterType(refTy);
+ if (fir::characterWithDynamicLen(chTy)) {
+ mlir::MLIRContext *ctx = builder.getContext();
+ fir::KindTy kind =
+ fir::factory::CharacterExprHelper::getCharacterKind(chTy);
+ fir::CharacterType singleTy =
+ fir::CharacterType::getSingleton(ctx, kind);
+ refTy = builder.getRefType(singleTy);
+ mlir::Type seqRefTy =
+ builder.getRefType(builder.getVarLenSeqTy(singleTy));
+ base = builder.createConvert(loc, seqRefTy, base);
+ }
+ }
+ auto coor = builder.create<fir::CoordinateOp>(
+ loc, refTy, base, llvm::ArrayRef<mlir::Value>{total});
+ // Convert to expected, original type after address arithmetic.
+ return builder.createConvert(loc, origRefTy, coor);
+ };
+ return array.match(
+ [&](const fir::ArrayBoxValue &arr) -> ExtValue {
+ // FIXME: this check can be removed when slicing is implemented
+ if (isSlice(aref))
+ fir::emitFatalError(
+ getLoc(),
+ "slice should be handled in array expression context");
+ return genFullDim(arr, one);
+ },
+ [&](const fir::CharArrayBoxValue &arr) -> ExtValue {
+ mlir::Value delta = arr.getLen();
+ // If the length is known in the type, fir.coordinate_of will
+ // already take the length into account.
+ if (fir::factory::CharacterExprHelper::hasConstantLengthInType(arr))
+ delta = one;
+ return fir::CharBoxValue(genFullDim(arr, delta), arr.getLen());
+ },
+ [&](const fir::BoxValue &arr) -> ExtValue {
+ // CoordinateOp for BoxValue is not generated here. The dimensions
+ // must be kept in the fir.coordinate_op so that potential fir.box
+ // strides can be applied by codegen.
+ fir::emitFatalError(
+ loc, "internal: BoxValue in dim-collapsed fir.coordinate_of");
+ },
+ [&](const auto &) -> ExtValue {
+ fir::emitFatalError(loc, "internal: array lowering failed");
+ });
+ }
+
ExtValue gen(const Fortran::evaluate::ArrayRef &aref) {
ExtValue base = aref.base().IsSymbol() ? gen(aref.base().GetFirstSymbol())
: gen(aref.base().GetComponent());
return genCoordinateOp(base, aref);
}
ExtValue genval(const Fortran::evaluate::ArrayRef &aref) {
- TODO(getLoc(), "genval ArrayRef");
+ return genLoad(gen(aref));
}
ExtValue gen(const Fortran::evaluate::CoarrayRef &coref) {
diff --git a/flang/lib/Lower/ConvertVariable.cpp b/flang/lib/Lower/ConvertVariable.cpp
index 593e9c7e6e3e..7d5f188c490d 100644
--- a/flang/lib/Lower/ConvertVariable.cpp
+++ b/flang/lib/Lower/ConvertVariable.cpp
@@ -728,6 +728,86 @@ void Fortran::lower::mapSymbolAttributes(
}
}
+ // Helper to generate scalars for the symbol properties.
+ auto genValue = [&](const Fortran::lower::SomeExpr &expr) {
+ return genScalarValue(converter, loc, expr, symMap, stmtCtx);
+ };
+
+ // For symbols reaching this point, all properties are constant and can be
+ // read/computed already into ssa values.
+
+ // The origin must be \vec{1}.
+ auto populateShape = [&](auto &shapes, const auto &bounds, mlir::Value box) {
+ for (auto iter : llvm::enumerate(bounds)) {
+ auto *spec = iter.value();
+ assert(spec->lbound().GetExplicit() &&
+ "lbound must be explicit with constant value 1");
+ if (auto high = spec->ubound().GetExplicit()) {
+ Fortran::lower::SomeExpr highEx{*high};
+ mlir::Value ub = genValue(highEx);
+ shapes.emplace_back(builder.createConvert(loc, idxTy, ub));
+ } else if (spec->ubound().isColon()) {
+ assert(box && "assumed bounds require a descriptor");
+ mlir::Value dim =
+ builder.createIntegerConstant(loc, idxTy, iter.index());
+ auto dimInfo =
+ builder.create<fir::BoxDimsOp>(loc, idxTy, idxTy, idxTy, box, dim);
+ shapes.emplace_back(dimInfo.getResult(1));
+ } else if (spec->ubound().isStar()) {
+ shapes.emplace_back(builder.create<fir::UndefOp>(loc, idxTy));
+ } else {
+ llvm::report_fatal_error("unknown bound category");
+ }
+ }
+ };
+
+ // The origin is not \vec{1}.
+ auto populateLBoundsExtents = [&](auto &lbounds, auto &extents,
+ const auto &bounds, mlir::Value box) {
+ for (auto iter : llvm::enumerate(bounds)) {
+ auto *spec = iter.value();
+ fir::BoxDimsOp dimInfo;
+ mlir::Value ub, lb;
+ if (spec->lbound().isColon() || spec->ubound().isColon()) {
+ // This is an assumed shape because allocatables and pointers extents
+ // are not constant in the scope and are not read here.
+ assert(box && "deferred bounds require a descriptor");
+ mlir::Value dim =
+ builder.createIntegerConstant(loc, idxTy, iter.index());
+ dimInfo =
+ builder.create<fir::BoxDimsOp>(loc, idxTy, idxTy, idxTy, box, dim);
+ extents.emplace_back(dimInfo.getResult(1));
+ if (auto low = spec->lbound().GetExplicit()) {
+ auto expr = Fortran::lower::SomeExpr{*low};
+ mlir::Value lb = builder.createConvert(loc, idxTy, genValue(expr));
+ lbounds.emplace_back(lb);
+ } else {
+ // Implicit lower bound is 1 (Fortran 2018 section 8.5.8.3 point 3.)
+ lbounds.emplace_back(builder.createIntegerConstant(loc, idxTy, 1));
+ }
+ } else {
+ if (auto low = spec->lbound().GetExplicit()) {
+ auto expr = Fortran::lower::SomeExpr{*low};
+ lb = builder.createConvert(loc, idxTy, genValue(expr));
+ } else {
+ TODO(loc, "assumed rank lowering");
+ }
+
+ 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));
+ }
+ }
+ }
+ };
+
// For symbols reaching this point, all properties are constant and can be
// read/computed already into ssa values.
@@ -827,7 +907,48 @@ void Fortran::lower::mapSymbolAttributes(
//===--------------------------------------------------------------===//
[&](const Fortran::lower::details::DynamicArray &x) {
- TODO(loc, "DynamicArray variable lowering");
+ // cast to the known constant parts from the declaration
+ mlir::Type varType = converter.genType(var);
+ mlir::Value addr = symMap.lookupSymbol(sym).getAddr();
+ mlir::Value argBox;
+ mlir::Type castTy = builder.getRefType(varType);
+ if (addr) {
+ if (auto boxTy = addr.getType().dyn_cast<fir::BoxType>()) {
+ argBox = addr;
+ mlir::Type refTy = builder.getRefType(boxTy.getEleTy());
+ addr = builder.create<fir::BoxAddrOp>(loc, refTy, argBox);
+ }
+ addr = builder.createConvert(loc, castTy, addr);
+ }
+ if (x.lboundAllOnes()) {
+ // if lower bounds are all ones, build simple shaped object
+ llvm::SmallVector<mlir::Value> shapes;
+ populateShape(shapes, x.bounds, argBox);
+ if (isDummy) {
+ symMap.addSymbolWithShape(sym, addr, shapes, true);
+ return;
+ }
+ // local array with computed bounds
+ assert(Fortran::lower::isExplicitShape(sym) ||
+ Fortran::semantics::IsAllocatableOrPointer(sym));
+ mlir::Value local =
+ createNewLocal(converter, loc, var, preAlloc, shapes);
+ symMap.addSymbolWithShape(sym, local, shapes);
+ return;
+ }
+ // if object is an array process the lower bound and extent values
+ llvm::SmallVector<mlir::Value> extents;
+ llvm::SmallVector<mlir::Value> lbounds;
+ populateLBoundsExtents(lbounds, extents, x.bounds, argBox);
+ if (isDummy) {
+ symMap.addSymbolWithBounds(sym, addr, extents, lbounds, true);
+ return;
+ }
+ // local array with computed bounds
+ assert(Fortran::lower::isExplicitShape(sym));
+ mlir::Value local =
+ createNewLocal(converter, loc, var, preAlloc, extents);
+ symMap.addSymbolWithBounds(sym, local, extents, lbounds);
},
//===--------------------------------------------------------------===//
diff --git a/flang/test/Lower/io-statement-1.f90 b/flang/test/Lower/io-statement-1.f90
index 1f9f51a6993e..f13612e20b0b 100644
--- a/flang/test/Lower/io-statement-1.f90
+++ b/flang/test/Lower/io-statement-1.f90
@@ -1,4 +1,4 @@
-! RUN: bbc %s -o - | FileCheck %s
+! RUN: bbc %s -emit-fir -o - | FileCheck %s
! UNSUPPORTED: system-windows
logical :: existsvar
diff --git a/flang/test/Lower/io-statement-2.f90 b/flang/test/Lower/io-statement-2.f90
index b6e360370708..123d55fa56f7 100644
--- a/flang/test/Lower/io-statement-2.f90
+++ b/flang/test/Lower/io-statement-2.f90
@@ -1,4 +1,5 @@
! RUN: bbc -emit-fir -o - %s | FileCheck %s
+! UNSUPPORTED: system-windows
character*10 :: exx
character*30 :: m
@@ -22,6 +23,118 @@
90 print*, exx, c, m, s
end
+! CHECK-LABEL: func @_QPcontrol0
+subroutine control0(n) ! no I/O condition specifier control flow
+dimension c(n), d(n,n), e(n,n), f(n)
+! CHECK-NOT: fir.if
+! CHECK: BeginExternalFormattedInput
+! CHECK-NOT: fir.if
+! CHECK: SetAdvance
+! CHECK-NOT: fir.if
+! CHECK: InputReal32
+! CHECK-NOT: fir.if
+! CHECK: InputReal32
+! CHECK-NOT: fir.if
+! CHECK: fir.do_loop
+! CHECK-NOT: fir.if
+! CHECK: InputReal32
+! CHECK-NOT: fir.if
+! CHECK: fir.do_loop
+! CHECK-NOT: fir.if
+! CHECK: InputReal32
+! CHECK-NOT: fir.if
+! CHECK: InputReal32
+! CHECK-NOT: fir.if
+! CHECK: InputReal32
+! CHECK-NOT: fir.if
+! CHECK: InputReal32
+! CHECK-NOT: fir.if
+! CHECK: EndIoStatement
+! CHECK-NOT: fir.if
+read(*,'(F7.2)', advance='no') a, b, (c(j), (d(k,j), e(k,j), k=1,n), f(j), j=1,n), g
+end
+
+! CHECK-LABEL: func @_QPcontrol1
+subroutine control1(n) ! I/O condition specifier control flow
+! CHECK: BeginExternalFormattedInput
+! CHECK: EnableHandlers
+! CHECK: SetAdvance
+! CHECK: fir.if
+! CHECK: InputReal32
+! CHECK: fir.if
+! CHECK: InputReal32
+! CHECK: fir.if
+! CHECK: fir.iterate_while
+! CHECK: fir.if
+! CHECK: InputReal32
+! CHECK: fir.if
+! CHECK: fir.iterate_while
+! CHECK: fir.if
+! CHECK: InputReal32
+! CHECK: fir.if
+! CHECK: InputReal32
+! CHECK: fir.if
+! CHECK: InputReal32
+! CHECK: fir.if
+! CHECK: InputReal32
+! CHECK: EndIoStatement
+dimension c(n), d(n,n), e(n,n), f(n)
+read(*,'(F7.2)', iostat=mm, advance='no') a, b, (c(j), (d(k,j), e(k,j), k=1,n), f(j), j=1,n), g
+end
+
+! CHECK-LABEL: func @_QPcontrol2
+subroutine control2() ! I/O condition specifier control flow (use index result)
+c = 1; d = 9
+! CHECK: BeginExternalFormattedOutput
+! CHECK: EnableHandlers
+! CHECK: :2 = fir.iterate_while
+! CHECK: = fir.if
+! CHECK: OutputReal
+! CHECK: = fir.if
+! CHECK: OutputReal
+! CHECK: fir.result
+! CHECK: else
+! CHECK: fir.result %false
+! CHECK: fir.result
+! CHECK: else
+! CHECK: fir.result %false
+! CHECK: = arith.addi %arg0, %c1
+! CHECK: = arith.select
+! CHECK: fir.result
+! CHECK: fir.if %{{[0-9]*}}#1
+! CHECK: OutputInteger
+! CHECK: EndIoStatement
+write(*,'(8F4.1,I5)',iostat=m) (c,d,j=11,14), j
+end
+
+! CHECK-LABEL: func @_QPloopnest
+subroutine loopnest
+ integer :: aa(3,3)
+ aa = 10
+ ! CHECK: BeginExternalListOutput
+ ! CHECK: EnableHandlers
+ ! CHECK: {{.*}}:2 = fir.iterate_while ({{.*}} = {{.*}} to {{.*}} step {{.*}}) and ({{.*}} = {{.*}}) -> (index, i1) {
+ ! CHECK: fir.if {{.*}} -> (i1) {
+ ! CHECK: {{.*}}:2 = fir.iterate_while ({{.*}} = {{.*}} to {{.*}} step {{.*}}) and ({{.*}} = {{.*}}) -> (index, i1) {
+ ! CHECK: fir.if {{.*}} -> (i1) {
+ ! CHECK: OutputInteger32
+ ! CHECK: fir.result {{.*}} : i1
+ ! CHECK: } else {
+ ! CHECK: fir.result {{.*}} : i1
+ ! CHECK: }
+ ! CHECK: fir.result {{.*}}, {{.*}} : index, i1
+ ! CHECK: }
+ ! CHECK: fir.result {{.*}}#1 : i1
+ ! CHECK: } else {
+ ! CHECK: fir.result {{.*}} : i1
+ ! CHECK: }
+ ! CHECK: fir.result {{.*}}, {{.*}} : index, i1
+ ! CHECK: }
+ ! CHECK: EndIoStatement
+ write(*,*,err=66) ((aa(j,k)+j+k,j=1,3),k=1,3)
+66 continue
+end
+
! CHECK-LABEL: func @_QPimpliedformat
subroutine impliedformat
! CHECK: BeginExternalListInput(%c-1
More information about the flang-commits
mailing list