Skip to content

Commit 27cfe7a

Browse files
authored
[flang] Set assumed-size last extent to -1 (#79156)
Currently lowering sets the extents of assumed-size array to "undef" which was OK as long as the value was not expected to be read. But when interfacing with the runtime and when passing assumed-size to assumed-rank, this last extent may be read and must be -1 as specified in the BIND(C) case in 18.5.3 point 5. Set this value to -1, and update all the lowering code that was looking for an undef defining op to identify assumed-size: much safer to propagate and use semantic info here, the previous check actually did not work if the array was used in an internal procedure (defining op not visible anymore). @clementval and @agozillon, I left assumed-size extent to zero in the acc/omp bounds op as it was, please double check that is what you want (I can imagine -1 may create troubles here, and 0 makes some sense as it would lead to no data transfer). This also allows removing special cases in UBOUND/LBOUND lowering. Also disable allocation of cray pointee. This was never intended and would now lead to crashes with the -1 value for assumed-size cray pointee.
1 parent 72f10f7 commit 27cfe7a

File tree

14 files changed

+97
-128
lines changed

14 files changed

+97
-128
lines changed

flang/include/flang/Optimizer/Builder/Array.h

Lines changed: 0 additions & 27 deletions
This file was deleted.

flang/include/flang/Optimizer/Builder/BoxValue.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -527,9 +527,6 @@ class ExtendedValue : public details::matcher<ExtendedValue> {
527527
[](const auto &box) -> bool { return false; });
528528
}
529529

530-
/// Is this an assumed size array ?
531-
bool isAssumedSize() const;
532-
533530
/// LLVM style debugging of extended values
534531
LLVM_DUMP_METHOD void dump() const { llvm::errs() << *this << '\n'; }
535532

flang/lib/Lower/ConvertVariable.cpp

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -684,6 +684,13 @@ static mlir::Value createNewLocal(Fortran::lower::AbstractConverter &converter,
684684
llvm::StringRef symNm = toStringRef(ultimateSymbol.name());
685685
bool isTarg = var.isTarget();
686686

687+
// Do not allocate storage for cray pointee. The address inside the cray
688+
// pointer will be used instead when using the pointee. Allocating space
689+
// would be a waste of space, and incorrect if the pointee is a non dummy
690+
// assumed-size (possible with cray pointee).
691+
if (ultimateSymbol.test(Fortran::semantics::Symbol::Flag::CrayPointee))
692+
return builder.create<fir::ZeroOp>(loc, fir::ReferenceType::get(ty));
693+
687694
// Let the builder do all the heavy lifting.
688695
if (!Fortran::semantics::IsProcedurePointer(ultimateSymbol))
689696
return builder.allocateLocal(loc, ty, nm, symNm, shape, lenParams, isTarg);
@@ -1454,6 +1461,15 @@ static void lowerExplicitLowerBounds(
14541461
assert(result.empty() || result.size() == box.dynamicBound().size());
14551462
}
14561463

1464+
/// Return -1 for the last dimension extent/upper bound of assumed-size arrays.
1465+
/// This value is required to fulfill the requirements for assumed-rank
1466+
/// associated with assumed-size (see for instance UBOUND in 16.9.196, and
1467+
/// CFI_desc_t requirements in 18.5.3 point 5.).
1468+
static mlir::Value getAssumedSizeExtent(mlir::Location loc,
1469+
fir::FirOpBuilder &builder) {
1470+
return builder.createIntegerConstant(loc, builder.getIndexType(), -1);
1471+
}
1472+
14571473
/// Lower explicit extents into \p result if this is an explicit-shape or
14581474
/// assumed-size array. Does nothing if this is not an explicit-shape or
14591475
/// assumed-size array.
@@ -1484,8 +1500,7 @@ lowerExplicitExtents(Fortran::lower::AbstractConverter &converter,
14841500
result.emplace_back(
14851501
computeExtent(builder, loc, lowerBounds[spec.index()], ub));
14861502
} else if (spec.value()->ubound().isStar()) {
1487-
// Assumed extent is undefined. Must be provided by user's code.
1488-
result.emplace_back(builder.create<fir::UndefOp>(loc, idxTy));
1503+
result.emplace_back(getAssumedSizeExtent(loc, builder));
14891504
}
14901505
}
14911506
assert(result.empty() || result.size() == box.dynamicBound().size());
@@ -1513,15 +1528,13 @@ lowerExplicitCharLen(Fortran::lower::AbstractConverter &converter,
15131528
return mlir::Value{};
15141529
}
15151530

