BytesFor() used to return KIND for the size, which is not always correct, so I changed it to return the size of the actual CppType corresponding to the given category and kind. MinElemLen() used to calculate size incorrectly (e.g. CFI_type_extended_double was sized 10, whereas it may occupy more bytes on a target), so I changed it to call BytesFor(). Additional changes were needed to resolve new failures for transformational intrinsics. These intrinsics used to work for not fully supported data types (e.g. REAL(3)), but now stopped working because CppType cannot be computed for those categories/kinds. The solution is to use known element size from the source argument(s) for establishing the destination descriptor - the element size is all that is needed for transformational intrinsics to keep working. Note that this does not help cases, where runtime still has to compute the element size, e.g. when it creates descriptors for components of derived types. If the component has unsupported data type, BytesFor() will still fail. So these cases require adding support for the missing types. New regression unit test in Runtime/Transformational.cpp demonstrates the case that will start working properly with this commit.
103 lines
3.3 KiB
C++
103 lines
3.3 KiB
C++
//===-- runtime/ISO_Fortran_util.h ------------------------------*- C++ -*-===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef FORTRAN_RUNTIME_ISO_FORTRAN_UTIL_H_
|
|
#define FORTRAN_RUNTIME_ISO_FORTRAN_UTIL_H_
|
|
|
|
// Internal utils for establishing CFI_cdesc_t descriptors.
|
|
|
|
#include "terminator.h"
|
|
#include "flang/ISO_Fortran_binding.h"
|
|
#include "flang/Runtime/descriptor.h"
|
|
#include "flang/Runtime/type-code.h"
|
|
#include <cstdlib>
|
|
|
|
namespace Fortran::ISO {
|
|
static inline constexpr bool IsCharacterType(CFI_type_t ty) {
|
|
return ty == CFI_type_char || ty == CFI_type_char16_t ||
|
|
ty == CFI_type_char32_t;
|
|
}
|
|
static inline constexpr bool IsAssumedSize(const CFI_cdesc_t *dv) {
|
|
return dv->rank > 0 && dv->dim[dv->rank - 1].extent == -1;
|
|
}
|
|
|
|
static inline std::size_t MinElemLen(CFI_type_t type) {
|
|
auto typeParams{Fortran::runtime::TypeCode{type}.GetCategoryAndKind()};
|
|
if (!typeParams) {
|
|
Fortran::runtime::Terminator terminator{__FILE__, __LINE__};
|
|
terminator.Crash(
|
|
"not yet implemented: CFI_type_t=%d", static_cast<int>(type));
|
|
}
|
|
|
|
return Fortran::runtime::Descriptor::BytesFor(
|
|
typeParams->first, typeParams->second);
|
|
}
|
|
|
|
static inline int VerifyEstablishParameters(CFI_cdesc_t *descriptor,
|
|
void *base_addr, CFI_attribute_t attribute, CFI_type_t type,
|
|
std::size_t elem_len, CFI_rank_t rank, const CFI_index_t extents[],
|
|
bool external) {
|
|
if (attribute != CFI_attribute_other && attribute != CFI_attribute_pointer &&
|
|
attribute != CFI_attribute_allocatable) {
|
|
return CFI_INVALID_ATTRIBUTE;
|
|
}
|
|
if (rank > CFI_MAX_RANK) {
|
|
return CFI_INVALID_RANK;
|
|
}
|
|
if (base_addr && attribute == CFI_attribute_allocatable) {
|
|
return CFI_ERROR_BASE_ADDR_NOT_NULL;
|
|
}
|
|
if (rank > 0 && base_addr && !extents) {
|
|
return CFI_INVALID_EXTENT;
|
|
}
|
|
if (type < CFI_type_signed_char || type > CFI_TYPE_LAST) {
|
|
return CFI_INVALID_TYPE;
|
|
}
|
|
if (!descriptor) {
|
|
return CFI_INVALID_DESCRIPTOR;
|
|
}
|
|
if (external) {
|
|
if (type == CFI_type_struct || type == CFI_type_other ||
|
|
IsCharacterType(type)) {
|
|
if (elem_len <= 0) {
|
|
return CFI_INVALID_ELEM_LEN;
|
|
}
|
|
}
|
|
} else {
|
|
// We do not expect CFI_type_other for internal invocations.
|
|
if (type == CFI_type_other) {
|
|
return CFI_INVALID_TYPE;
|
|
}
|
|
}
|
|
return CFI_SUCCESS;
|
|
}
|
|
|
|
static inline void EstablishDescriptor(CFI_cdesc_t *descriptor, void *base_addr,
|
|
CFI_attribute_t attribute, CFI_type_t type, std::size_t elem_len,
|
|
CFI_rank_t rank, const CFI_index_t extents[]) {
|
|
descriptor->base_addr = base_addr;
|
|
descriptor->elem_len = elem_len;
|
|
descriptor->version = CFI_VERSION;
|
|
descriptor->rank = rank;
|
|
descriptor->type = type;
|
|
descriptor->attribute = attribute;
|
|
descriptor->f18Addendum = 0;
|
|
std::size_t byteSize{elem_len};
|
|
constexpr std::size_t lower_bound{0};
|
|
if (base_addr) {
|
|
for (std::size_t j{0}; j < rank; ++j) {
|
|
descriptor->dim[j].lower_bound = lower_bound;
|
|
descriptor->dim[j].extent = extents[j];
|
|
descriptor->dim[j].sm = byteSize;
|
|
byteSize *= extents[j];
|
|
}
|
|
}
|
|
}
|
|
} // namespace Fortran::ISO
|
|
#endif // FORTRAN_RUNTIME_ISO_FORTRAN_UTIL_H_
|