[flang] test and debug RESHAPE
Original-commit: flang-compiler/f18@c20ce350c1 Reviewed-on: https://github.com/flang-compiler/f18/pull/162 Tree-same-pre-rewrite: false
This commit is contained in:
parent
a8fed82258
commit
fac96c4612
|
@ -16,7 +16,6 @@
|
|||
// as specified in section 18.5.5 of Fortran 2018.
|
||||
|
||||
#include "descriptor.h"
|
||||
#include <cstdlib>
|
||||
|
||||
namespace Fortran::ISO {
|
||||
extern "C" {
|
||||
|
@ -37,12 +36,13 @@ int CFI_allocate(CFI_cdesc_t *descriptor, const CFI_index_t lower_bounds[],
|
|||
if (descriptor->version != CFI_VERSION) {
|
||||
return CFI_INVALID_DESCRIPTOR;
|
||||
}
|
||||
if ((descriptor->attribute &
|
||||
~(CFI_attribute_pointer | CFI_attribute_allocatable)) != 0) {
|
||||
if (descriptor->attribute != CFI_attribute_allocatable &&
|
||||
descriptor->attribute != CFI_attribute_pointer) {
|
||||
// Non-interoperable object
|
||||
return CFI_INVALID_DESCRIPTOR;
|
||||
}
|
||||
if (descriptor->base_addr != nullptr) {
|
||||
if (descriptor->attribute == CFI_attribute_allocatable &&
|
||||
descriptor->base_addr != nullptr) {
|
||||
return CFI_ERROR_BASE_ADDR_NOT_NULL;
|
||||
}
|
||||
if (descriptor->rank > CFI_MAX_RANK) {
|
||||
|
@ -70,7 +70,7 @@ int CFI_allocate(CFI_cdesc_t *descriptor, const CFI_index_t lower_bounds[],
|
|||
dim->sm = byteSize;
|
||||
byteSize *= extent;
|
||||
}
|
||||
void *p{std::malloc(byteSize)};
|
||||
void *p{new char[byteSize]};
|
||||
if (p == nullptr) {
|
||||
return CFI_ERROR_MEM_ALLOCATION;
|
||||
}
|
||||
|
@ -83,15 +83,15 @@ int CFI_deallocate(CFI_cdesc_t *descriptor) {
|
|||
if (descriptor->version != CFI_VERSION) {
|
||||
return CFI_INVALID_DESCRIPTOR;
|
||||
}
|
||||
if ((descriptor->attribute &
|
||||
~(CFI_attribute_pointer | CFI_attribute_allocatable)) != 0) {
|
||||
if (descriptor->attribute != CFI_attribute_allocatable &&
|
||||
descriptor->attribute != CFI_attribute_pointer) {
|
||||
// Non-interoperable object
|
||||
return CFI_INVALID_DESCRIPTOR;
|
||||
}
|
||||
if (descriptor->base_addr == nullptr) {
|
||||
return CFI_ERROR_BASE_ADDR_NULL;
|
||||
}
|
||||
std::free(descriptor->base_addr);
|
||||
delete[] static_cast<char *>(descriptor->base_addr);
|
||||
descriptor->base_addr = nullptr;
|
||||
return CFI_SUCCESS;
|
||||
}
|
||||
|
@ -141,12 +141,16 @@ static constexpr std::size_t MinElemLen(CFI_type_t type) {
|
|||
int CFI_establish(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[]) {
|
||||
if ((attribute & ~(CFI_attribute_pointer | CFI_attribute_allocatable)) != 0) {
|
||||
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 != nullptr && attribute != CFI_attribute_pointer) {
|
||||
return CFI_ERROR_BASE_ADDR_NOT_NULL;
|
||||
}
|
||||
if (rank > 0 && base_addr != nullptr && extents == nullptr) {
|
||||
return CFI_INVALID_EXTENT;
|
||||
}
|
||||
|
@ -177,7 +181,14 @@ int CFI_establish(CFI_cdesc_t *descriptor, void *base_addr,
|
|||
}
|
||||
|
||||
int CFI_is_contiguous(const CFI_cdesc_t *descriptor) {
|
||||
return 0; // TODO
|
||||
std::size_t bytes{descriptor->elem_len};
|
||||
for (int j{0}; j < descriptor->rank; ++j) {
|
||||
if (bytes != descriptor->dim[j].sm) {
|
||||
return 0;
|
||||
}
|
||||
bytes *= descriptor->dim[j].extent;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int CFI_section(CFI_cdesc_t *result, const CFI_cdesc_t *source,
|
||||
|
|
|
@ -47,4 +47,36 @@ bool DerivedType::IsNontrivialAnalysis() const {
|
|||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void DerivedType::Initialize(char *instance) const {
|
||||
if (typeBoundProcedures_ > InitializerTBP) {
|
||||
if (auto f{reinterpret_cast<void (*)(char *)>(
|
||||
typeBoundProcedure_[InitializerTBP].code.host)}) {
|
||||
f(instance);
|
||||
}
|
||||
}
|
||||
for (std::size_t j{0}; j < components_; ++j) {
|
||||
if (const Descriptor * descriptor{component_[j].GetDescriptor(instance)}) {
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DerivedType::Destroy(char *instance, bool finalize) const {
|
||||
if (finalize && typeBoundProcedures_ > FinalTBP) {
|
||||
if (auto f{reinterpret_cast<void (*)(char *)>(
|
||||
typeBoundProcedure_[FinalTBP].code.host)}) {
|
||||
f(instance);
|
||||
}
|
||||
}
|
||||
const char *constInstance{instance};
|
||||
for (std::size_t j{0}; j < components_; ++j) {
|
||||
if (Descriptor * descriptor{component_[j].GetDescriptor(instance)}) {
|
||||
descriptor->Deallocate(finalize);
|
||||
} else if (const Descriptor *
|
||||
descriptor{component_[j].GetDescriptor(constInstance)}) {
|
||||
descriptor->Destroy(component_[j].Locate<char>(instance), finalize);
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace Fortran::runtime
|
||||
|
|
|
@ -77,6 +77,14 @@ public:
|
|||
return reinterpret_cast<const A *>(dtInstance + offset_);
|
||||
}
|
||||
|
||||
Descriptor *GetDescriptor(char *dtInstance) const {
|
||||
if (IsDescriptor()) {
|
||||
return Locate<Descriptor>(dtInstance);
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
const Descriptor *GetDescriptor(const char *dtInstance) const {
|
||||
if (staticDescriptor_ != nullptr) {
|
||||
return staticDescriptor_;
|
||||
|
@ -144,14 +152,8 @@ public:
|
|||
|
||||
std::size_t components() const { return components_; }
|
||||
|
||||
// TBP 0 is the initializer: SUBROUTINE INIT(INSTANCE)
|
||||
static constexpr int initializerTBP{0};
|
||||
|
||||
// TBP 1 is the sourced allocation copier: SUBROUTINE COPYINIT(TO, FROM)
|
||||
static constexpr int copierTBP{1};
|
||||
|
||||
// TBP 2 is the FINAL subroutine.
|
||||
static constexpr int finalTBP{2};
|
||||
// The first few type-bound procedure indices are special.
|
||||
enum SpecialTBP { InitializerTBP, CopierTBP, FinalTBP };
|
||||
|
||||
std::size_t typeBoundProcedures() const { return typeBoundProcedures_; }
|
||||
const TypeBoundProcedure &typeBoundProcedure(int n) const {
|
||||
|
@ -176,6 +178,9 @@ public:
|
|||
|
||||
bool IsSameType(const DerivedType &) const;
|
||||
|
||||
void Initialize(char *instance) const;
|
||||
void Destroy(char *instance, bool finalize = true) const;
|
||||
|
||||
private:
|
||||
enum Flag { SEQUENCE = 1, BIND_C = 2, NONTRIVIAL = 4 };
|
||||
|
||||
|
|
|
@ -20,10 +20,9 @@
|
|||
namespace Fortran::runtime {
|
||||
|
||||
Descriptor::~Descriptor() {
|
||||
// Descriptors created by Descriptor::Create() must be destroyed by
|
||||
// Descriptor::Destroy(), not by the default destructor, so that
|
||||
// the array variant operator delete[] is properly used.
|
||||
assert(!(Addendum() && (Addendum()->flags() & DescriptorAddendum::Created)));
|
||||
if (raw_.attribute != CFI_attribute_pointer) {
|
||||
Deallocate();
|
||||
}
|
||||
}
|
||||
|
||||
void Descriptor::Establish(TypeCode t, std::size_t elementBytes, void *p,
|
||||
|
@ -60,42 +59,33 @@ void Descriptor::Establish(const DerivedType &dt, void *p, int rank,
|
|||
new (Addendum()) DescriptorAddendum{&dt};
|
||||
}
|
||||
|
||||
Descriptor *Descriptor::Create(TypeCode t, std::size_t elementBytes, void *p,
|
||||
int rank, const SubscriptValue *extent, ISO::CFI_attribute_t attribute) {
|
||||
std::unique_ptr<Descriptor> Descriptor::Create(TypeCode t,
|
||||
std::size_t elementBytes, void *p, int rank, const SubscriptValue *extent,
|
||||
ISO::CFI_attribute_t attribute) {
|
||||
std::size_t bytes{SizeInBytes(rank, true)};
|
||||
Descriptor *result{reinterpret_cast<Descriptor *>(std::malloc(bytes))};
|
||||
Descriptor *result{reinterpret_cast<Descriptor *>(new char[bytes])};
|
||||
CHECK(result != nullptr);
|
||||
result->Establish(t, elementBytes, p, rank, extent, attribute, true);
|
||||
result->Addendum()->flags() |= DescriptorAddendum::Created;
|
||||
return result;
|
||||
return std::unique_ptr<Descriptor>{result};
|
||||
}
|
||||
|
||||
Descriptor *Descriptor::Create(TypeCategory c, int kind, void *p, int rank,
|
||||
const SubscriptValue *extent, ISO::CFI_attribute_t attribute) {
|
||||
std::unique_ptr<Descriptor> Descriptor::Create(TypeCategory c, int kind,
|
||||
void *p, int rank, const SubscriptValue *extent,
|
||||
ISO::CFI_attribute_t attribute) {
|
||||
std::size_t bytes{SizeInBytes(rank, true)};
|
||||
Descriptor *result{reinterpret_cast<Descriptor *>(std::malloc(bytes))};
|
||||
Descriptor *result{reinterpret_cast<Descriptor *>(new char[bytes])};
|
||||
CHECK(result != nullptr);
|
||||
result->Establish(c, kind, p, rank, extent, attribute, true);
|
||||
result->Addendum()->flags() |= DescriptorAddendum::Created;
|
||||
return result;
|
||||
return std::unique_ptr<Descriptor>{result};
|
||||
}
|
||||
|
||||
Descriptor *Descriptor::Create(const DerivedType &dt, void *p, int rank,
|
||||
const SubscriptValue *extent, ISO::CFI_attribute_t attribute) {
|
||||
std::unique_ptr<Descriptor> Descriptor::Create(const DerivedType &dt, void *p,
|
||||
int rank, const SubscriptValue *extent, ISO::CFI_attribute_t attribute) {
|
||||
std::size_t bytes{SizeInBytes(rank, true, dt.lenParameters())};
|
||||
Descriptor *result{reinterpret_cast<Descriptor *>(std::malloc(bytes))};
|
||||
Descriptor *result{reinterpret_cast<Descriptor *>(new char[bytes])};
|
||||
CHECK(result != nullptr);
|
||||
result->Establish(dt, p, rank, extent, attribute);
|
||||
result->Addendum()->flags() |= DescriptorAddendum::Created;
|
||||
return result;
|
||||
}
|
||||
|
||||
void Descriptor::Destroy() {
|
||||
if (const DescriptorAddendum * addendum{Addendum()}) {
|
||||
if (addendum->flags() & DescriptorAddendum::Created) {
|
||||
std::free(reinterpret_cast<void *>(this));
|
||||
}
|
||||
}
|
||||
return std::unique_ptr<Descriptor>{result};
|
||||
}
|
||||
|
||||
std::size_t Descriptor::SizeInBytes() const {
|
||||
|
@ -113,11 +103,75 @@ std::size_t Descriptor::Elements() const {
|
|||
return elements;
|
||||
}
|
||||
|
||||
int Descriptor::Allocate(
|
||||
const SubscriptValue lb[], const SubscriptValue ub[], std::size_t charLen) {
|
||||
int result{ISO::CFI_allocate(&raw_, lb, ub, charLen)};
|
||||
if (result == CFI_SUCCESS) {
|
||||
// TODO: derived type initialization
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int Descriptor::Deallocate(bool finalize) {
|
||||
if (raw_.base_addr != nullptr) {
|
||||
Destroy(static_cast<char *>(raw_.base_addr), finalize);
|
||||
}
|
||||
return ISO::CFI_deallocate(&raw_);
|
||||
}
|
||||
|
||||
void Descriptor::Destroy(char *data, bool finalize) const {
|
||||
if (data != nullptr) {
|
||||
if (const DescriptorAddendum * addendum{Addendum()}) {
|
||||
if (addendum->flags() & DescriptorAddendum::DoNotFinalize) {
|
||||
finalize = false;
|
||||
}
|
||||
if (const DerivedType * dt{addendum->derivedType()}) {
|
||||
std::size_t elements{Elements()};
|
||||
std::size_t elementBytes{ElementBytes()};
|
||||
for (std::size_t j{0}; j < elements; ++j) {
|
||||
dt->Destroy(data + j * elementBytes, finalize);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Descriptor::Check() const {
|
||||
// TODO
|
||||
}
|
||||
|
||||
std::ostream &Descriptor::Dump(std::ostream &o) const {
|
||||
o << "Descriptor @ 0x" << std::hex << reinterpret_cast<std::intptr_t>(this)
|
||||
<< std::dec << ":\n";
|
||||
o << " base_addr 0x" << std::hex
|
||||
<< reinterpret_cast<std::intptr_t>(raw_.base_addr) << std::dec << '\n';
|
||||
o << " elem_len " << raw_.elem_len << '\n';
|
||||
o << " version " << raw_.version
|
||||
<< (raw_.version == CFI_VERSION ? "(ok)" : "BAD!") << '\n';
|
||||
o << " rank " << static_cast<int>(raw_.rank) << '\n';
|
||||
o << " type " << static_cast<int>(raw_.type) << '\n';
|
||||
o << " attribute " << static_cast<int>(raw_.attribute) << '\n';
|
||||
o << " addendum? " << static_cast<bool>(raw_.f18Addendum) << '\n';
|
||||
for (int j{0}; j < raw_.rank; ++j) {
|
||||
o << " dim[" << j << "] lower_bound " << raw_.dim[j].lower_bound << '\n';
|
||||
o << " extent " << raw_.dim[j].extent << '\n';
|
||||
o << " sm " << raw_.dim[j].sm << '\n';
|
||||
}
|
||||
if (const DescriptorAddendum * addendum{Addendum()}) {
|
||||
addendum->Dump(o);
|
||||
}
|
||||
return o;
|
||||
}
|
||||
|
||||
std::size_t DescriptorAddendum::SizeInBytes() const {
|
||||
return SizeInBytes(LenParameters());
|
||||
}
|
||||
|
||||
std::ostream &DescriptorAddendum::Dump(std::ostream &o) const {
|
||||
o << " derivedType @ 0x" << std::hex
|
||||
<< reinterpret_cast<std::intptr_t>(derivedType_) << std::dec << '\n';
|
||||
o << " flags " << flags_ << '\n';
|
||||
// TODO: LEN parameter values
|
||||
return o;
|
||||
}
|
||||
} // namespace Fortran::runtime
|
||||
|
|
|
@ -31,6 +31,8 @@
|
|||
#include <cinttypes>
|
||||
#include <cstddef>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <ostream>
|
||||
|
||||
namespace Fortran::runtime {
|
||||
|
||||
|
@ -63,11 +65,8 @@ public:
|
|||
enum Flags {
|
||||
StaticDescriptor = 0x001,
|
||||
ImplicitAllocatable = 0x002, // compiler-created allocatable
|
||||
Created = 0x004, // allocated by Descriptor::Create()
|
||||
DoNotFinalize = 0x008, // compiler temporary
|
||||
Target = 0x010, // TARGET attribute
|
||||
AllContiguous = 0x020, // all array elements are contiguous
|
||||
LeadingDimensionContiguous = 0x040, // only leading dimension contiguous
|
||||
DoNotFinalize = 0x004, // compiler temporary
|
||||
Target = 0x008, // TARGET attribute
|
||||
};
|
||||
|
||||
explicit DescriptorAddendum(
|
||||
|
@ -100,6 +99,8 @@ public:
|
|||
len_[which] = x;
|
||||
}
|
||||
|
||||
std::ostream &Dump(std::ostream &) const;
|
||||
|
||||
private:
|
||||
const DerivedType *derivedType_{nullptr};
|
||||
std::uint64_t flags_{0};
|
||||
|
@ -116,13 +117,20 @@ public:
|
|||
// Be advised: this class type is not suitable for use when allocating
|
||||
// a descriptor -- it is a dynamic view of the common descriptor format.
|
||||
// If used in a simple declaration of a local variable or dynamic allocation,
|
||||
// the size is going to be wrong, since the true size of a descriptor
|
||||
// depends on the number of its dimensions and the presence of an addendum.
|
||||
// the size is going to be correct only by accident, since the true size of
|
||||
// a descriptor depends on the number of its dimensions and the presence and
|
||||
// size of an addendum, which depends on the type of the data.
|
||||
// Use the class template StaticDescriptor (below) to declare a descriptor
|
||||
// whose type and rank are fixed and known at compilation time. Use the
|
||||
// Create() static member functions otherwise to dynamically allocate a
|
||||
// descriptor.
|
||||
Descriptor() = delete;
|
||||
|
||||
Descriptor() {
|
||||
// Minimal initialization to prevent the destructor from running amuck
|
||||
// later if the descriptor is never established.
|
||||
raw_.base_addr = nullptr;
|
||||
raw_.f18Addendum = false;
|
||||
}
|
||||
|
||||
~Descriptor();
|
||||
|
||||
|
@ -138,20 +146,18 @@ public:
|
|||
const SubscriptValue *extent = nullptr,
|
||||
ISO::CFI_attribute_t attribute = CFI_attribute_other);
|
||||
|
||||
static Descriptor *Create(TypeCode t, std::size_t elementBytes,
|
||||
static std::unique_ptr<Descriptor> Create(TypeCode t,
|
||||
std::size_t elementBytes, void *p = nullptr, int rank = maxRank,
|
||||
const SubscriptValue *extent = nullptr,
|
||||
ISO::CFI_attribute_t attribute = CFI_attribute_other);
|
||||
static std::unique_ptr<Descriptor> Create(TypeCategory, int kind,
|
||||
void *p = nullptr, int rank = maxRank,
|
||||
const SubscriptValue *extent = nullptr,
|
||||
ISO::CFI_attribute_t attribute = CFI_attribute_other);
|
||||
static Descriptor *Create(TypeCategory, int kind, void *p = nullptr,
|
||||
int rank = maxRank, const SubscriptValue *extent = nullptr,
|
||||
static std::unique_ptr<Descriptor> Create(const DerivedType &dt,
|
||||
void *p = nullptr, int rank = maxRank,
|
||||
const SubscriptValue *extent = nullptr,
|
||||
ISO::CFI_attribute_t attribute = CFI_attribute_other);
|
||||
static Descriptor *Create(const DerivedType &dt, void *p = nullptr,
|
||||
int rank = maxRank, const SubscriptValue *extent = nullptr,
|
||||
ISO::CFI_attribute_t attribute = CFI_attribute_other);
|
||||
|
||||
// Descriptor instances allocated via Create() above must be deallocated
|
||||
// by calling Destroy().
|
||||
void Destroy();
|
||||
|
||||
ISO::CFI_cdesc_t &raw() { return raw_; }
|
||||
const ISO::CFI_cdesc_t &raw() const { return raw_; }
|
||||
|
@ -168,6 +174,7 @@ public:
|
|||
bool IsAllocatable() const {
|
||||
return raw_.attribute == CFI_attribute_allocatable;
|
||||
}
|
||||
bool IsAllocated() const { return raw_.base_addr != nullptr; }
|
||||
|
||||
Dimension &GetDimension(int dim) {
|
||||
return *reinterpret_cast<Dimension *>(&raw_.dim[dim]);
|
||||
|
@ -247,20 +254,29 @@ public:
|
|||
|
||||
std::size_t Elements() const;
|
||||
|
||||
bool IsContiguous() const {
|
||||
if (raw_.attribute == CFI_attribute_allocatable) {
|
||||
return true;
|
||||
int Allocate(const SubscriptValue lb[], const SubscriptValue ub[],
|
||||
std::size_t charLen = 0); // TODO: SOURCE= and MOLD=
|
||||
int Deallocate(bool finalize = true);
|
||||
void Destroy(char *data, bool finalize = true) const;
|
||||
|
||||
bool IsContiguous(int leadingDimensions = maxRank) const {
|
||||
auto bytes{static_cast<SubscriptValue>(ElementBytes())};
|
||||
for (int j{0}; j < leadingDimensions && j < raw_.rank; ++j) {
|
||||
const Dimension &dim{GetDimension(j)};
|
||||
if (bytes != dim.ByteStride()) {
|
||||
return false;
|
||||
}
|
||||
bytes *= dim.Extent();
|
||||
}
|
||||
if (const DescriptorAddendum * addendum{Addendum()}) {
|
||||
return (addendum->flags() & DescriptorAddendum::AllContiguous) != 0;
|
||||
}
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void Check() const;
|
||||
|
||||
// TODO: creation of array sections
|
||||
|
||||
std::ostream &Dump(std::ostream &) const;
|
||||
|
||||
private:
|
||||
ISO::CFI_cdesc_t raw_;
|
||||
};
|
||||
|
@ -284,6 +300,10 @@ public:
|
|||
static constexpr std::size_t byteSize{
|
||||
Descriptor::SizeInBytes(maxRank, hasAddendum, maxLengthTypeParameters)};
|
||||
|
||||
StaticDescriptor() { new (storage_) Descriptor{}; }
|
||||
|
||||
~StaticDescriptor() { descriptor().~Descriptor(); }
|
||||
|
||||
Descriptor &descriptor() { return *reinterpret_cast<Descriptor *>(storage_); }
|
||||
const Descriptor &descriptor() const {
|
||||
return *reinterpret_cast<const Descriptor *>(storage_);
|
||||
|
|
|
@ -12,13 +12,13 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "descriptor.h"
|
||||
#include "transformational.h"
|
||||
#include "../lib/common/idioms.h"
|
||||
#include "../lib/evaluate/integer.h"
|
||||
#include <algorithm>
|
||||
#include <bitset>
|
||||
#include <cinttypes>
|
||||
#include <cstdlib>
|
||||
#include <memory>
|
||||
|
||||
namespace Fortran::runtime {
|
||||
|
||||
|
@ -39,8 +39,8 @@ static inline std::int64_t GetInt64(const char *p, std::size_t bytes) {
|
|||
}
|
||||
|
||||
// F2018 16.9.163
|
||||
Descriptor *RESHAPE(const Descriptor &source, const Descriptor &shape,
|
||||
const Descriptor *pad, const Descriptor *order) {
|
||||
std::unique_ptr<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());
|
||||
|
@ -48,11 +48,13 @@ Descriptor *RESHAPE(const Descriptor &source, const Descriptor &shape,
|
|||
CHECK(resultRank >= 0 && resultRank <= static_cast<SubscriptValue>(maxRank));
|
||||
|
||||
// Extract and check the shape of the result; compute its element count.
|
||||
SubscriptValue lowerBound[maxRank]; // all 1's
|
||||
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) {
|
||||
lowerBound[j] = 1;
|
||||
resultExtent[j] =
|
||||
GetInt64(shape.Element<char>(&shapeSubscript), shapeElementBytes);
|
||||
CHECK(resultExtent[j] >= 0);
|
||||
|
@ -61,11 +63,12 @@ Descriptor *RESHAPE(const Descriptor &source, const Descriptor &shape,
|
|||
|
||||
// Check that there are sufficient elements in the SOURCE=, or that
|
||||
// the optional PAD= argument is present and nonempty.
|
||||
std::size_t elementBytes{source.ElementBytes()};
|
||||
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());
|
||||
CHECK(pad->ElementBytes() == elementBytes);
|
||||
}
|
||||
|
||||
// Extract and check the optional ORDER= argument, which must be a
|
||||
|
@ -89,28 +92,22 @@ Descriptor *RESHAPE(const Descriptor &source, const Descriptor &shape,
|
|||
}
|
||||
}
|
||||
|
||||
// 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};
|
||||
std::unique_ptr<Descriptor> result;
|
||||
if (sourceDerivedType != nullptr) {
|
||||
result =
|
||||
Descriptor::Create(*sourceDerivedType, data, resultRank, resultExtent);
|
||||
result = Descriptor::Create(*sourceDerivedType, nullptr, resultRank,
|
||||
resultExtent, CFI_attribute_allocatable);
|
||||
} else {
|
||||
result = Descriptor::Create(
|
||||
source.type(), elementBytes, data, resultRank, resultExtent);
|
||||
result = Descriptor::Create(source.type(), elementBytes, nullptr,
|
||||
resultRank, resultExtent,
|
||||
CFI_attribute_allocatable); // TODO rearrange these arguments
|
||||
}
|
||||
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) {
|
||||
|
@ -118,6 +115,11 @@ Descriptor *RESHAPE(const Descriptor &source, const Descriptor &shape,
|
|||
j, sourceAddendum->LenParameterValue(j));
|
||||
}
|
||||
}
|
||||
// Allocate storage for the result's data.
|
||||
int status{result->Allocate(lowerBound, resultExtent, elementBytes)};
|
||||
if (status != CFI_SUCCESS) {
|
||||
common::die("RESHAPE: Allocate failed (error %d)", status);
|
||||
}
|
||||
|
||||
// Populate the result's elements.
|
||||
SubscriptValue resultSubscript[maxRank];
|
||||
|
|
|
@ -16,11 +16,13 @@
|
|||
#define FORTRAN_RUNTIME_TRANSFORMATIONAL_H_
|
||||
|
||||
#include "descriptor.h"
|
||||
#include <memory>
|
||||
|
||||
namespace Fortran::runtime {
|
||||
|
||||
Descriptor *RESHAPE(const Descriptor &source, const Descriptor &shape,
|
||||
const Descriptor *pad = nullptr, const Descriptor *order = nullptr);
|
||||
std::unique_ptr<Descriptor> RESHAPE(const Descriptor &source,
|
||||
const Descriptor &shape, const Descriptor *pad = nullptr,
|
||||
const Descriptor *order = nullptr);
|
||||
|
||||
} // namespace Fortran::runtime
|
||||
#endif // FORTRAN_RUNTIME_TRANSFORMATIONAL_H_
|
||||
|
|
|
@ -21,44 +21,56 @@ 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 ones[]{1, 1, 1};
|
||||
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)};
|
||||
std::unique_ptr<Descriptor> source{
|
||||
Descriptor::Create(TypeCategory::Integer, sizeof(std::int32_t), nullptr,
|
||||
3, sourceExtent, CFI_attribute_allocatable)};
|
||||
source->Check();
|
||||
MATCH(3, source->rank());
|
||||
MATCH(sizeof(std::int32_t), source->ElementBytes());
|
||||
TEST(source->IsAllocatable());
|
||||
TEST(!source->IsPointer());
|
||||
TEST(source->Allocate(ones, sourceExtent, sizeof(std::int32_t)) ==
|
||||
CFI_SUCCESS);
|
||||
TEST(source->IsAllocated());
|
||||
MATCH(2, source->GetDimension(0).Extent());
|
||||
MATCH(3, source->GetDimension(1).Extent());
|
||||
MATCH(4, source->GetDimension(2).Extent());
|
||||
MATCH(24, source->Elements());
|
||||
for (std::size_t j{0}; j < 24; ++j) {
|
||||
*source->Element<std::int32_t>(j * sizeof(std::int32_t)) = j;
|
||||
}
|
||||
|
||||
static const std::int16_t shapeData[]{8, 4};
|
||||
static const SubscriptValue shapeExtent{2};
|
||||
Descriptor *shape{Descriptor::Create(TypeCategory::Integer,
|
||||
std::unique_ptr<Descriptor> shape{Descriptor::Create(TypeCategory::Integer,
|
||||
static_cast<int>(sizeof shapeData[0]),
|
||||
const_cast<void *>(reinterpret_cast<const void *>(shapeData)), 1,
|
||||
&shapeExtent)};
|
||||
&shapeExtent, CFI_attribute_pointer)};
|
||||
shape->Check();
|
||||
MATCH(1, shape->rank());
|
||||
MATCH(2, shape->GetDimension(0).Extent());
|
||||
TEST(shape->IsPointer());
|
||||
TEST(!shape->IsAllocatable());
|
||||
|
||||
StaticDescriptor<3> padDescriptor;
|
||||
Descriptor &pad{padDescriptor.descriptor()};
|
||||
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);
|
||||
pad.Establish(TypeCategory::Integer, static_cast<int>(sizeof padData[0]),
|
||||
const_cast<void *>(reinterpret_cast<const void *>(padData)), 3, padExtent,
|
||||
CFI_attribute_pointer);
|
||||
padDescriptor.Check();
|
||||
pad.Check();
|
||||
MATCH(3, pad.rank());
|
||||
MATCH(2, pad.GetDimension(0).Extent());
|
||||
MATCH(2, pad.GetDimension(1).Extent());
|
||||
MATCH(3, pad.GetDimension(2).Extent());
|
||||
|
||||
Descriptor *result{RESHAPE(*source, *shape, &padDescriptor.descriptor())};
|
||||
std::unique_ptr<Descriptor> result{RESHAPE(*source, *shape, &pad)};
|
||||
|
||||
TEST(result != nullptr);
|
||||
TEST(result.get() != nullptr);
|
||||
result->Check();
|
||||
MATCH(sizeof(std::int32_t), result->ElementBytes());
|
||||
MATCH(2, result->rank());
|
||||
|
@ -73,12 +85,5 @@ int main() {
|
|||
|
||||
// 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 a new issue