1516-
/// Treat negative values as undefined. Assumed size arrays will return -1 from
1517-
/// the front end for example. Using negative values can produce hard to find
1518-
/// bugs much further along in the compilation.
1531+
/// Assumed size arrays last extent is -1 in the front end.
15191532
static mlir::Value genExtentValue(fir::FirOpBuilder &builder,
15201533
mlir::Location loc, mlir::Type idxTy,
15211534
long frontEndExtent) {
15221535
if (frontEndExtent >= 0)
15231536
return builder.createIntegerConstant(loc, idxTy, frontEndExtent);
1524-
return builder.create<fir::UndefOp>(loc, idxTy);
1537+
return getAssumedSizeExtent(loc, builder);
15251538
}
15261539

15271540
/// If a symbol is an array, it may have been declared with unknown extent
@@ -2000,7 +2013,7 @@ void Fortran::lower::mapSymbolAttributes(
20002013
builder.create<fir::BoxDimsOp>(loc, idxTy, idxTy, idxTy, box, dim);
20012014
shapes.emplace_back(dimInfo.getResult(1));
20022015
} else if (spec->ubound().isStar()) {
2003-
shapes.emplace_back(builder.create<fir::UndefOp>(loc, idxTy));
2016+
shapes.emplace_back(getAssumedSizeExtent(loc, builder));
20042017
} else {
20052018
llvm::report_fatal_error("unknown bound category");
20062019
}
@@ -2047,7 +2060,7 @@ void Fortran::lower::mapSymbolAttributes(
20472060
} else {
20482061
// An assumed size array. The extent is not computed.
20492062
assert(spec->ubound().isStar() && "expected assumed size");
2050-
extents.emplace_back(builder.create<fir::UndefOp>(loc, idxTy));
2063+
extents.emplace_back(getAssumedSizeExtent(loc, builder));
20512064
}
20522065
}
20532066
}

