Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[flang][runtime] Enable I/O APIs in F18 runtime offload builds. #87543

Merged
merged 2 commits into from
Apr 3, 2024

Conversation

vzakhari
Copy link
Contributor

@vzakhari vzakhari commented Apr 3, 2024

No description provided.

@vzakhari vzakhari requested a review from klausler April 3, 2024 19:10
@llvmbot llvmbot added flang:runtime flang Flang issues not falling into any other category labels Apr 3, 2024
@llvmbot
Copy link
Member

llvmbot commented Apr 3, 2024

@llvm/pr-subscribers-flang-runtime

Author: Slava Zakharin (vzakhari)

Changes

Patch is 59.55 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/87543.diff

8 Files Affected:

  • (modified) flang/include/flang/Runtime/io-api.h (+82-82)
  • (modified) flang/runtime/environment.cpp (+2)
  • (modified) flang/runtime/environment.h (+1-1)
  • (modified) flang/runtime/freestanding-tools.h (+19)
  • (modified) flang/runtime/io-api.cpp (+99-105)
  • (modified) flang/runtime/io-error.cpp (+6-3)
  • (modified) flang/runtime/io-error.h (+1-1)
  • (modified) flang/runtime/namelist.cpp (+25-21)
diff --git a/flang/include/flang/Runtime/io-api.h b/flang/include/flang/Runtime/io-api.h
index 1b6c4f5d6a65ca..328afc715a3f1e 100644
--- a/flang/include/flang/Runtime/io-api.h
+++ b/flang/include/flang/Runtime/io-api.h
@@ -92,18 +92,18 @@ constexpr std::size_t RecommendedInternalIoScratchAreaBytes(
 
 // Internal I/O to/from character arrays &/or non-default-kind character
 // requires a descriptor, which is copied.
-Cookie IONAME(BeginInternalArrayListOutput)(const Descriptor &,
+Cookie IODECL(BeginInternalArrayListOutput)(const Descriptor &,
     void **scratchArea = nullptr, std::size_t scratchBytes = 0,
     const char *sourceFile = nullptr, int sourceLine = 0);
-Cookie IONAME(BeginInternalArrayListInput)(const Descriptor &,
+Cookie IODECL(BeginInternalArrayListInput)(const Descriptor &,
     void **scratchArea = nullptr, std::size_t scratchBytes = 0,
     const char *sourceFile = nullptr, int sourceLine = 0);
-Cookie IONAME(BeginInternalArrayFormattedOutput)(const Descriptor &,
+Cookie IODECL(BeginInternalArrayFormattedOutput)(const Descriptor &,
     const char *format, std::size_t formatLength,
     const Descriptor *formatDescriptor = nullptr, void **scratchArea = nullptr,
     std::size_t scratchBytes = 0, const char *sourceFile = nullptr,
     int sourceLine = 0);
-Cookie IONAME(BeginInternalArrayFormattedInput)(const Descriptor &,
+Cookie IODECL(BeginInternalArrayFormattedInput)(const Descriptor &,
     const char *format, std::size_t formatLength,
     const Descriptor *formatDescriptor = nullptr, void **scratchArea = nullptr,
     std::size_t scratchBytes = 0, const char *sourceFile = nullptr,
@@ -111,20 +111,20 @@ Cookie IONAME(BeginInternalArrayFormattedInput)(const Descriptor &,
 
 // Internal I/O to/from a default-kind character scalar can avoid a
 // descriptor.
-Cookie IONAME(BeginInternalListOutput)(char *internal,
+Cookie IODECL(BeginInternalListOutput)(char *internal,
     std::size_t internalLength, void **scratchArea = nullptr,
     std::size_t scratchBytes = 0, const char *sourceFile = nullptr,
     int sourceLine = 0);
-Cookie IONAME(BeginInternalListInput)(const char *internal,
+Cookie IODECL(BeginInternalListInput)(const char *internal,
     std::size_t internalLength, void **scratchArea = nullptr,
     std::size_t scratchBytes = 0, const char *sourceFile = nullptr,
     int sourceLine = 0);
-Cookie IONAME(BeginInternalFormattedOutput)(char *internal,
+Cookie IODECL(BeginInternalFormattedOutput)(char *internal,
     std::size_t internalLength, const char *format, std::size_t formatLength,
     const Descriptor *formatDescriptor = nullptr, void **scratchArea = nullptr,
     std::size_t scratchBytes = 0, const char *sourceFile = nullptr,
     int sourceLine = 0);
-Cookie IONAME(BeginInternalFormattedInput)(const char *internal,
+Cookie IODECL(BeginInternalFormattedInput)(const char *internal,
     std::size_t internalLength, const char *format, std::size_t formatLength,
     const Descriptor *formatDescriptor = nullptr, void **scratchArea = nullptr,
     std::size_t scratchBytes = 0, const char *sourceFile = nullptr,
@@ -139,63 +139,63 @@ Cookie IONAME(BeginInternalFormattedInput)(const char *internal,
 // If handleError is false, and the unit number is out of range, the program
 // will be terminated. Otherwise, if unit is out of range, a nonzero Iostat
 // code is returned and ioMsg is set if it is not a nullptr.
-enum Iostat IONAME(CheckUnitNumberInRange64)(std::int64_t unit,
+enum Iostat IODECL(CheckUnitNumberInRange64)(std::int64_t unit,
     bool handleError, char *ioMsg = nullptr, std::size_t ioMsgLength = 0,
     const char *sourceFile = nullptr, int sourceLine = 0);
-enum Iostat IONAME(CheckUnitNumberInRange128)(common::int128_t unit,
+enum Iostat IODECL(CheckUnitNumberInRange128)(common::int128_t unit,
     bool handleError, char *ioMsg = nullptr, std::size_t ioMsgLength = 0,
     const char *sourceFile = nullptr, int sourceLine = 0);
 
 // External synchronous I/O initiation
 Cookie IODECL(BeginExternalListOutput)(ExternalUnit = DefaultOutputUnit,
     const char *sourceFile = nullptr, int sourceLine = 0);
-Cookie IONAME(BeginExternalListInput)(ExternalUnit = DefaultInputUnit,
+Cookie IODECL(BeginExternalListInput)(ExternalUnit = DefaultInputUnit,
     const char *sourceFile = nullptr, int sourceLine = 0);
-Cookie IONAME(BeginExternalFormattedOutput)(const char *format, std::size_t,
+Cookie IODECL(BeginExternalFormattedOutput)(const char *format, std::size_t,
     const Descriptor *formatDescriptor = nullptr,
     ExternalUnit = DefaultOutputUnit, const char *sourceFile = nullptr,
     int sourceLine = 0);
-Cookie IONAME(BeginExternalFormattedInput)(const char *format, std::size_t,
+Cookie IODECL(BeginExternalFormattedInput)(const char *format, std::size_t,
     const Descriptor *formatDescriptor = nullptr,
     ExternalUnit = DefaultInputUnit, const char *sourceFile = nullptr,
     int sourceLine = 0);
-Cookie IONAME(BeginUnformattedOutput)(ExternalUnit = DefaultOutputUnit,
+Cookie IODECL(BeginUnformattedOutput)(ExternalUnit = DefaultOutputUnit,
     const char *sourceFile = nullptr, int sourceLine = 0);
-Cookie IONAME(BeginUnformattedInput)(ExternalUnit = DefaultInputUnit,
+Cookie IODECL(BeginUnformattedInput)(ExternalUnit = DefaultInputUnit,
     const char *sourceFile = nullptr, int sourceLine = 0);
 
 // WAIT(ID=)
-Cookie IONAME(BeginWait)(ExternalUnit, AsynchronousId,
+Cookie IODECL(BeginWait)(ExternalUnit, AsynchronousId,
     const char *sourceFile = nullptr, int sourceLine = 0);
 // WAIT(no ID=)
-Cookie IONAME(BeginWaitAll)(
+Cookie IODECL(BeginWaitAll)(
     ExternalUnit, const char *sourceFile = nullptr, int sourceLine = 0);
 
 // Other I/O statements
-Cookie IONAME(BeginClose)(
+Cookie IODECL(BeginClose)(
     ExternalUnit, const char *sourceFile = nullptr, int sourceLine = 0);
-Cookie IONAME(BeginFlush)(
+Cookie IODECL(BeginFlush)(
     ExternalUnit, const char *sourceFile = nullptr, int sourceLine = 0);
-Cookie IONAME(BeginBackspace)(
+Cookie IODECL(BeginBackspace)(
     ExternalUnit, const char *sourceFile = nullptr, int sourceLine = 0);
-Cookie IONAME(BeginEndfile)(
+Cookie IODECL(BeginEndfile)(
     ExternalUnit, const char *sourceFile = nullptr, int sourceLine = 0);
-Cookie IONAME(BeginRewind)(
+Cookie IODECL(BeginRewind)(
     ExternalUnit, const char *sourceFile = nullptr, int sourceLine = 0);
 
 // OPEN(UNIT=) and OPEN(NEWUNIT=) have distinct interfaces.
-Cookie IONAME(BeginOpenUnit)(
+Cookie IODECL(BeginOpenUnit)(
     ExternalUnit, const char *sourceFile = nullptr, int sourceLine = 0);
-Cookie IONAME(BeginOpenNewUnit)(
+Cookie IODECL(BeginOpenNewUnit)(
     const char *sourceFile = nullptr, int sourceLine = 0);
 
 // The variant forms of INQUIRE() statements have distinct interfaces.
 // BeginInquireIoLength() is basically a no-op output statement.
-Cookie IONAME(BeginInquireUnit)(
+Cookie IODECL(BeginInquireUnit)(
     ExternalUnit, const char *sourceFile = nullptr, int sourceLine = 0);
-Cookie IONAME(BeginInquireFile)(const char *, std::size_t,
+Cookie IODECL(BeginInquireFile)(const char *, std::size_t,
     const char *sourceFile = nullptr, int sourceLine = 0);
-Cookie IONAME(BeginInquireIoLength)(
+Cookie IODECL(BeginInquireIoLength)(
     const char *sourceFile = nullptr, int sourceLine = 0);
 
 // If an I/O statement has any IOSTAT=, ERR=, END=, or EOR= specifiers,
@@ -214,33 +214,33 @@ Cookie IONAME(BeginInquireIoLength)(
 //     }
 //   }
 //   if (EndIoStatement(cookie) == FORTRAN_RUTIME_IOSTAT_END) goto label666;
-void IONAME(EnableHandlers)(Cookie, bool hasIoStat = false, bool hasErr = false,
+void IODECL(EnableHandlers)(Cookie, bool hasIoStat = false, bool hasErr = false,
     bool hasEnd = false, bool hasEor = false, bool hasIoMsg = false);
 
 // ASYNCHRONOUS='YES' or 'NO' on READ/WRITE/OPEN
 // Use GetAsynchronousId() to handle ID=.
-bool IONAME(SetAsynchronous)(Cookie, const char *, std::size_t);
+bool IODECL(SetAsynchronous)(Cookie, const char *, std::size_t);
 
 // Control list options.  These return false on a error that the
 // Begin...() call has specified will be handled by the caller.
 // The interfaces that pass a default-kind CHARACTER argument
 // are limited to passing specific case-insensitive keyword values.
 // ADVANCE=YES, NO
-bool IONAME(SetAdvance)(Cookie, const char *, std::size_t);
+bool IODECL(SetAdvance)(Cookie, const char *, std::size_t);
 // BLANK=NULL, ZERO
-bool IONAME(SetBlank)(Cookie, const char *, std::size_t);
+bool IODECL(SetBlank)(Cookie, const char *, std::size_t);
 // DECIMAL=COMMA, POINT
-bool IONAME(SetDecimal)(Cookie, const char *, std::size_t);
+bool IODECL(SetDecimal)(Cookie, const char *, std::size_t);
 // DELIM=APOSTROPHE, QUOTE, NONE
-bool IONAME(SetDelim)(Cookie, const char *, std::size_t);
+bool IODECL(SetDelim)(Cookie, const char *, std::size_t);
 // PAD=YES, NO
-bool IONAME(SetPad)(Cookie, const char *, std::size_t);
-bool IONAME(SetPos)(Cookie, std::int64_t);
-bool IONAME(SetRec)(Cookie, std::int64_t);
+bool IODECL(SetPad)(Cookie, const char *, std::size_t);
+bool IODECL(SetPos)(Cookie, std::int64_t);
+bool IODECL(SetRec)(Cookie, std::int64_t);
 // ROUND=UP, DOWN, ZERO, NEAREST, COMPATIBLE, PROCESSOR_DEFINED
-bool IONAME(SetRound)(Cookie, const char *, std::size_t);
+bool IODECL(SetRound)(Cookie, const char *, std::size_t);
 // SIGN=PLUS, SUPPRESS, PROCESSOR_DEFINED
-bool IONAME(SetSign)(Cookie, const char *, std::size_t);
+bool IODECL(SetSign)(Cookie, const char *, std::size_t);
 
 // Data item transfer for modes other than NAMELIST:
 // Any data object that can be passed as an actual argument without the
@@ -256,34 +256,34 @@ bool IONAME(SetSign)(Cookie, const char *, std::size_t);
 // Once the statement has encountered an error, all following items will be
 // ignored and also return false; but compiled code should check for errors
 // and avoid the following items when they might crash.
-bool IONAME(OutputDescriptor)(Cookie, const Descriptor &);
-bool IONAME(InputDescriptor)(Cookie, const Descriptor &);
+bool IODECL(OutputDescriptor)(Cookie, const Descriptor &);
+bool IODECL(InputDescriptor)(Cookie, const Descriptor &);
 // Formatted (including list directed) I/O data items
-bool IONAME(OutputInteger8)(Cookie, std::int8_t);
-bool IONAME(OutputInteger16)(Cookie, std::int16_t);
+bool IODECL(OutputInteger8)(Cookie, std::int8_t);
+bool IODECL(OutputInteger16)(Cookie, std::int16_t);
 bool IODECL(OutputInteger32)(Cookie, std::int32_t);
-bool IONAME(OutputInteger64)(Cookie, std::int64_t);
-bool IONAME(OutputInteger128)(Cookie, common::int128_t);
-bool IONAME(InputInteger)(Cookie, std::int64_t &, int kind = 8);
-bool IONAME(OutputReal32)(Cookie, float);
-bool IONAME(InputReal32)(Cookie, float &);
-bool IONAME(OutputReal64)(Cookie, double);
-bool IONAME(InputReal64)(Cookie, double &);
-bool IONAME(OutputComplex32)(Cookie, float, float);
-bool IONAME(InputComplex32)(Cookie, float[2]);
-bool IONAME(OutputComplex64)(Cookie, double, double);
-bool IONAME(InputComplex64)(Cookie, double[2]);
-bool IONAME(OutputCharacter)(Cookie, const char *, std::size_t, int kind = 1);
-bool IONAME(OutputAscii)(Cookie, const char *, std::size_t);
-bool IONAME(InputCharacter)(Cookie, char *, std::size_t, int kind = 1);
-bool IONAME(InputAscii)(Cookie, char *, std::size_t);
-bool IONAME(OutputLogical)(Cookie, bool);
-bool IONAME(InputLogical)(Cookie, bool &);
+bool IODECL(OutputInteger64)(Cookie, std::int64_t);
+bool IODECL(OutputInteger128)(Cookie, common::int128_t);
+bool IODECL(InputInteger)(Cookie, std::int64_t &, int kind = 8);
+bool IODECL(OutputReal32)(Cookie, float);
+bool IODECL(InputReal32)(Cookie, float &);
+bool IODECL(OutputReal64)(Cookie, double);
+bool IODECL(InputReal64)(Cookie, double &);
+bool IODECL(OutputComplex32)(Cookie, float, float);
+bool IODECL(InputComplex32)(Cookie, float[2]);
+bool IODECL(OutputComplex64)(Cookie, double, double);
+bool IODECL(InputComplex64)(Cookie, double[2]);
+bool IODECL(OutputCharacter)(Cookie, const char *, std::size_t, int kind = 1);
+bool IODECL(OutputAscii)(Cookie, const char *, std::size_t);
+bool IODECL(InputCharacter)(Cookie, char *, std::size_t, int kind = 1);
+bool IODECL(InputAscii)(Cookie, char *, std::size_t);
+bool IODECL(OutputLogical)(Cookie, bool);
+bool IODECL(InputLogical)(Cookie, bool &);
 
 // NAMELIST I/O must be the only data item in an (otherwise)
 // list-directed I/O statement.
-bool IONAME(OutputNamelist)(Cookie, const NamelistGroup &);
-bool IONAME(InputNamelist)(Cookie, const NamelistGroup &);
+bool IODECL(OutputNamelist)(Cookie, const NamelistGroup &);
+bool IODECL(InputNamelist)(Cookie, const NamelistGroup &);
 
 // When an I/O list item has a derived type with a specific defined
 // I/O subroutine of the appropriate generic kind for the active
@@ -294,9 +294,9 @@ bool IONAME(InputNamelist)(Cookie, const NamelistGroup &);
 // made such a generic interface inaccessible), these data item transfer
 // APIs enable the I/O runtime to make the right calls to defined I/O
 // subroutines.
-bool IONAME(OutputDerivedType)(
+bool IODECL(OutputDerivedType)(
     Cookie, const Descriptor &, const NonTbpDefinedIoTable *);
-bool IONAME(InputDerivedType)(
+bool IODECL(InputDerivedType)(
     Cookie, const Descriptor &, const NonTbpDefinedIoTable *);
 
 // Additional specifier interfaces for the connection-list of
@@ -304,56 +304,56 @@ bool IONAME(InputDerivedType)(
 // SetDelim(), GetIoMsg(), SetPad(), SetRound(), SetSign(),
 // & SetAsynchronous() are also acceptable for OPEN.
 // ACCESS=SEQUENTIAL, DIRECT, STREAM
-bool IONAME(SetAccess)(Cookie, const char *, std::size_t);
+bool IODECL(SetAccess)(Cookie, const char *, std::size_t);
 // ACTION=READ, WRITE, or READWRITE
-bool IONAME(SetAction)(Cookie, const char *, std::size_t);
+bool IODECL(SetAction)(Cookie, const char *, std::size_t);
 // CARRIAGECONTROL=LIST, FORTRAN, NONE
-bool IONAME(SetCarriagecontrol)(Cookie, const char *, std::size_t);
+bool IODECL(SetCarriagecontrol)(Cookie, const char *, std::size_t);
 // CONVERT=NATIVE, LITTLE_ENDIAN, BIG_ENDIAN, or SWAP
-bool IONAME(SetConvert)(Cookie, const char *, std::size_t);
+bool IODECL(SetConvert)(Cookie, const char *, std::size_t);
 // ENCODING=UTF-8, DEFAULT
-bool IONAME(SetEncoding)(Cookie, const char *, std::size_t);
+bool IODECL(SetEncoding)(Cookie, const char *, std::size_t);
 // FORM=FORMATTED, UNFORMATTED
-bool IONAME(SetForm)(Cookie, const char *, std::size_t);
+bool IODECL(SetForm)(Cookie, const char *, std::size_t);
 // POSITION=ASIS, REWIND, APPEND
-bool IONAME(SetPosition)(Cookie, const char *, std::size_t);
-bool IONAME(SetRecl)(Cookie, std::size_t); // RECL=
+bool IODECL(SetPosition)(Cookie, const char *, std::size_t);
+bool IODECL(SetRecl)(Cookie, std::size_t); // RECL=
 
 // STATUS can be set during an OPEN or CLOSE statement.
 // For OPEN: STATUS=OLD, NEW, SCRATCH, REPLACE, UNKNOWN
 // For CLOSE: STATUS=KEEP, DELETE
-bool IONAME(SetStatus)(Cookie, const char *, std::size_t);
+bool IODECL(SetStatus)(Cookie, const char *, std::size_t);
 
-bool IONAME(SetFile)(Cookie, const char *, std::size_t chars);
+bool IODECL(SetFile)(Cookie, const char *, std::size_t chars);
 
 // Acquires the runtime-created unit number for OPEN(NEWUNIT=)
-bool IONAME(GetNewUnit)(Cookie, int &, int kind = 4);
+bool IODECL(GetNewUnit)(Cookie, int &, int kind = 4);
 
 // READ(SIZE=), after all input items
-std::size_t IONAME(GetSize)(Cookie);
+std::size_t IODECL(GetSize)(Cookie);
 
 // INQUIRE(IOLENGTH=), after all output items
-std::size_t IONAME(GetIoLength)(Cookie);
+std::size_t IODECL(GetIoLength)(Cookie);
 
 // GetIoMsg() does not modify its argument unless an error or
 // end-of-record/file condition is present.
-void IONAME(GetIoMsg)(Cookie, char *, std::size_t); // IOMSG=
+void IODECL(GetIoMsg)(Cookie, char *, std::size_t); // IOMSG=
 
 // Defines ID= on READ/WRITE(ASYNCHRONOUS='YES')
-AsynchronousId IONAME(GetAsynchronousId)(Cookie);
+AsynchronousId IODECL(GetAsynchronousId)(Cookie);
 
 // INQUIRE() specifiers are mostly identified by their NUL-terminated
 // case-insensitive names.
 // ACCESS, ACTION, ASYNCHRONOUS, BLANK, CONVERT, DECIMAL, DELIM, DIRECT,
 // ENCODING, FORM, FORMATTED, NAME, PAD, POSITION, READ, READWRITE, ROUND,
 // SEQUENTIAL, SIGN, STREAM, UNFORMATTED, WRITE:
-bool IONAME(InquireCharacter)(Cookie, InquiryKeywordHash, char *, std::size_t);
+bool IODECL(InquireCharacter)(Cookie, InquiryKeywordHash, char *, std::size_t);
 // EXIST, NAMED, OPENED, and PENDING (without ID):
-bool IONAME(InquireLogical)(Cookie, InquiryKeywordHash, bool &);
+bool IODECL(InquireLogical)(Cookie, InquiryKeywordHash, bool &);
 // PENDING with ID
-bool IONAME(InquirePendingId)(Cookie, AsynchronousId, bool &);
+bool IODECL(InquirePendingId)(Cookie, AsynchronousId, bool &);
 // NEXTREC, NUMBER, POS, RECL, SIZE
-bool IONAME(InquireInteger64)(
+bool IODECL(InquireInteger64)(
     Cookie, InquiryKeywordHash, std::int64_t &, int kind = 8);
 
 // This function must be called to end an I/O statement, and its
diff --git a/flang/runtime/environment.cpp b/flang/runtime/environment.cpp
index b74067a377774b..b2c9665a28df28 100644
--- a/flang/runtime/environment.cpp
+++ b/flang/runtime/environment.cpp
@@ -49,6 +49,7 @@ static void SetEnvironmentDefaults(const EnvironmentDefaultList *envDefaults) {
   }
 }
 
+RT_OFFLOAD_API_GROUP_BEGIN
 Fortran::common::optional<Convert> GetConvertFromString(
     const char *x, std::size_t n) {
   static const char *keywords[]{
@@ -68,6 +69,7 @@ Fortran::common::optional<Convert> GetConvertFromString(
     return Fortran::common::nullopt;
   }
 }
+RT_OFFLOAD_API_GROUP_END
 
 void ExecutionEnvironment::Configure(int ac, const char *av[],
     const char *env[], const EnvironmentDefaultList *envDefaults) {
diff --git a/flang/runtime/environment.h b/flang/runtime/environment.h
index 6c56993fb1d6ec..b8b9f10e4e57f5 100644
--- a/flang/runtime/environment.h
+++ b/flang/runtime/environment.h
@@ -31,7 +31,7 @@ RT_OFFLOAD_VAR_GROUP_END
 // External unformatted I/O data conversions
 enum class Convert { Unknown, Native, LittleEndian, BigEndian, Swap };
 
-Fortran::common::optional<Convert> GetConvertFromString(
+RT_API_ATTRS Fortran::common::optional<Convert> GetConvertFromString(
     const char *, std::size_t);
 
 struct ExecutionEnvironment {
diff --git a/flang/runtime/freestanding-tools.h b/flang/runtime/freestanding-tools.h
index 451bf13b9fa6da..9089dc6bcf53e1 100644
--- a/flang/runtime/freestanding-tools.h
+++ b/flang/runtime/freestanding-tools.h
@@ -52,6 +52,11 @@
 #define STD_STRCPY_UNSUPPORTED 1
 #endif
 
+#if !defined(STD_STRCMP_UNSUPPORTED) && \
+    (defined(__CUDACC__) || defined(__CUDA__)) && defined(__CUDA_ARCH__)
+#define STD_STRCMP_UNSUPPORTED 1
+#endif
+
 namespace Fortran::runtime {
 
 #if STD_FILL_N_UNSUPPORTED
@@ -176,5 +181,19 @@ static inline RT_API_ATTRS char *strcpy(char *dest, const char *src) {
 using std::strcpy;
 #endif // !STD_STRCPY_UNSUPPORTED
 
+#if STD_STRCMP_UNSUPPORTED
+// Provides alternative implementation for std::strcmp(), if
+// it is not supported.
+static inline RT_API_ATTRS int strcmp(const char *lhs, const char *rhs) {
+  while (*lhs != '\0' && *lhs == *rhs) {
+    ++lhs;
+    ++rhs;
+  }
+  return static_cast<unsigned char>(*lhs) - static_cast<unsigned char>(*rhs);
+}
+#else // !STD_STRCMP_UNSUPPORTED
+using std::strcmp;
+#endif // !STD_STRCMP_UNSUPPORTED
+
 } // namespace Fortran::runtime
 #endif // FORTRAN_RUNTIME_FREESTANDING_TOOLS_H_
diff --git a/flang/runtime/io-api.cpp b/flang/runtime/io-api.cpp
index 3a86c9fa7375e1..ccb5b576451dd2 100644
--- a/flang/runtime/io-api.cpp
+++ b/flang/runtime/io-api.cpp
@@ -25,8 +25,9 @@
 #include <memory>
 
 namespace Fortran::runtime::io {
+RT_EXT_API_GROUP_BEGIN
 
-const char *InquiryKeywordHashDecode(
+RT_API_ATTRS const char *InquiryKeywordHashDecode(
     char *buffer, std::size_t n, InquiryKeywordHash hash) {
   if (n < 1) {
     return nullptr;
@@ -44,7 +45,7 @@ const char *InquiryKeywordHashDecode(
 }
 
 template <Direction DIR>
-Cookie BeginInternalArrayListIO(const Descriptor &descriptor,
+RT_API_ATTRS Cookie BeginInternalArrayListIO(const Descriptor &descriptor,
     void ** /*scratchArea*/, std::size_t /*scratchBytes*/,
     const char *sourceFile, int sourceLine) {
   Terminator oom{sourceFile, sourceLine};
@@ -54,14 +55,14 @@ Cookie BeginInternalArrayListIO(const Descriptor &descriptor,
               ->ioStatementState();
 }
 
-Cookie IONAME(BeginInternalArrayListOutput)(const Descriptor &descriptor,
+Cookie IODEF(BeginInternalArrayListO...
[truncated]

@vzakhari vzakhari merged commit 718638d into llvm:main Apr 3, 2024
6 of 7 checks passed
joker-eph added a commit that referenced this pull request Apr 4, 2024
joker-eph added a commit that referenced this pull request Apr 4, 2024
…s." (#87629)

Reverts #87543

The pre-merge Windows build is broken.
@joker-eph
Copy link
Collaborator

This broke the windows bot:

FAILED: tools/flang/unittests/Runtime/FlangRuntimeTests.exe 
cmd.exe /C "cd . && C:\BuildTools\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin\cmake.exe -E vs_link_exe --intdir=tools\flang\unittests\Runtime\CMakeFiles\FlangRuntimeTests.dir --rc="C:\Program Files (x86)\Windows Kits\10\bin\10.0.19041.0\x64\rc.exe" --mt="C:\Program Files (x86)\Windows Kits\10\bin\10.0.19041.0\x64\mt.exe" --manifests  -- C:\BuildTools\VC\Tools\MSVC\14.29.30133\bin\Hostx64\x64\link.exe /nologo tools\flang\unittests\Runtime\CMakeFiles\FlangRuntimeTests.dir\Allocatable.cpp.obj tools\flang\unittests\Runtime\CMakeFiles\FlangRuntimeTests.dir\ArrayConstructor.cpp.obj tools\flang\unittests\Runtime\CMakeFiles\FlangRuntimeTests.dir\BufferTest.cpp.obj tools\flang\unittests\Runtime\CMakeFiles\FlangRuntimeTests.dir\CharacterTest.cpp.obj tools\flang\unittests\Runtime\CMakeFiles\FlangRuntimeTests.dir\CommandTest.cpp.obj tools\flang\unittests\Runtime\CMakeFiles\FlangRuntimeTests.dir\Complex.cpp.obj tools\flang\unittests\Runtime\CMakeFiles\FlangRuntimeTests.dir\CrashHandlerFixture.cpp.obj tools\flang\unittests\Runtime\CMakeFiles\FlangRuntimeTests.dir\Derived.cpp.obj tools\flang\unittests\Runtime\CMakeFiles\FlangRuntimeTests.dir\ExternalIOTest.cpp.obj tools\flang\unittests\Runtime\CMakeFiles\FlangRuntimeTests.dir\Format.cpp.obj tools\flang\unittests\Runtime\CMakeFiles\FlangRuntimeTests.dir\Inquiry.cpp.obj tools\flang\unittests\Runtime\CMakeFiles\FlangRuntimeTests.dir\ListInputTest.cpp.obj tools\flang\unittests\Runtime\CMakeFiles\FlangRuntimeTests.dir\LogicalFormatTest.cpp.obj tools\flang\unittests\Runtime\CMakeFiles\FlangRuntimeTests.dir\Matmul.cpp.obj tools\flang\unittests\Runtime\CMakeFiles\FlangRuntimeTests.dir\MatmulTranspose.cpp.obj tools\flang\unittests\Runtime\CMakeFiles\FlangRuntimeTests.dir\MiscIntrinsic.cpp.obj tools\flang\unittests\Runtime\CMakeFiles\FlangRuntimeTests.dir\Namelist.cpp.obj tools\flang\unittests\Runtime\CMakeFiles\FlangRuntimeTests.dir\Numeric.cpp.obj tools\flang\unittests\Runtime\CMakeFiles\FlangRuntimeTests.dir\NumericalFormatTest.cpp.obj tools\flang\unittests\Runtime\CMakeFiles\FlangRuntimeTests.dir\Pointer.cpp.obj tools\flang\unittests\Runtime\CMakeFiles\FlangRuntimeTests.dir\Ragged.cpp.obj tools\flang\unittests\Runtime\CMakeFiles\FlangRuntimeTests.dir\Random.cpp.obj tools\flang\unittests\Runtime\CMakeFiles\FlangRuntimeTests.dir\Reduction.cpp.obj tools\flang\unittests\Runtime\CMakeFiles\FlangRuntimeTests.dir\RuntimeCrashTest.cpp.obj tools\flang\unittests\Runtime\CMakeFiles\FlangRuntimeTests.dir\Stop.cpp.obj tools\flang\unittests\Runtime\CMakeFiles\FlangRuntimeTests.dir\Time.cpp.obj tools\flang\unittests\Runtime\CMakeFiles\FlangRuntimeTests.dir\TemporaryStack.cpp.obj tools\flang\unittests\Runtime\CMakeFiles\FlangRuntimeTests.dir\Transformational.cpp.obj tools\flang\unittests\Runtime\CMakeFiles\FlangRuntimeTests.dir\C_\ws\buildbot\premerge-monolithic-windows\llvm-project\llvm\resources\windows_version_resource.rc.res  /out:tools\flang\unittests\Runtime\FlangRuntimeTests.exe /implib:tools\flang\unittests\Runtime\FlangRuntimeTests.lib /pdb:tools\flang\unittests\Runtime\FlangRuntimeTests.pdb /version:0.0 /machine:x64 /STACK:10000000 /INCREMENTAL:NO /subsystem:console  lib\LLVMSupport.lib  lib\llvm_gtest_main.lib  lib\llvm_gtest.lib  lib\FortranRuntime.lib  lib\LLVMSupport.lib  psapi.lib  shell32.lib  ole32.lib  uuid.lib  advapi32.lib  ws2_32.lib  delayimp.lib  -delayload:shell32.dll  -delayload:ole32.dll  lib\LLVMDemangle.lib  lib\FortranDecimal.lib  kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.lib && cd ."
LINK: command "C:\BuildTools\VC\Tools\MSVC\14.29.30133\bin\Hostx64\x64\link.exe /nologo tools\flang\unittests\Runtime\CMakeFiles\FlangRuntimeTests.dir\Allocatable.cpp.obj tools\flang\unittests\Runtime\CMakeFiles\FlangRuntimeTests.dir\ArrayConstructor.cpp.obj tools\flang\unittests\Runtime\CMakeFiles\FlangRuntimeTests.dir\BufferTest.cpp.obj tools\flang\unittests\Runtime\CMakeFiles\FlangRuntimeTests.dir\CharacterTest.cpp.obj tools\flang\unittests\Runtime\CMakeFiles\FlangRuntimeTests.dir\CommandTest.cpp.obj tools\flang\unittests\Runtime\CMakeFiles\FlangRuntimeTests.dir\Complex.cpp.obj tools\flang\unittests\Runtime\CMakeFiles\FlangRuntimeTests.dir\CrashHandlerFixture.cpp.obj tools\flang\unittests\Runtime\CMakeFiles\FlangRuntimeTests.dir\Derived.cpp.obj tools\flang\unittests\Runtime\CMakeFiles\FlangRuntimeTests.dir\ExternalIOTest.cpp.obj tools\flang\unittests\Runtime\CMakeFiles\FlangRuntimeTests.dir\Format.cpp.obj tools\flang\unittests\Runtime\CMakeFiles\FlangRuntimeTests.dir\Inquiry.cpp.obj tools\flang\unittests\Runtime\CMakeFiles\FlangRuntimeTests.dir\ListInputTest.cpp.obj tools\flang\unittests\Runtime\CMakeFiles\FlangRuntimeTests.dir\LogicalFormatTest.cpp.obj tools\flang\unittests\Runtime\CMakeFiles\FlangRuntimeTests.dir\Matmul.cpp.obj tools\flang\unittests\Runtime\CMakeFiles\FlangRuntimeTests.dir\MatmulTranspose.cpp.obj tools\flang\unittests\Runtime\CMakeFiles\FlangRuntimeTests.dir\MiscIntrinsic.cpp.obj tools\flang\unittests\Runtime\CMakeFiles\FlangRuntimeTests.dir\Namelist.cpp.obj tools\flang\unittests\Runtime\CMakeFiles\FlangRuntimeTests.dir\Numeric.cpp.obj tools\flang\unittests\Runtime\CMakeFiles\FlangRuntimeTests.dir\NumericalFormatTest.cpp.obj tools\flang\unittests\Runtime\CMakeFiles\FlangRuntimeTests.dir\Pointer.cpp.obj tools\flang\unittests\Runtime\CMakeFiles\FlangRuntimeTests.dir\Ragged.cpp.obj tools\flang\unittests\Runtime\CMakeFiles\FlangRuntimeTests.dir\Random.cpp.obj tools\flang\unittests\Runtime\CMakeFiles\FlangRuntimeTests.dir\Reduction.cpp.obj tools\flang\unittests\Runtime\CMakeFiles\FlangRuntimeTests.dir\RuntimeCrashTest.cpp.obj tools\flang\unittests\Runtime\CMakeFiles\FlangRuntimeTests.dir\Stop.cpp.obj tools\flang\unittests\Runtime\CMakeFiles\FlangRuntimeTests.dir\Time.cpp.obj tools\flang\unittests\Runtime\CMakeFiles\FlangRuntimeTests.dir\TemporaryStack.cpp.obj tools\flang\unittests\Runtime\CMakeFiles\FlangRuntimeTests.dir\Transformational.cpp.obj tools\flang\unittests\Runtime\CMakeFiles\FlangRuntimeTests.dir\C_\ws\buildbot\premerge-monolithic-windows\llvm-project\llvm\resources\windows_version_resource.rc.res /out:tools\flang\unittests\Runtime\FlangRuntimeTests.exe /implib:tools\flang\unittests\Runtime\FlangRuntimeTests.lib /pdb:tools\flang\unittests\Runtime\FlangRuntimeTests.pdb /version:0.0 /machine:x64 /STACK:10000000 /INCREMENTAL:NO /subsystem:console lib\LLVMSupport.lib lib\llvm_gtest_main.lib lib\llvm_gtest.lib lib\FortranRuntime.lib lib\LLVMSupport.lib psapi.lib shell32.lib ole32.lib uuid.lib advapi32.lib ws2_32.lib delayimp.lib -delayload:shell32.dll -delayload:ole32.dll lib\LLVMDemangle.lib lib\FortranDecimal.lib kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.lib /MANIFEST /MANIFESTFILE:tools\flang\unittests\Runtime\FlangRuntimeTests.exe.manifest" failed (exit code 1120) with the following output:
ExternalIOTest.cpp.obj : error LNK2019: unresolved external symbol _FortranAioSetForm referenced in function "private: virtual void __cdecl ExternalIOTests_TestWriteAfterEndfile_Test::TestBody(void)" (?TestBody@ExternalIOTests_TestWriteAfterEndfile_Test@@EEAAXXZ)
tools\flang\unittests\Runtime\FlangRuntimeTests.exe : fatal error LNK1120: 1 unresolved externals

https://lab.llvm.org/buildbot/#/builders/271/builds/6254

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
flang:runtime flang Flang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants