verilator/src/V3WidthCommit.h

178 lines
6.1 KiB
C++
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// -*- mode: C++; c-file-style: "cc-mode" -*-
//*************************************************************************
// DESCRIPTION: Verilator: Cleanup stage in V3Width
//
// Code available from: http://www.veripool.org/verilator
//
//*************************************************************************
//
// Copyright 2003-2018 by Wilson Snyder. 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.
//
// 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.
//
//*************************************************************************
#ifndef _V3WIDTHCOMMIT_H_
#define _V3WIDTHCOMMIT_H_ 1
#include "config_build.h"
#include "verilatedos.h"
#include "V3Error.h"
#include "V3Ast.h"
#ifndef _V3WIDTH_CPP_
# error "V3WidthCommit for V3Width internal use only"
#endif
//######################################################################
/// Remove all $signed, $unsigned, we're done with them.
/// This step is only called on real V3Width, not intermediate e.g. widthParams
class WidthRemoveVisitor : public AstNVisitor {
private:
// VISITORS
virtual void visit(AstSigned* nodep) {
replaceWithSignedVersion(nodep, nodep->lhsp()->unlinkFrBack()); VL_DANGLING(nodep);
}
virtual void visit(AstUnsigned* nodep) {
replaceWithSignedVersion(nodep, nodep->lhsp()->unlinkFrBack()); VL_DANGLING(nodep);
}
virtual void visit(AstNode* nodep) {
iterateChildren(nodep);
}
void replaceWithSignedVersion(AstNode* nodep, AstNode* newp) {
UINFO(6," Replace "<<nodep<<" w/ "<<newp<<endl);
nodep->replaceWith(newp);
newp->dtypeFrom(nodep);
pushDeletep(nodep); VL_DANGLING(nodep);
}
public:
// CONSTRUCTORS
WidthRemoveVisitor() {}
virtual ~WidthRemoveVisitor() {}
AstNode* mainAcceptEdit(AstNode* nodep) {
return iterateSubtreeReturnEdits(nodep);
}
};
//######################################################################
// Now that all widthing is complete,
// Copy all width() to widthMin(). V3Const expects this
class WidthCommitVisitor : public AstNVisitor {
// NODE STATE
// AstVar::user1p -> bool, processed
AstUser1InUse m_inuser1;
public:
// METHODS
static AstConst* newIfConstCommitSize(AstConst* nodep) {
if (((nodep->dtypep()->width() != nodep->num().width())
|| !nodep->num().sized())
&& !nodep->num().isString()) { // Need to force the number from unsized to sized
V3Number num (nodep->fileline(), nodep->dtypep()->width());
num.opAssign(nodep->num());
num.isSigned(nodep->isSigned());
AstConst* newp = new AstConst(nodep->fileline(), num);
newp->dtypeFrom(nodep);
return newp;
} else {
return NULL;
}
}
private:
// METHODS
void editDType(AstNode* nodep) {
// Edit dtypes for this node
nodep->dtypep(editOneDType(nodep->dtypep()));
}
AstNodeDType* editOneDType(AstNodeDType* nodep) {
// See if the dtype/refDType can be converted to a standard one
// This reduces the number of dtypes in the system, and since
// dtypep() figures into sameTree() results in better optimizations
if (!nodep) return NULL;
// Recurse to handle the data type, as may change the size etc of this type
if (!nodep->user1()) iterate(nodep);
// Look for duplicate
if (AstBasicDType* bdtypep = VN_CAST(nodep, BasicDType)) {
AstBasicDType* newp = nodep->findInsertSameDType(bdtypep);
if (newp != bdtypep && debug()>=9) {
UINFO(9,"dtype replacement "); nodep->dumpSmall(cout);
cout<<" ----> "; newp->dumpSmall(cout); cout<<endl;
}
return newp;
}
return nodep;
}
// VISITORS
virtual void visit(AstConst* nodep) {
if (!nodep->dtypep()) nodep->v3fatalSrc("No dtype");
iterate(nodep->dtypep()); // Do datatype first
if (AstConst* newp = newIfConstCommitSize(nodep)) {
nodep->replaceWith(newp);
AstNode* oldp = nodep; nodep = newp;
//if (debug()>4) oldp->dumpTree(cout," fixConstSize_old: ");
//if (debug()>4) newp->dumpTree(cout," _new: ");
pushDeletep(oldp); VL_DANGLING(oldp);
}
editDType(nodep);
}
virtual void visit(AstNodeDType* nodep) {
visitIterateNodeDType(nodep);
}
virtual void visit(AstNodeClassDType* nodep) {
if (nodep->user1SetOnce()) return; // Process once
visitIterateNodeDType(nodep);
nodep->clearCache();
}
virtual void visit(AstParamTypeDType* nodep) {
if (nodep->user1SetOnce()) return; // Process once
visitIterateNodeDType(nodep);
// Move to type table as all dtype pointers must resolve there
nodep->unlinkFrBack(); // Make non-child
v3Global.rootp()->typeTablep()->addTypesp(nodep);
}
void visitIterateNodeDType(AstNodeDType* nodep) {
// Rather than use dtypeChg which may make new nodes, we simply edit in place,
// as we don't need to preserve any widthMin's, and every dtype with the same width
// gets an identical edit.
if (nodep->user1SetOnce()) return; // Process once
nodep->widthMinFromWidth();
// Too late to any unspecified sign to be anything but unsigned
if (nodep->numeric().isNosign()) nodep->numeric(AstNumeric::UNSIGNED);
iterateChildren(nodep);
nodep->virtRefDTypep(editOneDType(nodep->virtRefDTypep()));
}
virtual void visit(AstNodePreSel* nodep) {
// This check could go anywhere after V3Param
nodep->v3fatalSrc("Presels should have been removed before this point");
}
virtual void visit(AstNode* nodep) {
iterateChildren(nodep);
editDType(nodep);
}
public:
// CONSTUCTORS
explicit WidthCommitVisitor(AstNetlist* nodep) {
// Were changing widthMin's, so the table is now somewhat trashed
nodep->typeTablep()->clearCache();
iterate(nodep);
// Don't want to repairCache, as all needed nodes have been added back in
// a repair would prevent dead nodes from being detected
}
virtual ~WidthCommitVisitor() {}
};
//######################################################################
#endif // Guard