forked from github/verilator
Internals: Remove Xnor node type.
Convert to Not(Xor(x)) up front, to help code coverage and optimize out extra nots sooner.
This commit is contained in:
parent
5b2844e1be
commit
af0e535015
@ -84,7 +84,7 @@
|
||||
"if (a) { ... b=2; } else { ... b=2;}" -> "b=2; if ..."
|
||||
Careful though, as b could appear in the statement or multiple times in statement
|
||||
(Could just require exatly two 'b's in statement)
|
||||
** Simplify XOR/XNOR/AND/OR bit selection trees
|
||||
** Simplify XOR/AND/OR bit selection trees
|
||||
Foo = A[1] ^ A[2] ^ A[3] etc are better as ^ ( A & 32'b...1110 )
|
||||
** Combine variables into wider elements
|
||||
Parallel statements on different bits should become single signal
|
||||
|
@ -1370,12 +1370,6 @@ static inline WDataOutP VL_XOR_W(int words, WDataOutP owp, WDataInP lwp, WDataIn
|
||||
for (int i = 0; (i < words); ++i) owp[i] = (lwp[i] ^ rwp[i]);
|
||||
return owp;
|
||||
}
|
||||
// EMIT_RULE: VL_XNOR: oclean=dirty; obits=lbits; lbits==rbits;
|
||||
static inline WDataOutP VL_XNOR_W(int words, WDataOutP owp, WDataInP lwp,
|
||||
WDataInP rwp) VL_MT_SAFE {
|
||||
for (int i = 0; (i < words); ++i) owp[i] = (lwp[i] ^ ~rwp[i]);
|
||||
return owp;
|
||||
}
|
||||
// EMIT_RULE: VL_NOT: oclean=dirty; obits=lbits;
|
||||
static inline WDataOutP VL_NOT_W(int words, WDataOutP owp, WDataInP lwp) VL_MT_SAFE {
|
||||
for (int i = 0; i < words; ++i) owp[i] = ~(lwp[i]);
|
||||
|
@ -234,7 +234,6 @@ sub gentree {
|
||||
'RANGE' => sub { t1; local $Avoid_Hex=1; p "[";t2;p ":";t3;p "]"; },
|
||||
'REDAND' => sub { p "&(";p1;p ")"; },
|
||||
'REDOR' => sub { p "|(";p1;p ")"; },
|
||||
'REDXNOR' => sub { p "~|(";p1;p ")"; },
|
||||
'REDXOR' => sub { p "~^(";p1;p ")"; },
|
||||
'REPLICATE' => sub { p "{";p1;p "{";p2;p "}}"; },
|
||||
'SCCTOR' => sub { p "SCCTOR what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
||||
@ -263,7 +262,6 @@ sub gentree {
|
||||
'VARSCOPE' => sub { },
|
||||
'WHILE' => sub { t1; p "while (";t2;p ") begin";indentInc;nl;t3;t4;indentDec;p "end";nl; },
|
||||
'WORDSEL' => sub { p1;p "[";p2;p ":";p3;p "]"; },
|
||||
'XNOR' => sub { p1;p " ~^ ";p2; },
|
||||
'XOR' => sub { p1;p " ^";p2; },
|
||||
);
|
||||
}
|
||||
|
@ -5647,25 +5647,6 @@ public:
|
||||
virtual bool sizeMattersLhs() const override { return false; }
|
||||
virtual int instrCount() const override { return 1 + V3Number::log2b(width()); }
|
||||
};
|
||||
class AstRedXnor final : public AstNodeUniop {
|
||||
// AstRedXnors are replaced with AstRedXors in V3Const.
|
||||
public:
|
||||
AstRedXnor(FileLine* fl, AstNode* lhsp)
|
||||
: ASTGEN_SUPER(fl, lhsp) {
|
||||
dtypeSetBit();
|
||||
}
|
||||
ASTNODE_NODE_FUNCS(RedXnor)
|
||||
virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.opRedXnor(lhs); }
|
||||
virtual string emitVerilog() override { return "%f(~^ %l)"; }
|
||||
virtual string emitC() override {
|
||||
v3fatalSrc("REDXNOR should have became REDXOR");
|
||||
return "";
|
||||
}
|
||||
virtual bool cleanOut() const override { return false; }
|
||||
virtual bool cleanLhs() const override { return true; }
|
||||
virtual bool sizeMattersLhs() const override { return false; }
|
||||
virtual int instrCount() const override { return 1 + V3Number::log2b(width()); }
|
||||
};
|
||||
|
||||
class AstLenN final : public AstNodeUniop {
|
||||
// Length of a string
|
||||
@ -6747,28 +6728,6 @@ public:
|
||||
virtual bool sizeMattersLhs() const override { return false; }
|
||||
virtual bool sizeMattersRhs() const override { return false; }
|
||||
};
|
||||
class AstXnor final : public AstNodeBiComAsv {
|
||||
public:
|
||||
AstXnor(FileLine* fl, AstNode* lhsp, AstNode* rhsp)
|
||||
: ASTGEN_SUPER(fl, lhsp, rhsp) {
|
||||
dtypeFrom(lhsp);
|
||||
}
|
||||
ASTNODE_NODE_FUNCS(Xnor)
|
||||
virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override {
|
||||
return new AstXnor(this->fileline(), lhsp, rhsp);
|
||||
}
|
||||
virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
|
||||
out.opXnor(lhs, rhs);
|
||||
}
|
||||
virtual string emitVerilog() override { return "%k(%l %f^ ~ %r)"; }
|
||||
virtual string emitC() override { return "VL_XNOR_%lq(%lW, %P, %li, %ri)"; }
|
||||
virtual string emitSimpleOperator() override { return "^ ~"; }
|
||||
virtual bool cleanOut() const override { return false; }
|
||||
virtual bool cleanLhs() const override { return false; }
|
||||
virtual bool cleanRhs() const override { return false; }
|
||||
virtual bool sizeMattersLhs() const override { return true; }
|
||||
virtual bool sizeMattersRhs() const override { return true; }
|
||||
};
|
||||
class AstEq final : public AstNodeBiCom {
|
||||
public:
|
||||
AstEq(FileLine* fl, AstNode* lhsp, AstNode* rhsp)
|
||||
|
@ -509,7 +509,7 @@ private:
|
||||
return true;
|
||||
}
|
||||
bool ifConcatMergeableBiop(const AstNode* nodep) {
|
||||
return (VN_IS(nodep, And) || VN_IS(nodep, Or) || VN_IS(nodep, Xor) || VN_IS(nodep, Xnor));
|
||||
return (VN_IS(nodep, And) || VN_IS(nodep, Or) || VN_IS(nodep, Xor));
|
||||
}
|
||||
bool ifAdjacentSel(const AstSel* lhsp, const AstSel* rhsp) {
|
||||
if (!v3Global.opt.oAssemble()) return false; // opt disabled
|
||||
@ -2248,7 +2248,6 @@ private:
|
||||
TREEOP ("AstShiftR{$lhsp.isZero, $rhsp}", "replaceZeroChkPure(nodep,$rhsp)");
|
||||
TREEOP ("AstShiftRS{$lhsp.isZero, $rhsp}", "replaceZeroChkPure(nodep,$rhsp)");
|
||||
TREEOP ("AstXor {$lhsp.isZero, $rhsp}", "replaceWRhs(nodep)");
|
||||
TREEOP ("AstXnor {$lhsp.isZero, $rhsp}", "AstNot{$rhsp}");
|
||||
TREEOP ("AstSub {$lhsp.isZero, $rhsp}", "AstNegate{$rhsp}");
|
||||
TREEOP ("AstAdd {$lhsp, $rhsp.isZero}", "replaceWLhs(nodep)");
|
||||
TREEOP ("AstAnd {$lhsp, $rhsp.isZero}", "replaceZeroChkPure(nodep,$lhsp)");
|
||||
@ -2262,7 +2261,6 @@ private:
|
||||
TREEOP ("AstShiftRS{$lhsp, $rhsp.isZero}", "replaceWLhs(nodep)");
|
||||
TREEOP ("AstSub {$lhsp, $rhsp.isZero}", "replaceWLhs(nodep)");
|
||||
TREEOP ("AstXor {$lhsp, $rhsp.isZero}", "replaceWLhs(nodep)");
|
||||
TREEOP ("AstXnor {$lhsp, $rhsp.isZero}", "AstNot{$lhsp}");
|
||||
// Non-zero on one side or the other
|
||||
TREEOP ("AstAnd {$lhsp.isAllOnes, $rhsp}", "replaceWRhs(nodep)");
|
||||
TREEOP ("AstLogAnd{$lhsp.isNeqZero, $rhsp}", "replaceWRhs(nodep)");
|
||||
@ -2273,7 +2271,6 @@ private:
|
||||
TREEOP ("AstOr {$lhsp, $rhsp.isAllOnes, isTPure($lhsp)}", "replaceWRhs(nodep)"); //->allOnes
|
||||
TREEOP ("AstLogOr {$lhsp, $rhsp.isNeqZero, isTPure($lhsp)}", "replaceNum(nodep,1)");
|
||||
TREEOP ("AstXor {$lhsp.isAllOnes, $rhsp}", "AstNot{$rhsp}");
|
||||
TREEOP ("AstXnor {$lhsp.isAllOnes, $rhsp}", "replaceWRhs(nodep)");
|
||||
TREEOP ("AstMul {$lhsp.isOne, $rhsp}", "replaceWRhs(nodep)");
|
||||
TREEOP ("AstMulS {$lhsp.isOne, $rhsp}", "replaceWRhs(nodep)");
|
||||
TREEOP ("AstDiv {$lhsp, $rhsp.isOne}", "replaceWLhs(nodep)");
|
||||
@ -2384,7 +2381,6 @@ private:
|
||||
TREEOP ("AstDivS {operandsSame($lhsp,,$rhsp)}", "replaceNum(nodep,1)");
|
||||
TREEOP ("AstOr {operandsSame($lhsp,,$rhsp)}", "replaceWLhs(nodep)");
|
||||
TREEOP ("AstSub {operandsSame($lhsp,,$rhsp)}", "replaceZero(nodep)");
|
||||
TREEOP ("AstXnor {operandsSame($lhsp,,$rhsp)}", "replaceAllOnes(nodep)");
|
||||
TREEOP ("AstXor {operandsSame($lhsp,,$rhsp)}", "replaceZero(nodep)");
|
||||
TREEOP ("AstEq {operandsSame($lhsp,,$rhsp)}", "replaceNum(nodep,1)"); // We let X==X -> 1, although in a true 4-state sim it's X.
|
||||
TREEOP ("AstEqD {operandsSame($lhsp,,$rhsp)}", "replaceNum(nodep,1)"); // We let X==X -> 1, although in a true 4-state sim it's X.
|
||||
@ -2461,8 +2457,6 @@ private:
|
||||
TREEOP ("AstAnd {operandShiftSame(nodep)}", "replaceShiftSame(nodep)");
|
||||
TREEOP ("AstOr {operandShiftSame(nodep)}", "replaceShiftSame(nodep)");
|
||||
TREEOP ("AstXor {operandShiftSame(nodep)}", "replaceShiftSame(nodep)");
|
||||
// "AstXnor{operandShiftSame(nodep)}", // Cannot ShiftSame as the shifted-in
|
||||
// zeros might create a one
|
||||
// Note can't simplify a extend{extends}, extends{extend}, as the sign
|
||||
// bits end up in the wrong places
|
||||
TREEOPV("AstExtend {$lhsp.castExtend}", "replaceExtend(nodep, VN_CAST(nodep->lhsp(), Extend)->lhsp())");
|
||||
@ -2480,7 +2474,6 @@ private:
|
||||
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");
|
||||
TREEOPV("AstSel{$fromp.castShiftR, operandSelShiftLower(nodep)}", "DONE");
|
||||
TREEOPC("AstSel{$fromp.castConst, $lsbp.castConst, $widthp.castConst, }", "replaceConst(nodep)");
|
||||
@ -2494,9 +2487,6 @@ private:
|
||||
TREEOPV("AstSel{$fromp.castAnd,$lhsp.castConst}", "replaceSelIntoUniop(nodep)");
|
||||
TREEOPV("AstSel{$fromp.castOr,$lhsp.castConst}", "replaceSelIntoUniop(nodep)");
|
||||
TREEOPV("AstSel{$fromp.castXor,$lhsp.castConst}", "replaceSelIntoUniop(nodep)");
|
||||
TREEOPV("AstSel{$fromp.castXnor,$lhsp.castConst}", "replaceSelIntoUniop(nodep)");
|
||||
// Conversions
|
||||
TREEOPV("AstRedXnor{$lhsp}", "AstNot{AstRedXor{$lhsp}}"); // Just eliminate XNOR's
|
||||
// This visit function here must allow for short-circuiting.
|
||||
TREEOPS("AstLogIf{$lhsp.isZero}", "replaceNum(nodep, 1)");
|
||||
TREEOPV("AstLogIf{$lhsp, $rhsp}", "AstLogOr{AstLogNot{$lhsp},$rhsp}");
|
||||
|
@ -270,15 +270,6 @@ private:
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool expandWide(AstNodeAssign* nodep, AstXnor* rhsp) {
|
||||
UINFO(8, " Wordize ASSIGN(XNOR) " << nodep << endl);
|
||||
for (int w = 0; w < nodep->widthWords(); w++) {
|
||||
addWordAssign(nodep, w,
|
||||
new AstXnor(nodep->fileline(), newAstWordSelClone(rhsp->lhsp(), w),
|
||||
newAstWordSelClone(rhsp->rhsp(), w)));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//-------- Triops
|
||||
bool expandWide(AstNodeAssign* nodep, AstNodeCond* rhsp) {
|
||||
UINFO(8, " Wordize ASSIGN(COND) " << nodep << endl);
|
||||
@ -859,8 +850,6 @@ private:
|
||||
did = expandWide(nodep, rhsp);
|
||||
} else if (AstXor* rhsp = VN_CAST(nodep->rhsp(), Xor)) {
|
||||
did = expandWide(nodep, rhsp);
|
||||
} else if (AstXnor* rhsp = VN_CAST(nodep->rhsp(), Xnor)) {
|
||||
did = expandWide(nodep, rhsp);
|
||||
} else if (AstNodeCond* rhsp = VN_CAST(nodep->rhsp(), NodeCond)) {
|
||||
did = expandWide(nodep, rhsp);
|
||||
}
|
||||
|
@ -1118,26 +1118,6 @@ V3Number& V3Number::opRedXor(const V3Number& lhs) {
|
||||
return setSingleBits(outc);
|
||||
}
|
||||
|
||||
V3Number& V3Number::opRedXnor(const V3Number& lhs) {
|
||||
// op i, 1 bit return
|
||||
NUM_ASSERT_OP_ARGS1(lhs);
|
||||
NUM_ASSERT_LOGIC_ARGS1(lhs);
|
||||
char outc = 1;
|
||||
for (int bit = 0; bit < lhs.width(); bit++) {
|
||||
if (lhs.bitIs1(bit)) {
|
||||
if (outc == 1) {
|
||||
outc = 0;
|
||||
} else if (outc == 0) {
|
||||
outc = 1;
|
||||
}
|
||||
} else if (lhs.bitIs0(bit)) {
|
||||
} else {
|
||||
outc = 'x';
|
||||
}
|
||||
}
|
||||
return setSingleBits(outc);
|
||||
}
|
||||
|
||||
V3Number& V3Number::opCountBits(const V3Number& expr, const V3Number& ctrl1, const V3Number& ctrl2,
|
||||
const V3Number& ctrl3) {
|
||||
NUM_ASSERT_OP_ARGS4(expr, ctrl1, ctrl2, ctrl3);
|
||||
@ -1278,24 +1258,6 @@ V3Number& V3Number::opXor(const V3Number& lhs, const V3Number& rhs) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
V3Number& V3Number::opXnor(const V3Number& lhs, const V3Number& rhs) {
|
||||
// i op j, max(L(lhs),L(rhs)) bit return, careful need to X/Z extend.
|
||||
NUM_ASSERT_OP_ARGS2(lhs, rhs);
|
||||
NUM_ASSERT_LOGIC_ARGS2(lhs, rhs);
|
||||
setZero();
|
||||
for (int bit = 0; bit < this->width(); bit++) {
|
||||
if (lhs.bitIs1(bit) && rhs.bitIs1(bit)) {
|
||||
setBit(bit, 1);
|
||||
} else if (lhs.bitIs0(bit) && rhs.bitIs0(bit)) {
|
||||
setBit(bit, 1);
|
||||
} else if (lhs.bitIsXZ(bit) && rhs.bitIsXZ(bit)) {
|
||||
setBit(bit, 'x');
|
||||
}
|
||||
// else zero
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
V3Number& V3Number::opConcat(const V3Number& lhs, const V3Number& rhs) {
|
||||
NUM_ASSERT_OP_ARGS2(lhs, rhs);
|
||||
NUM_ASSERT_LOGIC_ARGS2(lhs, rhs);
|
||||
|
@ -326,7 +326,6 @@ public:
|
||||
V3Number& opRedOr(const V3Number& lhs);
|
||||
V3Number& opRedAnd(const V3Number& lhs);
|
||||
V3Number& opRedXor(const V3Number& lhs);
|
||||
V3Number& opRedXnor(const V3Number& lhs);
|
||||
V3Number& opCountBits(const V3Number& expr, const V3Number& ctrl1, const V3Number& ctrl2,
|
||||
const V3Number& ctrl3);
|
||||
V3Number& opCountOnes(const V3Number& lhs);
|
||||
@ -375,7 +374,6 @@ public:
|
||||
V3Number& opAnd(const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opChangeXor(const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opXor(const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opXnor(const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opOr(const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opShiftR(const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opShiftRS(const V3Number& lhs, const V3Number& rhs, // Arithmetic w/carry
|
||||
|
@ -47,8 +47,6 @@ void test(const string& lhss, const string& op, const string& rhss, const string
|
||||
gotnum.opRedAnd(lhnum);
|
||||
} else if (op == "redXor") {
|
||||
gotnum.opRedXor(lhnum);
|
||||
} else if (op == "redXnor") {
|
||||
gotnum.opRedXnor(lhnum);
|
||||
} else if (op == "concat") {
|
||||
gotnum.opConcat(lhnum, rhnum);
|
||||
} else if (op == "repl") {
|
||||
|
@ -254,7 +254,6 @@ private:
|
||||
// Widths: 1 bit out, Any width lhs
|
||||
virtual void visit(AstRedAnd* nodep) override { visit_red_and_or(nodep); }
|
||||
virtual void visit(AstRedOr* nodep) override { visit_red_and_or(nodep); }
|
||||
virtual void visit(AstRedXnor* nodep) override { visit_red_and_or(nodep); }
|
||||
virtual void visit(AstRedXor* nodep) override { visit_red_and_or(nodep); }
|
||||
virtual void visit(AstOneHot* nodep) override { visit_red_and_or(nodep); }
|
||||
virtual void visit(AstOneHot0* nodep) override { visit_red_and_or(nodep); }
|
||||
@ -300,7 +299,6 @@ private:
|
||||
// Real: Not allowed
|
||||
virtual void visit(AstAnd* nodep) override { visit_boolmath_and_or(nodep); }
|
||||
virtual void visit(AstOr* nodep) override { visit_boolmath_and_or(nodep); }
|
||||
virtual void visit(AstXnor* nodep) override { visit_boolmath_and_or(nodep); }
|
||||
virtual void visit(AstXor* nodep) override { visit_boolmath_and_or(nodep); }
|
||||
virtual void visit(AstBufIf1* nodep) override {
|
||||
visit_boolmath_and_or(nodep);
|
||||
|
@ -4148,7 +4148,7 @@ expr<nodep>: // IEEE: part of expression/constant_expression/primary
|
||||
| '^' ~r~expr %prec prREDUCTION { $$ = new AstRedXor ($1,$2); }
|
||||
| yP_NAND ~r~expr %prec prREDUCTION { $$ = new AstLogNot($1, new AstRedAnd($1, $2)); }
|
||||
| yP_NOR ~r~expr %prec prREDUCTION { $$ = new AstLogNot($1, new AstRedOr($1, $2)); }
|
||||
| yP_XNOR ~r~expr %prec prREDUCTION { $$ = new AstRedXnor ($1,$2); }
|
||||
| yP_XNOR ~r~expr %prec prREDUCTION { $$ = new AstLogNot($1, new AstRedXor($1, $2)); }
|
||||
//
|
||||
// // IEEE: inc_or_dec_expression
|
||||
| ~l~inc_or_dec_expression { $<fl>$=$<fl>1; $$ = $1; }
|
||||
@ -4189,9 +4189,9 @@ expr<nodep>: // IEEE: part of expression/constant_expression/primary
|
||||
| ~l~expr '&' ~r~expr { $$ = new AstAnd ($2,$1,$3); }
|
||||
| ~l~expr '|' ~r~expr { $$ = new AstOr ($2,$1,$3); }
|
||||
| ~l~expr '^' ~r~expr { $$ = new AstXor ($2,$1,$3); }
|
||||
| ~l~expr yP_XNOR ~r~expr { $$ = new AstXnor ($2,$1,$3); }
|
||||
| ~l~expr yP_NOR ~r~expr { $$ = new AstNot($2,new AstOr ($2,$1,$3)); }
|
||||
| ~l~expr yP_NAND ~r~expr { $$ = new AstNot($2,new AstAnd ($2,$1,$3)); }
|
||||
| ~l~expr yP_XNOR ~r~expr { $$ = new AstNot{$2, new AstXor{$2, $1, $3}}; }
|
||||
| ~l~expr yP_NOR ~r~expr { $$ = new AstNot{$2, new AstOr{$2, $1, $3}}; }
|
||||
| ~l~expr yP_NAND ~r~expr { $$ = new AstNot{$2, new AstAnd{$2, $1, $3}}; }
|
||||
| ~l~expr yP_SLEFT ~r~expr { $$ = new AstShiftL ($2,$1,$3); }
|
||||
| ~l~expr yP_SRIGHT ~r~expr { $$ = new AstShiftR ($2,$1,$3); }
|
||||
| ~l~expr yP_SSRIGHT ~r~expr { $$ = new AstShiftRS ($2,$1,$3); }
|
||||
|
Loading…
Reference in New Issue
Block a user