//
//===----------------------------------------------------------------------===//
-// Portable 128-bit unsigned integer arithmetic for use in impoverished
-// C++ implementations lacking __uint128_t.
+// Portable 128-bit integer arithmetic for use in impoverished C++
+// implementations lacking __uint128_t & __int128_t.
#ifndef FORTRAN_COMMON_UINT128_H_
#define FORTRAN_COMMON_UINT128_H_
constexpr Int128 &operator=(const Int128 &) = default;
constexpr Int128 &operator=(Int128 &&) = default;
+ constexpr Int128(const Int128<!IS_SIGNED> &n)
+ : low_{n.low()}, high_{n.high()} {}
+ constexpr Int128(Int128<!IS_SIGNED> &&n) : low_{n.low()}, high_{n.high()} {}
+ constexpr Int128 &operator=(const Int128<!IS_SIGNED> &n) {
+ low_ = n.low();
+ high_ = n.high();
+ }
+ constexpr Int128 &operator=(Int128<!IS_SIGNED> &&n) {
+ low_ = n.low();
+ high_ = n.high();
+ }
+
constexpr Int128 operator+() const { return *this; }
constexpr Int128 operator~() const { return {~high_, ~low_}; }
constexpr Int128 operator-() const { return ~*this + 1; }
#ifndef FORTRAN_RUNTIME_IO_API_H_
#define FORTRAN_RUNTIME_IO_API_H_
+#include "flang/Common/uint128.h"
#include "flang/Runtime/entry-names.h"
#include "flang/Runtime/iostat.h"
#include <cinttypes>
// These functions initiate data transfer statements (READ, WRITE, PRINT).
// Example: PRINT *, 666 is implemented as the series of calls:
// Cookie cookie{BeginExternalListOutput(DefaultUnit,__FILE__,__LINE__)};
-// OutputInteger64(cookie, 666);
+// OutputInteger32(cookie, 666);
// EndIoStatement(cookie);
// Internal I/O initiation
bool IONAME(InputUnformattedBlock)(
Cookie, char *, std::size_t, std::size_t elementBytes);
// Formatted (including list directed) I/O data items
+bool IONAME(OutputInteger8)(Cookie, std::int8_t);
+bool IONAME(OutputInteger16)(Cookie, std::int16_t);
+bool IONAME(OutputInteger32)(Cookie, std::int32_t);
bool IONAME(OutputInteger64)(Cookie, std::int64_t);
+#ifdef __SIZEOF_INT128__
+bool IONAME(OutputInteger128)(Cookie, common::int128_t);
+#endif
bool IONAME(InputInteger)(Cookie, std::int64_t &, int kind = 8);
bool IONAME(OutputReal32)(Cookie, float);
bool IONAME(InputReal32)(Cookie, float &);
// automatic repetition counts, like "10*3.14159", for list-directed and
// NAMELIST array output.
-template <typename A, Direction DIR>
+template <int KIND, Direction DIR>
inline bool FormattedIntegerIO(
IoStatementState &io, const Descriptor &descriptor) {
std::size_t numElements{descriptor.Elements()};
SubscriptValue subscripts[maxRank];
descriptor.GetLowerBounds(subscripts);
+ using IntType = CppTypeFor<TypeCategory::Integer, KIND>;
for (std::size_t j{0}; j < numElements; ++j) {
if (auto edit{io.GetNextDataEdit()}) {
- A &x{ExtractElement<A>(io, descriptor, subscripts)};
+ IntType &x{ExtractElement<IntType>(io, descriptor, subscripts)};
if constexpr (DIR == Direction::Output) {
- if (!EditIntegerOutput(io, *edit, static_cast<std::int64_t>(x))) {
+ if (!EditIntegerOutput<KIND>(io, *edit, x)) {
return false;
}
} else if (edit->descriptor != DataEdit::ListDirectedNullValue) {
- if (!EditIntegerInput(io, *edit, reinterpret_cast<void *>(&x),
- static_cast<int>(sizeof(A)))) {
+ if (!EditIntegerInput(io, *edit, reinterpret_cast<void *>(&x), KIND)) {
return false;
}
}
return true;
}
-template <typename A, Direction DIR>
+template <int KIND, Direction DIR>
inline bool FormattedLogicalIO(
IoStatementState &io, const Descriptor &descriptor) {
std::size_t numElements{descriptor.Elements()};
SubscriptValue subscripts[maxRank];
descriptor.GetLowerBounds(subscripts);
auto *listOutput{io.get_if<ListDirectedStatementState<Direction::Output>>()};
+ using IntType = CppTypeFor<TypeCategory::Integer, KIND>;
for (std::size_t j{0}; j < numElements; ++j) {
- A &x{ExtractElement<A>(io, descriptor, subscripts)};
+ IntType &x{ExtractElement<IntType>(io, descriptor, subscripts)};
if (listOutput) {
if (!ListDirectedLogicalOutput(io, *listOutput, x != 0)) {
return false;
case TypeCategory::Integer:
switch (kind) {
case 1:
- return FormattedIntegerIO<CppTypeFor<TypeCategory::Integer, 1>, DIR>(
- io, descriptor);
+ return FormattedIntegerIO<1, DIR>(io, descriptor);
case 2:
- return FormattedIntegerIO<CppTypeFor<TypeCategory::Integer, 2>, DIR>(
- io, descriptor);
+ return FormattedIntegerIO<2, DIR>(io, descriptor);
case 4:
- return FormattedIntegerIO<CppTypeFor<TypeCategory::Integer, 4>, DIR>(
- io, descriptor);
+ return FormattedIntegerIO<4, DIR>(io, descriptor);
case 8:
- return FormattedIntegerIO<CppTypeFor<TypeCategory::Integer, 8>, DIR>(
- io, descriptor);
+ return FormattedIntegerIO<8, DIR>(io, descriptor);
case 16:
- return FormattedIntegerIO<CppTypeFor<TypeCategory::Integer, 16>, DIR>(
- io, descriptor);
+ return FormattedIntegerIO<16, DIR>(io, descriptor);
default:
handler.Crash(
"DescriptorIO: Unimplemented INTEGER kind (%d) in descriptor",
case TypeCategory::Logical:
switch (kind) {
case 1:
- return FormattedLogicalIO<CppTypeFor<TypeCategory::Integer, 1>, DIR>(
- io, descriptor);
+ return FormattedLogicalIO<1, DIR>(io, descriptor);
case 2:
- return FormattedLogicalIO<CppTypeFor<TypeCategory::Integer, 2>, DIR>(
- io, descriptor);
+ return FormattedLogicalIO<2, DIR>(io, descriptor);
case 4:
- return FormattedLogicalIO<CppTypeFor<TypeCategory::Integer, 4>, DIR>(
- io, descriptor);
+ return FormattedLogicalIO<4, DIR>(io, descriptor);
case 8:
- return FormattedLogicalIO<CppTypeFor<TypeCategory::Integer, 8>, DIR>(
- io, descriptor);
+ return FormattedLogicalIO<8, DIR>(io, descriptor);
default:
handler.Crash(
"DescriptorIO: Unimplemented LOGICAL kind (%d) in descriptor",
namespace Fortran::runtime::io {
-template <typename INT, typename UINT>
-bool EditIntegerOutput(IoStatementState &io, const DataEdit &edit, INT n) {
- char buffer[130], *end = &buffer[sizeof buffer], *p = end;
- bool isNegative{false};
- if constexpr (std::is_same_v<INT, UINT>) {
- isNegative = (n >> (8 * sizeof(INT) - 1)) != 0;
- } else {
- isNegative = n < 0;
- }
- UINT un{static_cast<UINT>(isNegative ? -n : n)};
+template <int KIND>
+bool EditIntegerOutput(IoStatementState &io, const DataEdit &edit,
+ common::HostSignedIntType<8 * KIND> n) {
+ char buffer[130], *end{&buffer[sizeof buffer]}, *p{end};
+ bool isNegative{n < 0};
+ using Unsigned = common::HostUnsignedIntType<8 * KIND>;
+ Unsigned un{static_cast<Unsigned>(n)};
int signChars{0};
switch (edit.descriptor) {
case DataEdit::ListDirected:
case 'G':
case 'I':
+ if (isNegative) {
+ un = -n;
+ }
if (isNegative || (edit.modes.editingFlags & signPlus)) {
signChars = 1; // '-' or '+'
}
while (un > 0) {
auto quotient{un / 10u};
- *--p = '0' + static_cast<int>(un - UINT{10} * quotient);
+ *--p = '0' + static_cast<int>(un - 10u * quotient);
un = quotient;
}
break;
"EX output editing is not yet implemented"); // TODO
}
-template <int binaryPrecision>
-bool RealOutputEditing<binaryPrecision>::Edit(const DataEdit &edit) {
+template <int KIND> bool RealOutputEditing<KIND>::Edit(const DataEdit &edit) {
switch (edit.descriptor) {
case 'D':
return EditEorDOutput(edit);
case 'B':
case 'O':
case 'Z':
- return EditIntegerOutput(io_, edit,
+ return EditIntegerOutput<KIND>(io_, edit,
decimal::BinaryFloatingPointNumber<binaryPrecision>{x_}.raw());
case 'G':
return Edit(EditForGOutput(edit));
io.Emit(x, std::min(width, len));
}
-template bool EditIntegerOutput<std::int64_t, std::uint64_t>(
+template bool EditIntegerOutput<1>(
+ IoStatementState &, const DataEdit &, std::int8_t);
+template bool EditIntegerOutput<2>(
+ IoStatementState &, const DataEdit &, std::int16_t);
+template bool EditIntegerOutput<4>(
+ IoStatementState &, const DataEdit &, std::int32_t);
+template bool EditIntegerOutput<8>(
IoStatementState &, const DataEdit &, std::int64_t);
-template bool EditIntegerOutput<common::uint128_t, common::uint128_t>(
- IoStatementState &, const DataEdit &, common::uint128_t);
+template bool EditIntegerOutput<16>(
+ IoStatementState &, const DataEdit &, common::int128_t);
template class RealOutputEditing<2>;
template class RealOutputEditing<3>;
// The DataEdit reference is const here (and elsewhere in this header) so that
// one edit descriptor with a repeat factor may safely serve to edit
// multiple elements of an array.
-template <typename INT = std::int64_t, typename UINT = std::uint64_t>
-bool EditIntegerOutput(IoStatementState &, const DataEdit &, INT);
+template <int KIND>
+bool EditIntegerOutput(
+ IoStatementState &, const DataEdit &, common::HostSignedIntType<8 * KIND>);
// Encapsulates the state of a REAL output conversion.
class RealOutputEditingBase {
bool EditDefaultCharacterOutput(
IoStatementState &, const DataEdit &, const char *, std::size_t);
-extern template bool EditIntegerOutput<std::int64_t, std::uint64_t>(
+extern template bool EditIntegerOutput<1>(
+ IoStatementState &, const DataEdit &, std::int8_t);
+extern template bool EditIntegerOutput<2>(
+ IoStatementState &, const DataEdit &, std::int16_t);
+extern template bool EditIntegerOutput<4>(
+ IoStatementState &, const DataEdit &, std::int32_t);
+extern template bool EditIntegerOutput<8>(
IoStatementState &, const DataEdit &, std::int64_t);
-extern template bool EditIntegerOutput<common::uint128_t, common::uint128_t>(
- IoStatementState &, const DataEdit &, common::uint128_t);
+extern template bool EditIntegerOutput<16>(
+ IoStatementState &, const DataEdit &, common::int128_t);
extern template class RealOutputEditing<2>;
extern template class RealOutputEditing<3>;
return false;
}
+bool IONAME(OutputInteger8)(Cookie cookie, std::int8_t n) {
+ cookie->CheckFormattedStmtType<Direction::Output>("OutputInteger8");
+ StaticDescriptor staticDescriptor;
+ Descriptor &descriptor{staticDescriptor.descriptor()};
+ descriptor.Establish(
+ TypeCategory::Integer, 1, reinterpret_cast<void *>(&n), 0);
+ return descr::DescriptorIO<Direction::Output>(*cookie, descriptor);
+}
+
+bool IONAME(OutputInteger16)(Cookie cookie, std::int16_t n) {
+ cookie->CheckFormattedStmtType<Direction::Output>("OutputInteger16");
+ StaticDescriptor staticDescriptor;
+ Descriptor &descriptor{staticDescriptor.descriptor()};
+ descriptor.Establish(
+ TypeCategory::Integer, 2, reinterpret_cast<void *>(&n), 0);
+ return descr::DescriptorIO<Direction::Output>(*cookie, descriptor);
+}
+
+bool IONAME(OutputInteger32)(Cookie cookie, std::int32_t n) {
+ cookie->CheckFormattedStmtType<Direction::Output>("OutputInteger32");
+ StaticDescriptor staticDescriptor;
+ Descriptor &descriptor{staticDescriptor.descriptor()};
+ descriptor.Establish(
+ TypeCategory::Integer, 4, reinterpret_cast<void *>(&n), 0);
+ return descr::DescriptorIO<Direction::Output>(*cookie, descriptor);
+}
+
bool IONAME(OutputInteger64)(Cookie cookie, std::int64_t n) {
cookie->CheckFormattedStmtType<Direction::Output>("OutputInteger64");
StaticDescriptor staticDescriptor;
Descriptor &descriptor{staticDescriptor.descriptor()};
descriptor.Establish(
- TypeCategory::Integer, sizeof n, reinterpret_cast<void *>(&n), 0);
+ TypeCategory::Integer, 8, reinterpret_cast<void *>(&n), 0);
+ return descr::DescriptorIO<Direction::Output>(*cookie, descriptor);
+}
+
+#ifdef __SIZEOF_INT128__
+bool IONAME(OutputInteger128)(Cookie cookie, common::int128_t n) {
+ cookie->CheckFormattedStmtType<Direction::Output>("OutputInteger128");
+ StaticDescriptor staticDescriptor;
+ Descriptor &descriptor{staticDescriptor.descriptor()};
+ descriptor.Establish(
+ TypeCategory::Integer, 16, reinterpret_cast<void *>(&n), 0);
return descr::DescriptorIO<Direction::Output>(*cookie, descriptor);
}
+#endif
bool IONAME(InputInteger)(Cookie cookie, std::int64_t &n, int kind) {
cookie->CheckFormattedStmtType<Direction::Input>("InputInteger");
// Write string, integer, and logical values to buffer
IONAME(OutputAscii)(cookie, "WORLD", 5);
IONAME(OutputInteger64)(cookie, 678);
- IONAME(OutputInteger64)(cookie, 0xfeedface);
+ IONAME(OutputInteger32)(cookie, 0xfeedface);
IONAME(OutputLogical)(cookie, true);
// Ensure IO succeeded