Coverage Report

Created: 2025-02-03 06:43

/src/spirv-tools/source/util/parse_number.cpp
Line
Count
Source (jump to first uncovered line)
1
// Copyright (c) 2016 Google Inc.
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//     http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
15
#include "source/util/parse_number.h"
16
17
#include <functional>
18
#include <iomanip>
19
#include <memory>
20
#include <sstream>
21
#include <string>
22
#include <tuple>
23
24
#include "source/util/hex_float.h"
25
#include "source/util/make_unique.h"
26
27
namespace spvtools {
28
namespace utils {
29
namespace {
30
31
// A helper class that temporarily stores error messages and dump the messages
32
// to a string which given as as pointer when it is destructed. If the given
33
// pointer is a nullptr, this class does not store error message.
34
class ErrorMsgStream {
35
 public:
36
  explicit ErrorMsgStream(std::string* error_msg_sink)
37
381k
      : error_msg_sink_(error_msg_sink) {
38
381k
    if (error_msg_sink_) stream_ = MakeUnique<std::ostringstream>();
39
381k
  }
40
381k
  ~ErrorMsgStream() {
41
381k
    if (error_msg_sink_ && stream_) *error_msg_sink_ = stream_->str();
42
381k
  }
43
  template <typename T>
44
769k
  ErrorMsgStream& operator<<(T val) {
45
769k
    if (stream_) *stream_ << val;
46
769k
    return *this;
47
769k
  }
parse_number.cpp:spvtools::utils::(anonymous namespace)::ErrorMsgStream& spvtools::utils::(anonymous namespace)::ErrorMsgStream::operator<< <char const*>(char const*)
Line
Count
Source
44
765k
  ErrorMsgStream& operator<<(T val) {
45
765k
    if (stream_) *stream_ << val;
46
765k
    return *this;
47
765k
  }
parse_number.cpp:spvtools::utils::(anonymous namespace)::ErrorMsgStream& spvtools::utils::(anonymous namespace)::ErrorMsgStream::operator<< <unsigned int>(unsigned int)
Line
Count
Source
44
913
  ErrorMsgStream& operator<<(T val) {
45
913
    if (stream_) *stream_ << val;
46
913
    return *this;
47
913
  }
parse_number.cpp:spvtools::utils::(anonymous namespace)::ErrorMsgStream& spvtools::utils::(anonymous namespace)::ErrorMsgStream::operator<< <std::__1::ios_base& (*)(std::__1::ios_base&)>(std::__1::ios_base& (*)(std::__1::ios_base&))
Line
Count
Source
44
2.46k
  ErrorMsgStream& operator<<(T val) {
45
2.46k
    if (stream_) *stream_ << val;
46
2.46k
    return *this;
47
2.46k
  }
parse_number.cpp:spvtools::utils::(anonymous namespace)::ErrorMsgStream& spvtools::utils::(anonymous namespace)::ErrorMsgStream::operator<< <long>(long)
Line
Count
Source
44
271
  ErrorMsgStream& operator<<(T val) {
45
271
    if (stream_) *stream_ << val;
46
271
    return *this;
47
271
  }
parse_number.cpp:spvtools::utils::(anonymous namespace)::ErrorMsgStream& spvtools::utils::(anonymous namespace)::ErrorMsgStream::operator<< <unsigned long>(unsigned long)
Line
Count
Source
44
549
  ErrorMsgStream& operator<<(T val) {
45
549
    if (stream_) *stream_ << val;
46
549
    return *this;
47
549
  }
parse_number.cpp:spvtools::utils::(anonymous namespace)::ErrorMsgStream& spvtools::utils::(anonymous namespace)::ErrorMsgStream::operator<< <int>(int)
Line
Count
Source
44
8
  ErrorMsgStream& operator<<(T val) {
45
8
    if (stream_) *stream_ << val;
46
8
    return *this;
47
8
  }
48
49
 private:
50
  std::unique_ptr<std::ostringstream> stream_;
51
  // The destination string to which this class dump the error message when
52
  // destructor is called.
53
  std::string* error_msg_sink_;
54
};
55
}  // namespace
56
57
EncodeNumberStatus ParseAndEncodeIntegerNumber(
58
    const char* text, const NumberType& type,
59
12.2M
    std::function<void(uint32_t)> emit, std::string* error_msg) {
60
12.2M
  if (!text) {
61
0
    ErrorMsgStream(error_msg) << "The given text is a nullptr";
62
0
    return EncodeNumberStatus::kInvalidText;
63
0
  }
64
65
12.2M
  if (!IsIntegral(type)) {
66
0
    ErrorMsgStream(error_msg) << "The expected type is not a integer type";
67
0
    return EncodeNumberStatus::kInvalidUsage;
68
0
  }
69
70
12.2M
  const uint32_t bit_width = AssumedBitWidth(type);
71
72
12.2M
  if (bit_width > 64) {
73
93
    ErrorMsgStream(error_msg)
74
93
        << "Unsupported " << bit_width << "-bit integer literals";
75
93
    return EncodeNumberStatus::kUnsupported;
76
93
  }
77
78
  // Either we are expecting anything or integer.
79
12.2M
  bool is_negative = text[0] == '-';
80
12.2M
  bool can_be_signed = IsSigned(type);
81
82
12.2M
  if (is_negative && !can_be_signed) {
83
3
    ErrorMsgStream(error_msg)
84
3
        << "Cannot put a negative number in an unsigned literal";
85
3
    return EncodeNumberStatus::kInvalidUsage;
86
3
  }
87
88
12.2M
  const bool is_hex = text[0] == '0' && (text[1] == 'x' || text[1] == 'X');
89
90
12.2M
  uint64_t decoded_bits;
91
12.2M
  if (is_negative) {
92
5.80k
    int64_t decoded_signed = 0;
93
94
5.80k
    if (!ParseNumber(text, &decoded_signed)) {
95
212
      ErrorMsgStream(error_msg) << "Invalid signed integer literal: " << text;
96
212
      return EncodeNumberStatus::kInvalidText;
97
212
    }
98
99
5.59k
    if (!CheckRangeAndIfHexThenSignExtend(decoded_signed, type, is_hex,
100
5.59k
                                          &decoded_signed)) {
101
271
      ErrorMsgStream(error_msg)
102
271
          << "Integer " << (is_hex ? std::hex : std::dec) << std::showbase
103
271
          << decoded_signed << " does not fit in a " << std::dec << bit_width
104
271
          << "-bit " << (IsSigned(type) ? "signed" : "unsigned") << " integer";
105
271
      return EncodeNumberStatus::kInvalidText;
106
271
    }
107
5.32k
    decoded_bits = decoded_signed;
108
12.2M
  } else {
109
    // There's no leading minus sign, so parse it as an unsigned integer.
110
12.2M
    if (!ParseNumber(text, &decoded_bits)) {
111
368k
      ErrorMsgStream(error_msg) << "Invalid unsigned integer literal: " << text;
112
368k
      return EncodeNumberStatus::kInvalidText;
113
368k
    }
114
11.9M
    if (!CheckRangeAndIfHexThenSignExtend(decoded_bits, type, is_hex,
115
11.9M
                                          &decoded_bits)) {
116
549
      ErrorMsgStream(error_msg)
117
549
          << "Integer " << (is_hex ? std::hex : std::dec) << std::showbase
118
549
          << decoded_bits << " does not fit in a " << std::dec << bit_width
119
549
          << "-bit " << (IsSigned(type) ? "signed" : "unsigned") << " integer";
120
549
      return EncodeNumberStatus::kInvalidText;
121
549
    }
122
11.9M
  }
123
11.9M
  if (bit_width > 32) {
124
1.89k
    uint32_t low = uint32_t(0x00000000ffffffff & decoded_bits);
125
1.89k
    uint32_t high = uint32_t((0xffffffff00000000 & decoded_bits) >> 32);
126
1.89k
    emit(low);
127
1.89k
    emit(high);
128
11.9M
  } else {
129
11.9M
    emit(uint32_t(decoded_bits));
130
11.9M
  }
131
11.9M
  return EncodeNumberStatus::kSuccess;
132
12.2M
}
133
134
EncodeNumberStatus ParseAndEncodeFloatingPointNumber(
135
    const char* text, const NumberType& type,
136
81.2k
    std::function<void(uint32_t)> emit, std::string* error_msg) {
137
81.2k
  if (!text) {
138
0
    ErrorMsgStream(error_msg) << "The given text is a nullptr";
139
0
    return EncodeNumberStatus::kInvalidText;
140
0
  }
141
142
81.2k
  if (!IsFloating(type)) {
143
0
    ErrorMsgStream(error_msg) << "The expected type is not a float type";
144
0
    return EncodeNumberStatus::kInvalidUsage;
145
0
  }
146
147
81.2k
  const auto bit_width = AssumedBitWidth(type);
148
81.2k
  switch (bit_width) {
149
30.7k
    case 16: {
150
30.7k
      HexFloat<FloatProxy<Float16>> hVal(0);
151
30.7k
      if (!ParseNumber(text, &hVal)) {
152
610
        ErrorMsgStream(error_msg) << "Invalid 16-bit float literal: " << text;
153
610
        return EncodeNumberStatus::kInvalidText;
154
610
      }
155
      // getAsFloat will return the Float16 value, and get_value
156
      // will return a uint16_t representing the bits of the float.
157
      // The encoding is therefore correct from the perspective of the SPIR-V
158
      // spec since the top 16 bits will be 0.
159
30.1k
      emit(static_cast<uint32_t>(hVal.value().getAsFloat().get_value()));
160
30.1k
      return EncodeNumberStatus::kSuccess;
161
30.7k
    } break;
162
30.4k
    case 32: {
163
30.4k
      HexFloat<FloatProxy<float>> fVal(0.0f);
164
30.4k
      if (!ParseNumber(text, &fVal)) {
165
10.1k
        ErrorMsgStream(error_msg) << "Invalid 32-bit float literal: " << text;
166
10.1k
        return EncodeNumberStatus::kInvalidText;
167
10.1k
      }
168
20.3k
      emit(BitwiseCast<uint32_t>(fVal));
169
20.3k
      return EncodeNumberStatus::kSuccess;
170
30.4k
    } break;
171
19.9k
    case 64: {
172
19.9k
      HexFloat<FloatProxy<double>> dVal(0.0);
173
19.9k
      if (!ParseNumber(text, &dVal)) {
174
752
        ErrorMsgStream(error_msg) << "Invalid 64-bit float literal: " << text;
175
752
        return EncodeNumberStatus::kInvalidText;
176
752
      }
177
19.2k
      uint64_t decoded_val = BitwiseCast<uint64_t>(dVal);
178
19.2k
      uint32_t low = uint32_t(0x00000000ffffffff & decoded_val);
179
19.2k
      uint32_t high = uint32_t((0xffffffff00000000 & decoded_val) >> 32);
180
19.2k
      emit(low);
181
19.2k
      emit(high);
182
19.2k
      return EncodeNumberStatus::kSuccess;
183
19.9k
    } break;
184
8
    default:
185
8
      break;
186
81.2k
  }
187
8
  ErrorMsgStream(error_msg)
188
8
      << "Unsupported " << bit_width << "-bit float literals";
189
8
  return EncodeNumberStatus::kUnsupported;
190
81.2k
}
191
192
EncodeNumberStatus ParseAndEncodeNumber(const char* text,
193
                                        const NumberType& type,
194
                                        std::function<void(uint32_t)> emit,
195
12.3M
                                        std::string* error_msg) {
196
12.3M
  if (!text) {
197
0
    ErrorMsgStream(error_msg) << "The given text is a nullptr";
198
0
    return EncodeNumberStatus::kInvalidText;
199
0
  }
200
201
12.3M
  if (IsUnknown(type)) {
202
0
    ErrorMsgStream(error_msg)
203
0
        << "The expected type is not a integer or float type";
204
0
    return EncodeNumberStatus::kInvalidUsage;
205
0
  }
206
207
  // If we explicitly expect a floating-point number, we should handle that
208
  // first.
209
12.3M
  if (IsFloating(type)) {
210
81.2k
    return ParseAndEncodeFloatingPointNumber(text, type, emit, error_msg);
211
81.2k
  }
212
213
12.2M
  return ParseAndEncodeIntegerNumber(text, type, emit, error_msg);
214
12.3M
}
215
216
}  // namespace utils
217
}  // namespace spvtools