1 //===-- runtime/descriptor-io.h ---------------------------------*- C++ -*-===//
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 #ifndef FORTRAN_RUNTIME_DESCRIPTOR_IO_H_
10 #define FORTRAN_RUNTIME_DESCRIPTOR_IO_H_
11
12 // Implementation of I/O data list item transfers based on descriptors.
13
14 #include "descriptor.h"
15 #include "edit-input.h"
16 #include "edit-output.h"
17 #include "io-stmt.h"
18 #include "terminator.h"
19 #include "flang/Common/uint128.h"
20
21 namespace Fortran::runtime::io::descr {
22 template <typename A>
ExtractElement(IoStatementState & io,const Descriptor & descriptor,const SubscriptValue subscripts[])23 inline A &ExtractElement(IoStatementState &io, const Descriptor &descriptor,
24 const SubscriptValue subscripts[]) {
25 A *p{descriptor.Element<A>(subscripts)};
26 if (!p) {
27 io.GetIoErrorHandler().Crash("ExtractElement: subscripts out of range");
28 }
29 return *p;
30 }
31
32 // Per-category descriptor-based I/O templates
33
34 template <typename A, Direction DIR>
FormattedIntegerIO(IoStatementState & io,const Descriptor & descriptor)35 inline bool FormattedIntegerIO(
36 IoStatementState &io, const Descriptor &descriptor) {
37 std::size_t numElements{descriptor.Elements()};
38 SubscriptValue subscripts[maxRank];
39 descriptor.GetLowerBounds(subscripts);
40 for (std::size_t j{0}; j < numElements; ++j) {
41 if (auto edit{io.GetNextDataEdit()}) {
42 A &x{ExtractElement<A>(io, descriptor, subscripts)};
43 if constexpr (DIR == Direction::Output) {
44 if (!EditIntegerOutput(io, *edit, static_cast<std::int64_t>(x))) {
45 return false;
46 }
47 } else if (edit->descriptor != DataEdit::ListDirectedNullValue) {
48 if (!EditIntegerInput(io, *edit, reinterpret_cast<void *>(&x),
49 static_cast<int>(sizeof(A)))) {
50 return false;
51 }
52 }
53 if (!descriptor.IncrementSubscripts(subscripts) && j + 1 < numElements) {
54 io.GetIoErrorHandler().Crash(
55 "FormattedIntegerIO: subscripts out of bounds");
56 }
57 } else {
58 return false;
59 }
60 }
61 return true;
62 }
63
64 template <int KIND, Direction DIR>
FormattedRealIO(IoStatementState & io,const Descriptor & descriptor)65 inline bool FormattedRealIO(
66 IoStatementState &io, const Descriptor &descriptor) {
67 std::size_t numElements{descriptor.Elements()};
68 SubscriptValue subscripts[maxRank];
69 descriptor.GetLowerBounds(subscripts);
70 using RawType = typename RealOutputEditing<KIND>::BinaryFloatingPoint;
71 for (std::size_t j{0}; j < numElements; ++j) {
72 if (auto edit{io.GetNextDataEdit()}) {
73 RawType &x{ExtractElement<RawType>(io, descriptor, subscripts)};
74 if constexpr (DIR == Direction::Output) {
75 if (!RealOutputEditing<KIND>{io, x}.Edit(*edit)) {
76 return false;
77 }
78 } else if (edit->descriptor != DataEdit::ListDirectedNullValue) {
79 if (!EditRealInput<KIND>(io, *edit, reinterpret_cast<void *>(&x))) {
80 return false;
81 }
82 }
83 if (!descriptor.IncrementSubscripts(subscripts) && j + 1 < numElements) {
84 io.GetIoErrorHandler().Crash(
85 "FormattedRealIO: subscripts out of bounds");
86 }
87 } else {
88 return false;
89 }
90 }
91 return true;
92 }
93
94 template <int KIND, Direction DIR>
FormattedComplexIO(IoStatementState & io,const Descriptor & descriptor)95 inline bool FormattedComplexIO(
96 IoStatementState &io, const Descriptor &descriptor) {
97 std::size_t numElements{descriptor.Elements()};
98 SubscriptValue subscripts[maxRank];
99 descriptor.GetLowerBounds(subscripts);
100 bool isListOutput{
101 io.get_if<ListDirectedStatementState<Direction::Output>>() != nullptr};
102 using RawType = typename RealOutputEditing<KIND>::BinaryFloatingPoint;
103 for (std::size_t j{0}; j < numElements; ++j) {
104 RawType *x{&ExtractElement<RawType>(io, descriptor, subscripts)};
105 if (isListOutput) {
106 DataEdit rEdit, iEdit;
107 rEdit.descriptor = DataEdit::ListDirectedRealPart;
108 iEdit.descriptor = DataEdit::ListDirectedImaginaryPart;
109 if (!RealOutputEditing<KIND>{io, x[0]}.Edit(rEdit) ||
110 !RealOutputEditing<KIND>{io, x[1]}.Edit(iEdit)) {
111 return false;
112 }
113 } else {
114 for (int k{0}; k < 2; ++k, ++x) {
115 auto edit{io.GetNextDataEdit()};
116 if (!edit) {
117 return false;
118 } else if constexpr (DIR == Direction::Output) {
119 if (!RealOutputEditing<KIND>{io, *x}.Edit(*edit)) {
120 return false;
121 }
122 } else if (edit->descriptor == DataEdit::ListDirectedNullValue) {
123 break;
124 } else if (!EditRealInput<KIND>(
125 io, *edit, reinterpret_cast<void *>(x))) {
126 return false;
127 }
128 }
129 }
130 if (!descriptor.IncrementSubscripts(subscripts) && j + 1 < numElements) {
131 io.GetIoErrorHandler().Crash(
132 "FormattedComplexIO: subscripts out of bounds");
133 }
134 }
135 return true;
136 }
137
138 template <typename A, Direction DIR>
FormattedCharacterIO(IoStatementState & io,const Descriptor & descriptor)139 inline bool FormattedCharacterIO(
140 IoStatementState &io, const Descriptor &descriptor) {
141 std::size_t numElements{descriptor.Elements()};
142 SubscriptValue subscripts[maxRank];
143 descriptor.GetLowerBounds(subscripts);
144 std::size_t length{descriptor.ElementBytes() / sizeof(A)};
145 auto *listOutput{io.get_if<ListDirectedStatementState<Direction::Output>>()};
146 for (std::size_t j{0}; j < numElements; ++j) {
147 A *x{&ExtractElement<A>(io, descriptor, subscripts)};
148 if (listOutput) {
149 if (!ListDirectedDefaultCharacterOutput(io, *listOutput, x, length)) {
150 return false;
151 }
152 } else if (auto edit{io.GetNextDataEdit()}) {
153 if constexpr (DIR == Direction::Output) {
154 if (!EditDefaultCharacterOutput(io, *edit, x, length)) {
155 return false;
156 }
157 } else {
158 if (edit->descriptor != DataEdit::ListDirectedNullValue) {
159 if (!EditDefaultCharacterInput(io, *edit, x, length)) {
160 return false;
161 }
162 }
163 }
164 } else {
165 return false;
166 }
167 if (!descriptor.IncrementSubscripts(subscripts) && j + 1 < numElements) {
168 io.GetIoErrorHandler().Crash(
169 "FormattedCharacterIO: subscripts out of bounds");
170 }
171 }
172 return true;
173 }
174
175 template <typename A, Direction DIR>
FormattedLogicalIO(IoStatementState & io,const Descriptor & descriptor)176 inline bool FormattedLogicalIO(
177 IoStatementState &io, const Descriptor &descriptor) {
178 std::size_t numElements{descriptor.Elements()};
179 SubscriptValue subscripts[maxRank];
180 descriptor.GetLowerBounds(subscripts);
181 auto *listOutput{io.get_if<ListDirectedStatementState<Direction::Output>>()};
182 for (std::size_t j{0}; j < numElements; ++j) {
183 A &x{ExtractElement<A>(io, descriptor, subscripts)};
184 if (listOutput) {
185 if (!ListDirectedLogicalOutput(io, *listOutput, x != 0)) {
186 return false;
187 }
188 } else if (auto edit{io.GetNextDataEdit()}) {
189 if constexpr (DIR == Direction::Output) {
190 if (!EditLogicalOutput(io, *edit, x != 0)) {
191 return false;
192 }
193 } else {
194 if (edit->descriptor != DataEdit::ListDirectedNullValue) {
195 bool truth{};
196 if (EditLogicalInput(io, *edit, truth)) {
197 x = truth;
198 } else {
199 return false;
200 }
201 }
202 }
203 } else {
204 return false;
205 }
206 if (!descriptor.IncrementSubscripts(subscripts) && j + 1 < numElements) {
207 io.GetIoErrorHandler().Crash(
208 "FormattedLogicalIO: subscripts out of bounds");
209 }
210 }
211 return true;
212 }
213
214 template <Direction DIR>
DescriptorIO(IoStatementState & io,const Descriptor & descriptor)215 static bool DescriptorIO(IoStatementState &io, const Descriptor &descriptor) {
216 if (!io.get_if<IoDirectionState<DIR>>()) {
217 io.GetIoErrorHandler().Crash(
218 "DescriptorIO() called for wrong I/O direction");
219 return false;
220 }
221 if constexpr (DIR == Direction::Input) {
222 io.BeginReadingRecord();
223 }
224 if (auto *unf{io.get_if<UnformattedIoStatementState<DIR>>()}) {
225 std::size_t elementBytes{descriptor.ElementBytes()};
226 SubscriptValue subscripts[maxRank];
227 descriptor.GetLowerBounds(subscripts);
228 std::size_t numElements{descriptor.Elements()};
229 if (descriptor.IsContiguous()) { // contiguous unformatted I/O
230 char &x{ExtractElement<char>(io, descriptor, subscripts)};
231 auto totalBytes{numElements * elementBytes};
232 if constexpr (DIR == Direction::Output) {
233 return unf->Emit(&x, totalBytes, elementBytes);
234 } else {
235 return unf->Receive(&x, totalBytes, elementBytes);
236 }
237 } else { // non-contiguous unformatted I/O
238 for (std::size_t j{0}; j < numElements; ++j) {
239 char &x{ExtractElement<char>(io, descriptor, subscripts)};
240 if constexpr (DIR == Direction::Output) {
241 if (!unf->Emit(&x, elementBytes, elementBytes)) {
242 return false;
243 }
244 } else {
245 if (!unf->Receive(&x, elementBytes, elementBytes)) {
246 return false;
247 }
248 }
249 if (!descriptor.IncrementSubscripts(subscripts) &&
250 j + 1 < numElements) {
251 io.GetIoErrorHandler().Crash(
252 "DescriptorIO: subscripts out of bounds");
253 }
254 }
255 return true;
256 }
257 } else if (auto catAndKind{descriptor.type().GetCategoryAndKind()}) {
258 int kind{catAndKind->second};
259 switch (catAndKind->first) {
260 case TypeCategory::Integer:
261 switch (kind) {
262 case 1:
263 return FormattedIntegerIO<std::int8_t, DIR>(io, descriptor);
264 case 2:
265 return FormattedIntegerIO<std::int16_t, DIR>(io, descriptor);
266 case 4:
267 return FormattedIntegerIO<std::int32_t, DIR>(io, descriptor);
268 case 8:
269 return FormattedIntegerIO<std::int64_t, DIR>(io, descriptor);
270 case 16:
271 return FormattedIntegerIO<common::uint128_t, DIR>(io, descriptor);
272 default:
273 io.GetIoErrorHandler().Crash(
274 "DescriptorIO: Unimplemented INTEGER kind (%d) in descriptor",
275 kind);
276 return false;
277 }
278 case TypeCategory::Real:
279 switch (kind) {
280 case 2:
281 return FormattedRealIO<2, DIR>(io, descriptor);
282 case 3:
283 return FormattedRealIO<3, DIR>(io, descriptor);
284 case 4:
285 return FormattedRealIO<4, DIR>(io, descriptor);
286 case 8:
287 return FormattedRealIO<8, DIR>(io, descriptor);
288 case 10:
289 return FormattedRealIO<10, DIR>(io, descriptor);
290 // TODO: case double/double
291 case 16:
292 return FormattedRealIO<16, DIR>(io, descriptor);
293 default:
294 io.GetIoErrorHandler().Crash(
295 "DescriptorIO: Unimplemented REAL kind (%d) in descriptor", kind);
296 return false;
297 }
298 case TypeCategory::Complex:
299 switch (kind) {
300 case 2:
301 return FormattedComplexIO<2, DIR>(io, descriptor);
302 case 3:
303 return FormattedComplexIO<3, DIR>(io, descriptor);
304 case 4:
305 return FormattedComplexIO<4, DIR>(io, descriptor);
306 case 8:
307 return FormattedComplexIO<8, DIR>(io, descriptor);
308 case 10:
309 return FormattedComplexIO<10, DIR>(io, descriptor);
310 // TODO: case double/double
311 case 16:
312 return FormattedComplexIO<16, DIR>(io, descriptor);
313 default:
314 io.GetIoErrorHandler().Crash(
315 "DescriptorIO: Unimplemented COMPLEX kind (%d) in descriptor",
316 kind);
317 return false;
318 }
319 case TypeCategory::Character:
320 switch (kind) {
321 case 1:
322 return FormattedCharacterIO<char, DIR>(io, descriptor);
323 // TODO cases 2, 4
324 default:
325 io.GetIoErrorHandler().Crash(
326 "DescriptorIO: Unimplemented CHARACTER kind (%d) in descriptor",
327 kind);
328 return false;
329 }
330 case TypeCategory::Logical:
331 switch (kind) {
332 case 1:
333 return FormattedLogicalIO<std::int8_t, DIR>(io, descriptor);
334 case 2:
335 return FormattedLogicalIO<std::int16_t, DIR>(io, descriptor);
336 case 4:
337 return FormattedLogicalIO<std::int32_t, DIR>(io, descriptor);
338 case 8:
339 return FormattedLogicalIO<std::int64_t, DIR>(io, descriptor);
340 default:
341 io.GetIoErrorHandler().Crash(
342 "DescriptorIO: Unimplemented LOGICAL kind (%d) in descriptor",
343 kind);
344 return false;
345 }
346 case TypeCategory::Derived:
347 io.GetIoErrorHandler().Crash(
348 "DescriptorIO: Unimplemented: derived type I/O",
349 static_cast<int>(descriptor.type().raw()));
350 return false;
351 }
352 }
353 io.GetIoErrorHandler().Crash("DescriptorIO: Bad type code (%d) in descriptor",
354 static_cast<int>(descriptor.type().raw()));
355 return false;
356 }
357 } // namespace Fortran::runtime::io::descr
358 #endif // FORTRAN_RUNTIME_DESCRIPTOR_IO_H_
359