• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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