diff --git a/kernel/constids.inc b/kernel/constids.inc index 29872d45e..1419c89fa 100644 --- a/kernel/constids.inc +++ b/kernel/constids.inc @@ -1,27 +1,27 @@ +// These must be in perfect ASCII order!!! +X($_AND_) +X($_OR_) +X($_XOR_) +X($add) +X($and) +X($logic_and) +X($logic_or) +X($mul) +X($or) +X($pmux) +X($reduce_and) +X($reduce_bool) +X($reduce_or) +X($reduce_xnor) +X($reduce_xor) +X($xor) X(A) -X(abc9_box) -X(abc9_box_id) -X(abc9_box_seq) -X(abc9_bypass) -X(abc9_carry) -X(abc9_flop) -X(abc9_keep) -X(abc9_lut) -X(abc9_mergeability) -X(abc9_scc_id) -X(abcgroup) X(ABITS) X(AD) +X(ADDEND_NEGATED) X(ADDR) -X(allconst) -X(allseq) X(ALOAD) X(ALOAD_POLARITY) -X(always_comb) -X(always_ff) -X(always_latch) -X(anyconst) -X(anyseq) X(ARGS) X(ARGS_WIDTH) X(ARST) @@ -29,27 +29,21 @@ X(ARST_POLARITY) X(ARST_VALUE) X(A_SIGNED) X(A_WIDTH) +X(A_WIDTHS) X(B) X(BI) X(BITS_USED) -X(blackbox) -X(B_SIGNED) -X(bugpoint_keep) -X(B_WIDTH) X(BYTE) +X(B_SIGNED) +X(B_WIDTH) +X(B_WIDTHS) X(C) -X(cells_not_processed) X(CE_OVER_SRST) X(CFG_ABITS) X(CFG_DBITS) X(CFG_INIT) -X(chain) X(CI) X(CLK) -X(clkbuf_driver) -X(clkbuf_inhibit) -X(clkbuf_inv) -X(clkbuf_sink) X(CLK_ENABLE) X(CLK_POLARITY) X(CLR) @@ -62,12 +56,13 @@ X(CTRL_IN) X(CTRL_IN_WIDTH) X(CTRL_OUT) X(CTRL_OUT_WIDTH) +X(C_SIGNED) +X(C_WIDTHS) X(D) X(DAT) X(DATA) X(DAT_DST_PEN) X(DAT_DST_POL) -X(defaultvalue) X(DELAY) X(DEPTH) X(DST) @@ -75,7 +70,6 @@ X(DST_EN) X(DST_PEN) X(DST_POL) X(DST_WIDTH) -X(dynports) X(E) X(EDGE_EN) X(EDGE_POL) @@ -83,82 +77,34 @@ X(EN) X(EN_DST) X(EN_POLARITY) X(EN_SRC) -X(enum_base_type) -X(enum_type) -X(equiv_merged) -X(equiv_region) -X(extract_order) X(F) X(FLAVOR) X(FORMAT) -X(force_downto) -X(force_upto) -X(fsm_encoding) -X(fsm_export) X(FULL) -X(full_case) X(G) -X(gclk) -X(gentb_clock) -X(gentb_constant) -X(gentb_skip) X(H) -X(hdlname) -X(hierconn) X(I) X(INIT) X(INIT_VALUE) -X(init) -X(initial_top) -X(interface_modport) -X(interfaces_replaced_in_module) -X(interface_type) -X(invertible_pin) -X(iopad_external_pin) -X(is_interface) X(J) X(K) -X(keep) -X(keep_hierarchy) X(L) -X(lib_whitebox) -X(localparam) -X(logic_block) -X(lram) X(LUT) -X(lut_keep) X(M) -X(maximize) -X(mem2reg) X(MEMID) -X(minimize) -X(module_not_derived) X(N) +X(NADDENDS) X(NAME) -X(noblackbox) -X(nolatches) -X(nomem2init) -X(nomem2reg) -X(nomeminit) -X(nosync) -X(nowrshmsk) -X(no_ram) -X(no_rw_check) +X(NPRODUCTS) X(O) X(OFFSET) -X(onehot) X(P) -X(parallel_case) -X(parameter) X(PORTID) X(PRIORITY) X(PRIORITY_MASK) -X(promoted_if) +X(PRODUCT_NEGATED) X(Q) X(R) -X(ram_block) -X(ram_style) -X(ramstyle) X(RD_ADDR) X(RD_ARST) X(RD_ARST_VALUE) @@ -176,19 +122,11 @@ X(RD_SRST_VALUE) X(RD_TRANSPARENCY_MASK) X(RD_TRANSPARENT) X(RD_WIDE_CONTINUATION) -X(reg) -X(replaced_by_gclk) -X(reprocess_after) -X(rom_block) -X(rom_style) -X(romstyle) X(S) X(SET) X(SET_POLARITY) -X(single_bit_vector) X(SIZE) X(SRC) -X(src) X(SRC_DST_PEN) X(SRC_DST_POL) X(SRC_EN) @@ -198,34 +136,24 @@ X(SRC_WIDTH) X(SRST) X(SRST_POLARITY) X(SRST_VALUE) -X(sta_arrival) X(STATE_BITS) X(STATE_NUM) X(STATE_NUM_LOG2) X(STATE_RST) X(STATE_TABLE) -X(smtlib2_module) -X(smtlib2_comb_expr) -X(submod) -X(syn_ramstyle) -X(syn_romstyle) X(S_WIDTH) X(T) X(TABLE) X(TAG) -X(techmap_autopurge) -X(_TECHMAP_BITS_CONNMAP_) -X(_TECHMAP_CELLNAME_) -X(_TECHMAP_CELLTYPE_) -X(techmap_celltype) -X(_TECHMAP_FAIL_) -X(techmap_maccmap) -X(_TECHMAP_REPLACE_) -X(techmap_simplemap) -X(_techmap_special_) -X(techmap_wrap) -X(_TECHMAP_PLACEHOLDER_) -X(techmap_chtype) +X(TRANSPARENCY_MASK) +X(TRANSPARENT) +X(TRANS_NUM) +X(TRANS_TABLE) +X(TRG) +X(TRG_ENABLE) +X(TRG_POLARITY) +X(TRG_WIDTH) +X(TYPE) X(T_FALL_MAX) X(T_FALL_MIN) X(T_FALL_TYP) @@ -237,31 +165,12 @@ X(T_LIMIT2_TYP) X(T_LIMIT_MAX) X(T_LIMIT_MIN) X(T_LIMIT_TYP) -X(to_delete) -X(top) -X(TRANS_NUM) -X(TRANSPARENCY_MASK) -X(TRANSPARENT) -X(TRANS_TABLE) -X(TRG) -X(TRG_ENABLE) -X(TRG_POLARITY) -X(TRG_WIDTH) X(T_RISE_MAX) X(T_RISE_MIN) X(T_RISE_TYP) -X(TYPE) X(U) -X(unique) -X(unused_bits) X(V) -X(via_celltype) -X(wand) -X(whitebox) X(WIDTH) -X(wildcard_port_conns) -X(wiretype) -X(wor) X(WORDS) X(WR_ADDR) X(WR_CLK) @@ -273,17 +182,125 @@ X(WR_PORTS) X(WR_PRIORITY_MASK) X(WR_WIDE_CONTINUATION) X(X) -X(xprop_decoder) X(Y) X(Y_WIDTH) +X(_TECHMAP_BITS_CONNMAP_) +X(_TECHMAP_CELLNAME_) +X(_TECHMAP_CELLTYPE_) +X(_TECHMAP_FAIL_) +X(_TECHMAP_PLACEHOLDER_) +X(_TECHMAP_REPLACE_) +X(_techmap_special_) +X(abc9_box) +X(abc9_box_id) +X(abc9_box_seq) +X(abc9_bypass) +X(abc9_carry) +X(abc9_flop) +X(abc9_keep) +X(abc9_lut) +X(abc9_mergeability) +X(abc9_scc_id) +X(abcgroup) +X(allconst) +X(allseq) +X(always_comb) +X(always_ff) +X(always_latch) +X(anyconst) +X(anyseq) X(area) +X(blackbox) +X(bugpoint_keep) X(capacitance) -X(NPRODUCTS) -X(NADDENDS) -X(PRODUCT_NEGATED) -X(ADDEND_NEGATED) -X(A_WIDTHS) -X(B_WIDTHS) -X(C_WIDTHS) -X(C_SIGNED) +X(cells_not_processed) +X(chain) +X(clkbuf_driver) +X(clkbuf_inhibit) +X(clkbuf_inv) +X(clkbuf_sink) +X(defaultvalue) +X(dynports) +X(enum_base_type) +X(enum_type) +X(equiv_merged) +X(equiv_region) +X(extract_order) +X(force_downto) +X(force_upto) +X(fsm_encoding) +X(fsm_export) +X(full_case) +X(gclk) +X(gentb_clock) +X(gentb_constant) +X(gentb_skip) +X(hdlname) +X(hierconn) +X(init) +X(initial_top) +X(interface_modport) +X(interface_type) +X(interfaces_replaced_in_module) +X(invertible_pin) +X(iopad_external_pin) +X(is_interface) +X(keep) +X(keep_hierarchy) +X(lib_whitebox) +X(localparam) +X(logic_block) +X(lram) +X(lut_keep) +X(maximize) +X(mem2reg) +X(minimize) +X(module_not_derived) +X(no_ram) +X(no_rw_check) +X(noblackbox) +X(nolatches) +X(nomem2init) +X(nomem2reg) +X(nomeminit) +X(nosync) +X(nowrshmsk) +X(onehot) +X(parallel_case) +X(parameter) +X(promoted_if) X(raise_error) +X(ram_block) +X(ram_style) +X(ramstyle) +X(reg) +X(replaced_by_gclk) +X(reprocess_after) +X(rom_block) +X(rom_style) +X(romstyle) +X(single_bit_vector) +X(smtlib2_comb_expr) +X(smtlib2_module) +X(src) +X(sta_arrival) +X(submod) +X(syn_ramstyle) +X(syn_romstyle) +X(techmap_autopurge) +X(techmap_celltype) +X(techmap_chtype) +X(techmap_maccmap) +X(techmap_simplemap) +X(techmap_wrap) +X(to_delete) +X(top) +X(unique) +X(unused_bits) +X(via_celltype) +X(wand) +X(whitebox) +X(wildcard_port_conns) +X(wiretype) +X(wor) +X(xprop_decoder) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 0250346d1..6d72704f4 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -29,6 +29,7 @@ #include #include #include +#include YOSYS_NAMESPACE_BEGIN @@ -37,7 +38,7 @@ RTLIL::IdString::destruct_guard_t RTLIL::IdString::destruct_guard; std::vector RTLIL::IdString::global_id_storage_; std::unordered_map RTLIL::IdString::global_id_index_; #ifndef YOSYS_NO_IDS_REFCNT -std::vector RTLIL::IdString::global_refcount_storage_; +std::vector RTLIL::IdString::global_refcount_storage_; std::vector RTLIL::IdString::global_free_idx_list_; #endif #ifdef YOSYS_USE_STICKY_IDS @@ -45,10 +46,32 @@ int RTLIL::IdString::last_created_idx_[8]; int RTLIL::IdString::last_created_idx_ptr_; #endif -#define X(_id) IdString RTLIL::ID::_id; +#define X(N) const RTLIL::IdString RTLIL::ID::N(RTLIL::StaticId::N); #include "kernel/constids.inc" #undef X +static void populate(std::string_view name) +{ + if (name[1] == '$') { + // Skip prepended '\' + name = name.substr(1); + } + RTLIL::IdString::global_id_index_.insert({name, GetSize(RTLIL::IdString::global_id_storage_)}); + RTLIL::IdString::global_id_storage_.push_back(const_cast(name.data())); +} + +void RTLIL::IdString::prepopulate() +{ + int size = static_cast(RTLIL::StaticId::STATIC_ID_END); + global_id_storage_.reserve(size); + RTLIL::IdString::global_id_storage_.push_back(const_cast("")); + global_id_index_.reserve(size); + global_refcount_storage_.resize(size, 1); +#define X(N) populate("\\" #N); +#include "kernel/constids.inc" +#undef X +} + dict RTLIL::constpad; const pool &RTLIL::builtin_ff_cell_types() { diff --git a/kernel/rtlil.h b/kernel/rtlil.h index c81a0c00a..80d0d0cfb 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -83,6 +83,14 @@ namespace RTLIL SB_EXCL_BB_CMDERR = 15 // call log_cmd_error on black boxed module }; + enum class StaticId : short { + STATIC_ID_BEGIN = 0, +#define X(N) N, +#include "kernel/constids.inc" +#undef X + STATIC_ID_END, + }; + struct Const; struct AttrObject; struct NamedObject; @@ -105,8 +113,18 @@ namespace RTLIL struct Process; struct Binding; struct IdString; + struct StaticIdString; typedef std::pair SigSig; + + struct StaticIdString { + constexpr StaticIdString(StaticId id, const IdString &id_str) : id_str(id_str), id(id) {} + constexpr inline operator const IdString &() const { return id_str; } + constexpr inline int index() const { return static_cast(id); } + + const IdString &id_str; + const StaticId id; + }; }; struct RTLIL::IdString @@ -127,7 +145,13 @@ struct RTLIL::IdString static std::vector global_id_storage_; static std::unordered_map global_id_index_; #ifndef YOSYS_NO_IDS_REFCNT - static std::vector global_refcount_storage_; + // For prepopulated IdStrings, the refcount is meaningless since they + // are never freed even if the refcount is zero. For code efficiency + // we increment the refcount of prepopulated IdStrings like any other string, + // but we never decrement the refcount or check whether it's zero. + // So, make this unsigned because refcounts of preopulated IdStrings may overflow + // and overflow of signed integers is undefined behavior. + static std::vector global_refcount_storage_; static std::vector global_free_idx_list_; #endif @@ -144,7 +168,7 @@ struct RTLIL::IdString if (global_id_storage_.at(idx) == nullptr) log("#X# DB-DUMP index %d: FREE\n", idx); else - log("#X# DB-DUMP index %d: '%s' (ref %d)\n", idx, global_id_storage_.at(idx), global_refcount_storage_.at(idx)); + log("#X# DB-DUMP index %d: '%s' (ref %u)\n", idx, global_id_storage_.at(idx), global_refcount_storage_.at(idx)); } #endif } @@ -166,15 +190,13 @@ struct RTLIL::IdString static inline int get_reference(int idx) { - if (idx) { #ifndef YOSYS_NO_IDS_REFCNT - global_refcount_storage_[idx]++; + global_refcount_storage_[idx]++; #endif #ifdef YOSYS_XTRACE_GET_PUT - if (yosys_xtrace) - log("#X# GET-BY-INDEX '%s' (index %d, refcount %d)\n", global_id_storage_.at(idx), idx, global_refcount_storage_.at(idx)); + if (yosys_xtrace && idx >= static_cast(StaticId::STATIC_ID_END)) + log("#X# GET-BY-INDEX '%s' (index %d, refcount %u)\n", global_id_storage_.at(idx), idx, global_refcount_storage_.at(idx)); #endif - } return idx; } @@ -182,9 +204,6 @@ struct RTLIL::IdString { log_assert(destruct_guard_ok); - if (!p[0]) - return 0; - auto it = global_id_index_.find((char*)p); if (it != global_id_index_.end()) { #ifndef YOSYS_NO_IDS_REFCNT @@ -192,11 +211,17 @@ struct RTLIL::IdString #endif #ifdef YOSYS_XTRACE_GET_PUT if (yosys_xtrace) - log("#X# GET-BY-NAME '%s' (index %d, refcount %d)\n", global_id_storage_.at(it->second), it->second, global_refcount_storage_.at(it->second)); + log("#X# GET-BY-NAME '%s' (index %d, refcount %u)\n", global_id_storage_.at(it->second), it->second, global_refcount_storage_.at(it->second)); #endif return it->second; } + if (global_id_index_.empty()) + prepopulate(); + + if (!p[0]) + return 0; + log_assert(p[0] == '$' || p[0] == '\\'); log_assert(p[1] != 0); for (const char *c = p; *c; c++) @@ -238,7 +263,7 @@ struct RTLIL::IdString #ifdef YOSYS_XTRACE_GET_PUT if (yosys_xtrace) - log("#X# GET-BY-NAME '%s' (index %d, refcount %d)\n", global_id_storage_.at(idx), idx, global_refcount_storage_.at(idx)); + log("#X# GET-BY-NAME '%s' (index %d, refcount %u)\n", global_id_storage_.at(idx), idx, global_refcount_storage_.at(idx)); #endif #ifdef YOSYS_USE_STICKY_IDS @@ -258,21 +283,20 @@ struct RTLIL::IdString { // put_reference() may be called from destructors after the destructor of // global_refcount_storage_ has been run. in this case we simply do nothing. - if (!destruct_guard_ok || !idx) + if (idx < static_cast(StaticId::STATIC_ID_END) || !destruct_guard_ok) return; #ifdef YOSYS_XTRACE_GET_PUT if (yosys_xtrace) { - log("#X# PUT '%s' (index %d, refcount %d)\n", global_id_storage_.at(idx), idx, global_refcount_storage_.at(idx)); + log("#X# PUT '%s' (index %d, refcount %u)\n", global_id_storage_.at(idx), idx, global_refcount_storage_.at(idx)); } #endif - int &refcount = global_refcount_storage_[idx]; + uint32_t &refcount = global_refcount_storage_[idx]; if (--refcount > 0) return; - log_assert(refcount == 0); free_reference(idx); } static inline void free_reference(int idx) @@ -281,6 +305,7 @@ struct RTLIL::IdString log("#X# Removed IdString '%s' with index %d.\n", global_id_storage_.at(idx), idx); log_backtrace("-X- ", yosys_xtrace-1); } + log_assert(idx >= static_cast(StaticId::STATIC_ID_END)); global_id_index_.erase(global_id_storage_.at(idx)); free(global_id_storage_.at(idx)); @@ -300,6 +325,7 @@ struct RTLIL::IdString inline IdString(const IdString &str) : index_(get_reference(str.index_)) { } inline IdString(IdString &&str) : index_(str.index_) { str.index_ = 0; } inline IdString(const std::string &str) : index_(get_reference(str.c_str())) { } + inline IdString(StaticId id) : index_(static_cast(id)) {} inline ~IdString() { put_reference(index_); } inline void operator=(const IdString &rhs) { @@ -331,6 +357,8 @@ struct RTLIL::IdString inline bool operator==(const IdString &rhs) const { return index_ == rhs.index_; } inline bool operator!=(const IdString &rhs) const { return index_ != rhs.index_; } + inline bool operator==(const StaticIdString &rhs) const; + inline bool operator!=(const StaticIdString &rhs) const; // The methods below are just convenience functions for better compatibility with std::string. @@ -416,12 +444,16 @@ struct RTLIL::IdString } bool in(const IdString &rhs) const { return *this == rhs; } + bool in(const StaticIdString &rhs) const { return *this == rhs; } bool in(const char *rhs) const { return *this == rhs; } bool in(const std::string &rhs) const { return *this == rhs; } inline bool in(const pool &rhs) const; inline bool in(const pool &&rhs) const; bool isPublic() const { return begins_with("\\"); } + +private: + static void prepopulate(); }; namespace hashlib { @@ -449,12 +481,76 @@ inline bool RTLIL::IdString::in(const pool &rhs) const { return rhs.co [[deprecated]] inline bool RTLIL::IdString::in(const pool &&rhs) const { return rhs.count(*this) != 0; } +inline bool RTLIL::IdString::operator==(const RTLIL::StaticIdString &rhs) const { + return index_ == rhs.index(); +} +inline bool RTLIL::IdString::operator!=(const RTLIL::StaticIdString &rhs) const { + return index_ != rhs.index(); +} + namespace RTLIL { namespace ID { -#define X(_id) extern IdString _id; +#define X(_id) extern const IdString _id; #include "kernel/constids.inc" #undef X - }; + } +} + +struct IdTableEntry { + const std::string_view name; + const RTLIL::StaticIdString static_id; +}; + +constexpr IdTableEntry IdTable[] = { +#define X(_id) {#_id, RTLIL::StaticIdString(RTLIL::StaticId::_id, RTLIL::ID::_id)}, +#include "kernel/constids.inc" +#undef X +}; + +constexpr int lookup_well_known_id(std::string_view name) +{ + int low = 0; + int high = sizeof(IdTable) / sizeof(IdTable[0]); + while (high - low >= 2) { + int mid = (low + high) / 2; + if (name < IdTable[mid].name) + high = mid; + else + low = mid; + } + if (IdTable[low].name == name) + return low; + return -1; +} + +// Create a statically allocated IdString object, using for example ID::A or ID($add). +// +// Recipe for Converting old code that is using conversion of strings like ID::A and +// "$add" for creating IdStrings: Run below SED command on the .cc file and then use for +// example "meld foo.cc foo.cc.orig" to manually compile errors, if necessary. +// +// sed -i.orig -r 's/"\\\\([a-zA-Z0-9_]+)"/ID(\1)/g; s/"(\$[a-zA-Z0-9_]+)"/ID(\1)/g;' +// +typedef const RTLIL::IdString &IDMacroHelperFunc(); + +template struct IDMacroHelper { + static constexpr RTLIL::StaticIdString eval(IDMacroHelperFunc) { + return IdTable[IdTableIndex].static_id; + } +}; +template <> struct IDMacroHelper<-1> { + static constexpr const RTLIL::IdString &eval(IDMacroHelperFunc func) { + return func(); + } +}; + +#define ID(_id) IDMacroHelper::eval([]() -> const RTLIL::IdString & { \ + const char *p = "\\" #_id, *q = p[1] == '$' ? p+1 : p; \ + static const YOSYS_NAMESPACE_PREFIX RTLIL::IdString id(q); \ + return id; \ + }) + +namespace RTLIL { extern dict constpad; const pool &builtin_ff_cell_types(); diff --git a/kernel/yosys.cc b/kernel/yosys.cc index 196b78186..fee951b0f 100644 --- a/kernel/yosys.cc +++ b/kernel/yosys.cc @@ -211,10 +211,6 @@ void yosys_setup() init_share_dirname(); init_abc_executable_name(); -#define X(_id) RTLIL::ID::_id = "\\" # _id; -#include "kernel/constids.inc" -#undef X - Pass::init_register(); yosys_design = new RTLIL::Design; yosys_celltypes.setup(); diff --git a/kernel/yosys_common.h b/kernel/yosys_common.h index 943aa4f05..fd84dd74e 100644 --- a/kernel/yosys_common.h +++ b/kernel/yosys_common.h @@ -206,13 +206,13 @@ namespace RTLIL { struct Module; struct Design; struct Monitor; - struct Selection; + struct Selection; struct SigChunk; enum State : unsigned char; typedef std::pair SigSig; - namespace ID {} + namespace ID {} } namespace AST { @@ -277,16 +277,6 @@ RTLIL::IdString new_id_suffix(std::string file, int line, std::string func, std: #define NEW_ID_SUFFIX(suffix) \ YOSYS_NAMESPACE_PREFIX new_id_suffix(__FILE__, __LINE__, __FUNCTION__, suffix) -// Create a statically allocated IdString object, using for example ID::A or ID($add). -// -// Recipe for Converting old code that is using conversion of strings like ID::A and -// "$add" for creating IdStrings: Run below SED command on the .cc file and then use for -// example "meld foo.cc foo.cc.orig" to manually compile errors, if necessary. -// -// sed -i.orig -r 's/"\\\\([a-zA-Z0-9_]+)"/ID(\1)/g; s/"(\$[a-zA-Z0-9_]+)"/ID(\1)/g;' -// -#define ID(_id) ([]() -> const RTLIL::IdString & { const char *p = "\\" #_id, *q = p[1] == '$' ? p+1 : p; \ - static const YOSYS_NAMESPACE_PREFIX RTLIL::IdString id(q); return id; })() namespace ID = RTLIL::ID;