forked from OSchip/llvm-project
[flang] Implement and test RESHAPE. Avoid G++ workaround when compiled with GNU 8.2.0.
Original-commit: flang-compiler/f18@80257ee0d2 Reviewed-on: https://github.com/flang-compiler/f18/pull/162 Tree-same-pre-rewrite: false
This commit is contained in:
parent
6f9fa21d50
commit
a8fed82258
|
@ -51,7 +51,7 @@ typedef ptrdiff_t CFI_index_t;
|
||||||
CFI_dim_t dim[rank]; \
|
CFI_dim_t dim[rank]; \
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef unsigned short CFI_attribute_t;
|
typedef unsigned char CFI_attribute_t;
|
||||||
#define CFI_attribute_pointer 1
|
#define CFI_attribute_pointer 1
|
||||||
#define CFI_attribute_allocatable 2
|
#define CFI_attribute_allocatable 2
|
||||||
#define CFI_attribute_other 0 /* neither pointer nor allocatable */
|
#define CFI_attribute_other 0 /* neither pointer nor allocatable */
|
||||||
|
|
|
@ -431,7 +431,7 @@ public:
|
||||||
|
|
||||||
constexpr std::int64_t ToInt64() const {
|
constexpr std::int64_t ToInt64() const {
|
||||||
std::int64_t signExtended = ToUInt64();
|
std::int64_t signExtended = ToUInt64();
|
||||||
if (bits < 64) {
|
if constexpr (bits < 64) {
|
||||||
signExtended |= -(signExtended >> (bits - 1)) << bits;
|
signExtended |= -(signExtended >> (bits - 1)) << bits;
|
||||||
}
|
}
|
||||||
return signExtended;
|
return signExtended;
|
||||||
|
|
|
@ -327,7 +327,7 @@ template<typename... Ps> inline constexpr auto first(const Ps &... ps) {
|
||||||
return AlternativesParser<Ps...>{ps...};
|
return AlternativesParser<Ps...>{ps...};
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !__GNUC__ || __clang__
|
#if !__GNUC__ || __clang__ || ((100 * __GNUC__ + __GNUC__MINOR__) >= 802)
|
||||||
// Implement operator|| with first(), unless compiling with g++,
|
// Implement operator|| with first(), unless compiling with g++,
|
||||||
// which can segfault at compile time and needs to continue to use
|
// which can segfault at compile time and needs to continue to use
|
||||||
// the original implementation of operator|| as of gcc-8.1.0.
|
// the original implementation of operator|| as of gcc-8.1.0.
|
||||||
|
@ -335,7 +335,7 @@ template<typename PA, typename PB>
|
||||||
inline constexpr auto operator||(const PA &pa, const PB &pb) {
|
inline constexpr auto operator||(const PA &pa, const PB &pb) {
|
||||||
return first(pa, pb);
|
return first(pa, pb);
|
||||||
}
|
}
|
||||||
#else // g++ only: original implementation
|
#else // g++ <= 8.1.0 only: original implementation
|
||||||
// If a and b are parsers, then a || b returns a parser that succeeds if
|
// If a and b are parsers, then a || b returns a parser that succeeds if
|
||||||
// a does so, or if a fails and b succeeds. The result types of the parsers
|
// a does so, or if a fails and b succeeds. The result types of the parsers
|
||||||
// must be the same type. If a succeeds, b is not attempted.
|
// must be the same type. If a succeeds, b is not attempted.
|
||||||
|
|
|
@ -16,5 +16,10 @@ add_library(FortranRuntime
|
||||||
ISO_Fortran_binding.cc
|
ISO_Fortran_binding.cc
|
||||||
derived-type.cc
|
derived-type.cc
|
||||||
descriptor.cc
|
descriptor.cc
|
||||||
|
transformational.cc
|
||||||
type-code.cc
|
type-code.cc
|
||||||
)
|
)
|
||||||
|
|
||||||
|
target_link_libraries(FortranRuntime
|
||||||
|
FortranEvaluate
|
||||||
|
)
|
||||||
|
|
|
@ -144,9 +144,6 @@ int CFI_establish(CFI_cdesc_t *descriptor, void *base_addr,
|
||||||
if ((attribute & ~(CFI_attribute_pointer | CFI_attribute_allocatable)) != 0) {
|
if ((attribute & ~(CFI_attribute_pointer | CFI_attribute_allocatable)) != 0) {
|
||||||
return CFI_INVALID_ATTRIBUTE;
|
return CFI_INVALID_ATTRIBUTE;
|
||||||
}
|
}
|
||||||
if ((attribute & CFI_attribute_allocatable) != 0 && base_addr != nullptr) {
|
|
||||||
return CFI_ERROR_BASE_ADDR_NOT_NULL;
|
|
||||||
}
|
|
||||||
if (rank > CFI_MAX_RANK) {
|
if (rank > CFI_MAX_RANK) {
|
||||||
return CFI_INVALID_RANK;
|
return CFI_INVALID_RANK;
|
||||||
}
|
}
|
||||||
|
@ -166,7 +163,9 @@ int CFI_establish(CFI_cdesc_t *descriptor, void *base_addr,
|
||||||
descriptor->elem_len = elem_len;
|
descriptor->elem_len = elem_len;
|
||||||
descriptor->version = CFI_VERSION;
|
descriptor->version = CFI_VERSION;
|
||||||
descriptor->rank = rank;
|
descriptor->rank = rank;
|
||||||
|
descriptor->type = type;
|
||||||
descriptor->attribute = attribute;
|
descriptor->attribute = attribute;
|
||||||
|
descriptor->f18Addendum = 0;
|
||||||
std::size_t byteSize{elem_len};
|
std::size_t byteSize{elem_len};
|
||||||
for (std::size_t j{0}; j < rank; ++j) {
|
for (std::size_t j{0}; j < rank; ++j) {
|
||||||
descriptor->dim[j].lower_bound = 1;
|
descriptor->dim[j].lower_bound = 1;
|
||||||
|
|
|
@ -31,7 +31,7 @@ bool DerivedType::IsNontrivialAnalysis() const {
|
||||||
definedAssignments_ > 0) {
|
definedAssignments_ > 0) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
for (int j{0}; j < components_; ++j) {
|
for (std::size_t j{0}; j < components_; ++j) {
|
||||||
if (component_[j].IsDescriptor()) {
|
if (component_[j].IsDescriptor()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -122,8 +122,9 @@ struct DefinedAssignment {
|
||||||
// the execution of FINAL subroutines.
|
// the execution of FINAL subroutines.
|
||||||
class DerivedType {
|
class DerivedType {
|
||||||
public:
|
public:
|
||||||
DerivedType(const char *n, int kps, int lps, const TypeParameter *tp, int cs,
|
DerivedType(const char *n, std::size_t kps, std::size_t lps,
|
||||||
const Component *ca, int tbps, const TypeBoundProcedure *tbp, int das,
|
const TypeParameter *tp, std::size_t cs, const Component *ca,
|
||||||
|
std::size_t tbps, const TypeBoundProcedure *tbp, std::size_t das,
|
||||||
const DefinedAssignment *da, std::size_t sz)
|
const DefinedAssignment *da, std::size_t sz)
|
||||||
: name_{n}, kindParameters_{kps}, lenParameters_{lps}, typeParameter_{tp},
|
: name_{n}, kindParameters_{kps}, lenParameters_{lps}, typeParameter_{tp},
|
||||||
components_{cs}, component_{ca}, typeBoundProcedures_{tbps},
|
components_{cs}, component_{ca}, typeBoundProcedures_{tbps},
|
||||||
|
@ -135,13 +136,13 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *name() const { return name_; }
|
const char *name() const { return name_; }
|
||||||
int kindParameters() const { return kindParameters_; }
|
std::size_t kindParameters() const { return kindParameters_; }
|
||||||
int lenParameters() const { return lenParameters_; }
|
std::size_t lenParameters() const { return lenParameters_; }
|
||||||
|
|
||||||
// KIND type parameters come first.
|
// KIND type parameters come first.
|
||||||
const TypeParameter &typeParameter(int n) const { return typeParameter_[n]; }
|
const TypeParameter &typeParameter(int n) const { return typeParameter_[n]; }
|
||||||
|
|
||||||
int components() const { return components_; }
|
std::size_t components() const { return components_; }
|
||||||
|
|
||||||
// TBP 0 is the initializer: SUBROUTINE INIT(INSTANCE)
|
// TBP 0 is the initializer: SUBROUTINE INIT(INSTANCE)
|
||||||
static constexpr int initializerTBP{0};
|
static constexpr int initializerTBP{0};
|
||||||
|
@ -152,7 +153,7 @@ public:
|
||||||
// TBP 2 is the FINAL subroutine.
|
// TBP 2 is the FINAL subroutine.
|
||||||
static constexpr int finalTBP{2};
|
static constexpr int finalTBP{2};
|
||||||
|
|
||||||
int typeBoundProcedures() const { return typeBoundProcedures_; }
|
std::size_t typeBoundProcedures() const { return typeBoundProcedures_; }
|
||||||
const TypeBoundProcedure &typeBoundProcedure(int n) const {
|
const TypeBoundProcedure &typeBoundProcedure(int n) const {
|
||||||
return typeBoundProcedure_[n];
|
return typeBoundProcedure_[n];
|
||||||
}
|
}
|
||||||
|
@ -184,14 +185,14 @@ private:
|
||||||
bool IsNontrivialAnalysis() const;
|
bool IsNontrivialAnalysis() const;
|
||||||
|
|
||||||
const char *name_{""}; // NUL-terminated constant text
|
const char *name_{""}; // NUL-terminated constant text
|
||||||
int kindParameters_{0};
|
std::size_t kindParameters_{0};
|
||||||
int lenParameters_{0};
|
std::size_t lenParameters_{0};
|
||||||
const TypeParameter *typeParameter_{nullptr}; // array
|
const TypeParameter *typeParameter_{nullptr}; // array
|
||||||
int components_{0}; // *not* including type parameters
|
std::size_t components_{0}; // *not* including type parameters
|
||||||
const Component *component_{nullptr}; // array
|
const Component *component_{nullptr}; // array
|
||||||
int typeBoundProcedures_{0};
|
std::size_t typeBoundProcedures_{0};
|
||||||
const TypeBoundProcedure *typeBoundProcedure_{nullptr}; // array
|
const TypeBoundProcedure *typeBoundProcedure_{nullptr}; // array
|
||||||
int definedAssignments_{0};
|
std::size_t definedAssignments_{0};
|
||||||
const DefinedAssignment *definedAssignment_{nullptr}; // array
|
const DefinedAssignment *definedAssignment_{nullptr}; // array
|
||||||
std::uint64_t flags_{0};
|
std::uint64_t flags_{0};
|
||||||
std::size_t bytes_{0};
|
std::size_t bytes_{0};
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
#include "descriptor.h"
|
#include "descriptor.h"
|
||||||
|
#include "../lib/common/idioms.h"
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
|
||||||
|
@ -25,41 +26,45 @@ Descriptor::~Descriptor() {
|
||||||
assert(!(Addendum() && (Addendum()->flags() & DescriptorAddendum::Created)));
|
assert(!(Addendum() && (Addendum()->flags() & DescriptorAddendum::Created)));
|
||||||
}
|
}
|
||||||
|
|
||||||
int Descriptor::Establish(TypeCode t, std::size_t elementBytes, void *p,
|
void Descriptor::Establish(TypeCode t, std::size_t elementBytes, void *p,
|
||||||
int rank, const SubscriptValue *extent, ISO::CFI_attribute_t attribute,
|
int rank, const SubscriptValue *extent, ISO::CFI_attribute_t attribute,
|
||||||
bool addendum) {
|
bool addendum) {
|
||||||
int result{
|
CHECK(ISO::CFI_establish(&raw_, p, attribute, t.raw(), elementBytes, rank,
|
||||||
CFI_establish(&raw_, p, attribute, t.raw(), elementBytes, rank, extent)};
|
extent) == CFI_SUCCESS);
|
||||||
raw_.f18Addendum = addendum;
|
raw_.f18Addendum = addendum;
|
||||||
return result;
|
if (addendum) {
|
||||||
|
new (Addendum()) DescriptorAddendum{};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int Descriptor::Establish(TypeCategory c, int kind, void *p, int rank,
|
void Descriptor::Establish(TypeCategory c, int kind, void *p, int rank,
|
||||||
const SubscriptValue *extent, ISO::CFI_attribute_t attribute,
|
const SubscriptValue *extent, ISO::CFI_attribute_t attribute,
|
||||||
bool addendum) {
|
bool addendum) {
|
||||||
std::size_t elementBytes = kind;
|
std::size_t elementBytes = kind;
|
||||||
if (c == TypeCategory::Complex) {
|
if (c == TypeCategory::Complex) {
|
||||||
elementBytes *= 2;
|
elementBytes *= 2;
|
||||||
}
|
}
|
||||||
int result{ISO::CFI_establish(&raw_, p, attribute, TypeCode(c, kind).raw(),
|
CHECK(ISO::CFI_establish(&raw_, p, attribute, TypeCode(c, kind).raw(),
|
||||||
elementBytes, rank, extent)};
|
elementBytes, rank, extent) == CFI_SUCCESS);
|
||||||
raw_.f18Addendum = addendum;
|
raw_.f18Addendum = addendum;
|
||||||
return result;
|
if (addendum) {
|
||||||
|
new (Addendum()) DescriptorAddendum{};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int Descriptor::Establish(const DerivedType &dt, void *p, int rank,
|
void Descriptor::Establish(const DerivedType &dt, void *p, int rank,
|
||||||
const SubscriptValue *extent, ISO::CFI_attribute_t attribute) {
|
const SubscriptValue *extent, ISO::CFI_attribute_t attribute) {
|
||||||
int result{ISO::CFI_establish(
|
CHECK(ISO::CFI_establish(&raw_, p, attribute, CFI_type_struct,
|
||||||
&raw_, p, attribute, CFI_type_struct, dt.SizeInBytes(), rank, extent)};
|
dt.SizeInBytes(), rank, extent) == CFI_SUCCESS);
|
||||||
raw_.f18Addendum = true;
|
raw_.f18Addendum = true;
|
||||||
Addendum()->set_derivedType(dt);
|
new (Addendum()) DescriptorAddendum{&dt};
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Descriptor *Descriptor::Create(TypeCode t, std::size_t elementBytes, void *p,
|
Descriptor *Descriptor::Create(TypeCode t, std::size_t elementBytes, void *p,
|
||||||
int rank, const SubscriptValue *extent, ISO::CFI_attribute_t attribute) {
|
int rank, const SubscriptValue *extent, ISO::CFI_attribute_t attribute) {
|
||||||
std::size_t bytes{SizeInBytes(rank)};
|
std::size_t bytes{SizeInBytes(rank, true)};
|
||||||
Descriptor *result{reinterpret_cast<Descriptor *>(new char[bytes])};
|
Descriptor *result{reinterpret_cast<Descriptor *>(std::malloc(bytes))};
|
||||||
|
CHECK(result != nullptr);
|
||||||
result->Establish(t, elementBytes, p, rank, extent, attribute, true);
|
result->Establish(t, elementBytes, p, rank, extent, attribute, true);
|
||||||
result->Addendum()->flags() |= DescriptorAddendum::Created;
|
result->Addendum()->flags() |= DescriptorAddendum::Created;
|
||||||
return result;
|
return result;
|
||||||
|
@ -67,8 +72,9 @@ Descriptor *Descriptor::Create(TypeCode t, std::size_t elementBytes, void *p,
|
||||||
|
|
||||||
Descriptor *Descriptor::Create(TypeCategory c, int kind, void *p, int rank,
|
Descriptor *Descriptor::Create(TypeCategory c, int kind, void *p, int rank,
|
||||||
const SubscriptValue *extent, ISO::CFI_attribute_t attribute) {
|
const SubscriptValue *extent, ISO::CFI_attribute_t attribute) {
|
||||||
std::size_t bytes{SizeInBytes(rank)};
|
std::size_t bytes{SizeInBytes(rank, true)};
|
||||||
Descriptor *result{reinterpret_cast<Descriptor *>(new char[bytes])};
|
Descriptor *result{reinterpret_cast<Descriptor *>(std::malloc(bytes))};
|
||||||
|
CHECK(result != nullptr);
|
||||||
result->Establish(c, kind, p, rank, extent, attribute, true);
|
result->Establish(c, kind, p, rank, extent, attribute, true);
|
||||||
result->Addendum()->flags() |= DescriptorAddendum::Created;
|
result->Addendum()->flags() |= DescriptorAddendum::Created;
|
||||||
return result;
|
return result;
|
||||||
|
@ -76,8 +82,9 @@ Descriptor *Descriptor::Create(TypeCategory c, int kind, void *p, int rank,
|
||||||
|
|
||||||
Descriptor *Descriptor::Create(const DerivedType &dt, void *p, int rank,
|
Descriptor *Descriptor::Create(const DerivedType &dt, void *p, int rank,
|
||||||
const SubscriptValue *extent, ISO::CFI_attribute_t attribute) {
|
const SubscriptValue *extent, ISO::CFI_attribute_t attribute) {
|
||||||
std::size_t bytes{SizeInBytes(rank, dt.IsNontrivial(), dt.lenParameters())};
|
std::size_t bytes{SizeInBytes(rank, true, dt.lenParameters())};
|
||||||
Descriptor *result{reinterpret_cast<Descriptor *>(new char[bytes])};
|
Descriptor *result{reinterpret_cast<Descriptor *>(std::malloc(bytes))};
|
||||||
|
CHECK(result != nullptr);
|
||||||
result->Establish(dt, p, rank, extent, attribute);
|
result->Establish(dt, p, rank, extent, attribute);
|
||||||
result->Addendum()->flags() |= DescriptorAddendum::Created;
|
result->Addendum()->flags() |= DescriptorAddendum::Created;
|
||||||
return result;
|
return result;
|
||||||
|
@ -86,7 +93,7 @@ Descriptor *Descriptor::Create(const DerivedType &dt, void *p, int rank,
|
||||||
void Descriptor::Destroy() {
|
void Descriptor::Destroy() {
|
||||||
if (const DescriptorAddendum * addendum{Addendum()}) {
|
if (const DescriptorAddendum * addendum{Addendum()}) {
|
||||||
if (addendum->flags() & DescriptorAddendum::Created) {
|
if (addendum->flags() & DescriptorAddendum::Created) {
|
||||||
delete[] reinterpret_cast<char *>(this);
|
std::free(reinterpret_cast<void *>(this));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -97,11 +104,20 @@ std::size_t Descriptor::SizeInBytes() const {
|
||||||
(addendum ? addendum->SizeInBytes() : 0);
|
(addendum ? addendum->SizeInBytes() : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::size_t Descriptor::Elements() const {
|
||||||
|
int n{rank()};
|
||||||
|
std::size_t elements{1};
|
||||||
|
for (int j{0}; j < n; ++j) {
|
||||||
|
elements *= GetDimension(j).Extent();
|
||||||
|
}
|
||||||
|
return elements;
|
||||||
|
}
|
||||||
|
|
||||||
void Descriptor::Check() const {
|
void Descriptor::Check() const {
|
||||||
// TODO
|
// TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t DescriptorAddendum::SizeInBytes() const {
|
std::size_t DescriptorAddendum::SizeInBytes() const {
|
||||||
return SizeInBytes(derivedType_->lenParameters());
|
return SizeInBytes(LenParameters());
|
||||||
}
|
}
|
||||||
} // namespace Fortran::runtime
|
} // namespace Fortran::runtime
|
||||||
|
|
|
@ -70,17 +70,25 @@ public:
|
||||||
LeadingDimensionContiguous = 0x040, // only leading dimension contiguous
|
LeadingDimensionContiguous = 0x040, // only leading dimension contiguous
|
||||||
};
|
};
|
||||||
|
|
||||||
explicit DescriptorAddendum(const DerivedType &dt, std::uint64_t flags = 0)
|
explicit DescriptorAddendum(
|
||||||
: derivedType_{&dt}, flags_{flags} {}
|
const DerivedType *dt = nullptr, std::uint64_t flags = 0)
|
||||||
|
: derivedType_{dt}, flags_{flags} {}
|
||||||
|
|
||||||
const DerivedType *derivedType() const { return derivedType_; }
|
const DerivedType *derivedType() const { return derivedType_; }
|
||||||
DescriptorAddendum &set_derivedType(const DerivedType &dt) {
|
DescriptorAddendum &set_derivedType(const DerivedType *dt) {
|
||||||
derivedType_ = &dt;
|
derivedType_ = dt;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
std::uint64_t &flags() { return flags_; }
|
std::uint64_t &flags() { return flags_; }
|
||||||
const std::uint64_t &flags() const { return flags_; }
|
const std::uint64_t &flags() const { return flags_; }
|
||||||
|
|
||||||
|
std::size_t LenParameters() const {
|
||||||
|
if (derivedType_ != nullptr) {
|
||||||
|
return derivedType_->lenParameters();
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
TypeParameterValue LenParameterValue(int which) const { return len_[which]; }
|
TypeParameterValue LenParameterValue(int which) const { return len_[which]; }
|
||||||
static constexpr std::size_t SizeInBytes(int lenParameters) {
|
static constexpr std::size_t SizeInBytes(int lenParameters) {
|
||||||
return sizeof(DescriptorAddendum) - sizeof(TypeParameterValue) +
|
return sizeof(DescriptorAddendum) - sizeof(TypeParameterValue) +
|
||||||
|
@ -118,15 +126,15 @@ public:
|
||||||
|
|
||||||
~Descriptor();
|
~Descriptor();
|
||||||
|
|
||||||
int Establish(TypeCode t, std::size_t elementBytes, void *p = nullptr,
|
void Establish(TypeCode t, std::size_t elementBytes, void *p = nullptr,
|
||||||
int rank = maxRank, const SubscriptValue *extent = nullptr,
|
int rank = maxRank, const SubscriptValue *extent = nullptr,
|
||||||
ISO::CFI_attribute_t attribute = CFI_attribute_other,
|
ISO::CFI_attribute_t attribute = CFI_attribute_other,
|
||||||
bool addendum = false);
|
bool addendum = false);
|
||||||
int Establish(TypeCategory, int kind, void *p = nullptr, int rank = maxRank,
|
void Establish(TypeCategory, int kind, void *p = nullptr, int rank = maxRank,
|
||||||
const SubscriptValue *extent = nullptr,
|
const SubscriptValue *extent = nullptr,
|
||||||
ISO::CFI_attribute_t attribute = CFI_attribute_other,
|
ISO::CFI_attribute_t attribute = CFI_attribute_other,
|
||||||
bool addendum = false);
|
bool addendum = false);
|
||||||
int Establish(const DerivedType &dt, void *p = nullptr, int rank = maxRank,
|
void Establish(const DerivedType &dt, void *p = nullptr, int rank = maxRank,
|
||||||
const SubscriptValue *extent = nullptr,
|
const SubscriptValue *extent = nullptr,
|
||||||
ISO::CFI_attribute_t attribute = CFI_attribute_other);
|
ISO::CFI_attribute_t attribute = CFI_attribute_other);
|
||||||
|
|
||||||
|
@ -142,7 +150,7 @@ public:
|
||||||
ISO::CFI_attribute_t attribute = CFI_attribute_other);
|
ISO::CFI_attribute_t attribute = CFI_attribute_other);
|
||||||
|
|
||||||
// Descriptor instances allocated via Create() above must be deallocated
|
// Descriptor instances allocated via Create() above must be deallocated
|
||||||
// by calling Destroy() so that operator delete[] is invoked.
|
// by calling Destroy().
|
||||||
void Destroy();
|
void Destroy();
|
||||||
|
|
||||||
ISO::CFI_cdesc_t &raw() { return raw_; }
|
ISO::CFI_cdesc_t &raw() { return raw_; }
|
||||||
|
@ -174,6 +182,41 @@ public:
|
||||||
return (subscriptValue - dimension.LowerBound()) * dimension.ByteStride();
|
return (subscriptValue - dimension.LowerBound()) * dimension.ByteStride();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::size_t SubscriptsToByteOffset(const SubscriptValue *subscript) const {
|
||||||
|
std::size_t offset{0};
|
||||||
|
for (int j{0}; j < raw_.rank; ++j) {
|
||||||
|
offset += SubscriptByteOffset(j, subscript[j]);
|
||||||
|
}
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename A> A *Element(std::size_t offset) const {
|
||||||
|
return reinterpret_cast<A *>(
|
||||||
|
reinterpret_cast<char *>(raw_.base_addr) + offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename A> A *Element(const SubscriptValue *subscript) const {
|
||||||
|
return Element<A>(SubscriptsToByteOffset(subscript));
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetLowerBounds(SubscriptValue *subscript) const {
|
||||||
|
for (int j{0}; j < raw_.rank; ++j) {
|
||||||
|
subscript[j] = GetDimension(j).LowerBound();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void IncrementSubscripts(
|
||||||
|
SubscriptValue *subscript, const int *permutation = nullptr) const {
|
||||||
|
for (int j{0}; j < raw_.rank; ++j) {
|
||||||
|
int k{permutation ? permutation[j] : j};
|
||||||
|
const Dimension &dim{GetDimension(k)};
|
||||||
|
if (subscript[k]++ < dim.UpperBound()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
subscript[k] = dim.LowerBound();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
DescriptorAddendum *Addendum() {
|
DescriptorAddendum *Addendum() {
|
||||||
if (raw_.f18Addendum != 0) {
|
if (raw_.f18Addendum != 0) {
|
||||||
return reinterpret_cast<DescriptorAddendum *>(&GetDimension(rank()));
|
return reinterpret_cast<DescriptorAddendum *>(&GetDimension(rank()));
|
||||||
|
@ -199,29 +242,36 @@ public:
|
||||||
}
|
}
|
||||||
return bytes;
|
return bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t SizeInBytes() const;
|
std::size_t SizeInBytes() const;
|
||||||
|
|
||||||
|
std::size_t Elements() const;
|
||||||
|
|
||||||
|
bool IsContiguous() const {
|
||||||
|
if (raw_.attribute == CFI_attribute_allocatable) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (const DescriptorAddendum * addendum{Addendum()}) {
|
||||||
|
return (addendum->flags() & DescriptorAddendum::AllContiguous) != 0;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void Check() const;
|
void Check() const;
|
||||||
|
|
||||||
// TODO: creation of array sections
|
// TODO: creation of array sections
|
||||||
|
|
||||||
template<typename A> A &Element(std::size_t offset = 0) const {
|
|
||||||
auto p = reinterpret_cast<char *>(raw_.base_addr);
|
|
||||||
return *reinterpret_cast<A *>(p + offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ISO::CFI_cdesc_t raw_;
|
ISO::CFI_cdesc_t raw_;
|
||||||
};
|
};
|
||||||
static_assert(sizeof(Descriptor) == sizeof(ISO::CFI_cdesc_t));
|
static_assert(sizeof(Descriptor) == sizeof(ISO::CFI_cdesc_t));
|
||||||
|
|
||||||
// Properly configured instances of StaticDescriptor will occupy the
|
// Properly configured instances of StaticDescriptor will occupy the
|
||||||
// exact amount of storage required for the descriptor based on its
|
// exact amount of storage required for the descriptor, its dimensional
|
||||||
// number of dimensions and whether it requires an addendum. To build
|
// information, and possible addendum. To build such a static descriptor,
|
||||||
// such a static descriptor, declare an instance of StaticDescriptor<>,
|
// declare an instance of StaticDescriptor<>, extract a reference to its
|
||||||
// extract a reference to the Descriptor via the descriptor() accessor,
|
// descriptor via the descriptor() accessor, and then built a Descriptor
|
||||||
// and then built a Descriptor therein via descriptor.Establish().
|
// therein via descriptor.Establish(), e.g.:
|
||||||
// e.g.:
|
|
||||||
// StaticDescriptor<R,A,LP> statDesc;
|
// StaticDescriptor<R,A,LP> statDesc;
|
||||||
// Descriptor &descriptor{statDesc.descriptor()};
|
// Descriptor &descriptor{statDesc.descriptor()};
|
||||||
// descriptor.Establish( ... );
|
// descriptor.Establish( ... );
|
||||||
|
@ -240,9 +290,10 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
void Check() {
|
void Check() {
|
||||||
assert(descriptor().SizeInBytes() <= byteSize);
|
|
||||||
assert(descriptor().rank() <= maxRank);
|
assert(descriptor().rank() <= maxRank);
|
||||||
|
assert(descriptor().SizeInBytes() <= byteSize);
|
||||||
if (DescriptorAddendum * addendum{descriptor().Addendum()}) {
|
if (DescriptorAddendum * addendum{descriptor().Addendum()}) {
|
||||||
|
assert(hasAddendum);
|
||||||
if (const DerivedType * dt{addendum->derivedType()}) {
|
if (const DerivedType * dt{addendum->derivedType()}) {
|
||||||
assert(dt->lenParameters() <= maxLengthTypeParameters);
|
assert(dt->lenParameters() <= maxLengthTypeParameters);
|
||||||
} else {
|
} else {
|
||||||
|
@ -252,6 +303,7 @@ public:
|
||||||
assert(!hasAddendum);
|
assert(!hasAddendum);
|
||||||
assert(maxLengthTypeParameters == 0);
|
assert(maxLengthTypeParameters == 0);
|
||||||
}
|
}
|
||||||
|
descriptor().Check();
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -0,0 +1,150 @@
|
||||||
|
// Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "descriptor.h"
|
||||||
|
#include "../lib/common/idioms.h"
|
||||||
|
#include "../lib/evaluate/integer.h"
|
||||||
|
#include <algorithm>
|
||||||
|
#include <bitset>
|
||||||
|
#include <cinttypes>
|
||||||
|
#include <cstdlib>
|
||||||
|
|
||||||
|
namespace Fortran::runtime {
|
||||||
|
|
||||||
|
template<int BITS> inline std::int64_t LoadInt64(const char *p) {
|
||||||
|
using Int = const evaluate::value::Integer<BITS>;
|
||||||
|
Int *ip{reinterpret_cast<Int *>(p)};
|
||||||
|
return ip->ToInt64();
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline std::int64_t GetInt64(const char *p, std::size_t bytes) {
|
||||||
|
switch (bytes) {
|
||||||
|
case 1: return LoadInt64<8>(p);
|
||||||
|
case 2: return LoadInt64<16>(p);
|
||||||
|
case 4: return LoadInt64<32>(p);
|
||||||
|
case 8: return LoadInt64<64>(p);
|
||||||
|
default: CRASH_NO_CASE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// F2018 16.9.163
|
||||||
|
Descriptor *RESHAPE(const Descriptor &source, const Descriptor &shape,
|
||||||
|
const Descriptor *pad, const Descriptor *order) {
|
||||||
|
// Compute and check the rank of the result.
|
||||||
|
CHECK(shape.rank() == 1);
|
||||||
|
CHECK(shape.type().IsInteger());
|
||||||
|
SubscriptValue resultRank{shape.GetDimension(0).Extent()};
|
||||||
|
CHECK(resultRank >= 0 && resultRank <= static_cast<SubscriptValue>(maxRank));
|
||||||
|
|
||||||
|
// Extract and check the shape of the result; compute its element count.
|
||||||
|
SubscriptValue resultExtent[maxRank];
|
||||||
|
std::size_t shapeElementBytes{shape.ElementBytes()};
|
||||||
|
std::size_t resultElements{1};
|
||||||
|
SubscriptValue shapeSubscript{shape.GetDimension(0).LowerBound()};
|
||||||
|
for (SubscriptValue j{0}; j < resultRank; ++j, ++shapeSubscript) {
|
||||||
|
resultExtent[j] =
|
||||||
|
GetInt64(shape.Element<char>(&shapeSubscript), shapeElementBytes);
|
||||||
|
CHECK(resultExtent[j] >= 0);
|
||||||
|
resultElements *= resultExtent[j];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that there are sufficient elements in the SOURCE=, or that
|
||||||
|
// the optional PAD= argument is present and nonempty.
|
||||||
|
std::size_t sourceElements{source.Elements()};
|
||||||
|
std::size_t padElements{pad ? pad->Elements() : 0};
|
||||||
|
if (resultElements < sourceElements) {
|
||||||
|
CHECK(padElements > 0);
|
||||||
|
CHECK(pad->ElementBytes() == source.ElementBytes());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract and check the optional ORDER= argument, which must be a
|
||||||
|
// permutation of [1..resultRank].
|
||||||
|
int dimOrder[maxRank];
|
||||||
|
if (order != nullptr) {
|
||||||
|
CHECK(order->rank() == 1);
|
||||||
|
CHECK(order->type().IsInteger());
|
||||||
|
CHECK(order->GetDimension(0).Extent() == resultRank);
|
||||||
|
std::bitset<maxRank> values;
|
||||||
|
SubscriptValue orderSubscript{order->GetDimension(0).LowerBound()};
|
||||||
|
for (SubscriptValue j{0}; j < resultRank; ++j, ++orderSubscript) {
|
||||||
|
auto k{GetInt64(order->Element<char>(orderSubscript), shapeElementBytes)};
|
||||||
|
CHECK(k >= 1 && k <= resultRank && !values.test(k - 1));
|
||||||
|
values.set(k - 1);
|
||||||
|
dimOrder[k - 1] = j;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (int j{0}; j < resultRank; ++j) {
|
||||||
|
dimOrder[j] = j;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocate the result's data storage.
|
||||||
|
std::size_t elementBytes{source.ElementBytes()};
|
||||||
|
std::size_t resultBytes{resultElements * elementBytes};
|
||||||
|
void *data{std::malloc(resultBytes)};
|
||||||
|
CHECK(resultBytes == 0 || data != nullptr);
|
||||||
|
|
||||||
|
// Create and populate the result's descriptor.
|
||||||
|
const DescriptorAddendum *sourceAddendum{source.Addendum()};
|
||||||
|
const DerivedType *sourceDerivedType{
|
||||||
|
sourceAddendum ? sourceAddendum->derivedType() : nullptr};
|
||||||
|
Descriptor *result{nullptr};
|
||||||
|
if (sourceDerivedType != nullptr) {
|
||||||
|
result =
|
||||||
|
Descriptor::Create(*sourceDerivedType, data, resultRank, resultExtent);
|
||||||
|
} else {
|
||||||
|
result = Descriptor::Create(
|
||||||
|
source.type(), elementBytes, data, resultRank, resultExtent);
|
||||||
|
}
|
||||||
|
DescriptorAddendum *resultAddendum{result->Addendum()};
|
||||||
|
CHECK(resultAddendum != nullptr);
|
||||||
|
resultAddendum->flags() |= DescriptorAddendum::DoNotFinalize;
|
||||||
|
resultAddendum->flags() |= DescriptorAddendum::AllContiguous;
|
||||||
|
if (sourceDerivedType != nullptr) {
|
||||||
|
std::size_t lenParameters{sourceDerivedType->lenParameters()};
|
||||||
|
for (std::size_t j{0}; j < lenParameters; ++j) {
|
||||||
|
resultAddendum->SetLenParameterValue(
|
||||||
|
j, sourceAddendum->LenParameterValue(j));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Populate the result's elements.
|
||||||
|
SubscriptValue resultSubscript[maxRank];
|
||||||
|
result->GetLowerBounds(resultSubscript);
|
||||||
|
SubscriptValue sourceSubscript[maxRank];
|
||||||
|
source.GetLowerBounds(sourceSubscript);
|
||||||
|
std::size_t resultElement{0};
|
||||||
|
std::size_t elementsFromSource{std::min(resultElements, sourceElements)};
|
||||||
|
for (; resultElement < elementsFromSource; ++resultElement) {
|
||||||
|
std::memcpy(result->Element<void>(resultSubscript),
|
||||||
|
source.Element<const void>(sourceSubscript), elementBytes);
|
||||||
|
source.IncrementSubscripts(sourceSubscript);
|
||||||
|
result->IncrementSubscripts(resultSubscript, dimOrder);
|
||||||
|
}
|
||||||
|
if (resultElement < resultElements) {
|
||||||
|
// Remaining elements come from the optional PAD= argument.
|
||||||
|
SubscriptValue padSubscript[maxRank];
|
||||||
|
pad->GetLowerBounds(padSubscript);
|
||||||
|
for (; resultElement < resultElements; ++resultElement) {
|
||||||
|
std::memcpy(result->Element<void>(resultSubscript),
|
||||||
|
pad->Element<const void>(padSubscript), elementBytes);
|
||||||
|
pad->IncrementSubscripts(padSubscript);
|
||||||
|
result->IncrementSubscripts(resultSubscript, dimOrder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Fortran::runtime
|
|
@ -0,0 +1,26 @@
|
||||||
|
// Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#ifndef FORTRAN_RUNTIME_TRANSFORMATIONAL_H_
|
||||||
|
#define FORTRAN_RUNTIME_TRANSFORMATIONAL_H_
|
||||||
|
|
||||||
|
#include "descriptor.h"
|
||||||
|
|
||||||
|
namespace Fortran::runtime {
|
||||||
|
|
||||||
|
Descriptor *RESHAPE(const Descriptor &source, const Descriptor &shape,
|
||||||
|
const Descriptor *pad = nullptr, const Descriptor *order = nullptr);
|
||||||
|
|
||||||
|
} // namespace Fortran::runtime
|
||||||
|
#endif // FORTRAN_RUNTIME_TRANSFORMATIONAL_H_
|
|
@ -59,5 +59,4 @@ TypeCode::TypeCode(TypeCategory f, int kind) {
|
||||||
case TypeCategory::Derived: raw_ = CFI_type_struct; break;
|
case TypeCategory::Derived: raw_ = CFI_type_struct; break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Fortran::runtime
|
} // namespace Fortran::runtime
|
||||||
|
|
|
@ -73,9 +73,20 @@ target_link_libraries(expression-test
|
||||||
FortranParser
|
FortranParser
|
||||||
)
|
)
|
||||||
|
|
||||||
|
add_executable(reshape-test
|
||||||
|
reshape.cc
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(reshape-test
|
||||||
|
FortranEvaluate
|
||||||
|
FortranEvaluateTesting
|
||||||
|
FortranRuntime
|
||||||
|
)
|
||||||
|
|
||||||
add_test(NAME Expression COMMAND expression-test)
|
add_test(NAME Expression COMMAND expression-test)
|
||||||
add_test(NAME Leadz COMMAND leading-zero-bit-count-test)
|
add_test(NAME Leadz COMMAND leading-zero-bit-count-test)
|
||||||
add_test(NAME PopPar COMMAND bit-population-count-test)
|
add_test(NAME PopPar COMMAND bit-population-count-test)
|
||||||
add_test(NAME Integer COMMAND integer-test)
|
add_test(NAME Integer COMMAND integer-test)
|
||||||
add_test(NAME Logical COMMAND logical-test)
|
add_test(NAME Logical COMMAND logical-test)
|
||||||
add_test(NAME Real COMMAND real-test)
|
add_test(NAME Real COMMAND real-test)
|
||||||
|
add_test(NAME RESHAPE COMMAND reshape-test)
|
||||||
|
|
|
@ -0,0 +1,84 @@
|
||||||
|
// Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "testing.h"
|
||||||
|
#include "../../runtime/descriptor.h"
|
||||||
|
#include "../../runtime/transformational.h"
|
||||||
|
#include <cinttypes>
|
||||||
|
|
||||||
|
using namespace Fortran::common;
|
||||||
|
using namespace Fortran::runtime;
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
std::size_t dataElements{24};
|
||||||
|
std::int32_t *data{new std::int32_t[dataElements]};
|
||||||
|
for (std::size_t j{0}; j < dataElements; ++j) {
|
||||||
|
data[j] = j;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const SubscriptValue sourceExtent[]{2, 3, 4};
|
||||||
|
Descriptor *source{Descriptor::Create(TypeCategory::Integer, sizeof data[0],
|
||||||
|
reinterpret_cast<void *>(data), 3, sourceExtent,
|
||||||
|
CFI_attribute_allocatable)};
|
||||||
|
source->Check();
|
||||||
|
MATCH(3, source->rank());
|
||||||
|
MATCH(2, source->GetDimension(0).Extent());
|
||||||
|
MATCH(3, source->GetDimension(1).Extent());
|
||||||
|
MATCH(4, source->GetDimension(2).Extent());
|
||||||
|
|
||||||
|
static const std::int16_t shapeData[]{8, 4};
|
||||||
|
static const SubscriptValue shapeExtent{2};
|
||||||
|
Descriptor *shape{Descriptor::Create(TypeCategory::Integer,
|
||||||
|
static_cast<int>(sizeof shapeData[0]),
|
||||||
|
const_cast<void *>(reinterpret_cast<const void *>(shapeData)), 1,
|
||||||
|
&shapeExtent)};
|
||||||
|
shape->Check();
|
||||||
|
MATCH(1, shape->rank());
|
||||||
|
MATCH(2, shape->GetDimension(0).Extent());
|
||||||
|
|
||||||
|
StaticDescriptor<3> padDescriptor;
|
||||||
|
static const std::int32_t padData[]{24, 25, 26, 27, 28, 29, 30, 31};
|
||||||
|
static const SubscriptValue padExtent[]{2, 2, 3};
|
||||||
|
padDescriptor.descriptor().Establish(TypeCategory::Integer,
|
||||||
|
static_cast<int>(sizeof padData[0]),
|
||||||
|
const_cast<void *>(reinterpret_cast<const void *>(padData)), 3,
|
||||||
|
padExtent);
|
||||||
|
padDescriptor.Check();
|
||||||
|
|
||||||
|
Descriptor *result{RESHAPE(*source, *shape, &padDescriptor.descriptor())};
|
||||||
|
|
||||||
|
TEST(result != nullptr);
|
||||||
|
result->Check();
|
||||||
|
MATCH(sizeof(std::int32_t), result->ElementBytes());
|
||||||
|
MATCH(2, result->rank());
|
||||||
|
TEST(result->type().IsInteger());
|
||||||
|
for (std::int32_t j{0}; j < 32; ++j) {
|
||||||
|
MATCH(j, *result->Element<std::int32_t>(j * sizeof(std::int32_t)));
|
||||||
|
}
|
||||||
|
for (std::int32_t j{0}; j < 32; ++j) {
|
||||||
|
SubscriptValue ss[2]{1 + (j % 8), 1 + (j / 8)};
|
||||||
|
MATCH(j, *result->Element<std::int32_t>(ss));
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: test ORDER=
|
||||||
|
|
||||||
|
// Plug leaks; should run cleanly beneath valgrind
|
||||||
|
free(result->raw().base_addr);
|
||||||
|
result->Destroy();
|
||||||
|
shape->Destroy();
|
||||||
|
source->Destroy();
|
||||||
|
delete[] data;
|
||||||
|
|
||||||
|
return testing::Complete();
|
||||||
|
}
|
Loading…
Reference in New Issue