blob: d16d420af5958ec420e8a030040fa5a2e03fc402 [file] [log] [blame]
Tim Keithc353ebb2020-04-22 22:39:241//===----------------------------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "compute-offsets.h"
10#include "../../runtime/descriptor.h"
11#include "flang/Evaluate/fold.h"
12#include "flang/Evaluate/shape.h"
13#include "flang/Evaluate/type.h"
14#include "flang/Semantics/scope.h"
15#include "flang/Semantics/semantics.h"
16#include "flang/Semantics/symbol.h"
17#include "flang/Semantics/tools.h"
18#include "flang/Semantics/type.h"
19#include <algorithm>
20#include <vector>
21
22namespace Fortran::semantics {
23
24class ComputeOffsetsHelper {
25public:
26 // TODO: configure based on target
27 static constexpr int descriptorSize{3 * 8};
28 static constexpr int maxAlignment{8};
29
30 ComputeOffsetsHelper(SemanticsContext &context) : context_{context} {}
31 void Compute() { Compute(context_.globalScope()); }
32
33private:
34 struct SizeAndAlign {
35 SizeAndAlign() {}
36 SizeAndAlign(std::size_t size) : size{size}, align{size} {}
37 SizeAndAlign(std::size_t size, std::size_t align)
38 : size{size}, align{align} {}
39 std::size_t size{0};
40 std::size_t align{0};
41 };
42
43 void Compute(Scope &);
44 void DoScope(Scope &);
45 void DoSymbol(Symbol &);
46 SizeAndAlign GetSizeAndAlign(const Symbol &);
47 std::size_t CountElements(const Symbol &);
48 static std::size_t Align(std::size_t, std::size_t);
49 static SizeAndAlign GetIntrinsicSizeAndAlign(TypeCategory, int);
50
51 SemanticsContext &context_;
52 evaluate::FoldingContext &foldingContext_{context_.foldingContext()};
53 std::size_t offset_{0};
54 std::size_t align_{0};
55};
56
57void ComputeOffsetsHelper::Compute(Scope &scope) {
58 for (Scope &child : scope.children()) {
59 Compute(child);
60 }
61 DoScope(scope);
62}
63
64void ComputeOffsetsHelper::DoScope(Scope &scope) {
65 if (scope.symbol() && scope.IsParameterizedDerivedType()) {
66 return; // only process instantiations of parameterized derived types
67 }
68 offset_ = 0;
69 align_ = 0;
70 for (auto symbol : scope.GetSymbols()) {
71 if (!symbol->has<TypeParamDetails>() && !symbol->has<SubprogramDetails>()) {
72 DoSymbol(*symbol);
73 }
74 }
75 scope.set_size(offset_);
76 scope.set_align(align_);
77}
78
79void ComputeOffsetsHelper::DoSymbol(Symbol &symbol) {
80 SizeAndAlign s{GetSizeAndAlign(symbol)};
81 if (s.size == 0) {
82 return;
83 }
84 offset_ = Align(offset_, s.align);
85 symbol.set_size(s.size);
86 symbol.set_offset(offset_);
87 offset_ += s.size;
88 if (s.align > align_) {
89 align_ = s.align;
90 }
91}
92
93auto ComputeOffsetsHelper::GetSizeAndAlign(const Symbol &symbol)
94 -> SizeAndAlign {
95 const DeclTypeSpec *type{symbol.GetType()};
96 if (!type) {
97 return {};
98 }
99 if (IsDescriptor(symbol) || IsProcedure(symbol)) {
100 int lenParams{0};
101 if (const DerivedTypeSpec * derived{type->AsDerived()}) {
102 lenParams = derived->NumLengthParameters();
103 }
104 std::size_t size{
105 runtime::Descriptor::SizeInBytes(symbol.Rank(), false, lenParams)};
106 return {size, maxAlignment};
107 }
108 SizeAndAlign result;
109 if (const IntrinsicTypeSpec * intrinsic{type->AsIntrinsic()}) {
110 if (auto kind{ToInt64(intrinsic->kind())}) {
111 result = GetIntrinsicSizeAndAlign(intrinsic->category(), *kind);
112 }
113 if (type->category() == DeclTypeSpec::Character) {
114 ParamValue length{type->characterTypeSpec().length()};
115 CHECK(length.isExplicit()); // else should be descriptor
116 if (MaybeIntExpr lengthExpr{length.GetExplicit()}) {
117 if (auto lengthInt{ToInt64(*lengthExpr)}) {
118 result.size *= *lengthInt;
119 }
120 }
121 }
122 } else if (const DerivedTypeSpec * derived{type->AsDerived()}) {
123 if (derived->scope()) {
124 result.size = derived->scope()->size();
125 result.align = derived->scope()->align();
126 }
127 } else {
128 DIE("not intrinsic or derived");
129 }
130 std::size_t elements{CountElements(symbol)};
131 if (elements > 1) {
132 result.size = Align(result.size, result.align);
133 }
134 result.size *= elements;
135 return result;
136}
137
138std::size_t ComputeOffsetsHelper::CountElements(const Symbol &symbol) {
139 if (auto shape{GetShape(foldingContext_, symbol)}) {
140 if (auto sizeExpr{evaluate::GetSize(std::move(*shape))}) {
141 if (auto size{ToInt64(Fold(foldingContext_, std::move(*sizeExpr)))}) {
142 return *size;
143 }
144 }
145 }
146 return 1;
147}
148
149// Align a size to its natural alignment, up to maxAlignment.
150std::size_t ComputeOffsetsHelper::Align(std::size_t x, std::size_t alignment) {
151 if (alignment > maxAlignment) {
152 alignment = maxAlignment;
153 }
154 return (x + alignment - 1) & -alignment;
155}
156
157auto ComputeOffsetsHelper::GetIntrinsicSizeAndAlign(
158 TypeCategory category, int kind) -> SizeAndAlign {
159 // TODO: does kind==10 need special handling?
160 std::size_t size{kind == 3 ? 2 : static_cast<std::size_t>(kind)};
161 if (category == TypeCategory::Complex) {
162 return {2 * size, size};
163 } else {
164 return {size};
165 }
166}
167
168void ComputeOffsets(SemanticsContext &context) {
169 ComputeOffsetsHelper{context}.Compute();
170}
171
172} // namespace Fortran::semantics