Cherry-picked MacOS fixes into master

This commit is contained in:
Matthias Koefferlein 2020-06-27 01:47:35 +02:00
parent 69fe4a5edf
commit c517aa4ff7
6 changed files with 137 additions and 27 deletions

View File

@ -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);

View File

@ -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:

View File

@ -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)

View File

@ -51,6 +51,9 @@ namespace {
// we do a initial scan and after this no more write access here.
typedef std::map<const std::type_info *, const ClassBase *, type_info_compare> 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<std::string, const ClassBase *> 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 std::type_info *, const ClassBase *, type_info_compare>::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;
}
}
}
}

View File

@ -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);
}
}
}

View File

@ -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");