From 90357c8e2879199c573792ba1fa628399d2f4686 Mon Sep 17 00:00:00 2001 From: HS Date: Sat, 15 Oct 2022 01:18:52 -0700 Subject: [PATCH] Introducing uhdm-cmp tool to topographically compare two uhdm binaries Also, fixed a few issues identified while testing the comparison logic generated by the scripts. --- CMakeLists.txt | 6 ++- scripts/classes.py | 28 ++++++------ util/uhdm-cmp.cpp | 105 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 123 insertions(+), 16 deletions(-) create mode 100644 util/uhdm-cmp.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 24615ba7..973e5813 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -243,8 +243,12 @@ if (UHDM_BUILD_TESTS) endif() # Useful utilities +add_executable(uhdm-cmp ${PROJECT_SOURCE_DIR}/util/uhdm-cmp.cpp) +target_link_libraries(uhdm-cmp PRIVATE uhdm) + add_executable(uhdm-dump ${PROJECT_SOURCE_DIR}/util/uhdm-dump.cpp) target_link_libraries(uhdm-dump PRIVATE uhdm) + add_executable(uhdm-hier ${PROJECT_SOURCE_DIR}/util/uhdm-hier.cpp) target_link_libraries(uhdm-hier PRIVATE uhdm) @@ -270,7 +274,7 @@ target_link_libraries(test_inst PRIVATE # Installation target install( - TARGETS uhdm capnp kj uhdm-dump uhdm-hier + TARGETS uhdm capnp kj uhdm-cmp uhdm-dump uhdm-hier ARCHIVE DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/uhdm PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_PREFIX}/include/uhdm) install(DIRECTORY ${GENDIR}/uhdm/ diff --git a/scripts/classes.py b/scripts/classes.py index cad2b054..69a8bfe2 100644 --- a/scripts/classes.py +++ b/scripts/classes.py @@ -526,16 +526,13 @@ def _get_GetVpiPropertyValue_implementation(model): def _get_Compare_implementation(model): vpi_blacklist = [ 'uhdmId', - 'uhdmParentType', 'uhdmType', 'vpiColumnNo', 'vpiEndColumnNo', 'vpiEndLineNo', 'vpiFile', 'vpiFullName', - 'vpiInstance', 'vpiLineNo', - 'vpiParent', ] classname = model['name'] @@ -544,18 +541,21 @@ def _get_Compare_implementation(model): includes = set() content = [ f'int {classname}::Compare(const BaseClass *const other, AnySet& visited) const {{', - ' int r = 0;', - ' if (!visited.insert(this).second) return r;', - '', - ' AnySet local;', - ' if ((r = basetype_t::Compare(other, local)) != 0) return r;', - ' visited.merge(local);', - '' + ' int r = 0;' ] + if not model['subclasses']: + # Mark self visited (and check) only for the most derived sub-class + content.append(' if (!visited.insert(this).second) return r;') + + content.extend([ + ' if ((r = basetype_t::Compare(other, visited)) != 0) return r;', + '' + ]) + var_declared = False for key, value in model.allitems(): - if key not in ['property', 'obj_ref', 'class_ref']: + if key not in ['property', 'obj_ref', 'class_ref', 'class']: continue vpi = value.get('vpi') @@ -591,8 +591,7 @@ def _get_Compare_implementation(model): f' auto lhs_{name} = lhs->{Name}();', f' auto rhs_{name} = rhs->{Name}();', f' if ((lhs_{name} != nullptr) && (rhs_{name} != nullptr)) {{', - f' if ((r = lhs_{name}->Compare(rhs_{name}, local)) != 0) return r;', - ' visited.merge(local);', + f' if ((r = lhs_{name}->Compare(rhs_{name}, visited)) != 0) return r;', f' }} else if ((lhs_{name} != nullptr) && (rhs_{name} == nullptr)) {{', ' return 1;', f' }} else if ((lhs_{name} == nullptr) && (rhs_{name} != nullptr)) {{', @@ -613,8 +612,7 @@ def _get_Compare_implementation(model): f' if ((r = static_cast(lhs_{name}->size() - rhs_{name}->size())) != 0) return r;', '', f' for (size_t i = 0, n = lhs_{name}->size(); i < n; ++i) {{', - f' if ((r = lhs_{name}->at(i)->Compare(rhs_{name}->at(i), local)) != 0) return r;', - ' visited.merge(local);', + f' if ((r = lhs_{name}->at(i)->Compare(rhs_{name}->at(i), visited)) != 0) return r;', ' }', f' }} else if ((lhs_{name} != nullptr) && (rhs_{name} == nullptr)) {{', ' return 1;', diff --git a/util/uhdm-cmp.cpp b/util/uhdm-cmp.cpp new file mode 100644 index 00000000..a6d387e8 --- /dev/null +++ b/util/uhdm-cmp.cpp @@ -0,0 +1,105 @@ +/* + * Copyright 2019 Alain Dargelas + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include +#include +#include +#include +#include + +namespace fs = std::filesystem; + +static int32_t usage(const char *progName) { + std::cerr << "Usage:" << std::endl + << " " << progName << " " << std::endl + << std::endl + << "Reads input uhdm binary representations of two files and " + "compares them topographically." + << std::endl + << std::endl + << "Exits with code" << std::endl + << " = 0, if input files are equal" << std::endl + << " < 0, if input files are not equal" << std::endl + << " > 0, for any failures" << std::endl; + return 1; +} + +int32_t main(int32_t argc, char **argv) { + if (argc != 3) { + return usage(argv[0]); + } + + fs::path fileA = argv[1]; + fs::path fileB = argv[2]; + + std::error_code ec; + if (!fs::is_regular_file(fileA, ec) || ec) { + std::cerr << fileA << ": File does not exist!" << std::endl; + return usage(argv[0]); + } + + if (!fs::is_regular_file(fileB, ec) || ec) { + std::cerr << fileB << ": File does not exist!" << std::endl; + return usage(argv[0]); + } + + std::unique_ptr serializerA(new UHDM::Serializer); + std::vector handlesA = serializerA->Restore(fileA); + + std::unique_ptr serializerB(new UHDM::Serializer); + std::vector handlesB = serializerB->Restore(fileB); + + if (handlesA.empty()) { + std::cerr << fileA << ": Failed to load." << std::endl; + return 1; + } + + if (handlesB.empty()) { + std::cerr << fileB << ": Failed to load." << std::endl; + return 1; + } + + if (handlesA.size() != handlesB.size()) { + std::cerr << "Number of designs mismatch." << std::endl; + return -1; + } + + std::function to_design = + [](vpiHandle handle) { + return (const UHDM::design *)((const uhdm_handle *)handle)->object; + }; + + std::vector designsA; + designsA.reserve(handlesA.size()); + std::transform(handlesA.begin(), handlesA.end(), std::back_inserter(designsA), + to_design); + + std::vector designsB; + designsB.reserve(handlesB.size()); + std::transform(handlesB.begin(), handlesB.end(), std::back_inserter(designsB), + to_design); + + for (size_t i = 0, n = designsA.size(); i < n; ++i) { + UHDM::AnySet visited; + if (designsA[i]->Compare(designsB[i], visited) != 0) { + return -1; + } + } + + return 0; +}