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:
Wilson Snyder 2020-12-10 00:04:10 -05:00
parent 5b2844e1be
commit af0e535015
11 changed files with 6 additions and 120 deletions

View File

@ -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

View File

@ -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]);

View File

@ -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; },
);
}

View File

@ -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)

View File

@ -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}");

View File

@ -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);
}

View File

@ -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);

View File

@ -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

View File

@ -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") {

View File

@ -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);

View File

@ -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); }