flang/lib/Lower/DirectivesCommon.h

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -761,7 +761,7 @@ template <typename BoundsOp, typename BoundsType>
761761
llvm::SmallVector<mlir::Value>
762762
genBaseBoundsOps(fir::FirOpBuilder &builder, mlir::Location loc,
763763
Fortran::lower::AbstractConverter &converter,
764-
fir::ExtendedValue dataExv) {
764+
fir::ExtendedValue dataExv, bool isAssumedSize) {
765765
mlir::Type idxTy = builder.getIndexType();
766766
mlir::Type boundTy = builder.getType<BoundsType>();
767767
llvm::SmallVector<mlir::Value> bounds;
@@ -770,14 +770,15 @@ genBaseBoundsOps(fir::FirOpBuilder &builder, mlir::Location loc,
770770
return bounds;
771771

772772
mlir::Value one = builder.createIntegerConstant(loc, idxTy, 1);
773-
for (std::size_t dim = 0; dim < dataExv.rank(); ++dim) {
773+
const unsigned rank = dataExv.rank();
774+
for (unsigned dim = 0; dim < rank; ++dim) {
774775
mlir::Value baseLb =
775776
fir::factory::readLowerBound(builder, loc, dataExv, dim, one);
776777
mlir::Value zero = builder.createIntegerConstant(loc, idxTy, 0);
777778
mlir::Value ub;
778779
mlir::Value lb = zero;
779780
mlir::Value ext = fir::factory::readExtent(builder, loc, dataExv, dim);
780-
if (mlir::isa<fir::UndefOp>(ext.getDefiningOp())) {
781+
if (isAssumedSize && dim + 1 == rank) {
781782
ext = zero;
782783
ub = lb;
783784
} else {
@@ -801,14 +802,16 @@ genBoundsOps(fir::FirOpBuilder &builder, mlir::Location loc,
801802
Fortran::lower::StatementContext &stmtCtx,
802803
const std::list<Fortran::parser::SectionSubscript> &subscripts,
803804
std::stringstream &asFortran, fir::ExtendedValue &dataExv,
804-
mlir::Value baseAddr, bool treatIndexAsSection = false) {
805+
bool dataExvIsAssumedSize, mlir::Value baseAddr,
806+
bool treatIndexAsSection = false) {
805807
int dimension = 0;
806808
mlir::Type idxTy = builder.getIndexType();
807809
mlir::Type boundTy = builder.getType<BoundsType>();
808810
llvm::SmallVector<mlir::Value> bounds;
809811

810812
mlir::Value zero = builder.createIntegerConstant(loc, idxTy, 0);
811813
mlir::Value one = builder.createIntegerConstant(loc, idxTy, 1);
814+
const int dataExvRank = static_cast<int>(dataExv.rank());
812815
for (const auto &subscript : subscripts) {
813816
const auto *triplet{
814817
std::get_if<Fortran::parser::SubscriptTriplet>(&subscript.u)};
@@ -912,7 +915,7 @@ genBoundsOps(fir::FirOpBuilder &builder, mlir::Location loc,
912915
}
913916

914917
extent = fir::factory::readExtent(builder, loc, dataExv, dimension);
915-
if (mlir::isa<fir::UndefOp>(extent.getDefiningOp())) {
918+
if (dataExvIsAssumedSize && dimension + 1 == dataExvRank) {
916919
extent = zero;
917920
if (ubound && lbound) {
918921
mlir::Value diff =
@@ -959,6 +962,7 @@ AddrAndBoundsInfo gatherDataOperandAddrAndBounds(
959962
const auto *dataRef =
960963
std::get_if<Fortran::parser::DataRef>(&designator.u);
961964
fir::ExtendedValue dataExv;
965+
bool dataExvIsAssumedSize = false;
962966
if (Fortran::parser::Unwrap<
963967
Fortran::parser::StructureComponent>(
964968
arrayElement->base)) {
@@ -971,6 +975,8 @@ AddrAndBoundsInfo gatherDataOperandAddrAndBounds(
971975
} else {
972976
const Fortran::parser::Name &name =
973977
Fortran::parser::GetLastName(*dataRef);
978+
dataExvIsAssumedSize = Fortran::semantics::IsAssumedSizeArray(
979+
name.symbol->GetUltimate());
974980
info = getDataOperandBaseAddr(converter, builder,
975981
*name.symbol, operandLocation);
976982
dataExv = converter.getSymbolExtendedValue(*name.symbol);
@@ -981,8 +987,8 @@ AddrAndBoundsInfo gatherDataOperandAddrAndBounds(
981987
asFortran << '(';
982988
bounds = genBoundsOps<BoundsOp, BoundsType>(
983989
builder, operandLocation, converter, stmtCtx,
984-
arrayElement->subscripts, asFortran, dataExv, info.addr,
985-
treatIndexAsSection);
990+
arrayElement->subscripts, asFortran, dataExv,
991+
dataExvIsAssumedSize, info.addr, treatIndexAsSection);
986992
}
987993
asFortran << ')';
988994
} else if (auto structComp = Fortran::parser::Unwrap<
@@ -993,7 +999,8 @@ AddrAndBoundsInfo gatherDataOperandAddrAndBounds(
993999
if (fir::unwrapRefType(info.addr.getType())
9941000
.isa<fir::SequenceType>())
9951001
bounds = genBaseBoundsOps<BoundsOp, BoundsType>(
996-
builder, operandLocation, converter, compExv);
1002+
builder, operandLocation, converter, compExv,
1003+
/*isAssumedSize=*/false);
9971004
asFortran << (*expr).AsFortran();
9981005

9991006
bool isOptional = Fortran::semantics::IsOptional(
@@ -1047,10 +1054,14 @@ AddrAndBoundsInfo gatherDataOperandAddrAndBounds(
10471054
bounds = genBoundsOpsFromBox<BoundsOp, BoundsType>(
10481055
builder, operandLocation, converter, dataExv, info);
10491056
}
1057+
bool dataExvIsAssumedSize =
1058+
Fortran::semantics::IsAssumedSizeArray(
1059+
name.symbol->GetUltimate());
10501060
if (fir::unwrapRefType(info.addr.getType())
10511061
.isa<fir::SequenceType>())
10521062
bounds = genBaseBoundsOps<BoundsOp, BoundsType>(
1053-
builder, operandLocation, converter, dataExv);
1063+
builder, operandLocation, converter, dataExv,
1064+
dataExvIsAssumedSize);
10541065
asFortran << name.ToString();
10551066
} else { // Unsupported
10561067
llvm::report_fatal_error(

flang/lib/Lower/OpenMP.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2915,11 +2915,14 @@ genTargetOp(Fortran::lower::AbstractConverter &converter,
29152915
mlir::omp::DataBoundsType>(
29162916
converter.getFirOpBuilder(), converter.getCurrentLocation(),
29172917
converter, dataExv, info);
2918-
if (fir::unwrapRefType(info.addr.getType()).isa<fir::SequenceType>())
2918+
if (fir::unwrapRefType(info.addr.getType()).isa<fir::SequenceType>()) {
2919+
bool dataExvIsAssumedSize =
2920+
Fortran::semantics::IsAssumedSizeArray(sym.GetUltimate());
29192921
bounds = Fortran::lower::genBaseBoundsOps<mlir::omp::DataBoundsOp,
29202922
mlir::omp::DataBoundsType>(
29212923
converter.getFirOpBuilder(), converter.getCurrentLocation(),
2922-
converter, dataExv);
2924+
converter, dataExv, dataExvIsAssumedSize);
2925+
}
29232926

29242927
llvm::omp::OpenMPOffloadMappingFlags mapFlag =
29252928
llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_IMPLICIT;

flang/lib/Optimizer/Builder/BoxValue.cpp

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -232,19 +232,3 @@ mlir::Value fir::factory::getExtentAtDimension(mlir::Location loc,
232232
return extents[dim];
233233
return {};
234234
}
235-
236-
static inline bool isUndefOp(mlir::Value v) {
237-
return mlir::isa_and_nonnull<fir::UndefOp>(v.getDefiningOp());
238-
}
239-
240-
bool fir::ExtendedValue::isAssumedSize() const {
241-
return match(
242-
[](const fir::ArrayBoxValue &box) -> bool {
243-
return !box.getExtents().empty() && isUndefOp(box.getExtents().back());
244-
;
245-
},
246-
[](const fir::CharArrayBoxValue &box) -> bool {
247-
return !box.getExtents().empty() && isUndefOp(box.getExtents().back());
248-
},
249-
[](const auto &box) -> bool { return false; });
250-
}

flang/lib/Optimizer/Builder/IntrinsicCall.cpp

Lines changed: 20 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -5691,10 +5691,10 @@ static mlir::Value computeLBOUND(fir::FirOpBuilder &builder, mlir::Location loc,
56915691
if (hasDefaultLowerBound(array))
56925692
return one;
56935693
mlir::Value lb = fir::factory::readLowerBound(builder, loc, array, dim, one);
5694-
if (dim + 1 == array.rank() && array.isAssumedSize())
5695-
return lb;
56965694
mlir::Value extent = fir::factory::readExtent(builder, loc, array, dim);
56975695
zero = builder.createConvert(loc, extent.getType(), zero);
5696+
// Note: for assumed size, the extent is -1, and the lower bound should
5697+
// be returned. It is important to test extent == 0 and not extent > 0.
56985698
auto dimIsEmpty = builder.create<mlir::arith::CmpIOp>(
56995699
loc, mlir::arith::CmpIPredicate::eq, extent, zero);
57005700
one = builder.createConvert(loc, lb.getType(), one);
@@ -5703,52 +5703,29 @@ static mlir::Value computeLBOUND(fir::FirOpBuilder &builder, mlir::Location loc,
57035703

57045704
/// Create a fir.box to be passed to the LBOUND/UBOUND runtime.
57055705
/// This ensure that local lower bounds of assumed shape are propagated and that
5706-
/// a fir.box with equivalent LBOUNDs but an explicit shape is created for
5707-
/// assumed size arrays to avoid undefined behaviors in codegen or the runtime.
5706+
/// a fir.box with equivalent LBOUNDs.
57085707
static mlir::Value
57095708
createBoxForRuntimeBoundInquiry(mlir::Location loc, fir::FirOpBuilder &builder,
57105709
const fir::ExtendedValue &array) {
5711-
if (!array.isAssumedSize())
5712-
return array.match(
5713-
[&](const fir::BoxValue &boxValue) -> mlir::Value {
5714-
// This entity is mapped to a fir.box that may not contain the local
5715-
// lower bound information if it is a dummy. Rebox it with the local
5716-
// shape information.
5717-
mlir::Value localShape = builder.createShape(loc, array);
5718-
mlir::Value oldBox = boxValue.getAddr();
5719-
return builder.create<fir::ReboxOp>(loc, oldBox.getType(), oldBox,
5720-
localShape,
5721-
/*slice=*/mlir::Value{});
5722-
},
5723-
[&](const auto &) -> mlir::Value {
5724-
// This a pointer/allocatable, or an entity not yet tracked with a
5725-
// fir.box. For pointer/allocatable, createBox will forward the
5726-
// descriptor that contains the correct lower bound information. For
5727-
// other entities, a new fir.box will be made with the local lower
5728-
// bounds.
5729-
return builder.createBox(loc, array);
5730-
});
5731-
// Assumed sized are not meant to be emboxed. This could cause the undefined
5732-
// extent cannot safely be understood by the runtime/codegen that will
5733-
// consider that the dimension is empty and that the related LBOUND value must
5734-
// be one. Pretend that the related extent is one to get the correct LBOUND
5735-
// value.
5736-
llvm::SmallVector<mlir::Value> shape =
5737-
fir::factory::getExtents(loc, builder, array);
5738-
assert(!shape.empty() && "assumed size must have at least one dimension");
5739-
shape.back() = builder.createIntegerConstant(loc, builder.getIndexType(), 1);
5740-
auto safeToEmbox = array.match(
5741-
[&](const fir::CharArrayBoxValue &x) -> fir::ExtendedValue {
5742-
return fir::CharArrayBoxValue{x.getAddr(), x.getLen(), shape,
5743-
x.getLBounds()};
5744-
},
5745-
[&](const fir::ArrayBoxValue &x) -> fir::ExtendedValue {
5746-
return fir::ArrayBoxValue{x.getAddr(), shape, x.getLBounds()};
5710+
return array.match(
5711+
[&](const fir::BoxValue &boxValue) -> mlir::Value {
5712+
// This entity is mapped to a fir.box that may not contain the local
5713+
// lower bound information if it is a dummy. Rebox it with the local
5714+
// shape information.
5715+
mlir::Value localShape = builder.createShape(loc, array);
5716+
mlir::Value oldBox = boxValue.getAddr();
5717+
return builder.create<fir::ReboxOp>(loc, oldBox.getType(), oldBox,
5718+
localShape,
5719+
/*slice=*/mlir::Value{});
57475720
},
5748-
[&](const auto &) -> fir::ExtendedValue {
5749-
fir::emitFatalError(loc, "not an assumed size array");
5721+
[&](const auto &) -> mlir::Value {
5722+
// This is a pointer/allocatable, or an entity not yet tracked with a
5723+
// fir.box. For pointer/allocatable, createBox will forward the
5724+
// descriptor that contains the correct lower bound information. For
5725+
// other entities, a new fir.box will be made with the local lower
5726+
// bounds.
5727+
return builder.createBox(loc, array);
57505728
});
5751-
return builder.createBox(loc, safeToEmbox);
57525729
}
57535730

57545731
// LBOUND

flang/lib/Optimizer/Transforms/ArrayValueCopy.cpp

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
//
77
//===----------------------------------------------------------------------===//
88

9-
#include "flang/Optimizer/Builder/Array.h"
109
#include "flang/Optimizer/Builder/BoxValue.h"
1110
#include "flang/Optimizer/Builder/FIRBuilder.h"
1211
#include "flang/Optimizer/Builder/Factory.h"
@@ -822,6 +821,16 @@ static mlir::Type getEleTy(mlir::Type ty) {
822821
return ReferenceType::get(eleTy);
823822
}
824823

824+
// This is an unsafe way to deduce this (won't be true in internal
825+
// procedure or inside select-rank for assumed-size). Only here to satisfy
826+
// legacy code until removed.
827+
static bool isAssumedSize(llvm::SmallVectorImpl<mlir::Value> &extents) {
828+
if (extents.empty())
829+
return false;
830+
auto cstLen = fir::getIntIfConstant(extents.back());
831+
return cstLen.has_value() && *cstLen == -1;
832+
}
833+
825834
// Extract extents from the ShapeOp/ShapeShiftOp into the result vector.
826835
static bool getAdjustedExtents(mlir::Location loc,
827836
mlir::PatternRewriter &rewriter,
@@ -840,7 +849,7 @@ static bool getAdjustedExtents(mlir::Location loc,
840849
emitFatalError(loc, "not a fir.shape/fir.shape_shift op");
841850
}
842851
auto idxTy = rewriter.getIndexType();
843-
if (factory::isAssumedSize(result)) {
852+
if (isAssumedSize(result)) {
844853
// Use slice information to compute the extent of the column.
845854
auto one = rewriter.create<mlir::arith::ConstantIndexOp>(loc, 1);
846855
mlir::Value size = one;
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
! Test lowering of assumed-size cray pointee. This is an
2+
! odd case where an assumed-size symbol is not a dummy.
3+
! Test that no bogus stack allocation is created for it
4+
! (it will take its address from the cray pointer when used).
5+
! RUN: bbc -emit-hlfir -o - %s | FileCheck %s
6+
7+
subroutine assumed_size_cray_ptr
8+
implicit none
9+
pointer(ivar,var)
10+
real :: var(*)
11+
end subroutine
12+
! CHECK-LABEL: func.func @_QPassumed_size_cray_ptr
13+
! CHECK-NOT: fir.alloca !fir.array<?xf32>
14+
! CHECK: return

0 commit comments

Comments
 (0)