2012-04-13 03:08:20 +02:00
|
|
|
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
2009-10-25 21:53:55 +01:00
|
|
|
//*************************************************************************
|
|
|
|
|
// DESCRIPTION: Verilator: Expression width calculations
|
|
|
|
|
//
|
2019-11-08 04:33:59 +01:00
|
|
|
// Code available from: https://verilator.org
|
2009-10-25 21:53:55 +01:00
|
|
|
//
|
|
|
|
|
//*************************************************************************
|
|
|
|
|
//
|
2023-01-01 16:18:39 +01:00
|
|
|
// Copyright 2003-2023 by Wilson Snyder. This program is free software; you
|
2020-03-21 16:24:24 +01:00
|
|
|
// can redistribute it and/or modify it under the terms of either the GNU
|
2009-10-25 21:53:55 +01:00
|
|
|
// Lesser General Public License Version 3 or the Perl Artistic License
|
|
|
|
|
// Version 2.0.
|
2020-03-21 16:24:24 +01:00
|
|
|
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
2009-10-25 21:53:55 +01:00
|
|
|
//
|
|
|
|
|
//*************************************************************************
|
|
|
|
|
// V3WidthSel's Transformations:
|
2019-05-19 22:13:13 +02:00
|
|
|
// Top down traversal:
|
|
|
|
|
// Replace SELPLUS/SELMINUS with SEL
|
|
|
|
|
// Replace SELEXTRACT with SEL
|
|
|
|
|
// Replace SELBIT with SEL or ARRAYSEL
|
2009-10-25 21:53:55 +01:00
|
|
|
//
|
2023-03-21 01:44:11 +01:00
|
|
|
// This code was once in V3LinkResolve, but ascending bit range vectors won't
|
2009-10-25 21:53:55 +01:00
|
|
|
// work that early. It was considered for V3Width and V3Param, but is
|
|
|
|
|
// fairly ugly both places as the nodes change in too strongly
|
|
|
|
|
// interconnected ways.
|
|
|
|
|
//
|
|
|
|
|
//*************************************************************************
|
2019-10-05 02:17:11 +02:00
|
|
|
|
2023-10-18 04:50:27 +02:00
|
|
|
#include "V3PchAstNoMT.h" // VL_MT_DISABLED_CODE_UNIT
|
2023-10-18 12:37:46 +02:00
|
|
|
|
|
|
|
|
#include "V3Const.h"
|
2022-08-05 11:56:57 +02:00
|
|
|
#include "V3Width.h"
|
2009-10-25 21:53:55 +01:00
|
|
|
|
2022-09-18 21:53:42 +02:00
|
|
|
VL_DEFINE_DEBUG_FUNCTIONS;
|
|
|
|
|
|
2009-10-25 21:53:55 +01:00
|
|
|
//######################################################################
|
|
|
|
|
// Width state, as a visitor of each AstNode
|
|
|
|
|
|
2022-01-02 19:56:40 +01:00
|
|
|
class WidthSelVisitor final : public VNVisitor {
|
2009-10-25 21:53:55 +01:00
|
|
|
private:
|
|
|
|
|
// IMPORTANT
|
|
|
|
|
//**** This is not a normal visitor, in that all iteration is instead
|
|
|
|
|
// done by the caller (V3Width). This avoids duplicating much of the
|
|
|
|
|
// complicated GenCase/GenFor/Cell/Function call logic that all depends
|
|
|
|
|
// on if widthing top-down or just for parameters.
|
|
|
|
|
#define iterateChildren DO_NOT_iterateChildern_IN_V3WidthSel
|
|
|
|
|
|
|
|
|
|
// METHODS
|
|
|
|
|
|
|
|
|
|
void checkConstantOrReplace(AstNode* nodep, const string& message) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// See also V3Width::checkConstantOrReplace
|
|
|
|
|
// Note can't call V3Const::constifyParam(nodep) here, as constify may change nodep on us!
|
2018-02-02 03:32:58 +01:00
|
|
|
if (!VN_IS(nodep, Const)) {
|
2019-05-19 22:13:13 +02:00
|
|
|
nodep->v3error(message);
|
2022-11-21 02:13:55 +01:00
|
|
|
nodep->replaceWith(new AstConst{nodep->fileline(), AstConst::Unsized32{}, 1});
|
2020-01-17 02:17:11 +01:00
|
|
|
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2009-10-25 21:53:55 +01:00
|
|
|
}
|
|
|
|
|
|
2013-01-13 20:49:53 +01:00
|
|
|
// RETURN TYPE
|
|
|
|
|
struct FromData {
|
2021-11-13 19:50:44 +01:00
|
|
|
AstNodeDType* const m_errp; // Node that was found, for error reporting if not known type
|
|
|
|
|
AstNodeDType* const m_dtypep; // Data type for the 'from' slice
|
2019-05-19 22:13:13 +02:00
|
|
|
VNumRange m_fromRange; // Numeric range bounds for the 'from' slice
|
2020-08-15 19:11:27 +02:00
|
|
|
FromData(AstNodeDType* errp, AstNodeDType* dtypep, const VNumRange& fromRange)
|
2020-08-16 15:55:36 +02:00
|
|
|
: m_errp{errp}
|
|
|
|
|
, m_dtypep{dtypep}
|
|
|
|
|
, m_fromRange{fromRange} {}
|
2020-11-17 01:56:16 +01:00
|
|
|
~FromData() = default;
|
2013-01-13 20:49:53 +01:00
|
|
|
};
|
2022-07-30 16:01:25 +02:00
|
|
|
static FromData fromDataForArray(AstNode* nodep, AstNode* basefromp) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// What is the data type and information for this SEL-ish's from()?
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(9, " fromData start ddtypep = " << basefromp << endl);
|
2019-05-19 22:13:13 +02:00
|
|
|
VNumRange fromRange; // constructs to isRanged(false)
|
|
|
|
|
while (basefromp) {
|
2018-02-02 03:32:58 +01:00
|
|
|
if (VN_IS(basefromp, AttrOf)) {
|
2021-10-22 14:56:48 +02:00
|
|
|
basefromp = VN_AS(basefromp, AttrOf)->fromp();
|
2019-05-19 22:13:13 +02:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
2019-07-06 18:57:50 +02:00
|
|
|
UASSERT_OBJ(basefromp && basefromp->dtypep(), nodep, "Select with no from dtype");
|
2021-11-13 19:50:44 +01:00
|
|
|
AstNodeDType* const ddtypep = basefromp->dtypep()->skipRefp();
|
|
|
|
|
AstNodeDType* const errp = ddtypep;
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(9, " fromData.ddtypep = " << ddtypep << endl);
|
2021-11-13 19:50:44 +01:00
|
|
|
if (const AstNodeArrayDType* const adtypep = VN_CAST(ddtypep, NodeArrayDType)) {
|
2019-05-19 22:13:13 +02:00
|
|
|
fromRange = adtypep->declRange();
|
2020-04-15 13:58:34 +02:00
|
|
|
} else if (VN_IS(ddtypep, AssocArrayDType)) {
|
2022-07-20 15:01:36 +02:00
|
|
|
} else if (VN_IS(ddtypep, WildcardArrayDType)) {
|
2020-04-15 13:58:34 +02:00
|
|
|
} else if (VN_IS(ddtypep, DynArrayDType)) {
|
|
|
|
|
} else if (VN_IS(ddtypep, QueueDType)) {
|
2021-11-26 23:55:36 +01:00
|
|
|
} else if (const AstNodeUOrStructDType* const adtypep
|
|
|
|
|
= VN_CAST(ddtypep, NodeUOrStructDType)) {
|
2019-05-19 22:13:13 +02:00
|
|
|
fromRange = adtypep->declRange();
|
2021-11-26 23:55:36 +01:00
|
|
|
} else if (const AstBasicDType* const adtypep = VN_CAST(ddtypep, BasicDType)) {
|
2020-01-26 22:38:22 +01:00
|
|
|
if (adtypep->isString() && VN_IS(nodep, SelBit)) {
|
|
|
|
|
} else if (adtypep->isRanged()) {
|
2020-04-15 13:58:34 +02:00
|
|
|
UASSERT_OBJ(
|
|
|
|
|
!(adtypep->rangep()
|
2020-12-07 03:13:56 +01:00
|
|
|
&& (!VN_IS(adtypep->rangep()->leftp(), Const)
|
|
|
|
|
|| !VN_IS(adtypep->rangep()->rightp(), Const))),
|
2020-04-15 13:58:34 +02:00
|
|
|
nodep,
|
|
|
|
|
"Non-constant variable range; errored earlier"); // in constifyParam(bfdtypep)
|
2019-05-19 22:13:13 +02:00
|
|
|
fromRange = adtypep->declRange();
|
|
|
|
|
} else {
|
2020-01-26 21:54:57 +01:00
|
|
|
nodep->v3error("Illegal bit or array select; type does not have a bit range, or "
|
|
|
|
|
<< "bad dimension: data type is " << errp->prettyDTypeNameQ());
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2020-04-15 13:58:34 +02:00
|
|
|
} else {
|
2020-01-26 21:54:57 +01:00
|
|
|
nodep->v3error("Illegal bit or array select; type already selected, or bad dimension: "
|
|
|
|
|
<< "data type is " << errp->prettyDTypeNameQ());
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
|
|
|
|
return FromData(errp, ddtypep, fromRange);
|
2009-10-25 21:53:55 +01:00
|
|
|
}
|
|
|
|
|
|
2022-11-13 21:33:11 +01:00
|
|
|
AstNodeExpr* newSubNeg(AstNodeExpr* lhsp, int32_t rhs) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Return lhs-rhs, but if rhs is negative use an add, so we won't
|
|
|
|
|
// have to deal with signed math and related 32bit sign extension problems
|
|
|
|
|
if (rhs == 0) {
|
|
|
|
|
return lhsp;
|
2018-02-02 03:32:58 +01:00
|
|
|
} else if (VN_IS(lhsp, Const)) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Optional vs just making add/sub below, but saves constification some work
|
2020-04-15 13:58:34 +02:00
|
|
|
V3Number num(lhsp, lhsp->width());
|
2021-10-22 14:56:48 +02:00
|
|
|
num.opSub(VN_AS(lhsp, Const)->num(), V3Number(lhsp, 32, rhs));
|
2019-05-10 02:03:19 +02:00
|
|
|
num.isSigned(lhsp->isSigned());
|
2022-11-21 02:13:55 +01:00
|
|
|
return new AstConst{lhsp->fileline(), num};
|
2019-05-19 22:13:13 +02:00
|
|
|
} else if (rhs > 0) {
|
2022-11-13 21:33:11 +01:00
|
|
|
AstNodeExpr* const newp
|
2022-11-21 02:13:55 +01:00
|
|
|
= new AstSub{lhsp->fileline(), lhsp,
|
|
|
|
|
new AstConst(lhsp->fileline(), AstConst::Unsized32{}, rhs)};
|
2019-05-19 22:13:13 +02:00
|
|
|
// We must make sure sub gets sign of original value, not from the constant
|
|
|
|
|
newp->dtypeFrom(lhsp);
|
|
|
|
|
return newp;
|
|
|
|
|
} else { // rhs < 0;
|
2022-11-13 21:33:11 +01:00
|
|
|
AstNodeExpr* const newp
|
2022-11-21 02:13:55 +01:00
|
|
|
= new AstAdd{lhsp->fileline(), lhsp,
|
|
|
|
|
new AstConst(lhsp->fileline(), AstConst::Unsized32{}, -rhs)};
|
2019-05-19 22:13:13 +02:00
|
|
|
// We must make sure sub gets sign of original value, not from the constant
|
|
|
|
|
newp->dtypeFrom(lhsp);
|
|
|
|
|
return newp;
|
|
|
|
|
}
|
2009-10-25 21:53:55 +01:00
|
|
|
}
|
2022-11-13 21:33:11 +01:00
|
|
|
AstNodeExpr* newSubNeg(int32_t lhs, AstNodeExpr* rhsp) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Return lhs-rhs
|
|
|
|
|
// We must make sure sub gets sign of original value
|
2022-11-21 02:13:55 +01:00
|
|
|
AstNodeExpr* const newp = new AstSub{
|
|
|
|
|
rhsp->fileline(), new AstConst(rhsp->fileline(), AstConst::Unsized32{}, lhs), rhsp};
|
2019-05-19 22:13:13 +02:00
|
|
|
newp->dtypeFrom(rhsp); // Important as AstSub default is lhs's sign
|
|
|
|
|
return newp;
|
2009-10-25 21:53:55 +01:00
|
|
|
}
|
|
|
|
|
|
2022-11-13 21:33:11 +01:00
|
|
|
AstNodeExpr* newSubLsbOf(AstNodeExpr* underp, const VNumRange& fromRange) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Account for a variable's LSB in bit selections
|
|
|
|
|
// Will likely become SUB(underp, lsb_of_signal).
|
|
|
|
|
// Don't report WIDTH warnings etc here, as may be inside a
|
|
|
|
|
// generate branch that will be deleted.
|
|
|
|
|
// SUB #'s Not needed when LSB==0 and MSB>=0 (ie [0:-13] must still get added!)
|
|
|
|
|
if (!fromRange.ranged()) {
|
|
|
|
|
// vector without range, or 0 lsb is ok, for example a INTEGER x; y = x[21:0];
|
|
|
|
|
return underp;
|
|
|
|
|
} else {
|
2023-03-21 01:44:11 +01:00
|
|
|
if (fromRange.ascending()) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// reg [1:3] was swapped to [3:1] (lsbEndianedp==3) and needs a SUB(3,under)
|
2022-11-13 21:33:11 +01:00
|
|
|
return newSubNeg(fromRange.hi(), underp);
|
2019-05-19 22:13:13 +02:00
|
|
|
} else {
|
|
|
|
|
// reg [3:1] needs a SUB(under,1)
|
2022-11-13 21:33:11 +01:00
|
|
|
return newSubNeg(underp, fromRange.lo());
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
|
|
|
|
}
|
2009-10-25 21:53:55 +01:00
|
|
|
}
|
|
|
|
|
|
2014-03-08 20:41:11 +01:00
|
|
|
AstNodeDType* sliceDType(AstPackArrayDType* nodep, int msb, int lsb) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Return slice needed for msb/lsb, either as original dtype or a new slice dtype
|
2020-04-15 13:58:34 +02:00
|
|
|
if (nodep->declRange().elements() == (msb - lsb + 1) // Extracting whole of original array
|
2019-05-19 22:13:13 +02:00
|
|
|
&& nodep->declRange().lo() == lsb) {
|
|
|
|
|
return nodep;
|
|
|
|
|
} else {
|
|
|
|
|
// Need a slice data type, which is an array of the extracted
|
|
|
|
|
// type, but with (presumably) different size
|
2023-03-21 01:44:11 +01:00
|
|
|
const VNumRange newRange{msb, lsb, nodep->declRange().ascending()};
|
2021-11-13 19:50:44 +01:00
|
|
|
AstNodeDType* const vardtypep
|
2022-11-21 02:13:55 +01:00
|
|
|
= new AstPackArrayDType{nodep->fileline(),
|
2019-05-19 22:13:13 +02:00
|
|
|
nodep->subDTypep(), // Need to strip off array reference
|
2022-11-21 02:13:55 +01:00
|
|
|
new AstRange{nodep->fileline(), newRange}};
|
2019-05-19 22:13:13 +02:00
|
|
|
v3Global.rootp()->typeTablep()->addTypesp(vardtypep);
|
|
|
|
|
return vardtypep;
|
|
|
|
|
}
|
2014-03-08 20:41:11 +01:00
|
|
|
}
|
|
|
|
|
|
2023-04-01 21:23:39 +02:00
|
|
|
AstNodeExpr* selQueueBackness(AstNode* nodep) {
|
|
|
|
|
if (VN_IS(nodep, Unbounded)) { // e.g. "[$]"
|
|
|
|
|
return new AstConst{nodep->fileline(), AstConst::Signed32{}, 0};
|
|
|
|
|
} else if (VN_IS(nodep, Sub) && VN_IS(VN_CAST(nodep, Sub)->lhsp(), Unbounded)) {
|
|
|
|
|
// e.g. "q[$ - 1]", where 1 is subnodep
|
|
|
|
|
AstNodeExpr* subrhsp = VN_CAST(nodep, Sub)->rhsp()->unlinkFrBack();
|
|
|
|
|
return subrhsp;
|
|
|
|
|
} else {
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-05 01:40:50 +02:00
|
|
|
void warnTri(AstNode* nodep) {
|
2021-10-22 14:56:48 +02:00
|
|
|
if (VN_IS(nodep, Const) && VN_AS(nodep, Const)->num().isFourState()) {
|
2020-05-05 01:40:50 +02:00
|
|
|
nodep->v3error(
|
|
|
|
|
"Selection index is constantly unknown or tristated: " << nodep->name());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-10-25 21:53:55 +01:00
|
|
|
// VISITORS
|
2020-01-25 02:10:44 +01:00
|
|
|
// If adding new visitors, ensure V3Width's visit(TYPE) calls into here
|
2009-10-25 21:53:55 +01:00
|
|
|
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstSelBit* nodep) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Select of a non-width specified part of an array, i.e. "array[2]"
|
|
|
|
|
// This select style has a lsb and msb (no user specified width)
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(6, "SELBIT " << nodep << endl);
|
2022-11-27 14:31:22 +01:00
|
|
|
if (debug() >= 9) nodep->backp()->dumpTree("- SELBT0: ");
|
2019-05-19 22:13:13 +02:00
|
|
|
// lhsp/rhsp do not need to be constant
|
2022-11-13 21:33:11 +01:00
|
|
|
AstNodeExpr* const fromp = nodep->fromp()->unlinkFrBack();
|
|
|
|
|
AstNodeExpr* const rhsp = nodep->rhsp()->unlinkFrBack(); // bit we're extracting
|
2022-11-27 14:31:22 +01:00
|
|
|
if (debug() >= 9) nodep->dumpTree("- SELBT2: ");
|
2021-06-21 00:32:57 +02:00
|
|
|
const FromData fromdata = fromDataForArray(nodep, fromp);
|
2021-11-13 19:50:44 +01:00
|
|
|
AstNodeDType* const ddtypep = fromdata.m_dtypep;
|
2021-06-21 00:32:57 +02:00
|
|
|
const VNumRange fromRange = fromdata.m_fromRange;
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(6, " ddtypep " << ddtypep << endl);
|
2021-11-26 23:55:36 +01:00
|
|
|
if (const AstUnpackArrayDType* const adtypep = VN_CAST(ddtypep, UnpackArrayDType)) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// SELBIT(array, index) -> ARRAYSEL(array, index)
|
2022-11-13 21:33:11 +01:00
|
|
|
AstNodeExpr* subp = rhsp;
|
2020-04-15 13:58:34 +02:00
|
|
|
if (fromRange.lo() != 0 || fromRange.hi() < 0) {
|
2018-08-25 15:52:45 +02:00
|
|
|
subp = newSubNeg(subp, fromRange.lo());
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2022-11-21 02:13:55 +01:00
|
|
|
AstArraySel* const newp = new AstArraySel{nodep->fileline(), fromp, subp};
|
2019-05-19 22:13:13 +02:00
|
|
|
newp->dtypeFrom(adtypep->subDTypep()); // Need to strip off array reference
|
2022-11-27 14:31:22 +01:00
|
|
|
if (debug() >= 9) newp->dumpTree("- SELBTn: ");
|
2020-04-15 13:58:34 +02:00
|
|
|
nodep->replaceWith(newp);
|
|
|
|
|
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
2021-11-26 23:55:36 +01:00
|
|
|
} else if (const AstPackArrayDType* const adtypep = VN_CAST(ddtypep, PackArrayDType)) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// SELBIT(array, index) -> SEL(array, index*width-of-subindex, width-of-subindex)
|
2022-11-13 21:33:11 +01:00
|
|
|
AstNodeExpr* subp = rhsp;
|
2023-03-21 01:44:11 +01:00
|
|
|
if (fromRange.ascending()) {
|
2020-12-13 22:23:59 +01:00
|
|
|
subp = newSubNeg(fromRange.hi(), subp);
|
|
|
|
|
} else {
|
|
|
|
|
subp = newSubNeg(subp, fromRange.lo());
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2020-04-15 13:58:34 +02:00
|
|
|
UASSERT_OBJ(!(!fromRange.elements() || (adtypep->width() % fromRange.elements()) != 0),
|
|
|
|
|
adtypep,
|
|
|
|
|
"Array extraction with width miscomputed " << adtypep->width() << "/"
|
|
|
|
|
<< fromRange.elements());
|
2023-09-01 00:29:58 +02:00
|
|
|
// cppcheck-suppress zerodivcond
|
2021-06-21 00:32:57 +02:00
|
|
|
const int elwidth = adtypep->width() / fromRange.elements();
|
2022-11-21 02:13:55 +01:00
|
|
|
AstSel* const newp = new AstSel{
|
2020-04-15 13:58:34 +02:00
|
|
|
nodep->fileline(), fromp,
|
2022-11-21 02:13:55 +01:00
|
|
|
new AstMul{nodep->fileline(),
|
|
|
|
|
new AstConst(nodep->fileline(), AstConst::Unsized32{}, elwidth), subp},
|
|
|
|
|
new AstConst(nodep->fileline(), AstConst::Unsized32{}, elwidth)};
|
2019-05-19 22:13:13 +02:00
|
|
|
newp->declRange(fromRange);
|
|
|
|
|
newp->declElWidth(elwidth);
|
|
|
|
|
newp->dtypeFrom(adtypep->subDTypep()); // Need to strip off array reference
|
2022-11-27 14:31:22 +01:00
|
|
|
if (debug() >= 9) newp->dumpTree("- SELBTn: ");
|
2020-04-15 13:58:34 +02:00
|
|
|
nodep->replaceWith(newp);
|
|
|
|
|
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
2021-11-26 23:55:36 +01:00
|
|
|
} else if (const AstAssocArrayDType* const adtypep = VN_CAST(ddtypep, AssocArrayDType)) {
|
2019-12-01 17:52:48 +01:00
|
|
|
// SELBIT(array, index) -> ASSOCSEL(array, index)
|
2023-04-01 21:23:39 +02:00
|
|
|
AstAssocSel* const newp = new AstAssocSel{nodep->fileline(), fromp, rhsp};
|
2019-12-01 17:52:48 +01:00
|
|
|
newp->dtypeFrom(adtypep->subDTypep()); // Need to strip off array reference
|
2022-11-27 14:31:22 +01:00
|
|
|
if (debug() >= 9) newp->dumpTree("- SELBTn: ");
|
2020-04-15 13:58:34 +02:00
|
|
|
nodep->replaceWith(newp);
|
|
|
|
|
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
2022-07-20 15:01:36 +02:00
|
|
|
} else if (const AstWildcardArrayDType* const adtypep
|
|
|
|
|
= VN_CAST(ddtypep, WildcardArrayDType)) {
|
|
|
|
|
// SELBIT(array, index) -> WILDCARDSEL(array, index)
|
2023-04-01 21:23:39 +02:00
|
|
|
AstWildcardSel* const newp = new AstWildcardSel{nodep->fileline(), fromp, rhsp};
|
2022-07-20 15:01:36 +02:00
|
|
|
newp->dtypeFrom(adtypep->subDTypep()); // Need to strip off array reference
|
2022-11-27 14:31:22 +01:00
|
|
|
if (debug() >= 9) newp->dumpTree("- SELBTn: ");
|
2022-07-20 15:01:36 +02:00
|
|
|
nodep->replaceWith(newp);
|
|
|
|
|
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
2021-11-26 23:55:36 +01:00
|
|
|
} else if (const AstDynArrayDType* const adtypep = VN_CAST(ddtypep, DynArrayDType)) {
|
2020-03-07 16:24:27 +01:00
|
|
|
// SELBIT(array, index) -> CMETHODCALL(queue, "at", index)
|
2023-04-01 21:23:39 +02:00
|
|
|
AstCMethodHard* const newp = new AstCMethodHard{nodep->fileline(), fromp, "at", rhsp};
|
2020-03-07 16:24:27 +01:00
|
|
|
newp->dtypeFrom(adtypep->subDTypep()); // Need to strip off queue reference
|
2022-11-27 14:31:22 +01:00
|
|
|
if (debug() >= 9) newp->dumpTree("- SELBTq: ");
|
2020-04-15 13:58:34 +02:00
|
|
|
nodep->replaceWith(newp);
|
|
|
|
|
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
2021-11-26 23:55:36 +01:00
|
|
|
} else if (const AstQueueDType* const adtypep = VN_CAST(ddtypep, QueueDType)) {
|
2019-12-01 18:35:49 +01:00
|
|
|
// SELBIT(array, index) -> CMETHODCALL(queue, "at", index)
|
2023-04-01 21:23:39 +02:00
|
|
|
AstCMethodHard* newp;
|
|
|
|
|
if (AstNodeExpr* const backnessp = selQueueBackness(rhsp)) {
|
|
|
|
|
newp = new AstCMethodHard{nodep->fileline(), fromp, "atBack", backnessp};
|
|
|
|
|
} else {
|
|
|
|
|
newp = new AstCMethodHard{nodep->fileline(), fromp, "at", rhsp};
|
|
|
|
|
}
|
2019-12-01 18:35:49 +01:00
|
|
|
newp->dtypeFrom(adtypep->subDTypep()); // Need to strip off queue reference
|
2022-11-27 14:31:22 +01:00
|
|
|
if (debug() >= 9) newp->dumpTree("- SELBTq: ");
|
2020-04-15 13:58:34 +02:00
|
|
|
nodep->replaceWith(newp);
|
|
|
|
|
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
|
|
|
|
} else if (VN_IS(ddtypep, BasicDType) && ddtypep->isString()) {
|
2020-01-26 22:38:22 +01:00
|
|
|
// SELBIT(string, index) -> GETC(string, index)
|
2021-11-26 23:55:36 +01:00
|
|
|
const AstNodeVarRef* const varrefp = VN_CAST(fromp, NodeVarRef);
|
2020-08-16 20:55:46 +02:00
|
|
|
if (!varrefp) {
|
2020-06-10 01:20:16 +02:00
|
|
|
nodep->v3warn(E_UNSUPPORTED,
|
|
|
|
|
"Unsupported: String array operation on non-variable");
|
2020-08-16 20:55:46 +02:00
|
|
|
}
|
2022-11-13 21:33:11 +01:00
|
|
|
AstNodeExpr* newp;
|
2020-10-31 03:28:51 +01:00
|
|
|
if (varrefp && varrefp->access().isReadOnly()) {
|
2022-11-21 02:13:55 +01:00
|
|
|
newp = new AstGetcN{nodep->fileline(), fromp, rhsp};
|
2020-10-31 03:28:51 +01:00
|
|
|
} else {
|
2022-11-21 02:13:55 +01:00
|
|
|
newp = new AstGetcRefN{nodep->fileline(), fromp, rhsp};
|
2020-01-26 22:38:22 +01:00
|
|
|
}
|
|
|
|
|
UINFO(6, " new " << newp << endl);
|
|
|
|
|
nodep->replaceWith(newp);
|
|
|
|
|
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
|
|
|
|
} else if (VN_IS(ddtypep, BasicDType)) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// SELBIT(range, index) -> SEL(array, index, 1)
|
2021-11-13 19:50:44 +01:00
|
|
|
AstSel* const newp
|
2022-11-21 02:13:55 +01:00
|
|
|
= new AstSel{nodep->fileline(), fromp, newSubLsbOf(rhsp, fromRange),
|
2021-11-13 19:50:44 +01:00
|
|
|
// Unsized so width from user
|
2022-11-21 02:13:55 +01:00
|
|
|
new AstConst{nodep->fileline(), AstConst::Unsized32{}, 1}};
|
2019-05-19 22:13:13 +02:00
|
|
|
newp->declRange(fromRange);
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(6, " new " << newp << endl);
|
2022-11-27 14:31:22 +01:00
|
|
|
if (debug() >= 9) newp->dumpTree("- SELBTn: ");
|
2020-04-15 13:58:34 +02:00
|
|
|
nodep->replaceWith(newp);
|
|
|
|
|
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
|
|
|
|
} else if (VN_IS(ddtypep, NodeUOrStructDType)) { // A bit from the packed struct
|
2019-05-19 22:13:13 +02:00
|
|
|
// SELBIT(range, index) -> SEL(array, index, 1)
|
2021-11-13 19:50:44 +01:00
|
|
|
AstSel* const newp
|
2022-11-21 02:13:55 +01:00
|
|
|
= new AstSel{nodep->fileline(), fromp, newSubLsbOf(rhsp, fromRange),
|
2021-11-13 19:50:44 +01:00
|
|
|
// Unsized so width from user
|
2022-11-21 02:13:55 +01:00
|
|
|
new AstConst{nodep->fileline(), AstConst::Unsized32{}, 1}};
|
2019-05-19 22:13:13 +02:00
|
|
|
newp->declRange(fromRange);
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(6, " new " << newp << endl);
|
2022-11-27 14:31:22 +01:00
|
|
|
if (debug() >= 9) newp->dumpTree("- SELBTn: ");
|
2020-04-15 13:58:34 +02:00
|
|
|
nodep->replaceWith(newp);
|
|
|
|
|
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
2020-08-15 16:12:55 +02:00
|
|
|
} else { // nullptr=bad extract, or unknown node type
|
2020-01-26 21:54:57 +01:00
|
|
|
nodep->v3error("Illegal bit or array select; type already selected, or bad dimension: "
|
|
|
|
|
<< "data type is" << fromdata.m_errp->prettyDTypeNameQ());
|
2019-05-19 22:13:13 +02:00
|
|
|
// How to recover? We'll strip a dimension.
|
2020-01-26 21:54:57 +01:00
|
|
|
nodep->replaceWith(fromp);
|
|
|
|
|
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2021-02-22 03:25:21 +01:00
|
|
|
if (!rhsp->backp()) VL_DO_DANGLING(pushDeletep(rhsp), rhsp);
|
2009-10-25 21:53:55 +01:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstSelExtract* nodep) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Select of a range specified part of an array, i.e. "array[2:3]"
|
|
|
|
|
// SELEXTRACT(from,msb,lsb) -> SEL(from, lsb, 1+msb-lsb)
|
|
|
|
|
// This select style has a (msb or lsb) and width
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(6, "SELEXTRACT " << nodep << endl);
|
2022-11-27 14:31:22 +01:00
|
|
|
// if (debug() >= 9) nodep->dumpTree("- SELEX0: ");
|
2019-05-19 22:13:13 +02:00
|
|
|
// Below 2 lines may change nodep->widthp()
|
2023-07-03 19:55:24 +02:00
|
|
|
V3Const::constifyParamsNoWarnEdit(nodep->leftp()); // May relink pointed to node
|
|
|
|
|
V3Const::constifyParamsNoWarnEdit(nodep->rightp()); // May relink pointed to node
|
2022-11-27 14:31:22 +01:00
|
|
|
// if (debug() >= 9) nodep->dumpTree("- SELEX3: ");
|
2023-04-01 21:23:39 +02:00
|
|
|
AstNodeExpr* const fromp = nodep->fromp()->unlinkFrBack();
|
|
|
|
|
const FromData fromdata = fromDataForArray(nodep, fromp);
|
|
|
|
|
AstNodeDType* const ddtypep = fromdata.m_dtypep;
|
|
|
|
|
const VNumRange fromRange = fromdata.m_fromRange;
|
|
|
|
|
if (VN_IS(ddtypep, QueueDType)) {
|
|
|
|
|
AstNodeExpr* const qleftp = nodep->rhsp()->unlinkFrBack();
|
|
|
|
|
AstNodeExpr* const qrightp = nodep->thsp()->unlinkFrBack();
|
|
|
|
|
AstNodeExpr* const qleftBacknessp = selQueueBackness(qleftp);
|
|
|
|
|
AstNodeExpr* const qrightBacknessp = selQueueBackness(qrightp);
|
|
|
|
|
// Use special methods to refer to back rather than math using
|
|
|
|
|
// queue size, this allows a single queue reference, to support
|
|
|
|
|
// for equations in side effects that select the queue to
|
|
|
|
|
// operate upon.
|
|
|
|
|
std::string name = (qleftBacknessp ? "sliceBackBack"
|
|
|
|
|
: qrightBacknessp ? "sliceFrontBack"
|
|
|
|
|
: "slice");
|
|
|
|
|
auto* const newp = new AstCMethodHard{nodep->fileline(), fromp, name,
|
|
|
|
|
qleftBacknessp ? qleftBacknessp : qleftp};
|
|
|
|
|
newp->addPinsp(qrightBacknessp ? qrightBacknessp : qrightp);
|
|
|
|
|
newp->dtypep(ddtypep);
|
|
|
|
|
newp->didWidth(true);
|
|
|
|
|
newp->protect(false);
|
|
|
|
|
UINFO(6, " new " << newp << endl);
|
|
|
|
|
nodep->replaceWith(newp);
|
|
|
|
|
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
// Non-queue
|
2020-12-07 03:13:56 +01:00
|
|
|
checkConstantOrReplace(nodep->leftp(),
|
2020-04-15 13:58:34 +02:00
|
|
|
"First value of [a:b] isn't a constant, maybe you want +: or -:");
|
2020-12-07 03:13:56 +01:00
|
|
|
checkConstantOrReplace(nodep->rightp(),
|
2020-04-15 13:58:34 +02:00
|
|
|
"Second value of [a:b] isn't a constant, maybe you want +: or -:");
|
2022-11-13 21:33:11 +01:00
|
|
|
AstNodeExpr* const msbp = nodep->rhsp()->unlinkFrBack();
|
|
|
|
|
AstNodeExpr* const lsbp = nodep->thsp()->unlinkFrBack();
|
2022-03-27 21:27:40 +02:00
|
|
|
int32_t msb = VN_AS(msbp, Const)->toSInt();
|
|
|
|
|
int32_t lsb = VN_AS(lsbp, Const)->toSInt();
|
|
|
|
|
const int32_t elem = (msb > lsb) ? (msb - lsb + 1) : (lsb - msb + 1);
|
2018-02-02 03:32:58 +01:00
|
|
|
if (VN_IS(ddtypep, UnpackArrayDType)) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Slice extraction
|
|
|
|
|
if (fromRange.elements() == elem
|
|
|
|
|
&& fromRange.lo() == lsb) { // Extracting whole of original array
|
2020-04-15 13:58:34 +02:00
|
|
|
nodep->replaceWith(fromp);
|
|
|
|
|
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
2017-11-23 20:55:32 +01:00
|
|
|
} else if (fromRange.elements() == 1) { // Extracting single element
|
2022-11-21 02:13:55 +01:00
|
|
|
AstArraySel* const newp = new AstArraySel{nodep->fileline(), fromp, lsbp};
|
2020-04-15 13:58:34 +02:00
|
|
|
nodep->replaceWith(newp);
|
|
|
|
|
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
2017-11-23 20:55:32 +01:00
|
|
|
} else { // Slice
|
2021-11-13 19:50:44 +01:00
|
|
|
AstSliceSel* const newp
|
2020-12-07 03:13:56 +01:00
|
|
|
= new AstSliceSel{nodep->fileline(), fromp,
|
|
|
|
|
VNumRange{msb - fromRange.lo(), lsb - fromRange.lo()}};
|
2020-04-15 13:58:34 +02:00
|
|
|
nodep->replaceWith(newp);
|
|
|
|
|
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
2017-11-23 20:55:32 +01:00
|
|
|
}
|
2021-11-26 23:55:36 +01:00
|
|
|
} else if (AstPackArrayDType* const adtypep = VN_CAST(ddtypep, PackArrayDType)) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// SELEXTRACT(array, msb, lsb) -> SEL(array,
|
|
|
|
|
// lsb*width-of-subindex, width-of-subindex*(msb-lsb))
|
2020-04-15 13:58:34 +02:00
|
|
|
UASSERT_OBJ(!(!fromRange.elements() || (adtypep->width() % fromRange.elements()) != 0),
|
|
|
|
|
adtypep,
|
|
|
|
|
"Array extraction with width miscomputed " << adtypep->width() << "/"
|
|
|
|
|
<< fromRange.elements());
|
2023-03-21 01:44:11 +01:00
|
|
|
if (fromRange.ascending()) {
|
|
|
|
|
// Below code assumes descending bit range; just works out if we swap
|
2021-11-26 23:55:36 +01:00
|
|
|
const int x = msb;
|
2020-04-15 13:58:34 +02:00
|
|
|
msb = lsb;
|
|
|
|
|
lsb = x;
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
|
|
|
|
if (lsb > msb) {
|
2021-01-15 13:31:48 +01:00
|
|
|
nodep->v3warn(
|
|
|
|
|
SELRANGE,
|
|
|
|
|
"[" << msb << ":" << lsb
|
2023-03-21 01:44:11 +01:00
|
|
|
<< "] Slice range has ascending bit ordering, perhaps you wanted [" << lsb
|
2021-01-15 13:31:48 +01:00
|
|
|
<< ":" << msb << "]");
|
2021-11-26 23:55:36 +01:00
|
|
|
const int x = msb;
|
2020-04-15 13:58:34 +02:00
|
|
|
msb = lsb;
|
|
|
|
|
lsb = x;
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2021-06-21 00:32:57 +02:00
|
|
|
const int elwidth = adtypep->width() / fromRange.elements();
|
2022-11-21 02:13:55 +01:00
|
|
|
AstSel* const newp = new AstSel{
|
2020-04-15 13:58:34 +02:00
|
|
|
nodep->fileline(), fromp,
|
2022-11-21 02:13:55 +01:00
|
|
|
new AstMul{nodep->fileline(), newSubLsbOf(lsbp, fromRange),
|
|
|
|
|
new AstConst(nodep->fileline(), AstConst::Unsized32{}, elwidth)},
|
|
|
|
|
new AstConst(nodep->fileline(), AstConst::Unsized32{}, (msb - lsb + 1) * elwidth)};
|
2019-05-19 22:13:13 +02:00
|
|
|
newp->declRange(fromRange);
|
|
|
|
|
newp->declElWidth(elwidth);
|
|
|
|
|
newp->dtypeFrom(sliceDType(adtypep, msb, lsb));
|
2022-11-27 14:31:22 +01:00
|
|
|
// if (debug() >= 9) newp->dumpTree("- EXTBTn: ");
|
2019-07-06 18:57:50 +02:00
|
|
|
UASSERT_OBJ(newp->widthMin() == newp->widthConst(), nodep, "Width mismatch");
|
2020-04-15 13:58:34 +02:00
|
|
|
nodep->replaceWith(newp);
|
|
|
|
|
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
|
|
|
|
} else if (VN_IS(ddtypep, BasicDType)) {
|
2023-03-21 01:44:11 +01:00
|
|
|
if (fromRange.ascending()) {
|
|
|
|
|
// Below code assumes descending bit range; just works out if we swap
|
2021-11-26 23:55:36 +01:00
|
|
|
const int x = msb;
|
2020-04-15 13:58:34 +02:00
|
|
|
msb = lsb;
|
|
|
|
|
lsb = x;
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
|
|
|
|
if (lsb > msb) {
|
2021-01-15 13:31:48 +01:00
|
|
|
nodep->v3warn(
|
|
|
|
|
SELRANGE,
|
|
|
|
|
"[" << msb << ":" << lsb
|
2023-03-21 01:44:11 +01:00
|
|
|
<< "] Slice range has ascending bit ordering, perhaps you wanted [" << lsb
|
2021-01-15 13:31:48 +01:00
|
|
|
<< ":" << msb << "]");
|
2021-11-26 23:55:36 +01:00
|
|
|
const int x = msb;
|
2020-04-15 13:58:34 +02:00
|
|
|
msb = lsb;
|
|
|
|
|
lsb = x;
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2022-11-21 02:13:55 +01:00
|
|
|
AstNodeExpr* const widthp = new AstConst(
|
|
|
|
|
msbp->fileline(), AstConst::Unsized32{}, // Unsized so width from user
|
|
|
|
|
msb + 1 - lsb);
|
2021-11-13 19:50:44 +01:00
|
|
|
AstSel* const newp
|
2022-11-21 02:13:55 +01:00
|
|
|
= new AstSel{nodep->fileline(), fromp, newSubLsbOf(lsbp, fromRange), widthp};
|
2019-05-19 22:13:13 +02:00
|
|
|
newp->declRange(fromRange);
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(6, " new " << newp << endl);
|
2022-11-27 14:31:22 +01:00
|
|
|
// if (debug() >= 9) newp->dumpTree("- SELEXnew: ");
|
2020-04-15 13:58:34 +02:00
|
|
|
nodep->replaceWith(newp);
|
|
|
|
|
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
|
|
|
|
} else if (VN_IS(ddtypep, NodeUOrStructDType)) {
|
2023-03-21 01:44:11 +01:00
|
|
|
// Classes don't have an ascending range
|
2019-05-19 22:13:13 +02:00
|
|
|
if (lsb > msb) {
|
2021-01-15 13:31:48 +01:00
|
|
|
nodep->v3warn(
|
|
|
|
|
SELRANGE,
|
|
|
|
|
"[" << msb << ":" << lsb
|
2023-03-21 01:44:11 +01:00
|
|
|
<< "] Slice range has ascending bit ordering, perhaps you wanted [" << lsb
|
2021-01-15 13:31:48 +01:00
|
|
|
<< ":" << msb << "]");
|
2021-11-26 23:55:36 +01:00
|
|
|
const int x = msb;
|
2020-04-15 13:58:34 +02:00
|
|
|
msb = lsb;
|
|
|
|
|
lsb = x;
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2022-11-21 02:13:55 +01:00
|
|
|
AstNodeExpr* const widthp = new AstConst(
|
|
|
|
|
msbp->fileline(), AstConst::Unsized32{}, // Unsized so width from user
|
|
|
|
|
msb + 1 - lsb);
|
2021-11-13 19:50:44 +01:00
|
|
|
AstSel* const newp
|
2022-11-21 02:13:55 +01:00
|
|
|
= new AstSel{nodep->fileline(), fromp, newSubLsbOf(lsbp, fromRange), widthp};
|
2019-05-19 22:13:13 +02:00
|
|
|
newp->declRange(fromRange);
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(6, " new " << newp << endl);
|
2022-11-27 14:31:22 +01:00
|
|
|
// if (debug() >= 9) newp->dumpTree("- SELEXnew: ");
|
2020-04-15 13:58:34 +02:00
|
|
|
nodep->replaceWith(newp);
|
|
|
|
|
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
2020-08-15 16:12:55 +02:00
|
|
|
} else { // nullptr=bad extract, or unknown node type
|
2020-01-26 21:54:57 +01:00
|
|
|
nodep->v3error("Illegal range select; type already selected, or bad dimension: "
|
|
|
|
|
<< "data type is " << fromdata.m_errp->prettyDTypeNameQ());
|
|
|
|
|
UINFO(1, " Related ddtype: " << ddtypep << endl);
|
2019-05-19 22:13:13 +02:00
|
|
|
// How to recover? We'll strip a dimension.
|
2020-01-26 21:54:57 +01:00
|
|
|
nodep->replaceWith(fromp);
|
|
|
|
|
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2019-09-09 13:50:21 +02:00
|
|
|
// delete whatever we didn't use in reconstruction
|
2021-02-22 03:25:21 +01:00
|
|
|
if (!fromp->backp()) VL_DO_DANGLING(pushDeletep(fromp), fromp);
|
|
|
|
|
if (!msbp->backp()) VL_DO_DANGLING(pushDeletep(msbp), msbp);
|
|
|
|
|
if (!lsbp->backp()) VL_DO_DANGLING(pushDeletep(lsbp), lsbp);
|
2009-10-25 21:53:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void replaceSelPlusMinus(AstNodePreSel* nodep) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Select of a range specified with +: or -:, i.e. "array[2+:3], [2-:3]"
|
|
|
|
|
// This select style has a lsb and width
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(6, "SELPLUS/MINUS " << nodep << endl);
|
2019-05-19 22:13:13 +02:00
|
|
|
// Below 2 lines may change nodep->widthp()
|
2022-11-27 14:31:22 +01:00
|
|
|
if (debug() >= 9) nodep->dumpTree("- SELPM0: ");
|
2020-05-18 19:46:00 +02:00
|
|
|
V3Width::widthParamsEdit(nodep->rhsp()); // constifyEdit doesn't ensure widths finished
|
2020-05-05 01:40:50 +02:00
|
|
|
V3Const::constifyEdit(nodep->rhsp()); // May relink pointed to node, ok if not const
|
2019-05-19 22:13:13 +02:00
|
|
|
V3Const::constifyParamsEdit(nodep->thsp()); // May relink pointed to node
|
2023-03-21 01:44:11 +01:00
|
|
|
checkConstantOrReplace(nodep->thsp(),
|
|
|
|
|
"Width of :+ or :- bit slice range isn't a constant");
|
2022-11-27 14:31:22 +01:00
|
|
|
if (debug() >= 9) nodep->dumpTree("- SELPM3: ");
|
2019-05-19 22:13:13 +02:00
|
|
|
// Now replace it with an AstSel
|
2022-11-13 21:33:11 +01:00
|
|
|
AstNodeExpr* const fromp = nodep->fromp()->unlinkFrBack();
|
|
|
|
|
AstNodeExpr* const rhsp = nodep->rhsp()->unlinkFrBack();
|
|
|
|
|
AstNodeExpr* const widthp = nodep->thsp()->unlinkFrBack();
|
2020-05-05 01:40:50 +02:00
|
|
|
warnTri(rhsp);
|
2021-10-22 14:56:48 +02:00
|
|
|
const int width = VN_AS(widthp, Const)->toSInt();
|
2020-04-15 13:58:34 +02:00
|
|
|
if (width > (1 << 28)) {
|
2022-11-05 16:40:34 +01:00
|
|
|
nodep->v3error("Width of :+ or :- is huge; vector of over 1 billion bits: "
|
2020-04-15 13:58:34 +02:00
|
|
|
<< widthp->prettyName());
|
|
|
|
|
}
|
|
|
|
|
if (width < 0) nodep->v3error("Width of :+ or :- is < 0: " << widthp->prettyName());
|
2021-06-21 00:32:57 +02:00
|
|
|
const FromData fromdata = fromDataForArray(nodep, fromp);
|
2021-11-26 23:55:36 +01:00
|
|
|
const AstNodeDType* const ddtypep = fromdata.m_dtypep;
|
2021-06-21 00:32:57 +02:00
|
|
|
const VNumRange fromRange = fromdata.m_fromRange;
|
2020-05-05 01:40:50 +02:00
|
|
|
if (VN_IS(ddtypep, UnpackArrayDType)) {
|
|
|
|
|
// Slice +: and -: extraction
|
|
|
|
|
if (fromRange.elements() == width && VN_IS(rhsp, Const)
|
2021-10-22 14:56:48 +02:00
|
|
|
&& VN_AS(rhsp, Const)->toSInt()
|
2020-05-05 01:40:50 +02:00
|
|
|
== fromRange.lo()) { // Extracting whole of original array
|
|
|
|
|
nodep->replaceWith(fromp);
|
|
|
|
|
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
|
|
|
|
} else if (fromRange.elements() == 1) { // Extracting single element
|
2022-11-21 02:13:55 +01:00
|
|
|
AstArraySel* const newp = new AstArraySel{nodep->fileline(), fromp, rhsp};
|
2020-05-05 01:40:50 +02:00
|
|
|
nodep->replaceWith(newp);
|
|
|
|
|
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
|
|
|
|
} else if (VN_IS(rhsp, Const)) { // Slice
|
2022-03-27 21:27:40 +02:00
|
|
|
const int32_t rhs = VN_AS(rhsp, Const)->toSInt();
|
2020-05-05 01:40:50 +02:00
|
|
|
// down array: lsb/lo +: width
|
|
|
|
|
// down array: msb/hi -: width
|
|
|
|
|
// up array: msb/lo +: width
|
|
|
|
|
// up array: lsb/hi -: width
|
2022-03-27 21:27:40 +02:00
|
|
|
const int32_t msb = VN_IS(nodep, SelPlus) ? rhs + width - 1 : rhs;
|
|
|
|
|
const int32_t lsb = VN_IS(nodep, SelPlus) ? rhs : rhs - width + 1;
|
2022-09-16 01:58:01 +02:00
|
|
|
AstSliceSel* const newp = new AstSliceSel{
|
2023-03-21 01:44:11 +01:00
|
|
|
nodep->fileline(), fromp, VNumRange{msb, lsb, fromRange.ascending()}};
|
2020-05-05 01:40:50 +02:00
|
|
|
nodep->replaceWith(newp);
|
|
|
|
|
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
|
|
|
|
} else {
|
2020-06-10 01:20:16 +02:00
|
|
|
nodep->v3warn(E_UNSUPPORTED, "Unsupported: Slice of non-constant bounds");
|
2020-05-05 01:40:50 +02:00
|
|
|
}
|
|
|
|
|
} else if (VN_IS(ddtypep, BasicDType) || VN_IS(ddtypep, PackArrayDType)
|
|
|
|
|
|| (VN_IS(ddtypep, NodeUOrStructDType)
|
2021-10-22 14:56:48 +02:00
|
|
|
&& VN_AS(ddtypep, NodeUOrStructDType)->packedUnsup())) {
|
2019-05-19 22:13:13 +02:00
|
|
|
int elwidth = 1;
|
2022-11-13 21:33:11 +01:00
|
|
|
AstNodeExpr* newwidthp = widthp;
|
2021-11-13 19:50:44 +01:00
|
|
|
if (const AstPackArrayDType* const adtypep = VN_CAST(ddtypep, PackArrayDType)) {
|
2019-05-19 22:13:13 +02:00
|
|
|
elwidth = adtypep->width() / fromRange.elements();
|
2020-04-15 13:58:34 +02:00
|
|
|
newwidthp
|
2022-11-21 02:13:55 +01:00
|
|
|
= new AstConst(nodep->fileline(), AstConst::Unsized32{}, width * elwidth);
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2022-11-13 21:33:11 +01:00
|
|
|
AstNodeExpr* newlsbp = nullptr;
|
2018-02-02 03:32:58 +01:00
|
|
|
if (VN_IS(nodep, SelPlus)) {
|
2023-03-21 01:44:11 +01:00
|
|
|
if (fromRange.ascending()) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// SELPLUS(from,lsb,width) -> SEL(from, (vector_msb-width+1)-sel, width)
|
2020-04-15 13:58:34 +02:00
|
|
|
newlsbp = newSubNeg((fromRange.hi() - width + 1), rhsp);
|
2019-05-19 22:13:13 +02:00
|
|
|
} else {
|
|
|
|
|
// SELPLUS(from,lsb,width) -> SEL(from, lsb-vector_lsb, width)
|
|
|
|
|
newlsbp = newSubNeg(rhsp, fromRange.lo());
|
|
|
|
|
}
|
2018-02-02 03:32:58 +01:00
|
|
|
} else if (VN_IS(nodep, SelMinus)) {
|
2023-03-21 01:44:11 +01:00
|
|
|
if (fromRange.ascending()) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// SELMINUS(from,msb,width) -> SEL(from, msb-[bit])
|
|
|
|
|
newlsbp = newSubNeg(fromRange.hi(), rhsp);
|
|
|
|
|
} else {
|
|
|
|
|
// SELMINUS(from,msb,width) -> SEL(from, msb-(width-1)-lsb#)
|
2020-04-15 13:58:34 +02:00
|
|
|
newlsbp = newSubNeg(rhsp, fromRange.lo() + (width - 1));
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
nodep->v3fatalSrc("Bad Case");
|
|
|
|
|
}
|
2020-04-15 13:58:34 +02:00
|
|
|
if (elwidth != 1) {
|
2022-11-21 02:13:55 +01:00
|
|
|
newlsbp = new AstMul{nodep->fileline(), newlsbp,
|
|
|
|
|
new AstConst(nodep->fileline(), elwidth)};
|
2020-04-15 13:58:34 +02:00
|
|
|
}
|
2022-11-21 02:13:55 +01:00
|
|
|
AstSel* const newp = new AstSel{nodep->fileline(), fromp, newlsbp, newwidthp};
|
2019-05-19 22:13:13 +02:00
|
|
|
newp->declRange(fromRange);
|
|
|
|
|
newp->declElWidth(elwidth);
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(6, " new " << newp << endl);
|
2022-11-27 14:31:22 +01:00
|
|
|
if (debug() >= 9) newp->dumpTree("- SELNEW: ");
|
2020-04-15 13:58:34 +02:00
|
|
|
nodep->replaceWith(newp);
|
|
|
|
|
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
2020-08-15 16:12:55 +02:00
|
|
|
} else { // nullptr=bad extract, or unknown node type
|
2020-01-26 21:54:57 +01:00
|
|
|
nodep->v3error("Illegal +: or -: select; type already selected, or bad dimension: "
|
|
|
|
|
<< "data type is " << fromdata.m_errp->prettyDTypeNameQ());
|
2019-05-19 22:13:13 +02:00
|
|
|
// How to recover? We'll strip a dimension.
|
2020-01-26 21:54:57 +01:00
|
|
|
nodep->replaceWith(fromp);
|
|
|
|
|
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2019-09-09 13:50:21 +02:00
|
|
|
// delete whatever we didn't use in reconstruction
|
2021-02-22 03:25:21 +01:00
|
|
|
if (!fromp->backp()) VL_DO_DANGLING(pushDeletep(fromp), fromp);
|
|
|
|
|
if (!rhsp->backp()) VL_DO_DANGLING(pushDeletep(rhsp), rhsp);
|
|
|
|
|
if (!widthp->backp()) VL_DO_DANGLING(pushDeletep(widthp), widthp);
|
2009-10-25 21:53:55 +01:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstSelPlus* nodep) override { replaceSelPlusMinus(nodep); }
|
|
|
|
|
void visit(AstSelMinus* nodep) override { replaceSelPlusMinus(nodep); }
|
2020-01-25 02:10:44 +01:00
|
|
|
// If adding new visitors, ensure V3Width's visit(TYPE) calls into here
|
2009-10-25 21:53:55 +01:00
|
|
|
|
|
|
|
|
//--------------------
|
|
|
|
|
// Default
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstNode* nodep) override { // LCOV_EXCL_LINE
|
2019-05-19 22:13:13 +02:00
|
|
|
// See notes above; we never iterate
|
|
|
|
|
nodep->v3fatalSrc("Shouldn't iterate in V3WidthSel");
|
2009-10-25 21:53:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public:
|
2019-09-12 13:22:22 +02:00
|
|
|
// CONSTRUCTORS
|
2020-11-17 01:56:16 +01:00
|
|
|
WidthSelVisitor() = default;
|
2022-09-16 12:22:11 +02:00
|
|
|
~WidthSelVisitor() override = default;
|
2020-04-15 13:58:34 +02:00
|
|
|
AstNode* mainAcceptEdit(AstNode* nodep) { return iterateSubtreeReturnEdits(nodep); }
|
2009-10-25 21:53:55 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//######################################################################
|
|
|
|
|
// Width class functions
|
|
|
|
|
|
|
|
|
|
AstNode* V3Width::widthSelNoIterEdit(AstNode* nodep) {
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(4, __FUNCTION__ << ": " << nodep << endl);
|
2009-10-25 21:53:55 +01:00
|
|
|
WidthSelVisitor visitor;
|
|
|
|
|
nodep = visitor.mainAcceptEdit(nodep);
|
|
|
|
|
return nodep;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#undef iterateChildren
|