2012-04-12 21:08:20 -04:00
|
|
|
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
2006-08-26 11:35:28 +00:00
|
|
|
//*************************************************************************
|
|
|
|
|
// DESCRIPTION: Verilator: Add C++ casts across expression size changes
|
|
|
|
|
//
|
2019-11-07 22:33:59 -05:00
|
|
|
// Code available from: https://verilator.org
|
2006-08-26 11:35:28 +00:00
|
|
|
//
|
|
|
|
|
//*************************************************************************
|
|
|
|
|
//
|
2026-01-26 20:24:34 -05:00
|
|
|
// This program is free software; you can redistribute it and/or modify it
|
|
|
|
|
// under the terms of either the GNU Lesser General Public License Version 3
|
|
|
|
|
// or the Perl Artistic License Version 2.0.
|
|
|
|
|
// SPDX-FileCopyrightText: 2004-2026 Wilson Snyder
|
2020-03-21 11:24:24 -04:00
|
|
|
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
2006-08-26 11:35:28 +00:00
|
|
|
//
|
|
|
|
|
//*************************************************************************
|
|
|
|
|
// V3Cast's Transformations:
|
2008-06-09 21:25:10 -04:00
|
|
|
//
|
2006-08-26 11:35:28 +00:00
|
|
|
// Each module:
|
2022-10-12 10:19:21 +01:00
|
|
|
// For each expression, if above expression requires 32 bits,
|
2019-05-19 16:13:13 -04:00
|
|
|
// and this isn't, cast to 32 bits.
|
2022-10-12 10:19:21 +01:00
|
|
|
// Likewise for 64 bit expressions.
|
2006-08-26 11:35:28 +00:00
|
|
|
//
|
|
|
|
|
// C++ rules:
|
2019-05-19 16:13:13 -04:00
|
|
|
// Integral promotions allow conversion to larger int. Unsigned is only
|
|
|
|
|
// used if a int would not fit the value.
|
2006-08-26 11:35:28 +00:00
|
|
|
//
|
2019-05-19 16:13:13 -04:00
|
|
|
// Bools converts to int, not unsigned.
|
2006-08-26 11:35:28 +00:00
|
|
|
//
|
2019-05-19 16:13:13 -04:00
|
|
|
// Most operations return unsigned if either operand is unsigned.
|
2006-08-26 11:35:28 +00:00
|
|
|
//
|
2019-05-19 16:13:13 -04:00
|
|
|
// Unsignedness can be lost on results of the below operations, as they
|
|
|
|
|
// may need the sign bit for proper operation:
|
|
|
|
|
// /, %, /=, %=, <, <=, >, or >=
|
2006-08-26 11:35:28 +00:00
|
|
|
//
|
2019-05-19 16:13:13 -04:00
|
|
|
// Signed values are always sign extended on promotion or right shift,
|
|
|
|
|
// even if assigning to a unsigned.
|
2006-08-26 11:35:28 +00:00
|
|
|
//
|
|
|
|
|
//*************************************************************************
|
2019-10-04 20:17:11 -04:00
|
|
|
|
2023-10-18 02:50:27 +00:00
|
|
|
#include "V3PchAstNoMT.h" // VL_MT_DISABLED_CODE_UNIT
|
|
|
|
|
|
2023-10-18 06:37:46 -04:00
|
|
|
#include "V3Cast.h"
|
|
|
|
|
|
2022-09-18 20:53:42 +01:00
|
|
|
VL_DEFINE_DEBUG_FUNCTIONS;
|
|
|
|
|
|
2006-08-26 11:35:28 +00:00
|
|
|
//######################################################################
|
|
|
|
|
// Cast state, as a visitor of each AstNode
|
|
|
|
|
|
2022-01-02 13:56:40 -05:00
|
|
|
class CastVisitor final : public VNVisitor {
|
2006-08-26 11:35:28 +00:00
|
|
|
// NODE STATE
|
|
|
|
|
// Entire netlist:
|
2026-08-08 13:05:05 -04:00
|
|
|
// AstNode::user1() // bool. Node is of known size
|
2022-01-02 13:56:40 -05:00
|
|
|
const VNUser1InUse m_inuser1;
|
2006-08-26 11:35:28 +00:00
|
|
|
|
|
|
|
|
// STATE
|
|
|
|
|
|
|
|
|
|
// METHODS
|
2009-01-21 16:56:50 -05:00
|
|
|
|
2022-11-13 20:33:11 +00:00
|
|
|
void insertCast(AstNodeExpr* nodep, int needsize) { // We'll insert ABOVE passed node
|
2022-01-02 10:32:35 -05:00
|
|
|
VNRelinker relinkHandle;
|
2019-05-19 16:13:13 -04:00
|
|
|
nodep->unlinkFrBack(&relinkHandle);
|
|
|
|
|
//
|
2021-07-11 18:42:01 -04:00
|
|
|
AstCCast* const castp
|
|
|
|
|
= new AstCCast{nodep->fileline(), nodep, needsize, nodep->widthMin()};
|
2025-05-22 20:29:32 -04:00
|
|
|
UINFO(4, " MadeCast " << static_cast<void*>(castp) << " for " << nodep);
|
2019-05-19 16:13:13 -04:00
|
|
|
relinkHandle.relink(castp);
|
2025-08-02 13:44:40 -04:00
|
|
|
// UINFOTREE(9, castp, "", "castins");
|
2019-05-19 16:13:13 -04:00
|
|
|
//
|
2020-01-24 20:10:44 -05:00
|
|
|
ensureLower32Cast(castp);
|
2019-05-19 16:13:13 -04:00
|
|
|
nodep->user1(1); // Now must be of known size
|
2006-08-26 11:35:28 +00:00
|
|
|
}
|
2025-08-19 22:02:10 +01:00
|
|
|
static int castSize(const AstNode* nodep) {
|
2020-04-15 07:58:34 -04:00
|
|
|
if (nodep->isQuad()) {
|
|
|
|
|
return VL_QUADSIZE;
|
|
|
|
|
} else if (nodep->width() <= 8) {
|
|
|
|
|
return 8;
|
|
|
|
|
} else if (nodep->width() <= 16) {
|
|
|
|
|
return 16;
|
|
|
|
|
} else {
|
|
|
|
|
return VL_IDATASIZE;
|
|
|
|
|
}
|
2006-08-26 11:35:28 +00:00
|
|
|
}
|
2022-11-13 20:33:11 +00:00
|
|
|
void ensureCast(AstNodeExpr* nodep) {
|
2020-04-15 07:58:34 -04:00
|
|
|
if (castSize(nodep->backp()) != castSize(nodep) || !nodep->user1()) {
|
2026-03-04 20:12:10 -05:00
|
|
|
if (!nodep->isNull() && !nodep->isString() && !nodep->isDouble())
|
|
|
|
|
insertCast(nodep, castSize(nodep->backp()));
|
2019-05-19 16:13:13 -04:00
|
|
|
}
|
2006-08-26 11:35:28 +00:00
|
|
|
}
|
2025-08-20 18:21:24 +01:00
|
|
|
// cppcheck-suppress constParameterPointer // lhsp might be changed
|
2020-01-24 20:10:44 -05:00
|
|
|
void ensureLower32Cast(AstCCast* nodep) {
|
2019-05-19 16:13:13 -04:00
|
|
|
// If we have uint64 = CAST(uint64(x)) then the upcasting
|
|
|
|
|
// really needs to be CAST(uint64(CAST(uint32(x))).
|
|
|
|
|
// Otherwise a (uint64)(a>b) would return wrong value, as
|
2019-09-09 07:50:21 -04:00
|
|
|
// less than has nondeterministic signedness.
|
2020-04-15 07:58:34 -04:00
|
|
|
if (nodep->isQuad() && !nodep->lhsp()->isQuad() && !VN_IS(nodep->lhsp(), CCast)) {
|
2019-12-08 21:36:38 -05:00
|
|
|
insertCast(nodep->lhsp(), VL_IDATASIZE);
|
2019-05-19 16:13:13 -04:00
|
|
|
}
|
2006-08-26 11:35:28 +00:00
|
|
|
}
|
2022-11-13 20:33:11 +00:00
|
|
|
void ensureNullChecked(AstNodeExpr* nodep) {
|
2020-04-05 09:30:23 -04:00
|
|
|
// TODO optimize to track null checked values and avoid where possible
|
|
|
|
|
if (!VN_IS(nodep->backp(), NullCheck)) {
|
2022-01-02 10:32:35 -05:00
|
|
|
VNRelinker relinkHandle;
|
2020-04-05 09:30:23 -04:00
|
|
|
nodep->unlinkFrBack(&relinkHandle);
|
2022-11-13 20:33:11 +00:00
|
|
|
relinkHandle.relink(new AstNullCheck{nodep->fileline(), nodep});
|
2020-04-05 09:30:23 -04:00
|
|
|
}
|
|
|
|
|
}
|
2006-08-26 11:35:28 +00:00
|
|
|
|
|
|
|
|
// VISITORS
|
2022-09-16 11:22:11 +01:00
|
|
|
void visit(AstNodeUniop* nodep) override {
|
2018-05-10 20:55:37 -04:00
|
|
|
iterateChildren(nodep);
|
2019-05-19 16:13:13 -04:00
|
|
|
nodep->user1(nodep->lhsp()->user1());
|
2020-01-24 20:10:44 -05:00
|
|
|
if (nodep->sizeMattersLhs()) ensureCast(nodep->lhsp());
|
2006-08-26 11:35:28 +00:00
|
|
|
}
|
2022-09-16 11:22:11 +01:00
|
|
|
void visit(AstNodeBiop* nodep) override {
|
2018-05-10 20:55:37 -04:00
|
|
|
iterateChildren(nodep);
|
2020-04-15 07:58:34 -04:00
|
|
|
nodep->user1(nodep->lhsp()->user1() | nodep->rhsp()->user1());
|
2020-01-24 20:10:44 -05:00
|
|
|
if (nodep->sizeMattersLhs()) ensureCast(nodep->lhsp());
|
|
|
|
|
if (nodep->sizeMattersRhs()) ensureCast(nodep->rhsp());
|
2006-08-26 11:35:28 +00:00
|
|
|
}
|
2025-08-15 23:49:06 +01:00
|
|
|
void visit(AstCond* nodep) override {
|
2023-05-30 14:59:00 +02:00
|
|
|
// 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
|
2023-11-10 23:25:53 -05:00
|
|
|
// common base class, so both classes can be safely casted.
|
2023-05-30 14:59:00 +02:00
|
|
|
const AstClassRefDType* const thenClassDtypep
|
2024-03-16 09:12:10 -04:00
|
|
|
= VN_CAST(nodep->thenp()->dtypep()->skipRefp(), ClassRefDType);
|
2023-05-30 14:59:00 +02:00
|
|
|
const AstClassRefDType* const elseClassDtypep
|
2024-03-16 09:12:10 -04:00
|
|
|
= VN_CAST(nodep->elsep()->dtypep()->skipRefp(), ClassRefDType);
|
2023-05-30 14:59:00 +02:00
|
|
|
const bool castRequired = thenClassDtypep && elseClassDtypep
|
|
|
|
|
&& (thenClassDtypep->classp() != elseClassDtypep->classp());
|
|
|
|
|
if (castRequired) {
|
|
|
|
|
const AstClass* const commonBaseClassp
|
2024-03-16 09:12:10 -04:00
|
|
|
= VN_AS(nodep->dtypep()->skipRefp(), ClassRefDType)->classp();
|
2023-05-30 14:59:00 +02:00
|
|
|
if (thenClassDtypep->classp() != commonBaseClassp) {
|
|
|
|
|
AstNodeExpr* thenp = nodep->thenp()->unlinkFrBack();
|
|
|
|
|
nodep->thenp(new AstCCast{thenp->fileline(), thenp, nodep});
|
|
|
|
|
}
|
|
|
|
|
if (elseClassDtypep->classp() != commonBaseClassp) {
|
|
|
|
|
AstNodeExpr* elsep = nodep->elsep()->unlinkFrBack();
|
|
|
|
|
nodep->elsep(new AstCCast{elsep->fileline(), elsep, nodep});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
visit(static_cast<AstNodeTriop*>(nodep));
|
|
|
|
|
}
|
2022-09-16 11:22:11 +01:00
|
|
|
void visit(AstNodeTriop* nodep) override {
|
2018-05-10 20:55:37 -04:00
|
|
|
iterateChildren(nodep);
|
2020-04-15 07:58:34 -04:00
|
|
|
nodep->user1(nodep->lhsp()->user1() | nodep->rhsp()->user1() | nodep->thsp()->user1());
|
2020-01-24 20:10:44 -05:00
|
|
|
if (nodep->sizeMattersLhs()) ensureCast(nodep->lhsp());
|
|
|
|
|
if (nodep->sizeMattersRhs()) ensureCast(nodep->rhsp());
|
|
|
|
|
if (nodep->sizeMattersThs()) ensureCast(nodep->thsp());
|
2006-08-26 11:35:28 +00:00
|
|
|
}
|
2022-09-16 11:22:11 +01:00
|
|
|
void visit(AstNodeQuadop* nodep) override {
|
2020-05-10 20:27:22 +02:00
|
|
|
iterateChildren(nodep);
|
|
|
|
|
nodep->user1(nodep->lhsp()->user1() | nodep->rhsp()->user1() | nodep->thsp()->user1()
|
|
|
|
|
| nodep->fhsp()->user1());
|
|
|
|
|
if (nodep->sizeMattersLhs()) ensureCast(nodep->lhsp());
|
|
|
|
|
if (nodep->sizeMattersRhs()) ensureCast(nodep->rhsp());
|
|
|
|
|
if (nodep->sizeMattersThs()) ensureCast(nodep->thsp());
|
|
|
|
|
if (nodep->sizeMattersFhs()) ensureCast(nodep->fhsp());
|
|
|
|
|
}
|
2022-09-16 11:22:11 +01:00
|
|
|
void visit(AstCCast* nodep) override {
|
2018-05-10 20:55:37 -04:00
|
|
|
iterateChildren(nodep);
|
2020-01-24 20:10:44 -05:00
|
|
|
ensureLower32Cast(nodep);
|
2019-05-19 16:13:13 -04:00
|
|
|
nodep->user1(1);
|
2006-08-26 11:35:28 +00:00
|
|
|
}
|
2023-10-18 17:51:25 -04:00
|
|
|
void visit(AstConsPackMember* nodep) override {
|
|
|
|
|
iterateChildren(nodep);
|
|
|
|
|
if (VN_IS(nodep->rhsp()->dtypep()->skipRefp(), BasicDType)) ensureCast(nodep->rhsp());
|
|
|
|
|
nodep->user1(1);
|
|
|
|
|
}
|
2023-10-06 21:33:31 -04:00
|
|
|
void visit(AstExprStmt* nodep) override {
|
|
|
|
|
iterateChildren(nodep);
|
|
|
|
|
nodep->user1(1);
|
|
|
|
|
}
|
2022-09-16 11:22:11 +01:00
|
|
|
void visit(AstNegate* nodep) override {
|
2018-05-10 20:55:37 -04:00
|
|
|
iterateChildren(nodep);
|
2019-05-19 16:13:13 -04:00
|
|
|
nodep->user1(nodep->lhsp()->user1());
|
2025-07-28 02:20:57 -04:00
|
|
|
if (nodep->lhsp()->widthMin() == 1 && !nodep->lhsp()->isWide()) {
|
2019-05-19 16:13:13 -04:00
|
|
|
// We want to avoid a GCC "converting of negative value" warning
|
|
|
|
|
// from our expansion of
|
|
|
|
|
// out = {32{a<b}} => out = - (a<b)
|
|
|
|
|
insertCast(nodep->lhsp(), castSize(nodep));
|
|
|
|
|
} else {
|
2025-07-28 02:20:57 -04:00
|
|
|
if (nodep->sizeMattersLhs()) ensureCast(nodep->lhsp());
|
2019-05-19 16:13:13 -04:00
|
|
|
}
|
2006-08-26 11:35:28 +00:00
|
|
|
}
|
2022-09-16 11:22:11 +01:00
|
|
|
void visit(AstVarRef* nodep) override {
|
2021-11-13 10:42:26 -05:00
|
|
|
const AstNode* const backp = nodep->backp();
|
2022-10-12 10:19:21 +01:00
|
|
|
if (nodep->access().isReadOnly() && VN_IS(backp, NodeExpr) && !VN_IS(backp, CCast)
|
|
|
|
|
&& !VN_IS(backp, NodeCCall) && !VN_IS(backp, CMethodHard) && !VN_IS(backp, SFormatF)
|
2022-12-21 01:22:42 +01:00
|
|
|
&& !VN_IS(backp, ArraySel) && !VN_IS(backp, StructSel) && !VN_IS(backp, RedXor)
|
2025-10-31 19:29:11 +01:00
|
|
|
&& (nodep->varp()->basicp() && !nodep->varp()->basicp()->isForkSync()
|
2023-10-26 16:38:47 +02:00
|
|
|
&& !nodep->varp()->basicp()->isProcessRef() && !nodep->varp()->basicp()->isEvent())
|
2022-05-15 16:03:32 +01:00
|
|
|
&& backp->width() && castSize(nodep) != castSize(nodep->varp())) {
|
2019-05-19 16:13:13 -04:00
|
|
|
// Cast vars to IData first, else below has upper bits wrongly set
|
|
|
|
|
// CData x=3; out = (QData)(x<<30);
|
2018-08-25 09:52:45 -04:00
|
|
|
insertCast(nodep, castSize(nodep));
|
2019-05-19 16:13:13 -04:00
|
|
|
}
|
|
|
|
|
nodep->user1(1);
|
2007-10-31 19:22:26 +00:00
|
|
|
}
|
2022-09-16 11:22:11 +01:00
|
|
|
void visit(AstConst* nodep) override {
|
2019-09-09 07:50:21 -04:00
|
|
|
// Constants are of unknown size if smaller than 33 bits, because
|
2019-05-19 16:13:13 -04:00
|
|
|
// we're too lazy to wrap every constant in the universe in
|
|
|
|
|
// ((IData)#).
|
2024-03-16 08:49:36 -04:00
|
|
|
nodep->user1(nodep->isQuad() || nodep->isWide() || nodep->isNull());
|
2006-08-26 11:35:28 +00:00
|
|
|
}
|
|
|
|
|
|
2020-04-05 09:30:23 -04:00
|
|
|
// Null dereference protection
|
2022-09-16 11:22:11 +01:00
|
|
|
void visit(AstNullCheck* nodep) override {
|
2020-04-05 09:30:23 -04:00
|
|
|
iterateChildren(nodep);
|
|
|
|
|
nodep->user1(nodep->lhsp()->user1());
|
|
|
|
|
}
|
2022-09-16 11:22:11 +01:00
|
|
|
void visit(AstCMethodCall* nodep) override {
|
2020-04-05 09:30:23 -04:00
|
|
|
iterateChildren(nodep);
|
|
|
|
|
ensureNullChecked(nodep->fromp());
|
2024-02-25 08:19:53 -05:00
|
|
|
nodep->user1(true);
|
|
|
|
|
}
|
|
|
|
|
void visit(AstCMethodHard* nodep) override {
|
|
|
|
|
iterateChildren(nodep);
|
|
|
|
|
nodep->user1(true);
|
2020-04-05 09:30:23 -04:00
|
|
|
}
|
2022-09-16 11:22:11 +01:00
|
|
|
void visit(AstMemberSel* nodep) override {
|
2020-04-05 09:30:23 -04:00
|
|
|
iterateChildren(nodep);
|
|
|
|
|
ensureNullChecked(nodep->fromp());
|
2025-07-28 02:20:57 -04:00
|
|
|
nodep->user1(true);
|
|
|
|
|
}
|
|
|
|
|
void visit(AstStructSel* nodep) override {
|
|
|
|
|
iterateChildren(nodep);
|
|
|
|
|
nodep->user1(true);
|
2020-04-05 09:30:23 -04:00
|
|
|
}
|
|
|
|
|
|
2006-08-26 11:35:28 +00:00
|
|
|
// NOPs
|
2022-09-16 11:22:11 +01:00
|
|
|
void visit(AstVar*) override {}
|
2006-08-26 11:35:28 +00:00
|
|
|
|
|
|
|
|
//--------------------
|
2022-09-16 11:22:11 +01:00
|
|
|
void visit(AstNode* nodep) override { iterateChildren(nodep); }
|
2006-08-26 11:35:28 +00:00
|
|
|
|
|
|
|
|
public:
|
2019-09-12 07:22:22 -04:00
|
|
|
// CONSTRUCTORS
|
2020-04-15 07:58:34 -04:00
|
|
|
explicit CastVisitor(AstNetlist* nodep) { iterate(nodep); }
|
2022-09-16 11:22:11 +01:00
|
|
|
~CastVisitor() override = default;
|
2006-08-26 11:35:28 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//######################################################################
|
|
|
|
|
// Cast class functions
|
|
|
|
|
|
|
|
|
|
void V3Cast::castAll(AstNetlist* nodep) {
|
2025-05-22 20:29:32 -04:00
|
|
|
UINFO(2, __FUNCTION__ << ":");
|
2021-11-26 10:52:36 -05:00
|
|
|
{ CastVisitor{nodep}; } // Destruct before checking
|
2024-01-09 16:35:13 +01:00
|
|
|
V3Global::dumpCheckGlobalTree("cast", 0, dumpTreeEitherLevel() >= 3);
|
2006-08-26 11:35:28 +00:00
|
|
|
}
|