From c517aa4ff702b49aa15d70b5052b04d95510189e Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 27 Jun 2020 01:47:35 +0200 Subject: [PATCH] Cherry-picked MacOS fixes into master --- src/db/db/dbHierarchyBuilder.cc | 9 ++-- src/db/db/dbNetlistCompare.cc | 16 ++---- src/db/unit_tests/dbNetlistCompareTests.cc | 61 ++++++++++++++++++++++ src/gsi/gsi/gsiClassBase.cc | 34 +++++++++--- src/tl/tl/tlStream.cc | 27 +++++++--- src/tl/unit_tests/tlStreamTests.cc | 17 ++++++ 6 files changed, 137 insertions(+), 27 deletions(-) diff --git a/src/db/db/dbHierarchyBuilder.cc b/src/db/db/dbHierarchyBuilder.cc index 35424cabc..0b15c3127 100644 --- a/src/db/db/dbHierarchyBuilder.cc +++ b/src/db/db/dbHierarchyBuilder.cc @@ -31,6 +31,9 @@ namespace db static HierarchyBuilderShapeInserter def_inserter; +static HierarchyBuilder::cell_map_type null_map; +static HierarchyBuilder::cell_map_type::const_iterator null_iterator = null_map.end (); + // ------------------------------------------------------------------------------------------- int @@ -168,7 +171,7 @@ HierarchyBuilder::reset () m_cell_map.clear (); m_cells_seen.clear (); m_cell_stack.clear (); - m_cm_entry = cell_map_type::const_iterator (); + m_cm_entry = null_iterator; m_cm_new_entry = false; } @@ -263,14 +266,14 @@ HierarchyBuilder::end (const RecursiveShapeIterator *iter) m_cells_seen.clear (); mp_initial_cell = m_cell_stack.empty () ? 0 : m_cell_stack.front ().second.front (); m_cell_stack.clear (); - m_cm_entry = cell_map_type::const_iterator (); + m_cm_entry = null_iterator; m_cm_new_entry = false; } void HierarchyBuilder::enter_cell (const RecursiveShapeIterator * /*iter*/, const db::Cell * /*cell*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/) { - tl_assert (m_cm_entry != m_cell_map.end () && m_cm_entry != cell_map_type::const_iterator ()); + tl_assert (m_cm_entry != m_cell_map.end () && m_cm_entry != null_iterator); m_cells_seen.insert (m_cm_entry->first); diff --git a/src/db/db/dbNetlistCompare.cc b/src/db/db/dbNetlistCompare.cc index 7844e4f1b..ac592823d 100644 --- a/src/db/db/dbNetlistCompare.cc +++ b/src/db/db/dbNetlistCompare.cc @@ -3349,26 +3349,20 @@ void align (Iter i1, Iter i2, Iter j1, Iter j2, Distance distance) vj.push_back (j); } - while (vi.size () < vj.size ()) { - vi.push_back (Iter ()); - } + size_t sz = std::max (vi.size (), vj.size ()); - while (vj.size () < vi.size ()) { - vj.push_back (Iter ()); - } - - if (vi.size () <= 1) { + if (sz <= 1) { return; } // Caution: this is an O(2) algorithm ... bool any_swapped = true; - for (size_t n = 0; n < vi.size () - 1 && any_swapped; ++n) { + for (size_t n = 0; n < sz - 1 && any_swapped; ++n) { any_swapped = false; - for (size_t m = n + 1; m < vj.size (); ++m) { - if (vi [n] == Iter () || vi [m] == Iter () || vj [n] == Iter () || vj [m] == Iter ()) { + for (size_t m = n + 1; m < sz; ++m) { + if (n >= vi.size () || m >= vi.size () || n >= vj.size () || m >= vj.size ()) { continue; } else if (distance (*vi [n], *vj [m]) + distance (*vi [m], *vj [n]) < distance (*vi [n], *vj [n]) + distance (*vi [m], *vj [m])) { // this will reduce the overall distance: diff --git a/src/db/unit_tests/dbNetlistCompareTests.cc b/src/db/unit_tests/dbNetlistCompareTests.cc index 718d85ffd..17b682925 100644 --- a/src/db/unit_tests/dbNetlistCompareTests.cc +++ b/src/db/unit_tests/dbNetlistCompareTests.cc @@ -2933,6 +2933,67 @@ TEST(18_ClockTree) "end_circuit TXEE TXEE MATCH" ); EXPECT_EQ (good, true); + + comp.set_depth_first (false); + logger.clear (); + good = comp.compare (&nl1, &nl2); + + txt = logger.text (); + // because L/R matching is ambiguous, we need to do this to + // establish reproducability on different platforms: + txt = tl::replaced (txt, "L", "X"); + txt = tl::replaced (txt, "R", "X"); + + EXPECT_EQ (txt, + "begin_circuit INV INV\n" + "match_nets VDD VDD\n" + "match_nets OUT OUT\n" + "match_nets IN IN\n" + "match_nets VSS VSS\n" + "match_pins IN IN\n" + "match_pins OUT OUT\n" + "match_pins VDD VDD\n" + "match_pins VSS VSS\n" + "match_devices $1 $1\n" + "match_devices $2 $2\n" + "end_circuit INV INV MATCH\n" + "begin_circuit TXEE TXEE\n" + "match_nets IN IN\n" + "match_nets VSS VSS\n" + "match_nets VDD VDD\n" + "match_nets S S\n" + "match_ambiguous_nets SX SX\n" + "match_ambiguous_nets SX SX\n" + "match_ambiguous_nets SXX SXX\n" + "match_ambiguous_nets SXX SXX\n" + "match_ambiguous_nets SXXX SXXX\n" + "match_ambiguous_nets SXXX SXXX\n" + "match_ambiguous_nets SXXX SXXX\n" + "match_ambiguous_nets SXXX SXXX\n" + "match_ambiguous_nets SXX SXX\n" + "match_ambiguous_nets SXX SXX\n" + "match_ambiguous_nets SXXX SXXX\n" + "match_ambiguous_nets SXXX SXXX\n" + "match_ambiguous_nets SXXX SXXX\n" + "match_ambiguous_nets SXXX SXXX\n" + "match_subcircuits TXXX TXXX\n" + "match_subcircuits TX TX\n" + "match_subcircuits TXXX TXXX\n" + "match_subcircuits TXXX TXXX\n" + "match_subcircuits TXX TXX\n" + "match_subcircuits TXX TXX\n" + "match_subcircuits TXXX TXXX\n" + "match_subcircuits TXXX TXXX\n" + "match_subcircuits TXXX TXXX\n" + "match_subcircuits T T\n" + "match_subcircuits TXXX TXXX\n" + "match_subcircuits TX TX\n" + "match_subcircuits TXX TXX\n" + "match_subcircuits TXXX TXXX\n" + "match_subcircuits TXX TXX\n" + "end_circuit TXEE TXEE MATCH" + ); + EXPECT_EQ (good, true); } TEST(19_SymmetricCircuit) diff --git a/src/gsi/gsi/gsiClassBase.cc b/src/gsi/gsi/gsiClassBase.cc index 670a1466d..776f4ecb3 100644 --- a/src/gsi/gsi/gsiClassBase.cc +++ b/src/gsi/gsi/gsiClassBase.cc @@ -51,6 +51,9 @@ namespace { // we do a initial scan and after this no more write access here. typedef std::map ti_to_class_map_t; static ti_to_class_map_t *sp_ti_to_class = 0; +// NOTE: MacOS/clang seems to have some issue with RTTI across shared objects. This map provides a name-based fallback +typedef std::map tname_to_class_map_t; +static tname_to_class_map_t *sp_tname_to_class = 0; ClassBase::ClassBase (const std::string &doc, const Methods &mm, bool do_register) : m_initialized (false), mp_base (0), mp_parent (0), m_doc (doc), m_methods (mm) @@ -68,6 +71,10 @@ ClassBase::ClassBase (const std::string &doc, const Methods &mm, bool do_registe delete sp_ti_to_class; sp_ti_to_class = 0; } + if (sp_tname_to_class) { + delete sp_tname_to_class; + sp_tname_to_class = 0; + } } } @@ -753,11 +760,18 @@ static void add_class_to_map (const gsi::ClassBase *c) if (! sp_ti_to_class) { sp_ti_to_class = new ti_to_class_map_t (); } + if (! sp_tname_to_class) { + sp_tname_to_class = new tname_to_class_map_t (); + } - if (ti && c->is_of_type (*ti) && !sp_ti_to_class->insert (std::make_pair (ti, c)).second) { - // Duplicate registration of this class - tl::error << "Duplicate registration of class " << c->name () << " (type " << ti->name () << ")"; - tl_assert (false); + if (ti && c->is_of_type (*ti)) { + if (!sp_ti_to_class->insert (std::make_pair (ti, c)).second) { + // Duplicate registration of this class + tl::error << "Duplicate registration of class " << c->name () << " (type " << ti->name () << ")"; + tl_assert (false); + } else { + sp_tname_to_class->insert (std::make_pair (std::string (ti->name ()), c)); + } } } @@ -775,11 +789,19 @@ const ClassBase *class_by_typeinfo_no_assert (const std::type_info &ti) if (! sp_ti_to_class) { return 0; } else { - std::map::const_iterator c = sp_ti_to_class->find (&ti); + ti_to_class_map_t::const_iterator c = sp_ti_to_class->find (&ti); if (c != sp_ti_to_class->end ()) { return c->second; } else { - return 0; + // try name lookup + tname_to_class_map_t::const_iterator cn = sp_tname_to_class->find (std::string (ti.name ())); + if (cn != sp_tname_to_class->end ()) { + // we can use this typeinfo as alias + sp_ti_to_class->insert (std::make_pair (&ti, cn->second)); + return cn->second; + } else { + return 0; + } } } } diff --git a/src/tl/tl/tlStream.cc b/src/tl/tl/tlStream.cc index e6d8d2b6f..193b0fabe 100644 --- a/src/tl/tl/tlStream.cc +++ b/src/tl/tl/tlStream.cc @@ -1106,10 +1106,22 @@ size_t InputPipe::read (char *b, size_t n) { tl_assert (m_file != NULL); - size_t ret = fread (b, 1, n, m_file); - if (ret < n) { - if (ferror (m_file)) { - throw FilePReadErrorException (m_source, ferror (m_file)); + + bool retry = true; + size_t ret = 0; + + while (retry) { + retry = false; + ret = fread (b, 1, n, m_file); + if (ret < n) { + if (ferror (m_file)) { + if (errno != EINTR) { + throw FilePReadErrorException (m_source, errno); + } else if (ret == 0) { + retry = true; + clearerr (m_file); + } + } } } @@ -1138,7 +1150,7 @@ OutputPipe::OutputPipe (const std::string &path) OutputPipe::~OutputPipe () { if (m_file != NULL) { - fclose (m_file); + pclose (m_file); m_file = NULL; } } @@ -1147,10 +1159,11 @@ void OutputPipe::write (const char *b, size_t n) { tl_assert (m_file != NULL); + size_t ret = fwrite (b, 1, n, m_file); if (ret < n) { - if (ferror (m_file)) { - throw FilePWriteErrorException (m_source, ferror (m_file)); + if (ferror (m_file) && errno != EINTR) { + throw FilePReadErrorException (m_source, errno); } } } diff --git a/src/tl/unit_tests/tlStreamTests.cc b/src/tl/unit_tests/tlStreamTests.cc index 733db501d..f2fb84218 100644 --- a/src/tl/unit_tests/tlStreamTests.cc +++ b/src/tl/unit_tests/tlStreamTests.cc @@ -52,6 +52,23 @@ TEST(InputPipe2) EXPECT_NE (ret, 0); } +TEST(OutputPipe1) +{ + std::string tf = tmp_file ("pipe_out"); + + { + tl::OutputPipe pipe ("cat >" + tf); + tl::OutputStream str (pipe); + str << "Hello, world!"; + } + + { + tl::InputStream is (tf); + std::string s = is.read_all (); + EXPECT_EQ (s, "Hello, world!"); + } +} + TEST(TextOutputStream) { std::string fn = tmp_file ("test.txt");