2020-06-19 04:28:43 +08:00
|
|
|
//===-- lib/Semantics/compute-offsets.cpp -----------------------*- C++ -*-===//
|
2020-04-23 06:39:24 +08:00
|
|
|
//
|
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "compute-offsets.h"
|
2020-07-02 02:45:38 +08:00
|
|
|
#include "flang/Evaluate/fold-designator.h"
|
2020-04-23 06:39:24 +08:00
|
|
|
#include "flang/Evaluate/fold.h"
|
|
|
|
#include "flang/Evaluate/shape.h"
|
|
|
|
#include "flang/Evaluate/type.h"
|
2021-09-02 07:00:53 +08:00
|
|
|
#include "flang/Runtime/descriptor.h"
|
2020-04-23 06:39:24 +08:00
|
|
|
#include "flang/Semantics/scope.h"
|
|
|
|
#include "flang/Semantics/semantics.h"
|
|
|
|
#include "flang/Semantics/symbol.h"
|
|
|
|
#include "flang/Semantics/tools.h"
|
|
|
|
#include "flang/Semantics/type.h"
|
|
|
|
#include <algorithm>
|
|
|
|
#include <vector>
|
|
|
|
|
|
|
|
namespace Fortran::semantics {
|
|
|
|
|
|
|
|
class ComputeOffsetsHelper {
|
|
|
|
public:
|
|
|
|
ComputeOffsetsHelper(SemanticsContext &context) : context_{context} {}
|
2020-12-16 03:06:44 +08:00
|
|
|
void Compute(Scope &);
|
2020-04-23 06:39:24 +08:00
|
|
|
|
|
|
|
private:
|
2020-05-07 06:00:14 +08:00
|
|
|
struct SizeAndAlignment {
|
|
|
|
SizeAndAlignment() {}
|
2020-06-19 04:28:43 +08:00
|
|
|
SizeAndAlignment(std::size_t bytes) : size{bytes}, alignment{bytes} {}
|
|
|
|
SizeAndAlignment(std::size_t bytes, std::size_t align)
|
|
|
|
: size{bytes}, alignment{align} {}
|
2020-04-23 06:39:24 +08:00
|
|
|
std::size_t size{0};
|
2020-05-07 06:00:14 +08:00
|
|
|
std::size_t alignment{0};
|
2020-04-23 06:39:24 +08:00
|
|
|
};
|
2020-05-07 02:43:06 +08:00
|
|
|
struct SymbolAndOffset {
|
2020-07-02 02:45:38 +08:00
|
|
|
SymbolAndOffset(Symbol &s, std::size_t off, const EquivalenceObject &obj)
|
2021-08-11 01:22:39 +08:00
|
|
|
: symbol{s}, offset{off}, object{&obj} {}
|
2020-07-02 02:45:38 +08:00
|
|
|
SymbolAndOffset(const SymbolAndOffset &) = default;
|
2021-08-11 01:22:39 +08:00
|
|
|
MutableSymbolRef symbol;
|
2020-07-02 02:45:38 +08:00
|
|
|
std::size_t offset;
|
|
|
|
const EquivalenceObject *object;
|
2020-05-07 02:43:06 +08:00
|
|
|
};
|
2020-04-23 06:39:24 +08:00
|
|
|
|
2020-05-07 02:43:06 +08:00
|
|
|
void DoCommonBlock(Symbol &);
|
2020-08-08 04:25:11 +08:00
|
|
|
void DoEquivalenceBlockBase(Symbol &, SizeAndAlignment &);
|
2020-07-02 02:45:38 +08:00
|
|
|
void DoEquivalenceSet(const EquivalenceSet &);
|
|
|
|
SymbolAndOffset Resolve(const SymbolAndOffset &);
|
2020-05-07 02:43:06 +08:00
|
|
|
std::size_t ComputeOffset(const EquivalenceObject &);
|
2022-04-01 03:55:45 +08:00
|
|
|
// Returns amount of padding that was needed for alignment
|
|
|
|
std::size_t DoSymbol(Symbol &);
|
2020-12-16 03:06:44 +08:00
|
|
|
SizeAndAlignment GetSizeAndAlignment(const Symbol &, bool entire);
|
|
|
|
std::size_t Align(std::size_t, std::size_t);
|
2020-04-23 06:39:24 +08:00
|
|
|
|
|
|
|
SemanticsContext &context_;
|
|
|
|
std::size_t offset_{0};
|
2020-12-16 03:06:44 +08:00
|
|
|
std::size_t alignment_{1};
|
2020-05-07 02:43:06 +08:00
|
|
|
// symbol -> symbol+offset that determines its location, from EQUIVALENCE
|
2021-03-19 01:26:23 +08:00
|
|
|
std::map<MutableSymbolRef, SymbolAndOffset, SymbolAddressCompare> dependents_;
|
2020-08-08 04:25:11 +08:00
|
|
|
// base symbol -> SizeAndAlignment for each distinct EQUIVALENCE block
|
2021-03-19 01:26:23 +08:00
|
|
|
std::map<MutableSymbolRef, SizeAndAlignment, SymbolAddressCompare>
|
|
|
|
equivalenceBlock_;
|
2020-04-23 06:39:24 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
void ComputeOffsetsHelper::Compute(Scope &scope) {
|
|
|
|
for (Scope &child : scope.children()) {
|
2020-12-16 03:06:44 +08:00
|
|
|
ComputeOffsets(context_, child);
|
2020-04-23 06:39:24 +08:00
|
|
|
}
|
2022-03-12 02:03:19 +08:00
|
|
|
if (scope.symbol() && scope.IsDerivedTypeWithKindParameter()) {
|
[flang] Generate PDT runtime type info in the type definition scope
This patches modifies PDT runtime type info generation so that it is
easier to handle derived type descriptor in lowering. It changes three
aspects:
1. The symbol name suffix of runtime type info for PDT instantiation is
changed from a serial number unrelated to the types to an encoding of
the instantiated KIND parameters.
2. New runtime type info is not created for each instantiation of PDT without
KIND parameters (only length parameters). Instead, the runtime type
info of the type definition is always used. It is updated to contain
the component descriptions.
3. Runtime type info of PDT instantiation is now always generated in the
scope where the type is defined. If several PDT type instantiation
are made in different scope with the same kind parameters, they will
use the same runtime type info.
Rational of the change:
In lowering, derived type descriptors are not mapped when instantiating derived
type objects. They are mapped later when symbol knowledge is not available anymore.
This mapping is based on the FIR representation of derived types. For
PDT, the FIR type information does not allow deducing the instantiation
scope, it only allows retrieving the type name, the type _definition_
scope, and the kind parameter values. Therefore, in order to be able to
retrieve the derived type descriptor from a FIR type, the derived type
descriptor must be generated in the definition scope and must reflect
the kind parameters. This justifies the need for changes 1. and 3.
above (suffix and scope change). Changes 2. comes from the fact that
all runtime type info of type without kind parameters can be generated
from the type definition, and that because of the suffix change, the
symbol name for type definition and type instantiation are the same.
Although this change is first motivated by how lowering handles derived
types, I believe it is also an improvement from a functional point of
view since this change will allow reducing the number of generated
runtime type info for PDTs, since redundant information (different
instantiations with same kind parameters) will only be generated once.
Differential Revision: https://reviews.llvm.org/D120801
2022-03-03 17:14:08 +08:00
|
|
|
return; // only process instantiations of kind parameterized derived types
|
2020-04-23 06:39:24 +08:00
|
|
|
}
|
2020-12-08 06:46:24 +08:00
|
|
|
if (scope.alignment().has_value()) {
|
|
|
|
return; // prevent infinite recursion in error cases
|
|
|
|
}
|
|
|
|
scope.SetAlignment(0);
|
2020-05-07 02:43:06 +08:00
|
|
|
// Build dependents_ from equivalences: symbol -> symbol+offset
|
2020-07-02 02:45:38 +08:00
|
|
|
for (const EquivalenceSet &set : scope.equivalenceSets()) {
|
2020-05-07 02:43:06 +08:00
|
|
|
DoEquivalenceSet(set);
|
|
|
|
}
|
2020-08-08 04:25:11 +08:00
|
|
|
// 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);
|
2020-12-16 03:06:44 +08:00
|
|
|
auto symInfo{GetSizeAndAlignment(*symbol, true)};
|
2020-08-08 04:25:11 +08:00
|
|
|
symbol->set_size(symInfo.size);
|
|
|
|
Symbol &base{*dep.symbol};
|
|
|
|
auto iter{equivalenceBlock_.find(base)};
|
|
|
|
std::size_t minBlockSize{dep.offset + symInfo.size};
|
|
|
|
if (iter == equivalenceBlock_.end()) {
|
|
|
|
equivalenceBlock_.emplace(
|
|
|
|
base, SizeAndAlignment{minBlockSize, symInfo.alignment});
|
|
|
|
} else {
|
|
|
|
SizeAndAlignment &blockInfo{iter->second};
|
|
|
|
blockInfo.size = std::max(blockInfo.size, minBlockSize);
|
|
|
|
blockInfo.alignment = std::max(blockInfo.alignment, symInfo.alignment);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Assign offsets for non-COMMON EQUIVALENCE blocks
|
|
|
|
for (auto &[symbol, blockInfo] : equivalenceBlock_) {
|
|
|
|
if (!InCommonBlock(*symbol)) {
|
|
|
|
DoSymbol(*symbol);
|
|
|
|
DoEquivalenceBlockBase(*symbol, blockInfo);
|
|
|
|
offset_ = std::max(offset_, symbol->offset() + blockInfo.size);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Process remaining non-COMMON symbols; this is all of them if there
|
|
|
|
// was no use of EQUIVALENCE in the scope.
|
2020-05-07 02:43:06 +08:00
|
|
|
for (auto &symbol : scope.GetSymbols()) {
|
|
|
|
if (!InCommonBlock(*symbol) &&
|
2020-08-08 04:25:11 +08:00
|
|
|
dependents_.find(symbol) == dependents_.end() &&
|
|
|
|
equivalenceBlock_.find(symbol) == equivalenceBlock_.end()) {
|
2020-04-23 06:39:24 +08:00
|
|
|
DoSymbol(*symbol);
|
|
|
|
}
|
|
|
|
}
|
2020-08-08 04:25:11 +08:00
|
|
|
scope.set_size(offset_);
|
2020-12-08 06:46:24 +08:00
|
|
|
scope.SetAlignment(alignment_);
|
2022-08-27 14:37:19 +08:00
|
|
|
// Assign offsets in COMMON blocks, unless this scope is a BLOCK construct,
|
|
|
|
// where COMMON blocks are illegal (C1107 and C1108).
|
|
|
|
if (scope.kind() != Scope::Kind::BlockConstruct) {
|
|
|
|
for (auto &pair : scope.commonBlocks()) {
|
|
|
|
DoCommonBlock(*pair.second);
|
|
|
|
}
|
2020-08-08 04:25:11 +08:00
|
|
|
}
|
2020-05-07 02:43:06 +08:00
|
|
|
for (auto &[symbol, dep] : dependents_) {
|
2020-08-08 04:25:11 +08:00
|
|
|
symbol->set_offset(dep.symbol->offset() + dep.offset);
|
|
|
|
if (const auto *block{FindCommonBlockContaining(*dep.symbol)}) {
|
|
|
|
symbol->get<ObjectEntityDetails>().set_commonBlock(*block);
|
2020-05-07 02:43:06 +08:00
|
|
|
}
|
|
|
|
}
|
2020-04-23 06:39:24 +08:00
|
|
|
}
|
|
|
|
|
2020-07-02 02:45:38 +08:00
|
|
|
auto ComputeOffsetsHelper::Resolve(const SymbolAndOffset &dep)
|
|
|
|
-> SymbolAndOffset {
|
2020-05-07 02:43:06 +08:00
|
|
|
auto it{dependents_.find(*dep.symbol)};
|
|
|
|
if (it == dependents_.end()) {
|
2020-07-02 02:45:38 +08:00
|
|
|
return dep;
|
2020-05-07 02:43:06 +08:00
|
|
|
} else {
|
2020-07-02 02:45:38 +08:00
|
|
|
SymbolAndOffset result{Resolve(it->second)};
|
|
|
|
result.offset += dep.offset;
|
|
|
|
result.object = dep.object;
|
|
|
|
return result;
|
2020-05-07 02:43:06 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ComputeOffsetsHelper::DoCommonBlock(Symbol &commonBlock) {
|
|
|
|
auto &details{commonBlock.get<CommonBlockDetails>()};
|
|
|
|
offset_ = 0;
|
2020-05-07 06:00:14 +08:00
|
|
|
alignment_ = 0;
|
2020-08-08 04:25:11 +08:00
|
|
|
std::size_t minSize{0};
|
|
|
|
std::size_t minAlignment{0};
|
2020-05-07 02:43:06 +08:00
|
|
|
for (auto &object : details.objects()) {
|
2020-08-08 04:25:11 +08:00
|
|
|
Symbol &symbol{*object};
|
2022-04-01 03:55:45 +08:00
|
|
|
auto errorSite{
|
|
|
|
commonBlock.name().empty() ? symbol.name() : commonBlock.name()};
|
|
|
|
if (std::size_t padding{DoSymbol(symbol)}) {
|
|
|
|
context_.Say(errorSite,
|
|
|
|
"COMMON block /%s/ requires %zd bytes of padding before '%s' for alignment"_port_en_US,
|
|
|
|
commonBlock.name(), padding, symbol.name());
|
|
|
|
}
|
2021-09-03 14:12:44 +08:00
|
|
|
auto eqIter{equivalenceBlock_.end()};
|
2020-08-08 04:25:11 +08:00
|
|
|
auto iter{dependents_.find(symbol)};
|
|
|
|
if (iter == dependents_.end()) {
|
2021-09-09 15:11:49 +08:00
|
|
|
eqIter = equivalenceBlock_.find(symbol);
|
2020-08-08 04:25:11 +08:00
|
|
|
if (eqIter != equivalenceBlock_.end()) {
|
2021-09-03 14:12:44 +08:00
|
|
|
DoEquivalenceBlockBase(symbol, eqIter->second);
|
2020-08-08 04:25:11 +08:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
SymbolAndOffset &dep{iter->second};
|
|
|
|
Symbol &base{*dep.symbol};
|
|
|
|
if (const auto *baseBlock{FindCommonBlockContaining(base)}) {
|
|
|
|
if (baseBlock == &commonBlock) {
|
|
|
|
context_.Say(errorSite,
|
|
|
|
"'%s' is storage associated with '%s' by EQUIVALENCE elsewhere in COMMON block /%s/"_err_en_US,
|
|
|
|
symbol.name(), base.name(), commonBlock.name());
|
|
|
|
} else { // 8.10.3(1)
|
|
|
|
context_.Say(errorSite,
|
|
|
|
"'%s' in COMMON block /%s/ must not be storage associated with '%s' in COMMON block /%s/ by EQUIVALENCE"_err_en_US,
|
|
|
|
symbol.name(), commonBlock.name(), base.name(),
|
|
|
|
baseBlock->name());
|
|
|
|
}
|
|
|
|
} else if (dep.offset > symbol.offset()) { // 8.10.3(3)
|
|
|
|
context_.Say(errorSite,
|
|
|
|
"'%s' cannot backward-extend COMMON block /%s/ via EQUIVALENCE with '%s'"_err_en_US,
|
|
|
|
symbol.name(), commonBlock.name(), base.name());
|
|
|
|
} else {
|
2021-09-03 14:12:44 +08:00
|
|
|
eqIter = equivalenceBlock_.find(base);
|
2020-08-08 04:25:11 +08:00
|
|
|
base.get<ObjectEntityDetails>().set_commonBlock(commonBlock);
|
|
|
|
base.set_offset(symbol.offset() - dep.offset);
|
|
|
|
}
|
|
|
|
}
|
2021-09-03 14:12:44 +08:00
|
|
|
// Get full extent of any EQUIVALENCE block into size of COMMON ( see
|
|
|
|
// 8.10.2.2 point 1 (2))
|
|
|
|
if (eqIter != equivalenceBlock_.end()) {
|
|
|
|
SizeAndAlignment &blockInfo{eqIter->second};
|
|
|
|
minSize = std::max(
|
|
|
|
minSize, std::max(offset_, eqIter->first->offset() + blockInfo.size));
|
|
|
|
minAlignment = std::max(minAlignment, blockInfo.alignment);
|
|
|
|
}
|
2020-08-08 04:25:11 +08:00
|
|
|
}
|
|
|
|
commonBlock.set_size(std::max(minSize, offset_));
|
|
|
|
details.set_alignment(std::max(minAlignment, alignment_));
|
[flang] Handle common block with different sizes in same file
Semantics is not preventing a named common block to appear with
different size in a same file (named common block should always have
the same storage size (see Fortran 2018 8.10.2.5), but it is a common
extension to accept different sizes).
Lowering was not coping with this well, since it just use the first
common block appearance, starting with BLOCK DATAs to define common
blocks (this also was an issue with the blank common block, which can
legally appear with different size in different scoping units).
Semantics is also not preventing named common from being initialized
outside of a BLOCK DATA, and lowering was dealing badly with this,
since it only gave an initial value to common blocks Globals if the
first common block appearance, starting with BLOCK DATAs had an initial
value.
Semantics is also allowing blank common to be initialized, while
lowering was assuming this would never happen, and was never creating
an initial value for it.
Lastly, semantics was not complaining if a COMMON block was initialized
in several scoping unit in a same file, while lowering can only generate
one of these initial value.
To fix this, add a structure to keep track of COMMON block properties
(biggest size, and initial value if any) at the Program level. Once the
size of a common block appearance is know, the common block appearance
is checked against this information. It allows semantics to emit an error
in case of multiple initialization in different scopes of a same common
block, and to warn in case named common blocks appears with different
sizes. Lastly, this allows lowering to use the Program level info about
common blocks to emit the right GlobalOp for a Common Block, regardless
of the COMMON Block appearances order: It emits a GlobalOp with the
biggest size, whose lowest bytes are initialized with the initial value
if any is given in a scope where the common block appears.
Lowering is updated to go emit the common blocks before anything else so
that the related GlobalOps are available when lowering the scopes where
common block appear. It is also updated to not assume that blank common
are never initialized.
Differential Revision: https://reviews.llvm.org/D124622
2022-04-29 20:52:27 +08:00
|
|
|
context_.MapCommonBlockAndCheckConflicts(commonBlock);
|
2020-08-08 04:25:11 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void ComputeOffsetsHelper::DoEquivalenceBlockBase(
|
|
|
|
Symbol &symbol, SizeAndAlignment &blockInfo) {
|
|
|
|
if (symbol.size() > blockInfo.size) {
|
|
|
|
blockInfo.size = symbol.size();
|
2020-05-07 02:43:06 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-02 02:45:38 +08:00
|
|
|
void ComputeOffsetsHelper::DoEquivalenceSet(const EquivalenceSet &set) {
|
2020-05-07 02:43:06 +08:00
|
|
|
std::vector<SymbolAndOffset> symbolOffsets;
|
2020-07-02 02:45:38 +08:00
|
|
|
std::optional<std::size_t> representative;
|
|
|
|
for (const EquivalenceObject &object : set) {
|
2020-05-07 02:43:06 +08:00
|
|
|
std::size_t offset{ComputeOffset(object)};
|
2020-07-02 02:45:38 +08:00
|
|
|
SymbolAndOffset resolved{
|
|
|
|
Resolve(SymbolAndOffset{object.symbol, offset, object})};
|
|
|
|
symbolOffsets.push_back(resolved);
|
|
|
|
if (!representative ||
|
|
|
|
resolved.offset >= symbolOffsets[*representative].offset) {
|
|
|
|
// The equivalenced object with the largest offset from its resolved
|
|
|
|
// symbol will be the representative of this set, since the offsets
|
|
|
|
// of the other objects will be positive relative to it.
|
|
|
|
representative = symbolOffsets.size() - 1;
|
2020-05-07 02:43:06 +08:00
|
|
|
}
|
|
|
|
}
|
2020-07-02 02:45:38 +08:00
|
|
|
CHECK(representative);
|
|
|
|
const SymbolAndOffset &base{symbolOffsets[*representative]};
|
|
|
|
for (const auto &[symbol, offset, object] : symbolOffsets) {
|
|
|
|
if (symbol == base.symbol) {
|
|
|
|
if (offset != base.offset) {
|
|
|
|
auto x{evaluate::OffsetToDesignator(
|
|
|
|
context_.foldingContext(), *symbol, base.offset, 1)};
|
|
|
|
auto y{evaluate::OffsetToDesignator(
|
|
|
|
context_.foldingContext(), *symbol, offset, 1)};
|
|
|
|
if (x && y) {
|
|
|
|
context_
|
|
|
|
.Say(base.object->source,
|
|
|
|
"'%s' and '%s' cannot have the same first storage unit"_err_en_US,
|
|
|
|
x->AsFortran(), y->AsFortran())
|
|
|
|
.Attach(object->source, "Incompatible reference to '%s'"_en_US,
|
|
|
|
y->AsFortran());
|
|
|
|
} else { // error recovery
|
|
|
|
context_
|
|
|
|
.Say(base.object->source,
|
|
|
|
"'%s' (offset %zd bytes and %zd bytes) cannot have the same first storage unit"_err_en_US,
|
|
|
|
symbol->name(), base.offset, offset)
|
|
|
|
.Attach(object->source,
|
|
|
|
"Incompatible reference to '%s' offset %zd bytes"_en_US,
|
|
|
|
symbol->name(), offset);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
dependents_.emplace(*symbol,
|
|
|
|
SymbolAndOffset{*base.symbol, base.offset - offset, *object});
|
2020-05-07 02:43:06 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Offset of this equivalence object from the start of its variable.
|
|
|
|
std::size_t ComputeOffsetsHelper::ComputeOffset(
|
|
|
|
const EquivalenceObject &object) {
|
|
|
|
std::size_t offset{0};
|
|
|
|
if (!object.subscripts.empty()) {
|
|
|
|
const ArraySpec &shape{object.symbol.get<ObjectEntityDetails>().shape()};
|
|
|
|
auto lbound{[&](std::size_t i) {
|
|
|
|
return *ToInt64(shape[i].lbound().GetExplicit());
|
|
|
|
}};
|
|
|
|
auto ubound{[&](std::size_t i) {
|
|
|
|
return *ToInt64(shape[i].ubound().GetExplicit());
|
|
|
|
}};
|
|
|
|
for (std::size_t i{object.subscripts.size() - 1};;) {
|
|
|
|
offset += object.subscripts[i] - lbound(i);
|
|
|
|
if (i == 0) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
--i;
|
|
|
|
offset *= ubound(i) - lbound(i) + 1;
|
|
|
|
}
|
|
|
|
}
|
2020-12-16 03:06:44 +08:00
|
|
|
auto result{offset * GetSizeAndAlignment(object.symbol, false).size};
|
2020-07-02 02:45:38 +08:00
|
|
|
if (object.substringStart) {
|
|
|
|
int kind{context_.defaultKinds().GetDefaultKind(TypeCategory::Character)};
|
|
|
|
if (const DeclTypeSpec * type{object.symbol.GetType()}) {
|
|
|
|
if (const IntrinsicTypeSpec * intrinsic{type->AsIntrinsic()}) {
|
|
|
|
kind = ToInt64(intrinsic->kind()).value_or(kind);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
result += kind * (*object.substringStart - 1);
|
|
|
|
}
|
|
|
|
return result;
|
2020-05-07 02:43:06 +08:00
|
|
|
}
|
|
|
|
|
2022-04-01 03:55:45 +08:00
|
|
|
std::size_t ComputeOffsetsHelper::DoSymbol(Symbol &symbol) {
|
2020-08-25 09:20:22 +08:00
|
|
|
if (!symbol.has<ObjectEntityDetails>() && !symbol.has<ProcEntityDetails>()) {
|
2022-04-01 03:55:45 +08:00
|
|
|
return 0;
|
2020-05-07 02:43:06 +08:00
|
|
|
}
|
2020-12-16 03:06:44 +08:00
|
|
|
SizeAndAlignment s{GetSizeAndAlignment(symbol, true)};
|
2020-04-23 06:39:24 +08:00
|
|
|
if (s.size == 0) {
|
2022-04-01 03:55:45 +08:00
|
|
|
return 0;
|
2020-04-23 06:39:24 +08:00
|
|
|
}
|
2022-04-01 03:55:45 +08:00
|
|
|
std::size_t previousOffset{offset_};
|
2020-05-07 06:00:14 +08:00
|
|
|
offset_ = Align(offset_, s.alignment);
|
2022-04-01 03:55:45 +08:00
|
|
|
std::size_t padding{offset_ - previousOffset};
|
2020-04-23 06:39:24 +08:00
|
|
|
symbol.set_size(s.size);
|
|
|
|
symbol.set_offset(offset_);
|
|
|
|
offset_ += s.size;
|
2020-05-07 06:00:14 +08:00
|
|
|
alignment_ = std::max(alignment_, s.alignment);
|
2022-04-01 03:55:45 +08:00
|
|
|
return padding;
|
2020-04-23 06:39:24 +08:00
|
|
|
}
|
|
|
|
|
2020-12-16 03:06:44 +08:00
|
|
|
auto ComputeOffsetsHelper::GetSizeAndAlignment(
|
|
|
|
const Symbol &symbol, bool entire) -> SizeAndAlignment {
|
2022-07-02 02:40:44 +08:00
|
|
|
auto &targetCharacteristics{context_.targetCharacteristics()};
|
|
|
|
if (IsDescriptor(symbol)) {
|
2021-07-20 02:53:20 +08:00
|
|
|
const auto *derived{
|
|
|
|
evaluate::GetDerivedTypeSpec(evaluate::DynamicType::From(symbol))};
|
|
|
|
int lenParams{derived ? CountLenParameters(*derived) : 0};
|
|
|
|
std::size_t size{runtime::Descriptor::SizeInBytes(
|
|
|
|
symbol.Rank(), derived != nullptr, lenParams)};
|
2022-07-02 02:40:44 +08:00
|
|
|
return {size, targetCharacteristics.descriptorAlignment()};
|
|
|
|
}
|
|
|
|
if (IsProcedurePointer(symbol)) {
|
|
|
|
return {targetCharacteristics.procedurePointerByteSize(),
|
|
|
|
targetCharacteristics.procedurePointerAlignment()};
|
2020-04-23 06:39:24 +08:00
|
|
|
}
|
2020-07-29 22:23:28 +08:00
|
|
|
if (IsProcedure(symbol)) {
|
|
|
|
return {};
|
|
|
|
}
|
2022-07-02 02:40:44 +08:00
|
|
|
auto &foldingContext{context_.foldingContext()};
|
2020-12-16 03:06:44 +08:00
|
|
|
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),
|
2022-07-02 02:40:44 +08:00
|
|
|
chars->type().GetAlignment(targetCharacteristics)};
|
2020-04-23 06:39:24 +08:00
|
|
|
}
|
2020-12-16 03:06:44 +08:00
|
|
|
} else { // element size only
|
2021-02-03 06:39:05 +08:00
|
|
|
if (auto size{ToInt64(chars->MeasureElementSizeInBytes(
|
2020-12-16 03:06:44 +08:00
|
|
|
foldingContext, true /*aligned*/))}) {
|
|
|
|
return {static_cast<std::size_t>(*size),
|
2022-07-02 02:40:44 +08:00
|
|
|
chars->type().GetAlignment(targetCharacteristics)};
|
2020-04-23 06:39:24 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-12-16 03:06:44 +08:00
|
|
|
return {};
|
2020-04-23 06:39:24 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Align a size to its natural alignment, up to maxAlignment.
|
|
|
|
std::size_t ComputeOffsetsHelper::Align(std::size_t x, std::size_t alignment) {
|
2022-07-02 02:40:44 +08:00
|
|
|
alignment =
|
|
|
|
std::min(alignment, context_.targetCharacteristics().maxAlignment());
|
2020-04-23 06:39:24 +08:00
|
|
|
return (x + alignment - 1) & -alignment;
|
|
|
|
}
|
|
|
|
|
2020-12-16 03:06:44 +08:00
|
|
|
void ComputeOffsets(SemanticsContext &context, Scope &scope) {
|
|
|
|
ComputeOffsetsHelper{context}.Compute(scope);
|
2020-04-23 06:39:24 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace Fortran::semantics
|