cxxrtl: ignore cell input signedness when it is irrelevant.
authorwhitequark <whitequark@whitequark.org>
Tue, 9 Jun 2020 07:26:13 +0000 (07:26 +0000)
committerwhitequark <whitequark@whitequark.org>
Tue, 9 Jun 2020 07:26:13 +0000 (07:26 +0000)
Before this commit, Verilog expressions like `x && 1` would result in
references to `logic_and_us` in generated CXXRTL code, which would
not compile. After this commit, since cells like that actually behave
the same regardless of signedness attributes, the signedness is
ignored, which also reduces the template instantiation pressure.

backends/cxxrtl/cxxrtl.h
backends/cxxrtl/cxxrtl_backend.cc

index 30f4667c5d98da53fc4843a22b0faea66fddd062..c988c9e80a4f2eea2bcf865ed44cc59a665de9be 100644 (file)
@@ -829,73 +829,55 @@ constexpr T max(const T &a, const T &b) {
 
 // Logic operations
 template<size_t BitsY, size_t BitsA>
-value<BitsY> not_u(const value<BitsA> &a) {
-       return a.template zcast<BitsY>().bit_not();
-}
-
-template<size_t BitsY, size_t BitsA>
-value<BitsY> not_s(const value<BitsA> &a) {
-       return a.template scast<BitsY>().bit_not();
-}
-
-template<size_t BitsY, size_t BitsA>
-value<BitsY> logic_not_u(const value<BitsA> &a) {
+value<BitsY> logic_not(const value<BitsA> &a) {
        return value<BitsY> { a ? 0u : 1u };
 }
 
-template<size_t BitsY, size_t BitsA>
-value<BitsY> logic_not_s(const value<BitsA> &a) {
-       return value<BitsY> { a ? 0u : 1u };
+template<size_t BitsY, size_t BitsA, size_t BitsB>
+value<BitsY> logic_and(const value<BitsA> &a, const value<BitsB> &b) {
+       return value<BitsY> { (bool(a) & bool(b)) ? 1u : 0u };
 }
 
-template<size_t BitsY, size_t BitsA>
-value<BitsY> reduce_and_u(const value<BitsA> &a) {
-       return value<BitsY> { a.bit_not().is_zero() ? 1u : 0u };
+template<size_t BitsY, size_t BitsA, size_t BitsB>
+value<BitsY> logic_or(const value<BitsA> &a, const value<BitsB> &b) {
+       return value<BitsY> { (bool(a) | bool(b)) ? 1u : 0u };
 }
 
+// Reduction operations
 template<size_t BitsY, size_t BitsA>
-value<BitsY> reduce_and_s(const value<BitsA> &a) {
+value<BitsY> reduce_and(const value<BitsA> &a) {
        return value<BitsY> { a.bit_not().is_zero() ? 1u : 0u };
 }
 
 template<size_t BitsY, size_t BitsA>
-value<BitsY> reduce_or_u(const value<BitsA> &a) {
-       return value<BitsY> { a ? 1u : 0u };
-}
-
-template<size_t BitsY, size_t BitsA>
-value<BitsY> reduce_or_s(const value<BitsA> &a) {
+value<BitsY> reduce_or(const value<BitsA> &a) {
        return value<BitsY> { a ? 1u : 0u };
 }
 
 template<size_t BitsY, size_t BitsA>
-value<BitsY> reduce_xor_u(const value<BitsA> &a) {
-       return value<BitsY> { (a.ctpop() % 2) ? 1u : 0u };
-}
-
-template<size_t BitsY, size_t BitsA>
-value<BitsY> reduce_xor_s(const value<BitsA> &a) {
+value<BitsY> reduce_xor(const value<BitsA> &a) {
        return value<BitsY> { (a.ctpop() % 2) ? 1u : 0u };
 }
 
 template<size_t BitsY, size_t BitsA>
-value<BitsY> reduce_xnor_u(const value<BitsA> &a) {
+value<BitsY> reduce_xnor(const value<BitsA> &a) {
        return value<BitsY> { (a.ctpop() % 2) ? 0u : 1u };
 }
 
 template<size_t BitsY, size_t BitsA>
-value<BitsY> reduce_xnor_s(const value<BitsA> &a) {
-       return value<BitsY> { (a.ctpop() % 2) ? 0u : 1u };
+value<BitsY> reduce_bool(const value<BitsA> &a) {
+       return value<BitsY> { a ? 1u : 0u };
 }
 
+// Bitwise operations
 template<size_t BitsY, size_t BitsA>
-value<BitsY> reduce_bool_u(const value<BitsA> &a) {
-       return value<BitsY> { a ? 1u : 0u };
+value<BitsY> not_u(const value<BitsA> &a) {
+       return a.template zcast<BitsY>().bit_not();
 }
 
 template<size_t BitsY, size_t BitsA>
-value<BitsY> reduce_bool_s(const value<BitsA> &a) {
-       return value<BitsY> { a ? 1u : 0u };
+value<BitsY> not_s(const value<BitsA> &a) {
+       return a.template scast<BitsY>().bit_not();
 }
 
 template<size_t BitsY, size_t BitsA, size_t BitsB>
@@ -938,26 +920,6 @@ value<BitsY> xnor_ss(const value<BitsA> &a, const value<BitsB> &b) {
        return a.template scast<BitsY>().bit_xor(b.template scast<BitsY>()).bit_not();
 }
 
-template<size_t BitsY, size_t BitsA, size_t BitsB>
-value<BitsY> logic_and_uu(const value<BitsA> &a, const value<BitsB> &b) {
-       return value<BitsY> { (bool(a) & bool(b)) ? 1u : 0u };
-}
-
-template<size_t BitsY, size_t BitsA, size_t BitsB>
-value<BitsY> logic_and_ss(const value<BitsA> &a, const value<BitsB> &b) {
-       return value<BitsY> { (bool(a) & bool(b)) ? 1u : 0u };
-}
-
-template<size_t BitsY, size_t BitsA, size_t BitsB>
-value<BitsY> logic_or_uu(const value<BitsA> &a, const value<BitsB> &b) {
-       return value<BitsY> { (bool(a) | bool(b)) ? 1u : 0u };
-}
-
-template<size_t BitsY, size_t BitsA, size_t BitsB>
-value<BitsY> logic_or_ss(const value<BitsA> &a, const value<BitsB> &b) {
-       return value<BitsY> { (bool(a) | bool(b)) ? 1u : 0u };
-}
-
 template<size_t BitsY, size_t BitsA, size_t BitsB>
 value<BitsY> shl_uu(const value<BitsA> &a, const value<BitsB> &b) {
        return a.template zcast<BitsY>().template shl(b);
index bf01b263a7089fab45d505269682edc77db96395..2646f93713e7ba649b8969ad1eb04deec01ebfbb 100644 (file)
@@ -192,6 +192,13 @@ bool is_binary_cell(RTLIL::IdString type)
                ID($add), ID($sub), ID($mul), ID($div), ID($mod));
 }
 
+bool is_extending_cell(RTLIL::IdString type)
+{
+       return !type.in(
+               ID($logic_not), ID($logic_and), ID($logic_or),
+               ID($reduce_and), ID($reduce_or), ID($reduce_xor), ID($reduce_xnor), ID($reduce_bool));
+}
+
 bool is_elidable_cell(RTLIL::IdString type)
 {
        return is_unary_cell(type) || is_binary_cell(type) || type.in(
@@ -907,17 +914,19 @@ struct CxxrtlWorker {
        {
                // Unary cells
                if (is_unary_cell(cell->type)) {
-                       f << cell->type.substr(1) << '_' <<
-                            (cell->getParam(ID::A_SIGNED).as_bool() ? 's' : 'u') <<
-                            "<" << cell->getParam(ID::Y_WIDTH).as_int() << ">(";
+                       f << cell->type.substr(1);
+                       if (is_extending_cell(cell->type))
+                               f << '_' << (cell->getParam(ID::A_SIGNED).as_bool() ? 's' : 'u');
+                       f << "<" << cell->getParam(ID::Y_WIDTH).as_int() << ">(";
                        dump_sigspec_rhs(cell->getPort(ID::A));
                        f << ")";
                // Binary cells
                } else if (is_binary_cell(cell->type)) {
-                       f << cell->type.substr(1) << '_' <<
-                            (cell->getParam(ID::A_SIGNED).as_bool() ? 's' : 'u') <<
-                            (cell->getParam(ID::B_SIGNED).as_bool() ? 's' : 'u') <<
-                            "<" << cell->getParam(ID::Y_WIDTH).as_int() << ">(";
+                       f << cell->type.substr(1);
+                       if (is_extending_cell(cell->type))
+                               f << '_' << (cell->getParam(ID::A_SIGNED).as_bool() ? 's' : 'u') <<
+                                           (cell->getParam(ID::B_SIGNED).as_bool() ? 's' : 'u');
+                       f << "<" << cell->getParam(ID::Y_WIDTH).as_int() << ">(";
                        dump_sigspec_rhs(cell->getPort(ID::A));
                        f << ", ";
                        dump_sigspec_rhs(cell->getPort(ID::B));