1717#include " flang/Semantics/symbol.h"
1818#include " flang/Semantics/tools.h"
1919#include " flang/Semantics/type.h"
20+ #include " llvm/TargetParser/Host.h"
21+ #include " llvm/TargetParser/Triple.h"
2022#include < algorithm>
2123#include < vector>
2224
@@ -51,9 +53,12 @@ class ComputeOffsetsHelper {
5153 SymbolAndOffset Resolve (const SymbolAndOffset &);
5254 std::size_t ComputeOffset (const EquivalenceObject &);
5355 // Returns amount of padding that was needed for alignment
54- std::size_t DoSymbol (Symbol &);
56+ std::size_t DoSymbol (
57+ Symbol &, std::optional<const size_t > newAlign = std::nullopt );
5558 SizeAndAlignment GetSizeAndAlignment (const Symbol &, bool entire);
5659 std::size_t Align (std::size_t , std::size_t );
60+ std::optional<size_t > CompAlignment (const Symbol &);
61+ std::optional<size_t > HasSpecialAlign (const Symbol &, Scope &);
5762
5863 SemanticsContext &context_;
5964 std::size_t offset_{0 };
@@ -65,6 +70,69 @@ class ComputeOffsetsHelper {
6570 equivalenceBlock_;
6671};
6772
73+ // This function is only called if the target platform is AIX.
74+ static bool isReal8OrLarger (const Fortran::semantics::DeclTypeSpec *type) {
75+ return ((type->IsNumeric (common::TypeCategory::Real) ||
76+ type->IsNumeric (common::TypeCategory::Complex)) &&
77+ evaluate::ToInt64 (type->numericTypeSpec ().kind ()) > 4 );
78+ }
79+
80+ // This function is only called if the target platform is AIX.
81+ // It determines the alignment of a component. If the component is a derived
82+ // type, the alignment is computed accordingly.
83+ std::optional<size_t > ComputeOffsetsHelper::CompAlignment (const Symbol &sym) {
84+ size_t max_align{0 };
85+ constexpr size_t fourByteAlign{4 };
86+ bool contain_double{false };
87+ auto derivedTypeSpec{sym.GetType ()->AsDerived ()};
88+ DirectComponentIterator directs{*derivedTypeSpec};
89+ for (auto it{directs.begin ()}; it != directs.end (); ++it) {
90+ auto type{it->GetType ()};
91+ auto s{GetSizeAndAlignment (*it, true )};
92+ if (isReal8OrLarger (type)) {
93+ max_align = std::max (max_align, fourByteAlign);
94+ contain_double = true ;
95+ } else if (type->AsDerived ()) {
96+ if (const auto newAlgin{CompAlignment (*it)}) {
97+ max_align = std::max (max_align, s.alignment );
98+ } else {
99+ return std::nullopt ;
100+ }
101+ } else {
102+ max_align = std::max (max_align, s.alignment );
103+ }
104+ }
105+
106+ if (contain_double) {
107+ return max_align;
108+ } else {
109+ return std::nullopt ;
110+ }
111+ }
112+
113+ // This function is only called if the target platform is AIX.
114+ // Special alignment is needed only if it is a bind(c) derived type
115+ // and contain real type components that have larger than 4 bytes.
116+ std::optional<size_t > ComputeOffsetsHelper::HasSpecialAlign (
117+ const Symbol &sym, Scope &scope) {
118+ // On AIX, if the component that is not the first component and is
119+ // a float of 8 bytes or larger, it has the 4-byte alignment.
120+ // Only set the special alignment for bind(c) derived type on that platform.
121+ if (const auto type{sym.GetType ()}) {
122+ auto &symOwner{sym.owner ()};
123+ if (symOwner.symbol () && symOwner.IsDerivedType () &&
124+ symOwner.symbol ()->attrs ().HasAny ({semantics::Attr::BIND_C}) &&
125+ &sym != &(*scope.GetSymbols ().front ())) {
126+ if (isReal8OrLarger (type)) {
127+ return 4UL ;
128+ } else if (type->AsDerived ()) {
129+ return CompAlignment (sym);
130+ }
131+ }
132+ }
133+ return std::nullopt ;
134+ }
135+
68136void ComputeOffsetsHelper::Compute (Scope &scope) {
69137 for (Scope &child : scope.children ()) {
70138 ComputeOffsets (context_, child);
@@ -113,7 +181,15 @@ void ComputeOffsetsHelper::Compute(Scope &scope) {
113181 if (!FindCommonBlockContaining (*symbol) &&
114182 dependents_.find (symbol) == dependents_.end () &&
115183 equivalenceBlock_.find (symbol) == equivalenceBlock_.end ()) {
116- DoSymbol (*symbol);
184+
185+ std::optional<size_t > newAlign{std::nullopt };
186+ // Handle special alignment requirement for AIX
187+ auto triple{llvm::Triple (
188+ llvm::Triple::normalize (llvm::sys::getDefaultTargetTriple ()))};
189+ if (triple.getOS () == llvm::Triple::OSType::AIX) {
190+ newAlign = HasSpecialAlign (*symbol, scope);
191+ }
192+ DoSymbol (*symbol, newAlign);
117193 if (auto *generic{symbol->detailsIf <GenericDetails>()}) {
118194 if (Symbol * specific{generic->specific ()};
119195 specific && !FindCommonBlockContaining (*specific)) {
@@ -313,7 +389,8 @@ std::size_t ComputeOffsetsHelper::ComputeOffset(
313389 return result;
314390}
315391
316- std::size_t ComputeOffsetsHelper::DoSymbol (Symbol &symbol) {
392+ std::size_t ComputeOffsetsHelper::DoSymbol (
393+ Symbol &symbol, std::optional<const size_t > newAlign) {
317394 if (!symbol.has <ObjectEntityDetails>() && !symbol.has <ProcEntityDetails>()) {
318395 return 0 ;
319396 }
@@ -322,12 +399,13 @@ std::size_t ComputeOffsetsHelper::DoSymbol(Symbol &symbol) {
322399 return 0 ;
323400 }
324401 std::size_t previousOffset{offset_};
325- offset_ = Align (offset_, s.alignment );
402+ size_t alignVal{newAlign.value_or (s.alignment )};
403+ offset_ = Align (offset_, alignVal);
326404 std::size_t padding{offset_ - previousOffset};
327405 symbol.set_size (s.size );
328406 symbol.set_offset (offset_);
329407 offset_ += s.size ;
330- alignment_ = std::max (alignment_, s. alignment );
408+ alignment_ = std::max (alignment_, alignVal );
331409 return padding;
332410}
333411
0 commit comments