From 34905e675a193210a1b422e2b66f8a2abbbc8755 Mon Sep 17 00:00:00 2001 From: Ethan Mahintorabi Date: Mon, 20 Apr 2026 20:52:40 +0000 Subject: [PATCH 1/2] Adds stream interface for parseLibertyFile Signed-off-by: Ethan Mahintorabi --- liberty/LibertyParser.cc | 18 ++++++++++++++---- liberty/LibertyParser.hh | 6 ++++++ 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/liberty/LibertyParser.cc b/liberty/LibertyParser.cc index 26c0fefc1..2ece34e4a 100644 --- a/liberty/LibertyParser.cc +++ b/liberty/LibertyParser.cc @@ -49,15 +49,25 @@ parseLibertyFile(std::string_view filename, std::string fn(filename); gzstream::igzstream stream(fn.c_str()); if (stream.is_open()) { - LibertyParser reader(filename, library_visitor, report); - LibertyScanner scanner(&stream, filename, &reader, report); - LibertyParse parser(&scanner, &reader); - parser.parse(); + parseLibertyFile(stream, filename, library_visitor, report); } else throw FileNotReadable(filename); } +void +parseLibertyFile(std::istream& file_contents, + std::string_view filename, + LibertyGroupVisitor *library_visitor, + Report *report) +{ + + LibertyParser reader(filename, library_visitor, report); + LibertyScanner scanner(&file_contents, filename, &reader, report); + LibertyParse parser(&scanner, &reader); + parser.parse(); +} + LibertyParser::LibertyParser(std::string_view filename, LibertyGroupVisitor *library_visitor, Report *report) : diff --git a/liberty/LibertyParser.hh b/liberty/LibertyParser.hh index 607e9d716..67602e9c9 100644 --- a/liberty/LibertyParser.hh +++ b/liberty/LibertyParser.hh @@ -25,6 +25,7 @@ #pragma once #include +#include #include #include #include @@ -277,6 +278,11 @@ public: virtual void visitVariable(LibertyVariable *variable) = 0; }; +void +parseLibertyFile(std::istream& file_contents, + std::string_view filename, + LibertyGroupVisitor *library_visitor, + Report *report); void parseLibertyFile(std::string_view filename, LibertyGroupVisitor *library_visitor, From 2c2fb347dda5f53e90b018442549c94e8a88b0c8 Mon Sep 17 00:00:00 2001 From: Ted Hong Date: Wed, 24 Jun 2026 17:29:28 +0000 Subject: [PATCH 2/2] Plumbed API for stream-based LibertyParser to LibertyReader. Signed-off-by: Ted Hong --- include/sta/Sta.hh | 21 +++++++++ liberty/LibertyParser.cc | 1 - liberty/LibertyParser.hh | 13 +++++- liberty/LibertyReader.cc | 14 +++++- liberty/LibertyReader.hh | 7 +++ liberty/LibertyReaderPvt.hh | 1 + liberty/test/cpp/TestLibertyStaCallbacks.cc | 47 +++++++++++++++++++++ search/Sta.cc | 34 +++++++++++++++ 8 files changed, 135 insertions(+), 3 deletions(-) diff --git a/include/sta/Sta.hh b/include/sta/Sta.hh index 9f9f53ed5..ddc689dc6 100644 --- a/include/sta/Sta.hh +++ b/include/sta/Sta.hh @@ -24,6 +24,7 @@ #pragma once +#include #include #include #include @@ -148,10 +149,25 @@ public: ModeSeq findModes(const std::string &mode_name) const; Sdc *cmdSdc() const; + // Read a Liberty file from a file. + // + // filename should be the path to the file, if ZLIB is included it may be + // either compressed or uncompressed. virtual LibertyLibrary *readLiberty(std::string_view filename, Scene *scene, const MinMaxAll *min_max, bool infer_latches); + // Read a Liberty file from an input stream. + // + // filename is used only as a label in diagnostic messages; it may but need + // not correspond to a file on disk. + // + // The input stream should provide uncompressed text. + virtual LibertyLibrary *readLiberty(std::istream& stream, + std::string_view filename, + Scene *scene, + const MinMaxAll *min_max, + bool infer_latches); // tmp public void readLibertyAfter(LibertyLibrary *liberty, Scene *scene, @@ -1516,6 +1532,11 @@ protected: Scene *scene, const MinMaxAll *min_max, bool infer_latches); + LibertyLibrary *readLibertyFile(std::istream& stream, + std::string_view filename, + Scene *scene, + const MinMaxAll *min_max, + bool infer_latches); void delayCalcPreamble(); void delaysInvalidFrom(const Port *port); void delaysInvalidFromFanin(const Port *port); diff --git a/liberty/LibertyParser.cc b/liberty/LibertyParser.cc index 2ece34e4a..e0029f9d0 100644 --- a/liberty/LibertyParser.cc +++ b/liberty/LibertyParser.cc @@ -61,7 +61,6 @@ parseLibertyFile(std::istream& file_contents, LibertyGroupVisitor *library_visitor, Report *report) { - LibertyParser reader(filename, library_visitor, report); LibertyScanner scanner(&file_contents, filename, &reader, report); LibertyParse parser(&scanner, &reader); diff --git a/liberty/LibertyParser.hh b/liberty/LibertyParser.hh index 67602e9c9..e3b334995 100644 --- a/liberty/LibertyParser.hh +++ b/liberty/LibertyParser.hh @@ -25,7 +25,7 @@ #pragma once #include -#include +#include #include #include #include @@ -278,11 +278,22 @@ public: virtual void visitVariable(LibertyVariable *variable) = 0; }; +// Parse a Liberty file from an input stream. +// +// filename is used only as a label in diagnostic messages; it may but need not +// correspond to a file on disk. +// +// The input stream should provide uncompressed text. void parseLibertyFile(std::istream& file_contents, std::string_view filename, LibertyGroupVisitor *library_visitor, Report *report); + +// Parse a Liberty file from a file. +// +// filename should be the path to the file, if ZLIB is included it may be +// either compressed or uncompressed. void parseLibertyFile(std::string_view filename, LibertyGroupVisitor *library_visitor, diff --git a/liberty/LibertyReader.cc b/liberty/LibertyReader.cc index 09733ca87..2868c3a9a 100644 --- a/liberty/LibertyReader.cc +++ b/liberty/LibertyReader.cc @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -79,6 +80,12 @@ readLibertyFile(std::string_view filename, return reader.readLibertyFile(filename); } +LibertyLibrary* readLibertyFile(std::istream& stream, std::string_view filename, + bool infer_latches, Network* network) { + LibertyReader reader(filename, infer_latches, network); + return reader.readLibertyFile(stream); +} + LibertyReader::LibertyReader(std::string_view filename, bool infer_latches, Network *network) : @@ -100,6 +107,11 @@ LibertyReader::readLibertyFile(std::string_view filename) return library_; } +LibertyLibrary* LibertyReader::readLibertyFile(std::istream& stream) { + parseLibertyFile(stream, filename_, this, report_); + return library_; +} + void LibertyReader::defineGroupVisitor(std::string_view type, LibraryGroupVisitor begin_visitor, @@ -1665,7 +1677,7 @@ LibertyReader::makeSequentials(LibertyCell *cell, makeSequentials(cell, cell_group, false, "latch", "enable", "data_in"); makeSequentials(cell, cell_group, false, "latch_bank", "enable", "data_in"); - const LibertyGroup *lut_group = cell_group->findSubgroup("lut");; + const LibertyGroup *lut_group = cell_group->findSubgroup("lut"); if (lut_group) { LibertyPort *out_port = nullptr; LibertyPort *out_port_inv = nullptr; diff --git a/liberty/LibertyReader.hh b/liberty/LibertyReader.hh index 030c42e82..297801889 100644 --- a/liberty/LibertyReader.hh +++ b/liberty/LibertyReader.hh @@ -25,6 +25,7 @@ #pragma once #include +#include namespace sta { @@ -36,4 +37,10 @@ readLibertyFile(std::string_view filename, bool infer_latches, Network *network); +LibertyLibrary * +readLibertyFile(std::istream& stream, + std::string_view filename, + bool infer_latches, + Network *network); + } // namespace sta diff --git a/liberty/LibertyReaderPvt.hh b/liberty/LibertyReaderPvt.hh index eabdc2cc8..b8a371b6a 100644 --- a/liberty/LibertyReaderPvt.hh +++ b/liberty/LibertyReaderPvt.hh @@ -70,6 +70,7 @@ public: bool infer_latches, Network *network); LibertyLibrary *readLibertyFile(std::string_view filename); + LibertyLibrary *readLibertyFile(std::istream& stream); LibertyLibrary *library() { return library_; } const LibertyLibrary *library() const { return library_; } diff --git a/liberty/test/cpp/TestLibertyStaCallbacks.cc b/liberty/test/cpp/TestLibertyStaCallbacks.cc index 52f0d155c..a14c5df7e 100644 --- a/liberty/test/cpp/TestLibertyStaCallbacks.cc +++ b/liberty/test/cpp/TestLibertyStaCallbacks.cc @@ -2,6 +2,7 @@ #include #include #include +#include #include #include "Units.hh" #include "TimingRole.hh" @@ -4344,4 +4345,50 @@ library(test_mbff_statetable) { "combinational"; } +// Verifies in-memory parsing via std::istream& without touching the filesystem. +TEST_F(StaLibertyTest, + ParserStreamOverload) +{ + const char *content = R"( + library(test_stream_overload) { + delay_model : table_lookup ; + time_unit : "1ns" ; + voltage_unit : "1V" ; + current_unit : "1mA" ; + capacitive_load_unit(1, ff) ; + define(custom_attr, cell, float) ; + my_variable = 42.0 ; + cell(SV1) { + area : 1.0 ; + pin(A) { direction : input ; capacitance : 0.01 ; } + pin(Z) { direction : output ; function : "A" ; } + } + } + )"; + + // Feed the parser directly from memory — no temp file involved. + std::stringstream stream(content); + RecordingLibertyVisitor visitor; + parseLibertyFile(stream, "", &visitor, sta_->report()); + + // Same expectations as the file-path variant: the visitor saw a library + // group with one define, one variable, and a cell with area=1.0. + EXPECT_GT(visitor.begin_count, 0); + EXPECT_EQ(visitor.begin_count, visitor.end_count); + ASSERT_EQ(visitor.root_groups.size(), 1u); + const LibertyGroup *library = visitor.root_groups.front(); + ASSERT_NE(library, nullptr); + EXPECT_EQ(library->defineMap().size(), 1u); + EXPECT_EQ(visitor.variables.size(), 1u); + EXPECT_GT(visitor.simple_attrs.size(), 0u); + + const LibertyGroup *cell = library->findSubgroup("cell"); + ASSERT_NE(cell, nullptr); + float area = 0.0f; + bool exists = false; + cell->findAttrFloat("area", area, exists); + EXPECT_TRUE(exists); + EXPECT_FLOAT_EQ(area, 1.0f); +} + } // namespace sta diff --git a/search/Sta.cc b/search/Sta.cc index 97fb3a527..014e5d67a 100644 --- a/search/Sta.cc +++ b/search/Sta.cc @@ -707,6 +707,24 @@ Sta::readLiberty(std::string_view filename, return library; } +LibertyLibrary* Sta::readLiberty(std::istream& stream, + std::string_view filename, Scene* scene, + const MinMaxAll* min_max, bool infer_latches) { + Stats stats(debug_, report_); + LibertyLibrary* library = + readLibertyFile(stream, filename, scene, min_max, infer_latches); + if (library + // The default library is the first library read. + // This corresponds to a link_path of '*'. + && network_->defaultLibertyLibrary() == nullptr) { + network_->setDefaultLibertyLibrary(library); + // Set units from default (first) library. + *units_ = *library->units(); + } + stats.report("Read liberty"); + return library; +} + LibertyLibrary * Sta::readLibertyFile(std::string_view filename, Scene *scene, @@ -723,6 +741,22 @@ Sta::readLibertyFile(std::string_view filename, return liberty; } + +LibertyLibrary* Sta::readLibertyFile(std::istream& stream, + std::string_view filename, Scene* scene, + const MinMaxAll* min_max, + bool infer_latches) { + LibertyLibrary* liberty = + sta::readLibertyFile(stream, filename, infer_latches, network_); + if (liberty) { + // Don't map liberty cells if they are redefined by reading another + // library with the same cell names. + readLibertyAfter(liberty, scene, min_max); + network_->readLibertyAfter(liberty); + } + return liberty; +} + void Sta::readLibertyAfter(LibertyLibrary *liberty, Scene *scene,