Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/llvm/llvm-project.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/flang
diff options
context:
space:
mode:
authorPeter Klausler <pklausler@nvidia.com>2022-07-09 02:16:42 +0300
committerPeter Klausler <pklausler@nvidia.com>2022-07-14 02:50:57 +0300
commitbe68a6adfba29b275272cb36e606bc0cb08518b3 (patch)
tree46007e6a700c11fd1e7b2e2731e84d46c6841a69 /flang
parente3923d000a6a0393bf6bd535b65433ed0de1ec28 (diff)
[flang] Error detection/avoidance for TRANSFER with empty MOLD= type
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
Diffstat (limited to 'flang')
-rw-r--r--flang/lib/Evaluate/shape.cpp35
-rw-r--r--flang/runtime/misc-intrinsic.cpp23
2 files changed, 40 insertions, 18 deletions
diff --git a/flang/lib/Evaluate/shape.cpp b/flang/lib/Evaluate/shape.cpp
index b7930cd66393..a2748feaabd1 100644
--- a/flang/lib/Evaluate/shape.cpp
+++ b/flang/lib/Evaluate/shape.cpp
@@ -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)}};
+ }
+ }
}
}
}
diff --git a/flang/runtime/misc-intrinsic.cpp b/flang/runtime/misc-intrinsic.cpp
index 356046ee05f8..19eb9351d47f 100644
--- a/flang/runtime/misc-intrinsic.cpp
+++ b/flang/runtime/misc-intrinsic.cpp
@@ -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,