Internals: Remove AstCondBound and AstNodeCond (#6293) (#6294)

Fixes #6293
This commit is contained in:
Geza Lore 2025-08-15 23:49:06 +01:00 committed by GitHub
parent d273e2cbd0
commit 6f69c990fd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
18 changed files with 70 additions and 114 deletions

View File

@ -406,31 +406,6 @@ private:
return lhsp()->isPure() && rhsp()->isPure() && thsp()->isPure();
}
};
class AstNodeCond VL_NOT_FINAL : public AstNodeTriop {
// @astgen alias op1 := condp
// @astgen alias op2 := thenp
// @astgen alias op3 := elsep
protected:
AstNodeCond(VNType t, FileLine* fl, AstNodeExpr* condp, AstNodeExpr* thenp,
AstNodeExpr* elsep);
public:
ASTGEN_MEMBERS_AstNodeCond;
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs,
const V3Number& ths) override;
string emitVerilog() override { return "%k(%l %f? %r %k: %t)"; }
string emitC() override { return "VL_COND_%nq%lq%rq%tq(%nw, %P, %li, %ri, %ti)"; }
string emitSMT() const override { return "(ite (__Vbool %l) %r %t)"; }
bool cleanOut() const override { return false; } // clean if e1 & e2 clean
bool cleanLhs() const override { return true; }
bool cleanRhs() const override { return false; }
bool cleanThs() const override { return false; } // Propagates up
bool sizeMattersLhs() const override { return false; }
bool sizeMattersRhs() const override { return false; }
bool sizeMattersThs() const override { return false; }
int instrCount() const override { return INSTR_COUNT_BRANCH; }
virtual AstNodeExpr* cloneType(AstNodeExpr* condp, AstNodeExpr* thenp, AstNodeExpr* elsep) = 0;
};
class AstNodeDistTriop VL_NOT_FINAL : public AstNodeTriop {
public:
AstNodeDistTriop(VNType t, FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp,
@ -4681,6 +4656,30 @@ public:
};
// === AstNodeTriop ===
class AstCond final : public AstNodeTriop {
// @astgen alias op1 := condp
// @astgen alias op2 := thenp
// @astgen alias op3 := elsep
public:
AstCond(FileLine* fl, AstNodeExpr* condp, AstNodeExpr* thenp, AstNodeExpr* elsep);
ASTGEN_MEMBERS_AstCond;
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs,
const V3Number& ths) override {
out.opAssign(lhs.isNeqZero() ? rhs : ths);
}
string emitVerilog() override { return "%k(%l %f? %r %k: %t)"; }
string emitC() override { return "VL_COND_%nq%lq%rq%tq(%nw, %P, %li, %ri, %ti)"; }
string emitSMT() const override { return "(ite (__Vbool %l) %r %t)"; }
bool cleanOut() const override { return false; } // clean if e1 & e2 clean
bool cleanLhs() const override { return true; }
bool cleanRhs() const override { return false; }
bool cleanThs() const override { return false; } // Propagates up
bool sizeMattersLhs() const override { return false; }
bool sizeMattersRhs() const override { return false; }
bool sizeMattersThs() const override { return false; }
int instrCount() const override { return INSTR_COUNT_BRANCH; }
};
class AstPostAdd final : public AstNodeTriop {
// Post-increment/add
// Children: lhsp: AstConst (1) as currently support only ++ not +=
@ -4859,28 +4858,6 @@ public:
bool sizeMattersThs() const override { return false; }
};
// === AstNodeCond ===
class AstCond final : public AstNodeCond {
// Conditional ?: expression
public:
AstCond(FileLine* fl, AstNodeExpr* condp, AstNodeExpr* thenp, AstNodeExpr* elsep)
: ASTGEN_SUPER_Cond(fl, condp, thenp, elsep) {}
ASTGEN_MEMBERS_AstCond;
AstNodeExpr* cloneType(AstNodeExpr* condp, AstNodeExpr* thenp, AstNodeExpr* elsep) override {
return new AstCond{fileline(), condp, thenp, elsep};
}
};
class AstCondBound final : public AstNodeCond {
// Conditional ?: expression, specially made for safety checking of array bounds
public:
AstCondBound(FileLine* fl, AstNodeExpr* condp, AstNodeExpr* thenp, AstNodeExpr* elsep)
: ASTGEN_SUPER_CondBound(fl, condp, thenp, elsep) {}
ASTGEN_MEMBERS_AstCondBound;
AstNodeExpr* cloneType(AstNodeExpr* condp, AstNodeExpr* thenp, AstNodeExpr* elsep) override {
return new AstCondBound{fileline(), condp, thenp, elsep};
}
};
// === AstNodeDistTriop ===
class AstDistErlang final : public AstNodeDistTriop {
public:

View File

@ -166,9 +166,8 @@ const char* AstNodeQuadop::broken() const {
return nullptr;
}
AstNodeCond::AstNodeCond(VNType t, FileLine* fl, AstNodeExpr* condp, AstNodeExpr* thenp,
AstNodeExpr* elsep)
: AstNodeTriop{t, fl, condp, thenp, elsep} {
AstCond::AstCond(FileLine* fl, AstNodeExpr* condp, AstNodeExpr* thenp, AstNodeExpr* elsep)
: ASTGEN_SUPER_Cond(fl, condp, thenp, elsep) {
UASSERT_OBJ(thenp, this, "No thenp expression");
UASSERT_OBJ(elsep, this, "No elsep expression");
if (thenp->isClassHandleValue() && elsep->isClassHandleValue()) {
@ -180,14 +179,6 @@ AstNodeCond::AstNodeCond(VNType t, FileLine* fl, AstNodeExpr* condp, AstNodeExpr
dtypeFrom(thenp);
}
}
void AstNodeCond::numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs,
const V3Number& ths) {
if (lhs.isNeqZero()) {
out.opAssign(rhs);
} else {
out.opAssign(ths);
}
}
void AstAddrOfCFunc::dump(std::ostream& str) const {
this->AstNodeExpr::dump(str);

View File

@ -115,7 +115,7 @@ class CastVisitor final : public VNVisitor {
if (nodep->sizeMattersLhs()) ensureCast(nodep->lhsp());
if (nodep->sizeMattersRhs()) ensureCast(nodep->rhsp());
}
void visit(AstNodeCond* nodep) override {
void visit(AstCond* nodep) override {
// All class types are castable to each other. If they are of different types,
// a compilation error will be thrown, so an explicit cast is required. Types were
// already checked by V3Width and dtypep of a condition operator is a type of their

View File

@ -261,7 +261,7 @@ class CleanVisitor final : public VNVisitor {
}
// Control flow operators
void visit(AstNodeCond* nodep) override {
void visit(AstCond* nodep) override {
iterateChildren(nodep);
ensureClean(nodep->condp());
setClean(nodep, isClean(nodep->thenp()) && isClean(nodep->elsep()));

View File

@ -1099,17 +1099,17 @@ class ConstVisitor final : public VNVisitor {
// (otherwise we'd be trading one operation for two operations)
// V3Clean often makes this pattern, as it postpones the AND until
// as high as possible, which is usually the right choice, except for this.
AstNodeCond* const condp = VN_CAST(nodep->rhsp(), NodeCond);
AstCond* const condp = VN_CAST(nodep->rhsp(), Cond);
if (!condp) return false;
if (!VN_IS(condp->thenp(), Const) && !VN_IS(condp->elsep(), Const)) return false;
AstConst* const maskp = VN_CAST(nodep->lhsp(), Const);
if (!maskp) return false;
UINFO(4, "AND(CONSTm, CONDcond(c, i, e))->CONDcond(c, AND(m,i), AND(m, e)) " << nodep);
AstNodeCond* const newp = static_cast<AstNodeCond*>(condp->cloneType(
condp->condp()->unlinkFrBack(),
AstCond* const newp = new AstCond{
condp->fileline(), condp->condp()->unlinkFrBack(),
new AstAnd{nodep->fileline(), maskp->cloneTree(false), condp->thenp()->unlinkFrBack()},
new AstAnd{nodep->fileline(), maskp->cloneTree(false),
condp->elsep()->unlinkFrBack()}));
condp->elsep()->unlinkFrBack()}};
newp->thenp()->dtypeFrom(nodep); // As And might have been to change widths
newp->elsep()->dtypeFrom(nodep);
nodep->replaceWithKeepDType(newp);
@ -3658,20 +3658,20 @@ class ConstVisitor final : public VNVisitor {
TREEOPC("AstAnd {$lhsp.isOne, matchRedundantClean(nodep)}", "DONE") // 1 & (a == b) -> (IData)(a == b)
// Trinary ops
// Note V3Case::Sel requires Cond to always be conditionally executed in C to prevent core dump!
TREEOP ("AstNodeCond{$condp.isZero, $thenp, $elsep}", "replaceWChild(nodep,$elsep)");
TREEOP ("AstNodeCond{$condp.isNeqZero, $thenp, $elsep}", "replaceWChild(nodep,$thenp)");
TREEOPA("AstNodeCond{$condp.isZero, $thenp.castConst, $elsep.castConst}", "replaceWChild(nodep,$elsep)");
TREEOPA("AstNodeCond{$condp.isNeqZero, $thenp.castConst, $elsep.castConst}", "replaceWChild(nodep,$thenp)");
TREEOP ("AstNodeCond{$condp, operandsSame($thenp,,$elsep)}","replaceWChild(nodep,$thenp)");
TREEOP ("AstCond{$condp.isZero, $thenp, $elsep}", "replaceWChild(nodep,$elsep)");
TREEOP ("AstCond{$condp.isNeqZero, $thenp, $elsep}", "replaceWChild(nodep,$thenp)");
TREEOPA("AstCond{$condp.isZero, $thenp.castConst, $elsep.castConst}", "replaceWChild(nodep,$elsep)");
TREEOPA("AstCond{$condp.isNeqZero, $thenp.castConst, $elsep.castConst}", "replaceWChild(nodep,$thenp)");
TREEOP ("AstCond{$condp, operandsSame($thenp,,$elsep)}","replaceWChild(nodep,$thenp)");
// This visit function here must allow for short-circuiting.
TREEOPS("AstCond{$condp.isZero}", "replaceWIteratedThs(nodep)");
TREEOPS("AstCond{$condp.isNeqZero}", "replaceWIteratedRhs(nodep)");
TREEOP ("AstCond{$condp.castNot, $thenp, $elsep}", "AstCond{$condp->castNot()->lhsp(), $elsep, $thenp}");
TREEOP ("AstNodeCond{$condp.width1, $thenp.width1, $thenp.isAllOnes, $elsep}", "AstLogOr {$condp, $elsep}"); // a?1:b == a||b
TREEOP ("AstNodeCond{$condp.width1, $thenp.width1, $thenp, $elsep.isZero, !$elsep.isClassHandleValue}", "AstLogAnd{$condp, $thenp}"); // a?b:0 == a&&b
TREEOP ("AstNodeCond{$condp.width1, $thenp.width1, $thenp, $elsep.isAllOnes}", "AstLogOr {AstNot{$condp}, $thenp}"); // a?b:1 == ~a||b
TREEOP ("AstNodeCond{$condp.width1, $thenp.width1, $thenp.isZero, !$thenp.isClassHandleValue, $elsep}", "AstLogAnd{AstNot{$condp}, $elsep}"); // a?0:b == ~a&&b
TREEOP ("AstNodeCond{!$condp.width1, operandBoolShift(nodep->condp())}", "replaceBoolShift(nodep->condp())");
TREEOP ("AstCond{$condp.width1, $thenp.width1, $thenp.isAllOnes, $elsep}", "AstLogOr {$condp, $elsep}"); // a?1:b == a||b
TREEOP ("AstCond{$condp.width1, $thenp.width1, $thenp, $elsep.isZero, !$elsep.isClassHandleValue}", "AstLogAnd{$condp, $thenp}"); // a?b:0 == a&&b
TREEOP ("AstCond{$condp.width1, $thenp.width1, $thenp, $elsep.isAllOnes}", "AstLogOr {AstNot{$condp}, $thenp}"); // a?b:1 == ~a||b
TREEOP ("AstCond{$condp.width1, $thenp.width1, $thenp.isZero, !$thenp.isClassHandleValue, $elsep}", "AstLogAnd{AstNot{$condp}, $elsep}"); // a?0:b == ~a&&b
TREEOP ("AstCond{!$condp.width1, operandBoolShift(nodep->condp())}", "replaceBoolShift(nodep->condp())");
// Prefer constants on left, since that often needs a shift, it lets
// constant red remove the shift
TREEOP ("AstNodeBiCom{!$lhsp.castConst, $rhsp.castConst}", "swapSides(nodep)");

View File

@ -1349,7 +1349,7 @@ public:
iterateAndNextConstNull(nodep->lhsp());
puts(")");
}
void visit(AstNodeCond* nodep) override {
void visit(AstCond* nodep) override {
// Widths match up already, so we'll just use C++'s operator w/o any temps.
if (nodep->thenp()->isWide()) {
emitOpName(nodep, nodep->emitC(), nodep->condp(), nodep->thenp(), nodep->elsep());

View File

@ -616,7 +616,7 @@ class EmitVBaseVisitorConst VL_NOT_FINAL : public VNVisitorConst {
}
puts("}");
}
void visit(AstNodeCond* nodep) override {
void visit(AstCond* nodep) override {
putbs("(");
iterateAndNextConstNull(nodep->condp());
putfs(nodep, " ? ");

View File

@ -221,7 +221,7 @@ class ExpandVisitor final : public VNVisitor {
// e.g. "logic [95:0] var[0]; logic [0] sel; out = var[sel];"
// Squash before C++ to avoid getting a C++ compiler warning
// (even though code would be unreachable as presumably a
// AstCondBound is protecting above this node.
// AstCond is protecting above this node.
return new AstConst{fl, AstConst::SizedEData{}, 0};
} else {
AstNodeExpr* wordp;
@ -240,25 +240,13 @@ class ExpandVisitor final : public VNVisitor {
}
}
static AstNodeExpr* dropCondBound(AstNodeExpr* nodep) {
// Experimental only...
// If there's a CONDBOUND safety to keep arrays in bounds,
// we're going to AND it to a value that always fits inside a
// word, so we don't need it.
// if (VN_IS(nodep, CondBound) && VN_IS(VN_AS(nodep, CondBound)->lhsp(), Lte)) {
// nodep = VN_AS(nodep, CondBound)->rhsp();
//}
return nodep;
}
static AstNodeExpr* newSelBitBit(AstNodeExpr* lsbp) {
// Return equation to get the VL_BITBIT of a constant or non-constant
FileLine* const fl = lsbp->fileline();
if (VN_IS(lsbp, Const)) {
return new AstConst{fl, VL_BITBIT_E(VN_AS(lsbp, Const)->toUInt())};
} else {
return new AstAnd{fl, new AstConst{fl, VL_EDATASIZE - 1},
dropCondBound(lsbp)->cloneTreePure(true)};
return new AstAnd{fl, new AstConst{fl, VL_EDATASIZE - 1}, lsbp->cloneTreePure(true)};
}
}
@ -343,7 +331,7 @@ class ExpandVisitor final : public VNVisitor {
return true;
}
//-------- Triops
bool expandWide(AstNodeAssign* nodep, AstNodeCond* rhsp) {
bool expandWide(AstNodeAssign* nodep, AstCond* rhsp) {
UINFO(8, " Wordize ASSIGN(COND) " << nodep);
if (!doExpandWide(nodep)) return false;
FileLine* const fl = nodep->fileline();
@ -498,7 +486,7 @@ class ExpandVisitor final : public VNVisitor {
AstNodeExpr* const lsbp = nodep->lsbp()->unlinkFrBack();
if (nodep->isQuad() && !fromp->isQuad()) fromp = new AstCCast{fl, fromp, nodep};
// {large}>>32 requires 64-bit shift operation; then cast
AstNodeExpr* newp = new AstShiftR{fl, fromp, dropCondBound(lsbp), fromp->width()};
AstNodeExpr* newp = new AstShiftR{fl, fromp, lsbp, fromp->width()};
newp->dtypeFrom(fromp);
if (!nodep->isQuad() && fromp->isQuad()) newp = new AstCCast{fl, newp, nodep};
newp->dtypeFrom(nodep);
@ -944,7 +932,7 @@ class ExpandVisitor final : public VNVisitor {
did = expandWide(nodep, rhsp);
} else if (AstXor* const rhsp = VN_CAST(nodep->rhsp(), Xor)) {
did = expandWide(nodep, rhsp);
} else if (AstNodeCond* const rhsp = VN_CAST(nodep->rhsp(), NodeCond)) {
} else if (AstCond* const rhsp = VN_CAST(nodep->rhsp(), Cond)) {
did = expandWide(nodep, rhsp);
}
} else if (AstSel* const lhsp = VN_CAST(nodep->lhsp(), Sel)) {

View File

@ -188,7 +188,7 @@ private:
if (nodep->thensp()) nodep->thensp()->user2(0); // Don't dump it
}
}
void visit(AstNodeCond* nodep) override {
void visit(AstCond* nodep) override {
if (m_ignoreRemaining) return;
// Just like if/else above, the ternary operator only evaluates
// one of the two expressions, so only count the max.

View File

@ -189,7 +189,7 @@ class LinkIncVisitor final : public VNVisitor {
void visit(AstLogOr* nodep) override { unsupported_visit(nodep); }
void visit(AstLogEq* nodep) override { unsupported_visit(nodep); }
void visit(AstLogIf* nodep) override { unsupported_visit(nodep); }
void visit(AstNodeCond* nodep) override { unsupported_visit(nodep); }
void visit(AstCond* nodep) override { unsupported_visit(nodep); }
void visit(AstPropSpec* nodep) override { unsupported_visit(nodep); }
void prepost_visit(AstNodeTriop* nodep) {
// Check if we are underneath a statement

View File

@ -95,11 +95,11 @@ namespace {
// if there is one and it is in a supported position, which are:
// - RHS is the Cond
// - RHS is And(Const, Cond). This And is inserted often by V3Clean.
AstNodeCond* extractCondFromRhs(AstNode* rhsp) {
if (AstNodeCond* const condp = VN_CAST(rhsp, NodeCond)) {
AstCond* extractCondFromRhs(AstNode* rhsp) {
if (AstCond* const condp = VN_CAST(rhsp, Cond)) {
return condp;
} else if (const AstAnd* const andp = VN_CAST(rhsp, And)) {
if (AstNodeCond* const condp = VN_CAST(andp->rhsp(), NodeCond)) {
if (AstCond* const condp = VN_CAST(andp->rhsp(), Cond)) {
if (VN_IS(andp->lhsp(), Const)) return condp;
}
}
@ -177,7 +177,7 @@ class CodeMotionAnalysisVisitor final : public VNVisitorConst {
static AstNodeExpr* extractCondition(const AstNodeStmt* nodep) {
AstNodeExpr* conditionp = nullptr;
if (const AstNodeAssign* const assignp = VN_CAST(nodep, NodeAssign)) {
if (AstNodeCond* const conditionalp = extractCondFromRhs(assignp->rhsp())) {
if (AstCond* const conditionalp = extractCondFromRhs(assignp->rhsp())) {
conditionp = conditionalp->condp();
}
} else if (const AstNodeIf* const ifp = VN_CAST(nodep, NodeIf)) {
@ -564,7 +564,7 @@ class MergeCondVisitor final : public VNVisitor {
return yieldsOneOrZero(biopp->lhsp()) && yieldsOneOrZero(biopp->rhsp());
return false;
}
if (const AstNodeCond* const condp = VN_CAST(nodep, NodeCond)) {
if (const AstCond* const condp = VN_CAST(nodep, Cond)) {
return yieldsOneOrZero(condp->thenp()) && yieldsOneOrZero(condp->elsep());
}
if (const AstCCast* const castp = VN_CAST(nodep, CCast)) {
@ -591,7 +591,7 @@ class MergeCondVisitor final : public VNVisitor {
AstNodeExpr* foldAndUnlink(AstNodeExpr* rhsp, bool condTrue) {
if (rhsp->sameTree(m_mgCondp)) {
return new AstConst{rhsp->fileline(), AstConst::BitTrue{}, condTrue};
} else if (const AstNodeCond* const condp = extractCondFromRhs(rhsp)) {
} else if (const AstCond* const condp = extractCondFromRhs(rhsp)) {
AstNodeExpr* const resp
= condTrue ? condp->thenp()->unlinkFrBack() : condp->elsep()->unlinkFrBack();
if (condp == rhsp) return resp;

View File

@ -321,7 +321,7 @@ class PremitVisitor final : public VNVisitor {
}
checkNode(nodep);
}
void visit(AstNodeCond* nodep) override {
void visit(AstCond* nodep) override {
iterateChildren(nodep);
if (nodep->thenp()->isWide() && !VN_IS(nodep->condp(), Const)
&& !VN_IS(nodep->condp(), VarRef)) {

View File

@ -766,7 +766,7 @@ class ConstraintExprVisitor final : public VNVisitor {
if (editFormat(nodep)) return;
editSMT(nodep, nodep->lhsp(), nodep->rhsp(), nodep->thsp());
}
void visit(AstNodeCond* nodep) override {
void visit(AstCond* nodep) override {
if (editFormat(nodep)) return;
if (!nodep->condp()->user1()) {
// Do not burden the solver if cond computable: (cond ? "then" : "else")

View File

@ -672,7 +672,7 @@ private:
}
}
}
void visit(AstNodeCond* nodep) override {
void visit(AstCond* nodep) override {
// We could use above visit(AstNodeTriop), but need to do short circuiting.
// It's also slower even O(n^2) to evaluate both sides when we
// really only need to evaluate one side.

View File

@ -190,11 +190,11 @@ class SliceVisitor final : public VNVisitor {
}
}
if (!newp) newp = new AstConst{nodep->fileline(), 0};
} else if (AstNodeCond* const snodep = VN_CAST(nodep, NodeCond)) {
} else if (AstCond* const snodep = VN_CAST(nodep, Cond)) {
UINFO(9, " cloneCond(" << elements << "," << elemIdx << ") " << nodep);
return snodep->cloneType(snodep->condp()->cloneTree(false, needPure),
return new AstCond{snodep->fileline(), snodep->condp()->cloneTree(false, needPure),
cloneAndSel(snodep->thenp(), elements, elemIdx, needPure),
cloneAndSel(snodep->elsep(), elements, elemIdx, needPure));
cloneAndSel(snodep->elsep(), elements, elemIdx, needPure)};
} else if (const AstSliceSel* const snodep = VN_CAST(nodep, SliceSel)) {
UINFO(9, " cloneSliceSel(" << elements << "," << elemIdx << ") " << nodep);
const int leOffset = (snodep->declRange().lo()

View File

@ -112,7 +112,7 @@ private:
if (nodep->thensp()) nodep->thensp()->user2(0); // Don't dump it
}
}
void visit(AstNodeCond* nodep) override {
void visit(AstCond* nodep) override {
if (m_ignoreRemaining) return;
// Just like if/else above, the ternary operator only evaluates
// one of the two expressions, so only count the max.

View File

@ -411,7 +411,7 @@ class UnknownVisitor final : public VNVisitor {
AstNodeExpr* const xexprp = new AstConst{nodep->fileline(), xnum};
AstNodeExpr* const newp
= condp->isZero() ? xexprp
: new AstCondBound{nodep->fileline(), condp, nodep, xexprp};
: new AstCond{nodep->fileline(), condp, nodep, xexprp};
UINFOTREE(9, newp, "", "_new");
// Link in conditional
replaceHandle.relink(newp);
@ -485,7 +485,7 @@ class UnknownVisitor final : public VNVisitor {
} else {
xnum.setAllBitsX();
}
AstNode* const newp = new AstCondBound{nodep->fileline(), condp, nodep,
AstNode* const newp = new AstCond{nodep->fileline(), condp, nodep,
new AstConst{nodep->fileline(), xnum}};
UINFOTREE(9, newp, "", "_new");
// Link in conditional, can blow away temp xor
@ -496,7 +496,7 @@ class UnknownVisitor final : public VNVisitor {
// ARRAYSEL(...) -> ARRAYSEL(COND(LT(bit<maxbit), bit, 0))
VNRelinker replaceHandle;
AstNodeExpr* const bitp = nodep->bitp()->unlinkFrBack(&replaceHandle);
AstNodeExpr* const newp = new AstCondBound{
AstNodeExpr* const newp = new AstCond{
bitp->fileline(), condp, bitp,
new AstConst{bitp->fileline(), AstConst::WidthedValue{}, bitp->width(), 0}};
// Added X's, tristate them too

View File

@ -492,7 +492,7 @@ class WidthVisitor final : public VNVisitor {
nodep->dtypeSetUInt64(); // A pointer, but not that it matters
}
void visit(AstNodeCond* nodep) override {
void visit(AstCond* nodep) override {
// op = cond ? expr1 : expr2
// See IEEE-2012 11.4.11 and Table 11-21.
// LHS is self-determined