2018-05-17 01:22:33 +08:00
|
|
|
// 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_DESCRIPTOR_H_
|
|
|
|
#define FORTRAN_RUNTIME_DESCRIPTOR_H_
|
|
|
|
|
|
|
|
// Defines data structures used during execution of a Fortran program
|
2018-05-18 02:32:23 +08:00
|
|
|
// to implement nontrivial dummy arguments, pointers, allocatables,
|
|
|
|
// function results, and the special behaviors of instances of derived types.
|
2018-05-17 01:22:33 +08:00
|
|
|
// This header file includes and extends the published language
|
|
|
|
// interoperability header that is required by the Fortran 2018 standard
|
|
|
|
// as a subset of definitions suitable for exposure to user C/C++ code.
|
2018-05-18 02:32:23 +08:00
|
|
|
// User C code is welcome to depend on that ISO_Fortran_binding.h file,
|
|
|
|
// but should never reference this internal header.
|
2018-05-17 01:22:33 +08:00
|
|
|
|
2018-08-01 07:46:30 +08:00
|
|
|
#include "derived-type.h"
|
|
|
|
#include "type-code.h"
|
2018-05-17 01:22:33 +08:00
|
|
|
#include "../include/flang/ISO_Fortran_binding.h"
|
2018-08-01 07:46:30 +08:00
|
|
|
#include <cassert>
|
2018-05-17 01:22:33 +08:00
|
|
|
#include <cinttypes>
|
|
|
|
#include <cstddef>
|
2018-08-01 07:46:30 +08:00
|
|
|
#include <cstring>
|
2018-05-17 01:22:33 +08:00
|
|
|
|
|
|
|
namespace Fortran::runtime {
|
|
|
|
|
2018-07-27 07:07:50 +08:00
|
|
|
using SubscriptValue = ISO::CFI_index_t;
|
2018-05-17 01:22:33 +08:00
|
|
|
|
2018-08-01 07:46:30 +08:00
|
|
|
static constexpr int maxRank{CFI_MAX_RANK};
|
|
|
|
|
2018-08-02 01:55:46 +08:00
|
|
|
// A C++ view of the sole interoperable standard descriptor (ISO::CFI_cdesc_t)
|
2018-06-19 02:03:43 +08:00
|
|
|
// and its type and per-dimension information.
|
2018-05-17 01:22:33 +08:00
|
|
|
|
|
|
|
class Dimension {
|
|
|
|
public:
|
2018-07-27 07:07:50 +08:00
|
|
|
SubscriptValue LowerBound() const { return raw_.lower_bound; }
|
|
|
|
SubscriptValue Extent() const { return raw_.extent; }
|
|
|
|
SubscriptValue UpperBound() const { return LowerBound() + Extent() - 1; }
|
|
|
|
SubscriptValue ByteStride() const { return raw_.sm; }
|
2018-05-17 01:31:35 +08:00
|
|
|
|
2018-05-17 01:22:33 +08:00
|
|
|
private:
|
2018-05-18 02:32:23 +08:00
|
|
|
ISO::CFI_dim_t raw_;
|
2018-05-17 01:22:33 +08:00
|
|
|
};
|
|
|
|
|
2018-07-27 07:07:50 +08:00
|
|
|
// The storage for this object follows the last used dim[] entry in a
|
2018-08-01 07:46:30 +08:00
|
|
|
// Descriptor (CFI_cdesc_t) generic descriptor. Space matters here, since
|
|
|
|
// descriptors serve as POINTER and ALLOCATABLE components of derived type
|
|
|
|
// instances. The presence of this structure is implied by the flag
|
2018-08-02 01:55:46 +08:00
|
|
|
// (CFI_cdesc_t.extra & ADDENDUM) != 0, and the number of elements in
|
2018-08-01 07:46:30 +08:00
|
|
|
// the len_[] array is determined by DerivedType::lenParameters().
|
2018-07-27 07:07:50 +08:00
|
|
|
class DescriptorAddendum {
|
2018-05-17 01:22:33 +08:00
|
|
|
public:
|
2018-08-02 01:55:46 +08:00
|
|
|
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
|
|
|
|
};
|
2018-07-27 07:07:50 +08:00
|
|
|
|
2018-08-02 01:55:46 +08:00
|
|
|
explicit DescriptorAddendum(const DerivedType &dt, std::uint64_t flags = 0)
|
|
|
|
: derivedType_{&dt}, flags_{flags} {}
|
2018-05-17 01:22:33 +08:00
|
|
|
|
2018-08-02 01:55:46 +08:00
|
|
|
const DerivedType *derivedType() const { return derivedType_; }
|
2018-08-01 07:46:30 +08:00
|
|
|
DescriptorAddendum &set_derivedType(const DerivedType &dt) {
|
|
|
|
derivedType_ = &dt;
|
|
|
|
return *this;
|
2018-07-27 07:07:50 +08:00
|
|
|
}
|
2018-08-02 01:55:46 +08:00
|
|
|
std::uint64_t &flags() { return flags_; }
|
|
|
|
const std::uint64_t &flags() const { return flags_; }
|
2018-05-17 01:22:33 +08:00
|
|
|
|
2018-07-27 07:07:50 +08:00
|
|
|
TypeParameterValue LenParameterValue(int which) const { return len_[which]; }
|
|
|
|
static constexpr std::size_t SizeInBytes(int lenParameters) {
|
|
|
|
return sizeof(DescriptorAddendum) - sizeof(TypeParameterValue) +
|
|
|
|
lenParameters * sizeof(TypeParameterValue);
|
|
|
|
}
|
|
|
|
std::size_t SizeInBytes() const;
|
|
|
|
|
|
|
|
void SetLenParameterValue(int which, TypeParameterValue x) {
|
|
|
|
len_[which] = x;
|
2018-05-17 01:22:33 +08:00
|
|
|
}
|
|
|
|
|
2018-07-27 07:07:50 +08:00
|
|
|
private:
|
2018-08-01 07:46:30 +08:00
|
|
|
const DerivedType *derivedType_{nullptr};
|
2018-08-02 01:55:46 +08:00
|
|
|
std::uint64_t flags_{0};
|
2018-07-27 07:07:50 +08:00
|
|
|
TypeParameterValue len_[1]; // must be the last component
|
|
|
|
// The LEN type parameter values can also include captured values of
|
|
|
|
// specification expressions that were used for bounds and for LEN type
|
|
|
|
// parameters of components. The values have been truncated to the LEN
|
|
|
|
// type parameter's type, if shorter than 64 bits, then sign-extended.
|
|
|
|
};
|
|
|
|
|
2018-07-28 07:52:17 +08:00
|
|
|
// A C++ view of a standard descriptor object.
|
|
|
|
class Descriptor {
|
2018-07-27 07:07:50 +08:00
|
|
|
public:
|
2018-08-01 07:46:30 +08:00
|
|
|
// 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
|
2018-08-02 01:55:46 +08:00
|
|
|
// depends on the number of its dimensions and the presence of an addendum.
|
|
|
|
// 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.
|
2018-08-01 07:46:30 +08:00
|
|
|
Descriptor() = delete;
|
|
|
|
|
|
|
|
~Descriptor();
|
|
|
|
|
|
|
|
int Establish(TypeCode t, std::size_t elementBytes, void *p = nullptr,
|
2018-08-02 01:55:46 +08:00
|
|
|
int rank = maxRank, const SubscriptValue *extent = nullptr,
|
|
|
|
ISO::CFI_attribute_t attribute = CFI_attribute_other,
|
|
|
|
bool addendum = false);
|
2018-08-02 00:45:59 +08:00
|
|
|
int Establish(TypeCategory, int kind, void *p = nullptr, int rank = maxRank,
|
2018-08-02 01:55:46 +08:00
|
|
|
const SubscriptValue *extent = nullptr,
|
|
|
|
ISO::CFI_attribute_t attribute = CFI_attribute_other,
|
|
|
|
bool addendum = false);
|
2018-08-01 07:46:30 +08:00
|
|
|
int Establish(const DerivedType &dt, void *p = nullptr, int rank = maxRank,
|
2018-08-02 01:55:46 +08:00
|
|
|
const SubscriptValue *extent = nullptr,
|
|
|
|
ISO::CFI_attribute_t attribute = CFI_attribute_other);
|
2018-07-28 07:52:17 +08:00
|
|
|
|
|
|
|
static Descriptor *Create(TypeCode t, std::size_t elementBytes,
|
2018-08-01 07:46:30 +08:00
|
|
|
void *p = nullptr, int rank = maxRank,
|
2018-08-02 01:55:46 +08:00
|
|
|
const SubscriptValue *extent = nullptr,
|
|
|
|
ISO::CFI_attribute_t attribute = CFI_attribute_other);
|
2018-08-02 00:45:59 +08:00
|
|
|
static Descriptor *Create(TypeCategory, int kind, void *p = nullptr,
|
2018-08-02 01:55:46 +08:00
|
|
|
int rank = maxRank, const SubscriptValue *extent = nullptr,
|
|
|
|
ISO::CFI_attribute_t attribute = CFI_attribute_other);
|
2018-08-01 07:46:30 +08:00
|
|
|
static Descriptor *Create(const DerivedType &dt, void *p = nullptr,
|
2018-08-02 01:55:46 +08:00
|
|
|
int rank = maxRank, const SubscriptValue *extent = nullptr,
|
|
|
|
ISO::CFI_attribute_t attribute = CFI_attribute_other);
|
2018-08-01 07:46:30 +08:00
|
|
|
|
|
|
|
// Descriptor instances allocated via Create() above must be deallocated
|
|
|
|
// by calling Destroy() so that operator delete[] is invoked.
|
2018-07-28 07:52:17 +08:00
|
|
|
void Destroy();
|
2018-07-27 07:07:50 +08:00
|
|
|
|
|
|
|
ISO::CFI_cdesc_t &raw() { return raw_; }
|
|
|
|
const ISO::CFI_cdesc_t &raw() const { return raw_; }
|
2018-05-17 01:22:33 +08:00
|
|
|
std::size_t ElementBytes() const { return raw_.elem_len; }
|
|
|
|
int rank() const { return raw_.rank; }
|
|
|
|
TypeCode type() const { return TypeCode{raw_.type}; }
|
|
|
|
|
2018-07-28 07:52:17 +08:00
|
|
|
Descriptor &set_base_addr(void *p) {
|
2018-07-27 07:07:50 +08:00
|
|
|
raw_.base_addr = p;
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2018-08-02 01:55:46 +08:00
|
|
|
bool IsPointer() const { return raw_.attribute == CFI_attribute_pointer; }
|
2018-05-17 01:22:33 +08:00
|
|
|
bool IsAllocatable() const {
|
2018-08-02 01:55:46 +08:00
|
|
|
return raw_.attribute == CFI_attribute_allocatable;
|
2018-05-17 01:22:33 +08:00
|
|
|
}
|
|
|
|
|
2018-05-18 02:32:23 +08:00
|
|
|
Dimension &GetDimension(int dim) {
|
|
|
|
return *reinterpret_cast<Dimension *>(&raw_.dim[dim]);
|
|
|
|
}
|
2018-05-17 01:22:33 +08:00
|
|
|
const Dimension &GetDimension(int dim) const {
|
|
|
|
return *reinterpret_cast<const Dimension *>(&raw_.dim[dim]);
|
|
|
|
}
|
|
|
|
|
2018-07-27 07:07:50 +08:00
|
|
|
std::size_t SubscriptByteOffset(
|
|
|
|
int dim, SubscriptValue subscriptValue) const {
|
|
|
|
const Dimension &dimension{GetDimension(dim)};
|
|
|
|
return (subscriptValue - dimension.LowerBound()) * dimension.ByteStride();
|
|
|
|
}
|
|
|
|
|
2018-05-18 02:32:23 +08:00
|
|
|
DescriptorAddendum *Addendum() {
|
2018-08-02 01:55:46 +08:00
|
|
|
if (raw_.f18Addendum != 0) {
|
2018-05-18 02:32:23 +08:00
|
|
|
return reinterpret_cast<DescriptorAddendum *>(&GetDimension(rank()));
|
|
|
|
} else {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
const DescriptorAddendum *Addendum() const {
|
2018-08-02 01:55:46 +08:00
|
|
|
if (raw_.f18Addendum != 0) {
|
2018-05-17 01:31:35 +08:00
|
|
|
return reinterpret_cast<const DescriptorAddendum *>(
|
|
|
|
&GetDimension(rank()));
|
2018-05-17 01:22:33 +08:00
|
|
|
} else {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-27 07:07:50 +08:00
|
|
|
static constexpr std::size_t SizeInBytes(
|
2018-08-02 01:55:46 +08:00
|
|
|
int rank, bool addendum = false, int lengthTypeParameters = 0) {
|
2018-07-28 07:52:17 +08:00
|
|
|
std::size_t bytes{sizeof(Descriptor) - sizeof(Dimension)};
|
2018-07-27 07:07:50 +08:00
|
|
|
bytes += rank * sizeof(Dimension);
|
2018-08-02 01:55:46 +08:00
|
|
|
if (addendum || lengthTypeParameters > 0) {
|
2018-07-27 07:07:50 +08:00
|
|
|
bytes += DescriptorAddendum::SizeInBytes(lengthTypeParameters);
|
|
|
|
}
|
|
|
|
return bytes;
|
|
|
|
}
|
2018-05-17 01:22:33 +08:00
|
|
|
std::size_t SizeInBytes() const;
|
|
|
|
|
2018-07-27 07:07:50 +08:00
|
|
|
void Check() const;
|
|
|
|
|
2018-08-01 07:46:30 +08:00
|
|
|
// TODO: creation of array sections
|
2018-07-27 07:07:50 +08:00
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2018-05-17 01:22:33 +08:00
|
|
|
private:
|
2018-05-18 02:32:23 +08:00
|
|
|
ISO::CFI_cdesc_t raw_;
|
2018-05-17 01:22:33 +08:00
|
|
|
};
|
2018-07-28 07:52:17 +08:00
|
|
|
static_assert(sizeof(Descriptor) == sizeof(ISO::CFI_cdesc_t));
|
2018-05-17 01:22:33 +08:00
|
|
|
|
2018-08-01 07:46:30 +08:00
|
|
|
// Properly configured instances of StaticDescriptor will occupy the
|
|
|
|
// exact amount of storage required for the descriptor based on its
|
|
|
|
// number of dimensions and whether it requires an addendum. To build
|
|
|
|
// such a static descriptor, declare an instance of StaticDescriptor<>,
|
|
|
|
// extract a reference to the Descriptor via the descriptor() accessor,
|
|
|
|
// and then built a Descriptor therein via descriptor.Establish().
|
|
|
|
// e.g.:
|
2018-08-02 01:55:46 +08:00
|
|
|
// StaticDescriptor<R,A,LP> statDesc;
|
2018-08-01 07:46:30 +08:00
|
|
|
// Descriptor &descriptor{statDesc.descriptor()};
|
|
|
|
// descriptor.Establish( ... );
|
2018-08-02 01:55:46 +08:00
|
|
|
template<int MAX_RANK = maxRank, bool ADDENDUM = false, int MAX_LEN_PARMS = 0>
|
2018-07-28 07:52:17 +08:00
|
|
|
class alignas(Descriptor) StaticDescriptor {
|
2018-07-27 07:07:50 +08:00
|
|
|
public:
|
|
|
|
static constexpr int maxRank{MAX_RANK};
|
|
|
|
static constexpr int maxLengthTypeParameters{MAX_LEN_PARMS};
|
2018-08-02 01:55:46 +08:00
|
|
|
static constexpr bool hasAddendum{ADDENDUM || MAX_LEN_PARMS > 0};
|
2018-08-01 07:46:30 +08:00
|
|
|
static constexpr std::size_t byteSize{
|
|
|
|
Descriptor::SizeInBytes(maxRank, hasAddendum, maxLengthTypeParameters)};
|
2018-07-27 07:07:50 +08:00
|
|
|
|
2018-08-01 07:46:30 +08:00
|
|
|
Descriptor &descriptor() { return *reinterpret_cast<Descriptor *>(storage_); }
|
2018-07-28 07:52:17 +08:00
|
|
|
const Descriptor &descriptor() const {
|
2018-08-01 07:46:30 +08:00
|
|
|
return *reinterpret_cast<const Descriptor *>(storage_);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Check() {
|
|
|
|
assert(descriptor().SizeInBytes() <= byteSize);
|
|
|
|
assert(descriptor().rank() <= maxRank);
|
|
|
|
if (DescriptorAddendum * addendum{descriptor().Addendum()}) {
|
|
|
|
if (const DerivedType * dt{addendum->derivedType()}) {
|
|
|
|
assert(dt->lenParameters() <= maxLengthTypeParameters);
|
|
|
|
} else {
|
|
|
|
assert(maxLengthTypeParameters == 0);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
assert(!hasAddendum);
|
|
|
|
assert(maxLengthTypeParameters == 0);
|
|
|
|
}
|
2018-05-17 01:22:33 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
2018-07-27 07:07:50 +08:00
|
|
|
char storage_[byteSize];
|
2018-05-17 01:22:33 +08:00
|
|
|
};
|
|
|
|
} // namespace Fortran::runtime
|
2018-05-17 05:25:45 +08:00
|
|
|
#endif // FORTRAN_RUNTIME_DESCRIPTOR_H_
|