2012-04-13 03:08:20 +02:00
|
|
|
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
2006-08-26 13:35:28 +02:00
|
|
|
//*************************************************************************
|
|
|
|
|
// DESCRIPTION: Verilator: Add C++ casts across expression size changes
|
|
|
|
|
//
|
2019-11-08 04:33:59 +01:00
|
|
|
// Code available from: https://verilator.org
|
2006-08-26 13:35:28 +02:00
|
|
|
//
|
|
|
|
|
//*************************************************************************
|
|
|
|
|
//
|
2020-01-07 00:05:53 +01:00
|
|
|
// Copyright 2004-2020 by Wilson Snyder. This program is free software; you can
|
2006-08-26 13:35:28 +02:00
|
|
|
// redistribute it and/or modify it under the terms of either the GNU
|
2009-05-04 23:07:57 +02:00
|
|
|
// Lesser General Public License Version 3 or the Perl Artistic License
|
|
|
|
|
// Version 2.0.
|
2006-08-26 13:35:28 +02:00
|
|
|
//
|
|
|
|
|
// Verilator is distributed in the hope that it will be useful,
|
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
// GNU General Public License for more details.
|
|
|
|
|
//
|
|
|
|
|
//*************************************************************************
|
|
|
|
|
// V3Cast's Transformations:
|
2008-06-10 03:25:10 +02:00
|
|
|
//
|
2006-08-26 13:35:28 +02:00
|
|
|
// Each module:
|
2019-05-19 22:13:13 +02:00
|
|
|
// For each math operator, if above operator requires 32 bits,
|
|
|
|
|
// and this isn't, cast to 32 bits.
|
|
|
|
|
// Likewise for 64 bit operators.
|
2006-08-26 13:35:28 +02:00
|
|
|
//
|
|
|
|
|
// C++ rules:
|
2019-05-19 22:13:13 +02:00
|
|
|
// Integral promotions allow conversion to larger int. Unsigned is only
|
|
|
|
|
// used if a int would not fit the value.
|
2006-08-26 13:35:28 +02:00
|
|
|
//
|
2019-05-19 22:13:13 +02:00
|
|
|
// Bools converts to int, not unsigned.
|
2006-08-26 13:35:28 +02:00
|
|
|
//
|
2019-05-19 22:13:13 +02:00
|
|
|
// Most operations return unsigned if either operand is unsigned.
|
2006-08-26 13:35:28 +02:00
|
|
|
//
|
2019-05-19 22:13:13 +02: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 13:35:28 +02:00
|
|
|
//
|
2019-05-19 22:13:13 +02:00
|
|
|
// Signed values are always sign extended on promotion or right shift,
|
|
|
|
|
// even if assigning to a unsigned.
|
2006-08-26 13:35:28 +02:00
|
|
|
//
|
|
|
|
|
//*************************************************************************
|
2019-10-05 02:17:11 +02:00
|
|
|
|
2006-12-18 20:20:45 +01:00
|
|
|
#include "config_build.h"
|
|
|
|
|
#include "verilatedos.h"
|
2006-08-26 13:35:28 +02:00
|
|
|
|
|
|
|
|
#include "V3Global.h"
|
|
|
|
|
#include "V3Cast.h"
|
|
|
|
|
#include "V3Ast.h"
|
|
|
|
|
|
2018-10-14 19:43:24 +02:00
|
|
|
#include <algorithm>
|
|
|
|
|
#include <cstdarg>
|
|
|
|
|
|
2006-08-26 13:35:28 +02:00
|
|
|
//######################################################################
|
|
|
|
|
// Cast state, as a visitor of each AstNode
|
|
|
|
|
|
|
|
|
|
class CastVisitor : public AstNVisitor {
|
|
|
|
|
private:
|
|
|
|
|
// NODE STATE
|
|
|
|
|
// Entire netlist:
|
2019-05-19 22:13:13 +02:00
|
|
|
// AstNode::user() // bool. Indicates node is of known size
|
|
|
|
|
AstUser1InUse m_inuser1;
|
2006-08-26 13:35:28 +02:00
|
|
|
|
|
|
|
|
// STATE
|
|
|
|
|
|
|
|
|
|
// METHODS
|
2018-05-14 12:50:47 +02:00
|
|
|
VL_DEBUG_FUNC; // Declare debug()
|
2009-01-21 22:56:50 +01:00
|
|
|
|
2006-08-26 13:35:28 +02:00
|
|
|
void insertCast(AstNode* nodep, int needsize) { // We'll insert ABOVE passed node
|
2019-05-19 22:13:13 +02:00
|
|
|
UINFO(4," NeedCast "<<nodep<<endl);
|
|
|
|
|
AstNRelinker relinkHandle;
|
|
|
|
|
nodep->unlinkFrBack(&relinkHandle);
|
|
|
|
|
//
|
2018-08-25 15:52:45 +02:00
|
|
|
AstCCast* castp = new AstCCast(nodep->fileline(), nodep, needsize, nodep->widthMin());
|
2019-05-19 22:13:13 +02:00
|
|
|
relinkHandle.relink(castp);
|
|
|
|
|
//if (debug()>8) castp->dumpTree(cout, "-castins: ");
|
|
|
|
|
//
|
2020-01-25 02:10:44 +01:00
|
|
|
ensureLower32Cast(castp);
|
2019-05-19 22:13:13 +02:00
|
|
|
nodep->user1(1); // Now must be of known size
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2018-08-25 15:52:45 +02:00
|
|
|
int castSize(AstNode* nodep) {
|
2019-05-19 22:13:13 +02:00
|
|
|
if (nodep->isQuad()) return VL_QUADSIZE;
|
2019-12-09 03:36:38 +01:00
|
|
|
else if (nodep->width() <= 8) return 8;
|
|
|
|
|
else if (nodep->width() <= 16) return 16;
|
|
|
|
|
else return VL_IDATASIZE;
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2020-01-25 02:10:44 +01:00
|
|
|
void ensureCast(AstNode* nodep) {
|
2019-05-19 22:13:13 +02:00
|
|
|
if (castSize(nodep->backp()) != castSize(nodep)
|
|
|
|
|
|| !nodep->user1()) {
|
|
|
|
|
insertCast(nodep, castSize(nodep->backp()));
|
|
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2020-01-25 02:10:44 +01:00
|
|
|
void ensureLower32Cast(AstCCast* nodep) {
|
2019-05-19 22:13:13 +02: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 13:50:21 +02:00
|
|
|
// less than has nondeterministic signedness.
|
2019-05-19 22:13:13 +02:00
|
|
|
if (nodep->isQuad() && !nodep->lhsp()->isQuad()
|
2018-02-02 03:32:58 +01:00
|
|
|
&& !VN_IS(nodep->lhsp(), CCast)) {
|
2019-12-09 03:36:38 +01:00
|
|
|
insertCast(nodep->lhsp(), VL_IDATASIZE);
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// VISITORS
|
2020-01-21 23:35:56 +01:00
|
|
|
virtual void visit(AstNodeUniop* nodep) VL_OVERRIDE {
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateChildren(nodep);
|
2019-05-19 22:13:13 +02:00
|
|
|
nodep->user1(nodep->lhsp()->user1());
|
2020-01-25 02:10:44 +01:00
|
|
|
if (nodep->sizeMattersLhs()) ensureCast(nodep->lhsp());
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2020-01-21 23:35:56 +01:00
|
|
|
virtual void visit(AstNodeBiop* nodep) VL_OVERRIDE {
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateChildren(nodep);
|
2019-05-19 22:13:13 +02:00
|
|
|
nodep->user1(nodep->lhsp()->user1()
|
|
|
|
|
| nodep->rhsp()->user1());
|
2020-01-25 02:10:44 +01:00
|
|
|
if (nodep->sizeMattersLhs()) ensureCast(nodep->lhsp());
|
|
|
|
|
if (nodep->sizeMattersRhs()) ensureCast(nodep->rhsp());
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2020-01-21 23:35:56 +01:00
|
|
|
virtual void visit(AstNodeTriop* nodep) VL_OVERRIDE {
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateChildren(nodep);
|
2019-05-19 22:13:13 +02:00
|
|
|
nodep->user1(nodep->lhsp()->user1()
|
|
|
|
|
| nodep->rhsp()->user1()
|
|
|
|
|
| nodep->thsp()->user1());
|
2020-01-25 02:10:44 +01:00
|
|
|
if (nodep->sizeMattersLhs()) ensureCast(nodep->lhsp());
|
|
|
|
|
if (nodep->sizeMattersRhs()) ensureCast(nodep->rhsp());
|
|
|
|
|
if (nodep->sizeMattersThs()) ensureCast(nodep->thsp());
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2020-01-21 23:35:56 +01:00
|
|
|
virtual void visit(AstCCast* nodep) VL_OVERRIDE {
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateChildren(nodep);
|
2020-01-25 02:10:44 +01:00
|
|
|
ensureLower32Cast(nodep);
|
2019-05-19 22:13:13 +02:00
|
|
|
nodep->user1(1);
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2020-01-21 23:35:56 +01:00
|
|
|
virtual void visit(AstNegate* nodep) VL_OVERRIDE {
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateChildren(nodep);
|
2019-05-19 22:13:13 +02:00
|
|
|
nodep->user1(nodep->lhsp()->user1());
|
|
|
|
|
if (nodep->lhsp()->widthMin()==1) {
|
|
|
|
|
// 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 {
|
2020-01-25 02:10:44 +01:00
|
|
|
ensureCast(nodep->lhsp());
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2020-01-21 23:35:56 +01:00
|
|
|
virtual void visit(AstVarRef* nodep) VL_OVERRIDE {
|
2019-05-19 22:13:13 +02:00
|
|
|
if (!nodep->lvalue()
|
2018-02-02 03:32:58 +01:00
|
|
|
&& !VN_IS(nodep->backp(), CCast)
|
|
|
|
|
&& VN_IS(nodep->backp(), NodeMath)
|
|
|
|
|
&& !VN_IS(nodep->backp(), ArraySel)
|
2019-05-19 22:13:13 +02:00
|
|
|
&& nodep->backp()->width()
|
|
|
|
|
&& castSize(nodep) != castSize(nodep->varp())) {
|
|
|
|
|
// Cast vars to IData first, else below has upper bits wrongly set
|
|
|
|
|
// CData x=3; out = (QData)(x<<30);
|
2018-08-25 15:52:45 +02:00
|
|
|
insertCast(nodep, castSize(nodep));
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
|
|
|
|
nodep->user1(1);
|
2007-10-31 20:22:26 +01:00
|
|
|
}
|
2020-01-21 23:35:56 +01:00
|
|
|
virtual void visit(AstConst* nodep) VL_OVERRIDE {
|
2019-09-09 13:50:21 +02:00
|
|
|
// Constants are of unknown size if smaller than 33 bits, because
|
2019-05-19 22:13:13 +02:00
|
|
|
// we're too lazy to wrap every constant in the universe in
|
|
|
|
|
// ((IData)#).
|
|
|
|
|
nodep->user1(nodep->isQuad() || nodep->isWide());
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// NOPs
|
2020-01-21 23:35:56 +01:00
|
|
|
virtual void visit(AstVar* nodep) VL_OVERRIDE {}
|
2006-08-26 13:35:28 +02:00
|
|
|
|
|
|
|
|
//--------------------
|
|
|
|
|
// Default: Just iterate
|
2020-01-21 23:35:56 +01:00
|
|
|
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateChildren(nodep);
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public:
|
2019-09-12 13:22:22 +02:00
|
|
|
// CONSTRUCTORS
|
2015-10-04 04:33:06 +02:00
|
|
|
explicit CastVisitor(AstNetlist* nodep) {
|
2018-05-11 02:55:37 +02:00
|
|
|
iterate(nodep);
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
|
|
|
|
virtual ~CastVisitor() {}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//######################################################################
|
|
|
|
|
// Cast class functions
|
|
|
|
|
|
|
|
|
|
void V3Cast::castAll(AstNetlist* nodep) {
|
|
|
|
|
UINFO(2,__FUNCTION__<<": "<<endl);
|
2018-03-10 18:57:50 +01:00
|
|
|
{
|
|
|
|
|
CastVisitor visitor (nodep);
|
|
|
|
|
} // Destruct before checking
|
2017-09-18 04:52:57 +02:00
|
|
|
V3Global::dumpCheckGlobalTree("cast", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|