[llvm-branch-commits] [flang][runtime] Added self-printing for InternalUnit. (PR #85181)
via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Wed Mar 13 22:33:00 PDT 2024
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-flang-runtime
Author: Slava Zakharin (vzakhari)
<details>
<summary>Changes</summary>
An InternalUnit might be constructed to allocate its own "output"
buffer of a predefined size. The buffer is then used for collecting
all the output, and it printed by std::printf at the end of the statement.
This is a suggested way for supporting 'PRINT *, ...' in the device code.
It might be not ideal, because the output is not formatted the same way
as the UNIT=5 output is formatted by default.
---
Full diff: https://github.com/llvm/llvm-project/pull/85181.diff
3 Files Affected:
- (modified) flang/runtime/internal-unit.cpp (+34-3)
- (modified) flang/runtime/internal-unit.h (+12-1)
- (modified) flang/runtime/io-stmt.cpp (+5-1)
``````````diff
diff --git a/flang/runtime/internal-unit.cpp b/flang/runtime/internal-unit.cpp
index 66140e00588723..39fefd8c58cafb 100644
--- a/flang/runtime/internal-unit.cpp
+++ b/flang/runtime/internal-unit.cpp
@@ -15,13 +15,24 @@
namespace Fortran::runtime::io {
template <Direction DIR>
-InternalDescriptorUnit<DIR>::InternalDescriptorUnit(
- Scalar scalar, std::size_t length, int kind) {
+InternalDescriptorUnit<DIR>::InternalDescriptorUnit(Scalar scalar,
+ std::size_t length, int kind, const Terminator &terminator,
+ bool allocateOwnOutput) {
internalIoCharKind = kind;
recordLength = length;
endfileRecordNumber = 2;
void *pointer{reinterpret_cast<void *>(const_cast<char *>(scalar))};
- descriptor().Establish(TypeCode{TypeCategory::Character, kind}, length * kind,
+ std::size_t bufferSize{length * kind};
+ if (allocateOwnOutput) {
+ RUNTIME_CHECK(terminator, DIR == Direction::Output);
+ pointer = AllocateMemoryOrCrash(terminator, ownBufferSizeInBytes);
+ usesOwnBuffer = true;
+
+ // Reserve one character of the kind for '\0' at the end.
+ bufferSize = (ownBufferSizeInBytes / kind) * kind - kind;
+ recordLength = bufferSize / kind;
+ }
+ descriptor().Establish(TypeCode{TypeCategory::Character, kind}, bufferSize,
pointer, 0, nullptr, CFI_attribute_pointer);
}
@@ -41,6 +52,26 @@ InternalDescriptorUnit<DIR>::InternalDescriptorUnit(
endfileRecordNumber = d.Elements() + 1;
}
+template <Direction DIR> void InternalDescriptorUnit<DIR>::EndIoStatement() {
+ if constexpr (DIR == Direction::Output) {
+ if (usesOwnBuffer) {
+ // Null terminate the buffer that contains just a single record.
+ Terminator terminator{__FILE__, __LINE__};
+ RUNTIME_CHECK(terminator,
+ furthestPositionInRecord <
+ static_cast<std::int64_t>(ownBufferSizeInBytes));
+ *reinterpret_cast<char *>(CurrentRecord() + furthestPositionInRecord) =
+ '\0';
+
+ // Print the buffer and deallocate memory.
+ // FIXME: this output does not match the regular unit 5 output.
+ std::printf("%s\n", descriptor().OffsetElement());
+ FreeMemory(descriptor().OffsetElement());
+ descriptor().set_base_addr(nullptr);
+ }
+ }
+}
+
template <Direction DIR>
bool InternalDescriptorUnit<DIR>::Emit(
const char *data, std::size_t bytes, IoErrorHandler &handler) {
diff --git a/flang/runtime/internal-unit.h b/flang/runtime/internal-unit.h
index b536ffb831d550..fdf6e498eabf7e 100644
--- a/flang/runtime/internal-unit.h
+++ b/flang/runtime/internal-unit.h
@@ -12,6 +12,7 @@
#define FORTRAN_RUNTIME_IO_INTERNAL_UNIT_H_
#include "connection.h"
+#include "flang/Runtime/api-attrs.h"
#include "flang/Runtime/descriptor.h"
#include <cinttypes>
#include <type_traits>
@@ -21,13 +22,19 @@ namespace Fortran::runtime::io {
class IoErrorHandler;
// Points to (but does not own) a CHARACTER scalar or array for internal I/O.
+// The internal unit does not own the scalar buffer unless it is constructed
+// with allocateOwnOutput set to true: in this case, it owns the buffer
+// and also prints it to stdout at the end of the statement.
+// This is used to support output on offload devices.
// Does not buffer.
template <Direction DIR> class InternalDescriptorUnit : public ConnectionState {
public:
using Scalar =
std::conditional_t<DIR == Direction::Input, const char *, char *>;
- InternalDescriptorUnit(Scalar, std::size_t chars, int kind);
+ InternalDescriptorUnit(Scalar, std::size_t chars, int kind,
+ const Terminator &terminator, bool allocateOwnOutput = false);
InternalDescriptorUnit(const Descriptor &, const Terminator &);
+ void EndIoStatement();
bool Emit(const char *, std::size_t, IoErrorHandler &);
std::size_t GetNextInputBytes(const char *&, IoErrorHandler &);
@@ -48,6 +55,10 @@ template <Direction DIR> class InternalDescriptorUnit : public ConnectionState {
void BlankFillOutputRecord();
StaticDescriptor<maxRank, true /*addendum*/> staticDescriptor_;
+ RT_OFFLOAD_VAR_GROUP_BEGIN
+ static constexpr std::size_t ownBufferSizeInBytes{1024};
+ RT_OFFLOAD_VAR_GROUP_END
+ bool usesOwnBuffer{false};
};
extern template class InternalDescriptorUnit<Direction::Output>;
diff --git a/flang/runtime/io-stmt.cpp b/flang/runtime/io-stmt.cpp
index efefbc5e1a1c08..417225f79006ff 100644
--- a/flang/runtime/io-stmt.cpp
+++ b/flang/runtime/io-stmt.cpp
@@ -82,7 +82,8 @@ void IoStatementBase::BadInquiryKeywordHashCrash(InquiryKeywordHash inquiry) {
template <Direction DIR>
InternalIoStatementState<DIR>::InternalIoStatementState(
Buffer scalar, std::size_t length, const char *sourceFile, int sourceLine)
- : IoStatementBase{sourceFile, sourceLine}, unit_{scalar, length, 1} {}
+ : IoStatementBase{sourceFile, sourceLine},
+ unit_{scalar, length, /*kind=*/1, *this} {}
template <Direction DIR>
InternalIoStatementState<DIR>::InternalIoStatementState(
@@ -119,6 +120,9 @@ template <Direction DIR> void InternalIoStatementState<DIR>::BackspaceRecord() {
}
template <Direction DIR> int InternalIoStatementState<DIR>::EndIoStatement() {
+ if constexpr (DIR == Direction::Output) {
+ unit_.EndIoStatement();
+ }
auto result{IoStatementBase::EndIoStatement()};
if (free_) {
FreeMemory(this);
``````````
</details>
https://github.com/llvm/llvm-project/pull/85181
More information about the llvm-branch-commits
mailing list