mirror of
https://github.com/verilator/verilator.git
synced 2025-01-01 04:07:34 +00:00
Internals: Remove use of V3Width code from V3AstNodes (#4537). No functional change intended.
`getCommonClassTypep` and its helper code has been moved to AstNode class. This is a lot better place for this functionality. Moreover, it allowed to get rid of the dependency on V3Width from generic AST-related code.
This commit is contained in:
parent
5b06c60318
commit
a5ee8b39ef
@ -1461,6 +1461,102 @@ AstNodeDType* AstNode::findStreamDType() const {
|
||||
return v3Global.rootp()->typeTablep()->findStreamDType(fileline());
|
||||
}
|
||||
|
||||
static const AstNodeDType* computeCastableBase(const AstNodeDType* nodep) {
|
||||
while (true) {
|
||||
if (const AstPackArrayDType* const packp = VN_CAST(nodep, PackArrayDType)) {
|
||||
nodep = packp->subDTypep();
|
||||
continue;
|
||||
} else if (const AstNodeDType* const refp = nodep->skipRefToEnump()) {
|
||||
if (refp != nodep) {
|
||||
nodep = refp;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return nodep;
|
||||
}
|
||||
}
|
||||
|
||||
static VCastable computeCastableImp(const AstNodeDType* toDtp, const AstNodeDType* fromDtp,
|
||||
const AstNode* fromConstp) {
|
||||
const VCastable castable = VCastable::UNSUPPORTED;
|
||||
toDtp = toDtp->skipRefToEnump();
|
||||
fromDtp = fromDtp->skipRefToEnump();
|
||||
if (toDtp == fromDtp) return VCastable::SAMEISH;
|
||||
if (toDtp->similarDType(fromDtp)) return VCastable::SAMEISH;
|
||||
// UNSUP unpacked struct/unions (treated like BasicDType)
|
||||
const AstNodeDType* fromBaseDtp = computeCastableBase(fromDtp);
|
||||
|
||||
const bool fromNumericable = VN_IS(fromBaseDtp, BasicDType) || VN_IS(fromBaseDtp, EnumDType)
|
||||
|| VN_IS(fromBaseDtp, StreamDType)
|
||||
|| VN_IS(fromBaseDtp, NodeUOrStructDType);
|
||||
|
||||
const AstNodeDType* toBaseDtp = computeCastableBase(toDtp);
|
||||
const bool toNumericable
|
||||
= VN_IS(toBaseDtp, BasicDType) || VN_IS(toBaseDtp, NodeUOrStructDType);
|
||||
|
||||
if (toBaseDtp == fromBaseDtp) {
|
||||
return VCastable::COMPATIBLE;
|
||||
} else if (toNumericable) {
|
||||
if (fromNumericable) return VCastable::COMPATIBLE;
|
||||
} else if (VN_IS(toDtp, EnumDType)) {
|
||||
if (VN_IS(fromBaseDtp, EnumDType) && toDtp->sameTree(fromDtp))
|
||||
return VCastable::ENUM_IMPLICIT;
|
||||
if (fromNumericable) return VCastable::ENUM_EXPLICIT;
|
||||
} else if (VN_IS(toDtp, ClassRefDType) && VN_IS(fromConstp, Const)) {
|
||||
if (VN_IS(fromConstp, Const) && VN_AS(fromConstp, Const)->num().isNull())
|
||||
return VCastable::COMPATIBLE;
|
||||
} else if (VN_IS(toDtp, ClassRefDType) && VN_IS(fromDtp, ClassRefDType)) {
|
||||
const auto toClassp = VN_AS(toDtp, ClassRefDType)->classp();
|
||||
const auto fromClassp = VN_AS(fromDtp, ClassRefDType)->classp();
|
||||
const bool downcast = AstClass::isClassExtendedFrom(toClassp, fromClassp);
|
||||
const bool upcast = AstClass::isClassExtendedFrom(fromClassp, toClassp);
|
||||
if (upcast) {
|
||||
return VCastable::COMPATIBLE;
|
||||
} else if (downcast) {
|
||||
return VCastable::DYNAMIC_CLASS;
|
||||
} else {
|
||||
return VCastable::INCOMPATIBLE;
|
||||
}
|
||||
}
|
||||
return castable;
|
||||
}
|
||||
|
||||
VCastable AstNode::computeCastable(const AstNodeDType* toDtp, const AstNodeDType* fromDtp,
|
||||
const AstNode* fromConstp) {
|
||||
const auto castable = computeCastableImp(toDtp, fromDtp, fromConstp);
|
||||
UINFO(9, " castable=" << castable << " for " << toDtp << endl);
|
||||
UINFO(9, " =?= " << fromDtp << endl);
|
||||
UINFO(9, " const= " << fromConstp << endl);
|
||||
return castable;
|
||||
}
|
||||
|
||||
AstNodeDType* AstNode::getCommonClassTypep(AstNode* nodep1, AstNode* nodep2) {
|
||||
// Return the class type that both nodep1 and nodep2 are castable to.
|
||||
// If both are null, return the type of null constant.
|
||||
// If one is a class and one is null, return AstClassRefDType that points to that class.
|
||||
// If no common class type exists, return nullptr.
|
||||
|
||||
// First handle cases with null values and when one class is a super class of the other.
|
||||
if (VN_IS(nodep1, Const)) std::swap(nodep1, nodep2);
|
||||
{
|
||||
const VCastable castable = computeCastable(nodep1->dtypep(), nodep2->dtypep(), nodep2);
|
||||
if (castable == VCastable::SAMEISH || castable == VCastable::COMPATIBLE) {
|
||||
return nodep1->dtypep();
|
||||
} else if (castable == VCastable::DYNAMIC_CLASS) {
|
||||
return nodep2->dtypep();
|
||||
}
|
||||
}
|
||||
|
||||
AstClassRefDType* classDtypep1 = VN_CAST(nodep1->dtypep(), ClassRefDType);
|
||||
while (classDtypep1) {
|
||||
const VCastable castable = computeCastable(classDtypep1, nodep2->dtypep(), nodep2);
|
||||
if (castable == VCastable::COMPATIBLE) return classDtypep1;
|
||||
AstClassExtends* const extendsp = classDtypep1->classp()->extendsp();
|
||||
classDtypep1 = extendsp ? VN_AS(extendsp->dtypep(), ClassRefDType) : nullptr;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//######################################################################
|
||||
// VNDeleter
|
||||
|
||||
|
43
src/V3Ast.h
43
src/V3Ast.h
@ -1249,6 +1249,45 @@ inline std::ostream& operator<<(std::ostream& os, const VUseType& rhs) {
|
||||
|
||||
// ######################################################################
|
||||
|
||||
class VCastable final {
|
||||
public:
|
||||
enum en : uint8_t {
|
||||
UNSUPPORTED,
|
||||
SAMEISH,
|
||||
COMPATIBLE,
|
||||
ENUM_EXPLICIT,
|
||||
ENUM_IMPLICIT,
|
||||
DYNAMIC_CLASS,
|
||||
INCOMPATIBLE,
|
||||
_ENUM_MAX // Leave last
|
||||
};
|
||||
enum en m_e;
|
||||
const char* ascii() const {
|
||||
static const char* const names[]
|
||||
= {"UNSUPPORTED", "SAMEISH", "COMPATIBLE", "ENUM_EXPLICIT",
|
||||
"ENUM_IMPLICIT", "DYNAMIC_CLASS", "INCOMPATIBLE"};
|
||||
return names[m_e];
|
||||
}
|
||||
VCastable()
|
||||
: m_e{UNSUPPORTED} {}
|
||||
// cppcheck-suppress noExplicitConstructor
|
||||
constexpr VCastable(en _e)
|
||||
: m_e{_e} {}
|
||||
explicit VCastable(int _e)
|
||||
: m_e(static_cast<en>(_e)) {} // Need () or GCC 4.8 false warning
|
||||
constexpr operator en() const { return m_e; }
|
||||
};
|
||||
constexpr bool operator==(const VCastable& lhs, const VCastable& rhs) {
|
||||
return lhs.m_e == rhs.m_e;
|
||||
}
|
||||
constexpr bool operator==(const VCastable& lhs, VCastable::en rhs) { return lhs.m_e == rhs; }
|
||||
constexpr bool operator==(VCastable::en lhs, const VCastable& rhs) { return lhs == rhs.m_e; }
|
||||
inline std::ostream& operator<<(std::ostream& os, const VCastable& rhs) {
|
||||
return os << rhs.ascii();
|
||||
}
|
||||
|
||||
// ######################################################################
|
||||
|
||||
class VBasicTypeKey final {
|
||||
public:
|
||||
const int m_width; // From AstNodeDType: Bit width of operation
|
||||
@ -1989,6 +2028,10 @@ public:
|
||||
AstNodeDType* findBasicDType(VBasicDTypeKwd kwd) const;
|
||||
static AstBasicDType* findInsertSameDType(AstBasicDType* nodep);
|
||||
|
||||
static VCastable computeCastable(const AstNodeDType* toDtp, const AstNodeDType* fromDtp,
|
||||
const AstNode* fromConstp);
|
||||
static AstNodeDType* getCommonClassTypep(AstNode* nodep1, AstNode* nodep2);
|
||||
|
||||
// METHODS - dump and error
|
||||
void v3errorEnd(std::ostringstream& str) const VL_RELEASE(V3Error::s().m_mutex);
|
||||
void v3errorEndFatal(std::ostringstream& str) const VL_ATTR_NORETURN
|
||||
|
@ -25,7 +25,6 @@
|
||||
#include "V3Hasher.h"
|
||||
#include "V3PartitionGraph.h" // Just for mtask dumping
|
||||
#include "V3String.h"
|
||||
#include "V3Width.h"
|
||||
|
||||
#include "V3Ast__gen_macros.h" // Generated by 'astgen'
|
||||
|
||||
@ -217,7 +216,7 @@ AstNodeCond::AstNodeCond(VNType t, FileLine* fl, AstNodeExpr* condp, AstNodeExpr
|
||||
UASSERT_OBJ(elsep, this, "No elsep expression");
|
||||
if (thenp->isClassHandleValue() && elsep->isClassHandleValue()) {
|
||||
// Get the most-deriving class type that both arguments can be casted to.
|
||||
AstNodeDType* const commonClassTypep = V3Width::getCommonClassTypep(thenp, elsep);
|
||||
AstNodeDType* const commonClassTypep = getCommonClassTypep(thenp, elsep);
|
||||
UASSERT_OBJ(commonClassTypep, this, "No common base class exists");
|
||||
dtypep(commonClassTypep);
|
||||
} else {
|
||||
|
154
src/V3Width.cpp
154
src/V3Width.cpp
@ -108,21 +108,6 @@ std::ostream& operator<<(std::ostream& str, const Determ& rhs) {
|
||||
return str << s_det[rhs];
|
||||
}
|
||||
|
||||
enum Castable : uint8_t {
|
||||
UNSUPPORTED,
|
||||
SAMEISH,
|
||||
COMPATIBLE,
|
||||
ENUM_EXPLICIT,
|
||||
ENUM_IMPLICIT,
|
||||
DYNAMIC_CLASS,
|
||||
INCOMPATIBLE
|
||||
};
|
||||
std::ostream& operator<<(std::ostream& str, const Castable& rhs) {
|
||||
static const char* const s_det[]
|
||||
= {"UNSUP", "IDENT", "COMPAT", "ENUM_EXP", "ENUM_IMP", "DYN_CLS", "INCOMPAT"};
|
||||
return str << s_det[rhs];
|
||||
}
|
||||
|
||||
#define v3widthWarn(lhs, rhs, msg) \
|
||||
v3errorEnd( \
|
||||
v3errorBuildMessage(V3Error::v3errorPrep((lhs) < (rhs) ? V3ErrorCode::WIDTHTRUNC \
|
||||
@ -518,7 +503,7 @@ private:
|
||||
if (nodep->thenp()->isClassHandleValue() && nodep->elsep()->isClassHandleValue()) {
|
||||
// Get the most-deriving class type that both arguments can be casted to.
|
||||
commonClassTypep
|
||||
= V3Width::getCommonClassTypep(nodep->thenp(), nodep->elsep());
|
||||
= AstNode::getCommonClassTypep(nodep->thenp(), nodep->elsep());
|
||||
}
|
||||
if (commonClassTypep) {
|
||||
nodep->dtypep(commonClassTypep);
|
||||
@ -1842,12 +1827,12 @@ private:
|
||||
AstNodeDType* const toDtp = nodep->top()->dtypep()->skipRefToEnump();
|
||||
AstNodeDType* const fromDtp = nodep->fromp()->dtypep()->skipRefToEnump();
|
||||
FileLine* const fl = nodep->fileline();
|
||||
const auto castable = computeCastable(toDtp, fromDtp, nodep->fromp());
|
||||
const auto castable = AstNode::computeCastable(toDtp, fromDtp, nodep->fromp());
|
||||
AstNode* newp;
|
||||
if (castable == DYNAMIC_CLASS) {
|
||||
if (castable == VCastable::DYNAMIC_CLASS) {
|
||||
// Keep in place, will compute at runtime
|
||||
return;
|
||||
} else if (castable == ENUM_EXPLICIT || castable == ENUM_IMPLICIT) {
|
||||
} else if (castable == VCastable::ENUM_EXPLICIT || castable == VCastable::ENUM_IMPLICIT) {
|
||||
// TODO is from is a constant we could simplify, though normal constant
|
||||
// elimination should do much the same
|
||||
// Form: "( ((v > size) ? false : enum_valid[v[N:0]])
|
||||
@ -1885,7 +1870,7 @@ private:
|
||||
nodep->fromp()->unlinkFrBack()},
|
||||
new AstConst{fl, AstConst::Signed32{}, 1}},
|
||||
new AstConst{fl, AstConst::Signed32{}, 0}};
|
||||
} else if (castable == SAMEISH || castable == COMPATIBLE) {
|
||||
} else if (castable == VCastable::SAMEISH || castable == VCastable::COMPATIBLE) {
|
||||
nodep->v3warn(CASTCONST, "$cast will always return one as "
|
||||
<< toDtp->prettyDTypeNameQ()
|
||||
<< " is always castable from "
|
||||
@ -1896,7 +1881,7 @@ private:
|
||||
new AstAssign{fl, nodep->top()->unlinkFrBack(),
|
||||
new AstCast{fl, nodep->fromp()->unlinkFrBack(), toDtp}},
|
||||
new AstConst{fl, AstConst::Signed32{}, 1}};
|
||||
} else if (castable == INCOMPATIBLE) {
|
||||
} else if (castable == VCastable::INCOMPATIBLE) {
|
||||
newp = new AstConst{fl, 0};
|
||||
nodep->v3warn(CASTCONST, "$cast will always return zero as "
|
||||
<< toDtp->prettyDTypeNameQ() << " is not castable from "
|
||||
@ -1941,23 +1926,24 @@ private:
|
||||
userIterateAndNext(nodep->fromp(), WidthVP{SELF, PRELIM}.p());
|
||||
AstNodeDType* const toDtp = nodep->dtypep()->skipRefToEnump();
|
||||
AstNodeDType* const fromDtp = nodep->fromp()->dtypep()->skipRefToEnump();
|
||||
const auto castable = computeCastable(toDtp, fromDtp, nodep->fromp());
|
||||
const auto castable = AstNode::computeCastable(toDtp, fromDtp, nodep->fromp());
|
||||
bool bad = false;
|
||||
if (castable == UNSUPPORTED) {
|
||||
if (castable == VCastable::UNSUPPORTED) {
|
||||
nodep->v3warn(E_UNSUPPORTED, "Unsupported: static cast to "
|
||||
<< toDtp->prettyDTypeNameQ() << " from "
|
||||
<< fromDtp->prettyDTypeNameQ());
|
||||
bad = true;
|
||||
} else if (castable == SAMEISH || castable == COMPATIBLE || castable == ENUM_IMPLICIT
|
||||
|| castable == ENUM_EXPLICIT) {
|
||||
} else if (castable == VCastable::SAMEISH || castable == VCastable::COMPATIBLE
|
||||
|| castable == VCastable::ENUM_IMPLICIT
|
||||
|| castable == VCastable::ENUM_EXPLICIT) {
|
||||
; // Continue
|
||||
} else if (castable == DYNAMIC_CLASS) {
|
||||
} else if (castable == VCastable::DYNAMIC_CLASS) {
|
||||
nodep->v3error("Dynamic, not static cast, required to cast "
|
||||
<< toDtp->prettyDTypeNameQ() << " from "
|
||||
<< fromDtp->prettyDTypeNameQ() << '\n'
|
||||
<< nodep->warnMore() << "... Suggest dynamic $cast");
|
||||
bad = true;
|
||||
} else if (castable == INCOMPATIBLE) {
|
||||
} else if (castable == VCastable::INCOMPATIBLE) {
|
||||
nodep->v3error("Incompatible types to static cast to "
|
||||
<< toDtp->prettyDTypeNameQ() << " from "
|
||||
<< fromDtp->prettyDTypeNameQ() << '\n');
|
||||
@ -4407,7 +4393,8 @@ private:
|
||||
"Case(type) statement requires items that have type() items");
|
||||
} else {
|
||||
AstNodeDType* const condDtp = VN_AS(condAttrp->fromp(), NodeDType);
|
||||
if (computeCastable(exprDtp, condDtp, nodep) == SAMEISH) {
|
||||
if (AstNode::computeCastable(exprDtp, condDtp, nodep)
|
||||
== VCastable::SAMEISH) {
|
||||
hit = true;
|
||||
break;
|
||||
}
|
||||
@ -6004,7 +5991,8 @@ private:
|
||||
UINFO(9, "==type lhsDtp " << lhsDtp << endl);
|
||||
UINFO(9, "==type rhsDtp " << lhsDtp << endl);
|
||||
const bool invert = VN_IS(nodep, NeqT);
|
||||
const bool identical = computeCastable(lhsDtp, rhsDtp, nodep) == SAMEISH;
|
||||
const bool identical
|
||||
= AstNode::computeCastable(lhsDtp, rhsDtp, nodep) == VCastable::SAMEISH;
|
||||
UINFO(9, "== " << identical << endl);
|
||||
const bool eq = invert ^ identical;
|
||||
AstNode* const newp = new AstConst{nodep->fileline(), AstConst::BitTrue{}, eq};
|
||||
@ -6641,9 +6629,11 @@ private:
|
||||
if (expBasicp && underBasicp) {
|
||||
if (const AstEnumDType* const expEnump
|
||||
= VN_CAST(expDTypep->skipRefToEnump(), EnumDType)) {
|
||||
const auto castable = computeCastable(expEnump, underp->dtypep(), underp);
|
||||
if (castable != SAMEISH && castable != COMPATIBLE && castable != ENUM_IMPLICIT
|
||||
&& !VN_IS(underp, Cast) && !VN_IS(underp, CastDynamic) && !m_enumItemp
|
||||
const auto castable
|
||||
= AstNode::computeCastable(expEnump, underp->dtypep(), underp);
|
||||
if (castable != VCastable::SAMEISH && castable != VCastable::COMPATIBLE
|
||||
&& castable != VCastable::ENUM_IMPLICIT && !VN_IS(underp, Cast)
|
||||
&& !VN_IS(underp, CastDynamic) && !m_enumItemp
|
||||
&& !nodep->fileline()->warnIsOff(V3ErrorCode::ENUMVALUE) && warnOn) {
|
||||
underp->v3warn(ENUMVALUE,
|
||||
"Implicit conversion to enum "
|
||||
@ -7363,68 +7353,9 @@ private:
|
||||
return false;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// METHODS - casting
|
||||
static Castable computeCastableImp(const AstNodeDType* toDtp, const AstNodeDType* fromDtp,
|
||||
const AstNode* fromConstp) {
|
||||
const Castable castable = UNSUPPORTED;
|
||||
toDtp = toDtp->skipRefToEnump();
|
||||
fromDtp = fromDtp->skipRefToEnump();
|
||||
if (toDtp == fromDtp) return SAMEISH;
|
||||
if (toDtp->similarDType(fromDtp)) return SAMEISH;
|
||||
// UNSUP unpacked struct/unions (treated like BasicDType)
|
||||
const AstNodeDType* fromBaseDtp = computeCastableBase(fromDtp);
|
||||
|
||||
const bool fromNumericable
|
||||
= VN_IS(fromBaseDtp, BasicDType) || VN_IS(fromBaseDtp, EnumDType)
|
||||
|| VN_IS(fromBaseDtp, StreamDType) || VN_IS(fromBaseDtp, NodeUOrStructDType);
|
||||
|
||||
const AstNodeDType* toBaseDtp = computeCastableBase(toDtp);
|
||||
const bool toNumericable
|
||||
= VN_IS(toBaseDtp, BasicDType) || VN_IS(toBaseDtp, NodeUOrStructDType);
|
||||
|
||||
if (toBaseDtp == fromBaseDtp) {
|
||||
return COMPATIBLE;
|
||||
} else if (toNumericable) {
|
||||
if (fromNumericable) return COMPATIBLE;
|
||||
} else if (VN_IS(toDtp, EnumDType)) {
|
||||
if (VN_IS(fromBaseDtp, EnumDType) && toDtp->sameTree(fromDtp)) return ENUM_IMPLICIT;
|
||||
if (fromNumericable) return ENUM_EXPLICIT;
|
||||
} else if (VN_IS(toDtp, ClassRefDType) && VN_IS(fromConstp, Const)) {
|
||||
if (VN_IS(fromConstp, Const) && VN_AS(fromConstp, Const)->num().isNull())
|
||||
return COMPATIBLE;
|
||||
} else if (VN_IS(toDtp, ClassRefDType) && VN_IS(fromDtp, ClassRefDType)) {
|
||||
const auto toClassp = VN_AS(toDtp, ClassRefDType)->classp();
|
||||
const auto fromClassp = VN_AS(fromDtp, ClassRefDType)->classp();
|
||||
const bool downcast = AstClass::isClassExtendedFrom(toClassp, fromClassp);
|
||||
const bool upcast = AstClass::isClassExtendedFrom(fromClassp, toClassp);
|
||||
if (upcast) {
|
||||
return COMPATIBLE;
|
||||
} else if (downcast) {
|
||||
return DYNAMIC_CLASS;
|
||||
} else {
|
||||
return INCOMPATIBLE;
|
||||
}
|
||||
}
|
||||
return castable;
|
||||
}
|
||||
static const AstNodeDType* computeCastableBase(const AstNodeDType* nodep) {
|
||||
while (true) {
|
||||
if (const AstPackArrayDType* const packp = VN_CAST(nodep, PackArrayDType)) {
|
||||
nodep = packp->subDTypep();
|
||||
continue;
|
||||
} else if (const AstNodeDType* const refp = nodep->skipRefToEnump()) {
|
||||
if (refp != nodep) {
|
||||
nodep = refp;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return nodep;
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// METHODS - special type detection
|
||||
|
||||
void assertAtStatement(AstNode* nodep) {
|
||||
if (VL_UNCOVERABLE(m_vup && !m_vup->selfDtm())) {
|
||||
UINFO(1, "-: " << m_vup << endl);
|
||||
@ -7529,15 +7460,6 @@ public:
|
||||
return userIterateSubtreeReturnEdits(nodep, WidthVP{SELF, BOTH}.p());
|
||||
}
|
||||
~WidthVisitor() override = default;
|
||||
|
||||
static Castable computeCastable(const AstNodeDType* toDtp, const AstNodeDType* fromDtp,
|
||||
const AstNode* fromConstp) {
|
||||
const auto castable = computeCastableImp(toDtp, fromDtp, fromConstp);
|
||||
UINFO(9, " castable=" << castable << " for " << toDtp << endl);
|
||||
UINFO(9, " =?= " << fromDtp << endl);
|
||||
UINFO(9, " const= " << fromConstp << endl);
|
||||
return castable;
|
||||
}
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
@ -7555,36 +7477,6 @@ void V3Width::width(AstNetlist* nodep) {
|
||||
} // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("width", 0, dumpTreeLevel() >= 3);
|
||||
}
|
||||
|
||||
AstNodeDType* V3Width::getCommonClassTypep(AstNode* nodep1, AstNode* nodep2) {
|
||||
// Return the class type that both nodep1 and nodep2 are castable to.
|
||||
// If both are null, return the type of null constant.
|
||||
// If one is a class and one is null, return AstClassRefDType that points to that class.
|
||||
// If no common class type exists, return nullptr.
|
||||
|
||||
// First handle cases with null values and when one class is a super class of the other.
|
||||
if (VN_IS(nodep1, Const)) std::swap(nodep1, nodep2);
|
||||
{
|
||||
const Castable castable
|
||||
= WidthVisitor::computeCastable(nodep1->dtypep(), nodep2->dtypep(), nodep2);
|
||||
if (castable == SAMEISH || castable == COMPATIBLE) {
|
||||
return nodep1->dtypep();
|
||||
} else if (castable == DYNAMIC_CLASS) {
|
||||
return nodep2->dtypep();
|
||||
}
|
||||
}
|
||||
|
||||
AstClassRefDType* classDtypep1 = VN_CAST(nodep1->dtypep(), ClassRefDType);
|
||||
while (classDtypep1) {
|
||||
const Castable castable
|
||||
= WidthVisitor::computeCastable(classDtypep1, nodep2->dtypep(), nodep2);
|
||||
if (castable == COMPATIBLE) return classDtypep1;
|
||||
AstClassExtends* const extendsp = classDtypep1->classp()->extendsp();
|
||||
classDtypep1 = extendsp ? VN_AS(extendsp->dtypep(), ClassRefDType) : nullptr;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//! Single node parameter propagation
|
||||
//! Smaller step... Only do a single node for parameter propagation
|
||||
AstNode* V3Width::widthParamsEdit(AstNode* nodep) {
|
||||
|
@ -34,8 +34,6 @@ public:
|
||||
static AstNode* widthParamsEdit(AstNode* nodep) VL_MT_DISABLED;
|
||||
static AstNode* widthGenerateParamsEdit(AstNode* nodep) VL_MT_DISABLED;
|
||||
|
||||
static AstNodeDType* getCommonClassTypep(AstNode* nodep1, AstNode* nodep2) VL_MT_DISABLED;
|
||||
|
||||
// For use only in WidthVisitor
|
||||
// Replace AstSelBit, etc with AstSel/AstArraySel
|
||||
// Returns replacement node if nodep was deleted, or null if none.
|
||||
|
Loading…
Reference in New Issue
Block a user