From ef4e1594470b46eab6f311998511a5eee22a96d3 Mon Sep 17 00:00:00 2001 From: whitequark Date: Tue, 9 Jun 2020 07:26:13 +0000 Subject: [PATCH] cxxrtl: ignore cell input signedness when it is irrelevant. 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 | 122 ++++++++++-------------------- backends/cxxrtl/cxxrtl_backend.cc | 23 ++++-- 2 files changed, 58 insertions(+), 87 deletions(-) diff --git a/backends/cxxrtl/cxxrtl.h b/backends/cxxrtl/cxxrtl.h index 30f4667c5..c988c9e80 100644 --- a/backends/cxxrtl/cxxrtl.h +++ b/backends/cxxrtl/cxxrtl.h @@ -829,6 +829,48 @@ constexpr T max(const T &a, const T &b) { // Logic operations template +value logic_not(const value &a) { + return value { a ? 0u : 1u }; +} + +template +value logic_and(const value &a, const value &b) { + return value { (bool(a) & bool(b)) ? 1u : 0u }; +} + +template +value logic_or(const value &a, const value &b) { + return value { (bool(a) | bool(b)) ? 1u : 0u }; +} + +// Reduction operations +template +value reduce_and(const value &a) { + return value { a.bit_not().is_zero() ? 1u : 0u }; +} + +template +value reduce_or(const value &a) { + return value { a ? 1u : 0u }; +} + +template +value reduce_xor(const value &a) { + return value { (a.ctpop() % 2) ? 1u : 0u }; +} + +template +value reduce_xnor(const value &a) { + return value { (a.ctpop() % 2) ? 0u : 1u }; +} + +template +value reduce_bool(const value &a) { + return value { a ? 1u : 0u }; +} + +// Bitwise operations +template value not_u(const value &a) { return a.template zcast().bit_not(); } @@ -838,66 +880,6 @@ value not_s(const value &a) { return a.template scast().bit_not(); } -template -value logic_not_u(const value &a) { - return value { a ? 0u : 1u }; -} - -template -value logic_not_s(const value &a) { - return value { a ? 0u : 1u }; -} - -template -value reduce_and_u(const value &a) { - return value { a.bit_not().is_zero() ? 1u : 0u }; -} - -template -value reduce_and_s(const value &a) { - return value { a.bit_not().is_zero() ? 1u : 0u }; -} - -template -value reduce_or_u(const value &a) { - return value { a ? 1u : 0u }; -} - -template -value reduce_or_s(const value &a) { - return value { a ? 1u : 0u }; -} - -template -value reduce_xor_u(const value &a) { - return value { (a.ctpop() % 2) ? 1u : 0u }; -} - -template -value reduce_xor_s(const value &a) { - return value { (a.ctpop() % 2) ? 1u : 0u }; -} - -template -value reduce_xnor_u(const value &a) { - return value { (a.ctpop() % 2) ? 0u : 1u }; -} - -template -value reduce_xnor_s(const value &a) { - return value { (a.ctpop() % 2) ? 0u : 1u }; -} - -template -value reduce_bool_u(const value &a) { - return value { a ? 1u : 0u }; -} - -template -value reduce_bool_s(const value &a) { - return value { a ? 1u : 0u }; -} - template value and_uu(const value &a, const value &b) { return a.template zcast().bit_and(b.template zcast()); @@ -938,26 +920,6 @@ value xnor_ss(const value &a, const value &b) { return a.template scast().bit_xor(b.template scast()).bit_not(); } -template -value logic_and_uu(const value &a, const value &b) { - return value { (bool(a) & bool(b)) ? 1u : 0u }; -} - -template -value logic_and_ss(const value &a, const value &b) { - return value { (bool(a) & bool(b)) ? 1u : 0u }; -} - -template -value logic_or_uu(const value &a, const value &b) { - return value { (bool(a) | bool(b)) ? 1u : 0u }; -} - -template -value logic_or_ss(const value &a, const value &b) { - return value { (bool(a) | bool(b)) ? 1u : 0u }; -} - template value shl_uu(const value &a, const value &b) { return a.template zcast().template shl(b); diff --git a/backends/cxxrtl/cxxrtl_backend.cc b/backends/cxxrtl/cxxrtl_backend.cc index bf01b263a..2646f9371 100644 --- a/backends/cxxrtl/cxxrtl_backend.cc +++ b/backends/cxxrtl/cxxrtl_backend.cc @@ -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));