3
0
Fork 0
mirror of https://github.com/YosysHQ/yosys synced 2025-11-03 13:07:58 +00:00

Optimize IdString operations to avoid calling c_str()

This commit is contained in:
Robert O'Callahan 2025-10-13 20:51:35 +00:00
parent 2075b3416f
commit a534fda855
2 changed files with 200 additions and 21 deletions

View file

@ -130,6 +130,8 @@ struct RTLIL::IdString
struct Storage {
char *buf;
int size;
std::string_view str_view() const { return {buf, static_cast<size_t>(size)}; }
};
#undef YOSYS_XTRACE_GET_PUT
@ -260,14 +262,135 @@ struct RTLIL::IdString
inline void append_to(std::string *out) const {
if (index_ >= 0) {
const Storage &storage = global_id_storage_.at(index_);
*out += std::string_view(storage.buf, storage.size);
*out += global_id_storage_.at(index_).str_view();
return;
}
*out += *global_autoidx_id_prefix_storage_.at(index_);
*out += std::to_string(-index_);
}
class Substrings {
std::string_view first_;
int suffix_number;
char buf[10];
public:
Substrings(const Storage &storage) : first_(storage.str_view()), suffix_number(-1) {}
// suffix_number must be non-negative
Substrings(const std::string *prefix, int suffix_number)
: first_(*prefix), suffix_number(suffix_number) {}
std::string_view first() { return first_; }
std::optional<std::string_view> next() {
if (suffix_number < 0)
return std::nullopt;
int i = sizeof(buf);
do {
--i;
buf[i] = (suffix_number % 10) + '0';
suffix_number /= 10;
} while (suffix_number > 0);
suffix_number = -1;
return std::string_view(buf + i, sizeof(buf) - i);
}
};
class const_iterator {
const std::string *prefix;
std::string suffix;
const char *c_str;
int c_str_len;
// When this is INT_MAX it's the generic "end" value.
int index;
public:
using iterator_category = std::forward_iterator_tag;
using value_type = char;
using difference_type = std::ptrdiff_t;
using pointer = const char*;
using reference = const char&;
const_iterator(const Storage &storage) : prefix(nullptr), c_str(storage.buf), c_str_len(storage.size), index(0) {}
const_iterator(const std::string *prefix, int number) :
prefix(prefix), suffix(std::to_string(number)), c_str(nullptr), c_str_len(0), index(0) {}
// Construct end-marker
const_iterator() : prefix(nullptr), c_str(nullptr), c_str_len(0), index(INT_MAX) {}
int size() const {
if (c_str != nullptr)
return c_str_len;
return GetSize(*prefix) + GetSize(suffix);
}
char operator*() const {
if (c_str != nullptr)
return c_str[index];
int prefix_size = GetSize(*prefix);
if (index < prefix_size)
return prefix->at(index);
return suffix[index - prefix_size];
}
const_iterator& operator++() { ++index; return *this; }
const_iterator operator++(int) { const_iterator result(*this); ++index; return result; }
const_iterator& operator+=(int i) { index += i; return *this; }
const_iterator operator+(int add) {
const_iterator result = *this;
result += add;
return result;
}
bool operator==(const const_iterator& other) const {
return index == other.index || (other.index == INT_MAX && index == size())
|| (index == INT_MAX && other.index == other.size());
}
bool operator!=(const const_iterator& other) const {
return !(*this == other);
}
};
const_iterator begin() const {
if (index_ >= 0) {
return const_iterator(global_id_storage_.at(index_));
}
return const_iterator(global_autoidx_id_prefix_storage_.at(index_), -index_);
}
const_iterator end() const {
return const_iterator();
}
Substrings substrings() const {
if (index_ >= 0) {
return Substrings(global_id_storage_.at(index_));
}
return Substrings(global_autoidx_id_prefix_storage_.at(index_), -index_);
}
inline bool lt_by_name(const IdString &rhs) const {
Substrings lhs_it = substrings();
Substrings rhs_it = rhs.substrings();
std::string_view lhs_substr = lhs_it.first();
std::string_view rhs_substr = rhs_it.first();
while (true) {
int min = std::min(GetSize(lhs_substr), GetSize(rhs_substr));
int diff = memcmp(lhs_substr.data(), rhs_substr.data(), min);
if (diff != 0)
return diff < 0;
lhs_substr = lhs_substr.substr(min);
rhs_substr = rhs_substr.substr(min);
if (rhs_substr.empty()) {
if (std::optional<std::string_view> s = rhs_it.next())
rhs_substr = *s;
else
return false;
}
if (lhs_substr.empty()) {
if (std::optional<std::string_view> s = lhs_it.next())
lhs_substr = *s;
else
return true;
}
}
}
inline bool operator<(const IdString &rhs) const {
return index_ < rhs.index_;
}
@ -284,30 +407,68 @@ struct RTLIL::IdString
bool operator!=(const char *rhs) const { return strcmp(c_str(), rhs) != 0; }
char operator[](size_t i) const {
const char *p = c_str();
if (index_ >= 0) {
const Storage &storage = global_id_storage_.at(index_);
#ifndef NDEBUG
for (; i != 0; i--, p++)
log_assert(*p != 0);
return *p;
#else
return *(p + i);
log_assert(static_cast<int>(i) < storage.size);
#endif
return *(storage.buf + i);
}
const std::string &id_start = *global_autoidx_id_prefix_storage_.at(index_);
if (i < id_start.size())
return id_start[i];
i -= id_start.size();
std::string suffix = std::to_string(-index_);
#ifndef NDEBUG
// Allow indexing to access the trailing null.
log_assert(i <= suffix.size());
#endif
return suffix[i];
}
std::string substr(size_t pos = 0, size_t len = std::string::npos) const {
if (len == std::string::npos || len + pos >= size())
return std::string(c_str() + pos);
else
return std::string(c_str() + pos, len);
std::string result;
const_iterator it = begin() + pos;
const_iterator end_it = end();
if (len != std::string::npos && len < it.size() - pos) {
end_it = it + len;
}
std::copy(it, end_it, std::back_inserter(result));
return result;
}
int compare(size_t pos, size_t len, const char* s) const {
return strncmp(c_str()+pos, s, len);
const_iterator it = begin() + pos;
const_iterator end_it = end();
while (len > 0 && *s != 0 && it != end_it) {
int diff = *it - *s;
if (diff != 0)
return diff;
++it;
++s;
--len;
}
return 0;
}
bool begins_with(std::string_view prefix) const {
if (size() < prefix.size()) return false;
return compare(0, prefix.size(), prefix.data()) == 0;
Substrings it = substrings();
std::string_view substr = it.first();
while (true) {
int min = std::min(GetSize(substr), GetSize(prefix));
if (memcmp(substr.data(), prefix.data(), min) != 0)
return false;
prefix = prefix.substr(min);
if (prefix.empty())
return true;
substr = substr.substr(min);
if (substr.empty()) {
if (std::optional<std::string_view> s = it.next())
substr = *s;
else
return false;
}
}
}
bool ends_with(std::string_view suffix) const {
@ -317,13 +478,13 @@ struct RTLIL::IdString
}
bool contains(std::string_view s) const {
return std::string_view(c_str()).find(s) != std::string::npos;
if (index_ >= 0)
return global_id_storage_.at(index_).str_view().find(s) != std::string::npos;
return str().find(s) != std::string::npos;
}
size_t size() const {
if (index_ >= 0)
return global_id_storage_.at(index_).size;
return strlen(c_str());
return begin().size();
}
bool empty() const {
@ -601,13 +762,13 @@ namespace RTLIL {
template <typename T> struct sort_by_name_str {
bool operator()(T *a, T *b) const {
return strcmp(a->name.c_str(), b->name.c_str()) < 0;
return a->name.lt_by_name(b->name);
}
};
struct sort_by_id_str {
bool operator()(const RTLIL::IdString &a, const RTLIL::IdString &b) const {
return strcmp(a.c_str(), b.c_str()) < 0;
return a.lt_by_name(b);
}
};

View file

@ -373,6 +373,24 @@ namespace RTLIL {
EXPECT_EQ(id, id2);
}
TEST_F(KernelRtlilTest, NewIdBeginsWith) {
IdString id = NEW_ID;
EXPECT_TRUE(id.begins_with("$auto"));
EXPECT_FALSE(id.begins_with("xyz"));
EXPECT_TRUE(id.begins_with("$auto$"));
EXPECT_FALSE(id.begins_with("abcdefghijklmn"));
EXPECT_TRUE(id.begins_with("$auto$rtlilTest"));
EXPECT_FALSE(id.begins_with("$auto$rtlilX"));
}
TEST_F(KernelRtlilTest, NewIdIndexing) {
IdString id = NEW_ID;
std::string str = id.str();
for (int i = 0; i < GetSize(str) + 1; ++i) {
EXPECT_EQ(id[i], str.c_str()[i]);
}
}
class WireRtlVsHdlIndexConversionTest :
public KernelRtlilTest,
public testing::WithParamInterface<std::tuple<bool, int, int>>