diff --git a/src/optimization/ConstantPropagation.cpp b/src/optimization/ConstantPropagation.cpp index d151cdd5..947acde3 100644 --- a/src/optimization/ConstantPropagation.cpp +++ b/src/optimization/ConstantPropagation.cpp @@ -5,19 +5,17 @@ #include "ConstantPropagation.h" #include #include +#include #include #include #include +#include "Reduction.h" #include "SNLDesignModeling.h" +#include "SNLDesignTruthTable.h" #include "SNLLibraryTruthTables.h" #include "SNLScalarNet.h" -#include "Utils.h" -#include -#include "SNLDesignTruthTable.h" #include "SNLTruthTable.h" -#include "Reduction.h" -#include "bne.h" - +#include "Utils.h" using namespace naja::DNL; using namespace naja::NAJA_OPT; using namespace naja::SNL; @@ -130,19 +128,28 @@ void ConstantPropagation::initializeTypesID() { } void ConstantPropagation::collectConstants() { - auto logic0 = SNLLibraryTruthTables::getDesignForTruthTable( - *(dnl_->getTop().getSNLModel()->getDB()->getPrimitiveLibraries().begin()), - SNLTruthTable::Logic0()) - .first; - auto logic1 = SNLLibraryTruthTables::getDesignForTruthTable( - *(dnl_->getTop().getSNLModel()->getDB()->getPrimitiveLibraries().begin()), - SNLTruthTable::Logic1()) - .first; + auto logic0 = SNLLibraryTruthTables::getDesignForTruthTable( + *(dnl_->getTop() + .getSNLModel() + ->getDB() + ->getPrimitiveLibraries() + .begin()), + SNLTruthTable::Logic0()) + .first; + auto logic1 = SNLLibraryTruthTables::getDesignForTruthTable( + *(dnl_->getTop() + .getSNLModel() + ->getDB() + ->getPrimitiveLibraries() + .begin()), + SNLTruthTable::Logic1()) + .first; for (DNLID leaf : dnl_->getLeaves()) { DNLInstanceFull instance = dnl_->getDNLInstanceFromID(leaf); if (instance.getSNLModel() == logic0) { for (DNLID termId = instance.getTermIndexes().first; - termId != DNLID_MAX and termId <= instance.getTermIndexes().second; termId++) { + termId != DNLID_MAX and termId <= instance.getTermIndexes().second; + termId++) { const DNLTerminalFull& term = dnl_->getDNLTerminalFromID(termId); if (term.getSnlBitTerm()->getDirection() == SNLBitTerm::Direction::Output) { @@ -152,7 +159,8 @@ void ConstantPropagation::collectConstants() { } } else if (instance.getSNLModel() == logic1) { for (DNLID termId = instance.getTermIndexes().first; - termId != DNLID_MAX and termId <= instance.getTermIndexes().second; termId++) { + termId != DNLID_MAX and termId <= instance.getTermIndexes().second; + termId++) { const DNLTerminalFull& term = dnl_->getDNLTerminalFromID(termId); if (term.getSnlBitTerm()->getDirection() == SNLBitTerm::Direction::Output) { @@ -163,13 +171,13 @@ void ConstantPropagation::collectConstants() { } } initialConstants0_.insert(dnl_->getDNLIsoDB().getConstant0Isos().begin(), - dnl_->getDNLIsoDB().getConstant0Isos().end()); + dnl_->getDNLIsoDB().getConstant0Isos().end()); initialConstants1_.insert(dnl_->getDNLIsoDB().getConstant1Isos().begin(), - dnl_->getDNLIsoDB().getConstant1Isos().end()); + dnl_->getDNLIsoDB().getConstant1Isos().end()); constants0_.insert(dnl_->getDNLIsoDB().getConstant0Isos().begin(), - dnl_->getDNLIsoDB().getConstant0Isos().end()); + dnl_->getDNLIsoDB().getConstant0Isos().end()); constants1_.insert(dnl_->getDNLIsoDB().getConstant1Isos().begin(), - dnl_->getDNLIsoDB().getConstant1Isos().end()); + dnl_->getDNLIsoDB().getConstant1Isos().end()); } unsigned ConstantPropagation::computeOutputValue(DNLID instanceID) { @@ -183,7 +191,8 @@ unsigned ConstantPropagation::computeOutputValue(DNLID instanceID) { } std::vector> constTerms; for (DNLID termId = instance.getTermIndexes().first; - termId != DNLID_MAX and termId <= instance.getTermIndexes().second; termId++) { + termId != DNLID_MAX and termId <= instance.getTermIndexes().second; + termId++) { const DNLTerminalFull& term = dnl_->getDNLTerminalFromID(termId); if (term.getSnlBitTerm()->getDirection() != SNLBitTerm::Direction::Input) { continue; @@ -194,7 +203,8 @@ unsigned ConstantPropagation::computeOutputValue(DNLID instanceID) { constTerms.push_back({term.getSnlTerm()->getBitTerm()->getID(), 1}); } } - SNLTruthTable reducedTruthTable = ReductionOptimization::reduceTruthTable(instance.getSNLInstance(), truthTable, constTerms); + SNLTruthTable reducedTruthTable = ReductionOptimization::reduceTruthTable( + instance.getSNLInstance(), truthTable, constTerms); if (reducedTruthTable.all0()) { return 0; } else if (reducedTruthTable.all1()) { @@ -207,20 +217,20 @@ void ConstantPropagation::performConstantPropagationAnalysis() { std::set constants; constants.insert(initialConstants0_.begin(), initialConstants0_.end()); constants.insert(initialConstants1_.begin(), initialConstants1_.end()); - #ifdef DEBUG_PRINTS +#ifdef DEBUG_PRINTS // LCOV_EXCL_START printf("Constant Propagation : Number of constants before: %lu\n", constants.size()); size_t loop = 0; - // LCOV_EXCL_STOP - #endif +// LCOV_EXCL_STOP +#endif while (!constants.empty()) { - #ifdef DEBUG_PRINTS +#ifdef DEBUG_PRINTS // LCOV_EXCL_START printf("loop: %lu\n", loop); loop++; // LCOV_EXCL_STOP - #endif +#endif std::set constantsNew; for (DNLID constant : constants) { DNLIso iso = dnl_->getDNLIsoDB().getIsoFromIsoIDconst(constant); @@ -275,7 +285,7 @@ void ConstantPropagation::performConstantPropagationAnalysis() { if (isConst) { partialConstantInstances_.erase(reader.getDNLInstance().getID()); // Analyze the contants in ouptus and propagate them - unsigned newConst = (unsigned) -1; + unsigned newConst = (unsigned)-1; if (truthTableEngine_ && q.isNull()) { newConst = computeOutputValue(reader.getDNLInstance().getID()); } else { @@ -292,7 +302,7 @@ void ConstantPropagation::performConstantPropagationAnalysis() { partialConstantInstances_.erase(reader.getDNLInstance().getID()); } } else { - unsigned newConst = (unsigned) -1; + unsigned newConst = (unsigned)-1; if (truthTableEngine_ && q.isNull()) { newConst = computeOutputValue(reader.getDNLInstance().getID()); } else { @@ -324,10 +334,11 @@ void ConstantPropagation::performConstantPropagationAnalysis() { constantsNew.insert(iso); constants0_.insert(iso); partialConstantInstances_.erase(reader.getDNLInstance().getID()); - + } else { if (!reader.getDNLInstance().isTop()) { - partialConstantInstances_.insert(reader.getDNLInstance().getID()); + partialConstantInstances_.insert( + reader.getDNLInstance().getID()); } } } @@ -357,7 +368,8 @@ unsigned ConstantPropagation::computeOutputValueForConstantInstance( designObjectID2Type_[instance.getSNLInstance()->getModel()->getID()]) { case Type::AND: { for (DNLID termId = instance.getTermIndexes().first; - termId != DNLID_MAX and termId <= instance.getTermIndexes().second; termId++) { + termId != DNLID_MAX and termId <= instance.getTermIndexes().second; + termId++) { const DNLTerminalFull& term = dnl_->getDNLTerminalFromID(termId); if (term.getSnlBitTerm()->getDirection() != SNLBitTerm::Direction::Input) { @@ -381,7 +393,8 @@ unsigned ConstantPropagation::computeOutputValueForConstantInstance( } case Type::OR: { for (DNLID termId = instance.getTermIndexes().first; - termId != DNLID_MAX and termId <= instance.getTermIndexes().second; termId++) { + termId != DNLID_MAX and termId <= instance.getTermIndexes().second; + termId++) { const DNLTerminalFull& term = dnl_->getDNLTerminalFromID(termId); if (constants1_.find(term.getIsoID()) != constants1_.end()) { #ifdef DEBUG_PRINTS @@ -402,7 +415,8 @@ unsigned ConstantPropagation::computeOutputValueForConstantInstance( case Type::XOR: { unsigned count = 0; for (DNLID termId = instance.getTermIndexes().first; - termId != DNLID_MAX and termId <= instance.getTermIndexes().second; termId++) { + termId != DNLID_MAX and termId <= instance.getTermIndexes().second; + termId++) { const DNLTerminalFull& term = dnl_->getDNLTerminalFromID(termId); if (term.getSnlBitTerm()->getDirection() != SNLBitTerm::Direction::Input) { @@ -421,7 +435,8 @@ unsigned ConstantPropagation::computeOutputValueForConstantInstance( } case Type::NAND: { for (DNLID termId = instance.getTermIndexes().first; - termId != DNLID_MAX and termId <= instance.getTermIndexes().second; termId++) { + termId != DNLID_MAX and termId <= instance.getTermIndexes().second; + termId++) { const DNLTerminalFull& term = dnl_->getDNLTerminalFromID(termId); if (term.getSnlBitTerm()->getDirection() != SNLBitTerm::Direction::Input) { @@ -445,7 +460,8 @@ unsigned ConstantPropagation::computeOutputValueForConstantInstance( } case Type::NOR: { for (DNLID termId = instance.getTermIndexes().first; - termId != DNLID_MAX and termId <= instance.getTermIndexes().second; termId++) { + termId != DNLID_MAX and termId <= instance.getTermIndexes().second; + termId++) { const DNLTerminalFull& term = dnl_->getDNLTerminalFromID(termId); if (term.getSnlBitTerm()->getDirection() != SNLBitTerm::Direction::Input) { @@ -470,7 +486,8 @@ unsigned ConstantPropagation::computeOutputValueForConstantInstance( case Type::XNOR: { unsigned count = 0; for (DNLID termId = instance.getTermIndexes().first; - termId != DNLID_MAX and termId <= instance.getTermIndexes().second; termId++) { + termId != DNLID_MAX and termId <= instance.getTermIndexes().second; + termId++) { const DNLTerminalFull& term = dnl_->getDNLTerminalFromID(termId); if (term.getSnlBitTerm()->getDirection() != SNLBitTerm::Direction::Input) { @@ -490,7 +507,8 @@ unsigned ConstantPropagation::computeOutputValueForConstantInstance( case Type::INV: { DNLID iso = DNLID_MAX; for (DNLID termId = instance.getTermIndexes().first; - termId != DNLID_MAX and termId <= instance.getTermIndexes().second; termId++) { + termId != DNLID_MAX and termId <= instance.getTermIndexes().second; + termId++) { const DNLTerminalFull& term = dnl_->getDNLTerminalFromID(termId); if (term.getSnlBitTerm()->getDirection() != SNLBitTerm::Direction::Input) { @@ -536,7 +554,8 @@ unsigned ConstantPropagation::computeOutputValueForConstantInstance( case Type::DFF: { unsigned d = (unsigned)-1; for (DNLID termId = instance.getTermIndexes().first; - termId != DNLID_MAX and termId <= instance.getTermIndexes().second; termId++) { + termId != DNLID_MAX and termId <= instance.getTermIndexes().second; + termId++) { const DNLTerminalFull& term = dnl_->getDNLTerminalFromID(termId); if (term.getSnlBitTerm()->getDirection() != SNLBitTerm::Direction::Input) { @@ -568,7 +587,8 @@ unsigned ConstantPropagation::computeOutputValueForConstantInstance( unsigned d = (unsigned)-1; unsigned q = (unsigned)-1; for (DNLID termId = instance.getTermIndexes().first; - termId != DNLID_MAX and termId <= instance.getTermIndexes().second; termId++) { + termId != DNLID_MAX and termId <= instance.getTermIndexes().second; + termId++) { const DNLTerminalFull& term = dnl_->getDNLTerminalFromID(termId); if (term.getSnlBitTerm()->getDirection() != SNLBitTerm::Direction::Input) { @@ -608,7 +628,8 @@ unsigned ConstantPropagation::computeOutputValueForConstantInstance( unsigned b1 = (unsigned)-1; unsigned b2 = (unsigned)-1; for (DNLID termId = instance.getTermIndexes().first; - termId != DNLID_MAX and termId <= instance.getTermIndexes().second; termId++) { + termId != DNLID_MAX and termId <= instance.getTermIndexes().second; + termId++) { const DNLTerminalFull& term = dnl_->getDNLTerminalFromID(termId); if (term.getSnlBitTerm()->getDirection() != SNLBitTerm::Direction::Input) { @@ -667,7 +688,8 @@ unsigned ConstantPropagation::computeOutputValueForPartiallyConstantInstance( designObjectID2Type_[instance.getSNLInstance()->getModel()->getID()]) { case Type::AND: { for (DNLID termId = instance.getTermIndexes().first; - termId != DNLID_MAX and termId <= instance.getTermIndexes().second; termId++) { + termId != DNLID_MAX and termId <= instance.getTermIndexes().second; + termId++) { const DNLTerminalFull& term = dnl_->getDNLTerminalFromID(termId); if (term.getSnlBitTerm()->getDirection() != SNLBitTerm::Direction::Input) { @@ -691,7 +713,8 @@ unsigned ConstantPropagation::computeOutputValueForPartiallyConstantInstance( } case Type::OR: { for (DNLID termId = instance.getTermIndexes().first; - termId != DNLID_MAX and termId <= instance.getTermIndexes().second; termId++) { + termId != DNLID_MAX and termId <= instance.getTermIndexes().second; + termId++) { const DNLTerminalFull& term = dnl_->getDNLTerminalFromID(termId); if (constants1_.find(term.getIsoID()) != constants1_.end()) { #ifdef DEBUG_PRINTS @@ -711,7 +734,8 @@ unsigned ConstantPropagation::computeOutputValueForPartiallyConstantInstance( } case Type::NAND: { for (DNLID termId = instance.getTermIndexes().first; - termId != DNLID_MAX and termId <= instance.getTermIndexes().second; termId++) { + termId != DNLID_MAX and termId <= instance.getTermIndexes().second; + termId++) { const DNLTerminalFull& term = dnl_->getDNLTerminalFromID(termId); if (term.getSnlBitTerm()->getDirection() != SNLBitTerm::Direction::Input) { @@ -739,7 +763,8 @@ unsigned ConstantPropagation::computeOutputValueForPartiallyConstantInstance( } case Type::NOR: { for (DNLID termId = instance.getTermIndexes().first; - termId != DNLID_MAX and termId <= instance.getTermIndexes().second; termId++) { + termId != DNLID_MAX and termId <= instance.getTermIndexes().second; + termId++) { const DNLTerminalFull& term = dnl_->getDNLTerminalFromID(termId); if (term.getSnlBitTerm()->getDirection() != SNLBitTerm::Direction::Input) { @@ -764,7 +789,8 @@ unsigned ConstantPropagation::computeOutputValueForPartiallyConstantInstance( case Type::DFF: { unsigned d = (unsigned)-1; for (DNLID termId = instance.getTermIndexes().first; - termId != DNLID_MAX and termId <= instance.getTermIndexes().second; termId++) { + termId != DNLID_MAX and termId <= instance.getTermIndexes().second; + termId++) { const DNLTerminalFull& term = dnl_->getDNLTerminalFromID(termId); if (term.getSnlBitTerm()->getDirection() != SNLBitTerm::Direction::Input) { @@ -796,7 +822,8 @@ unsigned ConstantPropagation::computeOutputValueForPartiallyConstantInstance( unsigned d = (unsigned)-1; unsigned q = (unsigned)-1; for (DNLID termId = instance.getTermIndexes().first; - termId != DNLID_MAX and termId <= instance.getTermIndexes().second; termId++) { + termId != DNLID_MAX and termId <= instance.getTermIndexes().second; + termId++) { const DNLTerminalFull& term = dnl_->getDNLTerminalFromID(termId); if (term.getSnlBitTerm()->getDirection() != SNLBitTerm::Direction::Input) { @@ -837,7 +864,8 @@ unsigned ConstantPropagation::computeOutputValueForPartiallyConstantInstance( unsigned b1 = (unsigned)-1; unsigned b2 = (unsigned)-1; for (DNLID termId = instance.getTermIndexes().first; - termId != DNLID_MAX and termId <= instance.getTermIndexes().second; termId++) { + termId != DNLID_MAX and termId <= instance.getTermIndexes().second; + termId++) { const DNLTerminalFull& term = dnl_->getDNLTerminalFromID(termId); if (term.getSnlBitTerm()->getDirection() != SNLBitTerm::Direction::Input) { @@ -883,6 +911,74 @@ unsigned ConstantPropagation::computeOutputValueForPartiallyConstantInstance( return (unsigned)-1; } +void ConstantPropagation::changeDriverToLocal0(SNLInstTerm* term, DNLID id) { + term->setNet(nullptr); + std::string name(std::string("logic0_naja_") + + term->getDesign()->getName().getString()); + auto netName = SNLName(name + "_net"); + SNLNet* assign0 = term->getDesign()->getNet(netName); + if (nullptr == assign0) { + assign0 = SNLScalarNet::create(term->getDesign(), netName); + } + assign0->setType(naja::SNL::SNLNet::Type::Supply0); + term->setNet(assign0); + SNLTruthTable tt(0, 0); + // find primitives library + if (term->getDB()->getPrimitiveLibraries().size() != 1) { + // LCOV_EXCL_START + throw SNLException("There should be only one primitive library"); + // LCOV_EXCL_STOP + } + auto primitives = *term->getDB()->getPrimitiveLibraries().begin(); + auto logic0 = + SNLLibraryTruthTables::getDesignForTruthTable(primitives, tt).first; + + SNLInstance* logic0Inst = term->getDesign()->getInstance(SNLName(name)); + if (nullptr == logic0Inst) { + if (logic0 == nullptr) { + // LCOV_EXCL_START + throw SNLException("No logic0 design found"); + // LCOV_EXCL_STOP + } + logic0Inst = SNLInstance::create(term->getDesign(), logic0, SNLName(name)); + } + (*logic0Inst->getInstTerms().begin())->setNet(assign0); +} + +void ConstantPropagation::changeDriverToLocal1(SNLInstTerm* term, DNLID id) { + term->setNet(nullptr); + std::string name(std::string("logic1_naja_") + + term->getDesign()->getName().getString()); + auto netName = SNLName(name + "_net"); + SNLNet* assign1 = term->getDesign()->getNet(netName); + if (nullptr == assign1) { + assign1 = SNLScalarNet::create(term->getDesign(), netName); + } + assign1->setType(naja::SNL::SNLNet::Type::Supply1); + term->setNet(assign1); + SNLTruthTable tt(0, 1); + + // find primitives library + if (term->getDB()->getPrimitiveLibraries().size() != 1) { + // LCOV_EXCL_START + throw SNLException("There should be only one primitive library"); + // LCOV_EXCL_STOP + } + auto primitives = *term->getDB()->getPrimitiveLibraries().begin(); + auto logic1 = + SNLLibraryTruthTables::getDesignForTruthTable(primitives, tt).first; + SNLInstance* logic1Inst = term->getDesign()->getInstance(SNLName(name)); + if (nullptr == logic1Inst) { + if (logic1 == nullptr) { + // LCOV_EXCL_START + throw SNLException("No logic1 design found"); + // LCOV_EXCL_STOP + } + logic1Inst = SNLInstance::create(term->getDesign(), logic1, SNLName(name)); + } + (*logic1Inst->getInstTerms().begin())->setNet(assign1); +} + void ConstantPropagation::propagateConstants() { for (DNLID iso : constants0_) { if (initialConstants0_.find(iso) != initialConstants0_.end()) { @@ -906,9 +1002,10 @@ void ConstantPropagation::propagateConstants() { currentInstance = currentInstance.getParentInstance(); } std::reverse(path.begin(), path.end()); - constant0Readers_.push_back( - std::tuple, SNLID::DesignObjectID, DNLID>( - path, readerTerm.getSnlTerm()->getBitTerm()->getID(), readerInst.getID())); + constant0Readers_.push_back(std::tuple, + SNLID::DesignObjectID, DNLID>( + path, readerTerm.getSnlTerm()->getBitTerm()->getID(), + readerInst.getID())); } } for (DNLID iso : constants1_) { @@ -933,9 +1030,10 @@ void ConstantPropagation::propagateConstants() { currentInstance = currentInstance.getParentInstance(); } std::reverse(path.begin(), path.end()); - constant1Readers_.push_back( - std::tuple, SNLID::DesignObjectID, DNLID>( - path, readerTerm.getSnlTerm()->getBitTerm()->getID(), readerInst.getID())); + constant1Readers_.push_back(std::tuple, + SNLID::DesignObjectID, DNLID>( + path, readerTerm.getSnlTerm()->getBitTerm()->getID(), + readerInst.getID())); } } for (DNLID instId : partialConstantInstances_) { @@ -948,48 +1046,111 @@ void ConstantPropagation::propagateConstants() { } std::reverse(path.begin(), path.end()); std::vector> instTerms; - //size_t numInputs = 0; + // size_t numInputs = 0; for (DNLID termId = inst.getTermIndexes().first; termId <= inst.getTermIndexes().second; termId++) { const DNLTerminalFull& term = dnl_->getDNLTerminalFromID(termId); if (term.getSnlBitTerm()->getDirection() == SNLBitTerm::Direction::Input) { - //numInputs++; + // numInputs++; if (constants0_.find(term.getIsoID()) != constants0_.end()) { - instTerms.push_back( - std::pair(term.getSnlTerm()->getBitTerm()->getID(), 0)); + instTerms.push_back(std::pair( + term.getSnlTerm()->getBitTerm()->getID(), 0)); } else if (constants1_.find(term.getIsoID()) != constants1_.end()) { - instTerms.push_back( - std::pair(term.getSnlTerm()->getBitTerm()->getID(), 1)); + instTerms.push_back(std::pair( + term.getSnlTerm()->getBitTerm()->getID(), 1)); } } } - //assert(numInputs > instTerms.size()); + // assert(numInputs > instTerms.size()); partialConstantReaders_.push_back( std::tuple, std::vector>, DNLID>( path, instTerms, inst.getID())); } - BNE::BNE bne; - for (auto& path : constant0Readers_) { - auto context = std::get<0>(path); - context.pop_back(); - bne.addDriveWithConstantAction(context, std::get<0>(path).back(), - std::get<1>(path), 0); - } - for (SNLBitTerm* term : constant0TopReaders_) { - bne.addDriveWithConstantAction(std::vector(), (unsigned) -1, (unsigned) -1, 0, term); - } - for (auto& path : constant1Readers_) { - auto context = std::get<0>(path); - context.pop_back(); - bne.addDriveWithConstantAction(context, std::get<0>(path).back(), - std::get<1>(path), 1); - } - for (SNLBitTerm* term : constant1TopReaders_) { - bne.addDriveWithConstantAction(std::vector(), (unsigned) -1, (unsigned) -1, 1, term); + if (!normalizedUniquification_) { + for (auto& path : constant0Readers_) { + Uniquifier uniquifier(std::get<0>(path), std::get<2>(path)); + uniquifier.process(); + SNLInstTerm* constTerm = + uniquifier.getPathUniq().back()->getInstTerm(std::get<1>(path)); + changeDriverToLocal0(constTerm, std::get<2>(path)); + } + for (SNLBitTerm* term : constant0TopReaders_) { + term->setNet(nullptr); + std::string name(std::string("logic0_naja_") + + term->getDesign()->getName().getString()); + auto netName = SNLName(name + "_net"); + SNLNet* assign0 = term->getDesign()->getNet(netName); + if (nullptr == assign0) { + assign0 = SNLScalarNet::create(term->getDesign(), netName); + } + assign0->setType(naja::SNL::SNLNet::Type::Supply0); + term->setNet(assign0); + SNLTruthTable tt(0, 0); + auto logic0 = SNLLibraryTruthTables::getDesignForTruthTable( + *(term->getDB()->getPrimitiveLibraries().begin()), tt) + .first; + SNLInstance* logic0Inst = term->getDesign()->getInstance(SNLName(name)); + if (nullptr == logic0Inst) { + logic0Inst = + SNLInstance::create(term->getDesign(), logic0, SNLName(name)); + } + (*logic0Inst->getInstTerms().begin())->setNet(assign0); + } + for (auto& path : constant1Readers_) { + Uniquifier uniquifier(std::get<0>(path), std::get<2>(path)); + uniquifier.process(); + SNLInstTerm* constTerm = + uniquifier.getPathUniq().back()->getInstTerm(std::get<1>(path)); + changeDriverToLocal1(constTerm, std::get<2>(path)); + } + for (SNLBitTerm* term : constant1TopReaders_) { + term->setNet(nullptr); + std::string name(std::string("logic1_naja_") + + term->getDesign()->getName().getString()); + auto netName = SNLName(name + "_net"); + SNLNet* assign1 = term->getDesign()->getNet(netName); + if (nullptr == assign1) { + assign1 = SNLScalarNet::create(term->getDesign(), netName); + } + assign1->setType(naja::SNL::SNLNet::Type::Supply1); + term->setNet(assign1); + SNLTruthTable tt(0, 1); + auto logic1 = SNLLibraryTruthTables::getDesignForTruthTable( + *(term->getDB()->getPrimitiveLibraries().begin()), tt) + .first; + SNLInstance* logic1Inst = term->getDesign()->getInstance(SNLName(name)); + if (nullptr == logic1Inst) { + logic1Inst = + SNLInstance::create(term->getDesign(), logic1, SNLName(name)); + } + (*logic1Inst->getInstTerms().begin())->setNet(assign1); + } + } else { + BNE::BNE bne; + for (auto& path : constant0Readers_) { + auto context = std::get<0>(path); + context.pop_back(); + bne.addDriveWithConstantAction(context, std::get<0>(path).back(), + std::get<1>(path), 0); + } + for (SNLBitTerm* term : constant0TopReaders_) { + bne.addDriveWithConstantAction(std::vector(), + (unsigned)-1, (unsigned)-1, 0, term); + } + for (auto& path : constant1Readers_) { + auto context = std::get<0>(path); + context.pop_back(); + bne.addDriveWithConstantAction(context, std::get<0>(path).back(), + std::get<1>(path), 1); + } + for (SNLBitTerm* term : constant1TopReaders_) { + bne.addDriveWithConstantAction(std::vector(), + (unsigned)-1, (unsigned)-1, 1, term); + } + bne.process(); } - bne.process(); } void ConstantPropagation::run() { diff --git a/src/optimization/ConstantPropagation.h b/src/optimization/ConstantPropagation.h index f2e47de3..77f15641 100644 --- a/src/optimization/ConstantPropagation.h +++ b/src/optimization/ConstantPropagation.h @@ -32,7 +32,9 @@ class ConstantPropagation { void setTruthTableEngine(bool value) { truthTableEngine_ = value; } - + void setNormalizedUniquification(bool value) { + normalizedUniquification_ = value; + } private: unsigned computeOutputValueForConstantInstance(DNLID instanceID); @@ -41,6 +43,8 @@ class ConstantPropagation { //void computOuputValuesforHalfAdder(DNLID instanceID); void performConstantPropagationAnalysis(); void propagateConstants(); + void changeDriverToLocal0(SNLInstTerm* term, DNLID id); + void changeDriverToLocal1(SNLInstTerm* term, DNLID id); DNLFull* dnl_ = nullptr; std::unordered_map designObjectID2Type_; std::set initialConstants0_; @@ -57,6 +61,7 @@ class ConstantPropagation { partialConstantReaders_; std::vector constant1TopReaders_; bool truthTableEngine_ = false; + bool normalizedUniquification_ = false; }; } // namespace naja::NAJA_OPT \ No newline at end of file diff --git a/src/optimization/Reduction.cpp b/src/optimization/Reduction.cpp index e080a498..46a3f59d 100644 --- a/src/optimization/Reduction.cpp +++ b/src/optimization/Reduction.cpp @@ -3,8 +3,8 @@ // // SPDX-License-Identifier: Apache-2.0 -#include #include "Reduction.h" +#include #include #include "SNLDesignTruthTable.h" #include "SNLTruthTable.h" @@ -15,25 +15,34 @@ using namespace naja::SNL; using namespace naja::NAJA_OPT; using namespace naja::BNE; -//#define DEBUG_PRINTS +// #define DEBUG_PRINTS ReductionOptimization::ReductionOptimization( - const std::vector, - std::vector>, - DNLID>>& partialConstantReaders) + const std::vector< + std::tuple, + std::vector>, + DNLID>>& partialConstantReaders) : partialConstantReaders_(partialConstantReaders) {} void ReductionOptimization::run() { for (auto& partialConstantReader : partialConstantReaders_) { - reducPartialConstantInstance(partialConstantReader); + if (normalizedUniquification_) { + reducPartialConstantInstanceWithNormalizedUniquification( + partialConstantReader); + } else { + reducPartialConstantInstance(partialConstantReader); + } + } + if (normalizedUniquification_) { + bne_.process(); } - bne_.process(); /*report_ = collectStatistics(); spdlog::info(report_);*/ destroy(); } -SNLTruthTable ReductionOptimization::reduceTruthTable(SNLInstance* uniquifiedCandidate, +SNLTruthTable ReductionOptimization::reduceTruthTable( + SNLInstance* uniquifiedCandidate, const SNLTruthTable& truthTable, const std::vector>& constTerms) { assert(constTerms.size() <= truthTable.size()); @@ -51,12 +60,62 @@ SNLTruthTable ReductionOptimization::reduceTruthTable(SNLInstance* uniquifiedCan } for (auto& constTerm : constTerms) { constInputs.push_back( - ConstantInput(termID2index[constTerm.first], - constTerm.second)); + ConstantInput(termID2index[constTerm.first], constTerm.second)); } return truthTable.getReducedWithConstants(constInputs); } +void ReductionOptimization::replaceInstance( + SNLInstance* instance, + const std::pair& result) { + reductionStatistics_[std::pair( + instance->getModel()->getName().getString(), + result.first->getName().getString())]++; + SNLDesign* design = instance->getDesign(); + SNLDesign* reducedDesign = result.first; + SNLInstance* reducedInstance = SNLInstance::create( + design, reducedDesign, + SNLName(std::string(instance->getName().getString()) + "_reduced")); + std::vector reducedInstTerms; + SNLInstTerm* output = nullptr; + SNLInstTerm* reducedOutput = nullptr; + for (auto term : reducedInstance->getInstTerms()) { + if (term->getDirection() != SNLInstTerm::Direction::Input) { + reducedOutput = term; + continue; + } + reducedInstTerms.push_back(term); + } + size_t index = 0; + size_t originNonConstantIndex = 0; + for (auto term : instance->getInstTerms()) { + if (term->getDirection() != SNLInstTerm::Direction::Input) { + output = term; + break; + } + } + for (auto term : instance->getInstTerms()) { + SNLBitNet* bitNet = term->getNet(); + term->setNet(nullptr); + if (bitNet->isConstant() || reducedInstTerms.empty()) { + continue; + } + originNonConstantIndex++; + if (std::find(result.second.begin(), result.second.end(), + originNonConstantIndex) != result.second.end()) { + continue; + } + reducedInstTerms[index]->setNet(bitNet); + index++; + if (index == reducedInstTerms.size()) { + break; + } + } + reducedOutput->setNet(output->getNet()); + output->setNet(nullptr); + instance->destroy(); +} + void ReductionOptimization::reducPartialConstantInstance( std::tuple, std::vector>, @@ -66,11 +125,14 @@ void ReductionOptimization::reducPartialConstantInstance( printf("reducPartialConstantInstance Reducing partial constant instance\n"); // LCOV_EXCL_STOP #endif - auto library = *(SNLUniverse::get()->getTopDesign()->getDB()->getPrimitiveLibraries().begin()); - /*Uniquifier uniquifier(std::get<0>(candidate), std::get<2>(candidate)); + auto library = *(SNLUniverse::get() + ->getTopDesign() + ->getDB() + ->getPrimitiveLibraries() + .begin()); + Uniquifier uniquifier(std::get<0>(candidate), std::get<2>(candidate)); uniquifier.process(); - SNLInstance* uniquifiedCandidate = uniquifier.getPathUniq().back();*/ - auto inst = getInstanceForPath(std::get<0>(candidate)); + SNLInstance* uniquifiedCandidate = uniquifier.getPathUniq().back(); /*if (!uniquifiedCandidate) {uniquifier.getPathUniq().back() std::ostringstream reason; auto instance = std::get<0>(candidate).back(); @@ -79,6 +141,76 @@ void ReductionOptimization::reducPartialConstantInstance( << instance->getDesign()->getName().getString(); throw SNLException(reason.str()); }*/ + SNLTruthTable invTruthTable = + SNLDesignTruthTable::getTruthTable(uniquifiedCandidate->getModel()); + if (!invTruthTable.isInitialized()) { +#ifdef DEBUG_PRINTS + // LCOV_EXCL_START + printf( + "reducPartialConstantInstance Truth table is not initialized for " + "design: %s\n", + unqiuifedCandidate->getModel()->getName().getString().c_str()); + // LCOV_EXCL_STOP +#endif + return; + } + SNLTruthTable reducedTruthTable = reduceTruthTable( + uniquifiedCandidate, invTruthTable, std::get<1>(candidate)); + if (reducedTruthTable.size() == 0) { +#ifdef DEBUG_PRINTS + // LCOV_EXCL_START + printf("reducPartialConstantInstance Full constant %s\n", + unqiuifedCandidate->getModel()->getName().getString().c_str()); +// LCOV_EXCL_STOP +#endif + } +#ifdef DEBUG_PRINTS + // LCOV_EXCL_START + printf("reducPartialConstantInstance truth table: %s\n", + invTruthTable.getString().c_str()); + printf("reducPartialConstantInstance reduced truth table: %s\n", + reducedTruthTable.getString().c_str()); +// LCOV_EXCL_STOP +#endif + auto result = + SNLLibraryTruthTables::getDesignForTruthTable(library, reducedTruthTable); + if (result.first) { +#ifdef DEBUG_PRINTS + // LCOV_EXCL_START + printf("reducPartialConstantInstance design %s\n", + unqiuifedCandidate->getModel()->getName().getString().c_str()); + printf("reducPartialConstantInstance redcued design %s\n", + result.first->getName().getString().c_str()); +// LCOV_EXCL_STOP +#endif + replaceInstance(uniquifiedCandidate, result); + } else { +#ifdef DEBUG_PRINTS + // LCOV_EXCL_START + printf( + "reducPartialConstantInstanceNo design found for the reduced truth " + "table\n"); +// LCOV_EXCL_STOP +#endif + } +} + +void ReductionOptimization:: + reducPartialConstantInstanceWithNormalizedUniquification( + std::tuple, + std::vector>, + DNLID>& candidate) { +#ifdef DEBUG_PRINTS + // LCOV_EXCL_START + printf("reducPartialConstantInstance Reducing partial constant instance\n"); + // LCOV_EXCL_STOP +#endif + auto library = *(SNLUniverse::get() + ->getTopDesign() + ->getDB() + ->getPrimitiveLibraries() + .begin()); + auto inst = getInstanceForPath(std::get<0>(candidate)); SNLTruthTable invTruthTable = SNLDesignTruthTable::getTruthTable(inst->getModel()); if (!invTruthTable.isInitialized()) { @@ -123,9 +255,8 @@ void ReductionOptimization::reducPartialConstantInstance( #endif auto context = std::get<0>(candidate); auto instance = context.back(); - context.pop_back(); + context.pop_back(); bne_.addReductionCommand(context, instance, result); - //replaceInstance(uniquifiedCandidate, result); } else { #ifdef DEBUG_PRINTS // LCOV_EXCL_START @@ -138,12 +269,11 @@ void ReductionOptimization::reducPartialConstantInstance( } std::string ReductionOptimization::collectStatistics() const { - std::stringstream ss; + std::stringstream ss; ss << "RO report:" << std::endl; for (const auto& entry : reductionStatistics_) { - ss << entry.first.first << " -> " << entry.first.second << " : " << entry.second << std::endl; + ss << entry.first.first << " -> " << entry.first.second << " : " + << entry.second << std::endl; } return ss.str(); } - - diff --git a/src/optimization/Reduction.h b/src/optimization/Reduction.h index cd88e7d5..273703ea 100644 --- a/src/optimization/Reduction.h +++ b/src/optimization/Reduction.h @@ -28,7 +28,14 @@ class ReductionOptimization { const std::vector>& constTerms); void run(); std::string collectStatistics() const; + void setNormalizedUniquification(bool normalizedUniquification) { + normalizedUniquification_ = normalizedUniquification; + } private: + void replaceInstance(SNLInstance* instance, const std::pair& result); + void reducPartialConstantInstanceWithNormalizedUniquification(std::tuple, + std::vector>, + DNLID>& candidate); void reducPartialConstantInstance(std::tuple, std::vector>, DNLID>& candidate); @@ -39,6 +46,7 @@ class ReductionOptimization { std::map, size_t> reductionStatistics_; std::string report_; BNE::BNE bne_; + bool normalizedUniquification_ = false; }; } // namespace naja::NAJA_OPT \ No newline at end of file diff --git a/src/optimization/RemoveLoadlessLogic.cpp b/src/optimization/RemoveLoadlessLogic.cpp index 218e0a91..bdc2c304 100644 --- a/src/optimization/RemoveLoadlessLogic.cpp +++ b/src/optimization/RemoveLoadlessLogic.cpp @@ -298,7 +298,8 @@ void LoadlessLogicRemover::removeLoadlessInstances( loadlessInstances) { BNE::BNE bne; for (auto& path : loadlessInstances) { - /*Uniquifier uniquifier(path.first, path.second); + if (!normalizedUniquification_) { + Uniquifier uniquifier(path.first, path.second); uniquifier.process(); for (SNLInstTerm* term : uniquifier.getPathUniq().back()->getInstTerms()) { auto net = term->getNet(); @@ -323,10 +324,14 @@ void LoadlessLogicRemover::removeLoadlessInstances( // LCOV_EXCL_STOP #endif - uniquifier.getPathUniq().back()->destroy();*/ - bne.addDeleteAction(path.first); + uniquifier.getPathUniq().back()->destroy(); + } else { + bne.addDeleteAction(path.first); + } + } + if (normalizedUniquification_) { + bne.process(); } - bne.process(); // #ifdef DEBUG_PRINTS // LCOV_EXCL_START spdlog::info("Deleted {} leaf instances out of {}", loadlessInstances.size(), diff --git a/src/optimization/RemoveLoadlessLogic.h b/src/optimization/RemoveLoadlessLogic.h index d1a3dcd0..e4a24752 100644 --- a/src/optimization/RemoveLoadlessLogic.h +++ b/src/optimization/RemoveLoadlessLogic.h @@ -39,11 +39,14 @@ class LoadlessLogicRemover { void removeLoadlessLogic(); std::string collectStatistics() const; std::string getReport() const { return report_; } - + void setNormalizedUniquification(bool normalizedUniquification) { + normalizedUniquification_ = normalizedUniquification; + } private: naja::DNL::DNL* dnl_; std::vector, DNLID>> loadlessInstances_; std::string report_; + bool normalizedUniquification_ = false; }; } // namespace naja::NAJA_OPT \ No newline at end of file diff --git a/test/logic_opt/ConstantPropagationTests.cpp b/test/logic_opt/ConstantPropagationTests.cpp index ec117943..124b7807 100644 --- a/test/logic_opt/ConstantPropagationTests.cpp +++ b/test/logic_opt/ConstantPropagationTests.cpp @@ -2750,6 +2750,7 @@ TEST_F(ConstantPropagationTests, TestConstantPropagationAND_Hierarchical_duplica .c_str()); } ConstantPropagation cp; + cp.setNormalizedUniquification(true); // 13. collect the constants cp.collectConstants(); // 14. run the constant propagation diff --git a/test/logic_opt/LoadlessLogicRemoverTests.cpp b/test/logic_opt/LoadlessLogicRemoverTests.cpp index e734a55e..48b88e3d 100644 --- a/test/logic_opt/LoadlessLogicRemoverTests.cpp +++ b/test/logic_opt/LoadlessLogicRemoverTests.cpp @@ -434,3 +434,78 @@ TEST_F(LoadlessRemoveLogicTests, simple_2_loadless_3_levels) { destroy(); } + +// Building a test like the prvious only with 3 levels of hierarchy +TEST_F(LoadlessRemoveLogicTests, simple_2_loadless_3_levels_bne) { + // Create a simple logic with a single + // input and output + SNLUniverse* univ = SNLUniverse::create(); + SNLDB* db = SNLDB::create(univ); + SNLLibrary* library = SNLLibrary::create(db, SNLName("MYLIB")); + SNLDesign* top = SNLDesign::create(library, SNLName("top")); + univ->setTopDesign(top); + SNLDesign* mod = SNLDesign::create(library, SNLName("mod")); + + auto inTerm = + SNLScalarTerm::create(mod, SNLTerm::Direction::Input, SNLName("in")); + auto outTerm = + SNLScalarTerm::create(mod, SNLTerm::Direction::Output, SNLName("out")); + + SNLDesign* bb = SNLDesign::create(library, SNLName("bb")); + auto inTermBB = + SNLScalarTerm::create(bb, SNLTerm::Direction::Input, SNLName("in")); + auto outTermBB = + SNLScalarTerm::create(bb, SNLTerm::Direction::Output, SNLName("out")); + + SNLDesign* bbNoOutput = SNLDesign::create(library, SNLName("bbNoOutput")); + auto inTermBBno = SNLScalarTerm::create(bbNoOutput, SNLTerm::Direction::Input, + SNLName("in")); + SNLDesign* bbNoOutputNoInput = + SNLDesign::create(library, SNLName("bbNoOutputNoInput")); + + SNLInstance* bb1 = SNLInstance::create(mod, bb, SNLName("bb1")); + SNLInstance* bb2 = SNLInstance::create(mod, bbNoOutput, SNLName("bb2")); + SNLInstance* bbnoni = + SNLInstance::create(mod, bbNoOutputNoInput, SNLName("bbnoni")); + + SNLDesign* hierNoOutput = SNLDesign::create(library, SNLName("hierNoOutput")); + auto inTermHIno = SNLScalarTerm::create(hierNoOutput, SNLTerm::Direction::Input, + SNLName("in")); + + SNLInstance* bb3 = + SNLInstance::create(hierNoOutput, bb, SNLName("bb1")); + SNLInstance* bb4 = + SNLInstance::create(hierNoOutput, bb, SNLName("bb2")); + + auto inNet1 = SNLScalarNet::create(mod, SNLName("inNet1")); + bb1->getInstTerm(inTermBB)->setNet(inNet1); + bb2->getInstTerm(inTermBBno)->setNet(inNet1); + inTerm->setNet(inNet1); + auto inNetHier = SNLScalarNet::create(hierNoOutput, SNLName("inNetHier")); + bb3->getInstTerm(inTermBB)->setNet(inNetHier); + bb4->getInstTerm(inTermBB)->setNet(inNetHier); + inTermHIno->setNet(inNetHier); + SNLInstance* hi1 = SNLInstance::create(mod, hierNoOutput, SNLName("hi1")); + SNLInstance* hi2 = SNLInstance::create(mod, hierNoOutput, SNLName("hi2")); + hi1->getInstTerm(inTermHIno)->setNet(inNet1); + hi2->getInstTerm(inTermHIno)->setNet(inNet1); + SNLInstance* modInst1 = SNLInstance::create(top, mod, SNLName("modInst1")); + SNLInstance* modInst2 = SNLInstance::create(top, mod, SNLName("modInst2")); + DNLFull* dnl = get(); + LoadlessLogicRemover remover; + remover.setNormalizedUniquification(true); + // Verify each function of remover + tbb::concurrent_unordered_set tracedIsos = remover.getTracedIsos(*dnl); + EXPECT_EQ(tracedIsos.size(), 1); + std::vector untracedIsos = remover.getUntracedIsos(*dnl, tracedIsos); + EXPECT_EQ(untracedIsos.size(), 0); + // std::set loadlessNets = lnr.getLoadlessNets(*dnl, tracedIsos); + // EXPECT_EQ(loadlessNets.size(), 1); + auto loadlessInstances = remover.getLoadlessInstances(*dnl, tracedIsos); + EXPECT_EQ(loadlessInstances.size(), 10); + destroy(); + remover.process(); + // Check that the loadless logic is removed + destroy(); +} + diff --git a/test/logic_opt/ReductionOptTests.cpp b/test/logic_opt/ReductionOptTests.cpp index 462fb6a8..a4dd2037 100644 --- a/test/logic_opt/ReductionOptTests.cpp +++ b/test/logic_opt/ReductionOptTests.cpp @@ -433,4 +433,393 @@ TEST_F(ReductionOptTests, testTruthTablesMap) { NetlistStatistics netlistStats(*get()); netlistStats.process(); printf("Netlist statistics: %s\n", netlistStats.getReport().c_str()); +} + + + +TEST_F(ReductionOptTests, test_bne) { + auto db = SNLDB::create(SNLUniverse::get()); + auto library = SNLLibrary::create(db, SNLLibrary::Type::Primitives, + SNLName("nangate45")); + auto primitives0Path = std::filesystem::path(SNL_PRIMITIVES_TEST_PATH); + primitives0Path /= "../snl/python/pyloader/scripts/"; + primitives0Path /= "primitives1.py"; + SNLPyLoader::loadPrimitives(library, primitives0Path); + ASSERT_EQ(13, library->getDesigns().size()); + auto logic0 = library->getDesign(SNLName("LOGIC0")); + EXPECT_NE(nullptr, logic0); + EXPECT_TRUE(logic0->isPrimitive()); + auto logic0TruthTable = SNLDesignTruthTable::getTruthTable(logic0); + EXPECT_TRUE(logic0TruthTable.isInitialized()); + EXPECT_EQ(0, logic0TruthTable.size()); + EXPECT_TRUE(logic0TruthTable.all0()); + + auto logic1 = library->getDesign(SNLName("LOGIC1")); + EXPECT_NE(nullptr, logic1); + EXPECT_TRUE(logic1->isPrimitive()); + auto logic1TruthTable = SNLDesignTruthTable::getTruthTable(logic1); + EXPECT_TRUE(logic1TruthTable.isInitialized()); + EXPECT_EQ(0, logic1TruthTable.size()); + EXPECT_TRUE(logic1TruthTable.all1()); + + auto and2 = library->getDesign(SNLName("AND2")); + EXPECT_NE(nullptr, and2); + EXPECT_TRUE(and2->isPrimitive()); + auto and2TruthTable = SNLDesignTruthTable::getTruthTable(and2); + EXPECT_TRUE(and2TruthTable.isInitialized()); + EXPECT_EQ(2, and2TruthTable.size()); + EXPECT_EQ(SNLTruthTable(2, 0x8), and2TruthTable); +} + +TEST_F(ReductionOptTests, testTruthTablesMap_bne) { + auto db = SNLDB::create(SNLUniverse::get()); + auto library = SNLLibrary::create(db, SNLLibrary::Type::Primitives, + SNLName("nangate45")); + auto primitives0Path = std::filesystem::path(SNL_PRIMITIVES_TEST_PATH); + primitives0Path /= "../snl/python/pyloader/scripts/"; + primitives0Path /= "primitives1.py"; + SNLPyLoader::loadPrimitives(library, primitives0Path); + ASSERT_EQ(13, library->getDesigns().size()); + + auto truthTables = SNLLibraryTruthTables::getTruthTables(library); + + auto logic0 = library->getDesign(SNLName("LOGIC0")); + auto logic1 = library->getDesign(SNLName("LOGIC1")); + + auto buf = library->getDesign(SNLName("BUF")); + ASSERT_NE(nullptr, buf); + auto bufTruthTable = SNLDesignTruthTable::getTruthTable(buf); + ASSERT_TRUE(bufTruthTable.isInitialized()); + auto tt = bufTruthTable.getReducedWithConstant(0, 0); + auto result = SNLLibraryTruthTables::getDesignForTruthTable(library, tt); + ASSERT_NE(nullptr, result.first); + EXPECT_EQ(result.first, logic0); + tt = bufTruthTable.getReducedWithConstant(0, 1); + result = SNLLibraryTruthTables::getDesignForTruthTable(library, tt); + auto design = result.first; + ASSERT_NE(nullptr, design); + EXPECT_EQ(design, logic1); + + auto inv = library->getDesign(SNLName("INV")); + ASSERT_NE(nullptr, inv); + auto invTruthTable = SNLDesignTruthTable::getTruthTable(inv); + ASSERT_TRUE(invTruthTable.isInitialized()); + tt = invTruthTable.getReducedWithConstant(0, 0); + result = SNLLibraryTruthTables::getDesignForTruthTable(library, tt); + design = result.first; + ASSERT_NE(nullptr, design); + EXPECT_EQ(design, logic1); + tt = invTruthTable.getReducedWithConstant(0, 1); + result = SNLLibraryTruthTables::getDesignForTruthTable(library, tt); + design = result.first; + ASSERT_NE(nullptr, design); + EXPECT_EQ(design, logic0); + + auto and2 = library->getDesign(SNLName("AND2")); + ASSERT_NE(nullptr, and2); + auto and2TruthTable = SNLDesignTruthTable::getTruthTable(and2); + ASSERT_TRUE(and2TruthTable.isInitialized()); + tt = and2TruthTable.getReducedWithConstant(0, 0); + result = SNLLibraryTruthTables::getDesignForTruthTable(library, tt); + design = result.first; + ASSERT_NE(nullptr, design); + EXPECT_EQ(design, logic0); + + auto or4 = library->getDesign(SNLName("OR4")); + ASSERT_NE(nullptr, or4); + auto or4TruthTable = SNLDesignTruthTable::getTruthTable(or4); + ASSERT_TRUE(or4TruthTable.isInitialized()); + tt = or4TruthTable.getReducedWithConstant(0, 1); + result = SNLLibraryTruthTables::getDesignForTruthTable(library, tt); + design = result.first; + ASSERT_NE(nullptr, design); + EXPECT_EQ(design, logic1); + tt = or4TruthTable.getReducedWithConstant(0, 0); + result = SNLLibraryTruthTables::getDesignForTruthTable(library, tt); + design = result.first; + ASSERT_NE(nullptr, design); + EXPECT_EQ(design, library->getDesign(SNLName("OR3"))); + + auto xor2 = library->getDesign(SNLName("XOR2")); + ASSERT_NE(nullptr, xor2); + auto xor2TruthTable = SNLDesignTruthTable::getTruthTable(xor2); + ASSERT_TRUE(xor2TruthTable.isInitialized()); + tt = xor2TruthTable.getReducedWithConstant(0, 0); + result = SNLLibraryTruthTables::getDesignForTruthTable(library, tt); + design = result.first; + ASSERT_NE(nullptr, design); + EXPECT_EQ(design, library->getDesign(SNLName("BUF"))); + + tt = xor2TruthTable.getReducedWithConstant(0, 1); + result = SNLLibraryTruthTables::getDesignForTruthTable(library, tt); + design = result.first; + ASSERT_NE(nullptr, design); + EXPECT_EQ(design, library->getDesign(SNLName("INV"))); + + auto xnor2 = library->getDesign(SNLName("XNOR2")); + ASSERT_NE(nullptr, xnor2); + auto xnor2TruthTable = SNLDesignTruthTable::getTruthTable(xnor2); + ASSERT_TRUE(xnor2TruthTable.isInitialized()); + tt = xnor2TruthTable.getReducedWithConstant(0, 0); + result = SNLLibraryTruthTables::getDesignForTruthTable(library, tt); + design = result.first; + ASSERT_NE(nullptr, design); + EXPECT_EQ(design, library->getDesign(SNLName("INV"))); + + tt = xnor2TruthTable.getReducedWithConstant(0, 1); + result = SNLLibraryTruthTables::getDesignForTruthTable(library, tt); + design = result.first; + ASSERT_NE(nullptr, design); + EXPECT_EQ(design, library->getDesign(SNLName("BUF"))); + + auto oai21 = library->getDesign(SNLName("OAI21")); + ASSERT_NE(nullptr, oai21); + auto oai21TruthTable = SNLDesignTruthTable::getTruthTable(oai21); + ASSERT_TRUE(oai21TruthTable.isInitialized()); + tt = oai21TruthTable.getReducedWithConstant(0, 0); + result = SNLLibraryTruthTables::getDesignForTruthTable(library, tt); + design = result.first; + ASSERT_NE(nullptr, design); + EXPECT_EQ(design, logic1); + + tt = oai21TruthTable.getReducedWithConstant(0, 1); + result = SNLLibraryTruthTables::getDesignForTruthTable(library, tt); + design = result.first; + ASSERT_NE(nullptr, design); + + auto mux2 = library->getDesign(SNLName("MUX2")); + ASSERT_NE(nullptr, mux2); + // 0: A, 1: B, 2: S + auto mux2TruthTable = SNLDesignTruthTable::getTruthTable(mux2); + ASSERT_TRUE(mux2TruthTable.isInitialized()); + // A=0 + tt = mux2TruthTable.getReducedWithConstant(0, 0); + result = SNLLibraryTruthTables::getDesignForTruthTable(library, tt); + design = result.first; + ASSERT_NE(nullptr, design); + EXPECT_EQ(design, and2); + + // A=1 + tt = mux2TruthTable.getReducedWithConstant(0, 1); + EXPECT_EQ(2, tt.size()); + EXPECT_EQ(0xB, tt.bits()); + result = SNLLibraryTruthTables::getDesignForTruthTable(library, tt); + design = result.first; + EXPECT_EQ(nullptr, design); // no design for or2 with one inversed input + + // if S=0, then A, if S=1, then B + tt = mux2TruthTable.getReducedWithConstant(2, 0); + EXPECT_EQ(2, tt.size()); + EXPECT_EQ(0xA, tt.bits()); + result = SNLLibraryTruthTables::getDesignForTruthTable(library, tt); + design = result.first; + ASSERT_NE(nullptr, design); + EXPECT_EQ(design, buf); + auto indexes = result.second; + EXPECT_EQ(1, indexes.size()); + EXPECT_EQ(1, indexes[0]); + + tt = mux2TruthTable.getReducedWithConstant(2, 1); + result = SNLLibraryTruthTables::getDesignForTruthTable(library, tt); + design = result.first; + ASSERT_NE(nullptr, design); + EXPECT_EQ(design, buf); + indexes = result.second; + EXPECT_EQ(1, indexes.size()); + EXPECT_EQ(0, indexes[0]); + + { + SNLLibrary* library = SNLLibrary::create(db, SNLName("MYLIB")); + // 2. Create a top model with one output + SNLDesign* top = SNLDesign::create(library, SNLName("top")); + SNLUniverse* univ = SNLUniverse::get(); + SNLDB* db = SNLDB::create(univ); + univ->setTopDesign(top); + auto topOut = + SNLScalarTerm::create(top, SNLTerm::Direction::Output, SNLName("out")); + auto topOut2 = + SNLScalarTerm::create(top, SNLTerm::Direction::Output, SNLName("out2")); + auto topOut3 = + SNLScalarTerm::create(top, SNLTerm::Direction::Output, SNLName("out3")); + auto topOut4 = + SNLScalarTerm::create(top, SNLTerm::Direction::Output, SNLName("out4")); + auto topOut5 = + SNLScalarTerm::create(top, SNLTerm::Direction::Output, SNLName("out5")); + auto topOut6 = + SNLScalarTerm::create(top, SNLTerm::Direction::Output, SNLName("out6")); + auto topOut7 = + SNLScalarTerm::create(top, SNLTerm::Direction::Output, SNLName("out7")); + auto topOut8 = + SNLScalarTerm::create(top, SNLTerm::Direction::Output, SNLName("out8")); + auto topOut9 = + SNLScalarTerm::create(top, SNLTerm::Direction::Output, SNLName("out9")); + auto topOut10 = + SNLScalarTerm::create(top, SNLTerm::Direction::Output, SNLName("out10")); + auto topOut11 = + SNLScalarTerm::create(top, SNLTerm::Direction::Output, SNLName("out11")); + auto topOut12 = + SNLScalarTerm::create(top, SNLTerm::Direction::Output, SNLName("out12")); + auto topIn = + SNLScalarTerm::create(top, SNLTerm::Direction::Output, SNLName("in")); + SNLDesign* mod = SNLDesign::create(library, SNLName("mod")); + auto modOut = + SNLScalarTerm::create(mod, SNLTerm::Direction::Output, SNLName("out")); + auto modOut2 = + SNLScalarTerm::create(mod, SNLTerm::Direction::Output, SNLName("out2")); + auto modOut3 = + SNLScalarTerm::create(mod, SNLTerm::Direction::Output, SNLName("out3")); + auto modOut4 = + SNLScalarTerm::create(mod, SNLTerm::Direction::Output, SNLName("out4")); + auto modOut5 = + SNLScalarTerm::create(mod, SNLTerm::Direction::Output, SNLName("out5")); + auto modOut6 = + SNLScalarTerm::create(mod, SNLTerm::Direction::Output, SNLName("out6")); + auto modIn = + SNLScalarTerm::create(mod, SNLTerm::Direction::Output, SNLName("in")); + // 8. create a mux instance in top + SNLInstance* modInst = SNLInstance::create(top, mod, SNLName("mod")); + SNLInstance* modInst2 = SNLInstance::create(top, mod, SNLName("mod2")); + SNLInstance* muxInst = SNLInstance::create(mod, mux2, SNLName("mux")); + SNLInstance* muxInst2 = SNLInstance::create(mod, mux2, SNLName("mux2")); + SNLInstance* muxInst3 = SNLInstance::create(mod, mux2, SNLName("mux3")); + SNLInstance* muxInst4 = SNLInstance::create(mod, mux2, SNLName("mux4")); + SNLInstance* muxInst5 = SNLInstance::create(mod, mux2, SNLName("mux5")); + SNLInstance* muxInst6 = SNLInstance::create(mod, mux2, SNLName("mux6")); + SNLInstance* logic0Inst = + SNLInstance::create(mod, logic0, SNLName("logic0")); + SNLInstance* logic1Inst = + SNLInstance::create(mod, logic1, SNLName("logic1")); + // 9. connect all instances inputs + // SNLNet* net1 = SNLScalarNet::create(top, SNLName("logic_0_net")); + //SNLNet* net2 = SNLScalarNet::create(mod, SNLName("constant_0_net")); + SNLNet* net3 = SNLScalarNet::create(top, SNLName("mux_output_net")); + SNLNet* net4 = SNLScalarNet::create(top, SNLName("input_net")); + SNLNet* net5 = SNLScalarNet::create(top, SNLName("constant_1_net")); + SNLNet* net6 = SNLScalarNet::create(top, SNLName("mux_output_net2")); + SNLNet* net7 = SNLScalarNet::create(top, SNLName("mux_output_net3")); + SNLNet* net8 = SNLScalarNet::create(top, SNLName("mux_output_net4")); + SNLNet* net9 = SNLScalarNet::create(top, SNLName("mux_output_net5")); + SNLNet* net10 = SNLScalarNet::create(top, SNLName("mux_output_net6")); + SNLNet* net11 = SNLScalarNet::create(top, SNLName("mod2out1")); + SNLNet* net12 = SNLScalarNet::create(top, SNLName("mod2out2")); + SNLNet* net13 = SNLScalarNet::create(top, SNLName("mod2out3")); + SNLNet* net14 = SNLScalarNet::create(top, SNLName("mod2out4")); + SNLNet* net15 = SNLScalarNet::create(top, SNLName("mod2out5")); + SNLNet* net16 = SNLScalarNet::create(top, SNLName("mod2out6")); + SNLNet* net2mod = SNLScalarNet::create(mod, SNLName("constant_0_net")); + SNLNet* net3mod = SNLScalarNet::create(mod, SNLName("mux_output_net")); + SNLNet* net4mod = SNLScalarNet::create(mod, SNLName("input_net")); + SNLNet* net5mod = SNLScalarNet::create(mod, SNLName("constant_1_net")); + SNLNet* net6mod = SNLScalarNet::create(mod, SNLName("mux_output_net2")); + SNLNet* net7mod = SNLScalarNet::create(mod, SNLName("mux_output_net3")); + SNLNet* net8mod = SNLScalarNet::create(mod, SNLName("mux_output_net4")); + SNLNet* net9mod = SNLScalarNet::create(mod, SNLName("mux_output_net5")); + SNLNet* net10mod = SNLScalarNet::create(mod, SNLName("mux_output_net6")); + + //Connect all instances inside mod + + // connect logic0 to mux + + // connect logic1 to mux + // net2->setType(naja::SNL::SNLNet::Type::Assign1); + (*logic0Inst->getInstTerms().begin())->setNet(net2mod); + (*logic1Inst->getInstTerms().begin())->setNet(net5mod); + + modIn->setNet(net6mod); + + //Twins muxes 1 and 4 + muxInst->getInstTerm(mux2->getScalarTerm(SNLName("A")))->setNet(net2mod); + muxInst4->getInstTerm(mux2->getScalarTerm(SNLName("A")))->setNet(net2mod); + muxInst->getInstTerm(mux2->getScalarTerm(SNLName("B")))->setNet(net4mod); + muxInst4->getInstTerm(mux2->getScalarTerm(SNLName("B")))->setNet(net4mod); + muxInst->getInstTerm(mux2->getScalarTerm(SNLName("S")))->setNet(net2mod); + muxInst4->getInstTerm(mux2->getScalarTerm(SNLName("S")))->setNet(net2mod); + // connect the mux instance output to the top output + muxInst->getInstTerm(mux2->getScalarTerm(SNLName("Z")))->setNet(net3mod); + modOut->setNet(net3mod); + muxInst4->getInstTerm(mux2->getScalarTerm(SNLName("Z")))->setNet(net7mod); + modOut4->setNet(net7mod); + + //Twins muxes 2 and 5 + muxInst2->getInstTerm(mux2->getScalarTerm(SNLName("A")))->setNet(net2mod); + muxInst5->getInstTerm(mux2->getScalarTerm(SNLName("A")))->setNet(net2mod); + muxInst2->getInstTerm(mux2->getScalarTerm(SNLName("B")))->setNet(net5mod); + muxInst5->getInstTerm(mux2->getScalarTerm(SNLName("B")))->setNet(net5mod); + muxInst2->getInstTerm(mux2->getScalarTerm(SNLName("S")))->setNet(net5mod); + muxInst5->getInstTerm(mux2->getScalarTerm(SNLName("S")))->setNet(net5mod); + muxInst2->getInstTerm(mux2->getScalarTerm(SNLName("Z")))->setNet(net6mod); + modOut2->setNet(net6mod); + muxInst5->getInstTerm(mux2->getScalarTerm(SNLName("Z")))->setNet(net9mod); + modOut5->setNet(net9mod); + + //Twins muxes 3 and 6 + muxInst3->getInstTerm(mux2->getScalarTerm(SNLName("A")))->setNet(net4mod); + muxInst6->getInstTerm(mux2->getScalarTerm(SNLName("A")))->setNet(net4mod); + muxInst3->getInstTerm(mux2->getScalarTerm(SNLName("B")))->setNet(net4mod); + muxInst6->getInstTerm(mux2->getScalarTerm(SNLName("B")))->setNet(net4mod); + muxInst3->getInstTerm(mux2->getScalarTerm(SNLName("S")))->setNet(net5mod); + muxInst6->getInstTerm(mux2->getScalarTerm(SNLName("S")))->setNet(net5mod); + muxInst3->getInstTerm(mux2->getScalarTerm(SNLName("Z")))->setNet(net7mod); + muxInst6->getInstTerm(mux2->getScalarTerm(SNLName("Z")))->setNet(net10mod); + modOut3->setNet(net7mod); + modOut6->setNet(net10mod); + + + //Connect all instances under top + topIn->setNet(net4); + + + modInst->getInstTerm(modIn)->setNet(net4); + modInst->getInstTerm(modOut)->setNet(net3); + topOut->setNet(net3); + modInst->getInstTerm(modOut2)->setNet(net6); + topOut2->setNet(net6); + modInst->getInstTerm(modOut3)->setNet(net7); + topOut3->setNet(net7); + modInst->getInstTerm(modOut4)->setNet(net8); + topOut4->setNet(net8); + modInst->getInstTerm(modOut5)->setNet(net9); + topOut5->setNet(net9); + modInst->getInstTerm(modOut6)->setNet(net10); + topOut6->setNet(net10); + + modInst2->getInstTerm(modIn)->setNet(net4); + modInst2->getInstTerm(modOut)->setNet(net11); + topOut7->setNet(net11); + modInst2->getInstTerm(modOut2)->setNet(net12); + topOut8->setNet(net12); + modInst2->getInstTerm(modOut3)->setNet(net13); + topOut9->setNet(net13); + modInst2->getInstTerm(modOut4)->setNet(net14); + topOut10->setNet(net14); + modInst2->getInstTerm(modOut5)->setNet(net15); + topOut11->setNet(net15); + modInst2->getInstTerm(modOut6)->setNet(net16); + topOut12->setNet(net16); + + ConstantPropagation cp; + cp.setTruthTableEngine(true); + cp.run(); + { + std::string dotFileName( + std::string(std::string("./afterCP") + std::string(".dot"))); + std::string svgFileName( + std::string(std::string("./afterCP") + std::string(".svg"))); + SnlVisualiser snl(top); + snl.process(); + snl.getNetlistGraph().dumpDotFile(dotFileName.c_str()); + system(std::string(std::string("dot -Tsvg ") + dotFileName + + std::string(" -o ") + svgFileName) + .c_str()); + } + printf("partial constant readers: %lu\n", + cp.getPartialConstantReaders().size()); + ReductionOptimization reductionOpt(cp.getPartialConstantReaders()); + reductionOpt.setNormalizedUniquification(true); + reductionOpt.run(); + reductionOpt.collectStatistics(); + } + NetlistStatistics netlistStats(*get()); + netlistStats.process(); + printf("Netlist statistics: %s\n", netlistStats.getReport().c_str()); } \ No newline at end of file diff --git a/thirdparty/cpptrace b/thirdparty/cpptrace index 0742b42d..90de25f1 160000 --- a/thirdparty/cpptrace +++ b/thirdparty/cpptrace @@ -1 +1 @@ -Subproject commit 0742b42dadaac62436cb226a7d084738a8f82d1a +Subproject commit 90de25f1dfe637b7929454644e39d0436606c999 diff --git a/thirdparty/googletest b/thirdparty/googletest index b514bdc8..e3978608 160000 --- a/thirdparty/googletest +++ b/thirdparty/googletest @@ -1 +1 @@ -Subproject commit b514bdc898e2951020cbdca1304b75f5950d1f59 +Subproject commit e39786088138f2749d64e9e90e0f9902daa77c40