diff --git a/include/revng/EarlyFunctionAnalysis/CFGHelpers.h b/include/revng/EarlyFunctionAnalysis/CFGHelpers.h index a1d4d524b..f69a0464f 100644 --- a/include/revng/EarlyFunctionAnalysis/CFGHelpers.h +++ b/include/revng/EarlyFunctionAnalysis/CFGHelpers.h @@ -44,15 +44,12 @@ inline ParsedSuccessor parseSuccessor(const T &Edge, .OptionalCallAddress = MetaAddress::invalid() }; case FunctionEdgeType::FunctionCall: { - // Note: we assume that the first concrete type is the CallEdge. This hack - // is necessary to be able to handle identical data structures under - // different namespaces. - using CallEdge = std::tuple_element_t<0, concrete_types_traits_t>; - auto *CE = llvm::cast(&Edge); + auto CastEdge = Edge.getCallEdge(); + revng_assert(CastEdge); auto NextInstructionAddress = BasicBlockID::invalid(); - if (not CE->hasAttribute(Binary, model::FunctionAttribute::NoReturn) - and not CE->IsTailCall()) { + if (not CastEdge->hasAttribute(Binary, model::FunctionAttribute::NoReturn) + and not CastEdge->IsTailCall()) { NextInstructionAddress = FallthroughAddress; } return ParsedSuccessor{ .NextInstructionAddress = NextInstructionAddress, diff --git a/include/revng/EarlyFunctionAnalysis/FunctionEdgeBase.h b/include/revng/EarlyFunctionAnalysis/FunctionEdgeBase.h index 0c01686c2..074e21b19 100644 --- a/include/revng/EarlyFunctionAnalysis/FunctionEdgeBase.h +++ b/include/revng/EarlyFunctionAnalysis/FunctionEdgeBase.h @@ -42,6 +42,10 @@ namespace model { class VerifyHelper; } +namespace efa { +class CallEdge; +} + class efa::FunctionEdgeBase : public efa::generated::FunctionEdgeBase { public: using generated::FunctionEdgeBase::FunctionEdgeBase; @@ -50,6 +54,9 @@ public: bool isDirect() const { return Destination().isValid(); } bool isIndirect() const { return not isDirect(); } + /// \return nullptr if this is not a call edge. + const efa::CallEdge *getCallEdge() const; + public: bool verify() const debug_function; bool verify(bool Assert) const debug_function; diff --git a/include/revng/Yield/FunctionEdgeBase.h b/include/revng/Yield/FunctionEdgeBase.h index 0a4bfd774..9b285d935 100644 --- a/include/revng/Yield/FunctionEdgeBase.h +++ b/include/revng/Yield/FunctionEdgeBase.h @@ -42,6 +42,10 @@ namespace model { class VerifyHelper; } +namespace yield { +class CallEdge; +} + class yield::FunctionEdgeBase : public yield::generated::FunctionEdgeBase { public: using generated::FunctionEdgeBase::FunctionEdgeBase; @@ -50,6 +54,9 @@ public: bool isDirect() const { return Destination().isValid(); } bool isIndirect() const { return not isDirect(); } + // Returns nullptr if this is not a call edge. + const yield::CallEdge *getCallEdge() const; + public: bool verify() const debug_function; bool verify(bool Assert) const debug_function; diff --git a/lib/ABI/CMakeLists.txt b/lib/ABI/CMakeLists.txt index faa8d10d0..60588c676 100644 --- a/lib/ABI/CMakeLists.txt +++ b/lib/ABI/CMakeLists.txt @@ -34,7 +34,7 @@ target_tuple_tree_generator( ROOT_TYPE Definition SCHEMA_PATH - "${CMAKE_BINARY_DIR}/abi-internal-schema.yml" + "${CMAKE_SOURCE_DIR}/include/revng/ABI/abi-internal-schema.yml" SCALAR_TYPES "model::ABI::Values" "model::Register::Values" diff --git a/lib/EarlyFunctionAnalysis/CMakeLists.txt b/lib/EarlyFunctionAnalysis/CMakeLists.txt index 498b0c472..0a2b29d00 100644 --- a/lib/EarlyFunctionAnalysis/CMakeLists.txt +++ b/lib/EarlyFunctionAnalysis/CMakeLists.txt @@ -44,7 +44,8 @@ target_link_libraries( set(EFA_HEADERS_DIR "${CMAKE_SOURCE_DIR}/include/revng/EarlyFunctionAnalysis") set(OUTPUT_DIR "${CMAKE_BINARY_DIR}/include/revng/EarlyFunctionAnalysis/Generated") -set(SCHEMA_PATH "${CMAKE_BINARY_DIR}/efa-schema.yml") +set(SCHEMA_PATH + "${CMAKE_SOURCE_DIR}/include/revng/EarlyFunctionAnalysis/efa-schema.yml") target_tuple_tree_generator( revngEarlyFunctionAnalysis INSTALL diff --git a/lib/EarlyFunctionAnalysis/ControlFlowGraph.cpp b/lib/EarlyFunctionAnalysis/ControlFlowGraph.cpp index c28be6952..889829f2d 100644 --- a/lib/EarlyFunctionAnalysis/ControlFlowGraph.cpp +++ b/lib/EarlyFunctionAnalysis/ControlFlowGraph.cpp @@ -298,6 +298,10 @@ void ControlFlowGraph::dumpCFG(const model::Binary &Binary) const { WriteGraph(&G, "function-metadata"); } +const CallEdge *FunctionEdgeBase::getCallEdge() const { + return llvm::dyn_cast(this); +} + bool FunctionEdgeBase::verify() const { return verify(false); } diff --git a/lib/Model/CMakeLists.txt b/lib/Model/CMakeLists.txt index 82f04f79e..8c15ca6eb 100644 --- a/lib/Model/CMakeLists.txt +++ b/lib/Model/CMakeLists.txt @@ -20,7 +20,7 @@ target_link_libraries(revngModel revngSupport) # Header files containing model YAML must be added here set(MODEL_HEADERS_DIR "${CMAKE_SOURCE_DIR}/include/revng/Model") -set(SCHEMA_PATH "${CMAKE_BINARY_DIR}/model-schema.yml") +set(SCHEMA_PATH "${CMAKE_SOURCE_DIR}/include/revng/Model/model-schema.yml") set(JSONSCHEMA_PATH "${CMAKE_BINARY_DIR}/model-jsonschema.yml") set(TYPESCRIPT_PATH "${CMAKE_BINARY_DIR}/lib/typescript/model.ts") set(DOCS_PATH "${CMAKE_BINARY_DIR}/share/doc/revng/references/model.md") diff --git a/lib/Pipeline/CMakeLists.txt b/lib/Pipeline/CMakeLists.txt index 5e182ea63..dba0a3405 100644 --- a/lib/Pipeline/CMakeLists.txt +++ b/lib/Pipeline/CMakeLists.txt @@ -28,7 +28,8 @@ target_link_libraries(revngPipeline revngStorage revngSupport ${LLVM_LIBRARIES}) set(PIPELINEDESCRIPTION_HEADERS_DIR "${CMAKE_SOURCE_DIR}/include/revng/Pipeline/Description") set(PIPELINEDESCRIPTION_SCHEMA_PATH - "${CMAKE_BINARY_DIR}/pipelineDescription-schema.yml") + "${CMAKE_SOURCE_DIR}/include/revng/Pipeline/Description/pipelineDescription-schema.yml" +) set(PIPELINEDESCRIPTION_JSONSCHEMA_PATH "${CMAKE_BINARY_DIR}/pipelineDescription-jsonschema.yml") set(PIPELINEDESCRIPTION_TYPESCRIPT_PATH diff --git a/lib/Yield/CMakeLists.txt b/lib/Yield/CMakeLists.txt index b45c40854..c38904fc1 100644 --- a/lib/Yield/CMakeLists.txt +++ b/lib/Yield/CMakeLists.txt @@ -56,7 +56,7 @@ target_tuple_tree_generator( ROOT_TYPE Function SCHEMA_PATH - "${CMAKE_BINARY_DIR}/yield-internal-schema.yml" + "${CMAKE_SOURCE_DIR}/include/revng/Yield/yield-internal-schema.yml" SEPARATE_STRING_TYPES "MetaAddress" SCALAR_TYPES @@ -89,7 +89,7 @@ target_tuple_tree_generator( ROOT_TYPE CrossRelations SCHEMA_PATH - "${CMAKE_BINARY_DIR}/yield-cross-relations.yml" + "${CMAKE_SOURCE_DIR}/include/revng/Yield/CrossRelations/yield-cross-relations.yml" SEPARATE_STRING_TYPES "MetaAddress" SCALAR_TYPES diff --git a/lib/Yield/ControlFlow/ConvertFromEFA.cpp b/lib/Yield/ControlFlow/ConvertFromEFA.cpp index 2ae8ec3b9..055663805 100644 --- a/lib/Yield/ControlFlow/ConvertFromEFA.cpp +++ b/lib/Yield/ControlFlow/ConvertFromEFA.cpp @@ -25,3 +25,7 @@ yield::FunctionEdge::FunctionEdge(const efa::FunctionEdge &Source) { Destination() = Source.Destination(); Type() = yield::FunctionEdgeType::from(Source.Type()); } + +const yield::CallEdge *yield::FunctionEdgeBase::getCallEdge() const { + return llvm::dyn_cast(this); +} diff --git a/scripts/tuple_tree_generator/extract_yaml.py b/scripts/tuple_tree_generator/extract_yaml.py deleted file mode 100755 index a8a03af0f..000000000 --- a/scripts/tuple_tree_generator/extract_yaml.py +++ /dev/null @@ -1,62 +0,0 @@ -#!/usr/bin/env python3 -# -# This file is distributed under the MIT License. See LICENSE.md for details. -# - -import argparse -import re -import sys -from pathlib import Path - -import jsonschema -import yaml - -argparser = argparse.ArgumentParser() -argparser.add_argument( - "delimiter", help="Delimiter marking comments containing YAML to be extracted" -) -argparser.add_argument("headers", nargs="+") -argparser.add_argument("--output", "-o", help="Output path") - -metaschema_path = Path(__file__).parent / "metaschema.yml" - - -def main(args): - # fmt: off - model_yaml_regex = re.compile( - rf""" - /\*\s*{args.delimiter}\s*\n # Match start of special comment - (?P.*) # Match everything inside in the "content" named group - \s*\n\s*{args.delimiter}\s*\*/ # Match end comment sequence - """, - re.VERBOSE | re.DOTALL, # re.DOTALL enables "." to match newlines - ) - # fmt: on - - definitions = [] - for header in args.headers: - with open(header, encoding="utf-8") as f: - data = f.read() - - match = model_yaml_regex.search(data) - if not match: - sys.stderr.write(f"ERROR: could not extract model yaml in {header}") - sys.exit(1) - unparsed_yaml = match.group("content") - - definition = yaml.safe_load(unparsed_yaml) - definitions.append(definition) - - metaschema = yaml.safe_load(metaschema_path.read_text()) - jsonschema.validate(instance=definitions, schema=metaschema) - - if args.output: - output = open(args.output, "w", encoding="utf-8") # noqa: SIM115 - else: - output = sys.stdout - - yaml.safe_dump(definitions, stream=output) - - -if __name__ == "__main__": - main(argparser.parse_args()) diff --git a/share/revng/cmake/TupleTreeGenerator.cmake b/share/revng/cmake/TupleTreeGenerator.cmake index 803160e19..1a092437c 100644 --- a/share/revng/cmake/TupleTreeGenerator.cmake +++ b/share/revng/cmake/TupleTreeGenerator.cmake @@ -50,12 +50,6 @@ function(tuple_tree_generator_impl) set(GENERATOR_DOCS_PATH "") endif() - # - # Collect all the definitions in a single YAML document - # - tuple_tree_generator_extract_definitions_from_headers( - "${GENERATOR_HEADERS}" "${GENERATOR_SCHEMA_PATH}") - # # C++ headers and implementation generation # @@ -147,17 +141,6 @@ function(tuple_tree_generator_impl) ${EXTRA_TARGETS} generate-node_modules) endfunction() -# Extracts tuple_tree_generator YAML definitions from the given header files -# -function(tuple_tree_generator_extract_definitions_from_headers HEADERS - OUTPUT_FILE) - add_custom_command( - OUTPUT "${OUTPUT_FILE}" - COMMAND "${CMAKE_SOURCE_DIR}/scripts/tuple_tree_generator/extract_yaml.py" - --output "${OUTPUT_FILE}" TUPLE-TREE-YAML ${HEADERS} - DEPENDS ${HEADERS}) -endfunction() - # Computes the list of headers and C++ source files that will be generated by # tuple_tree_generator. Note: the output variables will be overwritten function(tuple_tree_generator_compute_generated_cpp_files SOURCE_HEADERS @@ -214,7 +197,6 @@ set(SCRIPTS_ROOT_DIR "${CMAKE_SOURCE_DIR}/scripts/tuple_tree_generator") # # TODO: detect and warn about extra files in those directories set(TUPLE_TREE_GENERATOR_SOURCES - "${SCRIPTS_ROOT_DIR}/extract_yaml.py" "${SCRIPTS_ROOT_DIR}/tuple-tree-generate-cpp.py" "${SCRIPTS_ROOT_DIR}/tuple-tree-generate-jsonschema.py" "${SCRIPTS_ROOT_DIR}/tuple-tree-generate-python.py" @@ -257,7 +239,6 @@ function( "${YAML_DEFINITIONS}" > "${EXPECTED_GENERATED_MARKDOWN}" OUTPUT "${EXPECTED_GENERATED_MARKDOWN}" DEPENDS "${YAML_DEFINITIONS}" "${TEMPLATES_DIR}/docs.md.tpl" - "${SCRIPTS_ROOT_DIR}/extract_yaml.py" ${TUPLE_TREE_GENERATOR_SOURCES}) endfunction() @@ -300,7 +281,6 @@ function( "${OUTPUT_DIR}" ${TRACKING} ${TRACKING_DEBUG} OUTPUT ${EXPECTED_GENERATED_HEADERS} ${EXPECTED_GENERATED_IMPLS} DEPENDS "${YAML_DEFINITIONS}" ${CPP_TEMPLATES} - "${SCRIPTS_ROOT_DIR}/extract_yaml.py" ${TUPLE_TREE_GENERATOR_SOURCES}) endfunction() @@ -445,7 +425,7 @@ endfunction() # NAMESPACE Delimiter used to mark comments embedding type schemas -# SCHEMA_PATH Where the schema will be collected +# SCHEMA_PATH Path to YAML schema # HEADER_DIRECTORY Directory where the headers will be generated diff --git a/tests/unit/CMakeLists.txt b/tests/unit/CMakeLists.txt index 6a66a9b43..6f1f41f69 100644 --- a/tests/unit/CMakeLists.txt +++ b/tests/unit/CMakeLists.txt @@ -292,7 +292,7 @@ target_tuple_tree_generator( ROOT_TYPE TestClass SCHEMA_PATH - "${OUTPUT_DIR}/schema.yml" + "${CMAKE_SOURCE_DIR}/tests/unit/TupleTreeGenerator/schema.yml" HEADERS_PATH "${HEADERS_DIR}/Generated" INCLUDE_PATH_PREFIX