Skip to content

Commit

Permalink
[flang] Error detection/avoidance for TRANSFER with empty MOLD= type
Browse files Browse the repository at this point in the history
When MOLD= is an array and there is no SIZE= in a call to TRANSFER(),
the size of an element of the MOLD= is used as the denominator in a
division to establish the extent of the vector result.  When the
total storage size of the SOURCE= is known to be zero, the result is
empty and no division is needed.

To avoid a division by zero at runtime, we need to check for a zero-sized
MOLD= element type when the storage size of SOURCE= is nonzero and there
is no SIZE=.  Further, in the compilation-time rewriting of calls to
SHAPE(TRANSFER(...)) and SIZE(TRANSFER(...)) for constant folding and
simplification purposes, we can't replace the call with an arithmetic
element count expression when the storage size of SOURCE= is not known
to be zero and the element size of MOLD= is not known to be nonzero at
compilation time.

These changes mostly affect tests using a MOLD= argument that is an
assumed-length character.

Differential Revision: https://reviews.llvm.org/D129680
  • Loading branch information
klausler committed Jul 13, 2022
1 parent e3923d0 commit be68a6a
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 18 deletions.
35 changes: 25 additions & 10 deletions flang/lib/Evaluate/shape.cpp
Expand Up @@ -931,19 +931,34 @@ auto GetShapeHelper::operator()(const ProcedureRef &call) const -> Result {
} else {
// SIZE= is absent and MOLD= is array: result is vector whose
// length is determined by sizes of types. See 16.9.193p4 case(ii).
// Note that if sourceBytes is not known to be empty, we
// can fold only when moldElementBytes is known to not be zero;
// the most general case risks a division by zero otherwise.
if (auto sourceTypeAndShape{
characteristics::TypeAndShape::Characterize(
call.arguments().at(0), *context_)}) {
auto sourceBytes{
sourceTypeAndShape->MeasureSizeInBytes(*context_)};
auto moldElementBytes{
moldTypeAndShape->MeasureElementSizeInBytes(*context_, true)};
if (sourceBytes && moldElementBytes) {
ExtentExpr extent{Fold(*context_,
(std::move(*sourceBytes) +
common::Clone(*moldElementBytes) - ExtentExpr{1}) /
common::Clone(*moldElementBytes))};
return Shape{MaybeExtentExpr{std::move(extent)}};
if (auto sourceBytes{
sourceTypeAndShape->MeasureSizeInBytes(*context_)}) {
*sourceBytes = Fold(*context_, std::move(*sourceBytes));
if (auto sourceBytesConst{ToInt64(*sourceBytes)}) {
if (*sourceBytesConst == 0) {
return Shape{ExtentExpr{0}};
}
}
if (auto moldElementBytes{
moldTypeAndShape->MeasureElementSizeInBytes(
*context_, true)}) {
*moldElementBytes =
Fold(*context_, std::move(*moldElementBytes));
auto moldElementBytesConst{ToInt64(*moldElementBytes)};
if (moldElementBytesConst && *moldElementBytesConst != 0) {
ExtentExpr extent{Fold(*context_,
(std::move(*sourceBytes) +
common::Clone(*moldElementBytes) - ExtentExpr{1}) /
common::Clone(*moldElementBytes))};
return Shape{MaybeExtentExpr{std::move(extent)}};
}
}
}
}
}
Expand Down
23 changes: 15 additions & 8 deletions flang/runtime/misc-intrinsic.cpp
Expand Up @@ -55,16 +55,23 @@ extern "C" {

void RTNAME(Transfer)(Descriptor &result, const Descriptor &source,
const Descriptor &mold, const char *sourceFile, int line) {
std::optional<std::int64_t> elements;
if (mold.rank() > 0) {
std::size_t moldElementBytes{mold.ElementBytes()};
std::size_t elements{
(source.Elements() * source.ElementBytes() + moldElementBytes - 1) /
moldElementBytes};
return TransferImpl(result, source, mold, sourceFile, line,
static_cast<std::int64_t>(elements));
} else {
return TransferImpl(result, source, mold, sourceFile, line, {});
if (std::size_t sourceElementBytes{
source.Elements() * source.ElementBytes()}) {
if (std::size_t moldElementBytes{mold.ElementBytes()}) {
elements = static_cast<std::int64_t>(
(sourceElementBytes + moldElementBytes - 1) / moldElementBytes);
} else {
Terminator{sourceFile, line}.Crash("TRANSFER: zero-sized type of MOLD= "
"when SOURCE= is not zero-sized");
}
} else {
elements = 0;
}
}
return TransferImpl(
result, source, mold, sourceFile, line, std::move(elements));
}

void RTNAME(TransferSize)(Descriptor &result, const Descriptor &source,
Expand Down

0 comments on commit be68a6a

Please sign in to comment.