diff --git a/.clang-tidy b/.clang-tidy index 624d78a8..d3c30232 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -2,7 +2,6 @@ Checks: 'clang-diagnostic-*,clang-analyzer-*,-*,performance-*,modernize-*,llvm-namespace-comment,google-explicit-constructor,bugprone-*,misc-*,readability-*, -readability-named-parameter,-modernize-use-trailing-return-type,-modernize-use-using' WarningsAsErrors: '' HeaderFilterRegex: '' -AnalyzeTemporaryDtors: false CheckOptions: - key: google-readability-braces-around-statements.ShortStatementLines value: '1' diff --git a/.github/workflows/basic-ci.yml b/.github/workflows/basic-ci.yml index f8a39fda..39044e6b 100644 --- a/.github/workflows/basic-ci.yml +++ b/.github/workflows/basic-ci.yml @@ -12,10 +12,22 @@ env: jobs: format-check: - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 + + - run: | + wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add - + echo "deb http://apt.llvm.org/noble/ llvm-toolchain-noble-18 main" | sudo tee /etc/apt/sources.list.d/llvm-18.list + + - name: Update apt + run: sudo apt-get update + + - name: Install clang-format + run: | + sudo apt-get remove clang-format-* + sudo apt-get install -t llvm-toolchain-noble-18 clang-format-18 - name: Format source code run: | @@ -24,7 +36,7 @@ jobs: -a \( -name "*.c" -o -name "*.cpp" -o -name "*.h" \) \ -not -path "*/lulesh/*" -not -path "*/CallSite.h" \ -print0 \ - | xargs -0 clang-format-14 -i + | xargs -0 clang-format-18 -i - name: Format check run: | @@ -35,7 +47,7 @@ jobs: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - uses: codespell-project/actions-codespell@v2 lit-suite: @@ -73,7 +85,7 @@ jobs: runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: LLVM apt if: ${{ matrix.llvm-version == 19 }} diff --git a/.github/workflows/ext-ci.yml b/.github/workflows/ext-ci.yml index 9d16f848..dffa84f1 100644 --- a/.github/workflows/ext-ci.yml +++ b/.github/workflows/ext-ci.yml @@ -31,10 +31,10 @@ jobs: runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Checkout test-bench - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: repository: tudasc/typeart-bench ssh-key: ${{ secrets.AUTH_SSH_CI_EXT }} @@ -129,10 +129,10 @@ jobs: runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Checkout AD test-bench - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: repository: ahueck/typeart-ad-benchmarks ssh-key: ${{ secrets.AUTH_SSH_CI_EXT_AD }} @@ -215,10 +215,10 @@ jobs: runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Checkout OMP test-bench - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: repository: tudasc/typeart-bench ssh-key: ${{ secrets.AUTH_SSH_CI_EXT }} diff --git a/demo/Makefile b/demo/Makefile index 16dd527b..3224b55b 100644 --- a/demo/Makefile +++ b/demo/Makefile @@ -3,7 +3,7 @@ MPIRUN ?= mpirun MPICC ?= typeart-mpicc # instead of standard mpicc -all: libtool.so 01_ex 02_ex toy toy-stack +all: libtool.so demo demo_broken libtool.so: tool.c $(MPICC) -shared -fPIC $< -o $@ diff --git a/externals/abseil/CMakeLists.txt b/externals/abseil/CMakeLists.txt index cf6c35a8..c47f6890 100644 --- a/externals/abseil/CMakeLists.txt +++ b/externals/abseil/CMakeLists.txt @@ -3,7 +3,7 @@ set(ABSL_PROPAGATE_CXX_STD ON) FetchContent_Declare( cpp-abseil GIT_REPOSITORY https://github.com/abseil/abseil-cpp.git - GIT_TAG 20240722.1 + GIT_TAG 20250814.1 GIT_SHALLOW 1 ) diff --git a/lib/passes/CMakeLists.txt b/lib/passes/CMakeLists.txt index 7d8f44af..0346d7f0 100644 --- a/lib/passes/CMakeLists.txt +++ b/lib/passes/CMakeLists.txt @@ -12,6 +12,8 @@ set(PASS_SOURCES instrumentation/MemOpArgCollector.cpp instrumentation/MemOpInstrumentation.cpp instrumentation/Instrumentation.cpp + instrumentation/TypeIDProvider.cpp + instrumentation/CallBackFunctionInserter.cpp TypeARTConfiguration.cpp Commandline.cpp ) diff --git a/lib/passes/Commandline.cpp b/lib/passes/Commandline.cpp index 204766ef..3ea91a4e 100644 --- a/lib/passes/Commandline.cpp +++ b/lib/passes/Commandline.cpp @@ -15,6 +15,7 @@ #include "analysis/MemInstFinder.h" #include "configuration/Configuration.h" #include "configuration/EnvironmentConfiguration.h" +#include "instrumentation/TypeIDProvider.h" #include "support/ConfigurationBase.h" #include "support/Logger.h" #include "typegen/TypeGenerator.h" @@ -83,6 +84,15 @@ static cl::opt cl_typeart_instrument_stack(Commandl cl::init(ConfigStdArgValues::stack), cl::cat(typeart_category)); +static cl::opt cl_typeart_type_serialization( + CommandlineStdArgs::type_serialization, cl::desc(ConfigStdArgDescriptions::type_serialization), + cl::values(clEnumValN(typeart::TypeSerializationImplementation::FILE, "file", "File based type serialization"), + clEnumValN(typeart::TypeSerializationImplementation::INLINE, "inline", + "Type descriptors through global variables"), + clEnumValN(typeart::TypeSerializationImplementation::HYBRID, "hybrid", + "Type descriptors through global variables except for C/C++ built-in types")), + cl::Hidden, cl::init(typeart::TypeSerializationImplementation::FILE), cl::cat(typeart_category)); + static cl::opt cl_typeart_instrument_stack_lifetime( CommandlineStdArgs::stack_lifetime, cl::desc(ConfigStdArgDescriptions::stack_lifetime), cl::init(ConfigStdArgValues::stack_lifetime), cl::cat(typeart_category)); @@ -198,6 +208,7 @@ CommandLineOptions::CommandLineOptions() { make_entry(ConfigStdArgs::heap, cl_typeart_instrument_heap), make_entry(ConfigStdArgs::global, cl_typeart_instrument_global), make_entry(ConfigStdArgs::stack, cl_typeart_instrument_stack), + make_entry(ConfigStdArgs::type_serialization, cl_typeart_type_serialization), make_entry(ConfigStdArgs::stack_lifetime, cl_typeart_instrument_stack_lifetime), make_entry(ConfigStdArgs::typegen, cl_typeart_typegen_implementation), make_entry(ConfigStdArgs::filter, cl_typeart_call_filter), @@ -217,6 +228,7 @@ CommandLineOptions::CommandLineOptions() { make_occurr_entry(ConfigStdArgs::heap, cl_typeart_instrument_heap), make_occurr_entry(ConfigStdArgs::global, cl_typeart_instrument_global), make_occurr_entry(ConfigStdArgs::stack, cl_typeart_instrument_stack), + make_occurr_entry(ConfigStdArgs::type_serialization, cl_typeart_type_serialization), make_occurr_entry(ConfigStdArgs::stack_lifetime, cl_typeart_instrument_stack_lifetime), make_occurr_entry(ConfigStdArgs::typegen, cl_typeart_typegen_implementation), make_occurr_entry(ConfigStdArgs::filter, cl_typeart_call_filter), diff --git a/lib/passes/TypeARTPass.cpp b/lib/passes/TypeARTPass.cpp index 23bc5afa..eed4416e 100644 --- a/lib/passes/TypeARTPass.cpp +++ b/lib/passes/TypeARTPass.cpp @@ -19,9 +19,11 @@ #include "configuration/PassBuilderUtil.h" #include "configuration/PassConfiguration.h" #include "configuration/TypeARTOptions.h" +#include "instrumentation/CallBackFunctionInserter.h" #include "instrumentation/MemOpArgCollector.h" #include "instrumentation/MemOpInstrumentation.h" #include "instrumentation/TypeARTFunctions.h" +#include "instrumentation/TypeIDProvider.h" #include "support/ConfigurationBase.h" #include "support/Logger.h" #include "support/ModuleDumper.h" @@ -48,7 +50,9 @@ #include #include +#include #include +#include #include #include #include @@ -95,26 +99,10 @@ class TypeArtPass : public llvm::PassInfoMixin { std::optional pass_opts{std::nullopt}; std::unique_ptr pass_config; - struct TypeArtFunc { - const std::string name; - llvm::Value* f{nullptr}; - }; - - TypeArtFunc typeart_alloc{"__typeart_alloc"}; - TypeArtFunc typeart_alloc_global{"__typeart_alloc_global"}; - TypeArtFunc typeart_alloc_stack{"__typeart_alloc_stack"}; - TypeArtFunc typeart_free{"__typeart_free"}; - TypeArtFunc typeart_leave_scope{"__typeart_leave_scope"}; - - TypeArtFunc typeart_alloc_omp = typeart_alloc; - TypeArtFunc typeart_alloc_stacks_omp = typeart_alloc_stack; - TypeArtFunc typeart_free_omp = typeart_free; - TypeArtFunc typeart_leave_scope_omp = typeart_leave_scope; - std::unique_ptr meminst_finder; std::unique_ptr typeManager; InstrumentationHelper instrumentation_helper; - TAFunctions functions; + std::unique_ptr functions; std::unique_ptr instrumentation_context; const config::Configuration& configuration() const { @@ -168,15 +156,27 @@ class TypeArtPass : public llvm::PassInfoMixin { instrumentation_helper.setModule(m); ModuleData mdata{&m}; - typeManager->registerModule(mdata); + const auto has_cu_types = typeManager->registerModule(mdata); + + declareInstrumentationFunctions(m); + { + auto type_id_handler = get_type_id_handler(m, &typeManager->getTypeDatabase(), configuration(), functions.get()); + // const bool heap = configuration()[config::ConfigStdArgs::heap]; + if (has_cu_types) { + LOG_DEBUG("Registering compilation unit types list") + type_id_handler->registerModule(mdata); + } - auto arg_collector = - std::make_unique(configuration(), typeManager.get(), instrumentation_helper); - // const bool instrument_stack_lifetime = configuration()[config::ConfigStdArgs::stack_lifetime]; - auto mem_instrument = std::make_unique(configuration(), functions, instrumentation_helper); - instrumentation_context = - std::make_unique(std::move(arg_collector), std::move(mem_instrument)); + auto arg_collector = + std::make_unique(configuration(), typeManager.get(), instrumentation_helper); + // const bool instrument_stack_lifetime = configuration()[config::ConfigStdArgs::stack_lifetime]; + auto cb_provider = make_callback_inserter(configuration(), std::move(type_id_handler), functions.get()); + auto mem_instrument = std::make_unique(configuration(), functions.get(), + instrumentation_helper, std::move(cb_provider)); + instrumentation_context = + std::make_unique(std::move(arg_collector), std::move(mem_instrument)); + } return true; } @@ -184,16 +184,20 @@ class TypeArtPass : public llvm::PassInfoMixin { /* * Persist the accumulated type definition information for this module. */ - const std::string types_file = configuration()[config::ConfigStdArgs::types]; - LOG_DEBUG("Writing type file to " << types_file); - - const auto [stored, error] = typeManager->store(); - if (stored) { - LOG_DEBUG("Success!"); - } else { - LOG_FATAL("Failed writing type config to " << types_file << ". Reason: " << error.message()); + // TODO: inline/hybrid types not supported in non-opaque mode + const bool emit_type_file_always = bool(LLVM_VERSION_MAJOR < 15); + TypeSerializationImplementation mode = configuration()[config::ConfigStdArgs::type_serialization]; + if (emit_type_file_always || mode == TypeSerializationImplementation::FILE) { + const std::string types_file = configuration()[config::ConfigStdArgs::types]; + LOG_DEBUG("Writing type file to " << types_file); + + const auto [stored, error] = typeManager->store(); + if (stored) { + LOG_DEBUG("Success!"); + } else { + LOG_FATAL("Failed writing type config to " << types_file << ". Reason: " << error.message()); + } } - const bool print_stats = configuration()[config::ConfigStdArgs::stats]; if (print_stats) { auto& out = llvm::errs(); @@ -203,30 +207,7 @@ class TypeArtPass : public llvm::PassInfoMixin { } void declareInstrumentationFunctions(Module& m) { - // Remove this return if problems come up during compilation - if (typeart_alloc_global.f != nullptr && typeart_alloc_stack.f != nullptr && typeart_alloc.f != nullptr && - typeart_free.f != nullptr && typeart_leave_scope.f != nullptr) { - return; - } - - TAFunctionDeclarator decl(m, instrumentation_helper, functions); - - auto alloc_arg_types = instrumentation_helper.make_parameters(IType::ptr, IType::type_id, IType::extent); - auto free_arg_types = instrumentation_helper.make_parameters(IType::ptr); - auto leavescope_arg_types = instrumentation_helper.make_parameters(IType::stack_count); - - typeart_alloc.f = decl.make_function(IFunc::heap, typeart_alloc.name, alloc_arg_types); - typeart_alloc_stack.f = decl.make_function(IFunc::stack, typeart_alloc_stack.name, alloc_arg_types); - typeart_alloc_global.f = decl.make_function(IFunc::global, typeart_alloc_global.name, alloc_arg_types); - typeart_free.f = decl.make_function(IFunc::free, typeart_free.name, free_arg_types); - typeart_leave_scope.f = decl.make_function(IFunc::scope, typeart_leave_scope.name, leavescope_arg_types); - - typeart_alloc_omp.f = decl.make_function(IFunc::heap_omp, typeart_alloc_omp.name, alloc_arg_types, true); - typeart_alloc_stacks_omp.f = - decl.make_function(IFunc::stack_omp, typeart_alloc_stacks_omp.name, alloc_arg_types, true); - typeart_free_omp.f = decl.make_function(IFunc::free_omp, typeart_free_omp.name, free_arg_types, true); - typeart_leave_scope_omp.f = - decl.make_function(IFunc::scope_omp, typeart_leave_scope_omp.name, leavescope_arg_types, true); + functions = declare_instrumentation_functions(m, configuration()); } void printStats(llvm::raw_ostream& out) { @@ -292,7 +273,7 @@ class TypeArtPass : public llvm::PassInfoMixin { const bool instrument_global = configuration()[config::ConfigStdArgs::global]; bool globals_were_instrumented{false}; if (instrument_global) { - declareInstrumentationFunctions(m); + // declareInstrumentationFunctions(m); const auto& globalsList = meminst_finder->getModuleGlobals(); if (!globalsList.empty()) { @@ -322,7 +303,7 @@ class TypeArtPass : public llvm::PassInfoMixin { // FIXME this is required when "PassManagerBuilder::EP_OptimizerLast" is used as the function (constant) pointer are // nullpointer/invalidated - declareInstrumentationFunctions(*f.getParent()); + // declareInstrumentationFunctions(*f.getParent()); bool mod{false}; // auto& c = f.getContext(); @@ -364,7 +345,7 @@ class LegacyTypeArtPass : public llvm::ModulePass { public: static char ID; // NOLINT - LegacyTypeArtPass() : ModulePass(ID){}; + LegacyTypeArtPass() : ModulePass(ID) {}; bool doInitialization(llvm::Module&) override; @@ -399,8 +380,9 @@ llvm::PassPluginLibraryInfo getTypeartPassPluginInfo() { using namespace llvm; return {LLVM_PLUGIN_API_VERSION, "TypeART", LLVM_VERSION_STRING, [](PassBuilder& pass_builder) { pass_builder.registerPipelineStartEPCallback([](auto& MPM, OptimizationLevel) { - auto parameters = typeart::util::pass::parsePassParameters(typeart::config::pass::parse_typeart_config, - "typeart", "typeart"); + auto parameters = + typeart::util::pass::parsePassParameters(typeart::config::pass::parse_typeart_config, + "typeart", "typeart"); if (!parameters) { LOG_FATAL("Error parsing heap params: " << parameters.takeError()) return; @@ -408,8 +390,9 @@ llvm::PassPluginLibraryInfo getTypeartPassPluginInfo() { MPM.addPass(typeart::pass::TypeArtPass(typeart::pass::TypeArtPass(parameters.get()))); }); pass_builder.registerOptimizerLastEPCallback([](auto& MPM, OptimizationLevel) { - auto parameters = typeart::util::pass::parsePassParameters(typeart::config::pass::parse_typeart_config, - "typeart", "typeart"); + auto parameters = typeart::util::pass::parsePassParameters( + typeart::config::pass::parse_typeart_config, "typeart", + "typeart"); if (!parameters) { LOG_FATAL("Error parsing stack params: " << parameters.takeError()) return; diff --git a/lib/passes/analysis/MemInstFinder.cpp b/lib/passes/analysis/MemInstFinder.cpp index 051fc85b..27bfb9ec 100644 --- a/lib/passes/analysis/MemInstFinder.cpp +++ b/lib/passes/analysis/MemInstFinder.cpp @@ -193,7 +193,7 @@ bool MemInstFinderPass::runOnModule(Module& module) { } if (util::starts_with_any_of(name, "llvm.", "__llvm_gcov", "__llvm_gcda", "__profn", "___asan", - "__msan", "__tsan")) { + "__msan", "__tsan", "__typeart", "_typeart")) { LOG_DEBUG("Prefixed matched on " << name) return true; } diff --git a/lib/passes/configuration/EnvironmentConfiguration.cpp b/lib/passes/configuration/EnvironmentConfiguration.cpp index 339ff524..2d43fa8a 100644 --- a/lib/passes/configuration/EnvironmentConfiguration.cpp +++ b/lib/passes/configuration/EnvironmentConfiguration.cpp @@ -16,6 +16,7 @@ #include "OptionsUtil.h" #include "PassConfiguration.h" #include "configuration/TypeARTOptions.h" +#include "instrumentation/TypeIDProvider.h" #include "support/ConfigurationBase.h" #include "support/Logger.h" #include "support/Util.h" @@ -113,6 +114,9 @@ EnvironmentFlagsOptions::EnvironmentFlagsOptions() { EnvironmentStdArgsValues::global), make_entry(ConfigStdArgs::stack, EnvironmentStdArgs::stack, EnvironmentStdArgsValues::stack), + make_entry(ConfigStdArgs::type_serialization, + EnvironmentStdArgs::type_serialization, + EnvironmentStdArgsValues::type_serialization), make_entry( ConfigStdArgs::stack_lifetime, EnvironmentStdArgs::stack_lifetime, EnvironmentStdArgsValues::stack_lifetime), make_entry(ConfigStdArgs::typegen, EnvironmentStdArgs::typegen, @@ -148,6 +152,7 @@ EnvironmentFlagsOptions::EnvironmentFlagsOptions() { make_occurr_entry(ConfigStdArgs::heap, EnvironmentStdArgs::heap), make_occurr_entry(ConfigStdArgs::global, EnvironmentStdArgs::global), make_occurr_entry(ConfigStdArgs::stack, EnvironmentStdArgs::stack), + make_occurr_entry(ConfigStdArgs::type_serialization, EnvironmentStdArgs::type_serialization), make_occurr_entry(ConfigStdArgs::stack_lifetime, EnvironmentStdArgs::stack_lifetime), make_occurr_entry(ConfigStdArgs::typegen, EnvironmentStdArgs::typegen), make_occurr_entry(ConfigStdArgs::filter, EnvironmentStdArgs::filter), diff --git a/lib/passes/configuration/OptionsUtil.h b/lib/passes/configuration/OptionsUtil.h index 1c308565..f44ac0c4 100644 --- a/lib/passes/configuration/OptionsUtil.h +++ b/lib/passes/configuration/OptionsUtil.h @@ -10,10 +10,11 @@ // SPDX-License-Identifier: BSD-3-Clause // -#ifndef TYPEART_CONFIGURATION_OPTIONS_UTIL_H -#define TYPEART_CONFIGURATION_OPTIONS_UTIL_H +#ifndef LIB_PASSES_CONFIGURATION_OPTIONSUTIL +#define LIB_PASSES_CONFIGURATION_OPTIONSUTIL #include "analysis/MemInstFinder.h" +#include "instrumentation/TypeIDProvider.h" #include "support/Logger.h" #include "typegen/TypeGenerator.h" @@ -30,6 +31,7 @@ bool with_any_of(llvm::StringRef lhs, Strings&&... rhs) { template ClType string_to_enum(llvm::StringRef cl_value) { using ::typeart::TypegenImplementation; + using ::typeart::TypeSerializationImplementation; using ::typeart::analysis::FilterImplementation; if constexpr (std::is_same_v) { auto val = llvm::StringSwitch(cl_value) @@ -38,12 +40,21 @@ ClType string_to_enum(llvm::StringRef cl_value) { .Default(TypegenImplementation::DIMETA); return val; } else { - auto val = llvm::StringSwitch(cl_value) - .Case("cg", FilterImplementation::cg) - .Case("none", FilterImplementation::none) - .Case("std", FilterImplementation::standard) - .Default(FilterImplementation::standard); - return val; + if constexpr (std::is_same_v) { + auto val = llvm::StringSwitch(cl_value) + .Case("cg", FilterImplementation::cg) + .Case("none", FilterImplementation::none) + .Case("std", FilterImplementation::standard) + .Default(FilterImplementation::standard); + return val; + } else { + auto val = llvm::StringSwitch(cl_value) + .Case("file", TypeSerializationImplementation::FILE) + .Case("hybrid", TypeSerializationImplementation::HYBRID) + .Case("inline", TypeSerializationImplementation::INLINE) + .Default(TypeSerializationImplementation::INLINE); + return val; + } } } @@ -69,4 +80,4 @@ ClType make_opt(llvm::StringRef cl_value) { } } // namespace typeart::config::util -#endif /* TYPEART_CONFIGURATION_OPTIONS_UTIL_H */ +#endif /* LIB_PASSES_CONFIGURATION_OPTIONSUTIL */ diff --git a/lib/passes/configuration/PassBuilderUtil.h b/lib/passes/configuration/PassBuilderUtil.h index bebeda9d..8908e2f5 100644 --- a/lib/passes/configuration/PassBuilderUtil.h +++ b/lib/passes/configuration/PassBuilderUtil.h @@ -52,8 +52,8 @@ inline bool checkParametrizedPassName(llvm::StringRef Name, llvm::StringRef Pass /// Expected<> template class. /// template -inline auto parsePassParameters(ParametersParseCallableT&& Parser, llvm::StringRef Name, llvm::StringRef PassName) - -> decltype(Parser(llvm::StringRef{})) { +inline auto parsePassParameters(ParametersParseCallableT&& Parser, llvm::StringRef Name, + llvm::StringRef PassName) -> decltype(Parser(llvm::StringRef{})) { using namespace llvm; using ParametersT = typename decltype(Parser(StringRef{}))::value_type; diff --git a/lib/passes/configuration/PassConfiguration.cpp b/lib/passes/configuration/PassConfiguration.cpp index 24177765..659aab1f 100644 --- a/lib/passes/configuration/PassConfiguration.cpp +++ b/lib/passes/configuration/PassConfiguration.cpp @@ -15,6 +15,7 @@ #include "OptionsUtil.h" #include "analysis/MemInstFinder.h" #include "configuration/Configuration.h" +#include "instrumentation/TypeIDProvider.h" #include "support/ConfigurationBase.h" #include "support/ConfigurationBaseOptions.h" #include "support/Error.h" @@ -102,6 +103,12 @@ PassConfig parse_typeart_config_with_occurrence(llvm::StringRef parameters) { continue; } + if (parameter_name.consume_front(PassStdArgsEq::type_serialization)) { + result.type_serialization = util::string_to_enum(parameter_name); + occurrence_map[ConfigStdArgs::type_serialization] = true; + continue; + } + if (parameter_name.consume_front(PassStdArgsEq::filter_glob)) { result.filter_config.glob = parameter_name; occurrence_map[ConfigStdArgs::filter_glob] = true; diff --git a/lib/passes/configuration/TypeARTOptions.cpp b/lib/passes/configuration/TypeARTOptions.cpp index 00a1d113..db1a76eb 100644 --- a/lib/passes/configuration/TypeARTOptions.cpp +++ b/lib/passes/configuration/TypeARTOptions.cpp @@ -14,6 +14,7 @@ #include "Configuration.h" #include "FileConfiguration.h" +#include "instrumentation/TypeIDProvider.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" @@ -24,6 +25,15 @@ using namespace llvm::yaml; using namespace typeart::config::file; +template <> +struct llvm::yaml::ScalarEnumerationTraits { + static void enumeration(IO& io, typeart::TypeSerializationImplementation& value) { + io.enumCase(value, "inline", typeart::TypeSerializationImplementation::INLINE); + io.enumCase(value, "file", typeart::TypeSerializationImplementation::FILE); + io.enumCase(value, "hybrid", typeart::TypeSerializationImplementation::HYBRID); + } +}; + template <> struct llvm::yaml::ScalarEnumerationTraits { static void enumeration(IO& io, typeart::analysis::FilterImplementation& value) { @@ -85,6 +95,7 @@ struct llvm::yaml::MappingTraits { yml_io.mapOptional(ConfigStdArgs::stats, info.statistics); yml_io.mapOptional(ConfigStdArgs::stack_lifetime, info.stack_lifetime); yml_io.mapRequired(ConfigStdArgs::typegen, info.typegen); + yml_io.mapRequired(ConfigStdArgs::type_serialization, info.type_serialization); yml_io.mapRequired(ConfigStdArgs::filter, info.filter); yml_io.mapOptional("call-filter", info.filter_config); yml_io.mapOptional("analysis", info.analysis_config); @@ -140,6 +151,7 @@ TypeARTConfigOptions construct_with(Constructor&& make_entry) { make_entry(ConfigStdArgs::analysis_filter_pointer_alloc, config.analysis_config.filter_pointer_alloc); make_entry(ConfigStdArgs::analysis_filter_alloca_non_array, config.analysis_config.filter_alloca_non_array); make_entry(ConfigStdArgs::typegen, config.typegen); + make_entry(ConfigStdArgs::type_serialization, config.type_serialization); return config; } @@ -160,8 +172,8 @@ TypeARTConfigOptions config_to_options(const Configuration& configuration) { } template -auto make_entry(std::string_view key, const T& field_value) - -> std::pair { +auto make_entry(std::string_view key, + const T& field_value) -> std::pair { if constexpr (std::is_enum_v) { return {key, config::OptionValue{static_cast(field_value)}}; } else { @@ -187,9 +199,10 @@ OptionsMap options_to_map(const TypeARTConfigOptions& config) { make_entry(ConfigStdArgs::analysis_filter_heap_alloc, config.analysis_config.filter_heap_alloc), make_entry(ConfigStdArgs::analysis_filter_pointer_alloc, config.analysis_config.filter_pointer_alloc), make_entry(ConfigStdArgs::analysis_filter_alloca_non_array, config.analysis_config.filter_alloca_non_array), + make_entry(ConfigStdArgs::type_serialization, config.type_serialization), }; return mapping_; -} +} // namespace helper } // namespace helper diff --git a/lib/passes/configuration/TypeARTOptions.h b/lib/passes/configuration/TypeARTOptions.h index 7110bed1..edccff6f 100644 --- a/lib/passes/configuration/TypeARTOptions.h +++ b/lib/passes/configuration/TypeARTOptions.h @@ -10,11 +10,12 @@ // SPDX-License-Identifier: BSD-3-Clause // -#ifndef TYPEART_CONFIGURATION_OPTIONS_H -#define TYPEART_CONFIGURATION_OPTIONS_H +#ifndef LIB_PASSES_CONFIGURATION_TYPEARTOPTIONS +#define LIB_PASSES_CONFIGURATION_TYPEARTOPTIONS #include "analysis/MemInstFinder.h" #include "configuration/Configuration.h" +#include "instrumentation/TypeIDProvider.h" #include "support/ConfigurationBase.h" #include "typegen/TypeGenerator.h" @@ -50,6 +51,11 @@ struct TypeARTConfigOptions { bool statistics{ConfigStdArgValues::stats}; bool stack_lifetime{ConfigStdArgValues::stack_lifetime}; TypegenImplementation typegen{TypegenImplementation::DIMETA}; +#if LLVM_VERSION_MAJOR > 14 + TypeSerializationImplementation type_serialization{TypeSerializationImplementation::HYBRID}; +#else + TypeSerializationImplementation type_serialization{TypeSerializationImplementation::FILE}; +#endif bool filter{false}; TypeARTCallFilterOptions filter_config{}; @@ -76,4 +82,4 @@ llvm::raw_ostream& operator<<(llvm::raw_ostream& out_s, const TypeARTConfigOptio } // namespace typeart::config -#endif /* TYPEART_CONFIGURATION_OPTIONS_H */ +#endif /* LIB_PASSES_CONFIGURATION_TYPEARTOPTIONS */ diff --git a/lib/passes/filter/FilterUtil.h b/lib/passes/filter/FilterUtil.h index 9878b8aa..c54ca2f5 100644 --- a/lib/passes/filter/FilterUtil.h +++ b/lib/passes/filter/FilterUtil.h @@ -46,8 +46,12 @@ using namespace llvm; namespace typeart::filter { struct FunctionAnalysis { - using FunctionCounts = struct { int decl, def, intrinsic, indirect; }; - using FunctionCalls = struct { llvm::SmallVector decl, def, intrinsic, indirect; }; + using FunctionCounts = struct { + int decl, def, intrinsic, indirect; + }; + using FunctionCalls = struct { + llvm::SmallVector decl, def, intrinsic, indirect; + }; FunctionCalls calls; diff --git a/lib/passes/instrumentation/CallBackFunctionInserter.cpp b/lib/passes/instrumentation/CallBackFunctionInserter.cpp new file mode 100644 index 00000000..cd89f9f7 --- /dev/null +++ b/lib/passes/instrumentation/CallBackFunctionInserter.cpp @@ -0,0 +1,94 @@ +#include "CallBackFunctionInserter.h" + +#include "configuration/Configuration.h" +#include "instrumentation/TypeIDProvider.h" +#include "support/ConfigurationBase.h" +#include "support/Logger.h" + +#include "llvm/IR/Function.h" +#include "llvm/IR/GlobalVariable.h" +#include "llvm/IR/IRBuilder.h" + +#include + +namespace typeart { + +class CallbackFunctionInserter final : public InstrumentationInserter { + std::unique_ptr type_id_handler_; + TAFunctionQuery* function_query_; + TypeSerializationImplementation mode_; + // bool mixed_mode{false}; + + private: + llvm::CallInst* create_instrumentation_call(llvm::IRBuilder<>& IRB, IFunc callback_type, + llvm::Value* instruction_or_value, InstrumentationPayload args); + + public: + CallbackFunctionInserter(const config::Configuration& configuration, std::unique_ptr type_id_handler, + TAFunctionQuery* function_query); + + llvm::CallInst* insert_heap_instrumentation(llvm::IRBuilder<>& IRB, llvm::CallBase* heap_call, + InstrumentationPayload) override; + + llvm::CallInst* insert_stack_instrumentation(llvm::IRBuilder<>& IRB, llvm::Instruction* alloca, + InstrumentationPayload) override; + + llvm::CallInst* insert_global_instrumentation(llvm::IRBuilder<>& IRB, llvm::GlobalValue* global_var, + InstrumentationPayload) override; + + llvm::CallInst* insert_free_instrumentation(llvm::IRBuilder<>& IRB, llvm::CallBase* call, + llvm::Value* pointer_value) override; +}; + +CallbackFunctionInserter::CallbackFunctionInserter(const config::Configuration& configuration, + std::unique_ptr type_id_handler, + TAFunctionQuery* function_query) + : type_id_handler_(std::move(type_id_handler)), function_query_(function_query) { + mode_ = configuration[config::ConfigStdArgs::type_serialization]; + // mixed_mode = value == TypeSerializationImplementation::HYBRID; +} + +// Private Helper Definition +llvm::CallInst* CallbackFunctionInserter::create_instrumentation_call(llvm::IRBuilder<>& IRB, IFunc callback_type, + llvm::Value* instruction_or_value, + InstrumentationPayload args) { + const auto callback_id = ifunc_for_function(callback_type, instruction_or_value); + auto type_id_param_out = type_id_handler_->getOrRegister(args.typeid_value); + + const auto mode = llvm::isa(type_id_param_out) ? mode_ : TypeSerializationImplementation::FILE; + auto function = function_query_->getFunctionFor(callback_id, mode); + + return IRB.CreateCall(function, + llvm::ArrayRef{args.pointer_value, type_id_param_out, args.element_count}); +} + +llvm::CallInst* CallbackFunctionInserter::insert_heap_instrumentation(llvm::IRBuilder<>& IRB, llvm::CallBase* heap_call, + InstrumentationPayload args) { + return create_instrumentation_call(IRB, IFunc::heap, heap_call, args); +} + +llvm::CallInst* CallbackFunctionInserter::insert_stack_instrumentation(llvm::IRBuilder<>& IRB, + llvm::Instruction* alloca, + InstrumentationPayload args) { + return create_instrumentation_call(IRB, IFunc::stack, alloca, args); +} + +llvm::CallInst* CallbackFunctionInserter::insert_global_instrumentation(llvm::IRBuilder<>& IRB, + llvm::GlobalValue* global_var, + InstrumentationPayload args) { + return create_instrumentation_call(IRB, IFunc::global, global_var, args); +} + +llvm::CallInst* CallbackFunctionInserter::insert_free_instrumentation(llvm::IRBuilder<>& IRB, llvm::CallBase* call, + llvm::Value* pointer_value) { + const auto callback_id = ifunc_for_function(IFunc::free, call); + return IRB.CreateCall(function_query_->getFunctionFor(callback_id), llvm::ArrayRef{pointer_value}); +} + +std::unique_ptr make_callback_inserter(const config::Configuration& configuration, + std::unique_ptr type_id_handler, + TAFunctionQuery* function_query) { + return std::make_unique(configuration, std::move(type_id_handler), function_query); +} + +} // namespace typeart \ No newline at end of file diff --git a/lib/passes/instrumentation/CallBackFunctionInserter.h b/lib/passes/instrumentation/CallBackFunctionInserter.h new file mode 100644 index 00000000..70e88737 --- /dev/null +++ b/lib/passes/instrumentation/CallBackFunctionInserter.h @@ -0,0 +1,54 @@ +#ifndef LIB_PASSES_INSTRUMENTATION_CALLBACKFUNCTIONINSERTER +#define LIB_PASSES_INSTRUMENTATION_CALLBACKFUNCTIONINSERTER + +#include "instrumentation/TypeARTFunctions.h" + +#include "llvm/IR/IRBuilder.h" + +#include + +namespace llvm { +class CallInst; +class Value; +class CallBase; +class Instruction; +class GlobalValue; +} // namespace llvm + +namespace typeart { +namespace config { +class Configuration; +} +class TypeRegistry; +class TAFunctionQuery; + +struct InstrumentationPayload { + llvm::Value* pointer_value; + llvm::Value* element_count; + llvm::Value* typeid_value; +}; + +class InstrumentationInserter { + public: + virtual ~InstrumentationInserter() = default; + + virtual llvm::CallInst* insert_heap_instrumentation(llvm::IRBuilder<>& IRB, llvm::CallBase* heap_call, + InstrumentationPayload) = 0; + + virtual llvm::CallInst* insert_stack_instrumentation(llvm::IRBuilder<>& IRB, llvm::Instruction* alloca, + InstrumentationPayload) = 0; + + virtual llvm::CallInst* insert_global_instrumentation(llvm::IRBuilder<>& IRB, llvm::GlobalValue* global_var, + InstrumentationPayload) = 0; + + virtual llvm::CallInst* insert_free_instrumentation(llvm::IRBuilder<>& IRB, llvm::CallBase* heap_call, + llvm::Value* pointer_value) = 0; +}; + +std::unique_ptr make_callback_inserter(const config::Configuration& configuration, + std::unique_ptr type_id_handler, + TAFunctionQuery* function_query); + +} // namespace typeart + +#endif /* LIB_PASSES_INSTRUMENTATION_CALLBACKFUNCTIONINSERTER */ diff --git a/lib/passes/instrumentation/InstrumentationHelper.h b/lib/passes/instrumentation/InstrumentationHelper.h index 081f1d5d..38d2a322 100644 --- a/lib/passes/instrumentation/InstrumentationHelper.h +++ b/lib/passes/instrumentation/InstrumentationHelper.h @@ -60,7 +60,6 @@ class InstrumentationHelper { llvm::Type* getTypeFor(IType id); llvm::ConstantInt* getConstantFor(IType id, size_t val = 0); - const std::map& getFunctionMap() const; virtual ~InstrumentationHelper(); }; diff --git a/lib/passes/instrumentation/MemOpInstrumentation.cpp b/lib/passes/instrumentation/MemOpInstrumentation.cpp index 5a763dc2..b50f1fc2 100644 --- a/lib/passes/instrumentation/MemOpInstrumentation.cpp +++ b/lib/passes/instrumentation/MemOpInstrumentation.cpp @@ -19,6 +19,8 @@ #include "TypeInterface.h" #include "analysis/MemOpData.h" #include "configuration/Configuration.h" +#include "instrumentation/CallBackFunctionInserter.h" +#include "instrumentation/TypeIDProvider.h" #include "support/ConfigurationBase.h" #include "support/Logger.h" #include "support/OmpUtil.h" @@ -41,6 +43,8 @@ #include "llvm/Support/raw_ostream.h" #include "llvm/Transforms/Utils/ModuleUtils.h" +#include +#include #include namespace llvm { @@ -51,9 +55,14 @@ using namespace llvm; namespace typeart { -MemOpInstrumentation::MemOpInstrumentation(const config::Configuration& typeart_conf, TAFunctionQuery& fquery, - InstrumentationHelper& instr) - : MemoryInstrument(), typeart_config(typeart_conf), function_query(&fquery), instrumentation_helper(&instr) { +MemOpInstrumentation::MemOpInstrumentation(const config::Configuration& typeart_conf, TAFunctionQuery* fquery, + InstrumentationHelper& instr, + std::unique_ptr function_instrumenter) + : MemoryInstrument(), + typeart_config(typeart_conf), + function_query(fquery), + instrumentation_helper(&instr), + function_instrumenter_(std::move(function_instrumenter)) { instrument_lifetime = typeart_config[config::ConfigStdArgs::stack_lifetime]; } @@ -61,6 +70,7 @@ InstrCount MemOpInstrumentation::instrumentHeap(const HeapArgList& heap) { InstrCount counter{0}; auto type_gen = typeart_config[config::ConfigStdArgs::typegen]; const bool is_llvm_ir_type = static_cast(type_gen) == static_cast(TypegenImplementation::IR); + for (const auto& [malloc, args] : heap) { auto kind = malloc.kind; auto* malloc_call = args.get_as(ArgMap::ID::pointer); @@ -87,8 +97,8 @@ InstrCount MemOpInstrumentation::instrumentHeap(const HeapArgList& heap) { Value* element_count{nullptr}; - auto parent_f = malloc.call->getFunction(); - const bool omp = util::omp::isOmpContext(parent_f); + // auto parent_f = malloc.call->getFunction(); + // const bool omp = util::omp::isOmpContext(parent_f); const bool dimeta_calc_byte_size = !is_llvm_ir_type && (typeid_value->equalsInt(TYPEART_VOID)); @@ -129,9 +139,8 @@ InstrCount MemOpInstrumentation::instrumentHeap(const HeapArgList& heap) { element_count = calculate_element_count(bytes); IRBuilder<> free_before_realloc(malloc_call); - const auto callback_id = omp ? IFunc::free_omp : IFunc::free; - free_before_realloc.CreateCall(function_query->getFunctionFor(callback_id), - ArrayRef{target_memory_address}); + function_instrumenter_->insert_free_instrumentation(free_before_realloc, llvm::dyn_cast(malloc_call), + target_memory_address); break; } default: @@ -139,9 +148,12 @@ InstrCount MemOpInstrumentation::instrumentHeap(const HeapArgList& heap) { continue; } - const auto callback_id = omp ? IFunc::heap_omp : IFunc::heap; - IRB.CreateCall(function_query->getFunctionFor(callback_id), - ArrayRef{malloc_call, typeid_value, element_count}); + function_instrumenter_->insert_heap_instrumentation(IRB, malloc.call, {malloc_call, element_count, typeid_value}); + + // const auto callback_id = ifunc_for_function(IFunc::heap, malloc.call); + // auto type_id_param = function_instrumenter->getOrRegister(typeid_value); + // IRB.CreateCall(function_query->getFunctionFor(callback_id), + // ArrayRef{malloc_call, type_id_param, element_count}); ++counter; } @@ -174,10 +186,13 @@ InstrCount MemOpInstrumentation::instrumentFree(const FreeArgList& frees) { IRBuilder<> IRB(insertBefore); - auto parent_f = fdata.call->getFunction(); - const auto callback_id = util::omp::isOmpContext(parent_f) ? IFunc::free_omp : IFunc::free; + function_instrumenter_->insert_free_instrumentation(IRB, fdata.call, free_arg); + + // auto parent_f = fdata.call->getFunction(); + // const auto callback_id = util::omp::isOmpContext(parent_f) ? IFunc::free_omp : IFunc::free; + // const auto callback_id = ifunc_for_function(IFunc::free, fdata.call); - IRB.CreateCall(function_query->getFunctionFor(callback_id), ArrayRef{free_arg}); + // IRB.CreateCall(function_query->getFunctionFor(callback_id), ArrayRef{free_arg}); ++counter; } @@ -195,9 +210,12 @@ InstrCount MemOpInstrumentation::instrumentStack(const StackArgList& stack) { auto* numElementsVal = args.get_value(ArgMap::ID::element_count); const auto instrument_stack = [&](IRBuilder<>& IRB, Value* data_ptr, Instruction* anchor) { - const auto callback_id = util::omp::isOmpContext(anchor->getFunction()) ? IFunc::stack_omp : IFunc::stack; - IRB.CreateCall(function_query->getFunctionFor(callback_id), - ArrayRef{data_ptr, typeIdConst, numElementsVal}); + // const auto callback_id = util::omp::isOmpContext(anchor->getFunction()) ? IFunc::stack_omp : IFunc::stack; + // const auto callback_id = ifunc_for_function(IFunc::stack, alloca); + // auto type_id_param = function_instrumenter->getOrRegister(typeIdConst); + // IRB.CreateCall(function_query->getFunctionFor(callback_id), + // ArrayRef{data_ptr, type_id_param, numElementsVal}); + function_instrumenter_->insert_stack_instrumentation(IRB, alloca, {data_ptr, numElementsVal, typeIdConst}); ++counter; auto* bblock = anchor->getParent(); @@ -238,8 +256,11 @@ InstrCount MemOpInstrumentation::instrumentGlobal(const GlobalArgList& globals) auto typeIdConst = args.get_value(ArgMap::ID::type_id); auto numElementsVal = args.get_value(ArgMap::ID::element_count); auto globalPtr = IRB.CreateBitOrPointerCast(global, instrumentation_helper->getTypeFor(IType::ptr)); - IRB.CreateCall(function_query->getFunctionFor(IFunc::global), - ArrayRef{globalPtr, typeIdConst, numElementsVal}); + // const auto callback_id = ifunc_for_function(IFunc::global, global); + // auto type_id_param = function_instrumenter->getOrRegister(typeIdConst); + // IRB.CreateCall(function_query->getFunctionFor(callback_id), + // ArrayRef{globalPtr, type_id_param, numElementsVal}); + function_instrumenter_->insert_global_instrumentation(IRB, global, {globalPtr, numElementsVal, typeIdConst}); ++counter; } }; diff --git a/lib/passes/instrumentation/MemOpInstrumentation.h b/lib/passes/instrumentation/MemOpInstrumentation.h index 0a8bd442..0b82c0bd 100644 --- a/lib/passes/instrumentation/MemOpInstrumentation.h +++ b/lib/passes/instrumentation/MemOpInstrumentation.h @@ -10,28 +10,34 @@ // SPDX-License-Identifier: BSD-3-Clause // -#ifndef TYPEART_MEMOPINSTRUMENTATION_H -#define TYPEART_MEMOPINSTRUMENTATION_H +#ifndef LIB_PASSES_INSTRUMENTATION_MEMOPINSTRUMENTATION +#define LIB_PASSES_INSTRUMENTATION_MEMOPINSTRUMENTATION #include "Instrumentation.h" #include "configuration/Configuration.h" +#include + namespace typeart { namespace config { class Configuration; } class TAFunctionQuery; class InstrumentationHelper; +class TypeRegistry; +class InstrumentationInserter; class MemOpInstrumentation final : public MemoryInstrument { const config::Configuration& typeart_config; TAFunctionQuery* function_query; + // std::unique_ptr type_id_handler; InstrumentationHelper* instrumentation_helper; + std::unique_ptr function_instrumenter_; bool instrument_lifetime{false}; public: - MemOpInstrumentation(const config::Configuration& typeart_conf, TAFunctionQuery& fquery, - InstrumentationHelper& instr); + MemOpInstrumentation(const config::Configuration& typeart_conf, TAFunctionQuery* fquery, InstrumentationHelper& instr, + std::unique_ptr function_instrumenter); InstrCount instrumentHeap(const HeapArgList& heap) override; InstrCount instrumentFree(const FreeArgList& frees) override; InstrCount instrumentStack(const StackArgList& stack) override; @@ -39,4 +45,4 @@ class MemOpInstrumentation final : public MemoryInstrument { }; } // namespace typeart -#endif // TYPEART_MEMOPINSTRUMENTATION_H +#endif /* LIB_PASSES_INSTRUMENTATION_MEMOPINSTRUMENTATION */ diff --git a/lib/passes/instrumentation/TypeARTFunctions.cpp b/lib/passes/instrumentation/TypeARTFunctions.cpp index f4955ec3..5ddfa462 100644 --- a/lib/passes/instrumentation/TypeARTFunctions.cpp +++ b/lib/passes/instrumentation/TypeARTFunctions.cpp @@ -1,4 +1,5 @@ // TypeART library + // // Copyright (c) 2017-2025 TypeART Authors // Distributed under the BSD 3-Clause license. @@ -12,7 +13,11 @@ #include "TypeARTFunctions.h" +#include "configuration/Configuration.h" +#include "instrumentation/TypeIDProvider.h" +#include "support/ConfigurationBase.h" #include "support/Logger.h" +#include "support/OmpUtil.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringMap.h" @@ -27,7 +32,11 @@ #include "llvm/Support/Casting.h" #include "llvm/Support/raw_ostream.h" +#include +#include #include +#include +#include namespace typeart { class InstrumentationHelper; @@ -37,29 +46,134 @@ using namespace llvm; namespace typeart { +namespace detail { +std::string get_func_suffix(IFunc id) { + switch (id) { + // case IFunc::free_cuda: + // case IFunc::heap_cuda: + // return "_cuda"; + case IFunc::free_omp: + case IFunc::heap_omp: + case IFunc::stack_omp: + case IFunc::scope_omp: + return "_omp"; + default: + return ""; + } +} + +enum class IFuncType : unsigned { standard, omp, cuda }; + +IFuncType ifunc_type_for(llvm::Function* f) { + if (f == nullptr) { + return IFuncType::standard; + } + + if (util::omp::isOmpContext(f)) { + return IFuncType::omp; + } + + return IFuncType::standard; +} + +} // namespace detail + +IFunc ifunc_for_function(IFunc general_type, llvm::Value* value) { + detail::IFuncType type = typeart::detail::IFuncType::standard; + + if (auto function = llvm::dyn_cast(value)) { + type = detail::ifunc_type_for(function); + } else if (auto alloca = llvm::dyn_cast(value)) { + type = detail::ifunc_type_for(alloca->getFunction()); + } else if (llvm::isa(value)) { + type = detail::ifunc_type_for(nullptr); + } else if (auto callbase = llvm::dyn_cast(value)) { + type = detail::ifunc_type_for(callbase->getFunction()); + // auto maybe_cuda = detail::ifunc_type_for(callbase->getCalledFunction()); + // if (maybe_cuda == detail::IFuncType::cuda) { + // type = detail::IFuncType::cuda; + // } + } + + if (detail::IFuncType::standard == type) { + return general_type; + } + + // if (detail::IFuncType::cuda == type) { + // switch (general_type) { + // case IFunc::heap: + // return IFunc::heap_cuda; + // case IFunc::free: + // return IFunc::free_cuda; + // default: + // return general_type; + // // llvm_unreachable("IFunc not supported for CUDA."); + // } + // } + + switch (general_type) { + case IFunc::stack: + return IFunc::stack_omp; + case IFunc::heap: + return IFunc::heap_omp; + case IFunc::free: + return IFunc::free_omp; + case IFunc::scope: + return IFunc::scope_omp; + default: + llvm_unreachable("IFunc type is not supported for OpenMP."); + } +} + +class TAFunctions final : public TAFunctionQuery { + // densemap has problems with IFunc + using FMap = std::unordered_map; + FMap typeart_callbacks; + + public: + llvm::Function* getFunctionFor( + IFunc id, TypeSerializationImplementation impl = TypeSerializationImplementation::FILE) const override; + void putFunctionFor(IFunc id, llvm::Function* f); + // void putAlternativeFunctionFor(IFunc id, llvm::Function* f); +}; + +class TAFunctionDeclarator { + llvm::Module& module; + // [[maybe_unused]] InstrumentationHelper& instr; + TAFunctions& typeart_functions; + llvm::StringMap function_map; + + public: + TAFunctionDeclarator(llvm::Module& m, InstrumentationHelper& instr, TAFunctions& typeart_func); + llvm::Function* make_function(IFunc function, llvm::StringRef basename, llvm::ArrayRef args, + bool alternative = false); + const llvm::StringMap& getFunctionMap() const; + virtual ~TAFunctionDeclarator() = default; +}; + TAFunctionDeclarator::TAFunctionDeclarator(Module& mod, InstrumentationHelper&, TAFunctions& typeart_funcs) : module(mod), typeart_functions(typeart_funcs) { } llvm::Function* TAFunctionDeclarator::make_function(IFunc func_id, llvm::StringRef basename, - llvm::ArrayRef args, bool with_omp, bool fixed_name) { - const auto make_fname = [&fixed_name](llvm::StringRef name, llvm::ArrayRef callback_arguments, - bool with_omp_postfix) { + llvm::ArrayRef args, bool alternative) { + const auto make_fname = [&func_id](llvm::StringRef name, llvm::ArrayRef callback_arguments) { std::string fname; llvm::raw_string_ostream os(fname); os << name; + os << detail::get_func_suffix(func_id); - if (!fixed_name) { - os << "_" << std::to_string(callback_arguments.size()); - } - if (with_omp_postfix) { - os << "_" - << "omp"; - } + // if (!fixed_name) { + // os << "_" << std::to_string(callback_arguments.size()); + // } + // if (with_omp_postfix) { + // os << "_" + // << "omp"; + // } return os.str(); }; - const auto name = make_fname(basename, args, with_omp); + const auto name = make_fname(basename, args); if (auto it = function_map.find(name); it != function_map.end()) { return it->second; @@ -91,7 +205,7 @@ llvm::Function* TAFunctionDeclarator::make_function(IFunc func_id, llvm::StringR Function* function{nullptr}; if (has_func_declared) { - LOG_WARNING("Function " << function_name << " is already declared in the module.") + LOG_DEBUG("Function " << function_name << " is already declared in the module.") function = dyn_cast(func_in_module.getCallee()->stripPointerCasts()); } else { function = dyn_cast(func_in_module.getCallee()); @@ -102,12 +216,15 @@ llvm::Function* TAFunctionDeclarator::make_function(IFunc func_id, llvm::StringR return function; }; - auto generated_function = do_make(name, FunctionType::get(Type::getVoidTy(c), args, false)); + auto* generated_function = do_make(name, FunctionType::get(Type::getVoidTy(c), args, false)); function_map[name] = generated_function; + // if (alternative) { + // typeart_functions.putAlternativeFunctionFor(func_id, generated_function); + // } else { typeart_functions.putFunctionFor(func_id, generated_function); - + // } return generated_function; } @@ -115,14 +232,110 @@ const llvm::StringMap& TAFunctionDeclarator::getFunctionMap() c return function_map; } -TAFunctions::TAFunctions() = default; +Function* TAFunctions::getFunctionFor(IFunc id, TypeSerializationImplementation impl) const { + const auto find_ = [&](const auto& map_) -> std::optional { + const auto element = map_.find(id); + if (element == std::end(map_)) { + LOG_WARNING("No functions for id " << int(id)) + return {}; + } + return element->second; + }; -Function* TAFunctions::getFunctionFor(IFunc id) { - return typeart_callbacks[id]; + auto result = find_(typeart_callbacks); + return result.value_or(nullptr); } void TAFunctions::putFunctionFor(IFunc id, llvm::Function* f) { typeart_callbacks[id] = f; } +class TAFunctionAlternatives : public TAFunctionQuery { + TAFunctions standard_; + TAFunctions alternative_; + + public: + TAFunctionAlternatives(TAFunctions standard, TAFunctions alternative) + : standard_(std::move(standard)), alternative_(std::move(alternative)) { + } + Function* getFunctionFor(IFunc id, TypeSerializationImplementation impl) const override { + if (impl != TypeSerializationImplementation::FILE) { + auto alternative = alternative_.getFunctionFor(id); + if (alternative != nullptr) { + return alternative; + } + } + return standard_.getFunctionFor(id); + } +}; + +namespace callbacks { +struct TypeArtFunc { + const std::string name; + llvm::Value* f{nullptr}; +}; + +TypeArtFunc typeart_alloc{"__typeart_alloc"}; +TypeArtFunc typeart_alloc_global{"__typeart_alloc_global"}; +TypeArtFunc typeart_alloc_stack{"__typeart_alloc_stack"}; +TypeArtFunc typeart_free{"__typeart_free"}; +TypeArtFunc typeart_leave_scope{"__typeart_leave_scope"}; + +TypeArtFunc typeart_alloc_omp = typeart_alloc; +TypeArtFunc typeart_alloc_stacks_omp = typeart_alloc_stack; +TypeArtFunc typeart_free_omp = typeart_free; +TypeArtFunc typeart_leave_scope_omp = typeart_leave_scope; + +TypeArtFunc typeart_alloc_mty{"__typeart_alloc_mty"}; +TypeArtFunc typeart_alloc_stack_mty{"__typeart_alloc_stack_mty"}; +TypeArtFunc typeart_alloc_global_mty{"__typeart_alloc_global_mty"}; +TypeArtFunc typeart_register_type{"__typeart_register_type"}; +TypeArtFunc typeart_alloc_omp_mty = typeart_alloc_mty; +TypeArtFunc typeart_alloc_stacks_omp_mty = typeart_alloc_stack_mty; + +} // namespace callbacks + +std::unique_ptr declare_instrumentation_functions(llvm::Module& m, + const config::Configuration& configuration) { + using namespace callbacks; + TAFunctions functions; + TAFunctions functions_alternative; + InstrumentationHelper instrumentation_helper; + instrumentation_helper.setModule(m); + TAFunctionDeclarator decl(m, instrumentation_helper, functions); + TAFunctionDeclarator decl_alternatives(m, instrumentation_helper, functions_alternative); + + auto alloc_arg_types = instrumentation_helper.make_parameters(IType::ptr, IType::type_id, IType::extent); + auto free_arg_types = instrumentation_helper.make_parameters(IType::ptr); + auto leavescope_arg_types = instrumentation_helper.make_parameters(IType::stack_count); + + // const TypeSerializationImplementation local_types = configuration[config::ConfigStdArgs::type_serialization]; + auto alloc_arg_types_mty = instrumentation_helper.make_parameters(IType::ptr, IType::ptr, IType::extent); + typeart_alloc_mty.f = decl_alternatives.make_function(IFunc::heap, typeart_alloc_mty.name, alloc_arg_types_mty); + typeart_alloc_stack_mty.f = + decl_alternatives.make_function(IFunc::stack, typeart_alloc_stack_mty.name, alloc_arg_types_mty); + typeart_alloc_global_mty.f = + decl_alternatives.make_function(IFunc::global, typeart_alloc_global_mty.name, alloc_arg_types_mty); + typeart_register_type.f = decl.make_function(IFunc::type, typeart_register_type.name, free_arg_types); + + typeart_alloc.f = decl.make_function(IFunc::heap, typeart_alloc.name, alloc_arg_types); + typeart_alloc_stack.f = decl.make_function(IFunc::stack, typeart_alloc_stack.name, alloc_arg_types); + typeart_alloc_global.f = decl.make_function(IFunc::global, typeart_alloc_global.name, alloc_arg_types); + typeart_free.f = decl.make_function(IFunc::free, typeart_free.name, free_arg_types); + typeart_leave_scope.f = decl.make_function(IFunc::scope, typeart_leave_scope.name, leavescope_arg_types); + + typeart_alloc_omp.f = decl.make_function(IFunc::heap_omp, typeart_alloc_omp.name, alloc_arg_types); + typeart_alloc_stacks_omp.f = decl.make_function(IFunc::stack_omp, typeart_alloc_stacks_omp.name, alloc_arg_types); + typeart_free_omp.f = decl.make_function(IFunc::free_omp, typeart_free_omp.name, free_arg_types); + + typeart_leave_scope_omp.f = decl.make_function(IFunc::scope_omp, typeart_leave_scope_omp.name, leavescope_arg_types); + + typeart_alloc_omp_mty.f = + decl_alternatives.make_function(IFunc::heap_omp, typeart_alloc_omp_mty.name, alloc_arg_types_mty); + typeart_alloc_stacks_omp_mty.f = + decl_alternatives.make_function(IFunc::stack_omp, typeart_alloc_stacks_omp_mty.name, alloc_arg_types_mty); + + return std::make_unique(functions, functions_alternative); +} + } // namespace typeart diff --git a/lib/passes/instrumentation/TypeARTFunctions.h b/lib/passes/instrumentation/TypeARTFunctions.h index d707a933..e0927ae3 100644 --- a/lib/passes/instrumentation/TypeARTFunctions.h +++ b/lib/passes/instrumentation/TypeARTFunctions.h @@ -14,12 +14,10 @@ #define TYPEART_TYPEARTFUNCTIONS_H #include "InstrumentationHelper.h" +#include "configuration/Configuration.h" +#include "instrumentation/TypeIDProvider.h" -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/StringMap.h" -#include "llvm/ADT/StringRef.h" - -#include +#include namespace llvm { class Function; @@ -30,49 +28,23 @@ class Module; namespace typeart { class InstrumentationHelper; -enum class IFunc : unsigned { - heap, - stack, - global, - free, - scope, - heap_omp, - stack_omp, - free_omp, - scope_omp, -}; +namespace config { +class Configuration; +} -class TAFunctionQuery { - public: - virtual llvm::Function* getFunctionFor(IFunc id) = 0; - virtual ~TAFunctionQuery() = default; -}; +enum class IFunc : unsigned { heap, stack, global, free, scope, heap_omp, stack_omp, free_omp, scope_omp, type }; -class TAFunctions : public TAFunctionQuery { - // densemap has problems with IFunc - using FMap = std::unordered_map; - FMap typeart_callbacks; +IFunc ifunc_for_function(IFunc general_type, llvm::Value* value); +class TAFunctionQuery { public: - TAFunctions(); - - llvm::Function* getFunctionFor(IFunc id) override; - void putFunctionFor(IFunc id, llvm::Function* f); + [[nodiscard]] virtual llvm::Function* getFunctionFor( + IFunc id, TypeSerializationImplementation impl = TypeSerializationImplementation::FILE) const = 0; + virtual ~TAFunctionQuery() = default; }; -class TAFunctionDeclarator { - llvm::Module& module; - // [[maybe_unused]] InstrumentationHelper& instr; - TAFunctions& typeart_functions; - llvm::StringMap function_map; - - public: - TAFunctionDeclarator(llvm::Module& m, InstrumentationHelper& instr, TAFunctions& typeart_func); - llvm::Function* make_function(IFunc function, llvm::StringRef basename, llvm::ArrayRef args, - bool with_omp = false, bool fixed_name = true); - const llvm::StringMap& getFunctionMap() const; - virtual ~TAFunctionDeclarator() = default; -}; +std::unique_ptr declare_instrumentation_functions(llvm::Module& m, + const config::Configuration& configuration); } // namespace typeart diff --git a/lib/passes/instrumentation/TypeIDProvider.cpp b/lib/passes/instrumentation/TypeIDProvider.cpp new file mode 100644 index 00000000..fcfb0e26 --- /dev/null +++ b/lib/passes/instrumentation/TypeIDProvider.cpp @@ -0,0 +1,509 @@ +#include "TypeIDProvider.h" + +#include "TypeDB.h" +#include "TypeDatabase.h" +#include "TypeInterface.h" +#include "configuration/Configuration.h" +#include "instrumentation/TypeARTFunctions.h" +#include "support/ConfigurationBase.h" +#include "support/Logger.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace typeart { + +void TypeRegistry::registerModule(const ModuleData&) { +} + +class TypeRegistryNoOp final : public TypeRegistry { + public: + llvm::Value* getOrRegister(llvm::Value* type_id_const) override { + return type_id_const; + } +}; + +namespace helper { + +void replace_whitespace_with_underscore(std::string& s) { + std::replace_if(s.begin(), s.end(), [](unsigned char c) { return std::isspace(c); }, '_'); +} + +inline int get_type_id(llvm::Value* type_id_const) { + auto* constant_int = llvm::dyn_cast(type_id_const); + assert(constant_int && "Expected llvm::ConstantInt"); + if (constant_int == nullptr) { + return TYPEART_UNKNOWN_TYPE; + } + assert(constant_int->getBitWidth() <= 32 && "Type ID is too wide"); + const int type_id = static_cast(constant_int->getSExtValue()); + return type_id; +} + +template +inline std::string concat(Args&&... args) { + const auto str = (std::string{} + ... + std::string{std::forward(args)}); + return str; +} + +template +inline std::string create_prefixed_name(Args&&... args) { + std::string name = concat("_typeart_", std::forward(args)...); + replace_whitespace_with_underscore(name); + return name; +} + +} // namespace helper + +namespace typedb { + +struct GlobalTypeData { + struct TypeData { + llvm::Constant* type_struct; + llvm::GlobalVariable* type; + llvm::Constant* name; + llvm::Constant* offset; + llvm::Constant* count; + }; + llvm::StringMap global_type_data; + + inline bool has_type_name(llvm::StringRef name) const { +#if LLVM_VERSION_MAJOR > 17 + return global_type_data.contains(name); +#else + return global_type_data.find(name) != global_type_data.end(); +#endif + } + + inline const TypeData& get_type(llvm::StringRef name) const { +#if LLVM_VERSION_MAJOR > 17 + return global_type_data.at(name); +#else + return global_type_data.find(name)->second; +#endif + } +}; + +struct GlobalTypeCallback { + llvm::Module* module_; + const TAFunctionQuery* f_query_; + llvm::StringRef ctor_function_name{"__typeart_init_module_type_globals"}; + + private: + bool has_function() const { + auto func = module_->getFunction(ctor_function_name); + return func != nullptr; + } + + llvm::BasicBlock* make_type_callback() const { + using namespace llvm; + const auto makeCtorFuncBody = [&]() -> BasicBlock* { + auto& c = module_->getContext(); + FunctionType* ctorType = FunctionType::get(llvm::Type::getVoidTy(c), false); + Function* ctorFunction = Function::Create(ctorType, Function::PrivateLinkage, ctor_function_name, module_); + BasicBlock* entry = BasicBlock::Create(c, "entry", ctorFunction); + auto* ret_inst = ReturnInst::Create(c); +#if LLVM_VERSION_MAJOR > 17 + ret_inst->insertInto(entry, entry->getFirstInsertionPt()); +#else + entry->getInstList().push_back(ret_inst); +#endif + + llvm::appendToGlobalCtors(*module_, ctorFunction, 0, nullptr); + + return entry; + }; + + auto* func = module_->getFunction(ctor_function_name); + if (func == nullptr) { + return makeCtorFuncBody(); + } + return &func->getEntryBlock(); + } + + llvm::BasicBlock* get_entry() { + auto* func = module_->getFunction(ctor_function_name); + if (func == nullptr) { + return make_type_callback(); + } + return &func->getEntryBlock(); + } + + public: + GlobalTypeCallback(llvm::Module* module, const TAFunctionQuery* f_query) : module_(module), f_query_(f_query) { + } + + void insert(llvm::Constant* global) { + auto* block = get_entry(); + for (auto& inst : *block) { + if (auto* call_base = llvm::dyn_cast(&inst)) { + auto* argument = call_base->getArgOperand(0); + if (global == argument) { + LOG_DEBUG("Skipping, already contained"); + return; + } + } + } + llvm::IRBuilder<> IRB{&*block->getFirstInsertionPt()}; + + IRB.CreateCall(f_query_->getFunctionFor(IFunc::type), llvm::ArrayRef{global}); + } +}; + +enum class IGlobalType : short { + type_id, + name, + extent, + num_members, + member_offsets, + member_types, + member_count, + type_flag, + ptr +}; + +struct TypeHelper { + llvm::IRBuilder<>& ir_build_; + explicit TypeHelper(llvm::IRBuilder<>& ir_build) : ir_build_(ir_build) { + } + + llvm::Type* get_type_for(IGlobalType type, bool as_array = false) { + switch (type) { + case IGlobalType::type_id: + case IGlobalType::extent: + return ir_build_.getInt32Ty(); + case IGlobalType::type_flag: + case IGlobalType::num_members: + return ir_build_.getInt16Ty(); + case IGlobalType::member_offsets: + case IGlobalType::member_types: + case IGlobalType::member_count: { + if (as_array) { + return ir_build_.getInt16Ty(); + } +#if LLVM_VERSION_MAJOR < 15 + return ir_build_.getInt8PtrTy(); +#else + return ir_build_.getPtrTy(); +#endif + } + case IGlobalType::name: + case IGlobalType::ptr: +#if LLVM_VERSION_MAJOR < 15 + return ir_build_.getInt8PtrTy(); +#else + return ir_build_.getPtrTy(); +#endif + } + llvm_unreachable("Should not be reached disk"); + } + + llvm::Constant* get_constant_for(IGlobalType type, size_t value) { + switch (type) { + case IGlobalType::type_id: + case IGlobalType::extent: + return ir_build_.getInt32(value); + case IGlobalType::type_flag: + case IGlobalType::num_members: + case IGlobalType::member_offsets: + case IGlobalType::member_count: + return ir_build_.getInt16(value); + default: + break; + } + return ir_build_.getInt32(value); + } + + llvm::Constant* get_constant_nullptr() { + return llvm::ConstantPointerNull::get(llvm::dyn_cast(get_type_for(IGlobalType::ptr))); + } +}; + +struct GlobalTypeRegistrar { + private: + llvm::Module* module_; + const TypeDatabase* type_db_; + llvm::IRBuilder<> ir_build; + GlobalTypeCallback type_callback; + llvm::StructType* struct_layout_type_; + GlobalTypeData global_types_; + TypeHelper types_helper; + const bool builtin_emit_name{false}; + + void declare_layout() { + auto& context = module_->getContext(); + struct_layout_type_ = llvm::StructType::create(context, "struct._typeart_struct_layout_t"); + struct_layout_type_->setBody({ + types_helper.get_type_for(IGlobalType::type_id), // int type_id + types_helper.get_type_for(IGlobalType::extent), // uint32 extent + types_helper.get_type_for(IGlobalType::num_members), // uint16 num_members + types_helper.get_type_for(IGlobalType::type_flag), // uint16 type_flag + types_helper.get_type_for(IGlobalType::name), // const char* name + types_helper.get_type_for(IGlobalType::member_offsets), // const uint16* offsets + types_helper.get_type_for(IGlobalType::member_count), // const uint16* count + types_helper.get_type_for(IGlobalType::member_types), // const typeart_struct_layout_t** member_types + + }); + } + + llvm::GlobalVariable* create_global( + llvm::StringRef name, llvm::Type* type, llvm::Constant* init = nullptr, + llvm::GlobalVariable::LinkageTypes link_type = llvm::GlobalValue::WeakODRLinkage) const { + // TODO: https://llvm.org/docs/LangRef.html#linkage w.r.t. forward declared types + auto* global_struct = + new llvm::GlobalVariable(*module_, type, true, link_type, init, helper::create_prefixed_name(name)); + return global_struct; + } + + llvm::Constant* make_gep(llvm::Type* type, llvm::GlobalVariable* global) { + auto* i32_zero_const = llvm::ConstantInt::get(ir_build.getInt32Ty(), 0); + return llvm::ConstantExpr::getInBoundsGetElementPtr( + type, global, llvm::ArrayRef{i32_zero_const, i32_zero_const}); + } + + llvm::Constant* create_global_constant_string(llvm::StringRef name) { + // TODO think about linkage + // auto* name_str = ir_build.CreateGlobalStringPtr(name, helper::create_prefixed_name("typename_", name), 0, + // module_); + auto* global_string = + ir_build.CreateGlobalString(name, helper::create_prefixed_name("typename_", name), 0, module_); + global_string->setConstant(true); + global_string->setLinkage(llvm::GlobalValue::WeakODRLinkage); + return make_gep(global_string->getValueType(), global_string); + } + + llvm::Constant* create_global_array_ptr(const llvm::StringRef name, llvm::ArrayRef values) { + if (values.empty()) { + LOG_DEBUG("No values for global array, returning nullptr") + return types_helper.get_constant_nullptr(); + } + + std::vector constants; + constants.reserve(values.size()); + for (uint64_t val : values) { + constants.push_back(types_helper.get_constant_for(IGlobalType::member_offsets, val)); + } + + auto* array_ty = llvm::ArrayType::get(types_helper.get_type_for(IGlobalType::member_offsets, true), values.size()); + auto* constant_array = llvm::ConstantArray::get(array_ty, constants); + auto* gv = create_global(name, array_ty, constant_array); + return make_gep(array_ty, gv); + } + + llvm::GlobalVariable* registerGlobalStruct(const std::string& name, int type_id, uint64_t type_size, + uint64_t member_count, llvm::Constant* offset_ptr, + llvm::Constant* members_data_ptr, llvm::Constant* count_ptr, + StructTypeFlag flag = StructTypeFlag::USER_DEFINED) { + const auto name_struct = flag == StructTypeFlag::FWD_DECL ? helper::concat(name, "_fwd") : name; + + llvm::GlobalVariable* global_struct = create_global(name_struct, struct_layout_type_); + global_struct->setConstant(false); + + // In the current scheme, built-ins do not need to produce a name string (Built) + const bool is_builtin = flag == StructTypeFlag::BUILTIN; + const bool emit_builtin_typename = is_builtin && builtin_emit_name; + llvm::Constant* name_str = (emit_builtin_typename || !is_builtin) ? create_global_constant_string(name) + : types_helper.get_constant_nullptr(); + + std::vector members = { + types_helper.get_constant_for(IGlobalType::type_id, type_id), + types_helper.get_constant_for(IGlobalType::extent, type_size), + types_helper.get_constant_for(IGlobalType::member_count, member_count), + types_helper.get_constant_for(IGlobalType::type_flag, + static_cast(flag)), // TODO: use real type + name_str, // + offset_ptr, // + count_ptr, // + members_data_ptr}; + llvm::Constant* init = llvm::ConstantStruct::get(struct_layout_type_, members); + global_struct->setInitializer(init); + + global_types_.global_type_data.try_emplace( + name, GlobalTypeData::TypeData{init, global_struct, name_str, offset_ptr, count_ptr}); + + return global_struct; + } + + llvm::GlobalVariable* registerTypeStruct(const StructTypeInfo* type_struct) { + const auto name = type_struct->name; + const auto type_size = type_struct->extent; + + if (type_struct->flag == StructTypeFlag::FWD_DECL) { + LOG_DEBUG("Type is forward decl " << name) + // return registerGlobalStructDecl(name); + } + + llvm::Constant* offset_ptr = create_global_array_ptr(helper::concat("offsets_", name), type_struct->offsets); + llvm::Constant* count_ptr = create_global_array_ptr(helper::concat("counts_", name), type_struct->array_sizes); + + llvm::Constant* members_array; + llvm::Type* ptr_type{nullptr}; // TODO: make this unqual? + std::vector member_types{}; + + for (auto member_type_id : type_struct->member_types) { + llvm::Constant* member = getOrRegister(member_type_id); + if (ptr_type == nullptr) { + ptr_type = member->getType(); + } + member_types.emplace_back(member); + } + + const auto member_count = type_struct->member_types.size(); + if (ptr_type != nullptr) { + assert(member_count == type_struct->num_members); + llvm::ArrayType* member_array_ty = llvm::ArrayType::get(ptr_type, member_count); + llvm::Constant* init = llvm::ConstantArray::get(member_array_ty, member_types); + members_array = create_global(helper::concat("member_types_", name), member_array_ty, init); + } else { + llvm::Constant* null_member = types_helper.get_constant_nullptr(); + members_array = null_member; + } + + return registerGlobalStruct(name, type_struct->type_id, type_size, member_count, offset_ptr, members_array, + count_ptr, type_struct->flag); + } + + llvm::GlobalVariable* registerBuiltin(int type_id) { + auto type_name = type_db_->getTypeName(type_id); + helper::replace_whitespace_with_underscore(type_name); + StructTypeInfo type_struct{type_id, type_name, type_db_->getTypeSize(type_id), 1, {}, + {}, {}, StructTypeFlag::BUILTIN}; + return registerTypeStruct(&type_struct); + } + + llvm::GlobalVariable* registerUserDefined(int type_id) { + const auto* const type_struct = type_db_->getStructInfo(type_id); + if (type_struct == nullptr) { + LOG_WARNING("Struct info is nullptr for id " << type_id) + } + return registerTypeStruct(type_struct); + } + + public: + GlobalTypeRegistrar(llvm::Module* m, const TypeDatabase* type_db, const TAFunctionQuery* f_query) + : module_(m), + type_db_(type_db), + ir_build(m->getContext()), + type_callback(module_, f_query), + types_helper(ir_build) { + declare_layout(); + } + + const TypeDatabase& db() const { + return *type_db_; + } + + llvm::Constant* getOrRegister(int type_id) { + const auto name = type_db_->getTypeName(type_id); + LOG_DEBUG(name << " aka " << helper::create_prefixed_name(name)) + return module_->getOrInsertGlobal( + helper::create_prefixed_name(name), struct_layout_type_, [&]() -> llvm::GlobalVariable* { + LOG_DEBUG("Registering << " << type_id << " " << name << " aka " << helper::create_prefixed_name(name)) + const bool is_builtin = type_db_->isBuiltinType(type_id); + if (is_builtin) { + auto* global = registerBuiltin(type_id); + type_callback.insert(global); + return global; + } + auto* global = registerUserDefined(type_id); + const auto fwd_decl = StructTypeFlag::FWD_DECL == type_db_->getStructInfo(type_id)->flag; + if (!fwd_decl) { + LOG_DEBUG("Registering forward declared variable " << *global) + } + type_callback.insert(global); + return global; + }); + } +}; // namespace typedb +} // namespace typedb + +class TypeRegistryGlobals final : public TypeRegistry { + // llvm::Module* module_; + typedb::GlobalTypeRegistrar registrar_; + + public: + TypeRegistryGlobals(llvm::Module& m, const TypeDatabase* type_db, const TAFunctionQuery* f_query) + : registrar_(&m, type_db, f_query) { + } + + void registerModule(const ModuleData& m) override { + for (const auto& type : m.types_list) { + if (builtins::BuiltInQuery::is_builtin_type(type.type_id)) { + continue; + } + if (!registrar_.db().isValid(type.type_id)) { + continue; + } + LOG_DEBUG("Registering type_id " << type.type_id) + /*const auto* type_id =*/registrar_.getOrRegister(type.type_id); + } + } + + llvm::Value* getOrRegister(llvm::Value* type_id_const) override { + return registrar_.getOrRegister(helper::get_type_id(type_id_const)); + } +}; + +class TypeRegistryAlternatives final : public TypeRegistry { + TypeRegistryGlobals globals; + TypeRegistryNoOp noops; + + public: + TypeRegistryAlternatives(llvm::Module& m, const TypeDatabase* type_db, const TAFunctionQuery* f_query) + : globals(m, type_db, f_query) { + } + + void registerModule(const ModuleData& m) override { + globals.registerModule(m); + } + + llvm::Value* getOrRegister(llvm::Value* type_id_const) override { + if (builtins::BuiltInQuery::is_builtin_type(helper::get_type_id(type_id_const))) { + return noops.getOrRegister(type_id_const); + } + return globals.getOrRegister(type_id_const); + } +}; + +std::unique_ptr get_type_id_handler(llvm::Module& m, const TypeDatabase* type_db, + const config::Configuration& configuration, + const TAFunctionQuery* f_query) { + TypeSerializationImplementation impl = configuration[config::ConfigStdArgs::type_serialization]; +#if LLVM_VERSION_MAJOR < 15 + if (impl != typeart::TypeSerializationImplementation::FILE) { + LOG_WARNING("Unsupported type serialization mode for LLVM-" << LLVM_VERSION_MAJOR) + } + // using llvm-14 would require opaque pointer mode for globals + return std::make_unique(); +#else + switch (impl) { + case typeart::TypeSerializationImplementation::FILE: + return std::make_unique(); + case typeart::TypeSerializationImplementation::HYBRID: + return std::make_unique(m, type_db, f_query); + default: + return std::make_unique(m, type_db, f_query); + } +#endif +} + +} // namespace typeart \ No newline at end of file diff --git a/lib/passes/instrumentation/TypeIDProvider.h b/lib/passes/instrumentation/TypeIDProvider.h new file mode 100644 index 00000000..e0467edc --- /dev/null +++ b/lib/passes/instrumentation/TypeIDProvider.h @@ -0,0 +1,39 @@ +#ifndef LIB_PASSES_INSTRUMENTATION_MODULETYPEREGISTRY +#define LIB_PASSES_INSTRUMENTATION_MODULETYPEREGISTRY + +// #include "TypeARTFunctions.h" +// #include "instrumentation/TypeARTFunctions.h" +#include "typegen/TypeGenerator.h" +#include "typelib/TypeDatabase.h" + +#include +#include + +namespace llvm { +class Value; +class Module; +} // namespace llvm + +namespace typeart { + +enum class TypeSerializationImplementation : uint8_t { FILE, INLINE, HYBRID }; + +namespace config { +class Configuration; +} +class TAFunctionQuery; + +class TypeRegistry { + public: + [[nodiscard]] virtual llvm::Value* getOrRegister(llvm::Value* type_id_const) = 0; + virtual void registerModule(const ModuleData&); + virtual ~TypeRegistry() = default; +}; + +std::unique_ptr get_type_id_handler(llvm::Module& m, const TypeDatabase* type_db, + const config::Configuration& configuration, + const TAFunctionQuery* f_query); + +} // namespace typeart + +#endif /* LIB_PASSES_INSTRUMENTATION_MODULETYPEREGISTRY */ diff --git a/lib/passes/typegen/TypeGenerator.cpp b/lib/passes/typegen/TypeGenerator.cpp index 176aa30c..2401bda2 100644 --- a/lib/passes/typegen/TypeGenerator.cpp +++ b/lib/passes/typegen/TypeGenerator.cpp @@ -55,10 +55,11 @@ int TypeIDGenerator::reserveNextTypeId() { } const TypeDatabase& TypeIDGenerator::getTypeDatabase() const { - return *this->typeDB.get(); + return *this->typeDB; } -void TypeIDGenerator::registerModule(const ModuleData&) { +bool TypeIDGenerator::registerModule(ModuleData&) { + return false; } } // namespace typeart::types diff --git a/lib/passes/typegen/TypeGenerator.h b/lib/passes/typegen/TypeGenerator.h index 977c228e..20d1c501 100644 --- a/lib/passes/typegen/TypeGenerator.h +++ b/lib/passes/typegen/TypeGenerator.h @@ -10,8 +10,8 @@ // SPDX-License-Identifier: BSD-3-Clause // -#ifndef TYPEART_TYPEGENERATOR_H -#define TYPEART_TYPEGENERATOR_H +#ifndef LIB_PASSES_TYPEGEN_TYPEGENERATOR +#define LIB_PASSES_TYPEGEN_TYPEGENERATOR #include "analysis/MemOpData.h" #include "typelib/TypeDatabase.h" @@ -25,6 +25,7 @@ #include #include #include +#include namespace llvm { class Type; @@ -40,13 +41,16 @@ struct TypeIdentifier final { std::uint64_t num_elements{1}; // > 1 for array-like type allocation }; +using TypeIdentifierList = std::vector; + struct ModuleData { llvm::Module* module; + TypeIdentifierList types_list{}; }; class TypeGenerator { public: - virtual void registerModule(const ModuleData&) = 0; + virtual bool registerModule(ModuleData&) = 0; [[nodiscard]] virtual TypeIdentifier getOrRegisterType(const MallocData&) = 0; [[nodiscard]] virtual TypeIdentifier getOrRegisterType(const AllocaData&) = 0; [[nodiscard]] virtual TypeIdentifier getOrRegisterType(const GlobalData&) = 0; @@ -64,4 +68,4 @@ std::unique_ptr make_typegen(std::string_view file, TypegenImplem } // namespace typeart -#endif // TYPEART_TYPEGENERATOR_H +#endif /* LIB_PASSES_TYPEGEN_TYPEGENERATOR */ diff --git a/lib/passes/typegen/TypeIDGenerator.h b/lib/passes/typegen/TypeIDGenerator.h index 6d00a726..8e6e271b 100644 --- a/lib/passes/typegen/TypeIDGenerator.h +++ b/lib/passes/typegen/TypeIDGenerator.h @@ -34,7 +34,7 @@ class TypeIDGenerator : public TypeGenerator { public: explicit TypeIDGenerator(std::string file_, std::unique_ptr database_of_types); - virtual void registerModule(const ModuleData&) override; + virtual bool registerModule(ModuleData&) override; [[nodiscard]] virtual const TypeDatabase& getTypeDatabase() const override; diff --git a/lib/passes/typegen/dimeta/DimetaTypeGen.cpp b/lib/passes/typegen/dimeta/DimetaTypeGen.cpp index ac14ecb8..39c57c7a 100644 --- a/lib/passes/typegen/dimeta/DimetaTypeGen.cpp +++ b/lib/passes/typegen/dimeta/DimetaTypeGen.cpp @@ -101,8 +101,10 @@ void remove_pointer_level(const llvm::AllocaInst* alloc, dimeta::LocatedType& va // If the alloca instruction is not a pointer, but the located_type has a pointer-like qualifier, we remove it. // Workaround for inlining issue, see test typemapping/05_milc_inline_metadata.c // TODO Should be removed if dimeta fixes it. - if (!alloc->getAllocatedType()->isPointerTy()) { - LOG_DEBUG("Alloca is not a pointer") + // Further refinement, array-like allocas to pointers stay untouched (second condition): + // this will cause MPI handle arrays (typedef "ptr to opaque struct") to be considered a pointer + if (!alloc->getAllocatedType()->isPointerTy() && !alloc->getAllocatedType()->isArrayTy()) { + LOG_DEBUG("Alloca is not a pointer type: " << *alloc->getAllocatedType()) const auto remove_pointer_level = [](auto& qual) { auto pointer_like_iter = llvm::find_if(qual, [](auto qualifier) { @@ -488,7 +490,7 @@ class DimetaTypeManager final : public TypeIDGenerator { workaround::remove_pointer_level(alloc, val.value()); const auto type_id = getOrRegister(val->type, false); const auto array_size_val = array_size(val->type); - LOG_DEBUG(array_size_val) + LOG_DEBUG("Array size of alloca " << array_size_val) return {type_id, array_size_val}; } } else if (auto* global = llvm::dyn_cast(type)) { @@ -502,19 +504,23 @@ class DimetaTypeManager final : public TypeIDGenerator { return {TYPEART_UNKNOWN_TYPE, 0}; } - void registerModule(const ModuleData& module) override { + bool registerModule(ModuleData& module) override { using namespace dimeta; // std::optional compile_unit_types(const llvm::Module*) LOG_DEBUG("Register module types") auto cu_types_list = dimeta::compile_unit_types(module.module).value_or(dimeta::CompileUnitTypeList{}); + std::vector cu_types; for (const auto& cu : cu_types_list) { const QualifiedTypeList& list = cu.types; for (const auto& cu_type : list) { - getOrRegister(cu_type); + cu_types.emplace_back(TypeIdentifier{getOrRegister(cu_type)}); } } + const bool has_cu_types = !cu_types.empty(); + module.types_list = std::move(cu_types); LOG_DEBUG("Done: Register module types") + return has_cu_types; } TypeIdentifier getOrRegisterType(const MallocData& data) override { diff --git a/lib/runtime/AccessCountPrinter.h b/lib/runtime/AccessCountPrinter.h index 525e84c7..d7cf343b 100644 --- a/lib/runtime/AccessCountPrinter.h +++ b/lib/runtime/AccessCountPrinter.h @@ -17,14 +17,9 @@ #include "support/Logger.h" #include "support/Table.h" -#include -#include #include #include #include -#include -#include -#include #include namespace typeart::softcounter { @@ -55,7 +50,6 @@ void serialize(const Recorder& r, std::ostringstream& buf) { return; } else { // const auto memory_use = memory::estimate(r.getMaxStackAllocs(), r.getMaxHeapAllocs(), r.getGlobalAllocs()); - Table overview_table("Alloc Stats from softcounters"); overview_table.wrap_length_ = true; overview_table.put(Row::make("Total heap", r.getHeapAllocs(), r.getHeapArray())); diff --git a/lib/runtime/AccessCounter.h b/lib/runtime/AccessCounter.h index ba4a6ad6..086c73a6 100644 --- a/lib/runtime/AccessCounter.h +++ b/lib/runtime/AccessCounter.h @@ -14,20 +14,14 @@ #define TYPEART_ACCESSCOUNTER_H #include "RuntimeData.h" -#include "RuntimeInterface.h" #include #include #include -#include -#include #include #include -#include #include -#include #include -#include #include #include #include diff --git a/lib/runtime/AllocMapWrapper.h b/lib/runtime/AllocMapWrapper.h index 6c6fc8ec..2500be6c 100644 --- a/lib/runtime/AllocMapWrapper.h +++ b/lib/runtime/AllocMapWrapper.h @@ -17,6 +17,7 @@ #include #include +#include namespace typeart { namespace mixin { diff --git a/lib/runtime/AllocationTracking.cpp b/lib/runtime/AllocationTracking.cpp index 54735548..c22c2072 100644 --- a/lib/runtime/AllocationTracking.cpp +++ b/lib/runtime/AllocationTracking.cpp @@ -171,8 +171,7 @@ AllocState AllocationTracker::doAlloc(const void* addr, int typeId, size_t count FreeState AllocationTracker::doFreeHeap(const void* addr, const void* retAddr) { if (unlikely(addr == nullptr)) { - LOG_ERROR("Free on nullptr " - << "(" << retAddr << ")"); + LOG_ERROR("Free on nullptr " << "(" << retAddr << ")"); return FreeState::ADDR_SKIPPED | FreeState::NULL_PTR; } @@ -233,56 +232,104 @@ std::optional AllocationTracker::findBaseAlloc(const void* a void __typeart_alloc(const void* addr, int typeId, size_t count) { TYPEART_RUNTIME_GUARD; const void* retAddr = __builtin_return_address(0); - typeart::RuntimeSystem::get().allocTracker.onAlloc(addr, typeId, count, retAddr); + typeart::RuntimeSystem::get().allocation_tracker().onAlloc(addr, typeId, count, retAddr); } void __typeart_alloc_stack(const void* addr, int typeId, size_t count) { TYPEART_RUNTIME_GUARD; const void* retAddr = __builtin_return_address(0); - typeart::RuntimeSystem::get().allocTracker.onAllocStack(addr, typeId, count, retAddr); + typeart::RuntimeSystem::get().allocation_tracker().onAllocStack(addr, typeId, count, retAddr); } void __typeart_alloc_global(const void* addr, int typeId, size_t count) { TYPEART_RUNTIME_GUARD; const void* retAddr = __builtin_return_address(0); - typeart::RuntimeSystem::get().allocTracker.onAllocGlobal(addr, typeId, count, retAddr); + typeart::RuntimeSystem::get().allocation_tracker().onAllocGlobal(addr, typeId, count, retAddr); } void __typeart_free(const void* addr) { TYPEART_RUNTIME_GUARD; const void* retAddr = __builtin_return_address(0); - typeart::RuntimeSystem::get().allocTracker.onFreeHeap(addr, retAddr); + typeart::RuntimeSystem::get().allocation_tracker().onFreeHeap(addr, retAddr); } void __typeart_leave_scope(int alloca_count) { TYPEART_RUNTIME_GUARD; const void* retAddr = __builtin_return_address(0); - typeart::RuntimeSystem::get().allocTracker.onLeaveScope(alloca_count, retAddr); + typeart::RuntimeSystem::get().allocation_tracker().onLeaveScope(alloca_count, retAddr); } void __typeart_alloc_omp(const void* addr, int typeId, size_t count) { TYPEART_RUNTIME_GUARD; const void* retAddr = __builtin_return_address(0); - typeart::RuntimeSystem::get().allocTracker.onAlloc(addr, typeId, count, retAddr); - typeart::RuntimeSystem::get().recorder.incOmpContextHeap(); + auto& rt = typeart::RuntimeSystem::get(); + rt.allocation_tracker().onAlloc(addr, typeId, count, retAddr); + rt.recorder.incOmpContextHeap(); } void __typeart_alloc_stack_omp(const void* addr, int typeId, size_t count) { TYPEART_RUNTIME_GUARD; const void* retAddr = __builtin_return_address(0); - typeart::RuntimeSystem::get().allocTracker.onAllocStack(addr, typeId, count, retAddr); - typeart::RuntimeSystem::get().recorder.incOmpContextStack(); + auto& rt = typeart::RuntimeSystem::get(); + rt.allocation_tracker().onAllocStack(addr, typeId, count, retAddr); + rt.recorder.incOmpContextStack(); } void __typeart_free_omp(const void* addr) { TYPEART_RUNTIME_GUARD; const void* retAddr = __builtin_return_address(0); - typeart::RuntimeSystem::get().allocTracker.onFreeHeap(addr, retAddr); - typeart::RuntimeSystem::get().recorder.incOmpContextFree(); + auto& rt = typeart::RuntimeSystem::get(); + rt.allocation_tracker().onFreeHeap(addr, retAddr); + rt.recorder.incOmpContextFree(); } void __typeart_leave_scope_omp(int alloca_count) { TYPEART_RUNTIME_GUARD; const void* retAddr = __builtin_return_address(0); - typeart::RuntimeSystem::get().allocTracker.onLeaveScope(alloca_count, retAddr); + typeart::RuntimeSystem::get().allocation_tracker().onLeaveScope(alloca_count, retAddr); +} + +void __typeart_alloc_mty(const void* addr, const void* info, size_t count) { + TYPEART_RUNTIME_GUARD; + const void* retAddr = __builtin_return_address(0); + const auto type_id = reinterpret_cast(info)->type_id; + auto& rt = typeart::RuntimeSystem::get(); + assert(type_id == rt.type_translator().get_type_id_for(info) && "Type ID of global and lookup must match"); + rt.allocation_tracker().onAlloc(addr, type_id, count, retAddr); +} + +void __typeart_alloc_stack_mty(const void* addr, const void* info, size_t count) { + TYPEART_RUNTIME_GUARD; + const void* retAddr = __builtin_return_address(0); + const auto type_id = reinterpret_cast(info)->type_id; + auto& rt = typeart::RuntimeSystem::get(); + assert(type_id == rt.type_translator().get_type_id_for(info) && "Type ID of global and lookup must match"); + rt.allocation_tracker().onAllocStack(addr, type_id, count, retAddr); +} + +void __typeart_alloc_global_mty(const void* addr, const void* info, size_t count) { + TYPEART_RUNTIME_GUARD; + const void* retAddr = __builtin_return_address(0); + const auto type_id = reinterpret_cast(info)->type_id; + auto& rt = typeart::RuntimeSystem::get(); + assert(type_id == rt.type_translator().get_type_id_for(info) && "Type ID of global and lookup must match"); + rt.allocation_tracker().onAllocGlobal(addr, type_id, count, retAddr); +} + +void __typeart_alloc_omp_mty(const void* addr, const void* info, size_t count) { + TYPEART_RUNTIME_GUARD; + const void* retAddr = __builtin_return_address(0); + const auto type_id = reinterpret_cast(info)->type_id; + auto& rt = typeart::RuntimeSystem::get(); + assert(type_id == rt.type_translator().get_type_id_for(info) && "Type ID of global and lookup must match"); + rt.allocation_tracker().onAlloc(addr, type_id, count, retAddr); +} + +void __typeart_alloc_stack_omp_mty(const void* addr, const void* info, size_t count) { + TYPEART_RUNTIME_GUARD; + const void* retAddr = __builtin_return_address(0); + const auto type_id = reinterpret_cast(info)->type_id; + auto& rt = typeart::RuntimeSystem::get(); + assert(type_id == rt.type_translator().get_type_id_for(info) && "Type ID of global and lookup must match"); + rt.allocation_tracker().onAllocStack(addr, type_id, count, retAddr); } diff --git a/lib/runtime/CMakeLists.txt b/lib/runtime/CMakeLists.txt index 0e030c5f..5d04cfbb 100644 --- a/lib/runtime/CMakeLists.txt +++ b/lib/runtime/CMakeLists.txt @@ -22,6 +22,7 @@ set(RUNTIME_LIB_SOURCES RuntimeInterface.h TypeResolution.cpp AllocationTracking.cpp + GlobalTypeDefCallbacks.cpp AllocationTracking.h TypeResolution.h Runtime.cpp @@ -48,6 +49,7 @@ target_link_libraries( $<$:MPI::MPI_CXX> $<$:phpmap::phpmap> $<$:absl::btree> + $<$:absl::flat_hash_map> $<$:sf::pointer> $<$>:Threads::Threads> ) diff --git a/lib/runtime/CallbackInterface.h b/lib/runtime/CallbackInterface.h index fa1371c9..6ca76206 100644 --- a/lib/runtime/CallbackInterface.h +++ b/lib/runtime/CallbackInterface.h @@ -36,6 +36,15 @@ void __typeart_alloc_omp(const void* addr, int type_id, size_t count); void __typeart_free_omp(const void* addr); void __typeart_alloc_stack_omp(const void* addr, int type_id, size_t count); void __typeart_leave_scope_omp(int alloca_count); + +// Called for inlined type definitions mode +void __typeart_alloc_mty(const void* addr, const void* info, size_t count); +void __typeart_alloc_global_mty(const void* addr, const void* info, size_t count); +void __typeart_alloc_stack_mty(const void* addr, const void* info, size_t count); +void __typeart_register_type(const void* type); + +void __typeart_alloc_global_mty_omp(const void* addr, const void* info, size_t count); +void __typeart_alloc_stack_mty_omp(const void* addr, const void* info, size_t count); #ifdef __cplusplus } #endif diff --git a/lib/runtime/GlobalTypeDefCallbacks.cpp b/lib/runtime/GlobalTypeDefCallbacks.cpp new file mode 100644 index 00000000..77812f5b --- /dev/null +++ b/lib/runtime/GlobalTypeDefCallbacks.cpp @@ -0,0 +1,116 @@ +#include "GlobalTypeDefCallbacks.h" + +#include "CallbackInterface.h" +#include "Runtime.h" +#include "RuntimeData.h" +#include "TypeInterface.h" +#include "support/Logger.h" +#include "typelib/TypeDatabase.h" + +#include +#include +#include +#include + +namespace typeart { + +#define unlikely(x) __builtin_expect(!!(x), 0) +#define CONCAT_(x, y) x##y +#define CONCAT(x, y) CONCAT_(x, y) +#define GUARDNAME CONCAT(typeart_guard_, __LINE__) +#define TYPEART_RUNTIME_GUARD \ + typeart::RTGuard GUARDNAME; \ + if (!GUARDNAME.shouldTrack()) { \ + return; \ + } + +class GlobalTypeTranslator::Impl { + TypeDatabase& type_db_; + RuntimeT::TypeLookupMapT& translator_map_; + int struct_count{0}; + + public: + explicit Impl(TypeDatabase& db, RuntimeT::TypeLookupMapT& translator_map) + : type_db_(db), translator_map_(translator_map) { + } + + int next_type_id(const GlobalTypeInfo* type) { + // a fwd_decl and the decl must have the same type_id: + { + const auto& struct_list = type_db_.getStructList(); + for (const auto& type_in_db : struct_list) { + if (type_in_db.name == type->name) { + return type_in_db.type_id; + } + } + } + const int id = static_cast(TYPEART_NUM_RESERVED_IDS) + struct_count; + ++struct_count; + return id; + } + + int register_t(const GlobalTypeInfo* type) { // NOLINT(misc-no-recursion) + if (unlikely(type == nullptr)) { + LOG_ERROR("Type descriptor is NULL, is it a weak extern global due to fwd decl?"); + return TYPEART_UNKNOWN_TYPE; + } + + if (auto element = translator_map_.find(type); element != translator_map_.end()) { + return element->second; + } + + const bool built_in = builtins::BuiltInQuery::is_builtin_type(type->type_id); + if (built_in) { + translator_map_.try_emplace(type, type->type_id); + return type->type_id; + } + + StructTypeInfo type_descriptor; + type_descriptor.type_id = next_type_id(type); + type_descriptor.name = type->name; + type_descriptor.extent = type->extent; + type_descriptor.num_members = type->num_members; + type_descriptor.flag = static_cast(type->flag); + + type_descriptor.array_sizes.reserve(type->num_members); + type_descriptor.offsets.reserve(type->num_members); + type_descriptor.member_types.reserve(type->num_members); + for (uint32_t i = 0; i < type->num_members; ++i) { + const auto member_id = register_t(type->member_types[i]); + const auto array_size = type->array_sizes[i]; + const auto offset = type->offsets[i]; + type_descriptor.array_sizes.emplace_back(array_size); + type_descriptor.offsets.emplace_back(offset); + type_descriptor.member_types.emplace_back(member_id); + } + + const bool fwd_decl = type_descriptor.flag == StructTypeFlag::FWD_DECL; + type_db_.registerStruct(type_descriptor, not fwd_decl); + translator_map_.try_emplace(type, type_descriptor.type_id); + + return type_descriptor.type_id; + } +}; + +GlobalTypeTranslator::GlobalTypeTranslator(TypeDatabase& db) : pImpl(std::make_unique(db, translator_map)) { +} + +GlobalTypeTranslator::~GlobalTypeTranslator() = default; + +void GlobalTypeTranslator::register_type(const void* type) { + const auto* info_struct = reinterpret_cast(type); + const auto type_id = pImpl->register_t(info_struct); + LOG_DEBUG("Type id reset: " << info_struct->name << " " << info_struct->type_id << " vs. " << type_id) + const_cast(info_struct)->type_id = type_id; +} + +} // namespace typeart + +void __typeart_register_type(const void* type_ptr) { + TYPEART_RUNTIME_GUARD; + if (unlikely(type_ptr == nullptr)) { + LOG_FATAL("type_ptr is NULL\n"); + return; + } + typeart::RuntimeSystem::get().type_translator().register_type(type_ptr); +} diff --git a/lib/runtime/GlobalTypeDefCallbacks.h b/lib/runtime/GlobalTypeDefCallbacks.h new file mode 100644 index 00000000..b59d93d4 --- /dev/null +++ b/lib/runtime/GlobalTypeDefCallbacks.h @@ -0,0 +1,44 @@ +#ifndef LIB_RUNTIME_GLOBALTYPEDEFCALLBACKS +#define LIB_RUNTIME_GLOBALTYPEDEFCALLBACKS + +#include "RuntimeData.h" +#include "TypeInterface.h" +#include "support/Logger.h" + +namespace typeart { + +class TypeDatabase; + +class GlobalTypeTranslator final { + private: + RuntimeT::TypeLookupMapT translator_map; + class Impl; + std::unique_ptr pImpl; + + public: + explicit GlobalTypeTranslator(TypeDatabase& db); + ~GlobalTypeTranslator(); + + void register_type(const void* type); + + [[nodiscard]] inline const RuntimeT::TypeLookupMapT& get_translator_map() const { + return translator_map; + } + + [[nodiscard]] inline int get_type_id_for(MemAddr addr) const { + if (auto element = translator_map.find(addr); element != translator_map.end()) { + return element->second; + } + LOG_WARNING("Unknown type for address " << addr) + return TYPEART_UNKNOWN_TYPE; + } + + GlobalTypeTranslator(const GlobalTypeTranslator&) = delete; + GlobalTypeTranslator& operator=(const GlobalTypeTranslator&) = delete; + GlobalTypeTranslator(GlobalTypeTranslator&&) noexcept = delete; + GlobalTypeTranslator& operator=(GlobalTypeTranslator&&) noexcept = delete; +}; + +} // namespace typeart + +#endif /* LIB_RUNTIME_GLOBALTYPEDEFCALLBACKS */ diff --git a/lib/runtime/Runtime.cpp b/lib/runtime/Runtime.cpp index 49786879..441f41cc 100644 --- a/lib/runtime/Runtime.cpp +++ b/lib/runtime/Runtime.cpp @@ -19,13 +19,10 @@ #include "TypeInterface.h" #include "support/ConfigurationBase.h" #include "support/Logger.h" -// #include "llvm/Support/raw_ostream.h" #include #include -#include #include -#include #include namespace typeart { @@ -36,7 +33,7 @@ std::string toString(const void* memAddr, int typeId, size_t count, size_t typeS bool heap) { std::string buf; llvm::raw_string_ostream s(buf); - const auto name = typeart::RuntimeSystem::get().typeResolution.db().getTypeName(typeId); + const auto name = typeart::RuntimeSystem::get().database().getTypeName(typeId); if ((typeId == TYPEART_VOID) && heap) { count /= typeSize; } @@ -45,7 +42,7 @@ std::string toString(const void* memAddr, int typeId, size_t count, size_t typeS } std::string toString(const void* memAddr, int typeId, size_t count, const void* calledFrom, bool heap) { - const auto typeSize = typeart::RuntimeSystem::get().typeResolution.db().getTypeSize(typeId); + const auto typeSize = typeart::RuntimeSystem::get().database().getTypeSize(typeId); return toString(memAddr, typeId, count, typeSize, calledFrom, heap); } @@ -64,11 +61,12 @@ inline void printTraceStart() { static constexpr const char* defaultTypeFileName = config::ConfigStdArgValues::types; -RuntimeSystem::RuntimeSystem() : rtScopeInit(), typeResolution(typeDB, recorder), allocTracker(typeDB, recorder) { +RuntimeSystem::RuntimeSystem() + : typeResolution_(typeDB_, recorder), allocTracker_(typeDB_, recorder), type_translator_(typeDB_) { debug::printTraceStart(); auto loadTypes = [this](const std::string& file, std::error_code& ec) -> bool { - auto loaded = io::load(&typeDB, file); + auto loaded = io::load(&typeDB_, file); ec = loaded.getError(); return !static_cast(ec); }; @@ -88,7 +86,7 @@ RuntimeSystem::RuntimeSystem() : rtScopeInit(), typeResolution(typeDB, recorder) if (!loadTypes(type_file, error)) { LOG_FATAL("Failed to load recorded types from " << config::EnvironmentStdArgs::types << "=" << type_file << " .Reason: " << error.message()); - std::exit(EXIT_FAILURE); // TODO: Error handling + // std::exit(EXIT_FAILURE); // TODO: Error handling } } else { if (!loadTypes(defaultTypeFileName, error)) { @@ -102,7 +100,7 @@ RuntimeSystem::RuntimeSystem() : rtScopeInit(), typeResolution(typeDB, recorder) } std::stringstream ss; - const auto& typeList = typeDB.getStructList(); + const auto& typeList = typeDB_.getStructList(); for (const auto& structInfo : typeList) { ss << structInfo.name << ", "; } diff --git a/lib/runtime/Runtime.h b/lib/runtime/Runtime.h index d0e52036..b17aaf43 100644 --- a/lib/runtime/Runtime.h +++ b/lib/runtime/Runtime.h @@ -10,11 +10,12 @@ // SPDX-License-Identifier: BSD-3-Clause // -#ifndef TYPEART_RUNTIME_H -#define TYPEART_RUNTIME_H +#ifndef LIB_RUNTIME_RUNTIME +#define LIB_RUNTIME_RUNTIME #include "AccessCounter.h" #include "AllocationTracking.h" +#include "GlobalTypeDefCallbacks.h" #include "TypeDB.h" #include "TypeResolution.h" @@ -44,7 +45,7 @@ struct RuntimeSystem { rtScope = true; } - void reset() { + void reset() const { // Reset rtScope to old value. rtScope = rtScopeWasSet; } @@ -54,15 +55,43 @@ struct RuntimeSystem { }; RTScopeInitializer rtScopeInit; - TypeDB typeDB{}; + TypeDB typeDB_{}; + TypeResolution typeResolution_; + AllocationTracker allocTracker_; + GlobalTypeTranslator type_translator_; public: Recorder recorder{}; - TypeResolution typeResolution; - AllocationTracker allocTracker; - static thread_local bool rtScope; + const TypeDB& database() const { + return typeDB_; + } + + TypeResolution& get_type_resolution() { + return typeResolution_; + } + + AllocationTracker& allocation_tracker() { + return allocTracker_; + } + + GlobalTypeTranslator& type_translator() { + return type_translator_; + } + + const GlobalTypeTranslator& type_translator() const { + return type_translator_; + } + + const TypeResolution& type_resolution() const { + return typeResolution_; + } + + const AllocationTracker& allocation_tracker() const { + return allocTracker_; + } + static RuntimeSystem& get() { // As opposed to a global variable, a singleton + instantiation during // the first callback/query avoids some problems when @@ -97,4 +126,4 @@ struct RTGuard final { } // namespace typeart -#endif // TYPEART_RUNTIME_H +#endif /* LIB_RUNTIME_RUNTIME */ diff --git a/lib/runtime/RuntimeData.h b/lib/runtime/RuntimeData.h index 998ae803..6253655e 100644 --- a/lib/runtime/RuntimeData.h +++ b/lib/runtime/RuntimeData.h @@ -21,10 +21,12 @@ #ifdef TYPEART_PHMAP #error TypeART-RT: Set ABSL and PHMAP, mutually exclusive. #endif + #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wpedantic" #pragma GCC diagnostic ignored "-Wshadow" #include "absl/container/btree_map.h" +#include "absl/container/flat_hash_map.h" #pragma GCC diagnostic pop #endif @@ -33,10 +35,12 @@ #error TypeART-RT: Set ABSL and PHMAP, mutually exclusive. #endif #include "parallel_hashmap/btree.h" +#include "parallel_hashmap/phmap.h" #endif #if !defined(TYPEART_PHMAP) && !defined(TYPEART_ABSEIL) #include +#include #endif #ifdef USE_SAFEPTR @@ -46,7 +50,14 @@ #include "safe_ptr.h" #endif +#if defined(__has_feature) +#if __has_feature(address_sanitizer) +#define __SANITIZE_ADDRESS__ +#endif +#endif + #include // size_t +#include #include namespace typeart { @@ -59,20 +70,42 @@ struct PointerInfo final { MemAddr debug{nullptr}; }; +struct GlobalTypeInfo { + std::int32_t type_id; + const std::uint32_t extent; + const std::uint16_t num_members; + const std::uint16_t flag; + + const char* name; + const std::uint16_t* offsets; + const std::uint16_t* array_sizes; + const GlobalTypeInfo** member_types; +}; + struct RuntimeT { using Stack = std::vector; static constexpr auto StackReserve{512U}; static constexpr char StackName[] = "std::vector"; #ifdef TYPEART_PHMAP - using PointerMapBaseT = phmap::btree_map; + using PointerMapBaseT = phmap::btree_map; + template + using HashmapT = phmap::flat_hash_map; static constexpr char MapName[] = "phmap::btree_map"; #endif #ifdef TYPEART_ABSEIL - using PointerMapBaseT = absl::btree_map; + using PointerMapBaseT = absl::btree_map; + template +#ifdef __SANITIZE_ADDRESS__ + using HashmapT = std::unordered_map; +#else + using HashmapT = absl::flat_hash_map; +#endif static constexpr char MapName[] = "absl::btree_map"; #endif #if !defined(TYPEART_PHMAP) && !defined(TYPEART_ABSEIL) - using PointerMapBaseT = std::map; + using PointerMapBaseT = std::map; + template + using HashmapT = std::unordered_map; static constexpr char MapName[] = "std::map"; #endif #ifdef USE_SAFEPTR @@ -82,10 +115,11 @@ struct RuntimeT { using PointerMap = PointerMapBaseT; static constexpr bool has_safe_map{false}; #endif - using MapEntry = PointerMapBaseT::value_type; - using MappedType = PointerMapBaseT::mapped_type; - using MapKey = PointerMapBaseT::key_type; - using StackEntry = Stack::value_type; + using MapEntry = PointerMapBaseT::value_type; + using MappedType = PointerMapBaseT::mapped_type; + using MapKey = PointerMapBaseT::key_type; + using StackEntry = Stack::value_type; + using TypeLookupMapT = HashmapT; }; } // namespace typeart diff --git a/lib/runtime/TypeResolution.cpp b/lib/runtime/TypeResolution.cpp index 0047a643..8552d326 100644 --- a/lib/runtime/TypeResolution.cpp +++ b/lib/runtime/TypeResolution.cpp @@ -16,16 +16,14 @@ #include "Runtime.h" #include "RuntimeData.h" #include "RuntimeInterface.h" +#include "TypeDB.h" #include "TypeInterface.h" #include "support/Logger.h" #include "support/System.h" -#include "llvm/Support/raw_ostream.h" - #include #include #include -#include #include #include @@ -274,22 +272,23 @@ TypeResolution::TypeArtStatus TypeResolution::getStructInfo(int type_id, const S return TYPEART_INVALID_ID; } -const TypeDB& TypeResolution::db() const { - return type_database; -} +// const TypeDB& TypeResolution::db() const { +// return type_database; +// } namespace detail { // inline typeart_status query_type(const void* addr, int* type, size_t* count) { // auto alloc = typeart::RuntimeSystem::get().allocTracker.findBaseAlloc(addr); // typeart::RuntimeSystem::get().recorder.incUsedInRequest(addr); // if (alloc) { -// return typeart::RuntimeSystem::get().typeResolution.getTypeInfo(addr, alloc->first, alloc->second, type, count); +// return typeart::RuntimeSystem::get().getTypeResolution().getTypeInfo(addr, alloc->first, alloc->second, type, +// count); // } // return TYPEART_UNKNOWN_ADDRESS; // } inline typeart_status query_type(const void* addr, typeart_type_info& info) { - auto alloc = typeart::RuntimeSystem::get().allocTracker.findBaseAlloc(addr); + auto alloc = typeart::RuntimeSystem::get().allocation_tracker().findBaseAlloc(addr); typeart::RuntimeSystem::get().recorder.incUsedInRequest(addr); if (alloc) { typeart_base_type_info base; @@ -299,8 +298,8 @@ inline typeart_status query_type(const void* addr, typeart_type_info& info) { info.base_type_info = base; info.address = addr; - const auto result = typeart::RuntimeSystem::get().typeResolution.getTypeInfo(addr, alloc->first, alloc->second, - &info.type_id, &info.count); + const auto result = typeart::RuntimeSystem::get().get_type_resolution().getTypeInfo( + addr, alloc->first, alloc->second, &info.type_id, &info.count); typeart::RuntimeSystem::get().recorder.incTypeQuery(base.type_id); return result; @@ -310,7 +309,7 @@ inline typeart_status query_type(const void* addr, typeart_type_info& info) { inline typeart_status query_struct_layout(int type_id, typeart_struct_layout* struct_layout) { const typeart::StructTypeInfo* struct_info; - typeart_status status = typeart::RuntimeSystem::get().typeResolution.getStructInfo(type_id, &struct_info); + typeart_status status = typeart::RuntimeSystem::get().get_type_resolution().getStructInfo(type_id, &struct_info); if (status == TYPEART_OK) { struct_layout->type_id = struct_info->type_id; struct_layout->name = struct_info->name.c_str(); @@ -367,7 +366,7 @@ typeart_status typeart_get_containing_type(typeart_type_info type, typeart_base_ containing_type->count = type.base_type_info.count; containing_type->address = type.base_type_info.address; const typeart::PointerInfo info{type.base_type_info.type_id, type.base_type_info.count}; - const auto result = typeart::RuntimeSystem::get().typeResolution.getContainingTypeInfo( + const auto result = typeart::RuntimeSystem::get().type_resolution().getContainingTypeInfo( type.address, containing_type->address, info, &containing_type->count, byte_offset); return result; @@ -376,7 +375,7 @@ typeart_status typeart_get_containing_type(typeart_type_info type, typeart_base_ typeart_status typeart_get_subtype(const typeart_struct_layout* container_layout, const void* base_addr, size_t offset, typeart_base_type_info* subtype_info, size_t* subtype_byte_offset) { typeart::RTGuard guard; - auto status = typeart::RuntimeSystem::get().typeResolution.getSubTypeInfo( + auto status = typeart::RuntimeSystem::get().get_type_resolution().getSubTypeInfo( base_addr, offset, *container_layout, &subtype_info->type_id, &subtype_info->address, subtype_byte_offset, &subtype_info->count); return status; @@ -389,7 +388,7 @@ typeart_status typeart_resolve_type_id(int type_id, typeart_struct_layout* struc typeart_status typeart_get_return_address(const void* addr, const void** return_addr) { typeart::RTGuard guard; - auto alloc = typeart::RuntimeSystem::get().allocTracker.findBaseAlloc(addr); + auto alloc = typeart::RuntimeSystem::get().allocation_tracker().findBaseAlloc(addr); if (alloc) { *return_addr = alloc.value().second.debug; @@ -463,45 +462,45 @@ typeart_status_t typeart_free_source_location(typeart_source_location* source_lo const char* typeart_get_type_name(int type_id) { typeart::RTGuard guard; - return typeart::RuntimeSystem::get().typeResolution.db().getTypeName(type_id).c_str(); + return typeart::RuntimeSystem::get().database().getTypeName(type_id).c_str(); } bool typeart_is_vector_type(int type_id) { typeart::RTGuard guard; - return typeart::RuntimeSystem::get().typeResolution.db().isVectorType(type_id); + return typeart::RuntimeSystem::get().database().isVectorType(type_id); } bool typeart_is_valid_type(int type_id) { typeart::RTGuard guard; - return typeart::RuntimeSystem::get().typeResolution.db().isValid(type_id); + return typeart::RuntimeSystem::get().database().isValid(type_id); } bool typeart_is_reserved_type(int type_id) { typeart::RTGuard guard; - return typeart::RuntimeSystem::get().typeResolution.db().isReservedType(type_id); + return typeart::RuntimeSystem::get().database().isReservedType(type_id); } bool typeart_is_builtin_type(int type_id) { typeart::RTGuard guard; - return typeart::RuntimeSystem::get().typeResolution.db().isBuiltinType(type_id); + return typeart::RuntimeSystem::get().database().isBuiltinType(type_id); } bool typeart_is_struct_type(int type_id) { typeart::RTGuard guard; - return typeart::RuntimeSystem::get().typeResolution.db().isStructType(type_id); + return typeart::RuntimeSystem::get().database().isStructType(type_id); } bool typeart_is_userdefined_type(int type_id) { typeart::RTGuard guard; - return typeart::RuntimeSystem::get().typeResolution.db().isUserDefinedType(type_id); + return typeart::RuntimeSystem::get().database().isUserDefinedType(type_id); } bool typeart_is_union(int type_id) { typeart::RTGuard guard; - return typeart::RuntimeSystem::get().typeResolution.db().isUnion(type_id); + return typeart::RuntimeSystem::get().database().isUnion(type_id); } size_t typeart_get_type_size(int type_id) { typeart::RTGuard guard; - return typeart::RuntimeSystem::get().typeResolution.db().getTypeSize(type_id); + return typeart::RuntimeSystem::get().database().getTypeSize(type_id); } diff --git a/lib/runtime/TypeResolution.h b/lib/runtime/TypeResolution.h index f47ca4b3..edd8ee9c 100644 --- a/lib/runtime/TypeResolution.h +++ b/lib/runtime/TypeResolution.h @@ -16,14 +16,14 @@ #include "AccessCounter.h" #include "RuntimeData.h" #include "RuntimeInterface.h" -#include "TypeDB.h" -#include "TypeInterface.h" #include -#include namespace typeart { +class TypeDB; +struct StructTypeInfo; + struct PointerInfo; class TypeResolution { @@ -50,7 +50,7 @@ class TypeResolution { TypeArtStatus getStructInfo(int type_id, const StructTypeInfo** structInfo) const; - [[nodiscard]] const TypeDB& db() const; + // [[nodiscard]] const TypeDB& db() const; }; } // namespace typeart diff --git a/lib/support/ConfigurationBaseOptions.h b/lib/support/ConfigurationBaseOptions.h index a8fe1e4d..87b889b0 100644 --- a/lib/support/ConfigurationBaseOptions.h +++ b/lib/support/ConfigurationBaseOptions.h @@ -44,5 +44,7 @@ TYPEART_CONFIG_OPTION(analysis_filter_pointer_alloc, "analysis-filter-pointer-al TYPEART_CONFIG_OPTION(analysis_filter_alloca_non_array, "analysis-filter-non-array-alloca", bool, false, "Filter scalar valued allocas.", "ANALYSIS_FILTER_NON_ARRAY_ALLOCA") TYPEART_CONFIG_OPTION(typegen, "typegen", std::string, "dimeta", "Select type layout generator.", "TYPEGEN") +TYPEART_CONFIG_OPTION(type_serialization, "type-serialization", std::string, "file", + "Serialization mode for type representation.", "TYPE_SERIALIZATION") #undef TYPEART_CONFIG_OPTION diff --git a/lib/typelib/TypeDB.cpp b/lib/typelib/TypeDB.cpp index 056cc963..9f262ed0 100644 --- a/lib/typelib/TypeDB.cpp +++ b/lib/typelib/TypeDB.cpp @@ -85,7 +85,7 @@ std::pair, std::error_code> make_database(std::str using namespace builtins; -const std::string unknown_struck_name{"typeart_unknown_struct"}; +const std::string unknown_struct_name{"typeart_unknown_struct"}; void TypeDB::clear() { struct_info_vec.clear(); @@ -115,9 +115,12 @@ bool TypeDB::isPointerType(int type_id) const { bool TypeDB::isUserDefinedType(int type_id) const { const auto* structInfo = getStructInfo(type_id); - LOG_DEBUG(structInfo->name << " " << static_cast(structInfo->flag) << " " - << (static_cast(structInfo->flag) == static_cast(StructTypeFlag::USER_DEFINED)) - << " " << (static_cast(structInfo->flag) == static_cast(StructTypeFlag::UNION))) + if (structInfo != nullptr) { + LOG_DEBUG(structInfo->name << " " << static_cast(structInfo->flag) << " " + << (static_cast(structInfo->flag) == static_cast(StructTypeFlag::USER_DEFINED)) + << " " + << (static_cast(structInfo->flag) == static_cast(StructTypeFlag::UNION))) + } return (structInfo != nullptr) && (static_cast(structInfo->flag) == static_cast(StructTypeFlag::USER_DEFINED) || static_cast(structInfo->flag) == static_cast(StructTypeFlag::UNION)); @@ -133,8 +136,10 @@ bool TypeDB::isVectorType(int type_id) const { bool TypeDB::isUnion(int type_id) const { const auto* structInfo = getStructInfo(type_id); - LOG_DEBUG(structInfo->name << " " << static_cast(structInfo->flag) << " " - << (static_cast(structInfo->flag) == static_cast(StructTypeFlag::UNION))) + if (structInfo != nullptr) { + LOG_DEBUG(structInfo->name << " " << static_cast(structInfo->flag) << " " + << (static_cast(structInfo->flag) == static_cast(StructTypeFlag::UNION))) + } return (structInfo != nullptr) && (static_cast(structInfo->flag) == static_cast(StructTypeFlag::UNION)); } @@ -155,7 +160,7 @@ void TypeDB::registerStruct(const StructTypeInfo& struct_type, bool overwrite) { LOG_ERROR("Type ID is reserved for unknown types. Struct: " << struct_type.name); } else { if (!overwrite) { - LOG_ERROR("Struct type ID already registered for " << struct_type.name << ". Conflicting struct is " + LOG_DEBUG("Struct type ID already registered for " << struct_type.name << ". Conflicting struct is " << getStructInfo(struct_type.type_id)->name); return; } @@ -181,7 +186,7 @@ const std::string& TypeDB::getTypeName(int type_id) const { } } - return unknown_struck_name; + return unknown_struct_name; } size_t TypeDB::getTypeSize(int type_id) const { diff --git a/lib/typelib/TypeDatabase.h b/lib/typelib/TypeDatabase.h index b32b521b..07678ffe 100644 --- a/lib/typelib/TypeDatabase.h +++ b/lib/typelib/TypeDatabase.h @@ -22,7 +22,7 @@ namespace typeart { -enum class StructTypeFlag : int { USER_DEFINED = 1, LLVM_VECTOR = 2, FWD_DECL = 4, UNION = 8 }; +enum class StructTypeFlag : int { USER_DEFINED = 1, LLVM_VECTOR = 2, FWD_DECL = 4, UNION = 8, BUILTIN = 16 }; struct StructTypeInfo { int type_id; diff --git a/scripts/opt-shim.in b/scripts/opt-shim.in index c3dc9af0..bd1659ef 100644 --- a/scripts/opt-shim.in +++ b/scripts/opt-shim.in @@ -67,6 +67,14 @@ function typeart_test_parse_cmd_line_fn() { export TYPEART_ANALYSIS_FILTER_POINTER_ALLOCA="${1#--typeart-analysis-filter-pointer-alloca=}" shift ;; + --typeart-type-serialization=*) + export TYPEART_TYPE_SERIALIZATION="${1#--typeart-type-serialization=}" + shift + ;; + --typeart-config=*) + export TYPEART_CONFIG_FILE="${1#--typeart-config=}" + shift + ;; *) typeart_test_pass_wrapper_more_args+=" $1" shift 1 diff --git a/scripts/typeart-wrapperv2.in b/scripts/typeart-wrapperv2.in index ef0557c8..cefc4091 100644 --- a/scripts/typeart-wrapperv2.in +++ b/scripts/typeart-wrapperv2.in @@ -98,7 +98,9 @@ function typeart_main_driver_fn() { if [ "$?" == 1 ]; then typeart_more_flags+=" ${typeart_ldflags}" fi - + + # export TYPEART_TYPE_SERIALIZATION="${TYPEART_TYPE_SERIALIZATION:-hybrid}" + $typeart_compiler ${typeart_plugin} ${typeart_includes} ${typeart_more_flags} ${typeart_san_flags} $@ } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index c6ed9114..ab79a884 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -145,6 +145,7 @@ set(TYPEART_SUITES runtime script typemapping + runtime_inlined_types staging ) diff --git a/test/lit.cfg b/test/lit.cfg index d7cde5df..b199110f 100644 --- a/test/lit.cfg +++ b/test/lit.cfg @@ -43,6 +43,7 @@ if config.asan: config.available_features.add('asan') if config.ubsan: config.available_features.add('ubsan') + # config.environment['UBSAN_OPTIONS'] = 'silence_unsigned_overflow=1' if config.tsan: config.available_features.add('tsan') if config.tsan or config.asan or config.ubsan: diff --git a/test/pass/arrays/05_vector.c b/test/pass/arrays/05_vector.c index a688988b..6a4f42b4 100644 --- a/test/pass/arrays/05_vector.c +++ b/test/pass/arrays/05_vector.c @@ -1,5 +1,5 @@ // clang-format off -// RUN: %remove %tu_yaml && %c-to-llvm %s | %apply-typeart --typeart-stack=true -S 2>&1 | %filecheck %s +// RUN: %remove %tu_yaml && %c-to-llvm %s | %apply-typeart --typeart-type-serialization=file --typeart-stack=true -S 2>&1 | %filecheck %s // clang-format on typedef float float2 __attribute__((ext_vector_type(2))); diff --git a/test/pass/arrays/07_avx.c b/test/pass/arrays/07_avx.c index 600ebed3..b9f26ec1 100644 --- a/test/pass/arrays/07_avx.c +++ b/test/pass/arrays/07_avx.c @@ -1,5 +1,5 @@ // clang-format off -// RUN: %remove %tu_yaml && %c-to-llvm -mavx %s | %opt -O2 -S | %apply-typeart --typeart-stack=true -S 2>&1 | %filecheck %s +// RUN: %remove %tu_yaml && %c-to-llvm -mavx %s | %opt -O2 -S | %apply-typeart --typeart-type-serialization=file --typeart-stack=true -S 2>&1 | %filecheck %s // clang-format on #include diff --git a/test/pass/filter/08_amg_box_algebra_mock.c b/test/pass/filter/08_amg_box_algebra_mock.c index 2519c118..ef4e1992 100644 --- a/test/pass/filter/08_amg_box_algebra_mock.c +++ b/test/pass/filter/08_amg_box_algebra_mock.c @@ -150,7 +150,7 @@ int hypre_MinUnionBoxes(hypre_BoxArray* boxes) { break; } /*switch(i) */ - } /* for (i= 0; i< 5; i++) */ + } /* for (i= 0; i< 5; i++) */ hypre_TFree(rotated_box); hypre_UnionBoxes(boxes); @@ -233,7 +233,7 @@ int hypre_MinUnionBoxes(hypre_BoxArray* boxes) { break; } /* switch(array) */ - } /* if (array != 5) */ + } /* if (array != 5) */ hypre_BoxArrayArrayDestroy(rotated_array); diff --git a/test/pass/filter/09_milc_gauge_stuff_mock.c b/test/pass/filter/09_milc_gauge_stuff_mock.c index 3b3a747f..ff743da0 100644 --- a/test/pass/filter/09_milc_gauge_stuff_mock.c +++ b/test/pass/filter/09_milc_gauge_stuff_mock.c @@ -127,9 +127,9 @@ void make_loop_table() { loop_num[iloop] = count; } /* end reflection*/ - } /* end permutation if block */ - } /* end permutation */ - } /* end iloop */ + } /* end permutation if block */ + } /* end permutation */ + } /* end iloop */ /* print out the loop coefficients */ printf("loop coefficients: nloop rep loop_coeff multiplicity\n"); diff --git a/test/pass/inline_types/01_simple_malloc_int.c b/test/pass/inline_types/01_simple_malloc_int.c new file mode 100644 index 00000000..69c16ab5 --- /dev/null +++ b/test/pass/inline_types/01_simple_malloc_int.c @@ -0,0 +1,30 @@ +// clang-format off +// RUN: %c-to-llvm %s | %apply-typeart -typeart-type-serialization=inline -S 2>&1 | %filecheck %s + +// RUN: %c-to-llvm %s | %apply-typeart -typeart-type-serialization=hybrid -S 2>&1 | %filecheck %s --check-prefix HYBRID + +// RUN: %c-to-llvm %s | %apply-typeart -typeart-type-serialization=file -S 2>&1 | %filecheck %s --check-prefix FILE + +// REQUIRES: llvm-18 || llvm-19 +// clang-format on + +#include +void test() { + int* p = (int*)malloc(42 * sizeof(int)); +} +// CHECK: TypeArtPass [Heap] +// CHECK-NEXT: Malloc{{[ ]*}}:{{[ ]*}}1 +// CHECK-NEXT: Free{{[ ]*}}:{{[ ]*}}0 +// CHECK-NEXT: Alloca{{[ ]*}}:{{[ ]*}}0 + +// CHECK: %struct._typeart_struct_layout_t = type { i32, i32, i16, i16, ptr, ptr, ptr, ptr } +// CHECK: [[POINTER:%[0-9a-z]+]] = call noalias{{( align [0-9]+)?}} ptr @malloc +// CHECK-NEXT: call void @__typeart_alloc_mty(ptr [[POINTER]], ptr {{.*}}, i64 42) + +// HYBRID-NOT: %struct._typeart_struct_layout_t = type { +// HYBRID: [[POINTER:%[0-9a-z]+]] = call noalias{{( align [0-9]+)?}} ptr @malloc +// HYBRID-NEXT: call void @__typeart_alloc(ptr [[POINTER]], i32 13, i64 42) + +// FILE-NOT: %struct._typeart_struct_layout_t = type { +// FILE: [[POINTER:%[0-9a-z]+]] = call noalias{{( align [0-9]+)?}} ptr @malloc +// FILE-NEXT: call void @__typeart_alloc(ptr [[POINTER]], i32 13, i64 42) diff --git a/test/pass/inline_types/02_calloc_realloc.c b/test/pass/inline_types/02_calloc_realloc.c new file mode 100644 index 00000000..6c568d70 --- /dev/null +++ b/test/pass/inline_types/02_calloc_realloc.c @@ -0,0 +1,31 @@ +// clang-format off +// RUN: %c-to-llvm %s | %apply-typeart -typeart-type-serialization=inline -S 2>&1 | %filecheck %s --check-prefix=REALLOC +// RUN: %c-to-llvm %s | %apply-typeart -typeart-type-serialization=inline -S 2>&1 | %filecheck %s + +// REQUIRES: llvm-18 || llvm-19 +// clang-format on +#include + +int main() { + double* pd = calloc(10, sizeof(double)); + + pd = realloc(pd, 20 * sizeof(double)); + + return 0; +} + +// clang-format off + +// CHECK: TypeArtPass [Heap] +// CHECK-NEXT: Malloc{{[ ]*}}:{{[ ]*}}2 +// CHECK-NEXT: Free{{[ ]*}}:{{[ ]*}}0 +// CHECK-NEXT: Alloca{{[ ]*}}:{{[ ]*}}0 + +// CHECK: [[POINTER:%[0-9a-z]+]] = call noalias{{( align [0-9]+)?}} ptr @calloc(i64{{( noundef)?}} [[SIZE:[0-9]+]], i64{{( noundef)?}} 8) +// CHECK-NEXT: call void @__typeart_alloc_mty(ptr [[POINTER]], ptr {{.*}}, i64 [[SIZE]]) + +// REALLOC: __typeart_free(ptr [[POINTER:%[0-9a-z]+]]) +// REALLOC-NEXT: [[POINTER2:%[0-9a-z]+]] = call{{( align [0-9]+)?}} ptr @realloc(ptr{{( noundef)?}} [[POINTER]], i64{{( noundef)?}} 160) +// REALLOC-NEXT: __typeart_alloc_mty(ptr [[POINTER2]], ptr {{.*}}, i64 20) + +// clang-format on diff --git a/test/pass/inline_types/03_simple_malloc_struct.c b/test/pass/inline_types/03_simple_malloc_struct.c new file mode 100644 index 00000000..9cec9b30 --- /dev/null +++ b/test/pass/inline_types/03_simple_malloc_struct.c @@ -0,0 +1,39 @@ +// clang-format off +// RUN: %c-to-llvm %s | %apply-typeart -typeart-type-serialization=inline -S 2>&1 | %filecheck %s + +// RUN: %c-to-llvm %s | %apply-typeart -typeart-type-serialization=hybrid -S 2>&1 | %filecheck %s --check-prefix HYBRID + +// RUN: %c-to-llvm %s | %apply-typeart -typeart-type-serialization=file -S 2>&1 | %filecheck %s --check-prefix FILE + +// REQUIRES: llvm-18 || llvm-19 +// clang-format on +#include +typedef struct ms { + int a; + double b; +} mystruct; + +void test() { + mystruct* m = (mystruct*)malloc(sizeof(mystruct)); + free(m); +} +// CHECK: TypeArtPass [Heap] +// CHECK-NEXT: Malloc{{[ ]*}}:{{[ ]*}}1 +// CHECK-NEXT: Free{{[ ]*}}:{{[ ]*}}1 +// CHECK-NEXT: Alloca{{[ ]*}}:{{[ ]*}}0 + +// CHECK: [[POINTER:%[0-9a-z]+]] = call noalias{{( align [0-9]+)?}} ptr @malloc +// CHECK-NEXT: call void @__typeart_alloc_mty(ptr [[POINTER]], ptr {{.*}}, i64 1) + +// CHECK: call void @free(ptr{{( noundef)?}} [[POINTER:%[0-9a-z]+]]) +// CHECK-NEXT: call void @__typeart_free(ptr [[POINTER]]) + +// HYBRID: [[POINTER:%[0-9a-z]+]] = call noalias{{( align [0-9]+)?}} ptr @malloc +// HYBRID-NOT: call void @__typeart_alloc(ptr [[POINTER]] +// HYBRID: call void @free(ptr{{( noundef)?}} [[POINTER:%[0-9a-z]+]]) +// HYBRID-NEXT: call void @__typeart_free(ptr [[POINTER]]) + +// FILE: [[POINTER:%[0-9a-z]+]] = call noalias{{( align [0-9]+)?}} ptr @malloc +// FILE: call void @__typeart_alloc(ptr [[POINTER]], i32 +// FILE: call void @free(ptr{{( noundef)?}} [[POINTER:%[0-9a-z]+]]) +// FILE-NEXT: call void @__typeart_free(ptr [[POINTER]]) diff --git a/test/pass/inline_types/04_fwd_decl.cpp b/test/pass/inline_types/04_fwd_decl.cpp new file mode 100644 index 00000000..01ad31c8 --- /dev/null +++ b/test/pass/inline_types/04_fwd_decl.cpp @@ -0,0 +1,30 @@ +// RUN: %cpp-to-llvm %s | %apply-typeart -typeart-type-serialization=inline -S | %filecheck %s + +// CHECK: @_typeart__ZTS6Domain_fwd = weak_odr global %struct._typeart_struct_layout_t { i32 256, + +// REQUIRES: llvm-18 || llvm-19 + +class Domain { + public: + Domain(int ranks, double other); + + int getRanks() const { + return m_ranks; + } + + double getOther() const { + return m_other; + } + + private: + int m_ranks; + double m_other; +}; + +int main(int argc, char* argv[]) { + Domain* dom; + + dom = new Domain(argc, 1.2); + + return dom->getRanks(); +} diff --git a/test/pass/malloc_free/05_simple_malloc_struct.c b/test/pass/malloc_free/05_simple_malloc_struct.c index d33405d6..9b2f33ab 100644 --- a/test/pass/malloc_free/05_simple_malloc_struct.c +++ b/test/pass/malloc_free/05_simple_malloc_struct.c @@ -1,5 +1,5 @@ // clang-format off -// RUN: %remove %tu_yaml && %c-to-llvm %s | %apply-typeart -S 2>&1 | %filecheck %s +// RUN: %remove %tu_yaml && %c-to-llvm %s | %apply-typeart --typeart-type-serialization=file -S 2>&1 | %filecheck %s // clang-format on #include typedef struct ms { diff --git a/test/pass/misc/05_make_all_callbacks.c b/test/pass/misc/05_make_all_callbacks.c index 0316c9fd..b4201d01 100644 --- a/test/pass/misc/05_make_all_callbacks.c +++ b/test/pass/misc/05_make_all_callbacks.c @@ -3,10 +3,13 @@ #include "../../../lib/runtime/CallbackInterface.h" int main(void) { - int count = 0; - int type_id = 10; - size_t extent = 0; - void* addr = NULL; + int count = 0; + int type_id = 10; + size_t extent = 0; + void* addr = NULL; + const void* info_ptr = NULL; + const void* type_ptr = NULL; + __typeart_alloc(addr, type_id, extent); __typeart_alloc_global(addr, type_id, extent); __typeart_alloc_stack(addr, type_id, extent); @@ -18,6 +21,14 @@ int main(void) { __typeart_alloc_stack_omp(addr, type_id, extent); __typeart_free_omp(addr); __typeart_leave_scope_omp(count); + + __typeart_alloc_mty(addr, info_ptr, count); + __typeart_alloc_global_mty(addr, info_ptr, count); + __typeart_alloc_stack_mty(addr, info_ptr, count); + __typeart_register_type(type_ptr); + __typeart_alloc_global_mty_omp(addr, info_ptr, count); + __typeart_alloc_stack_mty_omp(addr, info_ptr, count); + return 0; } diff --git a/test/pass/misc/07_config_file.c b/test/pass/misc/07_config_file.c index 1e9a48ad..b2386ebf 100644 --- a/test/pass/misc/07_config_file.c +++ b/test/pass/misc/07_config_file.c @@ -1,20 +1,19 @@ // RUN: %c-to-llvm %s | %apply-typeart --typeart-config=%S/07_typeart_config_stack.yml 2>&1 | %filecheck %s // REQUIRES: llvm-14 -// XFAIL: * - #include void test() { int* p = (int*)malloc(42 * sizeof(int)); } -// CHECK: types: {{.*}} +// CHECK: types: 07_config_file.c.yaml // CHECK-NEXT: heap: false // CHECK-NEXT: stack: true // CHECK-NEXT: global: false // CHECK-NEXT: stats: {{.*}} // CHECK-NEXT: stack-lifetime: false // CHECK-NEXT: typegen: {{dimeta|ir}} +// CHECK-NEXT: type-serialization: inline // CHECK-NEXT: filter: false // CHECK-NEXT: call-filter: // CHECK-NEXT: implementation: std diff --git a/test/pass/misc/07_typeart_config_stack.yml b/test/pass/misc/07_typeart_config_stack.yml index 06534720..2a3e2526 100644 --- a/test/pass/misc/07_typeart_config_stack.yml +++ b/test/pass/misc/07_typeart_config_stack.yml @@ -3,8 +3,10 @@ types: "types_config.yaml" heap: false stack: true global: false +stats: true stack-lifetime: false typegen: "dimeta" +type-serialization: inline filter: false call-filter: implementation: "std" diff --git a/test/pass/misc/08_config_file_default.c b/test/pass/misc/08_config_file_default.c index f5bcf213..6e908b29 100644 --- a/test/pass/misc/08_config_file_default.c +++ b/test/pass/misc/08_config_file_default.c @@ -1,5 +1,7 @@ // RUN: %c-to-llvm %s | %apply-typeart -S 2>&1 | %filecheck %s +// REQUIRES: !llvm-14 + // CHECK-NOT: {{(Error|Fatal)}} // CHECK: types: {{.*}}.yaml @@ -9,6 +11,7 @@ // CHECK-NEXT: stats: true // CHECK-NEXT: stack-lifetime: true // CHECK-NEXT: typegen: {{dimeta|ir}} +// CHECK-NEXT: type-serialization: hybrid // CHECK-NEXT: filter: false // CHECK-NEXT: call-filter: // CHECK-NEXT: implementation: std diff --git a/test/pass/misc/09_config_file_cl.c b/test/pass/misc/09_config_file_cl.c index f27503e4..21b7fa14 100644 --- a/test/pass/misc/09_config_file_cl.c +++ b/test/pass/misc/09_config_file_cl.c @@ -7,8 +7,6 @@ // Priority control with command line args vs. config file contents. -// XFAIL: * - #include void test() { int x = 0; diff --git a/test/pass/new_delete/03_inv_struct.cpp b/test/pass/new_delete/03_inv_struct.cpp index 09986c9b..ce7354f7 100644 --- a/test/pass/new_delete/03_inv_struct.cpp +++ b/test/pass/new_delete/03_inv_struct.cpp @@ -1,5 +1,5 @@ // clang-format off -// RUN: %cpp-to-llvm %s | %apply-typeart -S 2>&1 | %filecheck %s +// RUN: %cpp-to-llvm %s | %apply-typeart --typeart-type-serialization=file -S 2>&1 | %filecheck %s // clang-format on // CHECK: TypeArtPass [Heap] diff --git a/test/pass/new_delete/04_inv_struct_array.cpp b/test/pass/new_delete/04_inv_struct_array.cpp index da17ee42..a96e625c 100644 --- a/test/pass/new_delete/04_inv_struct_array.cpp +++ b/test/pass/new_delete/04_inv_struct_array.cpp @@ -1,5 +1,5 @@ // clang-format off -// RUN: %cpp-to-llvm %s | %apply-typeart -S 2>&1 | %filecheck %s +// RUN: %cpp-to-llvm %s | %apply-typeart --typeart-type-serialization=file -S 2>&1 | %filecheck %s // clang-format on // CHECK: TypeArtPass [Heap] diff --git a/test/pass/new_delete/05_struct_array.cpp b/test/pass/new_delete/05_struct_array.cpp index 7d6b7b3f..ecc2b8b0 100644 --- a/test/pass/new_delete/05_struct_array.cpp +++ b/test/pass/new_delete/05_struct_array.cpp @@ -1,5 +1,5 @@ // clang-format off -// RUN: %cpp-to-llvm %s | %apply-typeart -S 2>&1 | %filecheck %s +// RUN: %cpp-to-llvm %s | %apply-typeart --typeart-type-serialization=file -S 2>&1 | %filecheck %s // clang-format on // CHECK: TypeArtPass [Heap] diff --git a/test/pass/new_delete/06_struct_array_def_dest.cpp b/test/pass/new_delete/06_struct_array_def_dest.cpp index dca95502..707ae822 100644 --- a/test/pass/new_delete/06_struct_array_def_dest.cpp +++ b/test/pass/new_delete/06_struct_array_def_dest.cpp @@ -1,5 +1,5 @@ // clang-format off -// RUN: %cpp-to-llvm %s | %apply-typeart -S 2>&1 | %filecheck %s +// RUN: %cpp-to-llvm %s | %apply-typeart --typeart-type-serialization=file -S 2>&1 | %filecheck %s // clang-format on // CHECK: TypeArtPass [Heap] diff --git a/test/pass/new_delete/07_struct_array_userdef_dest.cpp b/test/pass/new_delete/07_struct_array_userdef_dest.cpp index fa6f3961..68ea898a 100644 --- a/test/pass/new_delete/07_struct_array_userdef_dest.cpp +++ b/test/pass/new_delete/07_struct_array_userdef_dest.cpp @@ -1,12 +1,12 @@ // clang-format off -// RUN: %cpp-to-llvm %s | %apply-typeart -S 2>&1 | %filecheck %s +// RUN: %cpp-to-llvm %s | %apply-typeart --typeart-type-serialization=file -S 2>&1 | %filecheck %s // Wrong size is calculated due to using Znam call, instead of bitcast to struct.S1* // REQUIRES: dimeta // clang-format on struct S1 { int x; - ~S1(){}; + ~S1() {}; }; // CHECK: call{{.*}} {{i8\*|ptr}} @_Znam(i64{{( noundef)?}} 16) diff --git a/test/pass/new_delete/09_inv_struct_delete.cpp b/test/pass/new_delete/09_inv_struct_delete.cpp index 0e27e635..a1d0eeab 100644 --- a/test/pass/new_delete/09_inv_struct_delete.cpp +++ b/test/pass/new_delete/09_inv_struct_delete.cpp @@ -1,5 +1,5 @@ // clang-format off -// RUN: %cpp-to-llvm %s | %apply-typeart -S 2>&1 | %filecheck %s +// RUN: %cpp-to-llvm %s | %apply-typeart --typeart-type-serialization=file -S 2>&1 | %filecheck %s // clang-format on // CHECK: TypeArtPass [Heap] diff --git a/test/pass/new_delete/10_inv_struct_array_delete.cpp b/test/pass/new_delete/10_inv_struct_array_delete.cpp index 4ebd4309..a4c84555 100644 --- a/test/pass/new_delete/10_inv_struct_array_delete.cpp +++ b/test/pass/new_delete/10_inv_struct_array_delete.cpp @@ -1,5 +1,5 @@ // clang-format off -// RUN: %cpp-to-llvm %s | %apply-typeart -S 2>&1 | %filecheck %s +// RUN: %cpp-to-llvm %s | %apply-typeart --typeart-type-serialization=file -S 2>&1 | %filecheck %s // clang-format on // CHECK: TypeArtPass [Heap] diff --git a/test/pass/new_delete/11_new_nothrow.cpp b/test/pass/new_delete/11_new_nothrow.cpp index 3af6ca0a..f3e6662a 100644 --- a/test/pass/new_delete/11_new_nothrow.cpp +++ b/test/pass/new_delete/11_new_nothrow.cpp @@ -1,5 +1,5 @@ // clang-format off -// RUN: %cpp-to-llvm %s | %apply-typeart -S 2>&1 | %filecheck %s +// RUN: %cpp-to-llvm %s | %apply-typeart --typeart-type-serialization=file -S 2>&1 | %filecheck %s // clang-format on #include diff --git a/test/pass/new_delete/12_new_aligned.cpp b/test/pass/new_delete/12_new_aligned.cpp index 62a7ec57..ea5e6fd5 100644 --- a/test/pass/new_delete/12_new_aligned.cpp +++ b/test/pass/new_delete/12_new_aligned.cpp @@ -1,5 +1,5 @@ // clang-format off -// RUN: %cpp-to-llvm %s | %apply-typeart -S 2>&1 | %filecheck %s +// RUN: %cpp-to-llvm %s | %apply-typeart --typeart-type-serialization=file -S 2>&1 | %filecheck %s // clang-format on #define __cpp_aligned_new 1 diff --git a/test/pass/new_delete/13_new_aligned_nothrow.cpp b/test/pass/new_delete/13_new_aligned_nothrow.cpp index ff785cf4..c552a975 100644 --- a/test/pass/new_delete/13_new_aligned_nothrow.cpp +++ b/test/pass/new_delete/13_new_aligned_nothrow.cpp @@ -1,5 +1,5 @@ // clang-format off -// RUN: %cpp-to-llvm %s | %apply-typeart -S 2>&1 | %filecheck %s +// RUN: %cpp-to-llvm %s | %apply-typeart --typeart-type-serialization=file -S 2>&1 | %filecheck %s // clang-format on #ifndef __cpp_aligned_new diff --git a/test/pass/new_delete/15_array_cookie.cpp b/test/pass/new_delete/15_array_cookie.cpp index d1ec95fb..6d326b7c 100644 --- a/test/pass/new_delete/15_array_cookie.cpp +++ b/test/pass/new_delete/15_array_cookie.cpp @@ -1,5 +1,5 @@ // clang-format off -// RUN: %cpp-to-llvm %s | %apply-typeart -S 2>&1 | %filecheck %s +// RUN: %cpp-to-llvm %s | %apply-typeart --typeart-type-serialization=file -S 2>&1 | %filecheck %s // clang-format on @@ -10,7 +10,7 @@ struct S1 { int x; - ~S1(){}; + ~S1() {}; }; // CHECK: [[MEM:%[0-9a-z]+]] = call{{.*}} {{i8\*|ptr}} @_Znam(i64{{( noundef)?}} 16) diff --git a/test/pass/new_delete/16_array_cookie_padded.cpp b/test/pass/new_delete/16_array_cookie_padded.cpp index ab9452f7..84921c67 100644 --- a/test/pass/new_delete/16_array_cookie_padded.cpp +++ b/test/pass/new_delete/16_array_cookie_padded.cpp @@ -1,5 +1,5 @@ // clang-format off -// RUN: %cpp-to-llvm %s | %apply-typeart -S 2>&1 | %filecheck %s +// RUN: %cpp-to-llvm %s | %apply-typeart --typeart-type-serialization=file -S 2>&1 | %filecheck %s // clang-format on // CHECK: TypeArtPass [Heap] @@ -9,7 +9,7 @@ struct alignas(16) S1 { int x; - ~S1(){}; + ~S1() {}; }; // CHECK: [[MEM:%[0-9a-z]+]] = call{{.*}} {{i8\*|ptr}} @_Znam(i64{{( noundef)?}} 48) diff --git a/test/pass/new_delete/17_array_cookie_dynamic_size.cpp b/test/pass/new_delete/17_array_cookie_dynamic_size.cpp index 4669cdfc..fc926355 100644 --- a/test/pass/new_delete/17_array_cookie_dynamic_size.cpp +++ b/test/pass/new_delete/17_array_cookie_dynamic_size.cpp @@ -10,7 +10,7 @@ struct S1 { int x; - ~S1(){}; + ~S1() {}; }; // CHECK: [[MEM:%[0-9a-z]+]] = call{{.*}} i8* @_Znam(i64{{( noundef)?}} [[ALLOC:%[0-9a-z]+]]) diff --git a/test/pass/new_delete/18_array_cookie_delete.cpp b/test/pass/new_delete/18_array_cookie_delete.cpp index 4fdaff6e..b169ec0c 100644 --- a/test/pass/new_delete/18_array_cookie_delete.cpp +++ b/test/pass/new_delete/18_array_cookie_delete.cpp @@ -9,7 +9,7 @@ struct S1 { int x; - ~S1(){}; + ~S1() {}; }; // CHECK: [[MEM:%[0-9a-z]+]] = getelementptr inbounds i8, {{i8\*|ptr}} [[ARR:%[0-9a-z]+]], i64 -8 diff --git a/test/pass/new_delete/19_array_cookie_dynamic_size_opaque.cpp b/test/pass/new_delete/19_array_cookie_dynamic_size_opaque.cpp index 0174641d..48ede9f1 100644 --- a/test/pass/new_delete/19_array_cookie_dynamic_size_opaque.cpp +++ b/test/pass/new_delete/19_array_cookie_dynamic_size_opaque.cpp @@ -1,5 +1,5 @@ // clang-format off -// RUN: %cpp-to-llvm %s | %apply-typeart -S 2>&1 | %filecheck %s +// RUN: %cpp-to-llvm %s | %apply-typeart --typeart-type-serialization=file -S 2>&1 | %filecheck %s // REQUIRES: llvm-18 || llvm-19 // clang-format on @@ -10,7 +10,7 @@ struct S1 { int x; - ~S1(){}; + ~S1() {}; }; // CHECK: [[MEM:%[0-9a-z]+]] = call{{.*}} ptr @_Znam(i64{{( noundef)?}} [[ALLOC:%[0-9a-z]+]]) diff --git a/test/pass/new_delete/20_no_array_cookie_lulesh_ad.llin b/test/pass/new_delete/20_no_array_cookie_lulesh_ad.llin index 03309760..43d30f97 100644 --- a/test/pass/new_delete/20_no_array_cookie_lulesh_ad.llin +++ b/test/pass/new_delete/20_no_array_cookie_lulesh_ad.llin @@ -1,4 +1,4 @@ -; RUN: %apply-typeart -S < %s | %filecheck %s +; RUN: %apply-typeart --typeart-type-serialization=file -S < %s | %filecheck %s ; REQUIRES: llvm-18 || llvm-19 ; llvm-reduce on lulesh.cc with culprit chunk.hpp:allocateData() where pattern is similar to array cookie. diff --git a/test/runtime/07_simple_struct_type_check.c b/test/runtime/07_simple_struct_type_check.c index 9aeda8b3..c04f5b79 100644 --- a/test/runtime/07_simple_struct_type_check.c +++ b/test/runtime/07_simple_struct_type_check.c @@ -1,4 +1,6 @@ -// RUN: %run %s --typeart-analysis-filter-non-array-alloca=true --compile_flags %dimeta_def 2>&1 | %filecheck %s +// clang-format off +// RUN: %run %s --typeart-analysis-filter-non-array-alloca=true --typeart-type-serialization=file --compile_flags "%dimeta_def -DIGNORE_ID=1" 2>&1 | %filecheck %s +// clang-format on #include "../struct_defs.h" #include "util.h" @@ -17,8 +19,12 @@ int main(int argc, char** argv) { s_int* a = malloc(sizeof(s_int)); // CHECK: Ok check_struct(a, "struct.s_int_t", 1); - // CHECK: Ok +// CHECK: Ok +#if IGNORE_ID == 1 + fprintf(stderr, "Ok\n"); +#else check(a, get_struct_id(0), 1, 0); +#endif // CHECK: Ok check(a, TYPEART_INT_32, 1, 1); // CHECK: Error: Unknown address @@ -30,8 +36,12 @@ int main(int argc, char** argv) { s_builtins* b = malloc(sizeof(s_builtins)); // CHECK: Ok check_struct(b, "struct.s_builtins_t", 1); - // CHECK: Ok +// CHECK: Ok +#if IGNORE_ID == 1 + fprintf(stderr, "Ok\n"); +#else check(b, get_struct_id(1), 1, 0); +#endif // CHECK: Ok check(b, TYPEART_INT_32, 1, 1); // CHECK: Error: Type mismatch @@ -53,8 +63,12 @@ int main(int argc, char** argv) { s_arrays* c = malloc(sizeof(s_arrays)); // CHECK: Ok check_struct(c, "struct.s_arrays_t", 1); - // CHECK: Ok +// CHECK: Ok +#if IGNORE_ID == 1 + fprintf(stderr, "Ok\n"); +#else check(c, get_struct_id(2), 1, 0); +#endif // CHECK: Ok check(c, TYPEART_INT_32, 3, 1); // CHECK: Ok @@ -78,8 +92,12 @@ int main(int argc, char** argv) { s_ptrs* d = malloc(sizeof(s_ptrs)); // CHECK: Ok check_struct(d, "struct.s_ptrs_t", 1); - // CHECK: Ok +// CHECK: Ok +#if IGNORE_ID == 1 + fprintf(stderr, "Ok\n"); +#else check(d, get_struct_id(3), 1, 0); +#endif // CHECK: Ok check(d, TYPEART_INT_8_TEST, 1, 1); // CHECK: Ok @@ -97,8 +115,12 @@ int main(int argc, char** argv) { s_mixed_simple* e = malloc(sizeof(s_mixed_simple)); // CHECK: Ok check_struct(e, "struct.s_mixed_simple_t", 1); - // CHECK: Ok +// CHECK: Ok +#if IGNORE_ID == 1 + fprintf(stderr, "Ok\n"); +#else check(e, get_struct_id(4), 1, 0); +#endif // CHECK: Ok check(e, TYPEART_INT_32, 1, 1); // CHECK: Ok diff --git a/test/runtime/08_recursive_struct_type_check.c b/test/runtime/08_recursive_struct_type_check.c index ff4004bf..618ca496 100644 --- a/test/runtime/08_recursive_struct_type_check.c +++ b/test/runtime/08_recursive_struct_type_check.c @@ -1,4 +1,5 @@ -// RUN: %run %s --typeart-analysis-filter-non-array-alloca=true 2>&1 | %filecheck %s +// RUN: %run %s --typeart-analysis-filter-non-array-alloca=true --compile_flags -DIGNORE_ID=1 2>&1 | %filecheck %s +// RUN: %run %s --typeart-analysis-filter-non-array-alloca=true --typeart-type-serialization=file 2>&1 | %filecheck %s #include "../struct_defs.h" #include "util.h" @@ -6,6 +7,9 @@ #include #include +// #define IGNORE_ID 1 + +// CHECK: [Trace] TypeART Runtime Trace int main(int argc, char** argv) { s_int s; @@ -14,7 +18,11 @@ int main(int argc, char** argv) { // CHECK: Ok check_struct(a, "struct.s_ptr_to_self_t", 1); // CHECK: Ok +#if IGNORE_ID == 1 + fprintf(stderr, "Ok\n"); +#else check(a, get_struct_id(0), 1, 0); +#endif // CHECK: Ok check(a, TYPEART_POINTER, 1, 1); // CHECK: Ok @@ -29,11 +37,19 @@ int main(int argc, char** argv) { // CHECK: Ok check_struct(b, "struct.s_struct_member_t", 1); // CHECK: Ok +#if IGNORE_ID == 1 + fprintf(stderr, "Ok\n"); +#else check(b, get_struct_id(1), 1, 0); +#endif // CHECK: Ok check(b, TYPEART_INT_32, 1, 1); - // CHECK: Ok +// CHECK: Ok +#if IGNORE_ID == 1 + fprintf(stderr, "Ok\n"); +#else check(&b->b, get_struct_id(0), 1, 0); +#endif // CHECK: Ok check(&b->b, TYPEART_POINTER, 1, 1); // CHECK: Ok @@ -48,7 +64,11 @@ int main(int argc, char** argv) { // CHECK: Ok check_struct(c, "struct.s_aos_t", 1); // CHECK: Ok +#if IGNORE_ID == 1 + fprintf(stderr, "Ok\n"); +#else check(c, get_struct_id(2), 1, 0); +#endif // CHECK: Ok check(c, TYPEART_INT_32, 1, 1); // CHECK: Ok diff --git a/test/runtime/22_threads_stack.cpp b/test/runtime/22_threads_stack.cpp index f42c522e..ae48015f 100644 --- a/test/runtime/22_threads_stack.cpp +++ b/test/runtime/22_threads_stack.cpp @@ -1,5 +1,6 @@ // clang-format off -// RUN: %run %s --thread 2>&1 | %filecheck %s --check-prefix=CHECK-TSAN +// : %run %s --thread 2>&1 | %filecheck %s --check-prefix=CHECK-TSAN +// export TYPEART_TYPE_SERIALIZATION=file // RUN: %run %s --thread 2>&1 | %filecheck %s // REQUIRES: thread // clang-format on diff --git a/test/runtime/30_omp_concurrent_w.cpp b/test/runtime/30_omp_concurrent_w.cpp index 80690450..70bfc12b 100644 --- a/test/runtime/30_omp_concurrent_w.cpp +++ b/test/runtime/30_omp_concurrent_w.cpp @@ -44,32 +44,31 @@ int main(int argc, char** argv) { #pragma omp parallel sections num_threads(3) { #pragma omp section - {repeat_alloc(beg, h1); -} + { repeat_alloc(beg, h1); } #pragma omp section -{ repeat_alloc(h2, e); } + { repeat_alloc(h2, e); } #pragma omp section -{ repeat_alloc(h1, h2); } -} + { repeat_alloc(h1, h2); } + } #pragma omp parallel sections num_threads(3) -{ + { #pragma omp section - { repeat_dealloc(beg, h1); } + { repeat_dealloc(beg, h1); } #pragma omp section - { repeat_dealloc(h2, e); } + { repeat_dealloc(h2, e); } #pragma omp section - { repeat_dealloc(h1, h2); } -} + { repeat_dealloc(h1, h2); } + } -// CHECK-TSAN-NOT: ThreadSanitizer + // CHECK-TSAN-NOT: ThreadSanitizer -// CHECK-NOT: Error + // CHECK-NOT: Error -// CHECK: Allocation type detail (heap, stack, global) -// CHECK: 24 : 300 , 0 , 0 , double + // CHECK: Allocation type detail (heap, stack, global) + // CHECK: 24 : 300 , 0 , 0 , double -// CHECK: Free allocation type detail (heap, stack) -// CHECK: 24 : 300 , 0 , double -return 0; + // CHECK: Free allocation type detail (heap, stack) + // CHECK: 24 : 300 , 0 , double + return 0; } diff --git a/test/runtime/41_array_cookie.cpp b/test/runtime/41_array_cookie.cpp index 6db9fbe8..8b7951b1 100644 --- a/test/runtime/41_array_cookie.cpp +++ b/test/runtime/41_array_cookie.cpp @@ -4,7 +4,7 @@ struct S1 { int x; - ~S1(){}; + ~S1() {}; }; int main() { diff --git a/test/runtime/44_typedb.cpp b/test/runtime/44_typedb.cpp index d6db3b8c..64bbaed1 100644 --- a/test/runtime/44_typedb.cpp +++ b/test/runtime/44_typedb.cpp @@ -1,5 +1,8 @@ +// RUN: export TYPEART_TYPE_SERIALIZATION=file // RUN: %run %s --compile_flags "-std=c++17" -o -O3 2>&1 | %filecheck %s +// TODO fails for inline/hybrid + #include "../../lib/runtime/RuntimeInterface.h" #include "../../lib/typelib/TypeDatabase.h" #include "TypeInterface.h" diff --git a/test/runtime/49_default_types_udef.c b/test/runtime/49_default_types_udef.c index 712cab21..cd35a0e0 100644 --- a/test/runtime/49_default_types_udef.c +++ b/test/runtime/49_default_types_udef.c @@ -1,3 +1,4 @@ +// RUN: export TYPEART_TYPE_SERIALIZATION=file // RUN: %run %s --clean_types 2>&1 | %filecheck %s struct Datastruct { diff --git a/test/runtime_inlined_types/01_simple_malloc_int.c b/test/runtime_inlined_types/01_simple_malloc_int.c new file mode 100644 index 00000000..913e281e --- /dev/null +++ b/test/runtime_inlined_types/01_simple_malloc_int.c @@ -0,0 +1,17 @@ +// clang-format off +// RUN: export TYPEART_TYPE_SERIALIZATION=inline +// RUN: %wrapper-cc -O1 %s -o %s.exe +// RUN: %s.exe 2>&1 | %filecheck %s + +// REQUIRES: llvm-18 || llvm-19 +// clang-format on + +#include +int main(void) { + int* p = (int*)malloc(42 * sizeof(int)); + free(p); + return 0; +} + +// CHECK: Allocation type detail (heap, stack, global) +// CHECK-NEXT: 13 : 1 , 0 , 0 , int \ No newline at end of file diff --git a/test/runtime_inlined_types/02_simple_malloc_int_multi_tu.c b/test/runtime_inlined_types/02_simple_malloc_int_multi_tu.c new file mode 100644 index 00000000..884df737 --- /dev/null +++ b/test/runtime_inlined_types/02_simple_malloc_int_multi_tu.c @@ -0,0 +1,32 @@ +// clang-format off +// RUN: export TYPEART_TYPE_SERIALIZATION=inline + +// : %cpp-to-llvm -DTYPEART_TU_ONE %s | %apply-typeart -typeart-instumentation=true -S > %s_1.ll +// : %cpp-to-llvm %s | %apply-typeart -typeart-instumentation=true -S > %s.ll + +// RUN: %wrapper-cc -c -O1 %s -DTYPEART_TU_ONE -o %s_1.o +// RUN: %wrapper-cc -c -O1 %s -o %s.o +// RUN: %wrapper-cc -O1 %s.o %s_1.o -o %s.exe +// RUN: %s.exe 2>&1 | %filecheck %s + +// REQUIRES: llvm-18 || llvm-19 +// clang-format on + +#include +#ifdef TYPEART_TU_ONE +void allocate() { + int* p = (int*)malloc(33 * sizeof(int)); + free(p); +} +#else +void allocate(); +int main(void) { + allocate(); + int* p = (int*)malloc(42 * sizeof(int)); + free(p); + return 0; +} +#endif + +// CHECK: Allocation type detail (heap, stack, global) +// CHECK-NEXT: 13 : 2 , 0 , 0 , int \ No newline at end of file diff --git a/test/runtime_inlined_types/03_simple_malloc_struct.c b/test/runtime_inlined_types/03_simple_malloc_struct.c new file mode 100644 index 00000000..112b8a78 --- /dev/null +++ b/test/runtime_inlined_types/03_simple_malloc_struct.c @@ -0,0 +1,24 @@ +// clang-format off +// RUN: export TYPEART_TYPE_SERIALIZATION=inline +// RUN: %wrapper-cc -O1 %s -o %s.exe +// RUN: %s.exe 2>&1 | %filecheck %s + +// REQUIRES: llvm-18 || llvm-19 +// clang-format on + +#include + +struct DataHolder { + double a; + float b; + int c; +}; + +int main(void) { + struct DataHolder* p = (struct DataHolder*)malloc(2 * sizeof(struct DataHolder)); + free(p); + return 0; +} + +// CHECK: Allocation type detail (heap, stack, global) +// CHECK-NEXT: 256 : 1 , 0 , 0 , DataHolder diff --git a/test/runtime_inlined_types/04_malloc_struct.c b/test/runtime_inlined_types/04_malloc_struct.c new file mode 100644 index 00000000..836560c1 --- /dev/null +++ b/test/runtime_inlined_types/04_malloc_struct.c @@ -0,0 +1,29 @@ +// clang-format off +// RUN: export TYPEART_TYPE_SERIALIZATION=inline +// RUN: %wrapper-cc -O1 %s -o %s.exe +// RUN: %s.exe 2>&1 | %filecheck %s + +// REQUIRES: llvm-18 || llvm-19 +// clang-format on + +#include + +struct DataNested { + struct DataNested* nested_pointer; +}; + +struct DataHolder { + double a; + float b; + int c; + struct DataNested nested; +}; + +int main(void) { + struct DataHolder* p = (struct DataHolder*)malloc(2 * sizeof(struct DataHolder)); + free(p); + return 0; +} + +// CHECK: Allocation type detail (heap, stack, global) +// CHECK-NEXT: 256 : 1 , 0 , 0 , DataHolder diff --git a/test/script/07_wrapper_demo.sh b/test/script/07_wrapper_demo.sh index ba0c09fd..70ea98de 100755 --- a/test/script/07_wrapper_demo.sh +++ b/test/script/07_wrapper_demo.sh @@ -4,8 +4,6 @@ # RUN: %s %t %S %wrapper-mpicc run-demo | %filecheck %s --check-prefix check-working # RUN: %s %t %S %wrapper-mpicc run-demo_broken | %filecheck %s --check-prefix check-broken -# RUN: %s %t %S %wrapper-mpicc runtoy | %filecheck %s --check-prefix check-toy - # REQUIRES: mpicc # UNSUPPORTED: sanitizer @@ -23,8 +21,6 @@ cd "$1" || exit 1 make clean MPICC="$3" make "$4" -exit 0 - # make sure "target" worked: if [ $? -gt 0 ]; then clean_up "$1" diff --git a/test/script/12_ir_viewer.sh b/test/script/12_ir_viewer.sh index d38fbfb2..37a9601d 100755 --- a/test/script/12_ir_viewer.sh +++ b/test/script/12_ir_viewer.sh @@ -30,21 +30,21 @@ exists 12_ir_viewer_target_stack.ll # CHECK: 1 # CHECK: 1 # CHECK: 1 -# CHECK: 1 +# : 1 exists 12_ir_viewer_target_base.ll exists 12_ir_viewer_target_heap.ll exists 12_ir_viewer_target_opt.ll exists 12_ir_viewer_target_stack.ll -exists 12_ir_viewer_target-types-ir-viewer.yaml +#exists 12_ir_viewer_target-types-ir-viewer.yaml "$python_interp" $1 -c 12_ir_viewer_target.c # CHECK: 0 # CHECK: 0 # CHECK: 0 # CHECK: 0 -# CHECK: 0 +# : 0 exists 12_ir_viewer_target_base.ll exists 12_ir_viewer_target_heap.ll exists 12_ir_viewer_target_opt.ll exists 12_ir_viewer_target_stack.ll -exists 12_ir_viewer_target-types-ir-viewer.yaml +#exists 12_ir_viewer_target-types-ir-viewer.yaml diff --git a/test/typemapping/01_simple_struct.c b/test/typemapping/01_simple_struct.c index e1c974b5..142932e8 100644 --- a/test/typemapping/01_simple_struct.c +++ b/test/typemapping/01_simple_struct.c @@ -1,5 +1,5 @@ // RUN: %remove %tu_yaml -// RUN: %c-to-llvm %s | %apply-typeart +// RUN: %c-to-llvm %s | %apply-typeart --typeart-type-serialization=file // RUN: cat %tu_yaml | %filecheck %s // Note: This test assumes standard alignment on a 64bit system. Non-standard alignment may lead to failure. diff --git a/test/typemapping/02_recursive_struct.c b/test/typemapping/02_recursive_struct.c index 7bc6c430..39c60ac0 100644 --- a/test/typemapping/02_recursive_struct.c +++ b/test/typemapping/02_recursive_struct.c @@ -1,5 +1,5 @@ // RUN: %remove %tu_yaml -// RUN: %c-to-llvm %s | %apply-typeart +// RUN: %c-to-llvm %s | %apply-typeart --typeart-type-serialization=file // RUN: cat %tu_yaml | %filecheck %s // Note: This test assumes standard alignment on a 64bit system. Non-standard alignment may lead to failure. diff --git a/test/typemapping/04_milc_mock.c b/test/typemapping/04_milc_mock.c index 9c1c1f46..6cc7b69a 100644 --- a/test/typemapping/04_milc_mock.c +++ b/test/typemapping/04_milc_mock.c @@ -1,5 +1,5 @@ // RUN: %remove %tu_yaml -// RUN: %c-to-llvm %s | %apply-typeart +// RUN: %c-to-llvm %s | %apply-typeart --typeart-type-serialization=file // RUN: cat %tu_yaml | %filecheck %s #include diff --git a/test/typemapping/06_anon_struct.c b/test/typemapping/06_anon_struct.c index 9dcdbd4e..e4bd1ed9 100644 --- a/test/typemapping/06_anon_struct.c +++ b/test/typemapping/06_anon_struct.c @@ -1,4 +1,4 @@ -// RUN: %c-to-llvm %s | %apply-typeart --typeart-stack=true +// RUN: %c-to-llvm %s | %apply-typeart --typeart-stack=true --typeart-type-serialization=file // RUN: cat %tu_yaml | %filecheck %s // REQUIRES: dimeta diff --git a/test/typemapping/07_no_ebo_heap_multi_inheritance.cpp b/test/typemapping/07_no_ebo_heap_multi_inheritance.cpp index f1f7e8bf..30be6006 100644 --- a/test/typemapping/07_no_ebo_heap_multi_inheritance.cpp +++ b/test/typemapping/07_no_ebo_heap_multi_inheritance.cpp @@ -1,5 +1,5 @@ // RUN: %remove %tu_yaml -// RUN: %cpp-to-llvm %s | %apply-typeart --typeart-stack=true +// RUN: %cpp-to-llvm %s | %apply-typeart --typeart-stack=true --typeart-type-serialization=file // RUN: cat %tu_yaml | %filecheck %s struct Base { diff --git a/test/typemapping/08_ebo_only_heap_multi_inheritance.cpp b/test/typemapping/08_ebo_only_heap_multi_inheritance.cpp index 9c9e8cea..5b434580 100644 --- a/test/typemapping/08_ebo_only_heap_multi_inheritance.cpp +++ b/test/typemapping/08_ebo_only_heap_multi_inheritance.cpp @@ -1,5 +1,5 @@ // RUN: %remove %tu_yaml -// RUN: %cpp-to-llvm %s | %apply-typeart --typeart-stack=true +// RUN: %cpp-to-llvm %s | %apply-typeart --typeart-stack=true --typeart-type-serialization=file // RUN: cat %tu_yaml | %filecheck %s struct Base { diff --git a/test/typemapping/09_stack_class_inheritance_virtual.cpp b/test/typemapping/09_stack_class_inheritance_virtual.cpp index 4b0009c4..90ca8ffa 100644 --- a/test/typemapping/09_stack_class_inheritance_virtual.cpp +++ b/test/typemapping/09_stack_class_inheritance_virtual.cpp @@ -1,5 +1,5 @@ // RUN: %remove %tu_yaml -// RUN: %cpp-to-llvm %s | %apply-typeart --typeart-stack=true +// RUN: %cpp-to-llvm %s | %apply-typeart --typeart-stack=true --typeart-type-serialization=file // RUN: cat %tu_yaml | %filecheck %s // REQUIRES: dimeta diff --git a/test/typemapping/10_multi_inheritance_virtual.cpp b/test/typemapping/10_multi_inheritance_virtual.cpp index 1a303dac..057006dd 100644 --- a/test/typemapping/10_multi_inheritance_virtual.cpp +++ b/test/typemapping/10_multi_inheritance_virtual.cpp @@ -1,5 +1,5 @@ // RUN: %remove %tu_yaml -// RUN: %cpp-to-llvm %s | %apply-typeart --typeart-stack=true +// RUN: %cpp-to-llvm %s | %apply-typeart --typeart-stack=true --typeart-type-serialization=file // RUN: cat %tu_yaml | %filecheck %s // REQUIRES: dimeta @@ -8,7 +8,7 @@ class Base { public: double x; - virtual void foo(){}; + virtual void foo() {}; }; class X { diff --git a/test/typemapping/11_void_nullptr.cpp b/test/typemapping/11_void_nullptr.cpp index 1e3d6f30..3e1fbfc4 100644 --- a/test/typemapping/11_void_nullptr.cpp +++ b/test/typemapping/11_void_nullptr.cpp @@ -1,5 +1,5 @@ // RUN: %remove %tu_yaml -// RUN: %cpp-to-llvm %s | %apply-typeart --typeart-stack=true +// RUN: %cpp-to-llvm %s | %apply-typeart --typeart-stack=true --typeart-type-serialization=file // RUN: cat %tu_yaml | %filecheck %s // REQUIRES: dimeta diff --git a/test/typemapping/12_complex.cpp b/test/typemapping/12_complex.cpp index a3c93951..23118f36 100644 --- a/test/typemapping/12_complex.cpp +++ b/test/typemapping/12_complex.cpp @@ -1,5 +1,5 @@ // RUN: %remove %tu_yaml -// RUN: %cpp-to-llvm %s | %apply-typeart --typeart-stack=true +// RUN: %cpp-to-llvm %s | %apply-typeart --typeart-stack=true --typeart-type-serialization=file // RUN: cat %tu_yaml | %filecheck %s // REQUIRES: dimeta diff --git a/test/typemapping/13_complex.c b/test/typemapping/13_complex.c index 532bbd52..9e5f5416 100644 --- a/test/typemapping/13_complex.c +++ b/test/typemapping/13_complex.c @@ -1,5 +1,5 @@ // RUN: %remove %tu_yaml -// RUN: %c-to-llvm %s | %apply-typeart --typeart-stack=true +// RUN: %c-to-llvm %s | %apply-typeart --typeart-stack=true --typeart-type-serialization=file // RUN: cat %tu_yaml | %filecheck %s // REQUIRES: llvm-18 || llvm-19 diff --git a/test/typemapping/14_union.c b/test/typemapping/14_union.c index 4deb27de..e496b431 100644 --- a/test/typemapping/14_union.c +++ b/test/typemapping/14_union.c @@ -1,5 +1,5 @@ // RUN: %remove %tu_yaml -// RUN: %c-to-llvm %s | %apply-typeart --typeart-stack=true +// RUN: %c-to-llvm %s | %apply-typeart --typeart-stack=true --typeart-type-serialization=file // RUN: cat %tu_yaml | %filecheck %s // REQUIRES: llvm-18 || llvm-19 diff --git a/test/typemapping/15_wchar.c b/test/typemapping/15_wchar.c index 4ee69b72..75ac4682 100644 --- a/test/typemapping/15_wchar.c +++ b/test/typemapping/15_wchar.c @@ -1,5 +1,5 @@ // RUN: %remove %tu_yaml -// RUN: %c-to-llvm %s | %apply-typeart --typeart-stack=true +// RUN: %c-to-llvm %s | %apply-typeart --typeart-stack=true --typeart-type-serialization=file // RUN: cat %tu_yaml | %filecheck %s // REQUIRES: llvm-18 || llvm-19 diff --git a/test/typemapping/16_mpi_dtype.c b/test/typemapping/16_mpi_dtype.c new file mode 100644 index 00000000..182da9d0 --- /dev/null +++ b/test/typemapping/16_mpi_dtype.c @@ -0,0 +1,24 @@ +// clang-format off +// RUN: %c-to-llvm %s | %apply-typeart --typeart-stack=true -S | %filecheck %s +// RUN: %c-to-llvm %s | %apply-typeart --typeart-type-serialization=inline --typeart-stack=true -S | %filecheck %s --check-prefix inline +// RUN: %c-to-llvm %s | %apply-typeart --typeart-type-serialization=hybrid --typeart-stack=true -S | %filecheck %s --check-prefix hybrid + +// REQUIRES: llvm-18 || llvm-19 +// clang-format on +struct ompi_struct_data; +typedef struct ompi_struct_data* MPI_Datatype; + +extern MPI_Datatype MPI_DOUBLE; +extern MPI_Datatype MPI_INT; + +int main(void) { + MPI_Datatype array_of_types[3] = {MPI_DOUBLE, MPI_DOUBLE, MPI_INT}; + + return 0; +} + +// CHECK-NOT: Error +// CHECK: call {{.*}} @__typeart_alloc_stack(ptr {{.*}}, i32 1, i64 3) +// inline: @_typeart_ptr = weak_odr global %struct._typeart_struct_layout_t +// inline: call {{.*}} @__typeart_alloc_stack_mty(ptr {{.*}}, ptr {{.*}}, i64 3) +// hybrid: call {{.*}} @__typeart_alloc_stack(ptr {{.*}}, i32 1, i64 3)