Skip to content

Commit

Permalink
[flang] Progress on Fortran I/O runtime
Browse files Browse the repository at this point in the history
Use internal units for internal I/O state

Replace use of virtual functions

reference_wrapper

Internal formatted output to array descriptor

Delete dead code

Begin list-directed internal output

Refactorings and renamings for clarity

List-directed external I/O (character)

COMPLEX list-directed output

Control list items

First cut at unformatted I/O

More OPEN statement work; rename class to ExternalFileUnit

Complete OPEN (exc. for POSITION=), add CLOSE()

OPEN(POSITION=)

Flush buffers on crash and for terminal output; clean up

Documentation

Fix backquote in documentation

Fix typo in comment

Begin implementation of input

Refactor binary floating-point properties to a new header, simplify numeric output editing

Dodge spurious GCC 7.2 build warning

Address review comments

Original-commit: flang-compiler/f18@9c4bba1
Reviewed-on: flang-compiler/f18#982
  • Loading branch information
klausler committed Feb 13, 2020
1 parent dbea781 commit 95696d5
Show file tree
Hide file tree
Showing 54 changed files with 2,928 additions and 1,177 deletions.
6 changes: 3 additions & 3 deletions flang/documentation/FortranForCProgrammers.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
<!--===- documentation/FortranForCProgrammers.md
<!--===- documentation/FortranForCProgrammers.md
Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
See https://llvm.org/LICENSE.txt for license information.
SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-->

Fortran For C Programmers
Expand Down
341 changes: 341 additions & 0 deletions flang/documentation/IORuntimeInternals.md

Large diffs are not rendered by default.

86 changes: 86 additions & 0 deletions flang/include/flang/common/real.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
//===-- include/flang/common/real.h -----------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef FORTRAN_COMMON_REAL_H_
#define FORTRAN_COMMON_REAL_H_

// Characteristics of IEEE-754 & related binary floating-point numbers.
// The various representations are distinguished by their binary precisions
// (number of explicit significand bits and any implicit MSB in the fraction).

#include <cinttypes>

namespace Fortran::common {

// Total representation size in bits for each type
static constexpr int BitsForBinaryPrecision(int binaryPrecision) {
switch (binaryPrecision) {
case 8: return 16; // IEEE single (truncated): 1+8+7
case 11: return 16; // IEEE half precision: 1+5+10
case 24: return 32; // IEEE single precision: 1+8+23
case 53: return 64; // IEEE double precision: 1+11+52
case 64: return 80; // x87 extended precision: 1+15+64
case 106: return 128; // "double-double": 2*(1+11+52)
case 112: return 128; // IEEE quad precision: 1+16+111
default: return -1;
}
}

// Number of significant decimal digits in the fraction of the
// exact conversion of the least nonzero (subnormal) value
// in each type; i.e., a 128-bit quad value can be formatted
// exactly with FORMAT(E0.22981).
static constexpr int MaxDecimalConversionDigits(int binaryPrecision) {
switch (binaryPrecision) {
case 8: return 93;
case 11: return 17;
case 24: return 105;
case 53: return 751;
case 64: return 11495;
case 106: return 2 * 751;
case 112: return 22981;
default: return -1;
}
}

template<int BINARY_PRECISION> class RealDetails {
private:
// Converts bit widths to whole decimal digits
static constexpr int LogBaseTwoToLogBaseTen(int logb2) {
constexpr std::int64_t LogBaseTenOfTwoTimesTenToThe12th{301029995664};
constexpr std::int64_t TenToThe12th{1000000000000};
std::int64_t logb10{
(logb2 * LogBaseTenOfTwoTimesTenToThe12th) / TenToThe12th};
return static_cast<int>(logb10);
}

public:
static constexpr int binaryPrecision{BINARY_PRECISION};
static constexpr int bits{BitsForBinaryPrecision(binaryPrecision)};
static constexpr bool isImplicitMSB{binaryPrecision != 64 /*x87*/};
static constexpr int significandBits{binaryPrecision - isImplicitMSB};
static constexpr int exponentBits{bits - significandBits - 1 /*sign*/};
static constexpr int maxExponent{(1 << exponentBits) - 1};
static constexpr int exponentBias{maxExponent / 2};

static constexpr int decimalPrecision{
LogBaseTwoToLogBaseTen(binaryPrecision - 1)};
static constexpr int decimalRange{LogBaseTwoToLogBaseTen(exponentBias - 1)};

// Number of significant decimal digits in the fraction of the
// exact conversion of the least nonzero subnormal.
static constexpr int maxDecimalConversionDigits{
MaxDecimalConversionDigits(binaryPrecision)};

static_assert(binaryPrecision > 0);
static_assert(exponentBits > 1);
static_assert(exponentBits <= 16);
};

}
#endif // FORTRAN_COMMON_REAL_H_
39 changes: 15 additions & 24 deletions flang/include/flang/decimal/binary-floating-point.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
// Access and manipulate the fields of an IEEE-754 binary
// floating-point value via a generalized template.

