parse_number.cpp 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  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. #include "source/util/parse_number.h"
  15. #include <functional>
  16. #include <iomanip>
  17. #include <memory>
  18. #include <sstream>
  19. #include <string>
  20. #include <tuple>
  21. #include "source/util/hex_float.h"
  22. #include "source/util/make_unique.h"
  23. namespace spvtools {
  24. namespace utils {
  25. namespace {
  26. // A helper class that temporarily stores error messages and dump the messages
  27. // to a string which given as as pointer when it is destructed. If the given
  28. // pointer is a nullptr, this class does not store error message.
  29. class ErrorMsgStream {
  30. public:
  31. explicit ErrorMsgStream(std::string* error_msg_sink)
  32. : error_msg_sink_(error_msg_sink) {
  33. if (error_msg_sink_) stream_ = MakeUnique<std::ostringstream>();
  34. }
  35. ~ErrorMsgStream() {
  36. if (error_msg_sink_ && stream_) *error_msg_sink_ = stream_->str();
  37. }
  38. template <typename T>
  39. ErrorMsgStream& operator<<(T val) {
  40. if (stream_) *stream_ << val;
  41. return *this;
  42. }
  43. private:
  44. std::unique_ptr<std::ostringstream> stream_;
  45. // The destination string to which this class dump the error message when
  46. // destructor is called.
  47. std::string* error_msg_sink_;
  48. };
  49. } // namespace
  50. EncodeNumberStatus ParseAndEncodeIntegerNumber(
  51. const char* text, const NumberType& type,
  52. std::function<void(uint32_t)> emit, std::string* error_msg) {
  53. if (!text) {
  54. ErrorMsgStream(error_msg) << "The given text is a nullptr";
  55. return EncodeNumberStatus::kInvalidText;
  56. }
  57. if (!IsIntegral(type)) {
  58. ErrorMsgStream(error_msg) << "The expected type is not a integer type";
  59. return EncodeNumberStatus::kInvalidUsage;
  60. }
  61. const uint32_t bit_width = AssumedBitWidth(type);
  62. if (bit_width > 64) {
  63. ErrorMsgStream(error_msg)
  64. << "Unsupported " << bit_width << "-bit integer literals";
  65. return EncodeNumberStatus::kUnsupported;
  66. }
  67. // Either we are expecting anything or integer.
  68. bool is_negative = text[0] == '-';
  69. bool can_be_signed = IsSigned(type);
  70. if (is_negative && !can_be_signed) {
  71. ErrorMsgStream(error_msg)
  72. << "Cannot put a negative number in an unsigned literal";
  73. return EncodeNumberStatus::kInvalidUsage;
  74. }
  75. const bool is_hex = text[0] == '0' && (text[1] == 'x' || text[1] == 'X');
  76. uint64_t decoded_bits;
  77. if (is_negative) {
  78. int64_t decoded_signed = 0;
  79. if (!ParseNumber(text, &decoded_signed)) {
  80. ErrorMsgStream(error_msg) << "Invalid signed integer literal: " << text;
  81. return EncodeNumberStatus::kInvalidText;
  82. }
  83. if (!CheckRangeAndIfHexThenSignExtend(decoded_signed, type, is_hex,
  84. &decoded_signed)) {
  85. ErrorMsgStream(error_msg)
  86. << "Integer " << (is_hex ? std::hex : std::dec) << std::showbase
  87. << decoded_signed << " does not fit in a " << std::dec << bit_width
  88. << "-bit " << (IsSigned(type) ? "signed" : "unsigned") << " integer";
  89. return EncodeNumberStatus::kInvalidText;
  90. }
  91. decoded_bits = decoded_signed;
  92. } else {
  93. // There's no leading minus sign, so parse it as an unsigned integer.
  94. if (!ParseNumber(text, &decoded_bits)) {
  95. ErrorMsgStream(error_msg) << "Invalid unsigned integer literal: " << text;
  96. return EncodeNumberStatus::kInvalidText;
  97. }
  98. if (!CheckRangeAndIfHexThenSignExtend(decoded_bits, type, is_hex,
  99. &decoded_bits)) {
  100. ErrorMsgStream(error_msg)
  101. << "Integer " << (is_hex ? std::hex : std::dec) << std::showbase
  102. << decoded_bits << " does not fit in a " << std::dec << bit_width
  103. << "-bit " << (IsSigned(type) ? "signed" : "unsigned") << " integer";
  104. return EncodeNumberStatus::kInvalidText;
  105. }
  106. }
  107. if (bit_width > 32) {
  108. uint32_t low = uint32_t(0x00000000ffffffff & decoded_bits);
  109. uint32_t high = uint32_t((0xffffffff00000000 & decoded_bits) >> 32);
  110. emit(low);
  111. emit(high);
  112. } else {
  113. emit(uint32_t(decoded_bits));
  114. }
  115. return EncodeNumberStatus::kSuccess;
  116. }
  117. EncodeNumberStatus ParseAndEncodeFloatingPointNumber(
  118. const char* text, const NumberType& type,
  119. std::function<void(uint32_t)> emit, std::string* error_msg) {
  120. if (!text) {
  121. ErrorMsgStream(error_msg) << "The given text is a nullptr";
  122. return EncodeNumberStatus::kInvalidText;
  123. }
  124. if (!IsFloating(type)) {
  125. ErrorMsgStream(error_msg) << "The expected type is not a float type";
  126. return EncodeNumberStatus::kInvalidUsage;
  127. }
  128. const auto bit_width = AssumedBitWidth(type);
  129. switch (bit_width) {
  130. case 16: {
  131. HexFloat<FloatProxy<Float16>> hVal(0);
  132. if (!ParseNumber(text, &hVal)) {
  133. ErrorMsgStream(error_msg) << "Invalid 16-bit float literal: " << text;
  134. return EncodeNumberStatus::kInvalidText;
  135. }
  136. // getAsFloat will return the Float16 value, and get_value
  137. // will return a uint16_t representing the bits of the float.
  138. // The encoding is therefore correct from the perspective of the SPIR-V
  139. // spec since the top 16 bits will be 0.
  140. emit(static_cast<uint32_t>(hVal.value().getAsFloat().get_value()));
  141. return EncodeNumberStatus::kSuccess;
  142. } break;
  143. case 32: {
  144. HexFloat<FloatProxy<float>> fVal(0.0f);
  145. if (!ParseNumber(text, &fVal)) {
  146. ErrorMsgStream(error_msg) << "Invalid 32-bit float literal: " << text;
  147. return EncodeNumberStatus::kInvalidText;
  148. }
  149. emit(BitwiseCast<uint32_t>(fVal));
  150. return EncodeNumberStatus::kSuccess;
  151. } break;
  152. case 64: {
  153. HexFloat<FloatProxy<double>> dVal(0.0);
  154. if (!ParseNumber(text, &dVal)) {
  155. ErrorMsgStream(error_msg) << "Invalid 64-bit float literal: " << text;
  156. return EncodeNumberStatus::kInvalidText;
  157. }
  158. uint64_t decoded_val = BitwiseCast<uint64_t>(dVal);
  159. uint32_t low = uint32_t(0x00000000ffffffff & decoded_val);
  160. uint32_t high = uint32_t((0xffffffff00000000 & decoded_val) >> 32);
  161. emit(low);
  162. emit(high);
  163. return EncodeNumberStatus::kSuccess;
  164. } break;
  165. default:
  166. break;
  167. }
  168. ErrorMsgStream(error_msg)
  169. << "Unsupported " << bit_width << "-bit float literals";
  170. return EncodeNumberStatus::kUnsupported;
  171. }
  172. EncodeNumberStatus ParseAndEncodeNumber(const char* text,
  173. const NumberType& type,
  174. std::function<void(uint32_t)> emit,
  175. std::string* error_msg) {
  176. if (!text) {
  177. ErrorMsgStream(error_msg) << "The given text is a nullptr";
  178. return EncodeNumberStatus::kInvalidText;
  179. }
  180. if (IsUnknown(type)) {
  181. ErrorMsgStream(error_msg)
  182. << "The expected type is not a integer or float type";
  183. return EncodeNumberStatus::kInvalidUsage;
  184. }
  185. // If we explicitly expect a floating-point number, we should handle that
  186. // first.
  187. if (IsFloating(type)) {
  188. return ParseAndEncodeFloatingPointNumber(text, type, emit, error_msg);
  189. }
  190. return ParseAndEncodeIntegerNumber(text, type, emit, error_msg);
  191. }
  192. } // namespace utils
  193. } // namespace spvtools