mirror of
https://github.com/YosysHQ/yosys
synced 2025-06-23 22:33:41 +00:00
Merge pull request #5101 from georgerennie/george/opt_expr_shift_ovfl
opt_expr: fix shift optimization with overflowing shift amount
This commit is contained in:
commit
6331f92d00
4 changed files with 168 additions and 2 deletions
|
@ -380,6 +380,33 @@ int RTLIL::Const::as_int(bool is_signed) const
|
|||
return ret;
|
||||
}
|
||||
|
||||
bool RTLIL::Const::convertible_to_int(bool is_signed) const
|
||||
{
|
||||
auto size = get_min_size(is_signed);
|
||||
return (size > 0 && size <= 32);
|
||||
}
|
||||
|
||||
std::optional<int> RTLIL::Const::try_as_int(bool is_signed) const
|
||||
{
|
||||
if (!convertible_to_int(is_signed))
|
||||
return std::nullopt;
|
||||
return as_int(is_signed);
|
||||
}
|
||||
|
||||
int RTLIL::Const::as_int_saturating(bool is_signed) const
|
||||
{
|
||||
if (!convertible_to_int(is_signed)) {
|
||||
if (!is_signed)
|
||||
return std::numeric_limits<int>::max();
|
||||
|
||||
const auto min_size = get_min_size(is_signed);
|
||||
log_assert(min_size > 0);
|
||||
const auto neg = get_bits().at(min_size - 1);
|
||||
return neg ? std::numeric_limits<int>::min() : std::numeric_limits<int>::max();
|
||||
}
|
||||
return as_int(is_signed);
|
||||
}
|
||||
|
||||
int RTLIL::Const::get_min_size(bool is_signed) const
|
||||
{
|
||||
if (empty()) return 0;
|
||||
|
@ -5462,6 +5489,38 @@ int RTLIL::SigSpec::as_int(bool is_signed) const
|
|||
return 0;
|
||||
}
|
||||
|
||||
bool RTLIL::SigSpec::convertible_to_int(bool is_signed) const
|
||||
{
|
||||
cover("kernel.rtlil.sigspec.convertible_to_int");
|
||||
|
||||
pack();
|
||||
if (!is_fully_const())
|
||||
return false;
|
||||
|
||||
return RTLIL::Const(chunks_[0].data).convertible_to_int(is_signed);
|
||||
}
|
||||
|
||||
std::optional<int> RTLIL::SigSpec::try_as_int(bool is_signed) const
|
||||
{
|
||||
cover("kernel.rtlil.sigspec.try_as_int");
|
||||
|
||||
pack();
|
||||
if (!is_fully_const())
|
||||
return std::nullopt;
|
||||
|
||||
return RTLIL::Const(chunks_[0].data).try_as_int(is_signed);
|
||||
}
|
||||
|
||||
int RTLIL::SigSpec::as_int_saturating(bool is_signed) const
|
||||
{
|
||||
cover("kernel.rtlil.sigspec.try_as_int");
|
||||
|
||||
pack();
|
||||
log_assert(is_fully_const() && GetSize(chunks_) <= 1);
|
||||
log_assert(!empty());
|
||||
return RTLIL::Const(chunks_[0].data).as_int_saturating(is_signed);
|
||||
}
|
||||
|
||||
std::string RTLIL::SigSpec::as_string() const
|
||||
{
|
||||
cover("kernel.rtlil.sigspec.as_string");
|
||||
|
|
|
@ -753,7 +753,26 @@ public:
|
|||
|
||||
std::vector<RTLIL::State>& bits();
|
||||
bool as_bool() const;
|
||||
|
||||
// Convert the constant value to a C++ int.
|
||||
// NOTE: If the constant is too wide to fit in int (32 bits) this will
|
||||
// truncate any higher bits, potentially over/underflowing. Consider using
|
||||
// try_as_int, as_int_saturating, or guarding behind convertible_to_int
|
||||
// instead.
|
||||
int as_int(bool is_signed = false) const;
|
||||
|
||||
// Returns true iff the constant can be converted to an int without
|
||||
// over/underflow.
|
||||
bool convertible_to_int(bool is_signed = false) const;
|
||||
|
||||
// Returns the constant's value as an int if it can be represented without
|
||||
// over/underflow, or std::nullopt otherwise.
|
||||
std::optional<int> try_as_int(bool is_signed = false) const;
|
||||
|
||||
// Returns the constant's value as an int if it can be represented without
|
||||
// over/underflow, otherwise the max/min value for int depending on the sign.
|
||||
int as_int_saturating(bool is_signed = false) const;
|
||||
|
||||
std::string as_string(const char* any = "-") const;
|
||||
static Const from_string(const std::string &str);
|
||||
std::vector<RTLIL::State> to_bits() const;
|
||||
|
@ -1130,7 +1149,27 @@ public:
|
|||
bool is_onehot(int *pos = nullptr) const;
|
||||
|
||||
bool as_bool() const;
|
||||
|
||||
// Convert the SigSpec to a C++ int, assuming all bits are constant.
|
||||
// NOTE: If the value is too wide to fit in int (32 bits) this will
|
||||
// truncate any higher bits, potentially over/underflowing. Consider using
|
||||
// try_as_int, as_int_saturating, or guarding behind convertible_to_int
|
||||
// instead.
|
||||
int as_int(bool is_signed = false) const;
|
||||
|
||||
// Returns true iff the SigSpec is constant and can be converted to an int
|
||||
// without over/underflow.
|
||||
bool convertible_to_int(bool is_signed = false) const;
|
||||
|
||||
// Returns the SigSpec's value as an int if it is a constant and can be
|
||||
// represented without over/underflow, or std::nullopt otherwise.
|
||||
std::optional<int> try_as_int(bool is_signed = false) const;
|
||||
|
||||
// Returns an all constant SigSpec's value as an int if it can be represented
|
||||
// without over/underflow, otherwise the max/min value for int depending on
|
||||
// the sign.
|
||||
int as_int_saturating(bool is_signed = false) const;
|
||||
|
||||
std::string as_string() const;
|
||||
RTLIL::Const as_const() const;
|
||||
RTLIL::Wire *as_wire() const;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue