[flang] Implement STORAGE_SIZE(), SIZEOF(), C_SIZEOF()

STORAGE_SIZE() is a standard inquiry intrinsic (size in bits
of an array element of the same type as the argument); SIZEOF()
is a common extension that returns the size in bytes of its
argument; C_SIZEOF() is a renaming of SIZEOF() in module ISO_C_BINDING.

STORAGE_SIZE() and SIZEOF() are implemented via rewrites to
expressions; these expressions will be constant when the necessary
type parameters and bounds are also constant.

Code to calculate the sizes of types (with and without alignment)
was isolated into Evaluate/type.* and /characteristics.*.
Code in Semantics/compute-offsets.* to calculate sizes and alignments
of derived types' scopes was exposed so that it can be called at type
instantiation time (earlier than before) so that these inquiry intrinsics
could be called from specification expressions.

Differential Revision: https://reviews.llvm.org/D93322
This commit is contained in:
peter klausler 2020-12-15 11:06:44 -08:00
parent 0f903015c7
commit 6aa3591e98
22 changed files with 165 additions and 163 deletions

View File

@ -129,7 +129,7 @@ accepted if enabled by command-line options.
* A `RETURN` statement may appear in a main program.
* DATA statement initialization is allowed for procedure pointers outside
structure constructors.
* Nonstandard intrinsic functions: ISNAN
* Nonstandard intrinsic functions: ISNAN, SIZEOF
### Extensions supported when enabled by options
@ -144,10 +144,11 @@ accepted if enabled by command-line options.
rule imposes an artificially small constraint in some cases
where Fortran mandates that something have the default `INTEGER`
type: specifically, the results of references to the intrinsic functions
`SIZE`, `LBOUND`, `UBOUND`, `SHAPE`, and the location reductions
`SIZE`, `STORAGE_SIZE`,`LBOUND`, `UBOUND`, `SHAPE`, and the location reductions
`FINDLOC`, `MAXLOC`, and `MINLOC` in the absence of an explicit
`KIND=` actual argument. We return `INTEGER(KIND=8)` by default in
these cases when the `-flarge-sizes` option is enabled.
`SIZEOF` and `C_SIZEOF` always return `INTEGER(KIND=8)`.
* Treat each specification-part like is has `IMPLICIT NONE`
[-fimplicit-none-type-always]
* Ignore occurrences of `IMPLICIT NONE` and `IMPLICIT NONE(TYPE)`

View File

@ -149,7 +149,7 @@ public:
bool isElemental = false, bool thisIsDeferredShape = false,
bool thatIsDeferredShape = false) const;
std::optional<Expr<SubscriptInteger>> MeasureSizeInBytes(
FoldingContext * = nullptr) const;
FoldingContext &) const;
llvm::raw_ostream &Dump(llvm::raw_ostream &) const;

View File

@ -235,6 +235,7 @@ public:
Rounding rounding() const { return rounding_; }
bool flushSubnormalsToZero() const { return flushSubnormalsToZero_; }
bool bigEndian() const { return bigEndian_; }
std::size_t maxAlignment() const { return maxAlignment_; }
const semantics::DerivedTypeSpec *pdtInstance() const { return pdtInstance_; }
const IntrinsicProcTable &intrinsics() const { return intrinsics_; }
@ -257,7 +258,8 @@ private:
const IntrinsicProcTable &intrinsics_;
Rounding rounding_{defaultRounding};
bool flushSubnormalsToZero_{false};
bool bigEndian_{false};
static constexpr bool bigEndian_{false}; // TODO: configure for target
static constexpr std::size_t maxAlignment_{8}; // TODO: configure for target
const semantics::DerivedTypeSpec *pdtInstance_{nullptr};
std::map<parser::CharBlock, ConstantSubscript> impliedDos_;
};

View File

