2323#include " kernel/yosys_common.h"
2424#include " kernel/yosys.h"
2525
26- #include < charconv>
2726#include < string_view>
2827#include < unordered_map>
2928
@@ -151,8 +150,16 @@ struct RTLIL::IdString
151150 ~destruct_guard_t () { destruct_guard_ok = false ; }
152151 } destruct_guard;
153152
153+ // String storage for nonnegative IDs
154154 static std::vector<char *> global_id_storage_;
155+ // Lookup table for nonnegative IDs
155156 static std::unordered_map<std::string_view, int > global_id_index_;
157+ // Shared prefix string storage for negative IDs. Append the negated (i.e. positive) ID
158+ // to this string to get the real string.
159+ // The prefix strings must live forever.
160+ static std::unordered_map<int , const std::string*> global_negative_id_prefix_storage_;
161+ // Explicit string storage for negative IDs
162+ static std::unordered_map<int , char *> global_negative_id_storage_;
156163#ifndef YOSYS_NO_IDS_REFCNT
157164 // All (index, refcount) pairs in this map have refcount > 0.
158165 static std::unordered_map<int , int > global_refcount_storage_;
@@ -198,58 +205,15 @@ struct RTLIL::IdString
198205 #endif
199206 return it->second ;
200207 }
208+ return really_insert (p, it);
209+ }
201210
202- ensure_prepopulated ();
203-
204- if (p.empty ())
205- return 0 ;
206-
207- log_assert (p[0 ] == ' $' || p[0 ] == ' \\ ' );
208- for (char ch : p)
209- if ((unsigned )ch <= (unsigned )' ' )
210- log_error (" Found control character or space (0x%02x) in string '%s' which is not allowed in RTLIL identifiers\n " , ch, std::string (p).c_str ());
211-
212- if (p.substr (0 , 6 ) == " $auto$" ) {
213- // Ensure new_id(_suffix) will not create collisions.
214- size_t autoidx_pos = p.find_last_of (' $' );
215- int p_autoidx;
216- std::string_view v = p.substr (autoidx_pos + 1 );
217- if (std::from_chars (v.begin (), v.end (), p_autoidx).ec == std::errc ()) {
218- autoidx = std::max (autoidx, p_autoidx + 1 );
219- }
220- }
221-
222- #ifndef YOSYS_NO_IDS_REFCNT
223- if (global_free_idx_list_.empty ()) {
224- log_assert (global_id_storage_.size () < 0x40000000 );
225- global_free_idx_list_.push_back (global_id_storage_.size ());
226- global_id_storage_.push_back (nullptr );
227- }
228-
229- int idx = global_free_idx_list_.back ();
230- global_free_idx_list_.pop_back ();
231- char * buf = static_cast <char *>(malloc (p.size () + 1 ));
232- memcpy (buf, p.data (), p.size ());
233- buf[p.size ()] = 0 ;
234- global_id_storage_.at (idx) = buf;
235- global_id_index_.insert (it, {std::string_view (buf, p.size ()), idx});
236- #else
237- int idx = global_id_storage_.size ();
238- global_id_storage_.push_back (strdup (p));
239- global_id_index_[global_id_storage_.back ()] = idx;
240- #endif
241-
242- if (yosys_xtrace) {
243- log (" #X# New IdString '%s' with index %d.\n " , global_id_storage_.at (idx), idx);
244- log_backtrace (" -X- " , yosys_xtrace-1 );
245- }
246-
247- #ifdef YOSYS_XTRACE_GET_PUT
248- if (yosys_xtrace)
249- log (" #X# GET-BY-NAME '%s' (index %d, refcount %u)\n " , global_id_storage_.at (idx), idx, refcount (idx));
250- #endif
251-
252- return idx;
211+ // Inserts an ID with string `prefix + autoidx', incrementing autoidx.
212+ // `prefix` must start with '$auto$', end with '$', and live forever.
213+ static IdString new_autoidx_with_prefix (const std::string *prefix) {
214+ int index = -(autoidx++);
215+ global_negative_id_prefix_storage_.insert ({index, prefix});
216+ return from_index (index);
253217 }
254218
255219 // the actual IdString object is just is a single int
@@ -279,11 +243,31 @@ struct RTLIL::IdString
279243 constexpr inline const IdString &id_string () const { return *this ; }
280244
281245 inline const char *c_str () const {
282- return global_id_storage_.at (index_);
246+ if (index_ >= 0 )
247+ return global_id_storage_.at (index_);
248+ auto it = global_negative_id_storage_.find (index_);
249+ if (it != global_negative_id_storage_.end ())
250+ return it->second ;
251+ std::string str = stringf (" %s%d" , *global_negative_id_prefix_storage_.at (index_), -index_);
252+ char *c = static_cast <char *>(malloc (str.size () + 1 ));
253+ memcpy (c, str.c_str (), str.size () + 1 );
254+ global_negative_id_storage_.insert (it, {index_, c});
255+ return c;
283256 }
284257
285258 inline std::string str () const {
286- return std::string (global_id_storage_.at (index_));
259+ std::string result;
260+ append_to (&result);
261+ return result;
262+ }
263+
264+ inline void append_to (std::string *out) const {
265+ if (index_ >= 0 ) {
266+ *out += global_id_storage_.at (index_);
267+ return ;
268+ }
269+ *out += *global_negative_id_prefix_storage_.at (index_);
270+ *out += std::to_string (-index_);
287271 }
288272
289273 inline bool operator <(const IdString &rhs) const {
@@ -389,6 +373,14 @@ struct RTLIL::IdString
389373
390374private:
391375 static void prepopulate ();
376+ static int really_insert (std::string_view p, std::unordered_map<std::string_view, int >::iterator &it);
377+
378+ protected:
379+ static IdString from_index (int index) {
380+ IdString result;
381+ result.index_ = index;
382+ return result;
383+ }
392384
393385public:
394386 static void ensure_prepopulated () {
@@ -458,7 +450,7 @@ struct RTLIL::OwningIdString : public RTLIL::IdString {
458450 #endif
459451 #ifdef YOSYS_XTRACE_GET_PUT
460452 if (yosys_xtrace && idx >= static_cast <short >(StaticId::STATIC_ID_END))
461- log (" #X# GET-BY-INDEX '%s' (index %d, refcount %u)\n " , global_id_storage_. at (idx), idx, refcount (idx));
453+ log (" #X# GET-BY-INDEX '%s' (index %d, refcount %u)\n " , from_index (idx), idx, refcount (idx));
462454 #endif
463455 }
464456
@@ -471,7 +463,7 @@ struct RTLIL::OwningIdString : public RTLIL::IdString {
471463 return ;
472464 #ifdef YOSYS_XTRACE_GET_PUT
473465 if (yosys_xtrace)
474- log (" #X# PUT '%s' (index %d, refcount %u)\n " , global_id_storage_. at (index_), index_, refcount (index_));
466+ log (" #X# PUT '%s' (index %d, refcount %u)\n " , from_index (index_), index_, refcount (index_));
475467 #endif
476468 auto it = global_refcount_storage_.find (index_);
477469 log_assert (it != global_refcount_storage_.end () && it->second >= 1 );
0 commit comments