Implement to_string(uint32_t) without using the locale (#5805)

Using the locale takes a mutex deep in the C++ library.
Avoid this on hot compilation paths, e.g. in the validator.

Fixed: #5802
This commit is contained in:
David Neto 2024-09-12 14:30:18 -07:00 committed by GitHub
parent 7c9210cc1d
commit 4451f6ab13
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 113 additions and 13 deletions

View File

@ -27,6 +27,7 @@ SPVTOOLS_SRC_FILES := \
source/table.cpp \
source/text.cpp \
source/text_handler.cpp \
source/to_string.cpp \
source/util/bit_vector.cpp \
source/util/parse_number.cpp \
source/util/string_utils.cpp \

View File

@ -475,6 +475,8 @@ static_library("spvtools") {
"source/text.h",
"source/text_handler.cpp",
"source/text_handler.h",
"source/to_string.cpp",
"source/to_string.h",
"source/util/bit_vector.cpp",
"source/util/bit_vector.h",
"source/util/bitutils.h",
@ -1416,6 +1418,7 @@ if (build_with_chromium && spvtools_build_executables) {
"test/text_to_binary.type_declaration_test.cpp",
"test/text_to_binary_test.cpp",
"test/text_word_get_test.cpp",
"test/to_string_test.cpp",
"test/unit_spirv.cpp",
"test/unit_spirv.h",
]

View File

@ -266,6 +266,7 @@ set(SPIRV_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/table.h
${CMAKE_CURRENT_SOURCE_DIR}/text.h
${CMAKE_CURRENT_SOURCE_DIR}/text_handler.h
${CMAKE_CURRENT_SOURCE_DIR}/to_string.h
${CMAKE_CURRENT_SOURCE_DIR}/val/validate.h
${CMAKE_CURRENT_SOURCE_DIR}/util/bit_vector.cpp
@ -294,6 +295,7 @@ set(SPIRV_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/table.cpp
${CMAKE_CURRENT_SOURCE_DIR}/text.cpp
${CMAKE_CURRENT_SOURCE_DIR}/text_handler.cpp
${CMAKE_CURRENT_SOURCE_DIR}/to_string.cpp
${CMAKE_CURRENT_SOURCE_DIR}/val/validate.cpp
${CMAKE_CURRENT_SOURCE_DIR}/val/validate_adjacency.cpp
${CMAKE_CURRENT_SOURCE_DIR}/val/validate_annotation.cpp

View File

@ -25,24 +25,15 @@
#include "source/binary.h"
#include "source/latest_version_spirv_header.h"
#include "source/parsed_operand.h"
#include "source/to_string.h"
#include "spirv-tools/libspirv.h"
namespace spvtools {
namespace {
// Converts a uint32_t to its string decimal representation.
std::string to_string(uint32_t id) {
// Use stringstream, since some versions of Android compilers lack
// std::to_string.
std::stringstream os;
os << id;
return os.str();
NameMapper GetTrivialNameMapper() {
return [](uint32_t i) { return spvtools::to_string(i); };
}
} // anonymous namespace
NameMapper GetTrivialNameMapper() { return to_string; }
FriendlyNameMapper::FriendlyNameMapper(const spv_const_context context,
const uint32_t* code,
const size_t wordCount)

View File

@ -17,6 +17,7 @@
#include "inst_debug_printf_pass.h"
#include "source/spirv_constant.h"
#include "source/to_string.h"
#include "source/util/string_utils.h"
#include "spirv/unified1/NonSemanticDebugPrintf.h"
@ -396,7 +397,7 @@ uint32_t InstDebugPrintfPass::GetStreamWriteFunctionId(uint32_t param_cnt) {
context()->AddFunction(std::move(output_func));
std::string name("stream_write_");
name += std::to_string(param_cnt);
name += spvtools::to_string(param_cnt);
context()->AddDebug2Inst(
NewGlobalName(param2output_func_id_[param_cnt], name));

44
source/to_string.cpp Normal file
View File

@ -0,0 +1,44 @@
// Copyright (c) 2024 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "source/to_string.h"
#include <cassert>
namespace spvtools {
std::string to_string(uint32_t n) {
// This implementation avoids using standard library features that access
// the locale. Using the locale requires taking a mutex which causes
// annoying serialization.
constexpr int max_digits = 10; // max uint has 10 digits
// Contains the resulting digits, with least significant digit in the last
// entry.
char buf[max_digits];
int write_index = max_digits - 1;
if (n == 0) {
buf[write_index] = '0';
} else {
while (n > 0) {
int units = n % 10;
buf[write_index--] = "0123456789"[units];
n = (n - units) / 10;
}
write_index++;
}
assert(write_index >= 0);
return std::string(buf + write_index, max_digits - write_index);
}
} // namespace spvtools

29
source/to_string.h Normal file
View File

@ -0,0 +1,29 @@
// Copyright (c) 2024 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef SOURCE_TO_STRING_H_
#define SOURCE_TO_STRING_H_
#include <cstdint>
#include <string>
namespace spvtools {
// Returns the decimal representation of a number as a string,
// without using the locale.
std::string to_string(uint32_t n);
} // namespace spvtools
#endif // SOURCE_TO_STRING_H_

View File

@ -151,6 +151,7 @@ set(TEST_SOURCES
text_to_binary.subgroup_dispatch_test.cpp
text_to_binary.reserved_sampling_test.cpp
text_word_get_test.cpp
to_string_test.cpp
unit_spirv.cpp
)

28
test/to_string_test.cpp Normal file
View File

@ -0,0 +1,28 @@
// Copyright (c) 2024 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "source/to_string.h"
#include "gmock/gmock.h"
namespace {
TEST(ToString, Uint32) {
EXPECT_EQ(spvtools::to_string(0u), "0");
EXPECT_EQ(spvtools::to_string(1u), "1");
EXPECT_EQ(spvtools::to_string(1234567890u), "1234567890");
EXPECT_EQ(spvtools::to_string(0xffffffffu), "4294967295");
}
} // namespace