#include "flang/common/real.h"
#include "flang/common/uint128.h"
#include <cinttypes>
#include <climits>
Expand All @@ -20,34 +21,24 @@

namespace Fortran::decimal {

static constexpr int BitsForPrecision(int prec) {
switch (prec) {
case 8: return 16;
case 11: return 16;
case 24: return 32;
case 53: return 64;
case 64: return 80;
case 112: return 128;
default: return -1;
}
}
template<int BINARY_PRECISION>
struct BinaryFloatingPointNumber
: public common::RealDetails<BINARY_PRECISION> {

// LOG10(2.)*1E12
static constexpr std::int64_t ScaledLogBaseTenOfTwo{301029995664};
using Details = common::RealDetails<BINARY_PRECISION>;
using Details::bits;
using Details::decimalPrecision;
using Details::decimalRange;
using Details::exponentBias;
using Details::exponentBits;
using Details::isImplicitMSB;
using Details::maxDecimalConversionDigits;
using Details::maxExponent;
using Details::significandBits;

template<int PRECISION> struct BinaryFloatingPointNumber {
static constexpr int precision{PRECISION};
static constexpr int bits{BitsForPrecision(precision)};
using RawType = common::HostUnsignedIntType<bits>;
static_assert(CHAR_BIT * sizeof(RawType) >= bits);
static constexpr bool implicitMSB{precision != 64 /*x87*/};
static constexpr int significandBits{precision - implicitMSB};
static constexpr int exponentBits{bits - 1 - significandBits};
static constexpr int maxExponent{(1 << exponentBits) - 1};
static constexpr int exponentBias{maxExponent / 2};
static constexpr RawType significandMask{(RawType{1} << significandBits) - 1};
static constexpr int RANGE{static_cast<int>(
(exponentBias - 1) * ScaledLogBaseTenOfTwo / 1000000000000)};

constexpr BinaryFloatingPointNumber() {} // zero
constexpr BinaryFloatingPointNumber(
Expand Down Expand Up @@ -76,7 +67,7 @@ template<int PRECISION> struct BinaryFloatingPointNumber {
constexpr RawType Significand() const { return raw & significandMask; }
constexpr RawType Fraction() const {
RawType sig{Significand()};
if (implicitMSB && BiasedExponent() > 0) {
if (isImplicitMSB && BiasedExponent() > 0) {
sig |= RawType{1} << significandBits;
}
return sig;
Expand Down
9 changes: 9 additions & 0 deletions flang/include/flang/decimal/decimal.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,15 @@ enum DecimalConversionFlags {
AlwaysSign = 2, /* emit leading '+' if not negative */
};

/*
* When allocating decimal conversion output buffers, use the maximum
* number of significant decimal digits in the representation of the
* least nonzero value, and add this extra space for a sign, a NUL, and
* some extra due to the library working internally in base 10**16
* and computing its output size in multiples of 16.
*/
#define EXTRA_DECIMAL_CONVERSION_SPACE (1 + 1 + 16 - 1)

#ifdef __cplusplus
template<int PREC>
ConversionToDecimalResult ConvertToDecimal(char *, size_t,
Expand Down
4 changes: 2 additions & 2 deletions flang/include/flang/evaluate/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -130,9 +130,9 @@ struct Rounding {
static constexpr Rounding defaultRounding;

#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
constexpr bool IsHostLittleEndian{false};
constexpr bool isHostLittleEndian{false};
#elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
constexpr bool IsHostLittleEndian{true};
constexpr bool isHostLittleEndian{true};
#else
#error host endianness is not known
#endif
Expand Down
2 changes: 1 addition & 1 deletion flang/include/flang/evaluate/complex.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ extern template class Complex<Real<Integer<16>, 11>>;
extern template class Complex<Real<Integer<16>, 8>>;
extern template class Complex<Real<Integer<32>, 24>>;
extern template class Complex<Real<Integer<64>, 53>>;
extern template class Complex<Real<Integer<80>, 64, false>>;
extern template class Complex<Real<Integer<80>, 64>>;
extern template class Complex<Real<Integer<128>, 112>>;
}
#endif // FORTRAN_EVALUATE_COMPLEX_H_
2 changes: 1 addition & 1 deletion flang/include/flang/evaluate/integer.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ namespace Fortran::evaluate::value {
// Member functions that correspond to Fortran intrinsic functions are
// named accordingly in ALL CAPS so that they can be referenced easily in
// the language standard.
template<int BITS, bool IS_LITTLE_ENDIAN = IsHostLittleEndian,
template<int BITS, bool IS_LITTLE_ENDIAN = isHostLittleEndian,
int PARTBITS = BITS <= 32 ? BITS : 32,
typename PART = HostUnsignedInt<PARTBITS>,
typename BIGPART = HostUnsignedInt<PARTBITS * 2>>
Expand Down
58 changes: 29 additions & 29 deletions flang/include/flang/evaluate/real.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "formatting.h"
#include "integer.h"
#include "rounding-bits.h"
#include "flang/common/real.h"
#include "flang/evaluate/common.h"
#include <cinttypes>
#include <limits>
Expand All @@ -30,26 +31,25 @@ static constexpr std::int64_t ScaledLogBaseTenOfTwo{301029995664};
// Models IEEE binary floating-point numbers (IEEE 754-2008,
// ISO/IEC/IEEE 60559.2011). The first argument to this
// class template must be (or look like) an instance of Integer<>;
// the second specifies the number of effective bits in the fraction;
// the third, if true, indicates that the most significant position of the
// fraction is an implicit bit whose value is assumed to be 1 in a finite
// normal number.
template<typename WORD, int PREC, bool IMPLICIT_MSB = true> class Real {
// the second specifies the number of effective bits (binary precision)
// in the fraction.
template<typename WORD, int PREC>
class Real : public common::RealDetails<PREC> {
public:
using Word = WORD;
static constexpr int binaryPrecision{PREC};
using Details = common::RealDetails<PREC>;
using Details::exponentBias;
using Details::exponentBits;
using Details::isImplicitMSB;
using Details::maxExponent;
using Details::significandBits;

static constexpr int bits{Word::bits};
static constexpr int precision{PREC};
using Fraction = Integer<precision>; // all bits made explicit
static constexpr bool implicitMSB{IMPLICIT_MSB};
static constexpr int significandBits{precision - implicitMSB};
static constexpr int exponentBits{bits - significandBits - 1 /*sign*/};
static_assert(precision > 0);
static_assert(exponentBits > 1);
static_assert(exponentBits <= 16);
static constexpr int maxExponent{(1 << exponentBits) - 1};
static constexpr int exponentBias{maxExponent / 2};

template<typename W, int P, bool I> friend class Real;
static_assert(bits >= Details::bits);
using Fraction = Integer<binaryPrecision>; // all bits made explicit

template<typename W, int P> friend class Real;

constexpr Real() {} // +0.0
constexpr Real(const Real &) = default;
Expand Down Expand Up @@ -130,12 +130,13 @@ template<typename WORD, int PREC, bool IMPLICIT_MSB = true> class Real {

static constexpr Real EPSILON() {
Real epsilon;
epsilon.Normalize(false, exponentBias - precision, Fraction::MASKL(1));
epsilon.Normalize(
false, exponentBias - binaryPrecision, Fraction::MASKL(1));
return epsilon;
}
static constexpr Real HUGE() {
Real huge;
huge.Normalize(false, maxExponent - 1, Fraction::MASKR(precision));
huge.Normalize(false, maxExponent - 1, Fraction::MASKR(binaryPrecision));
return huge;
}
static constexpr Real TINY() {
Expand All @@ -144,11 +145,9 @@ template<typename WORD, int PREC, bool IMPLICIT_MSB = true> class Real {
return tiny;
}

static constexpr int DIGITS{precision};
static constexpr int PRECISION{static_cast<int>(
(precision - 1) * ScaledLogBaseTenOfTwo / 1000000000000)};
static constexpr int RANGE{static_cast<int>(
(exponentBias - 1) * ScaledLogBaseTenOfTwo / 1000000000000)};
static constexpr int DIGITS{binaryPrecision};
static constexpr int PRECISION{Details::decimalPrecision};
static constexpr int RANGE{Details::decimalRange};
static constexpr int MAXEXPONENT{maxExponent - 1 - exponentBias};
static constexpr int MINEXPONENT{1 - exponentBias};

Expand Down Expand Up @@ -190,7 +189,7 @@ template<typename WORD, int PREC, bool IMPLICIT_MSB = true> class Real {
}
ValueWithRealFlags<Real> result;
int exponent{exponentBias + absN.bits - leadz - 1};
int bitsNeeded{absN.bits - (leadz + implicitMSB)};
int bitsNeeded{absN.bits - (leadz + isImplicitMSB)};
int bitsLost{bitsNeeded - significandBits};
if (bitsLost <= 0) {
Fraction fraction{Fraction::ConvertUnsigned(absN).value};
Expand Down Expand Up @@ -224,7 +223,8 @@ template<typename WORD, int PREC, bool IMPLICIT_MSB = true> class Real {
result.flags.set(
RealFlag::Overflow, exponent >= exponentBias + result.value.bits);
result.flags |= intPart.flags;
int shift{exponent - exponentBias - precision + 1}; // positive -> left
int shift{
exponent - exponentBias - binaryPrecision + 1}; // positive -> left
result.value =
result.value.ConvertUnsigned(intPart.value.GetFraction().SHIFTR(-shift))
.value.SHIFTL(shift);
Expand Down Expand Up @@ -252,7 +252,7 @@ template<typename WORD, int PREC, bool IMPLICIT_MSB = true> class Real {
}
ValueWithRealFlags<Real> result;
int exponent{exponentBias + x.UnbiasedExponent()};
int bitsLost{A::precision - precision};
int bitsLost{A::binaryPrecision - binaryPrecision};
if (exponent < 1) {
bitsLost += 1 - exponent;
exponent = 1;
Expand Down Expand Up @@ -282,7 +282,7 @@ template<typename WORD, int PREC, bool IMPLICIT_MSB = true> class Real {
// Extracts the fraction; any implied bit is made explicit.
constexpr Fraction GetFraction() const {
Fraction result{Fraction::ConvertUnsigned(word_).value};
if constexpr (!implicitMSB) {
if constexpr (!isImplicitMSB) {
return result;
} else {
int exponent{Exponent()};
Expand Down Expand Up @@ -366,7 +366,7 @@ extern template class Real<Integer<16>, 11>; // IEEE half format
extern template class Real<Integer<16>, 8>; // the "other" half format
extern template class Real<Integer<32>, 24>; // IEEE single
extern template class Real<Integer<64>, 53>; // IEEE double
extern template class Real<Integer<80>, 64, false>; // 80387 extended precision
extern template class Real<Integer<80>, 64>; // 80387 extended precision
extern template class Real<Integer<128>, 112>; // IEEE quad
// N.B. No "double-double" support.
}
Expand Down
2 changes: 1 addition & 1 deletion flang/include/flang/evaluate/type.h
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,7 @@ class Type<TypeCategory::Real, 8> : public TypeBase<TypeCategory::Real, 8> {
template<>
class Type<TypeCategory::Real, 10> : public TypeBase<TypeCategory::Real, 10> {
public:
using Scalar = value::Real<value::Integer<80>, 64, false>;
using Scalar = value::Real<value::Integer<80>, 64>;
};

// REAL(KIND=16) is IEEE quad precision (128 bits)
Expand Down
3 changes: 2 additions & 1 deletion flang/lib/decimal/big-radix-floating-point.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,8 @@ template<int PREC, int LOG10RADIX = 16> class BigRadixFloatingPointNumber {

// The base-2 logarithm of the least significant bit that can arise
// in a subnormal IEEE floating-point number.
static constexpr int minLog2AnyBit{-Real::exponentBias - Real::precision};
static constexpr int minLog2AnyBit{
-Real::exponentBias - Real::binaryPrecision};

// The number of Digits needed to represent the smallest subnormal.
static constexpr int maxDigits{3 - minLog2AnyBit / log10Radix};
Expand Down
Loading

0 comments on commit 95696d5

Please sign in to comment.