From 2923893d34c98a3e0462206e2c1ceabd4de552da Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 12 Mar 2011 07:45:04 -0500 Subject: [PATCH] Support loop unrolling on width mismatches, bug 333 --- Changes | 2 + src/V3Const.cpp | 77 ++++++++++++++++++++++++++++---- src/V3Number.cpp | 6 +++ src/V3Number.h | 1 + src/V3Unroll.cpp | 3 +- test_regress/t/t_mem_multidim.v | 2 +- test_regress/t/t_unroll_signed.v | 23 ++++++++++ 7 files changed, 104 insertions(+), 10 deletions(-) diff --git a/Changes b/Changes index 54c4429d6..d0ec0cc89 100644 --- a/Changes +++ b/Changes @@ -9,6 +9,8 @@ indicates the contributor was also the author of the fix; Thanks! **** Support $bits(data_type), bug327. [Alex Solomatnikov] +**** Support loop unrolling on width mismatches, bug 333. [Joe Eiler] + **** Accelerate bit-selected inversions. **** Add error on circular parameter definitions, bug329. [Alex Solomatnikov] diff --git a/src/V3Const.cpp b/src/V3Const.cpp index 9ddd85d17..d160d3857 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -290,13 +290,61 @@ private: // SEL(EXTEND(any,width,...),(width-1),0) -> ... // Since select's return unsigned, this is always an extend AstExtend* extendp = nodep->fromp()->castExtend(); - return (m_doV - && extendp - && nodep->lsbp()->castConst() - && nodep->widthp()->castConst() - && nodep->lsbConst()==0 - && (int)nodep->widthConst()==extendp->lhsp()->width() - ); + if (!(m_doV + && extendp + && nodep->lsbp()->castConst() + && nodep->widthp()->castConst() + && nodep->lsbConst()==0 + && (int)nodep->widthConst()==extendp->lhsp()->width() + )) return false; + replaceWChild(nodep, extendp->lhsp()); nodep=NULL; + return true; + } + bool operandSelBiLower(AstSel* nodep) { + // SEL(ADD(a,b),(width-1),0) -> ADD(SEL(a),SEL(b)) + // Add or any operation which doesn't care if we discard top bits + AstNodeBiop* bip = nodep->fromp()->castNodeBiop(); + if (!(m_doV + && bip + && nodep->lsbp()->castConst() + && nodep->widthp()->castConst() + && nodep->lsbConst()==0 + )) return false; + if (debug()>=9) nodep->dumpTree(cout,"SEL(BI)-in:"); + AstNode* bilhsp = bip->lhsp()->unlinkFrBack(); + AstNode* birhsp = bip->rhsp()->unlinkFrBack(); + bip->lhsp(new AstSel(nodep->fileline(), bilhsp, 0, nodep->widthConst())); + bip->rhsp(new AstSel(nodep->fileline(), birhsp, 0, nodep->widthConst())); + if (debug()>=9) bip->dumpTree(cout,"SEL(BI)-ou:"); + replaceWChild(nodep, bip); nodep=NULL; + return true; + } + + bool operandBiExtendConst(AstNodeBiop* nodep) { + // Loop unrolling likes standalone compares + // EQ(EXTEND(xx{width3}), const{width32}) -> EQ(xx{3},const{3}) + // Beware that the constant must have zero bits (+ 1 if signed) or compare + // would be incorrect + AstExtend* extendp = nodep->lhsp()->castExtend(); + if (!extendp) return false; + AstNode* smallerp = extendp->lhsp(); + int subsize = smallerp->width(); + AstConst* constp = nodep->rhsp()->castConst(); + if (!constp) return false; + if (!constp->num().isBitsZero(constp->width()-1, subsize)) return false; + // + if (debug()>=9) nodep->dumpTree(cout,"BI(EXTEND)-in:"); + smallerp->unlinkFrBack(); + extendp->unlinkFrBack()->deleteTree(); // aka nodep->lhsp. + nodep->lhsp(smallerp); + + constp->unlinkFrBack(); + V3Number num (constp->fileline(), subsize); + num.opAssign(constp->num()); + nodep->rhsp(new AstConst(constp->fileline(), num)); + constp->deleteTree(); constp=NULL; + if (debug()>=9) nodep->dumpTree(cout,"BI(EXTEND)-ou:"); + return true; } AstNode* afterComment(AstNode* nodep) { @@ -1716,6 +1764,13 @@ private: TREEOP ("AstShiftL{operandShiftShift(nodep)}", "replaceShiftShift(nodep)"); TREEOP ("AstShiftR{operandShiftShift(nodep)}", "replaceShiftShift(nodep)"); TREEOP ("AstWordSel{operandWordOOB(nodep)}", "replaceZero(nodep)"); + // Compress out EXTENDs to appease loop unroller + TREEOPV("AstEq {$lhsp.castExtend,operandBiExtendConst(nodep)}", "DONE"); + TREEOPV("AstNeq {$lhsp.castExtend,operandBiExtendConst(nodep)}", "DONE"); + TREEOPV("AstGt {$lhsp.castExtend,operandBiExtendConst(nodep)}", "DONE"); + TREEOPV("AstGte {$lhsp.castExtend,operandBiExtendConst(nodep)}", "DONE"); + TREEOPV("AstLt {$lhsp.castExtend,operandBiExtendConst(nodep)}", "DONE"); + TREEOPV("AstLte {$lhsp.castExtend,operandBiExtendConst(nodep)}", "DONE"); // Identical operands on both sides // AstLogAnd/AstLogOr already converted to AstAnd/AstOr for these rules // AstAdd->ShiftL(#,1) but uncommon @@ -1793,9 +1848,15 @@ private: TREEOPV("AstReplicate{$lhsp, $rhsp.isOne, $lhsp->width()==nodep->width()}", "replaceWLhs(nodep)"); // {1{lhs}}->lhs // Next rule because AUTOINST puts the width of bits in // to pins, even when the widths are exactly the same across the hierarchy. - TREEOPV("AstSel{operandSelExtend(nodep)}", "replaceWChild(nodep, nodep->fromp()->castExtend()->lhsp())"); + TREEOPV("AstSel{operandSelExtend(nodep)}", "DONE"); TREEOPV("AstSel{operandSelFull(nodep)}", "replaceWChild(nodep, nodep->fromp())"); TREEOPV("AstSel{$fromp.castSel}", "replaceSelSel(nodep)"); + TREEOPV("AstSel{$fromp.castAdd, operandSelBiLower(nodep)}", "DONE"); + TREEOPV("AstSel{$fromp.castAnd, operandSelBiLower(nodep)}", "DONE"); + TREEOPV("AstSel{$fromp.castOr, operandSelBiLower(nodep)}", "DONE"); + TREEOPV("AstSel{$fromp.castSub, operandSelBiLower(nodep)}", "DONE"); + TREEOPV("AstSel{$fromp.castXnor,operandSelBiLower(nodep)}", "DONE"); + TREEOPV("AstSel{$fromp.castXor, operandSelBiLower(nodep)}", "DONE"); TREEOPC("AstSel{$fromp.castConst, $lsbp.castConst, $widthp.castConst, }", "replaceConst(nodep)"); TREEOPV("AstSel{$fromp.castConcat, $lsbp.castConst, $widthp.castConst, }", "replaceSelConcat(nodep)"); TREEOPV("AstSel{$fromp.castReplicate, $lsbp.castConst, $widthp.isOne, }", "replaceSelReplicate(nodep)"); diff --git a/src/V3Number.cpp b/src/V3Number.cpp index 23247548c..49443e7c1 100644 --- a/src/V3Number.cpp +++ b/src/V3Number.cpp @@ -555,6 +555,12 @@ bool V3Number::isNeqZero() const { } return false; } +bool V3Number::isBitsZero(int msb, int lsb) const { + for (int i=lsb; i<=msb; i++) { + if (VL_UNLIKELY(!bitIs0(i))) return false; + } + return true; +} bool V3Number::isEqOne() const { if (m_value[0]!=1 || m_valueX[0]) return false; for (int i=1; i=0+1 && index0<=2 && index1>=1+1 && index1<=3 && index2>=2+1 && index2<=5) begin + if (index0>=0+1 && index0<=2 && index1>=1+1 /*&& index1<=3 CMPCONST*/ && index2>=2+1 && index2<=5) begin narrow <= ({narrow[6:0], narrow[7]^narrow[0]} ^ {memn[index0][index1][index2]}); wread = memw[index0][index1][index2]; diff --git a/test_regress/t/t_unroll_signed.v b/test_regress/t/t_unroll_signed.v index d9a5ded6e..45f99561c 100644 --- a/test_regress/t/t_unroll_signed.v +++ b/test_regress/t/t_unroll_signed.v @@ -118,6 +118,29 @@ module t (/*AUTOARG*/ if (total != -28) $stop; end //=== + 10: begin + // mostly cover a small index + total = 0; + for (i3=0; i3<3'd7; i3=i3+3'd1) begin + total = total - {29'd0,i3} -1; + dly_to_insure_was_unrolled[i3[0]] <= 0; + end + if (total != -28) $stop; + end + //=== + 11: begin + // width violation on <, causes extend + total = 0; + for (i3=3'd0; i3<7; i3=i3+1) begin + total = total - {29'd0,i3} -1; + dly_to_insure_was_unrolled[i3[0]] <= 0; + end + if (total != -28) $stop; + end + //=== + // width violation on <, causes extend signed + // Unsupported as yet + //=== 19: begin $write("*-* All Finished *-*\n"); $finish;