Warning: This file is not a C or C++ file. It does not have highlighting.

1//===-- include/flang/Evaluate/rounding-bits.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_EVALUATE_ROUNDING_BITS_H_
10#define FORTRAN_EVALUATE_ROUNDING_BITS_H_
11
12#include "flang/Evaluate/target.h"
13
14// A helper class used by Real<> to determine rounding of rational results
15// to floating-point values. Bits lost from intermediate computations by
16// being shifted rightward are accumulated in instances of this class.
17
18namespace Fortran::evaluate::value {
19
20class RoundingBits {
21public:
22 constexpr RoundingBits(
23 bool guard = false, bool round = false, bool sticky = false)
24 : guard_{guard}, round_{round}, sticky_{sticky} {}
25
26 template <typename FRACTION>
27 constexpr RoundingBits(const FRACTION &fraction, int rshift) {
28 if (rshift > 0 && rshift < fraction.bits + 1) {
29 guard_ = fraction.BTEST(rshift - 1);
30 }
31 if (rshift > 1 && rshift < fraction.bits + 2) {
32 round_ = fraction.BTEST(rshift - 2);
33 }
34 if (rshift > 2) {
35 if (rshift >= fraction.bits + 2) {
36 sticky_ = !fraction.IsZero();
37 } else {
38 auto mask{fraction.MASKR(rshift - 2)};
39 sticky_ = !fraction.IAND(mask).IsZero();
40 }
41 }
42 }
43
44 constexpr bool guard() const { return guard_; }
45 constexpr bool round() const { return round_; }
46 constexpr bool sticky() const { return sticky_; }
47 constexpr bool empty() const { return !(guard_ | round_ | sticky_); }
48
49 constexpr bool Negate() {
50 bool carry{!sticky_};
51 if (carry) {
52 carry = !round_;
53 } else {
54 round_ = !round_;
55 }
56 if (carry) {
57 carry = !guard_;
58 } else {
59 guard_ = !guard_;
60 }
61 return carry;
62 }
63
64 constexpr bool ShiftLeft() {
65 bool oldGuard{guard_};
66 guard_ = round_;
67 round_ = sticky_;
68 return oldGuard;
69 }
70
71 constexpr void ShiftRight(bool newGuard) {
72 sticky_ |= round_;
73 round_ = guard_;
74 guard_ = newGuard;
75 }
76
77 // Determines whether a value should be rounded by increasing its
78 // fraction, given a rounding mode and a summary of the lost bits.
79 constexpr bool MustRound(
80 Rounding rounding, bool isNegative, bool isOdd) const {
81 bool round{false}; // to dodge bogus g++ warning about missing return
82 switch (rounding.mode) {
83 case common::RoundingMode::TiesToEven:
84 round = guard_ && (round_ | sticky_ | isOdd);
85 break;
86 case common::RoundingMode::ToZero:
87 break;
88 case common::RoundingMode::Down:
89 round = isNegative && !empty();
90 break;
91 case common::RoundingMode::Up:
92 round = !isNegative && !empty();
93 break;
94 case common::RoundingMode::TiesAwayFromZero:
95 round = guard_;
96 break;
97 }
98 return round;
99 }
100
101private:
102 bool guard_{false}; // 0.5 * ulp (unit in lowest place)
103 bool round_{false}; // 0.25 * ulp
104 bool sticky_{false}; // true if any lesser-valued bit would be set
105};
106} // namespace Fortran::evaluate::value
107#endif // FORTRAN_EVALUATE_ROUNDING_BITS_H_
108

Warning: This file is not a C or C++ file. It does not have highlighting.

source code of flang/include/flang/Evaluate/rounding-bits.h