1d1862eb8Speter klausler //===-- lib/Semantics/compute-offsets.cpp -----------------------*- C++ -*-===// 2c353ebbfSTim Keith // 3c353ebbfSTim Keith // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4c353ebbfSTim Keith // See https://llvm.org/LICENSE.txt for license information. 5c353ebbfSTim Keith // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6c353ebbfSTim Keith // 7c353ebbfSTim Keith //===----------------------------------------------------------------------===// 8c353ebbfSTim Keith 9c353ebbfSTim Keith #include "compute-offsets.h" 1031e6cd28Speter klausler #include "flang/Evaluate/fold-designator.h" 11c353ebbfSTim Keith #include "flang/Evaluate/fold.h" 12c353ebbfSTim Keith #include "flang/Evaluate/shape.h" 13c353ebbfSTim Keith #include "flang/Evaluate/type.h" 14c91ba043SMichael Kruse #include "flang/Runtime/descriptor-consts.h" 15c353ebbfSTim Keith #include "flang/Semantics/scope.h" 16c353ebbfSTim Keith #include "flang/Semantics/semantics.h" 17c353ebbfSTim Keith #include "flang/Semantics/symbol.h" 18c353ebbfSTim Keith #include "flang/Semantics/tools.h" 19c353ebbfSTim Keith #include "flang/Semantics/type.h" 20*79e788d0SKelvin Li #include "llvm/TargetParser/Host.h" 21*79e788d0SKelvin Li #include "llvm/TargetParser/Triple.h" 22c353ebbfSTim Keith #include <algorithm> 23c353ebbfSTim Keith #include <vector> 24c353ebbfSTim Keith 25c353ebbfSTim Keith namespace Fortran::semantics { 26c353ebbfSTim Keith 27c353ebbfSTim Keith class ComputeOffsetsHelper { 28c353ebbfSTim Keith public: 29c353ebbfSTim Keith ComputeOffsetsHelper(SemanticsContext &context) : context_{context} {} 306aa3591eSpeter klausler void Compute(Scope &); 31c353ebbfSTim Keith 32c353ebbfSTim Keith private: 3354b35c06STim Keith struct SizeAndAlignment { 3454b35c06STim Keith SizeAndAlignment() {} 35d1862eb8Speter klausler SizeAndAlignment(std::size_t bytes) : size{bytes}, alignment{bytes} {} 36d1862eb8Speter klausler SizeAndAlignment(std::size_t bytes, std::size_t align) 37d1862eb8Speter klausler : size{bytes}, alignment{align} {} 38c353ebbfSTim Keith std::size_t size{0}; 3954b35c06STim Keith std::size_t alignment{0}; 40c353ebbfSTim Keith }; 41237d0e3cSTim Keith struct SymbolAndOffset { 4231e6cd28Speter klausler SymbolAndOffset(Symbol &s, std::size_t off, const EquivalenceObject &obj) 43d60a0220Speter klausler : symbol{s}, offset{off}, object{&obj} {} 4431e6cd28Speter klausler SymbolAndOffset(const SymbolAndOffset &) = default; 45d60a0220Speter klausler MutableSymbolRef symbol; 4631e6cd28Speter klausler std::size_t offset; 4731e6cd28Speter klausler const EquivalenceObject *object; 48237d0e3cSTim Keith }; 49c353ebbfSTim Keith 50237d0e3cSTim Keith void DoCommonBlock(Symbol &); 514ac617f4Speter klausler void DoEquivalenceBlockBase(Symbol &, SizeAndAlignment &); 5231e6cd28Speter klausler void DoEquivalenceSet(const EquivalenceSet &); 5331e6cd28Speter klausler SymbolAndOffset Resolve(const SymbolAndOffset &); 54237d0e3cSTim Keith std::size_t ComputeOffset(const EquivalenceObject &); 55c709f503SPeter Klausler // Returns amount of padding that was needed for alignment 56*79e788d0SKelvin Li std::size_t DoSymbol( 57*79e788d0SKelvin Li Symbol &, std::optional<const size_t> newAlign = std::nullopt); 586aa3591eSpeter klausler SizeAndAlignment GetSizeAndAlignment(const Symbol &, bool entire); 596aa3591eSpeter klausler std::size_t Align(std::size_t, std::size_t); 60*79e788d0SKelvin Li std::optional<size_t> CompAlignment(const Symbol &); 61*79e788d0SKelvin Li std::optional<size_t> HasSpecialAlign(const Symbol &, Scope &); 62c353ebbfSTim Keith 63c353ebbfSTim Keith SemanticsContext &context_; 64c353ebbfSTim Keith std::size_t offset_{0}; 656aa3591eSpeter klausler std::size_t alignment_{1}; 66237d0e3cSTim Keith // symbol -> symbol+offset that determines its location, from EQUIVALENCE 670d8331c0Speter klausler std::map<MutableSymbolRef, SymbolAndOffset, SymbolAddressCompare> dependents_; 684ac617f4Speter klausler // base symbol -> SizeAndAlignment for each distinct EQUIVALENCE block 690d8331c0Speter klausler std::map<MutableSymbolRef, SizeAndAlignment, SymbolAddressCompare> 700d8331c0Speter klausler equivalenceBlock_; 71c353ebbfSTim Keith }; 72c353ebbfSTim Keith 73*79e788d0SKelvin Li // This function is only called if the target platform is AIX. 74*79e788d0SKelvin Li static bool isReal8OrLarger(const Fortran::semantics::DeclTypeSpec *type) { 75*79e788d0SKelvin Li return ((type->IsNumeric(common::TypeCategory::Real) || 76*79e788d0SKelvin Li type->IsNumeric(common::TypeCategory::Complex)) && 77*79e788d0SKelvin Li evaluate::ToInt64(type->numericTypeSpec().kind()) > 4); 78*79e788d0SKelvin Li } 79*79e788d0SKelvin Li 80*79e788d0SKelvin Li // This function is only called if the target platform is AIX. 81*79e788d0SKelvin Li // It determines the alignment of a component. If the component is a derived 82*79e788d0SKelvin Li // type, the alignment is computed accordingly. 83*79e788d0SKelvin Li std::optional<size_t> ComputeOffsetsHelper::CompAlignment(const Symbol &sym) { 84*79e788d0SKelvin Li size_t max_align{0}; 85*79e788d0SKelvin Li constexpr size_t fourByteAlign{4}; 86*79e788d0SKelvin Li bool contain_double{false}; 87*79e788d0SKelvin Li auto derivedTypeSpec{sym.GetType()->AsDerived()}; 88*79e788d0SKelvin Li DirectComponentIterator directs{*derivedTypeSpec}; 89*79e788d0SKelvin Li for (auto it{directs.begin()}; it != directs.end(); ++it) { 90*79e788d0SKelvin Li auto type{it->GetType()}; 91*79e788d0SKelvin Li auto s{GetSizeAndAlignment(*it, true)}; 92*79e788d0SKelvin Li if (isReal8OrLarger(type)) { 93*79e788d0SKelvin Li max_align = std::max(max_align, fourByteAlign); 94*79e788d0SKelvin Li contain_double = true; 95*79e788d0SKelvin Li } else if (type->AsDerived()) { 96*79e788d0SKelvin Li if (const auto newAlgin{CompAlignment(*it)}) { 97*79e788d0SKelvin Li max_align = std::max(max_align, s.alignment); 98*79e788d0SKelvin Li } else { 99*79e788d0SKelvin Li return std::nullopt; 100*79e788d0SKelvin Li } 101*79e788d0SKelvin Li } else { 102*79e788d0SKelvin Li max_align = std::max(max_align, s.alignment); 103*79e788d0SKelvin Li } 104*79e788d0SKelvin Li } 105*79e788d0SKelvin Li 106*79e788d0SKelvin Li if (contain_double) { 107*79e788d0SKelvin Li return max_align; 108*79e788d0SKelvin Li } else { 109*79e788d0SKelvin Li return std::nullopt; 110*79e788d0SKelvin Li } 111*79e788d0SKelvin Li } 112*79e788d0SKelvin Li 113*79e788d0SKelvin Li // This function is only called if the target platform is AIX. 114*79e788d0SKelvin Li // Special alignment is needed only if it is a bind(c) derived type 115*79e788d0SKelvin Li // and contain real type components that have larger than 4 bytes. 116*79e788d0SKelvin Li std::optional<size_t> ComputeOffsetsHelper::HasSpecialAlign( 117*79e788d0SKelvin Li const Symbol &sym, Scope &scope) { 118*79e788d0SKelvin Li // On AIX, if the component that is not the first component and is 119*79e788d0SKelvin Li // a float of 8 bytes or larger, it has the 4-byte alignment. 120*79e788d0SKelvin Li // Only set the special alignment for bind(c) derived type on that platform. 121*79e788d0SKelvin Li if (const auto type{sym.GetType()}) { 122*79e788d0SKelvin Li auto &symOwner{sym.owner()}; 123*79e788d0SKelvin Li if (symOwner.symbol() && symOwner.IsDerivedType() && 124*79e788d0SKelvin Li symOwner.symbol()->attrs().HasAny({semantics::Attr::BIND_C}) && 125*79e788d0SKelvin Li &sym != &(*scope.GetSymbols().front())) { 126*79e788d0SKelvin Li if (isReal8OrLarger(type)) { 127*79e788d0SKelvin Li return 4UL; 128*79e788d0SKelvin Li } else if (type->AsDerived()) { 129*79e788d0SKelvin Li return CompAlignment(sym); 130*79e788d0SKelvin Li } 131*79e788d0SKelvin Li } 132*79e788d0SKelvin Li } 133*79e788d0SKelvin Li return std::nullopt; 134*79e788d0SKelvin Li } 135*79e788d0SKelvin Li 136c353ebbfSTim Keith void ComputeOffsetsHelper::Compute(Scope &scope) { 137c353ebbfSTim Keith for (Scope &child : scope.children()) { 1386aa3591eSpeter klausler ComputeOffsets(context_, child); 139c353ebbfSTim Keith } 140f2da8f5eSJean Perier if (scope.symbol() && scope.IsDerivedTypeWithKindParameter()) { 141f88a9497SJean Perier return; // only process instantiations of kind parameterized derived types 142c353ebbfSTim Keith } 1434fede8bcSpeter klausler if (scope.alignment().has_value()) { 1444fede8bcSpeter klausler return; // prevent infinite recursion in error cases 1454fede8bcSpeter klausler } 1464fede8bcSpeter klausler scope.SetAlignment(0); 147237d0e3cSTim Keith // Build dependents_ from equivalences: symbol -> symbol+offset 14831e6cd28Speter klausler for (const EquivalenceSet &set : scope.equivalenceSets()) { 149237d0e3cSTim Keith DoEquivalenceSet(set); 150237d0e3cSTim Keith } 1514ac617f4Speter klausler // Compute a base symbol and overall block size for each 1524ac617f4Speter klausler // disjoint EQUIVALENCE storage sequence. 1534ac617f4Speter klausler for (auto &[symbol, dep] : dependents_) { 1544ac617f4Speter klausler dep = Resolve(dep); 1554ac617f4Speter klausler CHECK(symbol->size() == 0); 1566aa3591eSpeter klausler auto symInfo{GetSizeAndAlignment(*symbol, true)}; 1574ac617f4Speter klausler symbol->set_size(symInfo.size); 1584ac617f4Speter klausler Symbol &base{*dep.symbol}; 1594ac617f4Speter klausler auto iter{equivalenceBlock_.find(base)}; 1604ac617f4Speter klausler std::size_t minBlockSize{dep.offset + symInfo.size}; 1614ac617f4Speter klausler if (iter == equivalenceBlock_.end()) { 1624ac617f4Speter klausler equivalenceBlock_.emplace( 1634ac617f4Speter klausler base, SizeAndAlignment{minBlockSize, symInfo.alignment}); 1644ac617f4Speter klausler } else { 1654ac617f4Speter klausler SizeAndAlignment &blockInfo{iter->second}; 1664ac617f4Speter klausler blockInfo.size = std::max(blockInfo.size, minBlockSize); 1674ac617f4Speter klausler blockInfo.alignment = std::max(blockInfo.alignment, symInfo.alignment); 1684ac617f4Speter klausler } 1694ac617f4Speter klausler } 1704ac617f4Speter klausler // Assign offsets for non-COMMON EQUIVALENCE blocks 1714ac617f4Speter klausler for (auto &[symbol, blockInfo] : equivalenceBlock_) { 17205e62db2SPeter Klausler if (!FindCommonBlockContaining(*symbol)) { 1734ac617f4Speter klausler DoSymbol(*symbol); 1744ac617f4Speter klausler DoEquivalenceBlockBase(*symbol, blockInfo); 1754ac617f4Speter klausler offset_ = std::max(offset_, symbol->offset() + blockInfo.size); 1764ac617f4Speter klausler } 1774ac617f4Speter klausler } 1784ac617f4Speter klausler // Process remaining non-COMMON symbols; this is all of them if there 1794ac617f4Speter klausler // was no use of EQUIVALENCE in the scope. 180237d0e3cSTim Keith for (auto &symbol : scope.GetSymbols()) { 18105e62db2SPeter Klausler if (!FindCommonBlockContaining(*symbol) && 1824ac617f4Speter klausler dependents_.find(symbol) == dependents_.end() && 1834ac617f4Speter klausler equivalenceBlock_.find(symbol) == equivalenceBlock_.end()) { 184*79e788d0SKelvin Li 185*79e788d0SKelvin Li std::optional<size_t> newAlign{std::nullopt}; 186*79e788d0SKelvin Li // Handle special alignment requirement for AIX 187*79e788d0SKelvin Li auto triple{llvm::Triple( 188*79e788d0SKelvin Li llvm::Triple::normalize(llvm::sys::getDefaultTargetTriple()))}; 189*79e788d0SKelvin Li if (triple.getOS() == llvm::Triple::OSType::AIX) { 190*79e788d0SKelvin Li newAlign = HasSpecialAlign(*symbol, scope); 191*79e788d0SKelvin Li } 192*79e788d0SKelvin Li DoSymbol(*symbol, newAlign); 193d418a03eSPeter Klausler if (auto *generic{symbol->detailsIf<GenericDetails>()}) { 194d418a03eSPeter Klausler if (Symbol * specific{generic->specific()}; 195d418a03eSPeter Klausler specific && !FindCommonBlockContaining(*specific)) { 196d418a03eSPeter Klausler // might be a shadowed procedure pointer 197d418a03eSPeter Klausler DoSymbol(*specific); 198d418a03eSPeter Klausler } 199d418a03eSPeter Klausler } 200c353ebbfSTim Keith } 201c353ebbfSTim Keith } 20208d6b874SPeter Klausler // Ensure that the size is a multiple of the alignment 20308d6b874SPeter Klausler offset_ = Align(offset_, alignment_); 204c353ebbfSTim Keith scope.set_size(offset_); 2054fede8bcSpeter klausler scope.SetAlignment(alignment_); 206b2c96d78SEmil Kieri // Assign offsets in COMMON blocks, unless this scope is a BLOCK construct, 207b2c96d78SEmil Kieri // where COMMON blocks are illegal (C1107 and C1108). 208b2c96d78SEmil Kieri if (scope.kind() != Scope::Kind::BlockConstruct) { 2094ac617f4Speter klausler for (auto &pair : scope.commonBlocks()) { 2104ac617f4Speter klausler DoCommonBlock(*pair.second); 2114ac617f4Speter klausler } 212b2c96d78SEmil Kieri } 2134ac617f4Speter klausler for (auto &[symbol, dep] : dependents_) { 2144ac617f4Speter klausler symbol->set_offset(dep.symbol->offset() + dep.offset); 2154ac617f4Speter klausler if (const auto *block{FindCommonBlockContaining(*dep.symbol)}) { 2164ac617f4Speter klausler symbol->get<ObjectEntityDetails>().set_commonBlock(*block); 2174ac617f4Speter klausler } 2184ac617f4Speter klausler } 219c353ebbfSTim Keith } 220c353ebbfSTim Keith 22131e6cd28Speter klausler auto ComputeOffsetsHelper::Resolve(const SymbolAndOffset &dep) 22231e6cd28Speter klausler -> SymbolAndOffset { 223237d0e3cSTim Keith auto it{dependents_.find(*dep.symbol)}; 224237d0e3cSTim Keith if (it == dependents_.end()) { 22531e6cd28Speter klausler return dep; 226237d0e3cSTim Keith } else { 22731e6cd28Speter klausler SymbolAndOffset result{Resolve(it->second)}; 22831e6cd28Speter klausler result.offset += dep.offset; 22931e6cd28Speter klausler result.object = dep.object; 23031e6cd28Speter klausler return result; 231237d0e3cSTim Keith } 232237d0e3cSTim Keith } 233237d0e3cSTim Keith 234237d0e3cSTim Keith void ComputeOffsetsHelper::DoCommonBlock(Symbol &commonBlock) { 235237d0e3cSTim Keith auto &details{commonBlock.get<CommonBlockDetails>()}; 236237d0e3cSTim Keith offset_ = 0; 23754b35c06STim Keith alignment_ = 0; 2384ac617f4Speter klausler std::size_t minSize{0}; 2394ac617f4Speter klausler std::size_t minAlignment{0}; 24094b4a986SPeter Klausler UnorderedSymbolSet previous; 24194b4a986SPeter Klausler for (auto object : details.objects()) { 2424ac617f4Speter klausler Symbol &symbol{*object}; 243c709f503SPeter Klausler auto errorSite{ 244c709f503SPeter Klausler commonBlock.name().empty() ? symbol.name() : commonBlock.name()}; 2454e43a14bSPeixin Qiao if (std::size_t padding{DoSymbol(symbol.GetUltimate())}) { 2460f973ac7SPeter Klausler context_.Warn(common::UsageWarning::CommonBlockPadding, errorSite, 247c709f503SPeter Klausler "COMMON block /%s/ requires %zd bytes of padding before '%s' for alignment"_port_en_US, 248c709f503SPeter Klausler commonBlock.name(), padding, symbol.name()); 249c709f503SPeter Klausler } 25094b4a986SPeter Klausler previous.emplace(symbol); 251084d8bebSJean Perier auto eqIter{equivalenceBlock_.end()}; 2524ac617f4Speter klausler auto iter{dependents_.find(symbol)}; 2534ac617f4Speter klausler if (iter == dependents_.end()) { 254d892d732SJean Perier eqIter = equivalenceBlock_.find(symbol); 2554ac617f4Speter klausler if (eqIter != equivalenceBlock_.end()) { 256084d8bebSJean Perier DoEquivalenceBlockBase(symbol, eqIter->second); 257237d0e3cSTim Keith } 2584ac617f4Speter klausler } else { 2594ac617f4Speter klausler SymbolAndOffset &dep{iter->second}; 2604ac617f4Speter klausler Symbol &base{*dep.symbol}; 2614ac617f4Speter klausler if (const auto *baseBlock{FindCommonBlockContaining(base)}) { 2624ac617f4Speter klausler if (baseBlock == &commonBlock) { 26394b4a986SPeter Klausler if (previous.find(SymbolRef{base}) == previous.end() || 26494b4a986SPeter Klausler base.offset() != symbol.offset() - dep.offset) { 2654ac617f4Speter klausler context_.Say(errorSite, 2664ac617f4Speter klausler "'%s' is storage associated with '%s' by EQUIVALENCE elsewhere in COMMON block /%s/"_err_en_US, 2674ac617f4Speter klausler symbol.name(), base.name(), commonBlock.name()); 268166563fdSPeter Klausler } 26994b4a986SPeter Klausler } else { // F'2023 8.10.3 p1 2704ac617f4Speter klausler context_.Say(errorSite, 2714ac617f4Speter klausler "'%s' in COMMON block /%s/ must not be storage associated with '%s' in COMMON block /%s/ by EQUIVALENCE"_err_en_US, 2724ac617f4Speter klausler symbol.name(), commonBlock.name(), base.name(), 2734ac617f4Speter klausler baseBlock->name()); 2744ac617f4Speter klausler } 2754ac617f4Speter klausler } else if (dep.offset > symbol.offset()) { // 8.10.3(3) 2764ac617f4Speter klausler context_.Say(errorSite, 2774ac617f4Speter klausler "'%s' cannot backward-extend COMMON block /%s/ via EQUIVALENCE with '%s'"_err_en_US, 2784ac617f4Speter klausler symbol.name(), commonBlock.name(), base.name()); 2794ac617f4Speter klausler } else { 280084d8bebSJean Perier eqIter = equivalenceBlock_.find(base); 2814ac617f4Speter klausler base.get<ObjectEntityDetails>().set_commonBlock(commonBlock); 2824ac617f4Speter klausler base.set_offset(symbol.offset() - dep.offset); 28394b4a986SPeter Klausler previous.emplace(base); 2844ac617f4Speter klausler } 2854ac617f4Speter klausler } 286084d8bebSJean Perier // Get full extent of any EQUIVALENCE block into size of COMMON ( see 287084d8bebSJean Perier // 8.10.2.2 point 1 (2)) 288084d8bebSJean Perier if (eqIter != equivalenceBlock_.end()) { 289084d8bebSJean Perier SizeAndAlignment &blockInfo{eqIter->second}; 290084d8bebSJean Perier minSize = std::max( 291084d8bebSJean Perier minSize, std::max(offset_, eqIter->first->offset() + blockInfo.size)); 292084d8bebSJean Perier minAlignment = std::max(minAlignment, blockInfo.alignment); 293084d8bebSJean Perier } 2944ac617f4Speter klausler } 2954ac617f4Speter klausler commonBlock.set_size(std::max(minSize, offset_)); 2964ac617f4Speter klausler details.set_alignment(std::max(minAlignment, alignment_)); 2972c8cb9acSJean Perier context_.MapCommonBlockAndCheckConflicts(commonBlock); 2984ac617f4Speter klausler } 2994ac617f4Speter klausler 3004ac617f4Speter klausler void ComputeOffsetsHelper::DoEquivalenceBlockBase( 3014ac617f4Speter klausler Symbol &symbol, SizeAndAlignment &blockInfo) { 3024ac617f4Speter klausler if (symbol.size() > blockInfo.size) { 3034ac617f4Speter klausler blockInfo.size = symbol.size(); 3044ac617f4Speter klausler } 305237d0e3cSTim Keith } 306237d0e3cSTim Keith 30731e6cd28Speter klausler void ComputeOffsetsHelper::DoEquivalenceSet(const EquivalenceSet &set) { 308237d0e3cSTim Keith std::vector<SymbolAndOffset> symbolOffsets; 30931e6cd28Speter klausler std::optional<std::size_t> representative; 31031e6cd28Speter klausler for (const EquivalenceObject &object : set) { 311237d0e3cSTim Keith std::size_t offset{ComputeOffset(object)}; 31231e6cd28Speter klausler SymbolAndOffset resolved{ 31331e6cd28Speter klausler Resolve(SymbolAndOffset{object.symbol, offset, object})}; 31431e6cd28Speter klausler symbolOffsets.push_back(resolved); 31531e6cd28Speter klausler if (!representative || 31631e6cd28Speter klausler resolved.offset >= symbolOffsets[*representative].offset) { 31731e6cd28Speter klausler // The equivalenced object with the largest offset from its resolved 31831e6cd28Speter klausler // symbol will be the representative of this set, since the offsets 31931e6cd28Speter klausler // of the other objects will be positive relative to it. 32031e6cd28Speter klausler representative = symbolOffsets.size() - 1; 321237d0e3cSTim Keith } 322237d0e3cSTim Keith } 32331e6cd28Speter klausler CHECK(representative); 32431e6cd28Speter klausler const SymbolAndOffset &base{symbolOffsets[*representative]}; 32531e6cd28Speter klausler for (const auto &[symbol, offset, object] : symbolOffsets) { 32631e6cd28Speter klausler if (symbol == base.symbol) { 32731e6cd28Speter klausler if (offset != base.offset) { 32831e6cd28Speter klausler auto x{evaluate::OffsetToDesignator( 32931e6cd28Speter klausler context_.foldingContext(), *symbol, base.offset, 1)}; 33031e6cd28Speter klausler auto y{evaluate::OffsetToDesignator( 33131e6cd28Speter klausler context_.foldingContext(), *symbol, offset, 1)}; 33231e6cd28Speter klausler if (x && y) { 33331e6cd28Speter klausler context_ 33431e6cd28Speter klausler .Say(base.object->source, 33531e6cd28Speter klausler "'%s' and '%s' cannot have the same first storage unit"_err_en_US, 33631e6cd28Speter klausler x->AsFortran(), y->AsFortran()) 33731e6cd28Speter klausler .Attach(object->source, "Incompatible reference to '%s'"_en_US, 33831e6cd28Speter klausler y->AsFortran()); 33931e6cd28Speter klausler } else { // error recovery 34031e6cd28Speter klausler context_ 34131e6cd28Speter klausler .Say(base.object->source, 34231e6cd28Speter klausler "'%s' (offset %zd bytes and %zd bytes) cannot have the same first storage unit"_err_en_US, 34331e6cd28Speter klausler symbol->name(), base.offset, offset) 34431e6cd28Speter klausler .Attach(object->source, 34531e6cd28Speter klausler "Incompatible reference to '%s' offset %zd bytes"_en_US, 34631e6cd28Speter klausler symbol->name(), offset); 34731e6cd28Speter klausler } 34831e6cd28Speter klausler } 34931e6cd28Speter klausler } else { 35031e6cd28Speter klausler dependents_.emplace(*symbol, 35131e6cd28Speter klausler SymbolAndOffset{*base.symbol, base.offset - offset, *object}); 352237d0e3cSTim Keith } 353237d0e3cSTim Keith } 354237d0e3cSTim Keith } 355237d0e3cSTim Keith 356237d0e3cSTim Keith // Offset of this equivalence object from the start of its variable. 357237d0e3cSTim Keith std::size_t ComputeOffsetsHelper::ComputeOffset( 358237d0e3cSTim Keith const EquivalenceObject &object) { 359237d0e3cSTim Keith std::size_t offset{0}; 360237d0e3cSTim Keith if (!object.subscripts.empty()) { 361d742c2aaSPeter Klausler if (const auto *details{object.symbol.detailsIf<ObjectEntityDetails>()}) { 362d742c2aaSPeter Klausler const ArraySpec &shape{details->shape()}; 363237d0e3cSTim Keith auto lbound{[&](std::size_t i) { 364237d0e3cSTim Keith return *ToInt64(shape[i].lbound().GetExplicit()); 365237d0e3cSTim Keith }}; 366237d0e3cSTim Keith auto ubound{[&](std::size_t i) { 367237d0e3cSTim Keith return *ToInt64(shape[i].ubound().GetExplicit()); 368237d0e3cSTim Keith }}; 369237d0e3cSTim Keith for (std::size_t i{object.subscripts.size() - 1};;) { 370237d0e3cSTim Keith offset += object.subscripts[i] - lbound(i); 371237d0e3cSTim Keith if (i == 0) { 372237d0e3cSTim Keith break; 373237d0e3cSTim Keith } 374237d0e3cSTim Keith --i; 375237d0e3cSTim Keith offset *= ubound(i) - lbound(i) + 1; 376237d0e3cSTim Keith } 377237d0e3cSTim Keith } 378d742c2aaSPeter Klausler } 3796aa3591eSpeter klausler auto result{offset * GetSizeAndAlignment(object.symbol, false).size}; 38031e6cd28Speter klausler if (object.substringStart) { 38131e6cd28Speter klausler int kind{context_.defaultKinds().GetDefaultKind(TypeCategory::Character)}; 38231e6cd28Speter klausler if (const DeclTypeSpec * type{object.symbol.GetType()}) { 38331e6cd28Speter klausler if (const IntrinsicTypeSpec * intrinsic{type->AsIntrinsic()}) { 38431e6cd28Speter klausler kind = ToInt64(intrinsic->kind()).value_or(kind); 38531e6cd28Speter klausler } 38631e6cd28Speter klausler } 38731e6cd28Speter klausler result += kind * (*object.substringStart - 1); 38831e6cd28Speter klausler } 38931e6cd28Speter klausler return result; 390237d0e3cSTim Keith } 391237d0e3cSTim Keith 392*79e788d0SKelvin Li std::size_t ComputeOffsetsHelper::DoSymbol( 393*79e788d0SKelvin Li Symbol &symbol, std::optional<const size_t> newAlign) { 394044a71d8STim Keith if (!symbol.has<ObjectEntityDetails>() && !symbol.has<ProcEntityDetails>()) { 395c709f503SPeter Klausler return 0; 396237d0e3cSTim Keith } 3976aa3591eSpeter klausler SizeAndAlignment s{GetSizeAndAlignment(symbol, true)}; 398c353ebbfSTim Keith if (s.size == 0) { 399c709f503SPeter Klausler return 0; 400c353ebbfSTim Keith } 401c709f503SPeter Klausler std::size_t previousOffset{offset_}; 402*79e788d0SKelvin Li size_t alignVal{newAlign.value_or(s.alignment)}; 403*79e788d0SKelvin Li offset_ = Align(offset_, alignVal); 404c709f503SPeter Klausler std::size_t padding{offset_ - previousOffset}; 405c353ebbfSTim Keith symbol.set_size(s.size); 406c353ebbfSTim Keith symbol.set_offset(offset_); 407c353ebbfSTim Keith offset_ += s.size; 408*79e788d0SKelvin Li alignment_ = std::max(alignment_, alignVal); 409c709f503SPeter Klausler return padding; 410c353ebbfSTim Keith } 411c353ebbfSTim Keith 4126aa3591eSpeter klausler auto ComputeOffsetsHelper::GetSizeAndAlignment( 4136aa3591eSpeter klausler const Symbol &symbol, bool entire) -> SizeAndAlignment { 41423c2bedfSPeter Klausler auto &targetCharacteristics{context_.targetCharacteristics()}; 41523c2bedfSPeter Klausler if (IsDescriptor(symbol)) { 416392173daSPeter Klausler auto dyType{evaluate::DynamicType::From(symbol)}; 417392173daSPeter Klausler const auto *derived{evaluate::GetDerivedTypeSpec(dyType)}; 418a48e4168Speter klausler int lenParams{derived ? CountLenParameters(*derived) : 0}; 419392173daSPeter Klausler bool needAddendum{derived || (dyType && dyType->IsUnlimitedPolymorphic())}; 420c91ba043SMichael Kruse 421c91ba043SMichael Kruse // FIXME: Get descriptor size from targetCharacteristics instead 422c91ba043SMichael Kruse // overapproximation 423c91ba043SMichael Kruse std::size_t size{runtime::MaxDescriptorSizeInBytes( 424392173daSPeter Klausler symbol.Rank(), needAddendum, lenParams)}; 425c91ba043SMichael Kruse 42623c2bedfSPeter Klausler return {size, targetCharacteristics.descriptorAlignment()}; 42723c2bedfSPeter Klausler } 42823c2bedfSPeter Klausler if (IsProcedurePointer(symbol)) { 42923c2bedfSPeter Klausler return {targetCharacteristics.procedurePointerByteSize(), 43023c2bedfSPeter Klausler targetCharacteristics.procedurePointerAlignment()}; 431c353ebbfSTim Keith } 4322c662f3dSTim Keith if (IsProcedure(symbol)) { 4332c662f3dSTim Keith return {}; 4342c662f3dSTim Keith } 43523c2bedfSPeter Klausler auto &foldingContext{context_.foldingContext()}; 4366aa3591eSpeter klausler if (auto chars{evaluate::characteristics::TypeAndShape::Characterize( 4376aa3591eSpeter klausler symbol, foldingContext)}) { 4386aa3591eSpeter klausler if (entire) { 4396aa3591eSpeter klausler if (auto size{ToInt64(chars->MeasureSizeInBytes(foldingContext))}) { 4406aa3591eSpeter klausler return {static_cast<std::size_t>(*size), 44123c2bedfSPeter Klausler chars->type().GetAlignment(targetCharacteristics)}; 442c353ebbfSTim Keith } 4436aa3591eSpeter klausler } else { // element size only 444efc5926cSpeter klausler if (auto size{ToInt64(chars->MeasureElementSizeInBytes( 4456aa3591eSpeter klausler foldingContext, true /*aligned*/))}) { 4466aa3591eSpeter klausler return {static_cast<std::size_t>(*size), 44723c2bedfSPeter Klausler chars->type().GetAlignment(targetCharacteristics)}; 448c353ebbfSTim Keith } 449c353ebbfSTim Keith } 450c353ebbfSTim Keith } 4516aa3591eSpeter klausler return {}; 452c353ebbfSTim Keith } 453c353ebbfSTim Keith 454c353ebbfSTim Keith // Align a size to its natural alignment, up to maxAlignment. 455c353ebbfSTim Keith std::size_t ComputeOffsetsHelper::Align(std::size_t x, std::size_t alignment) { 45623c2bedfSPeter Klausler alignment = 45723c2bedfSPeter Klausler std::min(alignment, context_.targetCharacteristics().maxAlignment()); 458c353ebbfSTim Keith return (x + alignment - 1) & -alignment; 459c353ebbfSTim Keith } 460c353ebbfSTim Keith 4616aa3591eSpeter klausler void ComputeOffsets(SemanticsContext &context, Scope &scope) { 4626aa3591eSpeter klausler ComputeOffsetsHelper{context}.Compute(scope); 463c353ebbfSTim Keith } 464c353ebbfSTim Keith 465c353ebbfSTim Keith } // namespace Fortran::semantics 466