FLANG
io-api-consts.h
1//===-- include/flang/Runtime/io-api-consts.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_IO_API_CONSTS_H_
10#define FORTRAN_RUNTIME_IO_API_CONSTS_H_
11
12#include "flang/Common/uint128.h"
13#include "flang/Runtime/entry-names.h"
14#include "flang/Runtime/iostat-consts.h"
15#include "flang/Runtime/magic-numbers.h"
16#include <cinttypes>
17#include <cstddef>
18
19namespace Fortran::runtime {
20class Descriptor;
21} // namespace Fortran::runtime
22
23namespace Fortran::runtime::io {
24
25struct NonTbpDefinedIoTable;
26class NamelistGroup;
27class IoStatementState;
28using Cookie = IoStatementState *;
29using ExternalUnit = int;
30using AsynchronousId = int;
31
32static constexpr ExternalUnit DefaultOutputUnit{FORTRAN_DEFAULT_OUTPUT_UNIT};
33static constexpr ExternalUnit DefaultInputUnit{FORTRAN_DEFAULT_INPUT_UNIT};
34
35// INQUIRE specifiers are encoded as simple base-26 packings of
36// the spellings of their keywords.
37using InquiryKeywordHash = std::uint64_t;
38constexpr InquiryKeywordHash HashInquiryKeyword(const char *p) {
39 InquiryKeywordHash hash{1};
40 while (char ch{*p++}) {
41 std::uint64_t letter{0};
42 if (ch >= 'a' && ch <= 'z') {
43 letter = ch - 'a';
44 } else {
45 letter = ch - 'A';
46 }
47 hash = 26 * hash + letter;
48 }
49 return hash;
50}
51
52extern "C" {
53
54#define IONAME(name) RTNAME(io##name)
55
56#ifndef IODECL
57#define IODECL(name) RT_API_ATTRS IONAME(name)
58#endif
59
60#ifndef IODEF
61#define IODEF(name) RT_API_ATTRS IONAME(name)
62#endif
63
64// These functions initiate data transfer statements (READ, WRITE, PRINT).
65// Example: PRINT *, 666 is implemented as the series of calls:
66// Cookie cookie{BeginExternalListOutput(DefaultOutputUnit,
67// __FILE__, __LINE__)};
68// OutputInteger32(cookie, 666);
69// EndIoStatement(cookie);
70// Formatted I/O with explicit formats can supply the format as a
71// const char * pointer with a length, or with a descriptor.
72
73// Internal I/O initiation
74// Internal I/O can loan the runtime library an optional block of memory
75// in which the library can maintain state across the calls that implement
76// the internal transfer; use of these blocks can reduce the need for dynamic
77// memory allocation &/or thread-local storage. The block must be sufficiently
78// aligned to hold a pointer.
79constexpr std::size_t RecommendedInternalIoScratchAreaBytes(
80 int maxFormatParenthesesNestingDepth) {
81 return 32 + 8 * maxFormatParenthesesNestingDepth;
82}
83
84// For NAMELIST I/O, use the API for the appropriate form of list-directed
85// I/O initiation and configuration, then call OutputNamelist/InputNamelist
86// below.
87
88// Internal I/O to/from character arrays &/or non-default-kind character
89// requires a descriptor, which is copied.
90Cookie IODECL(BeginInternalArrayListOutput)(const Descriptor &,
91 void **scratchArea = nullptr, std::size_t scratchBytes = 0,
92 const char *sourceFile = nullptr, int sourceLine = 0);
93Cookie IODECL(BeginInternalArrayListInput)(const Descriptor &,
94 void **scratchArea = nullptr, std::size_t scratchBytes = 0,
95 const char *sourceFile = nullptr, int sourceLine = 0);
96Cookie IODECL(BeginInternalArrayFormattedOutput)(const Descriptor &,
97 const char *format, std::size_t formatLength,
98 const Descriptor *formatDescriptor = nullptr, void **scratchArea = nullptr,
99 std::size_t scratchBytes = 0, const char *sourceFile = nullptr,
100 int sourceLine = 0);
101Cookie IODECL(BeginInternalArrayFormattedInput)(const Descriptor &,
102 const char *format, std::size_t formatLength,
103 const Descriptor *formatDescriptor = nullptr, void **scratchArea = nullptr,
104 std::size_t scratchBytes = 0, const char *sourceFile = nullptr,
105 int sourceLine = 0);
106
107// Internal I/O to/from a default-kind character scalar can avoid a
108// descriptor.
109Cookie IODECL(BeginInternalListOutput)(char *internal,
110 std::size_t internalLength, void **scratchArea = nullptr,
111 std::size_t scratchBytes = 0, const char *sourceFile = nullptr,
112 int sourceLine = 0);
113Cookie IODECL(BeginInternalListInput)(const char *internal,
114 std::size_t internalLength, void **scratchArea = nullptr,
115 std::size_t scratchBytes = 0, const char *sourceFile = nullptr,
116 int sourceLine = 0);
117Cookie IODECL(BeginInternalFormattedOutput)(char *internal,
118 std::size_t internalLength, const char *format, std::size_t formatLength,
119 const Descriptor *formatDescriptor = nullptr, void **scratchArea = nullptr,
120 std::size_t scratchBytes = 0, const char *sourceFile = nullptr,
121 int sourceLine = 0);
122Cookie IODECL(BeginInternalFormattedInput)(const char *internal,
123 std::size_t internalLength, const char *format, std::size_t formatLength,
124 const Descriptor *formatDescriptor = nullptr, void **scratchArea = nullptr,
125 std::size_t scratchBytes = 0, const char *sourceFile = nullptr,
126 int sourceLine = 0);
127
128// External unit numbers must fit in default integers. When the integer
129// provided as UNIT is of a wider type than the default integer, it could
130// overflow when converted to a default integer.
131// CheckUnitNumberInRange should be called to verify that a unit number of a
132// wide integer type can fit in a default integer. Since it should be called
133// before the BeginXXX(unit, ...) call, it has its own error handling interface.
134// If handleError is false, and the unit number is out of range, the program
135// will be terminated. Otherwise, if unit is out of range, a nonzero Iostat
136// code is returned and ioMsg is set if it is not a nullptr.
137enum Iostat IODECL(CheckUnitNumberInRange64)(std::int64_t unit,
138 bool handleError, char *ioMsg = nullptr, std::size_t ioMsgLength = 0,
139 const char *sourceFile = nullptr, int sourceLine = 0);
140enum Iostat IODECL(CheckUnitNumberInRange128)(common::int128_t unit,
141 bool handleError, char *ioMsg = nullptr, std::size_t ioMsgLength = 0,
142 const char *sourceFile = nullptr, int sourceLine = 0);
143
144// External synchronous I/O initiation
145Cookie IODECL(BeginExternalListOutput)(ExternalUnit = DefaultOutputUnit,
146 const char *sourceFile = nullptr, int sourceLine = 0);
147Cookie IODECL(BeginExternalListInput)(ExternalUnit = DefaultInputUnit,
148 const char *sourceFile = nullptr, int sourceLine = 0);
149Cookie IODECL(BeginExternalFormattedOutput)(const char *format, std::size_t,
150 const Descriptor *formatDescriptor = nullptr,
151 ExternalUnit = DefaultOutputUnit, const char *sourceFile = nullptr,
152 int sourceLine = 0);
153Cookie IODECL(BeginExternalFormattedInput)(const char *format, std::size_t,
154 const Descriptor *formatDescriptor = nullptr,
155 ExternalUnit = DefaultInputUnit, const char *sourceFile = nullptr,
156 int sourceLine = 0);
157Cookie IODECL(BeginUnformattedOutput)(ExternalUnit = DefaultOutputUnit,
158 const char *sourceFile = nullptr, int sourceLine = 0);
159Cookie IODECL(BeginUnformattedInput)(ExternalUnit = DefaultInputUnit,
160 const char *sourceFile = nullptr, int sourceLine = 0);
161
162// WAIT(ID=)
163Cookie IODECL(BeginWait)(ExternalUnit, AsynchronousId,
164 const char *sourceFile = nullptr, int sourceLine = 0);
165// WAIT(no ID=)
166Cookie IODECL(BeginWaitAll)(
167 ExternalUnit, const char *sourceFile = nullptr, int sourceLine = 0);
168
169// Other I/O statements
170Cookie IODECL(BeginClose)(
171 ExternalUnit, const char *sourceFile = nullptr, int sourceLine = 0);
172Cookie IODECL(BeginFlush)(
173 ExternalUnit, const char *sourceFile = nullptr, int sourceLine = 0);
174Cookie IODECL(BeginBackspace)(
175 ExternalUnit, const char *sourceFile = nullptr, int sourceLine = 0);
176Cookie IODECL(BeginEndfile)(
177 ExternalUnit, const char *sourceFile = nullptr, int sourceLine = 0);
178Cookie IODECL(BeginRewind)(
179 ExternalUnit, const char *sourceFile = nullptr, int sourceLine = 0);
180
181// OPEN(UNIT=) and OPEN(NEWUNIT=) have distinct interfaces.
182Cookie IODECL(BeginOpenUnit)(
183 ExternalUnit, const char *sourceFile = nullptr, int sourceLine = 0);
184Cookie IODECL(BeginOpenNewUnit)(
185 const char *sourceFile = nullptr, int sourceLine = 0);
186
187// The variant forms of INQUIRE() statements have distinct interfaces.
188// BeginInquireIoLength() is basically a no-op output statement.
189Cookie IODECL(BeginInquireUnit)(
190 ExternalUnit, const char *sourceFile = nullptr, int sourceLine = 0);
191Cookie IODECL(BeginInquireFile)(const char *, std::size_t,
192 const char *sourceFile = nullptr, int sourceLine = 0);
193Cookie IODECL(BeginInquireIoLength)(
194 const char *sourceFile = nullptr, int sourceLine = 0);
195
196// If an I/O statement has any IOSTAT=, ERR=, END=, or EOR= specifiers,
197// call EnableHandlers() immediately after the Begin...() call.
198// An output or OPEN statement may not enable HasEnd or HasEor.
199// This call makes the runtime library defer those particular error/end
200// conditions to the EndIoStatement() call rather than terminating
201// the image. E.g., for READ(*,*,END=666) A, B, (C(J),J=1,N)
202// Cookie cookie{BeginExternalListInput(DefaultInputUnit,__FILE__,__LINE__)};
203// EnableHandlers(cookie, false, false, true /*END=*/, false);
204// if (InputReal64(cookie, &A)) {
205// if (InputReal64(cookie, &B)) {
206// for (int J{1}; J<=N; ++J) {
207// if (!InputReal64(cookie, &C[J])) break;
208// }
209// }
210// }
211// if (EndIoStatement(cookie) == FORTRAN_RUTIME_IOSTAT_END) goto label666;
212void IODECL(EnableHandlers)(Cookie, bool hasIoStat = false, bool hasErr = false,
213 bool hasEnd = false, bool hasEor = false, bool hasIoMsg = false);
214
215// ASYNCHRONOUS='YES' or 'NO' on READ/WRITE/OPEN
216// Use GetAsynchronousId() to handle ID=.
217bool IODECL(SetAsynchronous)(Cookie, const char *, std::size_t);
218
219// Control list options. These return false on a error that the
220// Begin...() call has specified will be handled by the caller.
221// The interfaces that pass a default-kind CHARACTER argument
222// are limited to passing specific case-insensitive keyword values.
223// ADVANCE=YES, NO
224bool IODECL(SetAdvance)(Cookie, const char *, std::size_t);
225// BLANK=NULL, ZERO
226bool IODECL(SetBlank)(Cookie, const char *, std::size_t);
227// DECIMAL=COMMA, POINT
228bool IODECL(SetDecimal)(Cookie, const char *, std::size_t);
229// DELIM=APOSTROPHE, QUOTE, NONE
230bool IODECL(SetDelim)(Cookie, const char *, std::size_t);
231// PAD=YES, NO
232bool IODECL(SetPad)(Cookie, const char *, std::size_t);
233bool IODECL(SetPos)(Cookie, std::int64_t);
234bool IODECL(SetRec)(Cookie, std::int64_t);
235// ROUND=UP, DOWN, ZERO, NEAREST, COMPATIBLE, PROCESSOR_DEFINED
236bool IODECL(SetRound)(Cookie, const char *, std::size_t);
237// SIGN=PLUS, SUPPRESS, PROCESSOR_DEFINED
238bool IODECL(SetSign)(Cookie, const char *, std::size_t);
239
240// Data item transfer for modes other than NAMELIST:
241// Any data object that can be passed as an actual argument without the
242// use of a temporary can be transferred by means of a descriptor;
243// vector-valued subscripts and coindexing will require elementwise
244// transfers &/or data copies. Unformatted transfers to/from contiguous
245// blocks of local image memory can avoid the descriptor, and there
246// are specializations for the most common scalar types.
247//
248// These functions return false when the I/O statement has encountered an
249// error or end-of-file/record condition that the caller has indicated
250// should not cause termination of the image by the runtime library.
251// Once the statement has encountered an error, all following items will be
252// ignored and also return false; but compiled code should check for errors
253// and avoid the following items when they might crash.
254bool IODECL(OutputDescriptor)(Cookie, const Descriptor &);
255bool IODECL(InputDescriptor)(Cookie, const Descriptor &);
256// Formatted (including list directed) I/O data items
257bool IODECL(OutputInteger8)(Cookie, std::int8_t);
258bool IODECL(OutputInteger16)(Cookie, std::int16_t);
259bool IODECL(OutputInteger32)(Cookie, std::int32_t);
260bool IODECL(OutputInteger64)(Cookie, std::int64_t);
261bool IODECL(OutputInteger128)(Cookie, common::int128_t);
262bool IODECL(InputInteger)(Cookie, std::int64_t &, int kind = 8);
263bool IODECL(OutputReal32)(Cookie, float);
264bool IODECL(InputReal32)(Cookie, float &);
265bool IODECL(OutputReal64)(Cookie, double);
266bool IODECL(InputReal64)(Cookie, double &);
267bool IODECL(OutputComplex32)(Cookie, float, float);
268bool IODECL(InputComplex32)(Cookie, float[2]);
269bool IODECL(OutputComplex64)(Cookie, double, double);
270bool IODECL(InputComplex64)(Cookie, double[2]);
271bool IODECL(OutputCharacter)(Cookie, const char *, std::size_t, int kind = 1);
272bool IODECL(OutputAscii)(Cookie, const char *, std::size_t);
273bool IODECL(InputCharacter)(Cookie, char *, std::size_t, int kind = 1);
274bool IODECL(InputAscii)(Cookie, char *, std::size_t);
275bool IODECL(OutputLogical)(Cookie, bool);
276bool IODECL(InputLogical)(Cookie, bool &);
277
278// NAMELIST I/O must be the only data item in an (otherwise)
279// list-directed I/O statement.
280bool IODECL(OutputNamelist)(Cookie, const NamelistGroup &);
281bool IODECL(InputNamelist)(Cookie, const NamelistGroup &);
282
283// When an I/O list item has a derived type with a specific defined
284// I/O subroutine of the appropriate generic kind for the active
285// I/O data transfer statement (read/write, formatted/unformatted)
286// that pertains to the type or its components, and those subroutines
287// are dynamic or neither type-bound nor defined with interfaces
288// in the same scope as the derived type (or an IMPORT statement has
289// made such a generic interface inaccessible), these data item transfer
290// APIs enable the I/O runtime to make the right calls to defined I/O
291// subroutines.
292bool IODECL(OutputDerivedType)(
293 Cookie, const Descriptor &, const NonTbpDefinedIoTable *);
294bool IODECL(InputDerivedType)(
295 Cookie, const Descriptor &, const NonTbpDefinedIoTable *);
296
297// Additional specifier interfaces for the connection-list of
298// on OPEN statement (only). SetBlank(), SetDecimal(),
299// SetDelim(), GetIoMsg(), SetPad(), SetRound(), SetSign(),
300// & SetAsynchronous() are also acceptable for OPEN.
301// ACCESS=SEQUENTIAL, DIRECT, STREAM
302bool IODECL(SetAccess)(Cookie, const char *, std::size_t);
303// ACTION=READ, WRITE, or READWRITE
304bool IODECL(SetAction)(Cookie, const char *, std::size_t);
305// CARRIAGECONTROL=LIST, FORTRAN, NONE
306bool IODECL(SetCarriagecontrol)(Cookie, const char *, std::size_t);
307// CONVERT=NATIVE, LITTLE_ENDIAN, BIG_ENDIAN, or SWAP
308bool IODECL(SetConvert)(Cookie, const char *, std::size_t);
309// ENCODING=UTF-8, DEFAULT
310bool IODECL(SetEncoding)(Cookie, const char *, std::size_t);
311// FORM=FORMATTED, UNFORMATTED
312bool IODECL(SetForm)(Cookie, const char *, std::size_t);
313// POSITION=ASIS, REWIND, APPEND
314bool IODECL(SetPosition)(Cookie, const char *, std::size_t);
315bool IODECL(SetRecl)(Cookie, std::size_t); // RECL=
316
317// STATUS can be set during an OPEN or CLOSE statement.
318// For OPEN: STATUS=OLD, NEW, SCRATCH, REPLACE, UNKNOWN
319// For CLOSE: STATUS=KEEP, DELETE
320bool IODECL(SetStatus)(Cookie, const char *, std::size_t);
321
322bool IODECL(SetFile)(Cookie, const char *, std::size_t chars);
323
324// Acquires the runtime-created unit number for OPEN(NEWUNIT=)
325bool IODECL(GetNewUnit)(Cookie, int &, int kind = 4);
326
327// READ(SIZE=), after all input items
328std::size_t IODECL(GetSize)(Cookie);
329
330// INQUIRE(IOLENGTH=), after all output items
331std::size_t IODECL(GetIoLength)(Cookie);
332
333// GetIoMsg() does not modify its argument unless an error or
334// end-of-record/file condition is present.
335void IODECL(GetIoMsg)(Cookie, char *, std::size_t); // IOMSG=
336
337// Defines ID= on READ/WRITE(ASYNCHRONOUS='YES')
338AsynchronousId IODECL(GetAsynchronousId)(Cookie);
339
340// INQUIRE() specifiers are mostly identified by their NUL-terminated
341// case-insensitive names.
342// ACCESS, ACTION, ASYNCHRONOUS, BLANK, CONVERT, DECIMAL, DELIM, DIRECT,
343// ENCODING, FORM, FORMATTED, NAME, PAD, POSITION, READ, READWRITE, ROUND,
344// SEQUENTIAL, SIGN, STREAM, UNFORMATTED, WRITE:
345bool IODECL(InquireCharacter)(Cookie, InquiryKeywordHash, char *, std::size_t);
346// EXIST, NAMED, OPENED, and PENDING (without ID):
347bool IODECL(InquireLogical)(Cookie, InquiryKeywordHash, bool &);
348// PENDING with ID
349bool IODECL(InquirePendingId)(Cookie, AsynchronousId, bool &);
350// NEXTREC, NUMBER, POS, RECL, SIZE
351bool IODECL(InquireInteger64)(
352 Cookie, InquiryKeywordHash, std::int64_t &, int kind = 8);
353
354// This function must be called to end an I/O statement, and its
355// cookie value may not be used afterwards unless it is recycled
356// by the runtime library to serve a later I/O statement.
357// The return value can be used to implement IOSTAT=, ERR=, END=, & EOR=;
358// store it into the IOSTAT= variable if there is one, and test
359// it to implement the various branches. The error condition
360// returned is guaranteed to only be one of the problems that the
361// EnableHandlers() call has indicated should be handled in compiled code
362// rather than by terminating the image.
363enum Iostat IODECL(EndIoStatement)(Cookie);
364
365} // extern "C"
366} // namespace Fortran::runtime::io
367
368#endif /* FORTRAN_RUNTIME_IO_API_CONSTS_H_ */