changes from upstream 4/13 with prima delaycalc checkArgs refactor, some coverity fix but still problematic

Signed-off-by: dsengupta0628 <dsengupta@precisioninno.com>
This commit is contained in:
dsengupta0628 2026-04-13 21:26:42 +00:00
commit d5925fcdcc
8 changed files with 242 additions and 139 deletions

View File

@ -36,6 +36,9 @@ option(ENABLE_ASAN "Compile with address santizer enabled" OFF)
# Turn on to debug compiler args.
set(CMAKE_VERBOSE_MAKEFILE OFF)
# Write compile_commands.json to the build directory for clang-tidy.
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
set(STA_HOME ${PROJECT_SOURCE_DIR})
message(STATUS "STA version: ${PROJECT_VERSION}")
@ -598,13 +601,13 @@ set(CXX_FLAGS -Wall -Wextra -pedantic -Wcast-qual -Wredundant-decls
if(ENABLE_TSAN)
message(STATUS "Thread sanitizer: ${ENABLE_TSAN}")
set(CXX_FLAGS "${CXX_FLAGS};-fsanitize=thread")
set(CMAKE_EXE_LINKER_FLAGS "-fsanitize=thread")
string(APPEND CMAKE_EXE_LINKER_FLAGS " -fsanitize=thread")
endif()
if(ENABLE_ASAN)
message(STATUS "Address sanitizer: ${ENABLE_ASAN}")
set(CXX_FLAGS "${CXX_FLAGS};-fsanitize=address")
set(CMAKE_EXE_LINKER_FLAGS "-fsanitize=address")
string(APPEND CMAKE_EXE_LINKER_FLAGS " -fsanitize=address")
endif()
target_compile_options(OpenSTA
@ -630,6 +633,7 @@ message(STATUS "STA library: ${CMAKE_BINARY_DIR}/libOpenSTA.a")
add_executable(sta app/Main.cc)
target_link_libraries(sta
PRIVATE
sta_swig
OpenSTA
)

View File

@ -216,43 +216,8 @@ PrimaDelayCalc::gateDelays(ArcDcalcArgSeq &dcalc_args,
parasitics_ = scene->parasitics(min_max);
node_index_map_ = NodeIndexMap(ParasiticNodeLess(parasitics_, network_));
bool failed = false;
output_waveforms_.resize(drvr_count_);
for (size_t drvr_idx = 0; drvr_idx < drvr_count_; drvr_idx++) {
ArcDcalcArg &dcalc_arg = dcalc_args[drvr_idx];
GateTableModel *table_model = dcalc_arg.arc()->gateTableModel(scene, min_max);
if (table_model && dcalc_arg.parasitic()) {
OutputWaveforms *output_waveforms = table_model->outputWaveforms();
float in_slew = dcalc_arg.inSlewFlt();
if (output_waveforms
// Bounds check because extrapolating waveforms does not work for shit.
&& output_waveforms->slewAxis()->inBounds(in_slew)
&& output_waveforms->capAxis()->inBounds(dcalc_arg.loadCap())) {
output_waveforms_[drvr_idx] = output_waveforms;
debugPrint(debug_, "ccs_dcalc", 1, "{} {}", dcalc_arg.drvrCell()->name(),
drvr_rf_->shortName());
LibertyCell *drvr_cell = dcalc_arg.drvrCell();
const LibertyLibrary *drvr_library = drvr_cell->libertyLibrary();
bool vdd_exists;
drvr_library->supplyVoltage("VDD", vdd_, vdd_exists);
if (!vdd_exists)
report_->error(1720, "VDD not defined in library {}",
drvr_library->name());
drvr_cell->ensureVoltageWaveforms(scenes_);
if (drvr_idx == 0) {
vth_ = drvr_library->outputThreshold(drvr_rf_) * vdd_;
vl_ = drvr_library->slewLowerThreshold(drvr_rf_) * vdd_;
vh_ = drvr_library->slewUpperThreshold(drvr_rf_) * vdd_;
}
}
else
failed = true;
}
else
failed = true;
}
if (failed)
bool arg_fail = checkArgs(dcalc_args, scene, min_max);
if (arg_fail)
return tableDcalcResults();
else {
simulate();
@ -260,6 +225,100 @@ PrimaDelayCalc::gateDelays(ArcDcalcArgSeq &dcalc_args,
}
}
// Return true on failure.
// Use falureReason() to get failure string.
bool
PrimaDelayCalc::checkArgs(ArcDcalcArgSeq &dcalc_args,
const Scene *scene,
const MinMax *min_max)
{
drvr_count_ = dcalc_args.size();
output_waveforms_.resize(drvr_count_);
failure_reason_ = nullptr;
failure_arg_ = nullptr;
for (size_t drvr_idx = 0; drvr_idx < drvr_count_; drvr_idx++) {
ArcDcalcArg &dcalc_arg = dcalc_args[drvr_idx];
GateTableModel *table_model = dcalc_arg.arc()->gateTableModel(scene, min_max);
if (table_model) {
if (dcalc_arg.parasitic()) {
OutputWaveforms *output_waveforms = table_model->outputWaveforms();
float in_slew = dcalc_arg.inSlewFlt();
if (output_waveforms) {
const LibertyLibrary *drvr_library = dcalc_arg.drvrLibrary();
float vdd;
bool vdd_exists;
drvr_library->supplyVoltage("VDD", vdd, vdd_exists);
if (vdd_exists) {
if (drvr_idx == 0) {
// Assume drivers are in the same library.
const RiseFall *drvr_rf = dcalc_arg.drvrEdge();
vdd_ = vdd;
vth_ = drvr_library->outputThreshold(drvr_rf) * vdd_;
vl_ = drvr_library->slewLowerThreshold(drvr_rf) * vdd_;
vh_ = drvr_library->slewUpperThreshold(drvr_rf) * vdd_;
}
}
else {
failure_reason_ = "vdd not defined";
failure_arg_ = &dcalc_arg;
}
// Bounds check because extrapolating waveforms does not work for shit.
if (output_waveforms->slewAxis()->inBounds(in_slew)) {
if (output_waveforms->capAxis()->inBounds(dcalc_arg.loadCap())) {
output_waveforms_[drvr_idx] = output_waveforms;
debugPrint(debug_, "prima", 1, "{} {}",
dcalc_arg.drvrCell()->name(),
dcalc_arg.drvrEdge()->to_string().c_str());
LibertyCell *drvr_cell = dcalc_arg.drvrCell();
drvr_cell->ensureVoltageWaveforms(scenes_);
}
else {
failure_reason_ = "load cap out of bounds";
failure_arg_ = &dcalc_arg;
}
}
else {
failure_reason_ = "input slew out of bounds";
failure_arg_ = &dcalc_arg;
}
}
else {
failure_reason_ = "no output waveforms";
failure_arg_ = &dcalc_arg;
}
}
else {
failure_reason_ = "no parasitic";
failure_arg_ = &dcalc_arg;
}
}
else {
failure_reason_ = "no table model";
failure_arg_ = &dcalc_arg;
}
}
if (failure_reason_) {
std::string reason = failureReason();
debugPrint(debug_,"prima", 1, "arg check failed {}.", reason.c_str());
}
return failure_reason_ != nullptr;
}
std::string
PrimaDelayCalc::failureReason()
{
const Pin *drvr_pin = failure_arg_->drvrPin();
const Instance *inst = network_->instance(drvr_pin);
LibertyPort *from = failure_arg_->arc()->from();
LibertyPort *to = failure_arg_->arc()->to();
return sta::format("{} {} -> {} {}",
sdc_network_->pathName(inst),
from->name(),
to->name(),
failure_reason_);
}
ArcDcalcResultSeq
PrimaDelayCalc::tableDcalcResults()
{
@ -938,8 +997,16 @@ PrimaDelayCalc::reportGateDelay(const Pin *drvr_pin,
const MinMax *min_max,
int digits)
{
GateTimingModel *model = arc->gateModel(scene, min_max);
if (model) {
ArcDcalcArgSeq dcalc_args;
dcalc_args.emplace_back(nullptr, drvr_pin, nullptr, arc, in_slew,
load_cap, parasitic);
bool arg_fail = checkArgs(dcalc_args, scene, min_max);
if (arg_fail)
return table_dcalc_->reportGateDelay(drvr_pin, arc, in_slew, load_cap,
parasitic, load_pin_index_map, scene,
min_max, digits);
else {
GateTimingModel *model = arc->gateModel(scene, min_max);
// Delay calc to find ceff.
gateDelay(drvr_pin, arc, in_slew, load_cap, parasitic,
load_pin_index_map, scene, min_max);
@ -949,7 +1016,6 @@ PrimaDelayCalc::reportGateDelay(const Pin *drvr_pin,
in_slew1, ceff, min_max,
PocvMode::scalar, digits);
}
return "";
}
////////////////////////////////////////////////////////////////

View File

@ -100,6 +100,10 @@ public:
const Scene *scene,
const MinMax *min_max,
int digits) override;
bool checkArgs(ArcDcalcArgSeq &dcalc_args,
const Scene *scene,
const MinMax *min_max);
std::string failureReason();
// Record waveform for drvr/load pin.
void watchPin(const Pin *pin) override;
@ -253,6 +257,9 @@ protected:
// Delay calculator to use when ccs waveforms are missing from liberty.
ArcDelayCalc *table_dcalc_;
const char *failure_reason_;
ArcDcalcArg *failure_arg_;
using ArcDelayCalc::reduceParasitic;
};

View File

@ -28,6 +28,7 @@
#include <string_view>
#include <vector>
#include "NetworkClass.hh"
#include "SdcClass.hh"
#include "SearchClass.hh"
#include "StringUtil.hh"

View File

@ -25,25 +25,26 @@
#pragma once
#include <string>
#include <string_view>
namespace sta {
std::string
cellVerilogName(std::string sta_name);
cellVerilogName(std::string_view sta_name);
std::string
instanceVerilogName(std::string sta_name);
instanceVerilogName(std::string_view sta_name);
std::string
netVerilogName(std::string sta_name);
netVerilogName(std::string_view sta_name);
std::string
portVerilogName(std::string sta_name);
portVerilogName(std::string_view sta_name);
std::string
moduleVerilogToSta(std::string sta_name);
moduleVerilogToSta(std::string_view sta_name);
std::string
instanceVerilogToSta(std::string sta_name);
instanceVerilogToSta(std::string_view sta_name);
std::string
netVerilogToSta(std::string sta_name);
netVerilogToSta(std::string_view sta_name);
std::string
portVerilogToSta(std::string sta_name);
portVerilogToSta(std::string_view sta_name);
} // namespace

View File

@ -1489,8 +1489,7 @@ LibertyCell::outputPortSequential(LibertyPort *port)
bool
LibertyCell::hasSequentials() const
{
return !sequentials_.empty()
|| statetable_ != nullptr;
return !sequentials_.empty() || statetable_ != nullptr;
}
void
@ -2478,16 +2477,10 @@ bool
LibertyPort::less(const LibertyPort *port1,
const LibertyPort *port2)
{
if (port1 == nullptr || port2 == nullptr)
if (port1 && port2)
return port1->pinIndex() < port2->pinIndex();
else
return port1 == nullptr && port2 != nullptr;
const std::string &name1 = port1->name();
const std::string &name2 = port2->name();
if (name1 == name2) {
PortDirection *dir1 = port1->direction();
PortDirection *dir2 = port2->direction();
return dir1->index() < dir2->index();
}
return name1 < name2;
}
void

View File

@ -34,26 +34,26 @@ namespace sta {
constexpr char verilog_escape = '\\';
static std::string
staToVerilog(std::string sta_name);
staToVerilog(std::string_view sta_name);
static std::string
staToVerilog2(std::string sta_name);
staToVerilog2(std::string_view sta_name);
static std::string
verilogToSta(const std::string verilog_name);
verilogToSta(const std::string_view verilog_name);
std::string
cellVerilogName(std::string sta_name)
cellVerilogName(std::string_view sta_name)
{
return staToVerilog(sta_name);
}
std::string
instanceVerilogName(std::string sta_name)
instanceVerilogName(std::string_view sta_name)
{
return staToVerilog(sta_name);
}
std::string
netVerilogName(std::string sta_name)
netVerilogName(std::string_view sta_name)
{
bool is_bus;
std::string bus_name;
@ -69,13 +69,20 @@ netVerilogName(std::string sta_name)
}
std::string
portVerilogName(std::string sta_name)
portVerilogName(std::string_view sta_name)
{
return staToVerilog2(sta_name);
}
// <cctype> functions expect a value representable as unsigned char or EOF.
static bool
isAlnumUnderscore(char ch)
{
return std::isalnum(static_cast<unsigned char>(ch)) != 0 || ch == '_';
}
static std::string
staToVerilog(std::string sta_name)
staToVerilog(std::string_view sta_name)
{
// Leave room for leading escape and trailing space if the name
// needs to be escaped.
@ -87,14 +94,18 @@ staToVerilog(std::string sta_name)
char ch = sta_name[i];
if (ch == verilog_escape) {
escaped = true;
char next_ch = sta_name[i + 1];
if (next_ch == verilog_escape) {
escaped_name += next_ch;
i++;
if (i + 1 < sta_length) {
char next_ch = sta_name[i + 1];
if (next_ch == verilog_escape) {
escaped_name += next_ch;
i++;
}
}
else
escaped_name += ch;
}
else {
if ((!(isalnum(ch) || ch == '_')))
if (!isAlnumUnderscore(ch))
escaped = true;
escaped_name += ch;
}
@ -105,11 +116,11 @@ staToVerilog(std::string sta_name)
return escaped_name;
}
else
return sta_name;
return std::string(sta_name);
}
static std::string
staToVerilog2(std::string sta_name)
staToVerilog2(std::string_view sta_name)
{
constexpr char bus_brkt_left = '[';
constexpr char bus_brkt_right = ']';
@ -123,16 +134,19 @@ staToVerilog2(std::string sta_name)
char ch = sta_name[i];
if (ch == verilog_escape) {
escaped = true;
char next_ch = sta_name[i + 1];
if (next_ch == verilog_escape) {
escaped_name += next_ch;
i++;
if (i + 1 < sta_length) {
char next_ch = sta_name[i + 1];
if (next_ch == verilog_escape) {
escaped_name += next_ch;
i++;
}
}
else
escaped_name += ch;
}
else {
bool is_brkt = (ch == bus_brkt_left || ch == bus_brkt_right);
if ((!(isalnum(ch) || ch == '_') && !is_brkt)
|| is_brkt)
if ((!isAlnumUnderscore(ch) && !is_brkt) || is_brkt)
escaped = true;
escaped_name += ch;
}
@ -143,45 +157,49 @@ staToVerilog2(std::string sta_name)
return escaped_name;
}
else
return sta_name;
return std::string(sta_name);
}
////////////////////////////////////////////////////////////////
std::string
moduleVerilogToSta(std::string module_name)
moduleVerilogToSta(std::string_view module_name)
{
return verilogToSta(module_name);
}
std::string
instanceVerilogToSta(std::string inst_name)
instanceVerilogToSta(std::string_view inst_name)
{
return verilogToSta(inst_name);
}
std::string
netVerilogToSta(std::string net_name)
netVerilogToSta(std::string_view net_name)
{
return verilogToSta(net_name);
}
std::string
portVerilogToSta(std::string port_name)
portVerilogToSta(std::string_view port_name)
{
return verilogToSta(port_name);
}
static std::string
verilogToSta(std::string verilog_name)
verilogToSta(std::string_view verilog_name)
{
if (verilog_name.empty())
return std::string(verilog_name);
if (verilog_name.front() == '\\') {
constexpr char divider = '/';
constexpr char bus_brkt_left = '[';
constexpr char bus_brkt_right = ']';
size_t verilog_name_length = verilog_name.size();
if (isspace(verilog_name.back()))
if (verilog_name_length > 1
&& std::isspace(static_cast<unsigned char>(verilog_name.back())) != 0)
verilog_name_length--;
std::string sta_name;
// Ignore leading '\'.
@ -198,7 +216,7 @@ verilogToSta(std::string verilog_name)
return sta_name;
}
else
return verilog_name;
return std::string(verilog_name);
}
} // namespace

View File

@ -24,11 +24,17 @@
#include "FilterObjects.hh"
#include <regex>
#include <stack>
#include <functional>
#include <memory>
#include <regex>
#include <stack>
#include <cstddef>
#include <string>
#include <string_view>
#include "NetworkClass.hh"
#include "Network.hh"
#include "StringUtil.hh"
#include "Property.hh"
#include "PatternMatch.hh"
#include "Sta.hh"
@ -52,22 +58,27 @@ public:
undefined
};
Token(std::string text,
Token(std::string_view text,
Kind kind);
std::string text;
Kind kind;
const std::string &text() const { return text_; }
Kind kind() const { return kind_; }
std::string text_;
Kind kind_;
};
struct PredicateToken : public Token
{
PredicateToken(std::string property,
std::string op,
std::string arg);
PredicateToken(std::string_view property,
std::string_view op,
std::string_view arg);
const std::string &property() const { return property_; }
const std::string &op() const { return op_; }
const std::string &arg() const { return arg_; }
std::string property;
std::string op;
std::string arg;
std::string property_;
std::string op_;
std::string arg_;
};
FilterExpr(std::string_view expression,
@ -82,19 +93,21 @@ private:
Report *report_;
};
FilterExpr::Token::Token(std::string text,
FilterExpr::Token::Token(std::string_view text,
Token::Kind kind) :
text (text),
kind(kind)
text_(text),
kind_(kind)
{
}
FilterExpr::PredicateToken::PredicateToken(std::string property,
std::string op,
std::string arg) :
Token(property + " " + op + " " + arg,
FilterExpr::PredicateToken::PredicateToken(std::string_view property,
std::string_view op,
std::string_view arg) :
Token(sta::format("{} {} {}", property, op, arg),
Token::Kind::predicate),
property(property), op(op), arg(arg)
property_(property),
op_(op),
arg_(arg)
{
}
@ -140,7 +153,7 @@ FilterExpr::lex()
std::string property = token_match[1].str();
// The default operation on a predicate if an op and arg are
// omitted is 'prop == 1 || true'.
// omitted is 'prop == 1'.
std::string op = "==";
std::string arg = "1";
@ -175,7 +188,7 @@ FilterExpr::shuntingYard(std::vector<std::unique_ptr<Token>> &infix)
std::stack<std::unique_ptr<Token>> operator_stack;
for (auto &token : infix) {
switch (token->kind) {
switch (token->kind()) {
case Token::Kind::predicate:
output.push_back(std::move(token));
break;
@ -185,7 +198,7 @@ FilterExpr::shuntingYard(std::vector<std::unique_ptr<Token>> &infix)
// The operators' enum values are ascending by precedence:
// inv > and > or
while (operator_stack.size()
&& operator_stack.top()->kind > token->kind) {
&& operator_stack.top()->kind() > token->kind()) {
output.push_back(std::move(operator_stack.top()));
operator_stack.pop();
}
@ -208,7 +221,7 @@ FilterExpr::shuntingYard(std::vector<std::unique_ptr<Token>> &infix)
if (operator_stack.empty())
report_->error(2601, "-filter extraneous ).");
while (operator_stack.size()
&& operator_stack.top()->kind != Token::Kind::op_lparen) {
&& operator_stack.top()->kind() != Token::Kind::op_lparen) {
output.push_back(std::move(operator_stack.top()));
operator_stack.pop();
if (operator_stack.empty())
@ -224,7 +237,7 @@ FilterExpr::shuntingYard(std::vector<std::unique_ptr<Token>> &infix)
}
while (operator_stack.size()) {
if (operator_stack.top()->kind == Token::Kind::op_lparen)
if (operator_stack.top()->kind() == Token::Kind::op_lparen)
report_->error(2603, "-filter unmatched (.");
output.push_back(std::move(operator_stack.top()));
operator_stack.pop();
@ -235,20 +248,20 @@ FilterExpr::shuntingYard(std::vector<std::unique_ptr<Token>> &infix)
////////////////////////////////////////////////////////////////
template <typename T> std::set<T*>
filterObjects(const char *property,
const char *op,
const char *pattern,
template <typename T> static std::set<T*>
filterObjects(std::string_view property,
std::string_view op,
std::string_view pattern,
std::set<T*> &all,
Sta *sta)
{
Properties &properties = sta->properties();
Network *network = sta->network();
auto filtered_objects = std::set<T*>();
bool exact_match = stringEq(op, "==");
bool pattern_match = stringEq(op, "=~");
bool not_match = stringEq(op, "!=");
bool not_pattern_match = stringEq(op, "!~");
bool exact_match = (op == "==");
bool pattern_match = (op == "=~");
bool not_match = (op == "!=");
bool not_pattern_match = (op == "!~");
for (T *object : all) {
PropertyValue value = properties.getProperty(object, property);
std::string prop = value.to_string(network);
@ -259,8 +272,8 @@ filterObjects(const char *property,
else if (stringEqual(pattern, "false"))
pattern = "0";
}
if ((exact_match && stringEq(prop.c_str(), pattern))
|| (not_match && !stringEq(prop.c_str(), pattern))
if ((exact_match && prop == pattern)
|| (not_match && prop != pattern)
|| (pattern_match && patternMatch(pattern, prop))
|| (not_pattern_match && !patternMatch(pattern, prop)))
filtered_objects.insert(object);
@ -268,9 +281,9 @@ filterObjects(const char *property,
return filtered_objects;
}
template <typename T> std::vector<T*>
template <typename T> static std::vector<T*>
filterObjects(std::string_view filter_expression,
std::vector<T*> *objects,
const std::vector<T*> *objects,
Sta *sta)
{
Report *report = sta->report();
@ -286,7 +299,7 @@ filterObjects(std::string_view filter_expression,
auto postfix = filter.postfix();
std::stack<std::set<T*>> eval_stack;
for (auto &token : postfix) {
if (token->kind == FilterExpr::Token::Kind::op_or) {
if (token->kind() == FilterExpr::Token::Kind::op_or) {
if (eval_stack.size() < 2)
report->error(2604, "-filter logical OR requires at least two operands.");
auto arg0 = eval_stack.top();
@ -298,7 +311,7 @@ filterObjects(std::string_view filter_expression,
std::inserter(union_result, union_result.begin()));
eval_stack.push(union_result);
}
else if (token->kind == FilterExpr::Token::Kind::op_and) {
else if (token->kind() == FilterExpr::Token::Kind::op_and) {
if (eval_stack.size() < 2) {
report->error(2605, "-filter logical AND requires two operands.");
}
@ -313,7 +326,7 @@ filterObjects(std::string_view filter_expression,
intersection_result.begin()));
eval_stack.push(intersection_result);
}
else if (token->kind == FilterExpr::Token::Kind::op_inv) {
else if (token->kind() == FilterExpr::Token::Kind::op_inv) {
if (eval_stack.size() < 1) {
report->error(2606, "-filter NOT missing operand.");
}
@ -327,13 +340,13 @@ filterObjects(std::string_view filter_expression,
difference_result.begin()));
eval_stack.push(difference_result);
}
else if (token->kind == FilterExpr::Token::Kind::defined
|| token->kind == FilterExpr::Token::Kind::undefined) {
else if (token->kind() == FilterExpr::Token::Kind::defined
|| token->kind() == FilterExpr::Token::Kind::undefined) {
bool should_be_defined =
(token->kind == FilterExpr::Token::Kind::defined);
(token->kind() == FilterExpr::Token::Kind::defined);
auto result = std::set<T*>();
for (auto object : all) {
PropertyValue value = properties.getProperty(object, token->text);
PropertyValue value = properties.getProperty(object, token->text());
bool is_defined = false;
switch (value.type()) {
case PropertyValue::Type::float_:
@ -377,12 +390,12 @@ filterObjects(std::string_view filter_expression,
}
eval_stack.push(result);
}
else if (token->kind == FilterExpr::Token::Kind::predicate) {
else if (token->kind() == FilterExpr::Token::Kind::predicate) {
auto *predicate_token =
static_cast<FilterExpr::PredicateToken *>(token.get());
auto result = filterObjects<T>(predicate_token->property.c_str(),
predicate_token->op.c_str(),
predicate_token->arg.c_str(),
auto result = filterObjects<T>(predicate_token->property(),
predicate_token->op(),
predicate_token->arg(),
all, sta);
eval_stack.push(result);
}
@ -495,7 +508,7 @@ filterExprToPostfix(std::string_view expr,
auto postfix = filter.postfix();
StringSeq result;
for (auto &token : postfix)
result.push_back(token->text);
result.push_back(token->text());
return result;
}