@ -33,16 +33,17 @@ public:
std::size_t size() const { return data_.size(); }
template <typename A> Result Add(ConstantSubscript, std::size_t, const A &) {
template <typename A>
Result Add(ConstantSubscript, std::size_t, const A &, FoldingContext &) {
return NotAConstant;
}
template <typename T>
Result Add(
ConstantSubscript offset, std::size_t bytes, const Constant<T> &x) {
Result Add(ConstantSubscript offset, std::size_t bytes, const Constant<T> &x,
FoldingContext &context) {
if (offset < 0 || offset + bytes > data_.size()) {
return OutOfRange;
} else {
auto elementBytes{ToInt64(x.GetType().MeasureSizeInBytes())};
auto elementBytes{ToInt64(x.GetType().MeasureSizeInBytes(context, true))};
if (!elementBytes ||
bytes !=
x.values().size() * static_cast<std::size_t>(*elementBytes)) {
@ -55,7 +56,8 @@ public:
}
template <int KIND>
Result Add(ConstantSubscript offset, std::size_t bytes,
const Constant<Type<TypeCategory::Character, KIND>> &x) {
const Constant<Type<TypeCategory::Character, KIND>> &x,
FoldingContext &) {
if (offset < 0 || offset + bytes > data_.size()) {
return OutOfRange;
} else {
@ -80,11 +82,13 @@ public:
}
}
}
Result Add(ConstantSubscript, std::size_t, const Constant<SomeDerived> &);
Result Add(ConstantSubscript, std::size_t, const Constant<SomeDerived> &,
FoldingContext &);
template <typename T>
Result Add(ConstantSubscript offset, std::size_t bytes, const Expr<T> &x) {
Result Add(ConstantSubscript offset, std::size_t bytes, const Expr<T> &x,
FoldingContext &c) {
return std::visit(
[&](const auto &y) { return Add(offset, bytes, y); }, x.u);
[&](const auto &y) { return Add(offset, bytes, y, c); }, x.u);
}
void AddPointer(ConstantSubscript, const Expr<SomeType> &);

View File

@ -141,8 +141,10 @@ public:
return charLength_;
}
std::optional<Expr<SubscriptInteger>> GetCharLength() const;
std::size_t GetAlignment(const FoldingContext &) const;
std::optional<Expr<SubscriptInteger>> MeasureSizeInBytes(
FoldingContext * = nullptr) const;
FoldingContext &, bool aligned) const;
std::string AsFortran() const;
std::string AsFortran(std::string &&charLenExpr) const;

View File

@ -167,17 +167,17 @@ bool TypeAndShape::IsCompatibleWith(parser::ContextualMessages &messages,
}
std::optional<Expr<SubscriptInteger>> TypeAndShape::MeasureSizeInBytes(
FoldingContext *foldingContext) const {
if (type_.category() == TypeCategory::Character && LEN_) {
Expr<SubscriptInteger> result{
common::Clone(*LEN_) * Expr<SubscriptInteger>{type_.kind()}};
if (foldingContext) {
result = Fold(*foldingContext, std::move(result));
FoldingContext &foldingContext) const {
if (auto elements{GetSize(Shape{shape_})}) {
// Sizes of arrays (even with single elements) are multiples of
// their alignments.
if (auto elementBytes{
type_.MeasureSizeInBytes(foldingContext, GetRank(shape_) > 0)}) {
return Fold(
foldingContext, std::move(*elements) * std::move(*elementBytes));
}
return result;
} else {
return type_.MeasureSizeInBytes(foldingContext);
}
return std::nullopt;
}
void TypeAndShape::AcquireShape(

View File

@ -27,8 +27,9 @@ std::optional<OffsetSymbol> DesignatorFolder::FoldDesignator(
} else if (symbol.has<semantics::ObjectEntityDetails>() &&
!IsNamedConstant(symbol)) {
if (auto type{DynamicType::From(symbol)}) {
if (auto bytes{ToInt64(type->MeasureSizeInBytes(&context_))}) {
if (auto extents{GetConstantExtents(context_, symbol)}) {
if (auto extents{GetConstantExtents(context_, symbol)}) {
if (auto bytes{ToInt64(
type->MeasureSizeInBytes(context_, GetRank(*extents) > 0))}) {
OffsetSymbol result{symbol, static_cast<std::size_t>(*bytes)};
auto stride{*bytes};
for (auto extent : *extents) {
@ -57,8 +58,8 @@ std::optional<OffsetSymbol> DesignatorFolder::FoldDesignator(
const ArrayRef &x, ConstantSubscript which) {
const Symbol &array{x.base().GetLastSymbol()};
if (auto type{DynamicType::From(array)}) {
if (auto bytes{ToInt64(type->MeasureSizeInBytes(&context_))}) {
if (auto extents{GetConstantExtents(context_, array)}) {
if (auto extents{GetConstantExtents(context_, array)}) {
if (auto bytes{ToInt64(type->MeasureSizeInBytes(context_, true))}) {
Shape lbs{GetLowerBounds(context_, x.base())};
if (auto lowerBounds{AsConstantExtents(context_, lbs)}) {
std::optional<OffsetSymbol> result;
@ -217,7 +218,7 @@ static std::optional<ArrayRef> OffsetToArrayRef(FoldingContext &context,
auto extents{AsConstantExtents(context, shape)};
Shape lbs{GetLowerBounds(context, entity)};
auto lower{AsConstantExtents(context, lbs)};
auto elementBytes{ToInt64(elementType.MeasureSizeInBytes(&context))};
auto elementBytes{ToInt64(elementType.MeasureSizeInBytes(context, true))};
if (!extents || !lower || !elementBytes || *elementBytes <= 0) {
return std::nullopt;
}
@ -316,7 +317,7 @@ std::optional<Expr<SomeType>> OffsetToDesignator(FoldingContext &context,
TypedWrapper<Designator>(*type, std::move(*dataRef))}) {
if (IsAllocatableOrPointer(symbol)) {
} else if (auto elementBytes{
ToInt64(type->MeasureSizeInBytes(&context))}) {
ToInt64(type->MeasureSizeInBytes(context, true))}) {
if (auto *zExpr{std::get_if<Expr<SomeComplex>>(&result->u)}) {
if (size * 2 > static_cast<std::size_t>(*elementBytes)) {
return result;

View File

@ -587,6 +587,22 @@ Expr<Type<TypeCategory::Integer, KIND>> FoldIntrinsicFunction(
return Expr<T>{ConvertToType<T>(Fold(context, std::move(product)))};
}
}
} else if (name == "sizeof") { // in bytes; extension
if (auto info{
characteristics::TypeAndShape::Characterize(args[0], context)}) {
if (auto bytes{info->MeasureSizeInBytes(context)}) {
return Expr<T>{Fold(context, ConvertToType<T>(std::move(*bytes)))};
}
}
} else if (name == "storage_size") { // in bits
if (const auto *expr{UnwrapExpr<Expr<SomeType>>(args[0])}) {
if (auto type{expr->GetType()}) {
if (auto bytes{type->MeasureSizeInBytes(context, true)}) {
return Expr<T>{
Fold(context, Expr<T>{8} * ConvertToType<T>(std::move(*bytes)))};
}
}
}
} else if (name == "ubound") {
return UBOUND(context, std::move(funcRef));
}

View File

@ -14,7 +14,7 @@
namespace Fortran::evaluate {
auto InitialImage::Add(ConstantSubscript offset, std::size_t bytes,
const Constant<SomeDerived> &x) -> Result {
const Constant<SomeDerived> &x, FoldingContext &context) -> Result {
if (offset < 0 || offset + bytes > data_.size()) {
return OutOfRange;
} else {
@ -36,7 +36,7 @@ auto InitialImage::Add(ConstantSubscript offset, std::size_t bytes,
AddPointer(offset + component.offset(), indExpr.value());
} else {
Result added{Add(offset + component.offset(), component.size(),
indExpr.value())};
indExpr.value(), context)};
if (added != Ok) {
return Ok;
}
@ -88,7 +88,8 @@ public:
using Scalar = typename Const::Element;
std::size_t elements{TotalElementCount(extents_)};
std::vector<Scalar> typedValue(elements);
auto elemBytes{ToInt64(type_.MeasureSizeInBytes(&context_))};
auto elemBytes{
ToInt64(type_.MeasureSizeInBytes(context_, GetRank(extents_) > 0))};
CHECK(elemBytes && *elemBytes >= 0);
std::size_t stride{static_cast<std::size_t>(*elemBytes)};
CHECK(offset_ + elements * stride <= image_.data_.size());

View File

@ -685,6 +685,8 @@ static const IntrinsicInterface genericIntrinsicFunction[]{
{{"array", AnyData, Rank::anyOrAssumedRank}, OptionalDIM,
SizeDefaultKIND},
KINDInt, Rank::scalar, IntrinsicClass::inquiryFunction},
{"sizeof", {{"a", AnyData, Rank::anyOrAssumedRank}}, SubscriptInt,
Rank::scalar, IntrinsicClass::inquiryFunction},
{"spacing", {{"x", SameReal}}, SameReal},
{"spread",
{{"source", SameType, Rank::known}, RequiredDIM,
@ -742,7 +744,7 @@ static const IntrinsicInterface genericIntrinsicFunction[]{
// AND, OR, XOR, LSHIFT, RSHIFT, SHIFT, ZEXT, IZEXT,
// COMPL, EQV, NEQV, INT8, JINT, JNINT, KNINT,
// QCMPLX, DFLOAT, QEXT, QFLOAT, QREAL, DNUM,
// INUM, JNUM, KNUM, QNUM, RNUM, RAN, RANF, ILEN, SIZEOF,
// INUM, JNUM, KNUM, QNUM, RNUM, RAN, RANF, ILEN,
// MCLOCK, SECNDS, COTAN, IBCHNG, ISHA, ISHC, ISHL, IXOR
// IARG, IARGC, NARGS, NUMARG, BADDRESS, IADDR, CACHESIZE,
// EOF, FP_CLASS, INT_PTR_KIND, MALLOC

View File

@ -643,17 +643,13 @@ auto GetShapeHelper::operator()(const ProcedureRef &call) const -> Result {
if (auto sourceTypeAndShape{
characteristics::TypeAndShape::Characterize(
call.arguments().at(0), context_)}) {
auto sourceElements{
GetSize(common::Clone(sourceTypeAndShape->shape()))};
auto sourceElementBytes{
sourceTypeAndShape->MeasureSizeInBytes(&context_)};
auto sourceBytes{sourceTypeAndShape->MeasureSizeInBytes(context_)};
auto moldElementBytes{
moldTypeAndShape->MeasureSizeInBytes(&context_)};
if (sourceElements && sourceElementBytes && moldElementBytes) {
moldTypeAndShape->type().MeasureSizeInBytes(context_, true)};
if (sourceBytes && moldElementBytes) {
ExtentExpr extent{Fold(context_,
((std::move(*sourceElements) *
std::move(*sourceElementBytes)) +
common::Clone(*moldElementBytes) - ExtentExpr{1}) /
(std::move(*sourceBytes) + common::Clone(*moldElementBytes) -
ExtentExpr{1}) /
common::Clone(*moldElementBytes))};
return Shape{MaybeExtentExpr{std::move(extent)}};
}

View File

@ -111,7 +111,7 @@ std::optional<Expr<SubscriptInteger>> DynamicType::GetCharLength() const {
return std::nullopt;
}
static constexpr int RealKindBytes(int kind) {
static constexpr std::size_t RealKindBytes(int kind) {
switch (kind) {
case 3: // non-IEEE 16-bit format (truncated 32-bit)
return 2;
@ -123,8 +123,26 @@ static constexpr int RealKindBytes(int kind) {
}
}
std::size_t DynamicType::GetAlignment(const FoldingContext &context) const {
switch (category_) {
case TypeCategory::Integer:
case TypeCategory::Character:
case TypeCategory::Logical:
return std::min<std::size_t>(kind_, context.maxAlignment());
case TypeCategory::Real:
case TypeCategory::Complex:
return std::min(RealKindBytes(kind_), context.maxAlignment());
case TypeCategory::Derived:
if (derived_ && derived_->scope()) {
return derived_->scope()->alignment().value_or(1);
}
break;
}
return 1; // needs to be after switch to dodge a bogus gcc warning
}
std::optional<Expr<SubscriptInteger>> DynamicType::MeasureSizeInBytes(
FoldingContext *context) const {
FoldingContext &context, bool aligned) const {
switch (category_) {
case TypeCategory::Integer:
return Expr<SubscriptInteger>{kind_};
@ -134,20 +152,18 @@ std::optional<Expr<SubscriptInteger>> DynamicType::MeasureSizeInBytes(
return Expr<SubscriptInteger>{2 * RealKindBytes(kind_)};
case TypeCategory::Character:
if (auto len{GetCharLength()}) {
auto result{Expr<SubscriptInteger>{kind_} * std::move(*len)};
if (context) {
return Fold(*context, std::move(result));
} else {
return std::move(result);
}
return Fold(context, Expr<SubscriptInteger>{kind_} * std::move(*len));
}
break;
case TypeCategory::Logical:
return Expr<SubscriptInteger>{kind_};
case TypeCategory::Derived:
if (derived_ && derived_->scope()) {
auto size{derived_->scope()->size()};
auto align{aligned ? derived_->scope()->alignment().value_or(0) : 0};
auto alignedSize{align > 0 ? ((size + align - 1) / align) * align : size};
return Expr<SubscriptInteger>{
static_cast<common::ConstantSubscript>(derived_->scope()->size())};
static_cast<ConstantSubscript>(alignedSize)};
}
break;
}

View File

@ -24,11 +24,8 @@ namespace Fortran::semantics {
class ComputeOffsetsHelper {
public:
// TODO: configure based on target
static constexpr std::size_t maxAlignment{8};
ComputeOffsetsHelper(SemanticsContext &context) : context_{context} {}
void Compute() { Compute(context_.globalScope()); }
void Compute(Scope &);
private:
struct SizeAndAlignment {
@ -48,24 +45,18 @@ private:
const EquivalenceObject *object;
};
void Compute(Scope &);
void DoScope(Scope &);
void DoCommonBlock(Symbol &);
void DoEquivalenceBlockBase(Symbol &, SizeAndAlignment &);
void DoEquivalenceSet(const EquivalenceSet &);
SymbolAndOffset Resolve(const SymbolAndOffset &);
std::size_t ComputeOffset(const EquivalenceObject &);
void DoSymbol(Symbol &);
SizeAndAlignment GetSizeAndAlignment(const Symbol &);
SizeAndAlignment GetElementSize(const Symbol &);
std::size_t CountElements(const Symbol &);
static std::size_t Align(std::size_t, std::size_t);
static SizeAndAlignment GetIntrinsicSizeAndAlignment(TypeCategory, int);
SizeAndAlignment GetSizeAndAlignment(const Symbol &, bool entire);
std::size_t Align(std::size_t, std::size_t);
SemanticsContext &context_;
evaluate::FoldingContext &foldingContext_{context_.foldingContext()};
std::size_t offset_{0};
std::size_t alignment_{0};
std::size_t alignment_{1};
// symbol -> symbol+offset that determines its location, from EQUIVALENCE
std::map<MutableSymbolRef, SymbolAndOffset> dependents_;
// base symbol -> SizeAndAlignment for each distinct EQUIVALENCE block
@ -74,14 +65,8 @@ private:
void ComputeOffsetsHelper::Compute(Scope &scope) {
for (Scope &child : scope.children()) {
Compute(child);
ComputeOffsets(context_, child);
}
DoScope(scope);
dependents_.clear();
equivalenceBlock_.clear();
}
void ComputeOffsetsHelper::DoScope(Scope &scope) {
if (scope.symbol() && scope.IsParameterizedDerivedType()) {
return; // only process instantiations of parameterized derived types
}
@ -93,14 +78,12 @@ void ComputeOffsetsHelper::DoScope(Scope &scope) {
for (const EquivalenceSet &set : scope.equivalenceSets()) {
DoEquivalenceSet(set);
}
offset_ = 0;
alignment_ = 1;
// Compute a base symbol and overall block size for each
// disjoint EQUIVALENCE storage sequence.
for (auto &[symbol, dep] : dependents_) {
dep = Resolve(dep);
CHECK(symbol->size() == 0);
auto symInfo{GetSizeAndAlignment(*symbol)};
auto symInfo{GetSizeAndAlignment(*symbol, true)};
symbol->set_size(symInfo.size);
Symbol &base{*dep.symbol};
auto iter{equivalenceBlock_.find(base)};
@ -285,7 +268,7 @@ std::size_t ComputeOffsetsHelper::ComputeOffset(
offset *= ubound(i) - lbound(i) + 1;
}
}
auto result{offset * GetElementSize(object.symbol).size};
auto result{offset * GetSizeAndAlignment(object.symbol, false).size};
if (object.substringStart) {
int kind{context_.defaultKinds().GetDefaultKind(TypeCategory::Character)};
if (const DeclTypeSpec * type{object.symbol.GetType()}) {
@ -302,7 +285,7 @@ void ComputeOffsetsHelper::DoSymbol(Symbol &symbol) {
if (!symbol.has<ObjectEntityDetails>() && !symbol.has<ProcEntityDetails>()) {
return;
}
SizeAndAlignment s{GetSizeAndAlignment(symbol)};
SizeAndAlignment s{GetSizeAndAlignment(symbol, true)};
if (s.size == 0) {
return;
}
@ -313,101 +296,51 @@ void ComputeOffsetsHelper::DoSymbol(Symbol &symbol) {
alignment_ = std::max(alignment_, s.alignment);
}
auto ComputeOffsetsHelper::GetSizeAndAlignment(const Symbol &symbol)
-> SizeAndAlignment {
SizeAndAlignment result{GetElementSize(symbol)};
std::size_t elements{CountElements(symbol)};
if (elements > 1) {
result.size = Align(result.size, result.alignment);
}
result.size *= elements;
return result;
}
auto ComputeOffsetsHelper::GetElementSize(const Symbol &symbol)
-> SizeAndAlignment {
const DeclTypeSpec *type{symbol.GetType()};
if (!evaluate::DynamicType::From(type).has_value()) {
return {};
}
auto ComputeOffsetsHelper::GetSizeAndAlignment(
const Symbol &symbol, bool entire) -> SizeAndAlignment {
// TODO: The size of procedure pointers is not yet known
// and is independent of rank (and probably also the number
// of length type parameters).
auto &foldingContext{context_.foldingContext()};
if (IsDescriptor(symbol) || IsProcedurePointer(symbol)) {
int lenParams{0};
if (const DerivedTypeSpec * derived{type->AsDerived()}) {
if (const auto *derived{evaluate::GetDerivedTypeSpec(
evaluate::DynamicType::From(symbol))}) {
lenParams = CountLenParameters(*derived);
}
std::size_t size{
runtime::Descriptor::SizeInBytes(symbol.Rank(), false, lenParams)};
return {size, maxAlignment};
return {size, foldingContext.maxAlignment()};
}
if (IsProcedure(symbol)) {
return {};
}
SizeAndAlignment result;
if (const IntrinsicTypeSpec * intrinsic{type->AsIntrinsic()}) {
if (auto kind{ToInt64(intrinsic->kind())}) {
result = GetIntrinsicSizeAndAlignment(intrinsic->category(), *kind);
}
if (type->category() == DeclTypeSpec::Character) {
ParamValue length{type->characterTypeSpec().length()};
CHECK(length.isExplicit()); // else should be descriptor
if (MaybeIntExpr lengthExpr{length.GetExplicit()}) {
if (auto lengthInt{ToInt64(*lengthExpr)}) {
result.size *= *lengthInt;
}
if (auto chars{evaluate::characteristics::TypeAndShape::Characterize(
symbol, foldingContext)}) {
if (entire) {
if (auto size{ToInt64(chars->MeasureSizeInBytes(foldingContext))}) {
return {static_cast<std::size_t>(*size),
chars->type().GetAlignment(foldingContext)};
}
}
} else if (const DerivedTypeSpec * derived{type->AsDerived()}) {
if (derived->scope()) {
DoScope(*const_cast<Scope *>(derived->scope()));
result.size = derived->scope()->size();
result.alignment = derived->scope()->alignment().value_or(0);
}
} else {
DIE("not intrinsic or derived");
}
return result;
}
std::size_t ComputeOffsetsHelper::CountElements(const Symbol &symbol) {
if (auto shape{GetShape(foldingContext_, symbol)}) {
if (auto sizeExpr{evaluate::GetSize(std::move(*shape))}) {
if (auto size{ToInt64(Fold(foldingContext_, std::move(*sizeExpr)))}) {
return *size;
} else { // element size only
if (auto size{ToInt64(chars->type().MeasureSizeInBytes(
foldingContext, true /*aligned*/))}) {
return {static_cast<std::size_t>(*size),
chars->type().GetAlignment(foldingContext)};
}
}
}
return 1;
return {};
}
// Align a size to its natural alignment, up to maxAlignment.
std::size_t ComputeOffsetsHelper::Align(std::size_t x, std::size_t alignment) {
if (alignment > maxAlignment) {
alignment = maxAlignment;
}
alignment = std::min(alignment, context_.foldingContext().maxAlignment());
return (x + alignment - 1) & -alignment;
}
auto ComputeOffsetsHelper::GetIntrinsicSizeAndAlignment(
TypeCategory category, int kind) -> SizeAndAlignment {
if (category == TypeCategory::Character) {
return {static_cast<std::size_t>(kind)};
}
auto bytes{evaluate::ToInt64(
evaluate::DynamicType{category, kind}.MeasureSizeInBytes())};
CHECK(bytes && *bytes > 0);
std::size_t size{static_cast<std::size_t>(*bytes)};
if (category == TypeCategory::Complex) {
return {size, size >> 1};
} else {
return {size};
}
}
void ComputeOffsets(SemanticsContext &context) {
ComputeOffsetsHelper{context}.Compute();
void ComputeOffsets(SemanticsContext &context, Scope &scope) {
ComputeOffsetsHelper{context}.Compute(scope);
}
} // namespace Fortran::semantics

View File

@ -11,7 +11,8 @@
namespace Fortran::semantics {
class SemanticsContext;
void ComputeOffsets(SemanticsContext &);
class Scope;
void ComputeOffsets(SemanticsContext &, Scope &);
} // namespace Fortran::semantics
#endif

View File

@ -229,9 +229,9 @@ DataInitializationCompiler::ConvertElement(
// (most) other Fortran compilers do. Pad on the right with spaces
// when short, truncate the right if long.
// TODO: big-endian targets
std::size_t bytes{static_cast<std::size_t>(evaluate::ToInt64(
type.MeasureSizeInBytes(&exprAnalyzer_.GetFoldingContext()))
.value())};
auto bytes{static_cast<std::size_t>(evaluate::ToInt64(
type.MeasureSizeInBytes(exprAnalyzer_.GetFoldingContext(), false))
.value())};
evaluate::BOZLiteralConstant bits{0};
for (std::size_t j{0}; j < bytes; ++j) {
char ch{j >= chValue->size() ? ' ' : chValue->at(j)};
@ -349,8 +349,8 @@ bool DataInitializationCompiler::InitElement(
DescribeElement(), designatorType->AsFortran());
}
auto folded{evaluate::Fold(context, std::move(converted->first))};
switch (
GetImage().Add(offsetSymbol.offset(), offsetSymbol.size(), folded)) {
switch (GetImage().Add(
offsetSymbol.offset(), offsetSymbol.size(), folded, context)) {
case evaluate::InitialImage::Ok:
return true;
case evaluate::InitialImage::NotAConstant:
@ -434,15 +434,15 @@ static bool CombineSomeEquivalencedInits(
// Compute the minimum common granularity
if (auto dyType{evaluate::DynamicType::From(symbol)}) {
minElementBytes = evaluate::ToInt64(
dyType->MeasureSizeInBytes(&exprAnalyzer.GetFoldingContext()))
dyType->MeasureSizeInBytes(exprAnalyzer.GetFoldingContext(), true))
.value_or(1);
}
for (const Symbol *s : conflicts) {
if (auto dyType{evaluate::DynamicType::From(*s)}) {
minElementBytes = std::min(minElementBytes,
static_cast<std::size_t>(evaluate::ToInt64(
dyType->MeasureSizeInBytes(&exprAnalyzer.GetFoldingContext()))
.value_or(1)));
minElementBytes = std::min<std::size_t>(minElementBytes,
evaluate::ToInt64(dyType->MeasureSizeInBytes(
exprAnalyzer.GetFoldingContext(), true))
.value_or(1));
} else {
minElementBytes = 1;
}

View File

@ -167,7 +167,7 @@ static bool PerformStatementSemantics(
SemanticsContext &context, parser::Program &program) {
ResolveNames(context, program);
RewriteParseTree(context, program);
ComputeOffsets(context);
ComputeOffsets(context, context.globalScope());
CheckDeclarations(context);
StatementSemanticsPass1{context}.Walk(program);
StatementSemanticsPass2 pass2{context};

View File

@ -8,6 +8,7 @@
#include "flang/Semantics/type.h"
#include "check-declarations.h"
#include "compute-offsets.h"
#include "flang/Evaluate/fold.h"
#include "flang/Parser/characters.h"
#include "flang/Semantics/scope.h"
@ -248,6 +249,7 @@ void DerivedTypeSpec::Instantiate(
}
}
}
ComputeOffsets(context, const_cast<Scope &>(typeScope));
return;
}
Scope &newScope{containingScope.MakeScope(Scope::Kind::DerivedType)};
@ -306,6 +308,7 @@ void InstantiateHelper::InstantiateComponents(const Scope &fromScope) {
for (const auto &pair : fromScope) {
InstantiateComponent(*pair.second);
}
ComputeOffsets(context_, scope_);
}
void InstantiateHelper::InstantiateComponent(const Symbol &oldSymbol) {

View File

@ -16,6 +16,7 @@ module __Fortran_builtins
integer, parameter, private :: int64 = selected_int_kind(18)
intrinsic :: __builtin_c_f_pointer
intrinsic :: sizeof ! extension
type :: __builtin_event_type
integer(kind=int64) :: __count

View File

@ -13,7 +13,8 @@ module iso_c_binding
use __Fortran_builtins, only: &
c_f_pointer => __builtin_c_f_pointer, &
c_ptr => __builtin_c_ptr, &
c_funptr => __builtin_c_funptr
c_funptr => __builtin_c_funptr, &
c_sizeof => sizeof
type(c_ptr), parameter :: c_null_ptr = c_ptr(0)
type(c_funptr), parameter :: c_null_funptr = c_funptr(0)
@ -32,7 +33,7 @@ module iso_c_binding
c_long = c_int64_t, &
c_long_long = c_int64_t, &
c_signed_char = c_int8_t, &
c_size_t = c_long_long, &
c_size_t = kind(c_sizeof(1)), &
c_intmax_t = c_int128_t, &
c_intptr_t = c_size_t, &
c_ptrdiff_t = c_size_t
@ -102,6 +103,5 @@ module iso_c_binding
end function c_funloc
! TODO c_f_procpointer
! TODO c_sizeof
end module iso_c_binding

View File

@ -0,0 +1,23 @@
! RUN: %S/test_folding.sh %s %t %f18
! Test implementations of STORAGE_SIZE() and SIZEOF() as expression rewrites
module m1
type :: t1
real :: a(2,3)
character*5 :: c(3)
end type
type :: t2(k)
integer, kind :: k
type(t1) :: a(k)
end type
type(t2(2)) :: a(2)
integer, parameter :: ss1 = storage_size(a(1)%a(1)%a)
integer, parameter :: sz1 = sizeof(a(1)%a(1)%a)
integer, parameter :: ss2 = storage_size(a(1)%a(1)%c)
integer, parameter :: sz2 = sizeof(a(1)%a(1)%c)
integer, parameter :: ss3 = storage_size(a(1)%a)
integer, parameter :: sz3 = sizeof(a(1)%a)
integer, parameter :: ss4 = storage_size(a)
integer, parameter :: sz4 = sizeof(a)
logical, parameter :: test_ss = all([ss1,ss2,ss3,ss4]==[32, 40, 320, 640])
logical, parameter :: test_sz = all([sz1,sz2,sz3,sz4]==[24, 15, 80, 160])
end module

View File

@ -6,7 +6,7 @@ module m1
integer :: n
end type
type t2
! t and t2 must be resolved to types in m, not components in t2
! t and t2 must be resolved to types in m1, not components in t2
type(t) :: t(10) = t(1)
type(t) :: x = t(1)
integer :: t2

View File

@ -59,7 +59,7 @@ module m05
subroutine s1(x)
class(t), intent(in) :: x
end subroutine
!CHECK: .dt.t, SAVE, TARGET: ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=NULL(),name=.n.t,sizeinbytes=0_8,parent=NULL(),uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=NULL(),procptr=.p.t,special=NULL())
!CHECK: .dt.t, SAVE, TARGET: ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=NULL(),name=.n.t,sizeinbytes=24_8,parent=NULL(),uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=NULL(),procptr=.p.t,special=NULL())
!CHECK: .p.t, SAVE, TARGET: ObjectEntity type: TYPE(procptrcomponent) shape: 0_8:0_8 init:[procptrcomponent::procptrcomponent(name=.n.p1,offset=0_8,initialization=s1)]
end module