From 068e5636ad29005c74126392e1388d07b40de638 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20H=C3=BCck?= Date: Fri, 24 Oct 2025 11:27:19 +0200 Subject: [PATCH 01/35] Enable new version of callbacks --- lib/passes/Commandline.cpp | 7 + lib/passes/TypeARTPass.cpp | 66 ++---- .../instrumentation/InstrumentationHelper.h | 1 - .../instrumentation/MemOpInstrumentation.cpp | 29 ++- .../instrumentation/MemOpInstrumentation.h | 8 +- .../instrumentation/TypeARTFunctions.cpp | 197 ++++++++++++++++-- lib/passes/instrumentation/TypeARTFunctions.h | 39 ++-- lib/runtime/AccessCountPrinter.h | 1 - lib/support/ConfigurationBaseOptions.h | 1 + 9 files changed, 239 insertions(+), 110 deletions(-) diff --git a/lib/passes/Commandline.cpp b/lib/passes/Commandline.cpp index 204766ef..aad19f5c 100644 --- a/lib/passes/Commandline.cpp +++ b/lib/passes/Commandline.cpp @@ -83,6 +83,11 @@ static cl::opt cl_typeart_instrument_stack(Commandl cl::init(ConfigStdArgValues::stack), cl::cat(typeart_category)); +static cl::opt cl_typeart_instrument(CommandlineStdArgs::instrumentation, + cl::desc(ConfigStdArgDescriptions::instrumentation), + cl::init(ConfigStdArgValues::instrumentation), + 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 +203,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::instrumentation, cl_typeart_instrument), 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 +223,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::instrumentation, cl_typeart_instrument), 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..f81f2c03 100644 --- a/lib/passes/TypeARTPass.cpp +++ b/lib/passes/TypeARTPass.cpp @@ -49,6 +49,7 @@ #include #include #include +#include #include #include #include @@ -95,26 +96,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 { @@ -170,13 +155,17 @@ class TypeArtPass : public llvm::PassInfoMixin { ModuleData mdata{&m}; typeManager->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)); + declareInstrumentationFunctions(m); + { + 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.get(), instrumentation_helper); + instrumentation_context = + std::make_unique(std::move(arg_collector), std::move(mem_instrument)); + } return true; } @@ -203,30 +192,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 +258,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 +288,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 +330,7 @@ class LegacyTypeArtPass : public llvm::ModulePass { public: static char ID; // NOLINT - LegacyTypeArtPass() : ModulePass(ID){}; + LegacyTypeArtPass() : ModulePass(ID) {}; bool doInitialization(llvm::Module&) override; 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..0e58da15 100644 --- a/lib/passes/instrumentation/MemOpInstrumentation.cpp +++ b/lib/passes/instrumentation/MemOpInstrumentation.cpp @@ -51,9 +51,9 @@ using namespace llvm; namespace typeart { -MemOpInstrumentation::MemOpInstrumentation(const config::Configuration& typeart_conf, TAFunctionQuery& fquery, +MemOpInstrumentation::MemOpInstrumentation(const config::Configuration& typeart_conf, TAFunctionQuery* fquery, InstrumentationHelper& instr) - : MemoryInstrument(), typeart_config(typeart_conf), function_query(&fquery), instrumentation_helper(&instr) { + : MemoryInstrument(), typeart_config(typeart_conf), function_query(fquery), instrumentation_helper(&instr) { instrument_lifetime = typeart_config[config::ConfigStdArgs::stack_lifetime]; } @@ -61,6 +61,9 @@ 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); + + function_query->getFunctionFor(IFunc::free); + for (const auto& [malloc, args] : heap) { auto kind = malloc.kind; auto* malloc_call = args.get_as(ArgMap::ID::pointer); @@ -139,7 +142,8 @@ InstrCount MemOpInstrumentation::instrumentHeap(const HeapArgList& heap) { continue; } - const auto callback_id = omp ? IFunc::heap_omp : IFunc::heap; + // const auto callback_id = omp ? IFunc::heap_omp : IFunc::heap; + const auto callback_id = ifunc_for_function(IFunc::heap, malloc.call); IRB.CreateCall(function_query->getFunctionFor(callback_id), ArrayRef{malloc_call, typeid_value, element_count}); ++counter; @@ -174,8 +178,9 @@ 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; + // 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}); ++counter; @@ -195,7 +200,8 @@ 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; + // const auto callback_id = util::omp::isOmpContext(anchor->getFunction()) ? IFunc::stack_omp : IFunc::stack; + const auto callback_id = ifunc_for_function(IFunc::stack, alloca); IRB.CreateCall(function_query->getFunctionFor(callback_id), ArrayRef{data_ptr, typeIdConst, numElementsVal}); ++counter; @@ -234,11 +240,12 @@ InstrCount MemOpInstrumentation::instrumentGlobal(const GlobalArgList& globals) const auto instrumentGlobalsInCtor = [&](auto& IRB) { for (const auto& [gdata, args] : globals) { // Instruction* global = args.get_as("pointer"); - auto global = gdata.global; - 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), + auto global = gdata.global; + 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)); + const auto callback_id = ifunc_for_function(IFunc::global, global); + IRB.CreateCall(function_query->getFunctionFor(callback_id), ArrayRef{globalPtr, typeIdConst, numElementsVal}); ++counter; } diff --git a/lib/passes/instrumentation/MemOpInstrumentation.h b/lib/passes/instrumentation/MemOpInstrumentation.h index 0a8bd442..6b238839 100644 --- a/lib/passes/instrumentation/MemOpInstrumentation.h +++ b/lib/passes/instrumentation/MemOpInstrumentation.h @@ -10,8 +10,8 @@ // 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" @@ -30,7 +30,7 @@ class MemOpInstrumentation final : public MemoryInstrument { bool instrument_lifetime{false}; public: - MemOpInstrumentation(const config::Configuration& typeart_conf, TAFunctionQuery& fquery, + MemOpInstrumentation(const config::Configuration& typeart_conf, TAFunctionQuery* fquery, InstrumentationHelper& instr); InstrCount instrumentHeap(const HeapArgList& heap) override; InstrCount instrumentFree(const FreeArgList& frees) override; @@ -39,4 +39,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..ff8e32ae 100644 --- a/lib/passes/instrumentation/TypeARTFunctions.cpp +++ b/lib/passes/instrumentation/TypeARTFunctions.cpp @@ -12,7 +12,10 @@ #include "TypeARTFunctions.h" +#include "configuration/Configuration.h" +#include "support/ConfigurationBase.h" #include "support/Logger.h" +#include "support/OmpUtil.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringMap.h" @@ -27,6 +30,7 @@ #include "llvm/Support/Casting.h" #include "llvm/Support/raw_ostream.h" +#include #include namespace typeart { @@ -37,29 +41,131 @@ 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 (auto global = llvm::dyn_cast(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) const override; + void putFunctionFor(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); + 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) { + 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 +197,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()); @@ -115,14 +221,73 @@ const llvm::StringMap& TAFunctionDeclarator::getFunctionMap() c return function_map; } -TAFunctions::TAFunctions() = default; - -Function* TAFunctions::getFunctionFor(IFunc id) { - return typeart_callbacks[id]; +Function* TAFunctions::getFunctionFor(IFunc id) const { + auto element = typeart_callbacks.find(id); + if (element == std::end(typeart_callbacks)) { + LOG_WARNING("No functions for id " << int(id)) + return nullptr; + } + return element->second; } void TAFunctions::putFunctionFor(IFunc id, llvm::Function* f) { typeart_callbacks[id] = f; } +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"}; + +} // namespace callbacks + +std::unique_ptr declare_instrumentation_functions(llvm::Module& m, + const config::Configuration& configuration) { + using namespace callbacks; + auto functions = std::make_unique(); + InstrumentationHelper instrumentation_helper; + instrumentation_helper.setModule(m); + TAFunctionDeclarator decl(m, instrumentation_helper, *functions.get()); + + 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 bool module_local_types = configuration[config::ConfigStdArgs::instrumentation]; + if (module_local_types) { + auto alloc_arg_types_mty = instrumentation_helper.make_parameters(IType::ptr, IType::ptr, IType::extent); + typeart_alloc.f = decl.make_function(IFunc::heap, typeart_alloc_mty.name, alloc_arg_types_mty); + } else { + 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); + + return functions; +} + } // namespace typeart diff --git a/lib/passes/instrumentation/TypeARTFunctions.h b/lib/passes/instrumentation/TypeARTFunctions.h index d707a933..ea26c777 100644 --- a/lib/passes/instrumentation/TypeARTFunctions.h +++ b/lib/passes/instrumentation/TypeARTFunctions.h @@ -14,11 +14,13 @@ #define TYPEART_TYPEARTFUNCTIONS_H #include "InstrumentationHelper.h" +#include "configuration/Configuration.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" +#include #include namespace llvm { @@ -30,6 +32,10 @@ class Module; namespace typeart { class InstrumentationHelper; +namespace config { +class Configuration; +} + enum class IFunc : unsigned { heap, stack, @@ -42,37 +48,16 @@ enum class IFunc : unsigned { scope_omp, }; -class TAFunctionQuery { - public: - virtual llvm::Function* getFunctionFor(IFunc id) = 0; - virtual ~TAFunctionQuery() = default; -}; - -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); + virtual llvm::Function* getFunctionFor(IFunc id) 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/runtime/AccessCountPrinter.h b/lib/runtime/AccessCountPrinter.h index 525e84c7..4143d6f2 100644 --- a/lib/runtime/AccessCountPrinter.h +++ b/lib/runtime/AccessCountPrinter.h @@ -55,7 +55,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/support/ConfigurationBaseOptions.h b/lib/support/ConfigurationBaseOptions.h index a8fe1e4d..74c3e9ef 100644 --- a/lib/support/ConfigurationBaseOptions.h +++ b/lib/support/ConfigurationBaseOptions.h @@ -44,5 +44,6 @@ 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(instrumentation, "instumentation", bool, true, "Instrument with module local types.", "HEAP") #undef TYPEART_CONFIG_OPTION From e83b85d60d892dbeb6ae3b8a4ce856d756cfb534 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20H=C3=BCck?= Date: Fri, 24 Oct 2025 13:52:26 +0200 Subject: [PATCH 02/35] Introduce type id value translator --- lib/passes/CMakeLists.txt | 1 + lib/passes/TypeARTPass.cpp | 5 ++-- lib/passes/configuration/TypeARTOptions.h | 6 ++--- .../instrumentation/MemOpInstrumentation.cpp | 19 +++++++++---- .../instrumentation/MemOpInstrumentation.h | 7 ++++- lib/passes/instrumentation/TypeARTFunctions.h | 5 ---- lib/passes/instrumentation/TypeIDProvider.cpp | 20 ++++++++++++++ lib/passes/instrumentation/TypeIDProvider.h | 27 +++++++++++++++++++ 8 files changed, 74 insertions(+), 16 deletions(-) create mode 100644 lib/passes/instrumentation/TypeIDProvider.cpp create mode 100644 lib/passes/instrumentation/TypeIDProvider.h diff --git a/lib/passes/CMakeLists.txt b/lib/passes/CMakeLists.txt index 7d8f44af..4c524da0 100644 --- a/lib/passes/CMakeLists.txt +++ b/lib/passes/CMakeLists.txt @@ -12,6 +12,7 @@ set(PASS_SOURCES instrumentation/MemOpArgCollector.cpp instrumentation/MemOpInstrumentation.cpp instrumentation/Instrumentation.cpp + instrumentation/TypeIDProvider.cpp TypeARTConfiguration.cpp Commandline.cpp ) diff --git a/lib/passes/TypeARTPass.cpp b/lib/passes/TypeARTPass.cpp index f81f2c03..8bb5f683 100644 --- a/lib/passes/TypeARTPass.cpp +++ b/lib/passes/TypeARTPass.cpp @@ -157,11 +157,12 @@ class TypeArtPass : public llvm::PassInfoMixin { declareInstrumentationFunctions(m); { + auto type_id_handler = get_type_id_handler(m, configuration()); 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.get(), instrumentation_helper); + auto mem_instrument = std::make_unique(configuration(), functions.get(), + std::move(type_id_handler), instrumentation_helper); instrumentation_context = std::make_unique(std::move(arg_collector), std::move(mem_instrument)); diff --git a/lib/passes/configuration/TypeARTOptions.h b/lib/passes/configuration/TypeARTOptions.h index 7110bed1..93b13608 100644 --- a/lib/passes/configuration/TypeARTOptions.h +++ b/lib/passes/configuration/TypeARTOptions.h @@ -10,8 +10,8 @@ // 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" @@ -76,4 +76,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/instrumentation/MemOpInstrumentation.cpp b/lib/passes/instrumentation/MemOpInstrumentation.cpp index 0e58da15..159620c1 100644 --- a/lib/passes/instrumentation/MemOpInstrumentation.cpp +++ b/lib/passes/instrumentation/MemOpInstrumentation.cpp @@ -19,6 +19,7 @@ #include "TypeInterface.h" #include "analysis/MemOpData.h" #include "configuration/Configuration.h" +#include "instrumentation/TypeIDProvider.h" #include "support/ConfigurationBase.h" #include "support/Logger.h" #include "support/OmpUtil.h" @@ -41,6 +42,7 @@ #include "llvm/Support/raw_ostream.h" #include "llvm/Transforms/Utils/ModuleUtils.h" +#include #include namespace llvm { @@ -52,8 +54,12 @@ 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) { + std::unique_ptr type_id_handle, InstrumentationHelper& instr) + : MemoryInstrument(), + typeart_config(typeart_conf), + function_query(fquery), + type_id_handler(std::move(type_id_handle)), + instrumentation_helper(&instr) { instrument_lifetime = typeart_config[config::ConfigStdArgs::stack_lifetime]; } @@ -144,8 +150,9 @@ InstrCount MemOpInstrumentation::instrumentHeap(const HeapArgList& heap) { // const auto callback_id = omp ? IFunc::heap_omp : IFunc::heap; const auto callback_id = ifunc_for_function(IFunc::heap, malloc.call); + auto type_id_param = type_id_handler->getOrRegister(typeid_value); IRB.CreateCall(function_query->getFunctionFor(callback_id), - ArrayRef{malloc_call, typeid_value, element_count}); + ArrayRef{malloc_call, type_id_param, element_count}); ++counter; } @@ -202,8 +209,9 @@ InstrCount MemOpInstrumentation::instrumentStack(const StackArgList& stack) { 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; const auto callback_id = ifunc_for_function(IFunc::stack, alloca); + auto type_id_param = type_id_handler->getOrRegister(typeIdConst); IRB.CreateCall(function_query->getFunctionFor(callback_id), - ArrayRef{data_ptr, typeIdConst, numElementsVal}); + ArrayRef{data_ptr, type_id_param, numElementsVal}); ++counter; auto* bblock = anchor->getParent(); @@ -245,8 +253,9 @@ InstrCount MemOpInstrumentation::instrumentGlobal(const GlobalArgList& globals) auto numElementsVal = args.get_value(ArgMap::ID::element_count); auto globalPtr = IRB.CreateBitOrPointerCast(global, instrumentation_helper->getTypeFor(IType::ptr)); const auto callback_id = ifunc_for_function(IFunc::global, global); + auto type_id_param = type_id_handler->getOrRegister(typeIdConst); IRB.CreateCall(function_query->getFunctionFor(callback_id), - ArrayRef{globalPtr, typeIdConst, numElementsVal}); + ArrayRef{globalPtr, type_id_param, numElementsVal}); ++counter; } }; diff --git a/lib/passes/instrumentation/MemOpInstrumentation.h b/lib/passes/instrumentation/MemOpInstrumentation.h index 6b238839..253d6f70 100644 --- a/lib/passes/instrumentation/MemOpInstrumentation.h +++ b/lib/passes/instrumentation/MemOpInstrumentation.h @@ -15,6 +15,9 @@ #include "Instrumentation.h" #include "configuration/Configuration.h" +#include "instrumentation/TypeIDProvider.h" + +#include namespace typeart { namespace config { @@ -22,16 +25,18 @@ class Configuration; } class TAFunctionQuery; class InstrumentationHelper; +class TypeRegistry; class MemOpInstrumentation final : public MemoryInstrument { const config::Configuration& typeart_config; TAFunctionQuery* function_query; + std::unique_ptr type_id_handler; InstrumentationHelper* instrumentation_helper; bool instrument_lifetime{false}; public: MemOpInstrumentation(const config::Configuration& typeart_conf, TAFunctionQuery* fquery, - InstrumentationHelper& instr); + std::unique_ptr type_id_handler, InstrumentationHelper& instr); InstrCount instrumentHeap(const HeapArgList& heap) override; InstrCount instrumentFree(const FreeArgList& frees) override; InstrCount instrumentStack(const StackArgList& stack) override; diff --git a/lib/passes/instrumentation/TypeARTFunctions.h b/lib/passes/instrumentation/TypeARTFunctions.h index ea26c777..64bddf6e 100644 --- a/lib/passes/instrumentation/TypeARTFunctions.h +++ b/lib/passes/instrumentation/TypeARTFunctions.h @@ -16,12 +16,7 @@ #include "InstrumentationHelper.h" #include "configuration/Configuration.h" -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/StringMap.h" -#include "llvm/ADT/StringRef.h" - #include -#include namespace llvm { class Function; diff --git a/lib/passes/instrumentation/TypeIDProvider.cpp b/lib/passes/instrumentation/TypeIDProvider.cpp new file mode 100644 index 00000000..089fd802 --- /dev/null +++ b/lib/passes/instrumentation/TypeIDProvider.cpp @@ -0,0 +1,20 @@ +#include "TypeIDProvider.h" + +#include "configuration/Configuration.h" + +#include + +namespace typeart { + +class TypeRegistryNoOp final : public TypeRegistry { + public: + llvm::Value* getOrRegister(llvm::Value* type_id_const) override { + return type_id_const; + } +}; + +std::unique_ptr get_type_id_handler(llvm::Module& m, const config::Configuration& configuration) { + return std::make_unique(); +} + +} // 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..54b85717 --- /dev/null +++ b/lib/passes/instrumentation/TypeIDProvider.h @@ -0,0 +1,27 @@ +#ifndef LIB_PASSES_INSTRUMENTATION_MODULETYPEREGISTRY +#define LIB_PASSES_INSTRUMENTATION_MODULETYPEREGISTRY + +#include + +namespace llvm { +class Value; +class Module; +} // namespace llvm + +namespace typeart { + +namespace config { +class Configuration; +} + +class TypeRegistry { + public: + virtual llvm::Value* getOrRegister(llvm::Value* type_id_const) = 0; + virtual ~TypeRegistry() = default; +}; + +std::unique_ptr get_type_id_handler(llvm::Module& m, const config::Configuration& configuration); + +} // namespace typeart + +#endif /* LIB_PASSES_INSTRUMENTATION_MODULETYPEREGISTRY */ From 1e2c9e138a503636bdb0b6c157bbeb38b2530238 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20H=C3=BCck?= Date: Fri, 24 Oct 2025 16:40:01 +0200 Subject: [PATCH 03/35] Skeleton global type descriptor --- lib/passes/TypeARTPass.cpp | 2 +- lib/passes/instrumentation/TypeIDProvider.cpp | 109 +++++++++++++++++- lib/passes/instrumentation/TypeIDProvider.h | 6 +- test/pass/inline_types/01_simple_malloc_int.c | 16 +++ 4 files changed, 130 insertions(+), 3 deletions(-) create mode 100644 test/pass/inline_types/01_simple_malloc_int.c diff --git a/lib/passes/TypeARTPass.cpp b/lib/passes/TypeARTPass.cpp index 8bb5f683..e3d329be 100644 --- a/lib/passes/TypeARTPass.cpp +++ b/lib/passes/TypeARTPass.cpp @@ -157,7 +157,7 @@ class TypeArtPass : public llvm::PassInfoMixin { declareInstrumentationFunctions(m); { - auto type_id_handler = get_type_id_handler(m, configuration()); + auto type_id_handler = get_type_id_handler(m, &typeManager->getTypeDatabase(), configuration()); auto arg_collector = std::make_unique(configuration(), typeManager.get(), instrumentation_helper); // const bool instrument_stack_lifetime = configuration()[config::ConfigStdArgs::stack_lifetime]; diff --git a/lib/passes/instrumentation/TypeIDProvider.cpp b/lib/passes/instrumentation/TypeIDProvider.cpp index 089fd802..7f4ed624 100644 --- a/lib/passes/instrumentation/TypeIDProvider.cpp +++ b/lib/passes/instrumentation/TypeIDProvider.cpp @@ -1,7 +1,13 @@ #include "TypeIDProvider.h" +#include "TypeDatabase.h" #include "configuration/Configuration.h" +#include "support/ConfigurationBase.h" +#include +#include +#include +#include #include namespace typeart { @@ -13,7 +19,108 @@ class TypeRegistryNoOp final : public TypeRegistry { } }; -std::unique_ptr get_type_id_handler(llvm::Module& m, const config::Configuration& configuration) { +namespace helper { +llvm::Constant* create_global_array_ptr(llvm::Module& M, llvm::LLVMContext& C, llvm::ArrayRef values, + const llvm::Twine& name) { + auto* int64_ty = llvm::Type::getInt64Ty(C); + std::vector constants; + constants.reserve(values.size()); + for (uint64_t val : values) { + constants.push_back(llvm::ConstantInt::get(int64_ty, val)); + } + + auto* array_ty = llvm::ArrayType::get(int64_ty, values.size()); + auto* constant_array = llvm::ConstantArray::get(array_ty, constants); + auto* gv = new llvm::GlobalVariable(M, array_ty, // + true, // + llvm::GlobalValue::InternalLinkage, // + constant_array, // + name); + auto constant_zero_i32 = llvm::ConstantInt::get(llvm::Type::getInt32Ty(C), 0); + return llvm::ConstantExpr::getGetElementPtr( // + array_ty, // + gv, // + llvm::ArrayRef{constant_zero_i32, constant_zero_i32}); +} +} // namespace helper + +namespace typedb { +struct GlobalTypeRegistrar { + llvm::Module* module_; + llvm::StructType* struct_layout_type_; + const TypeDatabase* type_db_; + + GlobalTypeRegistrar() = default; + GlobalTypeRegistrar(llvm::Module* m, llvm::StructType* struct_layout_type, const TypeDatabase* type_db) + : module_(m), struct_layout_type_(struct_layout_type), type_db_(type_db) { + } + + llvm::GlobalVariable* getOrRegister(int type_id) { + llvm::GlobalVariable* global_struct_test = + new llvm::GlobalVariable(*module_, struct_layout_type_, false, llvm::GlobalValue::InternalLinkage, + nullptr, // init later + "type_id_test" + + ); + auto& context = module_->getContext(); + llvm::IRBuilder<> Builder(context); + llvm::Constant* NameStr = Builder.CreateGlobalStringPtr("sample struct", "str.name", 0, module_); + llvm::Constant* OffsetsPtr = helper::create_global_array_ptr(*module_, context, {0, 8}, "offsets.arr"); + llvm::Constant* CountPtr = helper::create_global_array_ptr(*module_, context, {1, 1}, "count.arr"); + std::vector Members = {Builder.getInt32(0), // + NameStr, // + Builder.getInt64(24), // + Builder.getInt64(2), // + OffsetsPtr, // + global_struct_test, // + CountPtr}; + llvm::Constant* TheInitializer = llvm::ConstantStruct::get(struct_layout_type_, Members); + + global_struct_test->setInitializer(TheInitializer); + return global_struct_test; + } +}; +} // namespace typedb + +class TypeRegistryGlobals final : public TypeRegistry { + llvm::Module* module_; + llvm::StructType* struct_layout_type_; + typedb::GlobalTypeRegistrar registrar_; + + private: + void declareLayout() { + auto& context = module_->getContext(); + llvm::IRBuilder<> Builder(context); + struct_layout_type_ = llvm::StructType::create(context, "struct.typeart_struct_layout_t"); + struct_layout_type_->setBody({ + Builder.getInt32Ty(), // int type_id + llvm::PointerType::getUnqual(context), // const char* name + Builder.getInt64Ty(), // size_t extent + Builder.getInt64Ty(), // size_t num_members + llvm::PointerType::getUnqual(context), // const size_t* offsets + llvm::PointerType::getUnqual(context), // const typeart_struct_layout_t* member_types + llvm::PointerType::getUnqual(context) // const size_t* count + }); + } + + public: + TypeRegistryGlobals(llvm::Module& m, const TypeDatabase* type_db) : module_(&m) { + declareLayout(); + registrar_ = typedb::GlobalTypeRegistrar(module_, struct_layout_type_, type_db); + } + + llvm::Value* getOrRegister(llvm::Value* type_id_const) override { + auto* constant_int = llvm::dyn_cast(type_id_const); + const int type_id = static_cast(constant_int->getSExtValue()); + return registrar_.getOrRegister(type_id); + } +}; + +std::unique_ptr get_type_id_handler(llvm::Module& m, const TypeDatabase* type_gen, + const config::Configuration& configuration) { + if (configuration[config::ConfigStdArgs::instrumentation]) { + return std::make_unique(m, type_gen); + } return std::make_unique(); } diff --git a/lib/passes/instrumentation/TypeIDProvider.h b/lib/passes/instrumentation/TypeIDProvider.h index 54b85717..586be84c 100644 --- a/lib/passes/instrumentation/TypeIDProvider.h +++ b/lib/passes/instrumentation/TypeIDProvider.h @@ -1,6 +1,9 @@ #ifndef LIB_PASSES_INSTRUMENTATION_MODULETYPEREGISTRY #define LIB_PASSES_INSTRUMENTATION_MODULETYPEREGISTRY +#include "TypeDatabase.h" +#include "TypeGenerator.h" + #include namespace llvm { @@ -20,7 +23,8 @@ class TypeRegistry { virtual ~TypeRegistry() = default; }; -std::unique_ptr get_type_id_handler(llvm::Module& m, const config::Configuration& configuration); +std::unique_ptr get_type_id_handler(llvm::Module& m, const TypeDatabase* type_db, + const config::Configuration& configuration); } // namespace typeart 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..0068a389 --- /dev/null +++ b/test/pass/inline_types/01_simple_malloc_int.c @@ -0,0 +1,16 @@ +// clang-format off +// RUN: %c-to-llvm %s | %apply-typeart -typeart-instumentation=true -S 2>&1 | %filecheck %s +// 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, ptr, i64, i64, ptr, ptr, ptr } +// CHECK: [[POINTER:%[0-9a-z]+]] = call noalias{{( align [0-9]+)?}} {{i8\*|ptr}} @malloc +// CHECK-NEXT: call void @__typeart_alloc_mty({{i8\*|ptr}} [[POINTER]], ptr {{.*}}, i64 42) From dfe70892801a729dae485dc923d128ad98670c48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20H=C3=BCck?= Date: Sat, 25 Oct 2025 15:15:37 +0200 Subject: [PATCH 04/35] Handle built-ins generically --- lib/passes/instrumentation/TypeIDProvider.cpp | 199 ++++++++++++------ lib/passes/typegen/TypeGenerator.h | 6 +- test/pass/inline_types/01_simple_malloc_int.c | 8 +- test/pass/inline_types/02_calloc_realloc.c | 31 +++ 4 files changed, 177 insertions(+), 67 deletions(-) create mode 100644 test/pass/inline_types/02_calloc_realloc.c diff --git a/lib/passes/instrumentation/TypeIDProvider.cpp b/lib/passes/instrumentation/TypeIDProvider.cpp index 7f4ed624..81013024 100644 --- a/lib/passes/instrumentation/TypeIDProvider.cpp +++ b/lib/passes/instrumentation/TypeIDProvider.cpp @@ -1,14 +1,23 @@ #include "TypeIDProvider.h" #include "TypeDatabase.h" +#include "TypeInterface.h" #include "configuration/Configuration.h" #include "support/ConfigurationBase.h" #include +#include +#include +#include +#include +#include #include #include +#include #include #include +#include +#include namespace typeart { @@ -20,72 +29,61 @@ class TypeRegistryNoOp final : public TypeRegistry { }; namespace helper { -llvm::Constant* create_global_array_ptr(llvm::Module& M, llvm::LLVMContext& C, llvm::ArrayRef values, - const llvm::Twine& name) { - auto* int64_ty = llvm::Type::getInt64Ty(C); - std::vector constants; - constants.reserve(values.size()); - for (uint64_t val : values) { - constants.push_back(llvm::ConstantInt::get(int64_ty, val)); +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) { + return TYPEART_UNKNOWN_TYPE; } + const int type_id = static_cast(constant_int->getSExtValue()); + return type_id; +} + +template +inline std::string concat(Args&&... args) { + const auto str = (llvm::StringRef{} + ... + llvm::StringRef{std::forward(args)}); + return str.str(); +} - auto* array_ty = llvm::ArrayType::get(int64_ty, values.size()); - auto* constant_array = llvm::ConstantArray::get(array_ty, constants); - auto* gv = new llvm::GlobalVariable(M, array_ty, // - true, // - llvm::GlobalValue::InternalLinkage, // - constant_array, // - name); - auto constant_zero_i32 = llvm::ConstantInt::get(llvm::Type::getInt32Ty(C), 0); - return llvm::ConstantExpr::getGetElementPtr( // - array_ty, // - gv, // - llvm::ArrayRef{constant_zero_i32, constant_zero_i32}); +template +inline std::string create_prefixed_name(Args&&... args) { + return concat(llvm::StringRef{"_typeart_"}, std::forward(args)...); } + } // namespace helper namespace typedb { -struct GlobalTypeRegistrar { - llvm::Module* module_; - llvm::StructType* struct_layout_type_; - const TypeDatabase* type_db_; - GlobalTypeRegistrar() = default; - GlobalTypeRegistrar(llvm::Module* m, llvm::StructType* struct_layout_type, const TypeDatabase* type_db) - : module_(m), struct_layout_type_(struct_layout_type), type_db_(type_db) { +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 { + return global_type_data.contains(name); } - llvm::GlobalVariable* getOrRegister(int type_id) { - llvm::GlobalVariable* global_struct_test = - new llvm::GlobalVariable(*module_, struct_layout_type_, false, llvm::GlobalValue::InternalLinkage, - nullptr, // init later - "type_id_test" - - ); - auto& context = module_->getContext(); - llvm::IRBuilder<> Builder(context); - llvm::Constant* NameStr = Builder.CreateGlobalStringPtr("sample struct", "str.name", 0, module_); - llvm::Constant* OffsetsPtr = helper::create_global_array_ptr(*module_, context, {0, 8}, "offsets.arr"); - llvm::Constant* CountPtr = helper::create_global_array_ptr(*module_, context, {1, 1}, "count.arr"); - std::vector Members = {Builder.getInt32(0), // - NameStr, // - Builder.getInt64(24), // - Builder.getInt64(2), // - OffsetsPtr, // - global_struct_test, // - CountPtr}; - llvm::Constant* TheInitializer = llvm::ConstantStruct::get(struct_layout_type_, Members); - - global_struct_test->setInitializer(TheInitializer); - return global_struct_test; + inline const TypeData& get_type(llvm::StringRef name) const { + return global_type_data.at(name); } }; -} // namespace typedb -class TypeRegistryGlobals final : public TypeRegistry { +struct GlobalTypeRegistrar { llvm::Module* module_; + const TypeDatabase* type_db_; + llvm::IRBuilder<> ir_build; llvm::StructType* struct_layout_type_; - typedb::GlobalTypeRegistrar registrar_; + GlobalTypeData global_types_; + + GlobalTypeRegistrar(llvm::Module* m, const TypeDatabase* type_db) + : module_(m), type_db_(type_db), ir_build(m->getContext()) { + declareLayout(); + } private: void declareLayout() { @@ -99,27 +97,106 @@ class TypeRegistryGlobals final : public TypeRegistry { Builder.getInt64Ty(), // size_t num_members llvm::PointerType::getUnqual(context), // const size_t* offsets llvm::PointerType::getUnqual(context), // const typeart_struct_layout_t* member_types - llvm::PointerType::getUnqual(context) // const size_t* count + llvm::PointerType::getUnqual(context), // const size_t* count + Builder.getInt32Ty(), // int type_flag }); } + llvm::GlobalVariable* create_global(llvm::StringRef name, llvm::Type* type, bool constant = true, + llvm::Constant* init = nullptr) { + llvm::GlobalVariable* global_struct = new llvm::GlobalVariable( + *module_, type, constant, llvm::GlobalValue::LinkOnceODRLinkage, init, helper::create_prefixed_name(name)); + return global_struct; + } + + llvm::Constant* create_global_constant_string(llvm::StringRef name) { + auto* name_str = ir_build.CreateGlobalStringPtr(name, helper::create_prefixed_name("typename_", name), 0, module_); + return name_str; + } + + llvm::Constant* create_global_array_ptr(const llvm::StringRef name, llvm::ArrayRef values) { + auto& context = module_->getContext(); + auto* int64_ty = llvm::Type::getInt64Ty(context); + + std::vector constants; + constants.reserve(values.size()); + for (uint64_t val : values) { + constants.push_back(llvm::ConstantInt::get(int64_ty, val)); + } + + auto* array_ty = llvm::ArrayType::get(int64_ty, values.size()); + auto* constant_array = llvm::ConstantArray::get(array_ty, constants); + auto* gv = create_global(name, array_ty, true, constant_array); + auto constant_zero_i32 = llvm::ConstantInt::get(llvm::Type::getInt32Ty(context), 0); + return llvm::ConstantExpr::getGetElementPtr( // + array_ty, // + gv, // + llvm::ArrayRef{constant_zero_i32, constant_zero_i32}); + } + + llvm::GlobalVariable* getOrRegisterBuiltin(int type_id) { + const auto name = type_db_->getTypeName(type_id); + const auto type_size = type_db_->getTypeSize(type_id); + + llvm::GlobalVariable* global_builtin_struct = create_global(name, struct_layout_type_, false); + llvm::Constant* name_str = create_global_constant_string(name); + llvm::Constant* offset_ptr = create_global_array_ptr(helper::concat("offsets_", name), {0}); + llvm::Constant* count_ptr = create_global_array_ptr(helper::concat("counts_", name), {1}); + + llvm::Constant* null_member = llvm::ConstantPointerNull::get(llvm::PointerType::getUnqual(module_->getContext())); + std::vector members = {ir_build.getInt32(type_id), // + name_str, // + ir_build.getInt64(type_size), // + ir_build.getInt64(1), // + offset_ptr, // + null_member, // + count_ptr, + ir_build.getInt32(static_cast(StructTypeFlag::USER_DEFINED))}; + llvm::Constant* init = llvm::ConstantStruct::get(struct_layout_type_, members); + + global_builtin_struct->setInitializer(init); + + global_types_.global_type_data.try_emplace( + name, GlobalTypeData::TypeData{init, global_builtin_struct, name_str, offset_ptr, count_ptr}); + + return global_builtin_struct; + } + public: - TypeRegistryGlobals(llvm::Module& m, const TypeDatabase* type_db) : module_(&m) { - declareLayout(); - registrar_ = typedb::GlobalTypeRegistrar(module_, struct_layout_type_, type_db); + llvm::GlobalVariable* getOrRegister(int type_id) { + const auto name = type_db_->getTypeName(type_id); + + if (global_types_.has_type_name(name)) { + return global_types_.get_type(name).type; + } + + const bool is_builtin = type_db_->isBuiltinType(type_id); + if (is_builtin) { + return getOrRegisterBuiltin(type_id); + } + // TODO handle user def type + return nullptr; + } +}; +} // namespace typedb + +class TypeRegistryGlobals final : public TypeRegistry { + llvm::Module* module_; + typedb::GlobalTypeRegistrar registrar_; + + public: + TypeRegistryGlobals(llvm::Module& m, const TypeDatabase* type_db) : module_(&m), registrar_(&m, type_db) { } llvm::Value* getOrRegister(llvm::Value* type_id_const) override { - auto* constant_int = llvm::dyn_cast(type_id_const); - const int type_id = static_cast(constant_int->getSExtValue()); - return registrar_.getOrRegister(type_id); + return registrar_.getOrRegister(helper::get_type_id(type_id_const)); } }; -std::unique_ptr get_type_id_handler(llvm::Module& m, const TypeDatabase* type_gen, +std::unique_ptr get_type_id_handler(llvm::Module& m, const TypeDatabase* type_db, const config::Configuration& configuration) { if (configuration[config::ConfigStdArgs::instrumentation]) { - return std::make_unique(m, type_gen); + return std::make_unique(m, type_db); } return std::make_unique(); } diff --git a/lib/passes/typegen/TypeGenerator.h b/lib/passes/typegen/TypeGenerator.h index 977c228e..53412181 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" @@ -64,4 +64,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/test/pass/inline_types/01_simple_malloc_int.c b/test/pass/inline_types/01_simple_malloc_int.c index 0068a389..9c35a0f9 100644 --- a/test/pass/inline_types/01_simple_malloc_int.c +++ b/test/pass/inline_types/01_simple_malloc_int.c @@ -1,5 +1,7 @@ // clang-format off // RUN: %c-to-llvm %s | %apply-typeart -typeart-instumentation=true -S 2>&1 | %filecheck %s + +// REQUIRES: llvm-18 || llvm-19 // clang-format on #include @@ -11,6 +13,6 @@ void test() { // CHECK-NEXT: Free{{[ ]*}}:{{[ ]*}}0 // CHECK-NEXT: Alloca{{[ ]*}}:{{[ ]*}}0 -// CHECK: %struct.typeart_struct_layout_t = type { i32, ptr, i64, i64, ptr, ptr, ptr } -// CHECK: [[POINTER:%[0-9a-z]+]] = call noalias{{( align [0-9]+)?}} {{i8\*|ptr}} @malloc -// CHECK-NEXT: call void @__typeart_alloc_mty({{i8\*|ptr}} [[POINTER]], ptr {{.*}}, i64 42) +// CHECK: %struct.typeart_struct_layout_t = type { i32, ptr, i64, i64, ptr, ptr, ptr, i32 } +// CHECK: [[POINTER:%[0-9a-z]+]] = call noalias{{( align [0-9]+)?}} ptr @malloc +// CHECK-NEXT: call void @__typeart_alloc_mty(ptr [[POINTER]], ptr {{.*}}, 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..14a32a43 --- /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-instumentation=true -S 2>&1 | %filecheck %s --check-prefix=REALLOC +// RUN: %c-to-llvm %s | %apply-typeart -typeart-instumentation=true -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 From f821965989e71a0c6dbbbd73d5b361b97842ed9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20H=C3=BCck?= Date: Sat, 25 Oct 2025 18:28:23 +0200 Subject: [PATCH 05/35] Serialize user def structs --- lib/passes/instrumentation/TypeIDProvider.cpp | 99 ++++++++++++++----- .../inline_types/03_simple_malloc_struct.c | 25 +++++ 2 files changed, 101 insertions(+), 23 deletions(-) create mode 100644 test/pass/inline_types/03_simple_malloc_struct.c diff --git a/lib/passes/instrumentation/TypeIDProvider.cpp b/lib/passes/instrumentation/TypeIDProvider.cpp index 81013024..2de55682 100644 --- a/lib/passes/instrumentation/TypeIDProvider.cpp +++ b/lib/passes/instrumentation/TypeIDProvider.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -134,32 +135,85 @@ struct GlobalTypeRegistrar { llvm::ArrayRef{constant_zero_i32, constant_zero_i32}); } - llvm::GlobalVariable* getOrRegisterBuiltin(int type_id) { - const auto name = type_db_->getTypeName(type_id); - const auto type_size = type_db_->getTypeSize(type_id); + 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) { + llvm::GlobalVariable* global_struct = create_global(name, struct_layout_type_, false); + llvm::Constant* name_str = create_global_constant_string(name); - llvm::GlobalVariable* global_builtin_struct = create_global(name, struct_layout_type_, false); - llvm::Constant* name_str = create_global_constant_string(name); - llvm::Constant* offset_ptr = create_global_array_ptr(helper::concat("offsets_", name), {0}); - llvm::Constant* count_ptr = create_global_array_ptr(helper::concat("counts_", name), {1}); + std::vector members = { + ir_build.getInt32(type_id), + name_str, + ir_build.getInt64(type_size), + ir_build.getInt64(member_count), + offset_ptr, + members_data_ptr, + count_ptr, + ir_build.getInt32(static_cast(StructTypeFlag::USER_DEFINED))}; // TODO: use real type - llvm::Constant* null_member = llvm::ConstantPointerNull::get(llvm::PointerType::getUnqual(module_->getContext())); - std::vector members = {ir_build.getInt32(type_id), // - name_str, // - ir_build.getInt64(type_size), // - ir_build.getInt64(1), // - offset_ptr, // - null_member, // - count_ptr, - ir_build.getInt32(static_cast(StructTypeFlag::USER_DEFINED))}; - llvm::Constant* init = llvm::ConstantStruct::get(struct_layout_type_, members); + llvm::Constant* init = llvm::ConstantStruct::get(struct_layout_type_, members); - global_builtin_struct->setInitializer(init); + global_struct->setInitializer(init); global_types_.global_type_data.try_emplace( - name, GlobalTypeData::TypeData{init, global_builtin_struct, name_str, offset_ptr, count_ptr}); + name, GlobalTypeData::TypeData{init, global_struct, name_str, offset_ptr, count_ptr}); - return global_builtin_struct; + return global_struct; + } + + llvm::GlobalVariable* registerBuiltin(int type_id) { + // struct StructTypeInfo { + // int type_id; + // std::string name; + // size_t extent; + // size_t num_members; + // std::vector offsets; + // std::vector member_types; + // std::vector array_sizes; + // StructTypeFlag flag; + // }; + StructTypeInfo type_struct{type_id, type_db_->getTypeName(type_id), type_db_->getTypeSize(type_id), 1, {0}, {}, + {1}, StructTypeFlag::USER_DEFINED}; + return registerTypeStruct(&type_struct); + } + + llvm::GlobalVariable* registerTypeStruct(const StructTypeInfo* type_struct) { + const auto name = type_struct->name; + const auto type_size = type_struct->extent; + + 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; + std::optional ptr_type; // 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) { + ptr_type.emplace(member->getType()); + } + member_types.emplace_back(member); + } + + const auto member_count = type_struct->member_types.size(); + if (ptr_type) { + assert(member_count == type_struct->num_members); + llvm::ArrayType* member_array_ty = llvm::ArrayType::get(ptr_type.value(), 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, true, init); + } else { + llvm::Constant* null_member = llvm::ConstantPointerNull::get(llvm::PointerType::getUnqual(module_->getContext())); + members_array = null_member; + } + + return registerGlobalStruct(name, type_struct->type_id, type_size, member_count, offset_ptr, members_array, + count_ptr); + } + + llvm::GlobalVariable* registerUserDefined(int type_id) { + const auto type_struct = type_db_->getStructInfo(type_id); + return registerTypeStruct(type_struct); } public: @@ -172,10 +226,9 @@ struct GlobalTypeRegistrar { const bool is_builtin = type_db_->isBuiltinType(type_id); if (is_builtin) { - return getOrRegisterBuiltin(type_id); + return registerBuiltin(type_id); } - // TODO handle user def type - return nullptr; + return registerUserDefined(type_id); } }; } // namespace typedb 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..817b3eb5 --- /dev/null +++ b/test/pass/inline_types/03_simple_malloc_struct.c @@ -0,0 +1,25 @@ +// clang-format off +// RUN: %c-to-llvm %s | %apply-typeart -typeart-instumentation=true -S 2>&1 | %filecheck %s + +// 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]]) From 6d66befced5b63477621fd26f278530910c11d88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20H=C3=BCck?= Date: Sun, 26 Oct 2025 10:33:12 +0100 Subject: [PATCH 06/35] Runtime test setup --- .../EnvironmentConfiguration.cpp | 4 +++ lib/passes/instrumentation/TypeIDProvider.cpp | 11 +++++--- lib/runtime/AllocationTracking.cpp | 12 ++++++-- lib/runtime/CallbackInterface.h | 5 ++++ lib/support/ConfigurationBaseOptions.h | 3 +- test/CMakeLists.txt | 1 + .../01_simple_malloc_int.c | 17 +++++++++++ .../02_simple_malloc_int_multi_tu.c | 28 +++++++++++++++++++ 8 files changed, 74 insertions(+), 7 deletions(-) create mode 100644 test/runtime_inlined_types/01_simple_malloc_int.c create mode 100644 test/runtime_inlined_types/02_simple_malloc_int_multi_tu.c diff --git a/lib/passes/configuration/EnvironmentConfiguration.cpp b/lib/passes/configuration/EnvironmentConfiguration.cpp index 339ff524..1a706457 100644 --- a/lib/passes/configuration/EnvironmentConfiguration.cpp +++ b/lib/passes/configuration/EnvironmentConfiguration.cpp @@ -113,6 +113,9 @@ EnvironmentFlagsOptions::EnvironmentFlagsOptions() { EnvironmentStdArgsValues::global), make_entry(ConfigStdArgs::stack, EnvironmentStdArgs::stack, EnvironmentStdArgsValues::stack), + make_entry(ConfigStdArgs::instrumentation, + EnvironmentStdArgs::instrumentation, + EnvironmentStdArgsValues::instrumentation), make_entry( ConfigStdArgs::stack_lifetime, EnvironmentStdArgs::stack_lifetime, EnvironmentStdArgsValues::stack_lifetime), make_entry(ConfigStdArgs::typegen, EnvironmentStdArgs::typegen, @@ -148,6 +151,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::instrumentation, EnvironmentStdArgs::instrumentation), 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/instrumentation/TypeIDProvider.cpp b/lib/passes/instrumentation/TypeIDProvider.cpp index 2de55682..2f46d6d8 100644 --- a/lib/passes/instrumentation/TypeIDProvider.cpp +++ b/lib/passes/instrumentation/TypeIDProvider.cpp @@ -105,13 +105,16 @@ struct GlobalTypeRegistrar { llvm::GlobalVariable* create_global(llvm::StringRef name, llvm::Type* type, bool constant = true, llvm::Constant* init = nullptr) { + // TODO: https://llvm.org/docs/LangRef.html#linkage w.r.t. forward declared types llvm::GlobalVariable* global_struct = new llvm::GlobalVariable( - *module_, type, constant, llvm::GlobalValue::LinkOnceODRLinkage, init, helper::create_prefixed_name(name)); + *module_, type, constant, llvm::GlobalValue::LinkOnceAnyLinkage, init, helper::create_prefixed_name(name)); return global_struct; } 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_); + return name_str; } @@ -185,13 +188,13 @@ struct GlobalTypeRegistrar { llvm::Constant* count_ptr = create_global_array_ptr(helper::concat("counts_", name), type_struct->array_sizes); llvm::Constant* members_array; - std::optional ptr_type; // TODO: make this unqual? + 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) { - ptr_type.emplace(member->getType()); + ptr_type = member->getType(); } member_types.emplace_back(member); } @@ -199,7 +202,7 @@ struct GlobalTypeRegistrar { const auto member_count = type_struct->member_types.size(); if (ptr_type) { assert(member_count == type_struct->num_members); - llvm::ArrayType* member_array_ty = llvm::ArrayType::get(ptr_type.value(), member_count); + 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, true, init); } else { diff --git a/lib/runtime/AllocationTracking.cpp b/lib/runtime/AllocationTracking.cpp index 54735548..d1349775 100644 --- a/lib/runtime/AllocationTracking.cpp +++ b/lib/runtime/AllocationTracking.cpp @@ -18,6 +18,7 @@ #include "RuntimeData.h" #include "TypeDB.h" #include "support/Logger.h" +#include "typelib/TypeDatabase.h" #include "llvm/Support/raw_ostream.h" @@ -171,8 +172,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; } @@ -286,3 +286,11 @@ void __typeart_leave_scope_omp(int alloca_count) { const void* retAddr = __builtin_return_address(0); typeart::RuntimeSystem::get().allocTracker.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* info_struct = reinterpret_cast(info); + // LOG_MSG("Callback with " << intptr_t(addr) << " " << info_struct->type_id); + typeart::RuntimeSystem::get().allocTracker.onAllocStack(addr, info_struct->type_id, count, retAddr); +} \ No newline at end of file diff --git a/lib/runtime/CallbackInterface.h b/lib/runtime/CallbackInterface.h index fa1371c9..3def54e4 100644 --- a/lib/runtime/CallbackInterface.h +++ b/lib/runtime/CallbackInterface.h @@ -36,6 +36,11 @@ 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); #ifdef __cplusplus } #endif diff --git a/lib/support/ConfigurationBaseOptions.h b/lib/support/ConfigurationBaseOptions.h index 74c3e9ef..6496f010 100644 --- a/lib/support/ConfigurationBaseOptions.h +++ b/lib/support/ConfigurationBaseOptions.h @@ -44,6 +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(instrumentation, "instumentation", bool, true, "Instrument with module local types.", "HEAP") +TYPEART_CONFIG_OPTION(instrumentation, "instumentation", bool, true, "Instrument with module local types.", + "INSTRUMENTATION") #undef TYPEART_CONFIG_OPTION 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/runtime_inlined_types/01_simple_malloc_int.c b/test/runtime_inlined_types/01_simple_malloc_int.c new file mode 100644 index 00000000..111d5afb --- /dev/null +++ b/test/runtime_inlined_types/01_simple_malloc_int.c @@ -0,0 +1,17 @@ +// clang-format off +// RUN: export TYPEART_INSTRUMENTATION=1 +// 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 : 0 , 1 , 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..dd9932f6 --- /dev/null +++ b/test/runtime_inlined_types/02_simple_malloc_int_multi_tu.c @@ -0,0 +1,28 @@ +// clang-format off +// RUN: export TYPEART_INSTRUMENTATION=1 +// 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 : 0 , 2 , 0 , int \ No newline at end of file From 9e62d3d3a0b1746efb2fab5f7856af5705101813 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20H=C3=BCck?= Date: Mon, 27 Oct 2025 14:17:27 +0100 Subject: [PATCH 07/35] Handle forward declared types by parsing all CU types --- .clang-tidy | 1 - lib/passes/TypeARTPass.cpp | 26 ++++++++++++------- lib/passes/configuration/PassBuilderUtil.h | 4 +-- lib/passes/configuration/TypeARTOptions.cpp | 4 +-- lib/passes/filter/FilterUtil.h | 8 ++++-- lib/passes/instrumentation/TypeIDProvider.cpp | 21 +++++++++++---- lib/passes/instrumentation/TypeIDProvider.h | 3 ++- lib/passes/typegen/TypeGenerator.cpp | 3 ++- lib/passes/typegen/TypeGenerator.h | 6 ++++- lib/passes/typegen/TypeIDGenerator.h | 2 +- lib/passes/typegen/dimeta/DimetaTypeGen.cpp | 8 ++++-- 11 files changed, 58 insertions(+), 28 deletions(-) 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/lib/passes/TypeARTPass.cpp b/lib/passes/TypeARTPass.cpp index e3d329be..ba85e40d 100644 --- a/lib/passes/TypeARTPass.cpp +++ b/lib/passes/TypeARTPass.cpp @@ -153,11 +153,16 @@ 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()); + 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]; @@ -174,16 +179,17 @@ 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()); + if (!configuration()[config::ConfigStdArgs::instrumentation]) { + 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(); 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/TypeARTOptions.cpp b/lib/passes/configuration/TypeARTOptions.cpp index 00a1d113..71c0922d 100644 --- a/lib/passes/configuration/TypeARTOptions.cpp +++ b/lib/passes/configuration/TypeARTOptions.cpp @@ -160,8 +160,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 { 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/TypeIDProvider.cpp b/lib/passes/instrumentation/TypeIDProvider.cpp index 2f46d6d8..8f91909c 100644 --- a/lib/passes/instrumentation/TypeIDProvider.cpp +++ b/lib/passes/instrumentation/TypeIDProvider.cpp @@ -4,6 +4,7 @@ #include "TypeInterface.h" #include "configuration/Configuration.h" #include "support/ConfigurationBase.h" +#include "support/Logger.h" #include #include @@ -22,6 +23,9 @@ namespace typeart { +void TypeRegistry::registerModule(const ModuleData&) { +} + class TypeRegistryNoOp final : public TypeRegistry { public: llvm::Value* getOrRegister(llvm::Value* type_id_const) override { @@ -106,8 +110,8 @@ struct GlobalTypeRegistrar { llvm::GlobalVariable* create_global(llvm::StringRef name, llvm::Type* type, bool constant = true, llvm::Constant* init = nullptr) { // TODO: https://llvm.org/docs/LangRef.html#linkage w.r.t. forward declared types - llvm::GlobalVariable* global_struct = new llvm::GlobalVariable( - *module_, type, constant, llvm::GlobalValue::LinkOnceAnyLinkage, init, helper::create_prefixed_name(name)); + auto* global_struct = new llvm::GlobalVariable(*module_, type, constant, llvm::GlobalValue::LinkOnceAnyLinkage, + init, helper::create_prefixed_name(name)); return global_struct; } @@ -193,14 +197,14 @@ struct GlobalTypeRegistrar { for (auto member_type_id : type_struct->member_types) { llvm::Constant* member = getOrRegister(member_type_id); - if (!ptr_type) { + 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) { + 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); @@ -215,7 +219,7 @@ struct GlobalTypeRegistrar { } llvm::GlobalVariable* registerUserDefined(int type_id) { - const auto type_struct = type_db_->getStructInfo(type_id); + const auto* const type_struct = type_db_->getStructInfo(type_id); return registerTypeStruct(type_struct); } @@ -244,6 +248,13 @@ class TypeRegistryGlobals final : public TypeRegistry { TypeRegistryGlobals(llvm::Module& m, const TypeDatabase* type_db) : module_(&m), registrar_(&m, type_db) { } + void registerModule(const ModuleData& m) override { + for (const auto& type : m.types_list) { + const auto type_id = registrar_.getOrRegister(type.type_id); + LOG_DEBUG("Registering type_id " << type_id) + } + } + llvm::Value* getOrRegister(llvm::Value* type_id_const) override { return registrar_.getOrRegister(helper::get_type_id(type_id_const)); } diff --git a/lib/passes/instrumentation/TypeIDProvider.h b/lib/passes/instrumentation/TypeIDProvider.h index 586be84c..7b9cb47a 100644 --- a/lib/passes/instrumentation/TypeIDProvider.h +++ b/lib/passes/instrumentation/TypeIDProvider.h @@ -20,7 +20,8 @@ class Configuration; class TypeRegistry { public: virtual llvm::Value* getOrRegister(llvm::Value* type_id_const) = 0; - virtual ~TypeRegistry() = default; + virtual void registerModule(const ModuleData&); + virtual ~TypeRegistry() = default; }; std::unique_ptr get_type_id_handler(llvm::Module& m, const TypeDatabase* type_db, diff --git a/lib/passes/typegen/TypeGenerator.cpp b/lib/passes/typegen/TypeGenerator.cpp index 176aa30c..9517e431 100644 --- a/lib/passes/typegen/TypeGenerator.cpp +++ b/lib/passes/typegen/TypeGenerator.cpp @@ -58,7 +58,8 @@ const TypeDatabase& TypeIDGenerator::getTypeDatabase() const { return *this->typeDB.get(); } -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 53412181..20d1c501 100644 --- a/lib/passes/typegen/TypeGenerator.h +++ b/lib/passes/typegen/TypeGenerator.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; 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..6adcbfb7 100644 --- a/lib/passes/typegen/dimeta/DimetaTypeGen.cpp +++ b/lib/passes/typegen/dimeta/DimetaTypeGen.cpp @@ -502,19 +502,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 { From b54a11b986736b2f938b3bdf8c6d954938b855b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20H=C3=BCck?= Date: Mon, 27 Oct 2025 16:47:34 +0100 Subject: [PATCH 08/35] Fix introducing same globals multiple times --- lib/passes/TypeARTPass.cpp | 1 + lib/passes/instrumentation/TypeIDProvider.cpp | 64 +++++++++++++------ lib/runtime/AllocationTracking.cpp | 2 +- .../02_simple_malloc_int_multi_tu.c | 4 ++ 4 files changed, 49 insertions(+), 22 deletions(-) diff --git a/lib/passes/TypeARTPass.cpp b/lib/passes/TypeARTPass.cpp index ba85e40d..9f549ac3 100644 --- a/lib/passes/TypeARTPass.cpp +++ b/lib/passes/TypeARTPass.cpp @@ -158,6 +158,7 @@ class TypeArtPass : public llvm::PassInfoMixin { declareInstrumentationFunctions(m); { auto type_id_handler = get_type_id_handler(m, &typeManager->getTypeDatabase(), configuration()); + // const bool heap = configuration()[config::ConfigStdArgs::heap]; if (has_cu_types) { LOG_DEBUG("Registering compilation unit types list") type_id_handler->registerModule(mdata); diff --git a/lib/passes/instrumentation/TypeIDProvider.cpp b/lib/passes/instrumentation/TypeIDProvider.cpp index 8f91909c..edfb3fd0 100644 --- a/lib/passes/instrumentation/TypeIDProvider.cpp +++ b/lib/passes/instrumentation/TypeIDProvider.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -107,19 +108,26 @@ struct GlobalTypeRegistrar { }); } - llvm::GlobalVariable* create_global(llvm::StringRef name, llvm::Type* type, bool constant = true, - llvm::Constant* init = nullptr) { + llvm::GlobalVariable* create_global( + llvm::StringRef name, llvm::Type* type, llvm::Constant* init = nullptr, + llvm::GlobalVariable::LinkageTypes link_type = llvm::GlobalValue::WeakODRLinkage) { // TODO: https://llvm.org/docs/LangRef.html#linkage w.r.t. forward declared types - auto* global_struct = new llvm::GlobalVariable(*module_, type, constant, llvm::GlobalValue::LinkOnceAnyLinkage, - init, helper::create_prefixed_name(name)); + auto* global_struct = + new llvm::GlobalVariable(*module_, type, true, link_type, init, helper::create_prefixed_name(name)); return global_struct; } 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_); - - return name_str; + // 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); + auto* i32_zero = llvm::ConstantInt::get(llvm::Type::getInt32Ty(module_->getContext()), 0); + return llvm::ConstantExpr::getInBoundsGetElementPtr(global_string->getValueType(), global_string, + llvm::ArrayRef{i32_zero, i32_zero}); } llvm::Constant* create_global_array_ptr(const llvm::StringRef name, llvm::ArrayRef values) { @@ -134,7 +142,7 @@ struct GlobalTypeRegistrar { auto* array_ty = llvm::ArrayType::get(int64_ty, values.size()); auto* constant_array = llvm::ConstantArray::get(array_ty, constants); - auto* gv = create_global(name, array_ty, true, constant_array); + auto* gv = create_global(name, array_ty, constant_array); auto constant_zero_i32 = llvm::ConstantInt::get(llvm::Type::getInt32Ty(context), 0); return llvm::ConstantExpr::getGetElementPtr( // array_ty, // @@ -145,7 +153,7 @@ struct GlobalTypeRegistrar { 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) { - llvm::GlobalVariable* global_struct = create_global(name, struct_layout_type_, false); + llvm::GlobalVariable* global_struct = create_global(name, struct_layout_type_); llvm::Constant* name_str = create_global_constant_string(name); std::vector members = { @@ -168,6 +176,17 @@ struct GlobalTypeRegistrar { return global_struct; } + llvm::GlobalVariable* registerGlobalStructDecl(const std::string& name) { + auto* global_struct = create_global(name, struct_layout_type_, nullptr, llvm::GlobalValue::ExternalWeakLinkage); + // new llvm::GlobalVariable(*module_, struct_layout_type_, true, llvm::GlobalValue::ExternalWeakLinkage, nullptr, + // helper::create_prefixed_name(name)); + // llvm::Constant* name_str = create_global_constant_string(name); + global_types_.global_type_data.try_emplace( + name, GlobalTypeData::TypeData{nullptr, global_struct, nullptr, nullptr, nullptr}); + + return global_struct; + } + llvm::GlobalVariable* registerBuiltin(int type_id) { // struct StructTypeInfo { // int type_id; @@ -188,6 +207,10 @@ struct GlobalTypeRegistrar { const auto name = type_struct->name; const auto type_size = type_struct->extent; + if (type_struct->flag == StructTypeFlag::FWD_DECL) { + 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); @@ -208,7 +231,7 @@ struct GlobalTypeRegistrar { 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, true, init); + members_array = create_global(helper::concat("member_types_", name), member_array_ty, init); } else { llvm::Constant* null_member = llvm::ConstantPointerNull::get(llvm::PointerType::getUnqual(module_->getContext())); members_array = null_member; @@ -224,18 +247,17 @@ struct GlobalTypeRegistrar { } public: - llvm::GlobalVariable* getOrRegister(int type_id) { + llvm::Constant* getOrRegister(int type_id) { const auto name = type_db_->getTypeName(type_id); - - if (global_types_.has_type_name(name)) { - return global_types_.get_type(name).type; - } - - const bool is_builtin = type_db_->isBuiltinType(type_id); - if (is_builtin) { - return registerBuiltin(type_id); - } - return registerUserDefined(type_id); + return module_->getOrInsertGlobal(helper::create_prefixed_name(name), struct_layout_type_, + [&]() -> llvm::GlobalVariable* { + LOG_DEBUG("Registering << " << type_id << " " << name) + const bool is_builtin = type_db_->isBuiltinType(type_id); + if (is_builtin) { + return registerBuiltin(type_id); + } + return registerUserDefined(type_id); + }); } }; } // namespace typedb diff --git a/lib/runtime/AllocationTracking.cpp b/lib/runtime/AllocationTracking.cpp index d1349775..222e8891 100644 --- a/lib/runtime/AllocationTracking.cpp +++ b/lib/runtime/AllocationTracking.cpp @@ -291,6 +291,6 @@ 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* info_struct = reinterpret_cast(info); - // LOG_MSG("Callback with " << intptr_t(addr) << " " << info_struct->type_id); + LOG_MSG("Callback with " << intptr_t(info) << " " << info_struct->type_id); typeart::RuntimeSystem::get().allocTracker.onAllocStack(addr, info_struct->type_id, count, retAddr); } \ 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 index dd9932f6..c09e2d9e 100644 --- a/test/runtime_inlined_types/02_simple_malloc_int_multi_tu.c +++ b/test/runtime_inlined_types/02_simple_malloc_int_multi_tu.c @@ -1,5 +1,9 @@ // clang-format off // RUN: export TYPEART_INSTRUMENTATION=1 + +// : %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 From 6e964805d946c0ccd0c3760b22548ed0fee1ef89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20H=C3=BCck?= Date: Mon, 27 Oct 2025 17:11:50 +0100 Subject: [PATCH 09/35] Fwd decl test --- test/pass/inline_types/04_fwd_decl.cpp | 32 ++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 test/pass/inline_types/04_fwd_decl.cpp 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..15bbcbfa --- /dev/null +++ b/test/pass/inline_types/04_fwd_decl.cpp @@ -0,0 +1,32 @@ +// RUN: export TYPEART_INSTRUMENTATION=1 + +// RUN: %cpp-to-llvm %s | %apply-typeart -typeart-instumentation=true -S | %filecheck --match-full-lines %s + +// CHECK: @_typeart__ZTS6Domain = extern_weak constant %struct.typeart_struct_layout_t + +// 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(); +} From 8bb2c95e9235539125a280e17f8bf45507ffcf0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20H=C3=BCck?= Date: Tue, 28 Oct 2025 11:03:45 +0100 Subject: [PATCH 10/35] Constructor function to register global types --- lib/passes/TypeARTPass.cpp | 2 +- lib/passes/analysis/MemInstFinder.cpp | 2 +- .../instrumentation/TypeARTFunctions.cpp | 2 + lib/passes/instrumentation/TypeARTFunctions.h | 12 +- lib/passes/instrumentation/TypeIDProvider.cpp | 118 +++++++++++++++--- lib/passes/instrumentation/TypeIDProvider.h | 4 +- test/pass/inline_types/01_simple_malloc_int.c | 2 +- test/pass/inline_types/04_fwd_decl.cpp | 2 +- 8 files changed, 110 insertions(+), 34 deletions(-) diff --git a/lib/passes/TypeARTPass.cpp b/lib/passes/TypeARTPass.cpp index 9f549ac3..318d5ca3 100644 --- a/lib/passes/TypeARTPass.cpp +++ b/lib/passes/TypeARTPass.cpp @@ -157,7 +157,7 @@ class TypeArtPass : public llvm::PassInfoMixin { declareInstrumentationFunctions(m); { - auto type_id_handler = get_type_id_handler(m, &typeManager->getTypeDatabase(), configuration()); + 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") 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/instrumentation/TypeARTFunctions.cpp b/lib/passes/instrumentation/TypeARTFunctions.cpp index ff8e32ae..acf435d0 100644 --- a/lib/passes/instrumentation/TypeARTFunctions.cpp +++ b/lib/passes/instrumentation/TypeARTFunctions.cpp @@ -253,6 +253,7 @@ TypeArtFunc typeart_free_omp = typeart_free; TypeArtFunc typeart_leave_scope_omp = typeart_leave_scope; TypeArtFunc typeart_alloc_mty{"__typeart_alloc_mty"}; +TypeArtFunc typeart_register_type{"__typeart_register_type"}; } // namespace callbacks @@ -272,6 +273,7 @@ std::unique_ptr declare_instrumentation_functions(llvm::Module& if (module_local_types) { auto alloc_arg_types_mty = instrumentation_helper.make_parameters(IType::ptr, IType::ptr, IType::extent); typeart_alloc.f = decl.make_function(IFunc::heap, typeart_alloc_mty.name, alloc_arg_types_mty); + typeart_register_type.f = decl.make_function(IFunc::type, typeart_register_type.name, free_arg_types); } else { typeart_alloc.f = decl.make_function(IFunc::heap, typeart_alloc.name, alloc_arg_types); } diff --git a/lib/passes/instrumentation/TypeARTFunctions.h b/lib/passes/instrumentation/TypeARTFunctions.h index 64bddf6e..7edbcfc0 100644 --- a/lib/passes/instrumentation/TypeARTFunctions.h +++ b/lib/passes/instrumentation/TypeARTFunctions.h @@ -31,17 +31,7 @@ namespace config { class Configuration; } -enum class IFunc : unsigned { - heap, - stack, - global, - free, - scope, - heap_omp, - stack_omp, - free_omp, - scope_omp, -}; +enum class IFunc : unsigned { heap, stack, global, free, scope, heap_omp, stack_omp, free_omp, scope_omp, type }; IFunc ifunc_for_function(IFunc general_type, llvm::Value* value); diff --git a/lib/passes/instrumentation/TypeIDProvider.cpp b/lib/passes/instrumentation/TypeIDProvider.cpp index edfb3fd0..43521388 100644 --- a/lib/passes/instrumentation/TypeIDProvider.cpp +++ b/lib/passes/instrumentation/TypeIDProvider.cpp @@ -3,20 +3,26 @@ #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 @@ -79,15 +85,80 @@ struct GlobalTypeData { } }; +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); + // llvm::IRBuilder<> Builder(entry); + ret_inst->insertInto(entry, entry->getFirstInsertionPt()); + // Builder.CreateRetVoid(); + + 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}); + } +}; + struct GlobalTypeRegistrar { llvm::Module* module_; const TypeDatabase* type_db_; llvm::IRBuilder<> ir_build; + GlobalTypeCallback type_callback; llvm::StructType* struct_layout_type_; GlobalTypeData global_types_; - GlobalTypeRegistrar(llvm::Module* m, const TypeDatabase* type_db) - : module_(m), type_db_(type_db), ir_build(m->getContext()) { + 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) { declareLayout(); } @@ -95,7 +166,7 @@ struct GlobalTypeRegistrar { void declareLayout() { auto& context = module_->getContext(); llvm::IRBuilder<> Builder(context); - struct_layout_type_ = llvm::StructType::create(context, "struct.typeart_struct_layout_t"); + struct_layout_type_ = llvm::StructType::create(context, "struct._typeart_struct_layout_t"); struct_layout_type_->setBody({ Builder.getInt32Ty(), // int type_id llvm::PointerType::getUnqual(context), // const char* name @@ -110,7 +181,7 @@ struct GlobalTypeRegistrar { llvm::GlobalVariable* create_global( llvm::StringRef name, llvm::Type* type, llvm::Constant* init = nullptr, - llvm::GlobalVariable::LinkageTypes link_type = llvm::GlobalValue::WeakODRLinkage) { + 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)); @@ -200,7 +271,9 @@ struct GlobalTypeRegistrar { // }; StructTypeInfo type_struct{type_id, type_db_->getTypeName(type_id), type_db_->getTypeSize(type_id), 1, {0}, {}, {1}, StructTypeFlag::USER_DEFINED}; - return registerTypeStruct(&type_struct); + + auto global = registerTypeStruct(&type_struct); + return global; } llvm::GlobalVariable* registerTypeStruct(const StructTypeInfo* type_struct) { @@ -249,15 +322,22 @@ struct GlobalTypeRegistrar { public: llvm::Constant* getOrRegister(int type_id) { const auto name = type_db_->getTypeName(type_id); - return module_->getOrInsertGlobal(helper::create_prefixed_name(name), struct_layout_type_, - [&]() -> llvm::GlobalVariable* { - LOG_DEBUG("Registering << " << type_id << " " << name) - const bool is_builtin = type_db_->isBuiltinType(type_id); - if (is_builtin) { - return registerBuiltin(type_id); - } - return registerUserDefined(type_id); - }); + return module_->getOrInsertGlobal( + helper::create_prefixed_name(name), struct_layout_type_, [&]() -> llvm::GlobalVariable* { + LOG_DEBUG("Registering << " << type_id << " " << 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) { + type_callback.insert(global); + } + return global; + }); } }; } // namespace typedb @@ -267,13 +347,14 @@ class TypeRegistryGlobals final : public TypeRegistry { typedb::GlobalTypeRegistrar registrar_; public: - TypeRegistryGlobals(llvm::Module& m, const TypeDatabase* type_db) : module_(&m), registrar_(&m, type_db) { + TypeRegistryGlobals(llvm::Module& m, const TypeDatabase* type_db, const TAFunctionQuery* f_query) + : module_(&m), registrar_(&m, type_db, f_query) { } void registerModule(const ModuleData& m) override { for (const auto& type : m.types_list) { const auto type_id = registrar_.getOrRegister(type.type_id); - LOG_DEBUG("Registering type_id " << type_id) + LOG_DEBUG("Registering type_id " << *type_id) } } @@ -283,9 +364,10 @@ class TypeRegistryGlobals final : public TypeRegistry { }; std::unique_ptr get_type_id_handler(llvm::Module& m, const TypeDatabase* type_db, - const config::Configuration& configuration) { + const config::Configuration& configuration, + const TAFunctionQuery* f_query) { if (configuration[config::ConfigStdArgs::instrumentation]) { - return std::make_unique(m, type_db); + return std::make_unique(m, type_db, f_query); } return std::make_unique(); } diff --git a/lib/passes/instrumentation/TypeIDProvider.h b/lib/passes/instrumentation/TypeIDProvider.h index 7b9cb47a..585e997e 100644 --- a/lib/passes/instrumentation/TypeIDProvider.h +++ b/lib/passes/instrumentation/TypeIDProvider.h @@ -1,6 +1,7 @@ #ifndef LIB_PASSES_INSTRUMENTATION_MODULETYPEREGISTRY #define LIB_PASSES_INSTRUMENTATION_MODULETYPEREGISTRY +#include "TypeARTFunctions.h" #include "TypeDatabase.h" #include "TypeGenerator.h" @@ -25,7 +26,8 @@ class TypeRegistry { }; std::unique_ptr get_type_id_handler(llvm::Module& m, const TypeDatabase* type_db, - const config::Configuration& configuration); + const config::Configuration& configuration, + const TAFunctionQuery* f_query); } // namespace typeart diff --git a/test/pass/inline_types/01_simple_malloc_int.c b/test/pass/inline_types/01_simple_malloc_int.c index 9c35a0f9..4fe6e0b1 100644 --- a/test/pass/inline_types/01_simple_malloc_int.c +++ b/test/pass/inline_types/01_simple_malloc_int.c @@ -13,6 +13,6 @@ void test() { // CHECK-NEXT: Free{{[ ]*}}:{{[ ]*}}0 // CHECK-NEXT: Alloca{{[ ]*}}:{{[ ]*}}0 -// CHECK: %struct.typeart_struct_layout_t = type { i32, ptr, i64, i64, ptr, ptr, ptr, i32 } +// CHECK: %struct._typeart_struct_layout_t = type { i32, ptr, i64, i64, ptr, ptr, ptr, i32 } // CHECK: [[POINTER:%[0-9a-z]+]] = call noalias{{( align [0-9]+)?}} ptr @malloc // CHECK-NEXT: call void @__typeart_alloc_mty(ptr [[POINTER]], ptr {{.*}}, i64 42) diff --git a/test/pass/inline_types/04_fwd_decl.cpp b/test/pass/inline_types/04_fwd_decl.cpp index 15bbcbfa..8ceb8c06 100644 --- a/test/pass/inline_types/04_fwd_decl.cpp +++ b/test/pass/inline_types/04_fwd_decl.cpp @@ -2,7 +2,7 @@ // RUN: %cpp-to-llvm %s | %apply-typeart -typeart-instumentation=true -S | %filecheck --match-full-lines %s -// CHECK: @_typeart__ZTS6Domain = extern_weak constant %struct.typeart_struct_layout_t +// CHECK: @_typeart__ZTS6Domain = extern_weak constant %struct._typeart_struct_layout_t // REQUIRES: llvm-18 || llvm-19 From b5e0ea41c4472b41aafb257e1123ef68dc49fd74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20H=C3=BCck?= Date: Tue, 28 Oct 2025 15:27:24 +0100 Subject: [PATCH 11/35] Register global type descriptors during runtime --- lib/runtime/AllocationTracking.cpp | 23 ++++-- lib/runtime/CMakeLists.txt | 1 + lib/runtime/CallbackInterface.h | 1 + lib/runtime/GlobalTypeDefCallbacks.cpp | 77 +++++++++++++++++++ lib/runtime/GlobalTypeDefCallbacks.h | 50 ++++++++++++ lib/runtime/Runtime.cpp | 3 +- lib/runtime/Runtime.h | 2 + lib/runtime/RuntimeData.h | 6 ++ .../01_simple_malloc_int.c | 2 +- .../02_simple_malloc_int_multi_tu.c | 2 +- .../03_simple_malloc_struct.c | 24 ++++++ 11 files changed, 183 insertions(+), 8 deletions(-) create mode 100644 lib/runtime/GlobalTypeDefCallbacks.cpp create mode 100644 lib/runtime/GlobalTypeDefCallbacks.h create mode 100644 test/runtime_inlined_types/03_simple_malloc_struct.c diff --git a/lib/runtime/AllocationTracking.cpp b/lib/runtime/AllocationTracking.cpp index 222e8891..e7ecc9f4 100644 --- a/lib/runtime/AllocationTracking.cpp +++ b/lib/runtime/AllocationTracking.cpp @@ -289,8 +289,21 @@ void __typeart_leave_scope_omp(int alloca_count) { 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* info_struct = reinterpret_cast(info); - LOG_MSG("Callback with " << intptr_t(info) << " " << info_struct->type_id); - typeart::RuntimeSystem::get().allocTracker.onAllocStack(addr, info_struct->type_id, count, retAddr); -} \ No newline at end of file + const void* retAddr = __builtin_return_address(0); + typeart::RuntimeSystem::get().allocTracker.onAlloc( + addr, typeart::RuntimeSystem::get().type_translator.get_type_id_for(info), 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); + typeart::RuntimeSystem::get().allocTracker.onAllocStack( + addr, typeart::RuntimeSystem::get().type_translator.get_type_id_for(info), 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); + typeart::RuntimeSystem::get().allocTracker.onAllocGlobal( + addr, typeart::RuntimeSystem::get().type_translator.get_type_id_for(info), count, retAddr); +} diff --git a/lib/runtime/CMakeLists.txt b/lib/runtime/CMakeLists.txt index 0e030c5f..84488d8d 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 diff --git a/lib/runtime/CallbackInterface.h b/lib/runtime/CallbackInterface.h index 3def54e4..101d6cb6 100644 --- a/lib/runtime/CallbackInterface.h +++ b/lib/runtime/CallbackInterface.h @@ -41,6 +41,7 @@ void __typeart_leave_scope_omp(int alloca_count); 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); #ifdef __cplusplus } #endif diff --git a/lib/runtime/GlobalTypeDefCallbacks.cpp b/lib/runtime/GlobalTypeDefCallbacks.cpp new file mode 100644 index 00000000..bcda5294 --- /dev/null +++ b/lib/runtime/GlobalTypeDefCallbacks.cpp @@ -0,0 +1,77 @@ +#include "GlobalTypeDefCallbacks.h" + +#include "AccessCounter.h" +#include "AllocationTracking.h" +#include "CallbackInterface.h" +#include "Runtime.h" +#include "RuntimeData.h" +#include "TypeDB.h" +#include "TypeInterface.h" +#include "support/Logger.h" +#include "typelib/TypeDatabase.h" + +#include "llvm/Support/raw_ostream.h" + +#include +#include +#include +#include +#include +#include +#include + +namespace typeart { + +#define TYPEART_RUNTIME_GUARD \ + typeart::RTGuard GUARDNAME; \ + if (!GUARDNAME.shouldTrack()) { \ + return; \ + } + +int GlobalTypeTranslator::next_type_id() { + const int id = static_cast(TYPEART_NUM_RESERVED_IDS) + struct_count; + ++struct_count; + return id; +} + +int GlobalTypeTranslator::register_t(const GlobalTypeInfo* type) { + // const bool built_in = type->type_id < TYPEART_NUM_VALID_IDS; + if (translator_map.contains(type)) { + return translator_map[type]; + } + builtins::BuiltInQuery query; + const bool built_in = query.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_descriptor.name = type->name; + type_descriptor.extent = type->extent; + type_descriptor.flag = static_cast(type->flag); + + const auto* array_sizes = static_cast(type->array_sizes); + const auto* array_offset = static_cast(type->offsets); + for (auto i = 0UL; i < type->num_members; ++i) { + type_descriptor.array_sizes.emplace_back(array_sizes[i]); + type_descriptor.offsets.emplace_back(array_offset[i]); + const auto member_id = register_t(static_cast(type->member_types)); + type_descriptor.member_types.emplace_back(member_id); + } + type_db.registerStruct(type_descriptor, true); + translator_map.try_emplace(type, type_descriptor.type_id); + return type_descriptor.type_id; +} + +void GlobalTypeTranslator::register_type(const void* type) { + const auto* info_struct = reinterpret_cast(type); + LOG_TRACE(register_t(info_struct)); +} + +} // namespace typeart + +void __typeart_register_type(const void* type_ptr) { + TYPEART_RUNTIME_GUARD; + typeart::RuntimeSystem::get().type_translator.register_type(type_ptr); +} \ No newline at end of file diff --git a/lib/runtime/GlobalTypeDefCallbacks.h b/lib/runtime/GlobalTypeDefCallbacks.h new file mode 100644 index 00000000..a0306f92 --- /dev/null +++ b/lib/runtime/GlobalTypeDefCallbacks.h @@ -0,0 +1,50 @@ +#ifndef LIB_RUNTIME_GLOBALTYPEDEFCALLBACKS +#define LIB_RUNTIME_GLOBALTYPEDEFCALLBACKS + +#include "RuntimeData.h" +#include "TypeDB.h" +#include "TypeInterface.h" +#include "support/Logger.h" +#include "typelib/TypeDatabase.h" + +namespace typeart { + +class GlobalTypeTranslator final { + private: + RuntimeT::TypeLookupMapT translator_map; + TypeDB& type_db; + struct GlobalTypeInfo { + int type_id; + const char* name; + size_t extent; + size_t num_members; + const void* offsets; + const GlobalTypeInfo* member_types; + const void* array_sizes; + int flag; + }; + + int struct_count{0}; + + int next_type_id(); + + int register_t(const GlobalTypeInfo* type); + + public: + explicit GlobalTypeTranslator(TypeDB& db) : type_db(db) { + } + + void register_type(const void* type); + + inline const RuntimeT::TypeLookupMapT& get_translator_map() const { + return translator_map; + } + + inline int get_type_id_for(MemAddr addr) const { + return translator_map.find(addr)->second; + } +}; + +} // namespace typeart + +#endif /* LIB_RUNTIME_GLOBALTYPEDEFCALLBACKS */ diff --git a/lib/runtime/Runtime.cpp b/lib/runtime/Runtime.cpp index 49786879..357cbace 100644 --- a/lib/runtime/Runtime.cpp +++ b/lib/runtime/Runtime.cpp @@ -64,7 +64,8 @@ inline void printTraceStart() { static constexpr const char* defaultTypeFileName = config::ConfigStdArgValues::types; -RuntimeSystem::RuntimeSystem() : rtScopeInit(), typeResolution(typeDB, recorder), allocTracker(typeDB, recorder) { +RuntimeSystem::RuntimeSystem() + : rtScopeInit(), typeResolution(typeDB, recorder), allocTracker(typeDB, recorder), type_translator(typeDB) { debug::printTraceStart(); auto loadTypes = [this](const std::string& file, std::error_code& ec) -> bool { diff --git a/lib/runtime/Runtime.h b/lib/runtime/Runtime.h index d0e52036..4b3f629f 100644 --- a/lib/runtime/Runtime.h +++ b/lib/runtime/Runtime.h @@ -15,6 +15,7 @@ #include "AccessCounter.h" #include "AllocationTracking.h" +#include "GlobalTypeDefCallbacks.h" #include "TypeDB.h" #include "TypeResolution.h" @@ -60,6 +61,7 @@ struct RuntimeSystem { Recorder recorder{}; TypeResolution typeResolution; AllocationTracker allocTracker; + GlobalTypeTranslator type_translator; static thread_local bool rtScope; diff --git a/lib/runtime/RuntimeData.h b/lib/runtime/RuntimeData.h index 998ae803..36ff54a6 100644 --- a/lib/runtime/RuntimeData.h +++ b/lib/runtime/RuntimeData.h @@ -25,6 +25,7 @@ #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 +34,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 @@ -65,14 +68,17 @@ struct RuntimeT { static constexpr char StackName[] = "std::vector"; #ifdef TYPEART_PHMAP using PointerMapBaseT = phmap::btree_map; + using TypeLookupMapT = phmap::flat_hash_map; static constexpr char MapName[] = "phmap::btree_map"; #endif #ifdef TYPEART_ABSEIL using PointerMapBaseT = absl::btree_map; + using TypeLookupMapT = absl::flat_hash_map; static constexpr char MapName[] = "absl::btree_map"; #endif #if !defined(TYPEART_PHMAP) && !defined(TYPEART_ABSEIL) using PointerMapBaseT = std::map; + using TypeLookupMapT = std::unordered_map; static constexpr char MapName[] = "std::map"; #endif #ifdef USE_SAFEPTR diff --git a/test/runtime_inlined_types/01_simple_malloc_int.c b/test/runtime_inlined_types/01_simple_malloc_int.c index 111d5afb..ea75937a 100644 --- a/test/runtime_inlined_types/01_simple_malloc_int.c +++ b/test/runtime_inlined_types/01_simple_malloc_int.c @@ -14,4 +14,4 @@ int main(void) { } // CHECK: Allocation type detail (heap, stack, global) -// CHECK-NEXT: 13 : 0 , 1 , 0 , int \ No newline at end of file +// 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 index c09e2d9e..8a45ee45 100644 --- a/test/runtime_inlined_types/02_simple_malloc_int_multi_tu.c +++ b/test/runtime_inlined_types/02_simple_malloc_int_multi_tu.c @@ -29,4 +29,4 @@ int main(void) { #endif // CHECK: Allocation type detail (heap, stack, global) -// CHECK-NEXT: 13 : 0 , 2 , 0 , int \ No newline at end of file +// 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..cf40370b --- /dev/null +++ b/test/runtime_inlined_types/03_simple_malloc_struct.c @@ -0,0 +1,24 @@ +// clang-format off +// RUN: export TYPEART_INSTRUMENTATION=1 +// 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 From adfb31cb256305499dfe88ed8b03930465696f0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20H=C3=BCck?= Date: Wed, 29 Oct 2025 09:19:48 +0100 Subject: [PATCH 12/35] Fixes to runtime type translator --- lib/runtime/GlobalTypeDefCallbacks.cpp | 101 ++++++++++++------ lib/runtime/GlobalTypeDefCallbacks.h | 30 ++---- test/runtime_inlined_types/04_malloc_struct.c | 29 +++++ 3 files changed, 108 insertions(+), 52 deletions(-) create mode 100644 test/runtime_inlined_types/04_malloc_struct.c diff --git a/lib/runtime/GlobalTypeDefCallbacks.cpp b/lib/runtime/GlobalTypeDefCallbacks.cpp index bcda5294..3e3d5968 100644 --- a/lib/runtime/GlobalTypeDefCallbacks.cpp +++ b/lib/runtime/GlobalTypeDefCallbacks.cpp @@ -28,45 +28,80 @@ namespace typeart { return; \ } -int GlobalTypeTranslator::next_type_id() { - const int id = static_cast(TYPEART_NUM_RESERVED_IDS) + struct_count; - ++struct_count; - return id; -} +class GlobalTypeTranslator::Impl { + public: + TypeDB& type_db_; + RuntimeT::TypeLookupMapT& translator_map_; + builtins::BuiltInQuery query_; + + struct GlobalTypeInfo { + int type_id; + const char* name; + size_t extent; + size_t num_members; + const std::int64_t* offsets; + const GlobalTypeInfo** member_types; + const std::int64_t* array_sizes; + int flag; + }; + + int struct_count{0}; -int GlobalTypeTranslator::register_t(const GlobalTypeInfo* type) { - // const bool built_in = type->type_id < TYPEART_NUM_VALID_IDS; - if (translator_map.contains(type)) { - return translator_map[type]; + explicit Impl(TypeDB& db, RuntimeT::TypeLookupMapT& translator_map) : type_db_(db), translator_map_(translator_map) { } - builtins::BuiltInQuery query; - const bool built_in = query.is_builtin_type(type->type_id); - if (built_in) { - translator_map.try_emplace(type, type->type_id); - return type->type_id; + + int next_type_id() { + const int id = static_cast(TYPEART_NUM_RESERVED_IDS) + struct_count; + ++struct_count; + return id; } - StructTypeInfo type_descriptor; - type_descriptor.type_id = next_type_id(); - type_descriptor.name = type->name; - type_descriptor.extent = type->extent; - type_descriptor.flag = static_cast(type->flag); - - const auto* array_sizes = static_cast(type->array_sizes); - const auto* array_offset = static_cast(type->offsets); - for (auto i = 0UL; i < type->num_members; ++i) { - type_descriptor.array_sizes.emplace_back(array_sizes[i]); - type_descriptor.offsets.emplace_back(array_offset[i]); - const auto member_id = register_t(static_cast(type->member_types)); - type_descriptor.member_types.emplace_back(member_id); + + int register_t(const GlobalTypeInfo* type) { + // const bool built_in = type->type_id < TYPEART_NUM_VALID_IDS; + if (translator_map_.contains(type)) { + return translator_map_[type]; + } + + const bool built_in = query_.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_descriptor.name = type->name; + type_descriptor.extent = type->extent; + type_descriptor.num_members = type->num_members; + type_descriptor.flag = static_cast(type->flag); + + // const auto* array_sizes = static_cast(type->array_sizes); + // const auto* array_offset = static_cast(type->offsets); + type_descriptor.array_sizes.reserve(type->num_members); + type_descriptor.offsets.reserve(type->num_members); + type_descriptor.member_types.reserve(type->num_members); + for (auto i = 0UL; i < type->num_members; ++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); + const auto member_id = register_t(reinterpret_cast(type->member_types[i])); + type_descriptor.member_types.emplace_back(member_id); + } + + type_db_.registerStruct(type_descriptor, true); + translator_map_.try_emplace(type, type_descriptor.type_id); + return type_descriptor.type_id; } - type_db.registerStruct(type_descriptor, true); - translator_map.try_emplace(type, type_descriptor.type_id); - return type_descriptor.type_id; +}; + +GlobalTypeTranslator::GlobalTypeTranslator(TypeDB& 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); - LOG_TRACE(register_t(info_struct)); + const auto* info_struct = reinterpret_cast(type); + pImpl->register_t(info_struct); } } // namespace typeart @@ -74,4 +109,4 @@ void GlobalTypeTranslator::register_type(const void* type) { void __typeart_register_type(const void* type_ptr) { TYPEART_RUNTIME_GUARD; typeart::RuntimeSystem::get().type_translator.register_type(type_ptr); -} \ No newline at end of file +} diff --git a/lib/runtime/GlobalTypeDefCallbacks.h b/lib/runtime/GlobalTypeDefCallbacks.h index a0306f92..c6bcc0dd 100644 --- a/lib/runtime/GlobalTypeDefCallbacks.h +++ b/lib/runtime/GlobalTypeDefCallbacks.h @@ -7,32 +7,19 @@ #include "support/Logger.h" #include "typelib/TypeDatabase.h" +#include + namespace typeart { class GlobalTypeTranslator final { private: RuntimeT::TypeLookupMapT translator_map; - TypeDB& type_db; - struct GlobalTypeInfo { - int type_id; - const char* name; - size_t extent; - size_t num_members; - const void* offsets; - const GlobalTypeInfo* member_types; - const void* array_sizes; - int flag; - }; - - int struct_count{0}; - - int next_type_id(); - - int register_t(const GlobalTypeInfo* type); + class Impl; + std::unique_ptr pImpl; public: - explicit GlobalTypeTranslator(TypeDB& db) : type_db(db) { - } + explicit GlobalTypeTranslator(TypeDB& db); + ~GlobalTypeTranslator(); void register_type(const void* type); @@ -43,6 +30,11 @@ class GlobalTypeTranslator final { inline int get_type_id_for(MemAddr addr) const { return translator_map.find(addr)->second; } + + GlobalTypeTranslator(const GlobalTypeTranslator&) = delete; + GlobalTypeTranslator& operator=(const GlobalTypeTranslator&) = delete; + GlobalTypeTranslator(GlobalTypeTranslator&&) noexcept = delete; + GlobalTypeTranslator& operator=(GlobalTypeTranslator&&) noexcept = delete; }; } // namespace typeart 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..16f8a988 --- /dev/null +++ b/test/runtime_inlined_types/04_malloc_struct.c @@ -0,0 +1,29 @@ +// clang-format off +// RUN: export TYPEART_INSTRUMENTATION=1 +// 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 From 1ff1c2fa64a2727c103a1487dfc1c2ed689820bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20H=C3=BCck?= Date: Thu, 30 Oct 2025 12:05:22 +0100 Subject: [PATCH 13/35] Towards selectable modes --- lib/passes/CMakeLists.txt | 1 + lib/passes/TypeARTPass.cpp | 5 +- .../CallBackFunctionInserter.cpp | 101 +++++++++++++++ .../CallBackFunctionInserter.h | 50 ++++++++ .../instrumentation/MemOpInstrumentation.cpp | 57 +++++---- .../instrumentation/MemOpInstrumentation.h | 9 +- .../instrumentation/TypeARTFunctions.cpp | 56 ++++++-- lib/passes/instrumentation/TypeIDProvider.cpp | 120 ++++++++---------- lib/runtime/GlobalTypeDefCallbacks.cpp | 3 +- lib/typelib/TypeDatabase.h | 2 +- 10 files changed, 289 insertions(+), 115 deletions(-) create mode 100644 lib/passes/instrumentation/CallBackFunctionInserter.cpp create mode 100644 lib/passes/instrumentation/CallBackFunctionInserter.h diff --git a/lib/passes/CMakeLists.txt b/lib/passes/CMakeLists.txt index 4c524da0..0346d7f0 100644 --- a/lib/passes/CMakeLists.txt +++ b/lib/passes/CMakeLists.txt @@ -13,6 +13,7 @@ set(PASS_SOURCES instrumentation/MemOpInstrumentation.cpp instrumentation/Instrumentation.cpp instrumentation/TypeIDProvider.cpp + instrumentation/CallBackFunctionInserter.cpp TypeARTConfiguration.cpp Commandline.cpp ) diff --git a/lib/passes/TypeARTPass.cpp b/lib/passes/TypeARTPass.cpp index 318d5ca3..d20d8db4 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" @@ -167,8 +169,9 @@ class TypeArtPass : public llvm::PassInfoMixin { 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(), - std::move(type_id_handler), instrumentation_helper); + instrumentation_helper, std::move(cb_provider)); instrumentation_context = std::make_unique(std::move(arg_collector), std::move(mem_instrument)); diff --git a/lib/passes/instrumentation/CallBackFunctionInserter.cpp b/lib/passes/instrumentation/CallBackFunctionInserter.cpp new file mode 100644 index 00000000..18f35d05 --- /dev/null +++ b/lib/passes/instrumentation/CallBackFunctionInserter.cpp @@ -0,0 +1,101 @@ +#include "CallBackFunctionInserter.h" + +#include "configuration/Configuration.h" +#include "instrumentation/TypeIDProvider.h" +#include "support/ConfigurationBase.h" + +#include "llvm/IR/Function.h" +#include "llvm/IR/GlobalVariable.h" +#include "llvm/IR/IRBuilder.h" + +#include + +namespace typeart { + +class CallbackFunctionInserter final : public InstrumentationInserter { + const config::Configuration& configuration_; + std::unique_ptr type_id_handler_; + TAFunctionQuery* function_query_; + bool mixed_mode{false}; + + private: + llvm::CallInst* create_instrumentation_call(llvm::IRBuilder<>& IRB, IFunc callback_type, + llvm::Value* instruction_or_value, llvm::Value* pointer_value, + llvm::Value* element_count, llvm::Value* typeid_value); + + 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, + llvm::Value* pointer_value, llvm::Value* element_count, + llvm::Value* typeid_value) override; + + llvm::CallInst* insert_stack_instrumentation(llvm::IRBuilder<>& IRB, llvm::Instruction* alloca, + llvm::Value* pointer_value, llvm::Value* element_count, + llvm::Value* typeid_value) override; + + llvm::CallInst* insert_global_instrumentation(llvm::IRBuilder<>& IRB, llvm::GlobalValue* global_var, + llvm::Value* pointer_value, llvm::Value* element_count, + llvm::Value* typeid_value) override; + + llvm::CallInst* insert_free_instrumentation(llvm::IRBuilder<>& IRB, llvm::Value* pointer_value) override; +}; + +CallbackFunctionInserter::CallbackFunctionInserter(const config::Configuration& configuration, + std::unique_ptr type_id_handler, + TAFunctionQuery* function_query) + : configuration_(configuration), type_id_handler_(std::move(type_id_handler)), function_query_(function_query) { +} + +// Private Helper Definition +llvm::CallInst* CallbackFunctionInserter::create_instrumentation_call(llvm::IRBuilder<>& IRB, IFunc callback_type, + llvm::Value* instruction_or_value, + llvm::Value* pointer_value, + llvm::Value* element_count, + llvm::Value* typeid_value) { + const auto callback_id = ifunc_for_function(callback_type, instruction_or_value); + + auto type_id_param_out = type_id_handler_->getOrRegister(typeid_value); + + return IRB.CreateCall(function_query_->getFunctionFor(callback_id), + llvm::ArrayRef{pointer_value, type_id_param_out, element_count}); +} + +// Public Function Definitions +llvm::CallInst* CallbackFunctionInserter::insert_heap_instrumentation(llvm::IRBuilder<>& IRB, llvm::CallBase* heap_call, + llvm::Value* pointer_value, + llvm::Value* element_count, + llvm::Value* typeid_value) { + return create_instrumentation_call(IRB, IFunc::heap, heap_call, pointer_value, element_count, typeid_value); +} + +llvm::CallInst* CallbackFunctionInserter::insert_stack_instrumentation(llvm::IRBuilder<>& IRB, + llvm::Instruction* alloca, + llvm::Value* pointer_value, + llvm::Value* element_count, + llvm::Value* typeid_value) { + return create_instrumentation_call(IRB, IFunc::stack, alloca, pointer_value, element_count, typeid_value); +} + +llvm::CallInst* CallbackFunctionInserter::insert_global_instrumentation(llvm::IRBuilder<>& IRB, + llvm::GlobalValue* global_var, + llvm::Value* pointer_value, + llvm::Value* element_count, + llvm::Value* typeid_value) { + return create_instrumentation_call(IRB, IFunc::global, global_var, pointer_value, element_count, typeid_value); +} + +llvm::CallInst* CallbackFunctionInserter::insert_free_instrumentation(llvm::IRBuilder<>& IRB, + llvm::Value* pointer_value) { + const auto callback_id = ifunc_for_function(IFunc::free, pointer_value); + 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..a460cd22 --- /dev/null +++ b/lib/passes/instrumentation/CallBackFunctionInserter.h @@ -0,0 +1,50 @@ +#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; + +class InstrumentationInserter { + public: + virtual ~InstrumentationInserter() = default; + + virtual llvm::CallInst* insert_heap_instrumentation(llvm::IRBuilder<>& IRB, llvm::CallBase* heap_call, + llvm::Value* pointer_value, llvm::Value* element_count, + llvm::Value* typeid_value) = 0; + + virtual llvm::CallInst* insert_stack_instrumentation(llvm::IRBuilder<>& IRB, llvm::Instruction* alloca, + llvm::Value* pointer_value, llvm::Value* element_count, + llvm::Value* typeid_value) = 0; + + virtual llvm::CallInst* insert_global_instrumentation(llvm::IRBuilder<>& IRB, llvm::GlobalValue* global_var, + llvm::Value* pointer_value, llvm::Value* element_count, + llvm::Value* typeid_value) = 0; + + virtual llvm::CallInst* insert_free_instrumentation(llvm::IRBuilder<>& IRB, 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/MemOpInstrumentation.cpp b/lib/passes/instrumentation/MemOpInstrumentation.cpp index 159620c1..639ff88a 100644 --- a/lib/passes/instrumentation/MemOpInstrumentation.cpp +++ b/lib/passes/instrumentation/MemOpInstrumentation.cpp @@ -19,6 +19,7 @@ #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" @@ -54,12 +55,13 @@ using namespace llvm; namespace typeart { MemOpInstrumentation::MemOpInstrumentation(const config::Configuration& typeart_conf, TAFunctionQuery* fquery, - std::unique_ptr type_id_handle, InstrumentationHelper& instr) + InstrumentationHelper& instr, + std::unique_ptr function_instrumenter) : MemoryInstrument(), typeart_config(typeart_conf), function_query(fquery), - type_id_handler(std::move(type_id_handle)), - instrumentation_helper(&instr) { + instrumentation_helper(&instr), + function_instrumenter_(std::move(function_instrumenter)) { instrument_lifetime = typeart_config[config::ConfigStdArgs::stack_lifetime]; } @@ -68,8 +70,6 @@ InstrCount MemOpInstrumentation::instrumentHeap(const HeapArgList& heap) { auto type_gen = typeart_config[config::ConfigStdArgs::typegen]; const bool is_llvm_ir_type = static_cast(type_gen) == static_cast(TypegenImplementation::IR); - function_query->getFunctionFor(IFunc::free); - for (const auto& [malloc, args] : heap) { auto kind = malloc.kind; auto* malloc_call = args.get_as(ArgMap::ID::pointer); @@ -138,9 +138,7 @@ 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, target_memory_address); break; } default: @@ -148,11 +146,12 @@ InstrCount MemOpInstrumentation::instrumentHeap(const HeapArgList& heap) { continue; } - // const auto callback_id = omp ? IFunc::heap_omp : IFunc::heap; - const auto callback_id = ifunc_for_function(IFunc::heap, malloc.call); - auto type_id_param = type_id_handler->getOrRegister(typeid_value); - IRB.CreateCall(function_query->getFunctionFor(callback_id), - ArrayRef{malloc_call, type_id_param, 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; } @@ -185,11 +184,13 @@ InstrCount MemOpInstrumentation::instrumentFree(const FreeArgList& frees) { IRBuilder<> IRB(insertBefore); + function_instrumenter_->insert_free_instrumentation(IRB, 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); + // 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; } @@ -208,10 +209,11 @@ InstrCount MemOpInstrumentation::instrumentStack(const StackArgList& stack) { 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; - const auto callback_id = ifunc_for_function(IFunc::stack, alloca); - auto type_id_param = type_id_handler->getOrRegister(typeIdConst); - IRB.CreateCall(function_query->getFunctionFor(callback_id), - ArrayRef{data_ptr, type_id_param, numElementsVal}); + // 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(); @@ -248,14 +250,15 @@ InstrCount MemOpInstrumentation::instrumentGlobal(const GlobalArgList& globals) const auto instrumentGlobalsInCtor = [&](auto& IRB) { for (const auto& [gdata, args] : globals) { // Instruction* global = args.get_as("pointer"); - auto global = gdata.global; - 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)); - const auto callback_id = ifunc_for_function(IFunc::global, global); - auto type_id_param = type_id_handler->getOrRegister(typeIdConst); - IRB.CreateCall(function_query->getFunctionFor(callback_id), - ArrayRef{globalPtr, type_id_param, numElementsVal}); + auto global = gdata.global; + 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)); + // 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 253d6f70..073ff338 100644 --- a/lib/passes/instrumentation/MemOpInstrumentation.h +++ b/lib/passes/instrumentation/MemOpInstrumentation.h @@ -15,7 +15,6 @@ #include "Instrumentation.h" #include "configuration/Configuration.h" -#include "instrumentation/TypeIDProvider.h" #include @@ -26,17 +25,19 @@ 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; + // std::unique_ptr type_id_handler; + std::unique_ptr function_instrumenter_; InstrumentationHelper* instrumentation_helper; bool instrument_lifetime{false}; public: - MemOpInstrumentation(const config::Configuration& typeart_conf, TAFunctionQuery* fquery, - std::unique_ptr type_id_handler, 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; diff --git a/lib/passes/instrumentation/TypeARTFunctions.cpp b/lib/passes/instrumentation/TypeARTFunctions.cpp index acf435d0..8d25dfb4 100644 --- a/lib/passes/instrumentation/TypeARTFunctions.cpp +++ b/lib/passes/instrumentation/TypeARTFunctions.cpp @@ -31,6 +31,7 @@ #include "llvm/Support/raw_ostream.h" #include +#include #include namespace typeart { @@ -80,7 +81,7 @@ IFunc ifunc_for_function(IFunc general_type, llvm::Value* value) { type = detail::ifunc_type_for(function); } else if (auto alloca = llvm::dyn_cast(value)) { type = detail::ifunc_type_for(alloca->getFunction()); - } else if (auto global = llvm::dyn_cast(value)) { + } 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()); @@ -124,10 +125,15 @@ class TAFunctions final : public TAFunctionQuery { // densemap has problems with IFunc using FMap = std::unordered_map; FMap typeart_callbacks; + FMap typeart_callbacks_alternatives; + bool with_alternative_{false}; public: + explicit TAFunctions(bool with_alternatives) : with_alternative_(with_alternatives) { + } llvm::Function* getFunctionFor(IFunc id) const override; - void putFunctionFor(IFunc id, llvm::Function* f); + void putFunctionFor(IFunc id, llvm::Function* f, bool alternative = false); + void putAlternativeFunctionFor(IFunc id, llvm::Function* f); }; class TAFunctionDeclarator { @@ -138,7 +144,8 @@ class TAFunctionDeclarator { public: TAFunctionDeclarator(llvm::Module& m, InstrumentationHelper& instr, TAFunctions& typeart_func); - llvm::Function* make_function(IFunc function, llvm::StringRef basename, llvm::ArrayRef args); + llvm::Function* make_function(IFunc function, llvm::StringRef basename, llvm::ArrayRef args, + bool alternative = false); const llvm::StringMap& getFunctionMap() const; virtual ~TAFunctionDeclarator() = default; }; @@ -148,7 +155,7 @@ TAFunctionDeclarator::TAFunctionDeclarator(Module& mod, InstrumentationHelper&, } llvm::Function* TAFunctionDeclarator::make_function(IFunc func_id, llvm::StringRef basename, - llvm::ArrayRef args) { + 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); @@ -208,12 +215,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; - typeart_functions.putFunctionFor(func_id, generated_function); - + if (alternative) { + typeart_functions.putAlternativeFunctionFor(func_id, generated_function); + } else { + typeart_functions.putFunctionFor(func_id, generated_function); + } return generated_function; } @@ -222,15 +232,31 @@ const llvm::StringMap& TAFunctionDeclarator::getFunctionMap() c } Function* TAFunctions::getFunctionFor(IFunc id) const { - auto element = typeart_callbacks.find(id); - if (element == std::end(typeart_callbacks)) { - LOG_WARNING("No functions for id " << int(id)) - return nullptr; + 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; + }; + + if (with_alternative_) { + auto result = find_(typeart_callbacks_alternatives); + if (result) { + return result.value(); + } } - return element->second; + + auto result = find_(typeart_callbacks); + return result.value_or(nullptr); } -void TAFunctions::putFunctionFor(IFunc id, llvm::Function* f) { +void TAFunctions::putFunctionFor(IFunc id, llvm::Function* f, bool alternative) { + if (alternative) { + typeart_callbacks_alternatives[id] = f; + return; + } typeart_callbacks[id] = f; } @@ -253,6 +279,8 @@ 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"}; } // namespace callbacks @@ -260,7 +288,7 @@ TypeArtFunc typeart_register_type{"__typeart_register_type"}; std::unique_ptr declare_instrumentation_functions(llvm::Module& m, const config::Configuration& configuration) { using namespace callbacks; - auto functions = std::make_unique(); + auto functions = std::make_unique(false); InstrumentationHelper instrumentation_helper; instrumentation_helper.setModule(m); TAFunctionDeclarator decl(m, instrumentation_helper, *functions.get()); diff --git a/lib/passes/instrumentation/TypeIDProvider.cpp b/lib/passes/instrumentation/TypeIDProvider.cpp index 43521388..43258d79 100644 --- a/lib/passes/instrumentation/TypeIDProvider.cpp +++ b/lib/passes/instrumentation/TypeIDProvider.cpp @@ -1,5 +1,6 @@ #include "TypeIDProvider.h" +#include "TypeDB.h" #include "TypeDatabase.h" #include "TypeInterface.h" #include "configuration/Configuration.h" @@ -44,7 +45,7 @@ namespace helper { 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) { + if (constant_int == nullptr) { return TYPEART_UNKNOWN_TYPE; } const int type_id = static_cast(constant_int->getSExtValue()); @@ -103,7 +104,7 @@ struct GlobalTypeCallback { 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); + auto* ret_inst = ReturnInst::Create(c); // llvm::IRBuilder<> Builder(entry); ret_inst->insertInto(entry, entry->getFirstInsertionPt()); // Builder.CreateRetVoid(); @@ -113,7 +114,7 @@ struct GlobalTypeCallback { return entry; }; - auto func = module_->getFunction(ctor_function_name); + auto* func = module_->getFunction(ctor_function_name); if (func == nullptr) { return makeCtorFuncBody(); } @@ -121,7 +122,7 @@ struct GlobalTypeCallback { } llvm::BasicBlock* get_entry() { - auto func = module_->getFunction(ctor_function_name); + auto* func = module_->getFunction(ctor_function_name); if (func == nullptr) { return make_type_callback(); } @@ -133,10 +134,10 @@ struct GlobalTypeCallback { } void insert(llvm::Constant* global) { - auto block = get_entry(); + auto* block = get_entry(); for (auto& inst : *block) { if (auto* call_base = llvm::dyn_cast(&inst)) { - auto argument = call_base->getArgOperand(0); + auto* argument = call_base->getArgOperand(0); if (global == argument) { LOG_DEBUG("Skipping, already contained"); return; @@ -159,11 +160,11 @@ struct GlobalTypeRegistrar { 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) { - declareLayout(); + declare_layout(); } private: - void declareLayout() { + void declare_layout() { auto& context = module_->getContext(); llvm::IRBuilder<> Builder(context); struct_layout_type_ = llvm::StructType::create(context, "struct._typeart_struct_layout_t"); @@ -188,6 +189,12 @@ struct GlobalTypeRegistrar { 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, @@ -196,14 +203,11 @@ struct GlobalTypeRegistrar { ir_build.CreateGlobalString(name, helper::create_prefixed_name("typename_", name), 0, module_); global_string->setConstant(true); global_string->setLinkage(llvm::GlobalValue::WeakODRLinkage); - auto* i32_zero = llvm::ConstantInt::get(llvm::Type::getInt32Ty(module_->getContext()), 0); - return llvm::ConstantExpr::getInBoundsGetElementPtr(global_string->getValueType(), global_string, - llvm::ArrayRef{i32_zero, i32_zero}); + return make_gep(global_string->getValueType(), global_string); } llvm::Constant* create_global_array_ptr(const llvm::StringRef name, llvm::ArrayRef values) { - auto& context = module_->getContext(); - auto* int64_ty = llvm::Type::getInt64Ty(context); + auto* int64_ty = ir_build.getInt64Ty(); std::vector constants; constants.reserve(values.size()); @@ -211,31 +215,35 @@ struct GlobalTypeRegistrar { constants.push_back(llvm::ConstantInt::get(int64_ty, val)); } - auto* array_ty = llvm::ArrayType::get(int64_ty, values.size()); - auto* constant_array = llvm::ConstantArray::get(array_ty, constants); - auto* gv = create_global(name, array_ty, constant_array); - auto constant_zero_i32 = llvm::ConstantInt::get(llvm::Type::getInt32Ty(context), 0); - return llvm::ConstantExpr::getGetElementPtr( // - array_ty, // - gv, // - llvm::ArrayRef{constant_zero_i32, constant_zero_i32}); + auto* array_ty = llvm::ArrayType::get(int64_ty, 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* registerGlobalStructDecl(const std::string& name) { + auto* global_struct = create_global(name, struct_layout_type_, nullptr, llvm::GlobalValue::ExternalWeakLinkage); + global_types_.global_type_data.try_emplace( + name, GlobalTypeData::TypeData{nullptr, global_struct, nullptr, nullptr, nullptr}); + + return global_struct; } 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) { + llvm::Constant* members_data_ptr, llvm::Constant* count_ptr, + StructTypeFlag flag = StructTypeFlag::USER_DEFINED) { llvm::GlobalVariable* global_struct = create_global(name, struct_layout_type_); llvm::Constant* name_str = create_global_constant_string(name); - std::vector members = { - ir_build.getInt32(type_id), - name_str, - ir_build.getInt64(type_size), - ir_build.getInt64(member_count), - offset_ptr, - members_data_ptr, - count_ptr, - ir_build.getInt32(static_cast(StructTypeFlag::USER_DEFINED))}; // TODO: use real type + std::vector members = {ir_build.getInt32(type_id), + name_str, + ir_build.getInt64(type_size), + ir_build.getInt64(member_count), + offset_ptr, + members_data_ptr, + count_ptr, + ir_build.getInt32(static_cast(flag))}; // TODO: use real type llvm::Constant* init = llvm::ConstantStruct::get(struct_layout_type_, members); @@ -247,35 +255,6 @@ struct GlobalTypeRegistrar { return global_struct; } - llvm::GlobalVariable* registerGlobalStructDecl(const std::string& name) { - auto* global_struct = create_global(name, struct_layout_type_, nullptr, llvm::GlobalValue::ExternalWeakLinkage); - // new llvm::GlobalVariable(*module_, struct_layout_type_, true, llvm::GlobalValue::ExternalWeakLinkage, nullptr, - // helper::create_prefixed_name(name)); - // llvm::Constant* name_str = create_global_constant_string(name); - global_types_.global_type_data.try_emplace( - name, GlobalTypeData::TypeData{nullptr, global_struct, nullptr, nullptr, nullptr}); - - return global_struct; - } - - llvm::GlobalVariable* registerBuiltin(int type_id) { - // struct StructTypeInfo { - // int type_id; - // std::string name; - // size_t extent; - // size_t num_members; - // std::vector offsets; - // std::vector member_types; - // std::vector array_sizes; - // StructTypeFlag flag; - // }; - StructTypeInfo type_struct{type_id, type_db_->getTypeName(type_id), type_db_->getTypeSize(type_id), 1, {0}, {}, - {1}, StructTypeFlag::USER_DEFINED}; - - auto global = registerTypeStruct(&type_struct); - return global; - } - llvm::GlobalVariable* registerTypeStruct(const StructTypeInfo* type_struct) { const auto name = type_struct->name; const auto type_size = type_struct->extent; @@ -311,7 +290,13 @@ struct GlobalTypeRegistrar { } return registerGlobalStruct(name, type_struct->type_id, type_size, member_count, offset_ptr, members_array, - count_ptr); + count_ptr, type_struct->flag); + } + + llvm::GlobalVariable* registerBuiltin(int type_id) { + StructTypeInfo type_struct{type_id, type_db_->getTypeName(type_id), type_db_->getTypeSize(type_id), 1, {0}, {}, + {1}, StructTypeFlag::BUILTIN}; + return registerTypeStruct(&type_struct); } llvm::GlobalVariable* registerUserDefined(int type_id) { @@ -327,11 +312,11 @@ struct GlobalTypeRegistrar { LOG_DEBUG("Registering << " << type_id << " " << name) const bool is_builtin = type_db_->isBuiltinType(type_id); if (is_builtin) { - auto global = registerBuiltin(type_id); + auto* global = registerBuiltin(type_id); type_callback.insert(global); return global; } - auto global = registerUserDefined(type_id); + auto* global = registerUserDefined(type_id); const auto fwd_decl = StructTypeFlag::FWD_DECL == type_db_->getStructInfo(type_id)->flag; if (!fwd_decl) { type_callback.insert(global); @@ -343,17 +328,20 @@ struct GlobalTypeRegistrar { } // namespace typedb class TypeRegistryGlobals final : public TypeRegistry { - llvm::Module* module_; + // llvm::Module* module_; typedb::GlobalTypeRegistrar registrar_; public: TypeRegistryGlobals(llvm::Module& m, const TypeDatabase* type_db, const TAFunctionQuery* f_query) - : module_(&m), registrar_(&m, type_db, f_query) { + : registrar_(&m, type_db, f_query) { } void registerModule(const ModuleData& m) override { for (const auto& type : m.types_list) { - const auto type_id = registrar_.getOrRegister(type.type_id); + if (builtins::BuiltInQuery::is_builtin_type(type.type_id)) { + continue; + } + const auto* type_id = registrar_.getOrRegister(type.type_id); LOG_DEBUG("Registering type_id " << *type_id) } } diff --git a/lib/runtime/GlobalTypeDefCallbacks.cpp b/lib/runtime/GlobalTypeDefCallbacks.cpp index 3e3d5968..21b83f96 100644 --- a/lib/runtime/GlobalTypeDefCallbacks.cpp +++ b/lib/runtime/GlobalTypeDefCallbacks.cpp @@ -32,7 +32,6 @@ class GlobalTypeTranslator::Impl { public: TypeDB& type_db_; RuntimeT::TypeLookupMapT& translator_map_; - builtins::BuiltInQuery query_; struct GlobalTypeInfo { int type_id; @@ -62,7 +61,7 @@ class GlobalTypeTranslator::Impl { return translator_map_[type]; } - const bool built_in = query_.is_builtin_type(type->type_id); + 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; 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; From 1d9abf1a3bffad60e3e9640807ded2dd69c8fe6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20H=C3=BCck?= Date: Thu, 30 Oct 2025 20:24:54 +0100 Subject: [PATCH 14/35] Add selectable type serialization --- lib/passes/Commandline.cpp | 17 ++-- lib/passes/TypeARTPass.cpp | 2 +- .../EnvironmentConfiguration.cpp | 9 +- lib/passes/configuration/OptionsUtil.h | 29 +++++-- .../configuration/PassConfiguration.cpp | 7 ++ lib/passes/configuration/TypeARTOptions.cpp | 15 +++- lib/passes/configuration/TypeARTOptions.h | 2 + .../CallBackFunctionInserter.cpp | 18 ++-- .../instrumentation/MemOpInstrumentation.cpp | 4 +- .../instrumentation/MemOpInstrumentation.h | 2 +- .../instrumentation/TypeARTFunctions.cpp | 85 +++++++++++-------- lib/passes/instrumentation/TypeARTFunctions.h | 6 +- lib/passes/instrumentation/TypeIDProvider.cpp | 32 ++++++- lib/passes/instrumentation/TypeIDProvider.h | 11 ++- lib/support/ConfigurationBaseOptions.h | 4 +- test/pass/inline_types/01_simple_malloc_int.c | 2 +- test/pass/inline_types/02_calloc_realloc.c | 4 +- .../inline_types/03_simple_malloc_struct.c | 2 +- test/pass/inline_types/04_fwd_decl.cpp | 4 +- test/pass/misc/08_config_file_default.c | 1 + .../01_simple_malloc_int.c | 2 +- .../02_simple_malloc_int_multi_tu.c | 2 +- .../03_simple_malloc_struct.c | 2 +- test/runtime_inlined_types/04_malloc_struct.c | 2 +- 24 files changed, 175 insertions(+), 89 deletions(-) diff --git a/lib/passes/Commandline.cpp b/lib/passes/Commandline.cpp index aad19f5c..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,10 +84,14 @@ static cl::opt cl_typeart_instrument_stack(Commandl cl::init(ConfigStdArgValues::stack), cl::cat(typeart_category)); -static cl::opt cl_typeart_instrument(CommandlineStdArgs::instrumentation, - cl::desc(ConfigStdArgDescriptions::instrumentation), - cl::init(ConfigStdArgValues::instrumentation), - 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), @@ -203,7 +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::instrumentation, cl_typeart_instrument), + 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), @@ -223,7 +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::instrumentation, cl_typeart_instrument), + 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 d20d8db4..6ec65b69 100644 --- a/lib/passes/TypeARTPass.cpp +++ b/lib/passes/TypeARTPass.cpp @@ -183,7 +183,7 @@ class TypeArtPass : public llvm::PassInfoMixin { /* * Persist the accumulated type definition information for this module. */ - if (!configuration()[config::ConfigStdArgs::instrumentation]) { + if (!configuration()[config::ConfigStdArgs::type_serialization]) { const std::string types_file = configuration()[config::ConfigStdArgs::types]; LOG_DEBUG("Writing type file to " << types_file); diff --git a/lib/passes/configuration/EnvironmentConfiguration.cpp b/lib/passes/configuration/EnvironmentConfiguration.cpp index 1a706457..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,9 +114,9 @@ EnvironmentFlagsOptions::EnvironmentFlagsOptions() { EnvironmentStdArgsValues::global), make_entry(ConfigStdArgs::stack, EnvironmentStdArgs::stack, EnvironmentStdArgsValues::stack), - make_entry(ConfigStdArgs::instrumentation, - EnvironmentStdArgs::instrumentation, - EnvironmentStdArgsValues::instrumentation), + 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, @@ -151,7 +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::instrumentation, EnvironmentStdArgs::instrumentation), + 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/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 71c0922d..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; } @@ -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 93b13608..0351d842 100644 --- a/lib/passes/configuration/TypeARTOptions.h +++ b/lib/passes/configuration/TypeARTOptions.h @@ -15,6 +15,7 @@ #include "analysis/MemInstFinder.h" #include "configuration/Configuration.h" +#include "instrumentation/TypeIDProvider.h" #include "support/ConfigurationBase.h" #include "typegen/TypeGenerator.h" @@ -50,6 +51,7 @@ struct TypeARTConfigOptions { bool statistics{ConfigStdArgValues::stats}; bool stack_lifetime{ConfigStdArgValues::stack_lifetime}; TypegenImplementation typegen{TypegenImplementation::DIMETA}; + TypeSerializationImplementation type_serialization{TypeSerializationImplementation::FILE}; bool filter{false}; TypeARTCallFilterOptions filter_config{}; diff --git a/lib/passes/instrumentation/CallBackFunctionInserter.cpp b/lib/passes/instrumentation/CallBackFunctionInserter.cpp index 18f35d05..dadeeb89 100644 --- a/lib/passes/instrumentation/CallBackFunctionInserter.cpp +++ b/lib/passes/instrumentation/CallBackFunctionInserter.cpp @@ -3,6 +3,7 @@ #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" @@ -13,10 +14,10 @@ namespace typeart { class CallbackFunctionInserter final : public InstrumentationInserter { - const config::Configuration& configuration_; std::unique_ptr type_id_handler_; TAFunctionQuery* function_query_; - bool mixed_mode{false}; + TypeSerializationImplementation mode_; + // bool mixed_mode{false}; private: llvm::CallInst* create_instrumentation_call(llvm::IRBuilder<>& IRB, IFunc callback_type, @@ -45,7 +46,9 @@ class CallbackFunctionInserter final : public InstrumentationInserter { CallbackFunctionInserter::CallbackFunctionInserter(const config::Configuration& configuration, std::unique_ptr type_id_handler, TAFunctionQuery* function_query) - : configuration_(configuration), type_id_handler_(std::move(type_id_handler)), function_query_(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 @@ -55,14 +58,15 @@ llvm::CallInst* CallbackFunctionInserter::create_instrumentation_call(llvm::IRBu llvm::Value* element_count, llvm::Value* typeid_value) { const auto callback_id = ifunc_for_function(callback_type, instruction_or_value); - auto type_id_param_out = type_id_handler_->getOrRegister(typeid_value); - return IRB.CreateCall(function_query_->getFunctionFor(callback_id), - llvm::ArrayRef{pointer_value, type_id_param_out, element_count}); + const auto mode = llvm::isa(type_id_param_out) ? mode_ : TypeSerializationImplementation::FILE; + LOG_FATAL(int(mode)); + auto function = function_query_->getFunctionFor(callback_id, mode); + + return IRB.CreateCall(function, llvm::ArrayRef{pointer_value, type_id_param_out, element_count}); } -// Public Function Definitions llvm::CallInst* CallbackFunctionInserter::insert_heap_instrumentation(llvm::IRBuilder<>& IRB, llvm::CallBase* heap_call, llvm::Value* pointer_value, llvm::Value* element_count, diff --git a/lib/passes/instrumentation/MemOpInstrumentation.cpp b/lib/passes/instrumentation/MemOpInstrumentation.cpp index 639ff88a..69b39c50 100644 --- a/lib/passes/instrumentation/MemOpInstrumentation.cpp +++ b/lib/passes/instrumentation/MemOpInstrumentation.cpp @@ -96,8 +96,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)); diff --git a/lib/passes/instrumentation/MemOpInstrumentation.h b/lib/passes/instrumentation/MemOpInstrumentation.h index 073ff338..0b82c0bd 100644 --- a/lib/passes/instrumentation/MemOpInstrumentation.h +++ b/lib/passes/instrumentation/MemOpInstrumentation.h @@ -31,8 +31,8 @@ class MemOpInstrumentation final : public MemoryInstrument { const config::Configuration& typeart_config; TAFunctionQuery* function_query; // std::unique_ptr type_id_handler; - std::unique_ptr function_instrumenter_; InstrumentationHelper* instrumentation_helper; + std::unique_ptr function_instrumenter_; bool instrument_lifetime{false}; public: diff --git a/lib/passes/instrumentation/TypeARTFunctions.cpp b/lib/passes/instrumentation/TypeARTFunctions.cpp index 8d25dfb4..e9c052b9 100644 --- a/lib/passes/instrumentation/TypeARTFunctions.cpp +++ b/lib/passes/instrumentation/TypeARTFunctions.cpp @@ -13,6 +13,7 @@ #include "TypeARTFunctions.h" #include "configuration/Configuration.h" +#include "instrumentation/TypeIDProvider.h" #include "support/ConfigurationBase.h" #include "support/Logger.h" #include "support/OmpUtil.h" @@ -33,6 +34,7 @@ #include #include #include +#include namespace typeart { class InstrumentationHelper; @@ -125,15 +127,12 @@ class TAFunctions final : public TAFunctionQuery { // densemap has problems with IFunc using FMap = std::unordered_map; FMap typeart_callbacks; - FMap typeart_callbacks_alternatives; - bool with_alternative_{false}; public: - explicit TAFunctions(bool with_alternatives) : with_alternative_(with_alternatives) { - } - llvm::Function* getFunctionFor(IFunc id) const override; - void putFunctionFor(IFunc id, llvm::Function* f, bool alternative = false); - void putAlternativeFunctionFor(IFunc id, llvm::Function* f); + 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 { @@ -219,11 +218,11 @@ llvm::Function* TAFunctionDeclarator::make_function(IFunc func_id, llvm::StringR function_map[name] = generated_function; - if (alternative) { - typeart_functions.putAlternativeFunctionFor(func_id, generated_function); - } else { - typeart_functions.putFunctionFor(func_id, generated_function); - } + // if (alternative) { + // typeart_functions.putAlternativeFunctionFor(func_id, generated_function); + // } else { + typeart_functions.putFunctionFor(func_id, generated_function); + // } return generated_function; } @@ -231,7 +230,7 @@ const llvm::StringMap& TAFunctionDeclarator::getFunctionMap() c return function_map; } -Function* TAFunctions::getFunctionFor(IFunc id) const { +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_)) { @@ -241,27 +240,34 @@ Function* TAFunctions::getFunctionFor(IFunc id) const { return element->second; }; - if (with_alternative_) { - auto result = find_(typeart_callbacks_alternatives); - if (result) { - return result.value(); - } - } - auto result = find_(typeart_callbacks); return result.value_or(nullptr); } -void TAFunctions::putFunctionFor(IFunc id, llvm::Function* f, bool alternative) { - if (alternative) { - typeart_callbacks_alternatives[id] = f; - return; - } +void TAFunctions::putFunctionFor(IFunc id, llvm::Function* f) { typeart_callbacks[id] = f; } -namespace callbacks { +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}; @@ -288,24 +294,27 @@ TypeArtFunc typeart_register_type{"__typeart_register_type"}; std::unique_ptr declare_instrumentation_functions(llvm::Module& m, const config::Configuration& configuration) { using namespace callbacks; - auto functions = std::make_unique(false); + TAFunctions functions; + TAFunctions functions_alternative; InstrumentationHelper instrumentation_helper; instrumentation_helper.setModule(m); - TAFunctionDeclarator decl(m, instrumentation_helper, *functions.get()); + 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 bool module_local_types = configuration[config::ConfigStdArgs::instrumentation]; - if (module_local_types) { - auto alloc_arg_types_mty = instrumentation_helper.make_parameters(IType::ptr, IType::ptr, IType::extent); - typeart_alloc.f = decl.make_function(IFunc::heap, typeart_alloc_mty.name, alloc_arg_types_mty); - typeart_register_type.f = decl.make_function(IFunc::type, typeart_register_type.name, free_arg_types); - } else { - typeart_alloc.f = decl.make_function(IFunc::heap, typeart_alloc.name, alloc_arg_types); - } + // 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); @@ -317,7 +326,9 @@ std::unique_ptr declare_instrumentation_functions(llvm::Module& typeart_leave_scope_omp.f = decl.make_function(IFunc::scope_omp, typeart_leave_scope_omp.name, leavescope_arg_types); - return functions; + // TODO: mty for OMP + + return std::make_unique(functions, functions_alternative); } } // namespace typeart diff --git a/lib/passes/instrumentation/TypeARTFunctions.h b/lib/passes/instrumentation/TypeARTFunctions.h index 7edbcfc0..430c8ece 100644 --- a/lib/passes/instrumentation/TypeARTFunctions.h +++ b/lib/passes/instrumentation/TypeARTFunctions.h @@ -15,6 +15,7 @@ #include "InstrumentationHelper.h" #include "configuration/Configuration.h" +#include "instrumentation/TypeIDProvider.h" #include @@ -37,8 +38,9 @@ IFunc ifunc_for_function(IFunc general_type, llvm::Value* value); class TAFunctionQuery { public: - virtual llvm::Function* getFunctionFor(IFunc id) const = 0; - virtual ~TAFunctionQuery() = default; + virtual llvm::Function* getFunctionFor( + IFunc id, TypeSerializationImplementation impl = TypeSerializationImplementation::FILE) const = 0; + virtual ~TAFunctionQuery() = default; }; std::unique_ptr declare_instrumentation_functions(llvm::Module& m, diff --git a/lib/passes/instrumentation/TypeIDProvider.cpp b/lib/passes/instrumentation/TypeIDProvider.cpp index 43258d79..7af98dc2 100644 --- a/lib/passes/instrumentation/TypeIDProvider.cpp +++ b/lib/passes/instrumentation/TypeIDProvider.cpp @@ -351,13 +351,39 @@ class TypeRegistryGlobals final : public TypeRegistry { } }; +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) { - if (configuration[config::ConfigStdArgs::instrumentation]) { - return std::make_unique(m, type_db, f_query); + TypeSerializationImplementation impl = configuration[config::ConfigStdArgs::type_serialization]; + 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); } - return std::make_unique(); } } // namespace typeart \ No newline at end of file diff --git a/lib/passes/instrumentation/TypeIDProvider.h b/lib/passes/instrumentation/TypeIDProvider.h index 585e997e..f1f458b0 100644 --- a/lib/passes/instrumentation/TypeIDProvider.h +++ b/lib/passes/instrumentation/TypeIDProvider.h @@ -1,10 +1,12 @@ #ifndef LIB_PASSES_INSTRUMENTATION_MODULETYPEREGISTRY #define LIB_PASSES_INSTRUMENTATION_MODULETYPEREGISTRY -#include "TypeARTFunctions.h" -#include "TypeDatabase.h" -#include "TypeGenerator.h" +// #include "TypeARTFunctions.h" +// #include "instrumentation/TypeARTFunctions.h" +#include "typegen/TypeGenerator.h" +#include "typelib/TypeDatabase.h" +#include #include namespace llvm { @@ -14,9 +16,12 @@ class Module; namespace typeart { +enum class TypeSerializationImplementation : uint8_t { FILE, INLINE, HYBRID }; + namespace config { class Configuration; } +class TAFunctionQuery; class TypeRegistry { public: diff --git a/lib/support/ConfigurationBaseOptions.h b/lib/support/ConfigurationBaseOptions.h index 6496f010..87b889b0 100644 --- a/lib/support/ConfigurationBaseOptions.h +++ b/lib/support/ConfigurationBaseOptions.h @@ -44,7 +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(instrumentation, "instumentation", bool, true, "Instrument with module local types.", - "INSTRUMENTATION") +TYPEART_CONFIG_OPTION(type_serialization, "type-serialization", std::string, "file", + "Serialization mode for type representation.", "TYPE_SERIALIZATION") #undef TYPEART_CONFIG_OPTION diff --git a/test/pass/inline_types/01_simple_malloc_int.c b/test/pass/inline_types/01_simple_malloc_int.c index 4fe6e0b1..5e732635 100644 --- a/test/pass/inline_types/01_simple_malloc_int.c +++ b/test/pass/inline_types/01_simple_malloc_int.c @@ -1,5 +1,5 @@ // clang-format off -// RUN: %c-to-llvm %s | %apply-typeart -typeart-instumentation=true -S 2>&1 | %filecheck %s +// RUN: %c-to-llvm %s | %apply-typeart -typeart-type-serialization=inline -S 2>&1 | %filecheck %s // REQUIRES: llvm-18 || llvm-19 // clang-format on diff --git a/test/pass/inline_types/02_calloc_realloc.c b/test/pass/inline_types/02_calloc_realloc.c index 14a32a43..6c568d70 100644 --- a/test/pass/inline_types/02_calloc_realloc.c +++ b/test/pass/inline_types/02_calloc_realloc.c @@ -1,6 +1,6 @@ // clang-format off -// RUN: %c-to-llvm %s | %apply-typeart -typeart-instumentation=true -S 2>&1 | %filecheck %s --check-prefix=REALLOC -// RUN: %c-to-llvm %s | %apply-typeart -typeart-instumentation=true -S 2>&1 | %filecheck %s +// 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 diff --git a/test/pass/inline_types/03_simple_malloc_struct.c b/test/pass/inline_types/03_simple_malloc_struct.c index 817b3eb5..4531dfca 100644 --- a/test/pass/inline_types/03_simple_malloc_struct.c +++ b/test/pass/inline_types/03_simple_malloc_struct.c @@ -1,5 +1,5 @@ // clang-format off -// RUN: %c-to-llvm %s | %apply-typeart -typeart-instumentation=true -S 2>&1 | %filecheck %s +// RUN: %c-to-llvm %s | %apply-typeart -typeart-type-serialization=inline -S 2>&1 | %filecheck %s // REQUIRES: llvm-18 || llvm-19 // clang-format on diff --git a/test/pass/inline_types/04_fwd_decl.cpp b/test/pass/inline_types/04_fwd_decl.cpp index 8ceb8c06..0558c14f 100644 --- a/test/pass/inline_types/04_fwd_decl.cpp +++ b/test/pass/inline_types/04_fwd_decl.cpp @@ -1,6 +1,4 @@ -// RUN: export TYPEART_INSTRUMENTATION=1 - -// RUN: %cpp-to-llvm %s | %apply-typeart -typeart-instumentation=true -S | %filecheck --match-full-lines %s +// RUN: %cpp-to-llvm %s | %apply-typeart -typeart-type-serialization=inline -S | %filecheck --match-full-lines %s // CHECK: @_typeart__ZTS6Domain = extern_weak constant %struct._typeart_struct_layout_t diff --git a/test/pass/misc/08_config_file_default.c b/test/pass/misc/08_config_file_default.c index f5bcf213..32094d47 100644 --- a/test/pass/misc/08_config_file_default.c +++ b/test/pass/misc/08_config_file_default.c @@ -9,6 +9,7 @@ // CHECK-NEXT: stats: true // CHECK-NEXT: stack-lifetime: true // CHECK-NEXT: typegen: {{dimeta|ir}} +// CHECK-NEXT: type-serialization: file // CHECK-NEXT: filter: false // CHECK-NEXT: call-filter: // CHECK-NEXT: implementation: std diff --git a/test/runtime_inlined_types/01_simple_malloc_int.c b/test/runtime_inlined_types/01_simple_malloc_int.c index ea75937a..913e281e 100644 --- a/test/runtime_inlined_types/01_simple_malloc_int.c +++ b/test/runtime_inlined_types/01_simple_malloc_int.c @@ -1,5 +1,5 @@ // clang-format off -// RUN: export TYPEART_INSTRUMENTATION=1 +// RUN: export TYPEART_TYPE_SERIALIZATION=inline // RUN: %wrapper-cc -O1 %s -o %s.exe // RUN: %s.exe 2>&1 | %filecheck %s 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 index 8a45ee45..884df737 100644 --- a/test/runtime_inlined_types/02_simple_malloc_int_multi_tu.c +++ b/test/runtime_inlined_types/02_simple_malloc_int_multi_tu.c @@ -1,5 +1,5 @@ // clang-format off -// RUN: export TYPEART_INSTRUMENTATION=1 +// 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 diff --git a/test/runtime_inlined_types/03_simple_malloc_struct.c b/test/runtime_inlined_types/03_simple_malloc_struct.c index cf40370b..112b8a78 100644 --- a/test/runtime_inlined_types/03_simple_malloc_struct.c +++ b/test/runtime_inlined_types/03_simple_malloc_struct.c @@ -1,5 +1,5 @@ // clang-format off -// RUN: export TYPEART_INSTRUMENTATION=1 +// RUN: export TYPEART_TYPE_SERIALIZATION=inline // RUN: %wrapper-cc -O1 %s -o %s.exe // RUN: %s.exe 2>&1 | %filecheck %s diff --git a/test/runtime_inlined_types/04_malloc_struct.c b/test/runtime_inlined_types/04_malloc_struct.c index 16f8a988..836560c1 100644 --- a/test/runtime_inlined_types/04_malloc_struct.c +++ b/test/runtime_inlined_types/04_malloc_struct.c @@ -1,5 +1,5 @@ // clang-format off -// RUN: export TYPEART_INSTRUMENTATION=1 +// RUN: export TYPEART_TYPE_SERIALIZATION=inline // RUN: %wrapper-cc -O1 %s -o %s.exe // RUN: %s.exe 2>&1 | %filecheck %s From c12eb1696d38494165b2e210eb0a9b44d5370dae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20H=C3=BCck?= Date: Fri, 31 Oct 2025 12:25:49 +0100 Subject: [PATCH 15/35] Refactoring --- .../CallBackFunctionInserter.cpp | 42 +++++++------------ .../CallBackFunctionInserter.h | 15 ++++--- .../instrumentation/MemOpInstrumentation.cpp | 6 +-- lib/passes/instrumentation/TypeARTFunctions.h | 2 +- lib/passes/instrumentation/TypeIDProvider.h | 2 +- lib/passes/typegen/TypeGenerator.cpp | 2 +- test/pass/inline_types/01_simple_malloc_int.c | 12 ++++++ .../inline_types/03_simple_malloc_struct.c | 14 +++++++ 8 files changed, 56 insertions(+), 39 deletions(-) diff --git a/lib/passes/instrumentation/CallBackFunctionInserter.cpp b/lib/passes/instrumentation/CallBackFunctionInserter.cpp index dadeeb89..d5520cc2 100644 --- a/lib/passes/instrumentation/CallBackFunctionInserter.cpp +++ b/lib/passes/instrumentation/CallBackFunctionInserter.cpp @@ -21,24 +21,20 @@ class CallbackFunctionInserter final : public InstrumentationInserter { private: llvm::CallInst* create_instrumentation_call(llvm::IRBuilder<>& IRB, IFunc callback_type, - llvm::Value* instruction_or_value, llvm::Value* pointer_value, - llvm::Value* element_count, llvm::Value* typeid_value); + 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, - llvm::Value* pointer_value, llvm::Value* element_count, - llvm::Value* typeid_value) override; + InstrumentationPayload) override; llvm::CallInst* insert_stack_instrumentation(llvm::IRBuilder<>& IRB, llvm::Instruction* alloca, - llvm::Value* pointer_value, llvm::Value* element_count, - llvm::Value* typeid_value) override; + InstrumentationPayload) override; llvm::CallInst* insert_global_instrumentation(llvm::IRBuilder<>& IRB, llvm::GlobalValue* global_var, - llvm::Value* pointer_value, llvm::Value* element_count, - llvm::Value* typeid_value) override; + InstrumentationPayload) override; llvm::CallInst* insert_free_instrumentation(llvm::IRBuilder<>& IRB, llvm::Value* pointer_value) override; }; @@ -54,40 +50,32 @@ CallbackFunctionInserter::CallbackFunctionInserter(const config::Configuration& // Private Helper Definition llvm::CallInst* CallbackFunctionInserter::create_instrumentation_call(llvm::IRBuilder<>& IRB, IFunc callback_type, llvm::Value* instruction_or_value, - llvm::Value* pointer_value, - llvm::Value* element_count, - llvm::Value* typeid_value) { + InstrumentationPayload args) { const auto callback_id = ifunc_for_function(callback_type, instruction_or_value); - auto type_id_param_out = type_id_handler_->getOrRegister(typeid_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; - LOG_FATAL(int(mode)); - auto function = function_query_->getFunctionFor(callback_id, mode); + auto function = function_query_->getFunctionFor(callback_id, mode); - return IRB.CreateCall(function, llvm::ArrayRef{pointer_value, type_id_param_out, element_count}); + 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, - llvm::Value* pointer_value, - llvm::Value* element_count, - llvm::Value* typeid_value) { - return create_instrumentation_call(IRB, IFunc::heap, heap_call, pointer_value, element_count, typeid_value); + InstrumentationPayload args) { + return create_instrumentation_call(IRB, IFunc::heap, heap_call, args); } llvm::CallInst* CallbackFunctionInserter::insert_stack_instrumentation(llvm::IRBuilder<>& IRB, llvm::Instruction* alloca, - llvm::Value* pointer_value, - llvm::Value* element_count, - llvm::Value* typeid_value) { - return create_instrumentation_call(IRB, IFunc::stack, alloca, pointer_value, element_count, typeid_value); + InstrumentationPayload args) { + return create_instrumentation_call(IRB, IFunc::stack, alloca, args); } llvm::CallInst* CallbackFunctionInserter::insert_global_instrumentation(llvm::IRBuilder<>& IRB, llvm::GlobalValue* global_var, - llvm::Value* pointer_value, - llvm::Value* element_count, - llvm::Value* typeid_value) { - return create_instrumentation_call(IRB, IFunc::global, global_var, pointer_value, element_count, typeid_value); + InstrumentationPayload args) { + return create_instrumentation_call(IRB, IFunc::global, global_var, args); } llvm::CallInst* CallbackFunctionInserter::insert_free_instrumentation(llvm::IRBuilder<>& IRB, diff --git a/lib/passes/instrumentation/CallBackFunctionInserter.h b/lib/passes/instrumentation/CallBackFunctionInserter.h index a460cd22..0026f4a7 100644 --- a/lib/passes/instrumentation/CallBackFunctionInserter.h +++ b/lib/passes/instrumentation/CallBackFunctionInserter.h @@ -22,21 +22,24 @@ 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, - llvm::Value* pointer_value, llvm::Value* element_count, - llvm::Value* typeid_value) = 0; + InstrumentationPayload) = 0; virtual llvm::CallInst* insert_stack_instrumentation(llvm::IRBuilder<>& IRB, llvm::Instruction* alloca, - llvm::Value* pointer_value, llvm::Value* element_count, - llvm::Value* typeid_value) = 0; + InstrumentationPayload) = 0; virtual llvm::CallInst* insert_global_instrumentation(llvm::IRBuilder<>& IRB, llvm::GlobalValue* global_var, - llvm::Value* pointer_value, llvm::Value* element_count, - llvm::Value* typeid_value) = 0; + InstrumentationPayload) = 0; virtual llvm::CallInst* insert_free_instrumentation(llvm::IRBuilder<>& IRB, llvm::Value* pointer_value) = 0; }; diff --git a/lib/passes/instrumentation/MemOpInstrumentation.cpp b/lib/passes/instrumentation/MemOpInstrumentation.cpp index 69b39c50..5905a9f0 100644 --- a/lib/passes/instrumentation/MemOpInstrumentation.cpp +++ b/lib/passes/instrumentation/MemOpInstrumentation.cpp @@ -146,7 +146,7 @@ InstrCount MemOpInstrumentation::instrumentHeap(const HeapArgList& heap) { continue; } - function_instrumenter_->insert_heap_instrumentation(IRB, malloc.call, malloc_call, element_count, typeid_value); + 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); @@ -213,7 +213,7 @@ InstrCount MemOpInstrumentation::instrumentStack(const StackArgList& stack) { // 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); + function_instrumenter_->insert_stack_instrumentation(IRB, alloca, {data_ptr, numElementsVal, typeIdConst}); ++counter; auto* bblock = anchor->getParent(); @@ -258,7 +258,7 @@ InstrCount MemOpInstrumentation::instrumentGlobal(const GlobalArgList& globals) // 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); + function_instrumenter_->insert_global_instrumentation(IRB, global, {globalPtr, numElementsVal, typeIdConst}); ++counter; } }; diff --git a/lib/passes/instrumentation/TypeARTFunctions.h b/lib/passes/instrumentation/TypeARTFunctions.h index 430c8ece..e0927ae3 100644 --- a/lib/passes/instrumentation/TypeARTFunctions.h +++ b/lib/passes/instrumentation/TypeARTFunctions.h @@ -38,7 +38,7 @@ IFunc ifunc_for_function(IFunc general_type, llvm::Value* value); class TAFunctionQuery { public: - virtual llvm::Function* getFunctionFor( + [[nodiscard]] virtual llvm::Function* getFunctionFor( IFunc id, TypeSerializationImplementation impl = TypeSerializationImplementation::FILE) const = 0; virtual ~TAFunctionQuery() = default; }; diff --git a/lib/passes/instrumentation/TypeIDProvider.h b/lib/passes/instrumentation/TypeIDProvider.h index f1f458b0..e0467edc 100644 --- a/lib/passes/instrumentation/TypeIDProvider.h +++ b/lib/passes/instrumentation/TypeIDProvider.h @@ -25,7 +25,7 @@ class TAFunctionQuery; class TypeRegistry { public: - virtual llvm::Value* getOrRegister(llvm::Value* type_id_const) = 0; + [[nodiscard]] virtual llvm::Value* getOrRegister(llvm::Value* type_id_const) = 0; virtual void registerModule(const ModuleData&); virtual ~TypeRegistry() = default; }; diff --git a/lib/passes/typegen/TypeGenerator.cpp b/lib/passes/typegen/TypeGenerator.cpp index 9517e431..2401bda2 100644 --- a/lib/passes/typegen/TypeGenerator.cpp +++ b/lib/passes/typegen/TypeGenerator.cpp @@ -55,7 +55,7 @@ int TypeIDGenerator::reserveNextTypeId() { } const TypeDatabase& TypeIDGenerator::getTypeDatabase() const { - return *this->typeDB.get(); + return *this->typeDB; } bool TypeIDGenerator::registerModule(ModuleData&) { diff --git a/test/pass/inline_types/01_simple_malloc_int.c b/test/pass/inline_types/01_simple_malloc_int.c index 5e732635..1ec9cadf 100644 --- a/test/pass/inline_types/01_simple_malloc_int.c +++ b/test/pass/inline_types/01_simple_malloc_int.c @@ -1,6 +1,10 @@ // 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 @@ -16,3 +20,11 @@ void test() { // CHECK: %struct._typeart_struct_layout_t = type { i32, ptr, i64, i64, ptr, ptr, ptr, i32 } // 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 { i32, ptr, i64, i64, ptr, ptr, ptr, i32 } +// 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 { i32, ptr, i64, i64, ptr, ptr, ptr, i32 } +// 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/03_simple_malloc_struct.c b/test/pass/inline_types/03_simple_malloc_struct.c index 4531dfca..9cec9b30 100644 --- a/test/pass/inline_types/03_simple_malloc_struct.c +++ b/test/pass/inline_types/03_simple_malloc_struct.c @@ -1,6 +1,10 @@ // 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 @@ -23,3 +27,13 @@ void test() { // 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]]) From 28f408e5254d19eeedd0c506d233c658d59c860f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20H=C3=BCck?= Date: Fri, 31 Oct 2025 15:00:06 +0100 Subject: [PATCH 16/35] Add OpenMP variants --- .../instrumentation/TypeARTFunctions.cpp | 6 +++- lib/runtime/AllocationTracking.cpp | 14 +++++++++ lib/runtime/CallbackInterface.h | 3 ++ lib/runtime/GlobalTypeDefCallbacks.cpp | 31 ++++++++++--------- 4 files changed, 39 insertions(+), 15 deletions(-) diff --git a/lib/passes/instrumentation/TypeARTFunctions.cpp b/lib/passes/instrumentation/TypeARTFunctions.cpp index e9c052b9..6d16b18c 100644 --- a/lib/passes/instrumentation/TypeARTFunctions.cpp +++ b/lib/passes/instrumentation/TypeARTFunctions.cpp @@ -288,6 +288,8 @@ 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 @@ -326,7 +328,9 @@ std::unique_ptr declare_instrumentation_functions(llvm::Module& typeart_leave_scope_omp.f = decl.make_function(IFunc::scope_omp, typeart_leave_scope_omp.name, leavescope_arg_types); - // TODO: mty for OMP + typeart_alloc_omp_mty.f = decl.make_function(IFunc::heap_omp, typeart_alloc_omp_mty.name, alloc_arg_types_mty); + typeart_alloc_stacks_omp_mty.f = + decl.make_function(IFunc::stack_omp, typeart_alloc_stacks_omp_mty.name, alloc_arg_types_mty); return std::make_unique(functions, functions_alternative); } diff --git a/lib/runtime/AllocationTracking.cpp b/lib/runtime/AllocationTracking.cpp index e7ecc9f4..94ef8533 100644 --- a/lib/runtime/AllocationTracking.cpp +++ b/lib/runtime/AllocationTracking.cpp @@ -307,3 +307,17 @@ void __typeart_alloc_global_mty(const void* addr, const void* info, size_t count typeart::RuntimeSystem::get().allocTracker.onAllocGlobal( addr, typeart::RuntimeSystem::get().type_translator.get_type_id_for(info), 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); + typeart::RuntimeSystem::get().allocTracker.onAlloc( + addr, typeart::RuntimeSystem::get().type_translator.get_type_id_for(info), 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); + typeart::RuntimeSystem::get().allocTracker.onAllocStack( + addr, typeart::RuntimeSystem::get().type_translator.get_type_id_for(info), count, retAddr); +} diff --git a/lib/runtime/CallbackInterface.h b/lib/runtime/CallbackInterface.h index 101d6cb6..6ca76206 100644 --- a/lib/runtime/CallbackInterface.h +++ b/lib/runtime/CallbackInterface.h @@ -42,6 +42,9 @@ 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 index 21b83f96..23145d4d 100644 --- a/lib/runtime/GlobalTypeDefCallbacks.cpp +++ b/lib/runtime/GlobalTypeDefCallbacks.cpp @@ -22,30 +22,32 @@ namespace typeart { +#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; \ } +struct GlobalTypeInfo { + int type_id; + const char* name; + size_t extent; + size_t num_members; + const std::int64_t* offsets; + const GlobalTypeInfo** member_types; + const std::int64_t* array_sizes; + int flag; +}; + class GlobalTypeTranslator::Impl { - public: TypeDB& type_db_; RuntimeT::TypeLookupMapT& translator_map_; - - struct GlobalTypeInfo { - int type_id; - const char* name; - size_t extent; - size_t num_members; - const std::int64_t* offsets; - const GlobalTypeInfo** member_types; - const std::int64_t* array_sizes; - int flag; - }; - int struct_count{0}; + public: explicit Impl(TypeDB& db, RuntimeT::TypeLookupMapT& translator_map) : type_db_(db), translator_map_(translator_map) { } @@ -96,10 +98,11 @@ class GlobalTypeTranslator::Impl { GlobalTypeTranslator::GlobalTypeTranslator(TypeDB& 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* info_struct = reinterpret_cast(type); pImpl->register_t(info_struct); } From a6e09b1a2eedb5a59e4d9234ddb66d8d3b377183 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20H=C3=BCck?= Date: Fri, 31 Oct 2025 17:00:24 +0100 Subject: [PATCH 17/35] Dependency fixes --- lib/runtime/CMakeLists.txt | 1 + lib/runtime/GlobalTypeDefCallbacks.cpp | 9 +++------ 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/lib/runtime/CMakeLists.txt b/lib/runtime/CMakeLists.txt index 84488d8d..5d04cfbb 100644 --- a/lib/runtime/CMakeLists.txt +++ b/lib/runtime/CMakeLists.txt @@ -49,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/GlobalTypeDefCallbacks.cpp b/lib/runtime/GlobalTypeDefCallbacks.cpp index 23145d4d..798e2acc 100644 --- a/lib/runtime/GlobalTypeDefCallbacks.cpp +++ b/lib/runtime/GlobalTypeDefCallbacks.cpp @@ -58,9 +58,8 @@ class GlobalTypeTranslator::Impl { } int register_t(const GlobalTypeInfo* type) { - // const bool built_in = type->type_id < TYPEART_NUM_VALID_IDS; - if (translator_map_.contains(type)) { - return translator_map_[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); @@ -76,8 +75,6 @@ class GlobalTypeTranslator::Impl { type_descriptor.num_members = type->num_members; type_descriptor.flag = static_cast(type->flag); - // const auto* array_sizes = static_cast(type->array_sizes); - // const auto* array_offset = static_cast(type->offsets); type_descriptor.array_sizes.reserve(type->num_members); type_descriptor.offsets.reserve(type->num_members); type_descriptor.member_types.reserve(type->num_members); @@ -86,7 +83,7 @@ class GlobalTypeTranslator::Impl { const auto offset = type->offsets[i]; type_descriptor.array_sizes.emplace_back(array_size); type_descriptor.offsets.emplace_back(offset); - const auto member_id = register_t(reinterpret_cast(type->member_types[i])); + const auto member_id = register_t(type->member_types[i]); type_descriptor.member_types.emplace_back(member_id); } From c433c2331f7c31371315638baacc2336c4f8b8ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20H=C3=BCck?= Date: Sat, 1 Nov 2025 15:10:14 +0100 Subject: [PATCH 18/35] Various fixes --- externals/abseil/CMakeLists.txt | 2 +- .../CallBackFunctionInserter.cpp | 7 +++--- .../CallBackFunctionInserter.h | 3 ++- .../instrumentation/MemOpInstrumentation.cpp | 6 +++-- .../instrumentation/TypeARTFunctions.cpp | 5 +++-- lib/passes/instrumentation/TypeIDProvider.cpp | 22 +++++++++++++++++-- 6 files changed, 34 insertions(+), 11 deletions(-) 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/instrumentation/CallBackFunctionInserter.cpp b/lib/passes/instrumentation/CallBackFunctionInserter.cpp index d5520cc2..cd89f9f7 100644 --- a/lib/passes/instrumentation/CallBackFunctionInserter.cpp +++ b/lib/passes/instrumentation/CallBackFunctionInserter.cpp @@ -36,7 +36,8 @@ class CallbackFunctionInserter final : public InstrumentationInserter { llvm::CallInst* insert_global_instrumentation(llvm::IRBuilder<>& IRB, llvm::GlobalValue* global_var, InstrumentationPayload) override; - llvm::CallInst* insert_free_instrumentation(llvm::IRBuilder<>& IRB, llvm::Value* pointer_value) override; + llvm::CallInst* insert_free_instrumentation(llvm::IRBuilder<>& IRB, llvm::CallBase* call, + llvm::Value* pointer_value) override; }; CallbackFunctionInserter::CallbackFunctionInserter(const config::Configuration& configuration, @@ -78,9 +79,9 @@ llvm::CallInst* CallbackFunctionInserter::insert_global_instrumentation(llvm::IR return create_instrumentation_call(IRB, IFunc::global, global_var, args); } -llvm::CallInst* CallbackFunctionInserter::insert_free_instrumentation(llvm::IRBuilder<>& IRB, +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, pointer_value); + const auto callback_id = ifunc_for_function(IFunc::free, call); return IRB.CreateCall(function_query_->getFunctionFor(callback_id), llvm::ArrayRef{pointer_value}); } diff --git a/lib/passes/instrumentation/CallBackFunctionInserter.h b/lib/passes/instrumentation/CallBackFunctionInserter.h index 0026f4a7..70e88737 100644 --- a/lib/passes/instrumentation/CallBackFunctionInserter.h +++ b/lib/passes/instrumentation/CallBackFunctionInserter.h @@ -41,7 +41,8 @@ class InstrumentationInserter { 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::Value* pointer_value) = 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, diff --git a/lib/passes/instrumentation/MemOpInstrumentation.cpp b/lib/passes/instrumentation/MemOpInstrumentation.cpp index 5905a9f0..b50f1fc2 100644 --- a/lib/passes/instrumentation/MemOpInstrumentation.cpp +++ b/lib/passes/instrumentation/MemOpInstrumentation.cpp @@ -43,6 +43,7 @@ #include "llvm/Support/raw_ostream.h" #include "llvm/Transforms/Utils/ModuleUtils.h" +#include #include #include @@ -138,7 +139,8 @@ InstrCount MemOpInstrumentation::instrumentHeap(const HeapArgList& heap) { element_count = calculate_element_count(bytes); IRBuilder<> free_before_realloc(malloc_call); - function_instrumenter_->insert_free_instrumentation(free_before_realloc, target_memory_address); + function_instrumenter_->insert_free_instrumentation(free_before_realloc, llvm::dyn_cast(malloc_call), + target_memory_address); break; } default: @@ -184,7 +186,7 @@ InstrCount MemOpInstrumentation::instrumentFree(const FreeArgList& frees) { IRBuilder<> IRB(insertBefore); - function_instrumenter_->insert_free_instrumentation(IRB, free_arg); + 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; diff --git a/lib/passes/instrumentation/TypeARTFunctions.cpp b/lib/passes/instrumentation/TypeARTFunctions.cpp index 6d16b18c..027c0223 100644 --- a/lib/passes/instrumentation/TypeARTFunctions.cpp +++ b/lib/passes/instrumentation/TypeARTFunctions.cpp @@ -328,9 +328,10 @@ std::unique_ptr declare_instrumentation_functions(llvm::Module& 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.make_function(IFunc::heap_omp, typeart_alloc_omp_mty.name, alloc_arg_types_mty); + 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.make_function(IFunc::stack_omp, typeart_alloc_stacks_omp_mty.name, alloc_arg_types_mty); + decl_alternatives.make_function(IFunc::stack_omp, typeart_alloc_stacks_omp_mty.name, alloc_arg_types_mty); return std::make_unique(functions, functions_alternative); } diff --git a/lib/passes/instrumentation/TypeIDProvider.cpp b/lib/passes/instrumentation/TypeIDProvider.cpp index 7af98dc2..01467f85 100644 --- a/lib/passes/instrumentation/TypeIDProvider.cpp +++ b/lib/passes/instrumentation/TypeIDProvider.cpp @@ -78,11 +78,19 @@ struct GlobalTypeData { 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 } }; @@ -105,9 +113,11 @@ struct GlobalTypeCallback { Function* ctorFunction = Function::Create(ctorType, Function::PrivateLinkage, ctor_function_name, module_); BasicBlock* entry = BasicBlock::Create(c, "entry", ctorFunction); auto* ret_inst = ReturnInst::Create(c); - // llvm::IRBuilder<> Builder(entry); +#if LLVM_VERSION_MAJOR > 17 ret_inst->insertInto(entry, entry->getFirstInsertionPt()); - // Builder.CreateRetVoid(); +#else + entry->getInstList().push_back(ret_inst); +#endif llvm::appendToGlobalCtors(*module_, ctorFunction, 0, nullptr); @@ -376,6 +386,13 @@ std::unique_ptr get_type_id_handler(llvm::Module& m, const TypeDat 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("Warning unsupported type serialization mode.") + } + // 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(); @@ -384,6 +401,7 @@ std::unique_ptr get_type_id_handler(llvm::Module& m, const TypeDat default: return std::make_unique(m, type_db, f_query); } +#endif } } // namespace typeart \ No newline at end of file From 98b0a0216eaacc6614d4ccbda996b1de0eb9fc51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20H=C3=BCck?= Date: Sat, 1 Nov 2025 18:25:02 +0100 Subject: [PATCH 19/35] Various fixes * LLVM 14: disregard inline/hybrid type serialization mode. * Non-opaque LLVM: always emit type file, also see above * Type handling: Arrays of MPI type handles (pointer to opaque struct) are treated as pointers * Runtime: check if hash map has type entry --- demo/Makefile | 2 +- lib/passes/TypeARTPass.cpp | 6 +++++- lib/passes/instrumentation/TypeIDProvider.cpp | 9 +++++++- lib/passes/typegen/dimeta/DimetaTypeGen.cpp | 8 ++++--- lib/runtime/AllocationTracking.cpp | 21 ++++++++++--------- lib/runtime/GlobalTypeDefCallbacks.h | 6 +++++- lib/typelib/TypeDB.cpp | 19 ++++++++++------- scripts/typeart-wrapperv2.in | 4 +++- test/script/07_wrapper_demo.sh | 4 ---- test/script/12_ir_viewer.sh | 8 +++---- 10 files changed, 54 insertions(+), 33 deletions(-) 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/lib/passes/TypeARTPass.cpp b/lib/passes/TypeARTPass.cpp index 6ec65b69..c86732c8 100644 --- a/lib/passes/TypeARTPass.cpp +++ b/lib/passes/TypeARTPass.cpp @@ -50,6 +50,7 @@ #include #include +#include #include #include #include @@ -183,7 +184,10 @@ class TypeArtPass : public llvm::PassInfoMixin { /* * Persist the accumulated type definition information for this module. */ - if (!configuration()[config::ConfigStdArgs::type_serialization]) { + // 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); diff --git a/lib/passes/instrumentation/TypeIDProvider.cpp b/lib/passes/instrumentation/TypeIDProvider.cpp index 01467f85..c3a8a4f5 100644 --- a/lib/passes/instrumentation/TypeIDProvider.cpp +++ b/lib/passes/instrumentation/TypeIDProvider.cpp @@ -270,6 +270,7 @@ struct GlobalTypeRegistrar { const auto type_size = type_struct->extent; if (type_struct->flag == StructTypeFlag::FWD_DECL) { + LOG_DEBUG("Type is forward decl " << name) return registerGlobalStructDecl(name); } @@ -311,6 +312,9 @@ struct GlobalTypeRegistrar { 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); } @@ -351,8 +355,11 @@ class TypeRegistryGlobals final : public TypeRegistry { if (builtins::BuiltInQuery::is_builtin_type(type.type_id)) { continue; } + if (!registrar_.type_db_->isValid(type.type_id)) { + continue; + } + LOG_DEBUG("Registering type_id " << type.type_id) const auto* type_id = registrar_.getOrRegister(type.type_id); - LOG_DEBUG("Registering type_id " << *type_id) } } diff --git a/lib/passes/typegen/dimeta/DimetaTypeGen.cpp b/lib/passes/typegen/dimeta/DimetaTypeGen.cpp index 6adcbfb7..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)) { diff --git a/lib/runtime/AllocationTracking.cpp b/lib/runtime/AllocationTracking.cpp index 94ef8533..2375ce77 100644 --- a/lib/runtime/AllocationTracking.cpp +++ b/lib/runtime/AllocationTracking.cpp @@ -16,6 +16,7 @@ #include "CallbackInterface.h" #include "Runtime.h" #include "RuntimeData.h" +#include "RuntimeInterface.h" #include "TypeDB.h" #include "support/Logger.h" #include "typelib/TypeDatabase.h" @@ -290,34 +291,34 @@ void __typeart_leave_scope_omp(int alloca_count) { void __typeart_alloc_mty(const void* addr, const void* info, size_t count) { TYPEART_RUNTIME_GUARD; const void* retAddr = __builtin_return_address(0); - typeart::RuntimeSystem::get().allocTracker.onAlloc( - addr, typeart::RuntimeSystem::get().type_translator.get_type_id_for(info), count, retAddr); + const auto type_id = typeart::RuntimeSystem::get().type_translator.get_type_id_for(info); + typeart::RuntimeSystem::get().allocTracker.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); - typeart::RuntimeSystem::get().allocTracker.onAllocStack( - addr, typeart::RuntimeSystem::get().type_translator.get_type_id_for(info), count, retAddr); + const auto type_id = typeart::RuntimeSystem::get().type_translator.get_type_id_for(info); + typeart::RuntimeSystem::get().allocTracker.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); - typeart::RuntimeSystem::get().allocTracker.onAllocGlobal( - addr, typeart::RuntimeSystem::get().type_translator.get_type_id_for(info), count, retAddr); + const auto type_id = typeart::RuntimeSystem::get().type_translator.get_type_id_for(info); + typeart::RuntimeSystem::get().allocTracker.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); - typeart::RuntimeSystem::get().allocTracker.onAlloc( - addr, typeart::RuntimeSystem::get().type_translator.get_type_id_for(info), count, retAddr); + const auto type_id = typeart::RuntimeSystem::get().type_translator.get_type_id_for(info); + typeart::RuntimeSystem::get().allocTracker.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); - typeart::RuntimeSystem::get().allocTracker.onAllocStack( - addr, typeart::RuntimeSystem::get().type_translator.get_type_id_for(info), count, retAddr); + const auto type_id = typeart::RuntimeSystem::get().type_translator.get_type_id_for(info); + typeart::RuntimeSystem::get().allocTracker.onAllocStack(addr, type_id, count, retAddr); } diff --git a/lib/runtime/GlobalTypeDefCallbacks.h b/lib/runtime/GlobalTypeDefCallbacks.h index c6bcc0dd..605c3c63 100644 --- a/lib/runtime/GlobalTypeDefCallbacks.h +++ b/lib/runtime/GlobalTypeDefCallbacks.h @@ -28,7 +28,11 @@ class GlobalTypeTranslator final { } inline int get_type_id_for(MemAddr addr) const { - return translator_map.find(addr)->second; + if (auto element = translator_map.find(addr); element != translator_map.end()) { + return element->second; + } + LOG_DEBUG("Unknown type for address " << addr) + return TYPEART_UNKNOWN_TYPE; } GlobalTypeTranslator(const GlobalTypeTranslator&) = delete; diff --git a/lib/typelib/TypeDB.cpp b/lib/typelib/TypeDB.cpp index 056cc963..e3409ec9 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)); } @@ -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/scripts/typeart-wrapperv2.in b/scripts/typeart-wrapperv2.in index ef0557c8..5393e464 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/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 From 81207b7bd41b9b614865b05fa4b42df2814b45b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20H=C3=BCck?= Date: Sun, 2 Nov 2025 12:21:03 +0100 Subject: [PATCH 20/35] Refactoring runtime --- lib/runtime/AccessCountPrinter.h | 5 ----- lib/runtime/AccessCounter.h | 6 ------ lib/runtime/AllocMapWrapper.h | 1 + lib/runtime/AllocationTracking.cpp | 2 -- lib/runtime/GlobalTypeDefCallbacks.cpp | 3 --- lib/runtime/GlobalTypeDefCallbacks.h | 8 +++----- lib/runtime/Runtime.cpp | 3 --- lib/runtime/TypeResolution.cpp | 4 +--- lib/runtime/TypeResolution.h | 6 +++--- 9 files changed, 8 insertions(+), 30 deletions(-) diff --git a/lib/runtime/AccessCountPrinter.h b/lib/runtime/AccessCountPrinter.h index 4143d6f2..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 { 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 2375ce77..1a38ae3f 100644 --- a/lib/runtime/AllocationTracking.cpp +++ b/lib/runtime/AllocationTracking.cpp @@ -16,10 +16,8 @@ #include "CallbackInterface.h" #include "Runtime.h" #include "RuntimeData.h" -#include "RuntimeInterface.h" #include "TypeDB.h" #include "support/Logger.h" -#include "typelib/TypeDatabase.h" #include "llvm/Support/raw_ostream.h" diff --git a/lib/runtime/GlobalTypeDefCallbacks.cpp b/lib/runtime/GlobalTypeDefCallbacks.cpp index 798e2acc..660f15a7 100644 --- a/lib/runtime/GlobalTypeDefCallbacks.cpp +++ b/lib/runtime/GlobalTypeDefCallbacks.cpp @@ -1,6 +1,5 @@ #include "GlobalTypeDefCallbacks.h" -#include "AccessCounter.h" #include "AllocationTracking.h" #include "CallbackInterface.h" #include "Runtime.h" @@ -10,8 +9,6 @@ #include "support/Logger.h" #include "typelib/TypeDatabase.h" -#include "llvm/Support/raw_ostream.h" - #include #include #include diff --git a/lib/runtime/GlobalTypeDefCallbacks.h b/lib/runtime/GlobalTypeDefCallbacks.h index 605c3c63..5cc742cc 100644 --- a/lib/runtime/GlobalTypeDefCallbacks.h +++ b/lib/runtime/GlobalTypeDefCallbacks.h @@ -2,15 +2,13 @@ #define LIB_RUNTIME_GLOBALTYPEDEFCALLBACKS #include "RuntimeData.h" -#include "TypeDB.h" #include "TypeInterface.h" #include "support/Logger.h" -#include "typelib/TypeDatabase.h" - -#include namespace typeart { +class TypeDB; + class GlobalTypeTranslator final { private: RuntimeT::TypeLookupMapT translator_map; @@ -31,7 +29,7 @@ class GlobalTypeTranslator final { if (auto element = translator_map.find(addr); element != translator_map.end()) { return element->second; } - LOG_DEBUG("Unknown type for address " << addr) + LOG_WARNING("Unknown type for address " << addr) return TYPEART_UNKNOWN_TYPE; } diff --git a/lib/runtime/Runtime.cpp b/lib/runtime/Runtime.cpp index 357cbace..9fbae54f 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 { diff --git a/lib/runtime/TypeResolution.cpp b/lib/runtime/TypeResolution.cpp index 0047a643..997c21e4 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 diff --git a/lib/runtime/TypeResolution.h b/lib/runtime/TypeResolution.h index f47ca4b3..08c824ab 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 { From d221989910e8ce15d6ceda2397ddee0fe02f647a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20H=C3=BCck?= Date: Sun, 2 Nov 2025 15:33:30 +0100 Subject: [PATCH 21/35] Fixes to set mode to hybrid per default --- lib/passes/TypeARTPass.cpp | 10 ++++++---- scripts/opt-shim.in | 4 ++++ scripts/typeart-wrapperv2.in | 2 +- test/typemapping/16_mpi_dtype.c | 24 ++++++++++++++++++++++++ 4 files changed, 35 insertions(+), 5 deletions(-) create mode 100644 test/typemapping/16_mpi_dtype.c diff --git a/lib/passes/TypeARTPass.cpp b/lib/passes/TypeARTPass.cpp index c86732c8..eed4416e 100644 --- a/lib/passes/TypeARTPass.cpp +++ b/lib/passes/TypeARTPass.cpp @@ -380,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; @@ -389,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/scripts/opt-shim.in b/scripts/opt-shim.in index c3dc9af0..168c61f3 100644 --- a/scripts/opt-shim.in +++ b/scripts/opt-shim.in @@ -67,6 +67,10 @@ 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_test_pass_wrapper_more_args+=" $1" shift 1 diff --git a/scripts/typeart-wrapperv2.in b/scripts/typeart-wrapperv2.in index 5393e464..cefc4091 100644 --- a/scripts/typeart-wrapperv2.in +++ b/scripts/typeart-wrapperv2.in @@ -99,7 +99,7 @@ function typeart_main_driver_fn() { typeart_more_flags+=" ${typeart_ldflags}" fi - export TYPEART_TYPE_SERIALIZATION="${TYPEART_TYPE_SERIALIZATION:-hybrid}" + # export TYPEART_TYPE_SERIALIZATION="${TYPEART_TYPE_SERIALIZATION:-hybrid}" $typeart_compiler ${typeart_plugin} ${typeart_includes} ${typeart_more_flags} ${typeart_san_flags} $@ } diff --git a/test/typemapping/16_mpi_dtype.c b/test/typemapping/16_mpi_dtype.c new file mode 100644 index 00000000..27d7499c --- /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 constant %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) From 0f71bdfd5a87dacfb0370e7a9a33bdd2c56c26b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20H=C3=BCck?= Date: Sun, 2 Nov 2025 15:56:13 +0100 Subject: [PATCH 22/35] Extended testing --- scripts/opt-shim.in | 4 ++++ test/pass/misc/05_make_all_callbacks.c | 19 +++++++++++++++---- test/pass/misc/07_config_file.c | 5 ++--- test/pass/misc/07_typeart_config_stack.yml | 2 ++ test/pass/misc/09_config_file_cl.c | 2 -- 5 files changed, 23 insertions(+), 9 deletions(-) diff --git a/scripts/opt-shim.in b/scripts/opt-shim.in index 168c61f3..bd1659ef 100644 --- a/scripts/opt-shim.in +++ b/scripts/opt-shim.in @@ -71,6 +71,10 @@ function typeart_test_parse_cmd_line_fn() { 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/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/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; From f41a4c023324853835365052eedec0eadbf4f5da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20H=C3=BCck?= Date: Sun, 2 Nov 2025 17:40:45 +0100 Subject: [PATCH 23/35] Hybrid mode per default, related bug fixes * Type descriptor member was NULL due to a fwd decl variable being extern, see 'runtime/22_threads_stack.cpp': * Fwd decl '_ZTSNSt6thread6_StateE' contained in '_ZTSNSt6thread11_State_implINS_8_InvokerISt5tupleIJPFvvEEEEEEE' * Global type variable contained whitespaces, replace with '_'. --- lib/passes/configuration/TypeARTOptions.h | 4 +++ lib/passes/instrumentation/TypeIDProvider.cpp | 11 ++++-- lib/runtime/GlobalTypeDefCallbacks.cpp | 10 ++++++ test/runtime/07_simple_struct_type_check.c | 34 +++++++++++++++---- test/runtime/08_recursive_struct_type_check.c | 24 +++++++++++-- test/runtime/22_threads_stack.cpp | 3 +- test/runtime/44_typedb.cpp | 3 ++ test/runtime/49_default_types_udef.c | 1 + 8 files changed, 79 insertions(+), 11 deletions(-) diff --git a/lib/passes/configuration/TypeARTOptions.h b/lib/passes/configuration/TypeARTOptions.h index 0351d842..edccff6f 100644 --- a/lib/passes/configuration/TypeARTOptions.h +++ b/lib/passes/configuration/TypeARTOptions.h @@ -51,7 +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{}; diff --git a/lib/passes/instrumentation/TypeIDProvider.cpp b/lib/passes/instrumentation/TypeIDProvider.cpp index c3a8a4f5..9c8b510d 100644 --- a/lib/passes/instrumentation/TypeIDProvider.cpp +++ b/lib/passes/instrumentation/TypeIDProvider.cpp @@ -42,6 +42,11 @@ class TypeRegistryNoOp final : public TypeRegistry { }; 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"); @@ -305,8 +310,10 @@ struct GlobalTypeRegistrar { } llvm::GlobalVariable* registerBuiltin(int type_id) { - StructTypeInfo type_struct{type_id, type_db_->getTypeName(type_id), type_db_->getTypeSize(type_id), 1, {0}, {}, - {1}, StructTypeFlag::BUILTIN}; + 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, {0}, + {}, {1}, StructTypeFlag::BUILTIN}; return registerTypeStruct(&type_struct); } diff --git a/lib/runtime/GlobalTypeDefCallbacks.cpp b/lib/runtime/GlobalTypeDefCallbacks.cpp index 660f15a7..dde00060 100644 --- a/lib/runtime/GlobalTypeDefCallbacks.cpp +++ b/lib/runtime/GlobalTypeDefCallbacks.cpp @@ -19,6 +19,7 @@ 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__) @@ -55,6 +56,11 @@ class GlobalTypeTranslator::Impl { } int register_t(const GlobalTypeInfo* type) { + if (unlikely(type == nullptr)) { + LOG_FATAL("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; } @@ -104,5 +110,9 @@ void GlobalTypeTranslator::register_type(const void* type) { 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/test/runtime/07_simple_struct_type_check.c b/test/runtime/07_simple_struct_type_check.c index 9aeda8b3..9f899138 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 --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/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 { From e31c9d61240777a1f7b9cb720cd5e15b697683b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20H=C3=BCck?= Date: Mon, 3 Nov 2025 13:50:50 +0100 Subject: [PATCH 24/35] Register fwd decl and map to same type id as def --- lib/passes/instrumentation/TypeIDProvider.cpp | 8 ++++--- lib/runtime/GlobalTypeDefCallbacks.cpp | 21 ++++++++++++------- lib/runtime/GlobalTypeDefCallbacks.h | 4 ++-- lib/runtime/RuntimeData.h | 14 +++++++++---- lib/typelib/TypeDB.cpp | 2 +- 5 files changed, 32 insertions(+), 17 deletions(-) diff --git a/lib/passes/instrumentation/TypeIDProvider.cpp b/lib/passes/instrumentation/TypeIDProvider.cpp index 9c8b510d..743a9c06 100644 --- a/lib/passes/instrumentation/TypeIDProvider.cpp +++ b/lib/passes/instrumentation/TypeIDProvider.cpp @@ -248,7 +248,8 @@ struct GlobalTypeRegistrar { uint64_t member_count, llvm::Constant* offset_ptr, llvm::Constant* members_data_ptr, llvm::Constant* count_ptr, StructTypeFlag flag = StructTypeFlag::USER_DEFINED) { - llvm::GlobalVariable* global_struct = create_global(name, struct_layout_type_); + const auto name_struct = flag == StructTypeFlag::FWD_DECL ? helper::concat(name, "_fwd") : name; + llvm::GlobalVariable* global_struct = create_global(name_struct, struct_layout_type_); llvm::Constant* name_str = create_global_constant_string(name); std::vector members = {ir_build.getInt32(type_id), @@ -276,7 +277,7 @@ struct GlobalTypeRegistrar { if (type_struct->flag == StructTypeFlag::FWD_DECL) { LOG_DEBUG("Type is forward decl " << name) - return registerGlobalStructDecl(name); + // return registerGlobalStructDecl(name); } llvm::Constant* offset_ptr = create_global_array_ptr(helper::concat("offsets_", name), type_struct->offsets); @@ -340,8 +341,9 @@ struct GlobalTypeRegistrar { auto* global = registerUserDefined(type_id); const auto fwd_decl = StructTypeFlag::FWD_DECL == type_db_->getStructInfo(type_id)->flag; if (!fwd_decl) { - type_callback.insert(global); + LOG_DEBUG("Registering forward declared variable " << *global) } + type_callback.insert(global); return global; }); } diff --git a/lib/runtime/GlobalTypeDefCallbacks.cpp b/lib/runtime/GlobalTypeDefCallbacks.cpp index dde00060..03b318e5 100644 --- a/lib/runtime/GlobalTypeDefCallbacks.cpp +++ b/lib/runtime/GlobalTypeDefCallbacks.cpp @@ -4,7 +4,6 @@ #include "CallbackInterface.h" #include "Runtime.h" #include "RuntimeData.h" -#include "TypeDB.h" #include "TypeInterface.h" #include "support/Logger.h" #include "typelib/TypeDatabase.h" @@ -41,17 +40,23 @@ struct GlobalTypeInfo { }; class GlobalTypeTranslator::Impl { - TypeDB& type_db_; + TypeDatabase& type_db_; RuntimeT::TypeLookupMapT& translator_map_; int struct_count{0}; + // a fwd_decl and the decl must have the same type_id: + RuntimeT::HashmapT name_typid_fwd_decl_dedup_; public: - explicit Impl(TypeDB& db, RuntimeT::TypeLookupMapT& translator_map) : type_db_(db), translator_map_(translator_map) { + explicit Impl(TypeDatabase& db, RuntimeT::TypeLookupMapT& translator_map) : type_db_(db), translator_map_(translator_map) { } - int next_type_id() { + int next_type_id(const GlobalTypeInfo* type) { + if(auto it_type = name_typid_fwd_decl_dedup_.find(type->name); it_type != name_typid_fwd_decl_dedup_.end()){ + return it_type->second; + } const int id = static_cast(TYPEART_NUM_RESERVED_IDS) + struct_count; ++struct_count; + name_typid_fwd_decl_dedup_.try_emplace(type->name, id); return id; } @@ -72,7 +77,7 @@ class GlobalTypeTranslator::Impl { } StructTypeInfo type_descriptor; - type_descriptor.type_id = next_type_id(); + 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; @@ -90,13 +95,15 @@ class GlobalTypeTranslator::Impl { type_descriptor.member_types.emplace_back(member_id); } - type_db_.registerStruct(type_descriptor, true); + const bool fwd_decl = type_descriptor.flag == StructTypeFlag::FWD_DECL; + type_db_.registerStruct(type_descriptor, !fwd_decl); translator_map_.try_emplace(type, type_descriptor.type_id); + return type_descriptor.type_id; } }; -GlobalTypeTranslator::GlobalTypeTranslator(TypeDB& db) : pImpl(std::make_unique(db, translator_map)) { +GlobalTypeTranslator::GlobalTypeTranslator(TypeDatabase& db) : pImpl(std::make_unique(db, translator_map)) { } GlobalTypeTranslator::~GlobalTypeTranslator() = default; diff --git a/lib/runtime/GlobalTypeDefCallbacks.h b/lib/runtime/GlobalTypeDefCallbacks.h index 5cc742cc..4a9d59bf 100644 --- a/lib/runtime/GlobalTypeDefCallbacks.h +++ b/lib/runtime/GlobalTypeDefCallbacks.h @@ -7,7 +7,7 @@ namespace typeart { -class TypeDB; +class TypeDatabase; class GlobalTypeTranslator final { private: @@ -16,7 +16,7 @@ class GlobalTypeTranslator final { std::unique_ptr pImpl; public: - explicit GlobalTypeTranslator(TypeDB& db); + explicit GlobalTypeTranslator(TypeDatabase& db); ~GlobalTypeTranslator(); void register_type(const void* type); diff --git a/lib/runtime/RuntimeData.h b/lib/runtime/RuntimeData.h index 36ff54a6..01f9b6d5 100644 --- a/lib/runtime/RuntimeData.h +++ b/lib/runtime/RuntimeData.h @@ -67,17 +67,23 @@ struct RuntimeT { static constexpr auto StackReserve{512U}; static constexpr char StackName[] = "std::vector"; #ifdef TYPEART_PHMAP - using PointerMapBaseT = phmap::btree_map; - using TypeLookupMapT = phmap::flat_hash_map; + using PointerMapBaseT = phmap::btree_map; + using TypeLookupMapT = phmap::flat_hash_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 + using HashmapT = absl::flat_hash_map; using TypeLookupMapT = absl::flat_hash_map; 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; using TypeLookupMapT = std::unordered_map; static constexpr char MapName[] = "std::map"; #endif diff --git a/lib/typelib/TypeDB.cpp b/lib/typelib/TypeDB.cpp index e3409ec9..9f262ed0 100644 --- a/lib/typelib/TypeDB.cpp +++ b/lib/typelib/TypeDB.cpp @@ -160,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; } From a60161a30b61f0442b4c9e34f00404d6437313ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20H=C3=BCck?= Date: Tue, 4 Nov 2025 21:38:08 +0100 Subject: [PATCH 25/35] Type serialization fixes * Always normalize global variable names during type serialization * Search type db during registration for duplicate names, remove hash map --- lib/passes/instrumentation/TypeIDProvider.cpp | 10 ++++-- lib/runtime/GlobalTypeDefCallbacks.cpp | 32 +++++++++++-------- test/pass/arrays/05_vector.c | 2 +- test/pass/arrays/07_avx.c | 2 +- test/pass/inline_types/04_fwd_decl.cpp | 4 +-- .../malloc_free/05_simple_malloc_struct.c | 2 +- test/pass/misc/08_config_file_default.c | 2 +- test/pass/new_delete/03_inv_struct.cpp | 2 +- test/pass/new_delete/04_inv_struct_array.cpp | 2 +- test/pass/new_delete/05_struct_array.cpp | 2 +- .../new_delete/06_struct_array_def_dest.cpp | 2 +- .../07_struct_array_userdef_dest.cpp | 4 +-- test/pass/new_delete/09_inv_struct_delete.cpp | 2 +- .../new_delete/10_inv_struct_array_delete.cpp | 2 +- test/pass/new_delete/11_new_nothrow.cpp | 2 +- test/pass/new_delete/12_new_aligned.cpp | 2 +- .../new_delete/13_new_aligned_nothrow.cpp | 2 +- test/pass/new_delete/15_array_cookie.cpp | 4 +-- .../new_delete/16_array_cookie_padded.cpp | 4 +-- .../19_array_cookie_dynamic_size_opaque.cpp | 4 +-- .../20_no_array_cookie_lulesh_ad.llin | 2 +- test/runtime/07_simple_struct_type_check.c | 2 +- test/typemapping/01_simple_struct.c | 2 +- test/typemapping/02_recursive_struct.c | 2 +- test/typemapping/04_milc_mock.c | 2 +- .../07_no_ebo_heap_multi_inheritance.cpp | 2 +- .../08_ebo_only_heap_multi_inheritance.cpp | 2 +- .../09_stack_class_inheritance_virtual.cpp | 2 +- .../10_multi_inheritance_virtual.cpp | 4 +-- test/typemapping/11_void_nullptr.cpp | 2 +- test/typemapping/12_complex.cpp | 2 +- test/typemapping/13_complex.c | 2 +- test/typemapping/14_union.c | 2 +- test/typemapping/15_wchar.c | 2 +- 34 files changed, 63 insertions(+), 55 deletions(-) diff --git a/lib/passes/instrumentation/TypeIDProvider.cpp b/lib/passes/instrumentation/TypeIDProvider.cpp index 743a9c06..577bd80a 100644 --- a/lib/passes/instrumentation/TypeIDProvider.cpp +++ b/lib/passes/instrumentation/TypeIDProvider.cpp @@ -53,6 +53,7 @@ inline int get_type_id(llvm::Value* type_id_const) { 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; } @@ -65,7 +66,9 @@ inline std::string concat(Args&&... args) { template inline std::string create_prefixed_name(Args&&... args) { - return concat(llvm::StringRef{"_typeart_"}, std::forward(args)...); + std::string name = concat(llvm::StringRef{"_typeart_"}, std::forward(args)...); + replace_whitespace_with_underscore(name); + return name; } } // namespace helper @@ -329,9 +332,10 @@ struct GlobalTypeRegistrar { public: 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) + 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); @@ -341,7 +345,7 @@ struct GlobalTypeRegistrar { 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) + LOG_DEBUG("Registering forward declared variable " << *global) } type_callback.insert(global); return global; diff --git a/lib/runtime/GlobalTypeDefCallbacks.cpp b/lib/runtime/GlobalTypeDefCallbacks.cpp index 03b318e5..8ba7f8d0 100644 --- a/lib/runtime/GlobalTypeDefCallbacks.cpp +++ b/lib/runtime/GlobalTypeDefCallbacks.cpp @@ -29,40 +29,44 @@ namespace typeart { } struct GlobalTypeInfo { - int type_id; + const int type_id; const char* name; - size_t extent; - size_t num_members; + const size_t extent; + const size_t num_members; const std::int64_t* offsets; const GlobalTypeInfo** member_types; const std::int64_t* array_sizes; - int flag; + const int flag; }; class GlobalTypeTranslator::Impl { TypeDatabase& type_db_; RuntimeT::TypeLookupMapT& translator_map_; int struct_count{0}; - // a fwd_decl and the decl must have the same type_id: - RuntimeT::HashmapT name_typid_fwd_decl_dedup_; public: - explicit Impl(TypeDatabase& db, RuntimeT::TypeLookupMapT& translator_map) : type_db_(db), translator_map_(translator_map) { + explicit Impl(TypeDatabase& db, RuntimeT::TypeLookupMapT& translator_map) + : type_db_(db), translator_map_(translator_map) { } int next_type_id(const GlobalTypeInfo* type) { - if(auto it_type = name_typid_fwd_decl_dedup_.find(type->name); it_type != name_typid_fwd_decl_dedup_.end()){ - return it_type->second; + // 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; - name_typid_fwd_decl_dedup_.try_emplace(type->name, id); return id; } int register_t(const GlobalTypeInfo* type) { if (unlikely(type == nullptr)) { - LOG_FATAL("Type descriptor is NULL, is it a weak extern global due to fwd decl?"); + LOG_ERROR("Type descriptor is NULL, is it a weak extern global due to fwd decl?"); return TYPEART_UNKNOWN_TYPE; } @@ -87,16 +91,16 @@ class GlobalTypeTranslator::Impl { type_descriptor.offsets.reserve(type->num_members); type_descriptor.member_types.reserve(type->num_members); for (auto i = 0UL; 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); - const auto member_id = register_t(type->member_types[i]); type_descriptor.member_types.emplace_back(member_id); } - const bool fwd_decl = type_descriptor.flag == StructTypeFlag::FWD_DECL; - type_db_.registerStruct(type_descriptor, !fwd_decl); + 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; 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/inline_types/04_fwd_decl.cpp b/test/pass/inline_types/04_fwd_decl.cpp index 0558c14f..d24a1382 100644 --- a/test/pass/inline_types/04_fwd_decl.cpp +++ b/test/pass/inline_types/04_fwd_decl.cpp @@ -1,6 +1,6 @@ -// RUN: %cpp-to-llvm %s | %apply-typeart -typeart-type-serialization=inline -S | %filecheck --match-full-lines %s +// RUN: %cpp-to-llvm %s | %apply-typeart -typeart-type-serialization=inline -S | %filecheck %s -// CHECK: @_typeart__ZTS6Domain = extern_weak constant %struct._typeart_struct_layout_t +// CHECK: @_typeart__ZTS6Domain_fwd = weak_odr constant %struct._typeart_struct_layout_t { i32 256, // REQUIRES: llvm-18 || llvm-19 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/08_config_file_default.c b/test/pass/misc/08_config_file_default.c index 32094d47..4bbbbb25 100644 --- a/test/pass/misc/08_config_file_default.c +++ b/test/pass/misc/08_config_file_default.c @@ -9,7 +9,7 @@ // CHECK-NEXT: stats: true // CHECK-NEXT: stack-lifetime: true // CHECK-NEXT: typegen: {{dimeta|ir}} -// CHECK-NEXT: type-serialization: file +// CHECK-NEXT: type-serialization: hybrid // CHECK-NEXT: filter: false // CHECK-NEXT: call-filter: // CHECK-NEXT: implementation: std 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/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 9f899138..c04f5b79 100644 --- a/test/runtime/07_simple_struct_type_check.c +++ b/test/runtime/07_simple_struct_type_check.c @@ -1,5 +1,5 @@ // clang-format off -// RUN: %run %s --typeart-analysis-filter-non-array-alloca=true --compile_flags "%dimeta_def -DIGNORE_ID=1" 2>&1 | %filecheck %s +// 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" 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/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 From e7a47653228ffe331ab88d50095eb06ad37b3a42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20H=C3=BCck?= Date: Wed, 5 Nov 2025 09:44:58 +0100 Subject: [PATCH 26/35] Refactorings --- lib/passes/instrumentation/TypeIDProvider.cpp | 10 +--- lib/runtime/AllocationTracking.cpp | 52 +++++++++++-------- lib/runtime/GlobalTypeDefCallbacks.cpp | 2 +- lib/runtime/GlobalTypeDefCallbacks.h | 4 +- lib/runtime/Runtime.cpp | 10 ++-- lib/runtime/Runtime.h | 37 +++++++++++-- lib/runtime/TypeResolution.cpp | 41 ++++++++------- lib/runtime/TypeResolution.h | 2 +- 8 files changed, 93 insertions(+), 65 deletions(-) diff --git a/lib/passes/instrumentation/TypeIDProvider.cpp b/lib/passes/instrumentation/TypeIDProvider.cpp index 577bd80a..fc9b741a 100644 --- a/lib/passes/instrumentation/TypeIDProvider.cpp +++ b/lib/passes/instrumentation/TypeIDProvider.cpp @@ -239,14 +239,6 @@ struct GlobalTypeRegistrar { return make_gep(array_ty, gv); } - llvm::GlobalVariable* registerGlobalStructDecl(const std::string& name) { - auto* global_struct = create_global(name, struct_layout_type_, nullptr, llvm::GlobalValue::ExternalWeakLinkage); - global_types_.global_type_data.try_emplace( - name, GlobalTypeData::TypeData{nullptr, global_struct, nullptr, nullptr, nullptr}); - - return global_struct; - } - 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, @@ -372,7 +364,7 @@ class TypeRegistryGlobals final : public TypeRegistry { continue; } LOG_DEBUG("Registering type_id " << type.type_id) - const auto* type_id = registrar_.getOrRegister(type.type_id); + /*const auto* type_id =*/registrar_.getOrRegister(type.type_id); } } diff --git a/lib/runtime/AllocationTracking.cpp b/lib/runtime/AllocationTracking.cpp index 1a38ae3f..3357bcf5 100644 --- a/lib/runtime/AllocationTracking.cpp +++ b/lib/runtime/AllocationTracking.cpp @@ -232,91 +232,99 @@ 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 = typeart::RuntimeSystem::get().type_translator.get_type_id_for(info); - typeart::RuntimeSystem::get().allocTracker.onAlloc(addr, type_id, count, retAddr); + auto& rt = typeart::RuntimeSystem::get(); + const auto type_id = rt.type_translator().get_type_id_for(info); + 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 = typeart::RuntimeSystem::get().type_translator.get_type_id_for(info); - typeart::RuntimeSystem::get().allocTracker.onAllocStack(addr, type_id, count, retAddr); + auto& rt = typeart::RuntimeSystem::get(); + const auto type_id = rt.type_translator().get_type_id_for(info); + 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 = typeart::RuntimeSystem::get().type_translator.get_type_id_for(info); - typeart::RuntimeSystem::get().allocTracker.onAllocGlobal(addr, type_id, count, retAddr); + auto& rt = typeart::RuntimeSystem::get(); + const auto type_id = rt.type_translator().get_type_id_for(info); + 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 = typeart::RuntimeSystem::get().type_translator.get_type_id_for(info); - typeart::RuntimeSystem::get().allocTracker.onAlloc(addr, type_id, count, retAddr); + auto& rt = typeart::RuntimeSystem::get(); + const auto type_id = rt.type_translator().get_type_id_for(info); + 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 = typeart::RuntimeSystem::get().type_translator.get_type_id_for(info); - typeart::RuntimeSystem::get().allocTracker.onAllocStack(addr, type_id, count, retAddr); + auto& rt = typeart::RuntimeSystem::get(); + const auto type_id = rt.type_translator().get_type_id_for(info); + rt.allocation_tracker().onAllocStack(addr, type_id, count, retAddr); } diff --git a/lib/runtime/GlobalTypeDefCallbacks.cpp b/lib/runtime/GlobalTypeDefCallbacks.cpp index 8ba7f8d0..2f470f59 100644 --- a/lib/runtime/GlobalTypeDefCallbacks.cpp +++ b/lib/runtime/GlobalTypeDefCallbacks.cpp @@ -125,5 +125,5 @@ void __typeart_register_type(const void* type_ptr) { LOG_FATAL("type_ptr is NULL\n"); return; } - typeart::RuntimeSystem::get().type_translator.register_type(type_ptr); + typeart::RuntimeSystem::get().type_translator().register_type(type_ptr); } diff --git a/lib/runtime/GlobalTypeDefCallbacks.h b/lib/runtime/GlobalTypeDefCallbacks.h index 4a9d59bf..b59d93d4 100644 --- a/lib/runtime/GlobalTypeDefCallbacks.h +++ b/lib/runtime/GlobalTypeDefCallbacks.h @@ -21,11 +21,11 @@ class GlobalTypeTranslator final { void register_type(const void* type); - inline const RuntimeT::TypeLookupMapT& get_translator_map() const { + [[nodiscard]] inline const RuntimeT::TypeLookupMapT& get_translator_map() const { return translator_map; } - inline int get_type_id_for(MemAddr addr) const { + [[nodiscard]] inline int get_type_id_for(MemAddr addr) const { if (auto element = translator_map.find(addr); element != translator_map.end()) { return element->second; } diff --git a/lib/runtime/Runtime.cpp b/lib/runtime/Runtime.cpp index 9fbae54f..a2a7e96c 100644 --- a/lib/runtime/Runtime.cpp +++ b/lib/runtime/Runtime.cpp @@ -33,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; } @@ -42,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); } @@ -62,11 +62,11 @@ inline void printTraceStart() { static constexpr const char* defaultTypeFileName = config::ConfigStdArgValues::types; RuntimeSystem::RuntimeSystem() - : rtScopeInit(), typeResolution(typeDB, recorder), allocTracker(typeDB, recorder), type_translator(typeDB) { + : rtScopeInit(), 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); }; @@ -100,7 +100,7 @@ RuntimeSystem::RuntimeSystem() } 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 4b3f629f..d0ec3864 100644 --- a/lib/runtime/Runtime.h +++ b/lib/runtime/Runtime.h @@ -55,16 +55,43 @@ struct RuntimeSystem { }; RTScopeInitializer rtScopeInit; - TypeDB typeDB{}; + TypeDB typeDB_{}; + TypeResolution typeResolution_; + AllocationTracker allocTracker_; + GlobalTypeTranslator type_translator_; public: Recorder recorder{}; - TypeResolution typeResolution; - AllocationTracker allocTracker; - GlobalTypeTranslator type_translator; - 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 diff --git a/lib/runtime/TypeResolution.cpp b/lib/runtime/TypeResolution.cpp index 997c21e4..9fd661fa 100644 --- a/lib/runtime/TypeResolution.cpp +++ b/lib/runtime/TypeResolution.cpp @@ -272,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; @@ -297,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; @@ -308,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(); @@ -365,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().get_type_resolution().getContainingTypeInfo( type.address, containing_type->address, info, &containing_type->count, byte_offset); return result; @@ -374,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; @@ -387,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; @@ -461,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 08c824ab..edd8ee9c 100644 --- a/lib/runtime/TypeResolution.h +++ b/lib/runtime/TypeResolution.h @@ -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 From 87e0b4599f607675ddf2566c536c039262feb97a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20H=C3=BCck?= Date: Wed, 5 Nov 2025 09:57:15 +0100 Subject: [PATCH 27/35] Fix bug in string concat. Runtime works without file --- lib/passes/instrumentation/TypeIDProvider.cpp | 6 +++--- lib/runtime/Runtime.cpp | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/passes/instrumentation/TypeIDProvider.cpp b/lib/passes/instrumentation/TypeIDProvider.cpp index fc9b741a..a7809631 100644 --- a/lib/passes/instrumentation/TypeIDProvider.cpp +++ b/lib/passes/instrumentation/TypeIDProvider.cpp @@ -60,13 +60,13 @@ inline int get_type_id(llvm::Value* type_id_const) { template inline std::string concat(Args&&... args) { - const auto str = (llvm::StringRef{} + ... + llvm::StringRef{std::forward(args)}); - return str.str(); + 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(llvm::StringRef{"_typeart_"}, std::forward(args)...); + std::string name = concat("_typeart_", std::forward(args)...); replace_whitespace_with_underscore(name); return name; } diff --git a/lib/runtime/Runtime.cpp b/lib/runtime/Runtime.cpp index a2a7e96c..3f6494b2 100644 --- a/lib/runtime/Runtime.cpp +++ b/lib/runtime/Runtime.cpp @@ -86,7 +86,7 @@ RuntimeSystem::RuntimeSystem() 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)) { From eaa5ef96f5c0f58dd7f3492adc7da5a8d2d23b5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20H=C3=BCck?= Date: Wed, 5 Nov 2025 11:06:16 +0100 Subject: [PATCH 28/35] Save some bytes by using 32 bit int types * lulesh inline mode: 4250 vs. 3698 bytes --- lib/passes/instrumentation/TypeIDProvider.cpp | 127 +++++++++++++----- lib/runtime/GlobalTypeDefCallbacks.cpp | 12 +- 2 files changed, 103 insertions(+), 36 deletions(-) diff --git a/lib/passes/instrumentation/TypeIDProvider.cpp b/lib/passes/instrumentation/TypeIDProvider.cpp index a7809631..81920326 100644 --- a/lib/passes/instrumentation/TypeIDProvider.cpp +++ b/lib/passes/instrumentation/TypeIDProvider.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -168,33 +169,86 @@ struct GlobalTypeCallback { } }; +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::type_flag: + return ir_build_.getInt32Ty(); + case IGlobalType::extent: + case IGlobalType::num_members: + return ir_build_.getInt32Ty(); + case IGlobalType::member_offsets: + case IGlobalType::member_types: + case IGlobalType::member_count: { + if (as_array) { + return ir_build_.getInt32Ty(); + } + return ir_build_.getPtrTy(); + } + case IGlobalType::name: + case IGlobalType::ptr: + return ir_build_.getPtrTy(); + } + 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::type_flag: + return ir_build_.getInt32(value); + case IGlobalType::extent: + case IGlobalType::num_members: + case IGlobalType::member_offsets: + case IGlobalType::member_count: + return ir_build_.getInt32(value); + default: + break; + } + return ir_build_.getInt64(value); + } +}; + 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_; - - 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) { - declare_layout(); - } + TypeHelper types_helper; private: void declare_layout() { - auto& context = module_->getContext(); - llvm::IRBuilder<> Builder(context); + auto& context = module_->getContext(); struct_layout_type_ = llvm::StructType::create(context, "struct._typeart_struct_layout_t"); struct_layout_type_->setBody({ - Builder.getInt32Ty(), // int type_id - llvm::PointerType::getUnqual(context), // const char* name - Builder.getInt64Ty(), // size_t extent - Builder.getInt64Ty(), // size_t num_members - llvm::PointerType::getUnqual(context), // const size_t* offsets - llvm::PointerType::getUnqual(context), // const typeart_struct_layout_t* member_types - llvm::PointerType::getUnqual(context), // const size_t* count - Builder.getInt32Ty(), // int type_flag + types_helper.get_type_for(IGlobalType::type_id), // int type_id + types_helper.get_type_for(IGlobalType::name), // const char* name + types_helper.get_type_for(IGlobalType::extent), // size_t extent + types_helper.get_type_for(IGlobalType::num_members), // size_t num_members + types_helper.get_type_for(IGlobalType::member_offsets), // const size_t* offsets + types_helper.get_type_for(IGlobalType::member_types), // const typeart_struct_layout_t** member_types + types_helper.get_type_for(IGlobalType::member_count), // const size_t* count + types_helper.get_type_for(IGlobalType::type_flag), // int type_flag }); } @@ -225,15 +279,13 @@ struct GlobalTypeRegistrar { } llvm::Constant* create_global_array_ptr(const llvm::StringRef name, llvm::ArrayRef values) { - auto* int64_ty = ir_build.getInt64Ty(); - std::vector constants; constants.reserve(values.size()); for (uint64_t val : values) { - constants.push_back(llvm::ConstantInt::get(int64_ty, val)); + constants.push_back(types_helper.get_constant_for(IGlobalType::member_offsets, val)); } - auto* array_ty = llvm::ArrayType::get(int64_ty, values.size()); + 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); @@ -247,14 +299,15 @@ struct GlobalTypeRegistrar { llvm::GlobalVariable* global_struct = create_global(name_struct, struct_layout_type_); llvm::Constant* name_str = create_global_constant_string(name); - std::vector members = {ir_build.getInt32(type_id), - name_str, - ir_build.getInt64(type_size), - ir_build.getInt64(member_count), - offset_ptr, - members_data_ptr, - count_ptr, - ir_build.getInt32(static_cast(flag))}; // TODO: use real type + std::vector members = { + types_helper.get_constant_for(IGlobalType::type_id, type_id), + name_str, + types_helper.get_constant_for(IGlobalType::extent, type_size), + types_helper.get_constant_for(IGlobalType::member_count, member_count), + offset_ptr, + members_data_ptr, + count_ptr, + types_helper.get_constant_for(IGlobalType::type_flag, static_cast(flag))}; // TODO: use real type llvm::Constant* init = llvm::ConstantStruct::get(struct_layout_type_, members); @@ -297,8 +350,9 @@ struct GlobalTypeRegistrar { 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 = llvm::ConstantPointerNull::get(llvm::PointerType::getUnqual(module_->getContext())); - members_array = null_member; + llvm::Constant* null_member = llvm::ConstantPointerNull::get( + llvm::dyn_cast(types_helper.get_type_for(IGlobalType::ptr))); + members_array = null_member; } return registerGlobalStruct(name, type_struct->type_id, type_size, member_count, offset_ptr, members_array, @@ -322,6 +376,19 @@ struct GlobalTypeRegistrar { } 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)) @@ -360,7 +427,7 @@ class TypeRegistryGlobals final : public TypeRegistry { if (builtins::BuiltInQuery::is_builtin_type(type.type_id)) { continue; } - if (!registrar_.type_db_->isValid(type.type_id)) { + if (!registrar_.db().isValid(type.type_id)) { continue; } LOG_DEBUG("Registering type_id " << type.type_id) diff --git a/lib/runtime/GlobalTypeDefCallbacks.cpp b/lib/runtime/GlobalTypeDefCallbacks.cpp index 2f470f59..79e798d5 100644 --- a/lib/runtime/GlobalTypeDefCallbacks.cpp +++ b/lib/runtime/GlobalTypeDefCallbacks.cpp @@ -29,14 +29,14 @@ namespace typeart { } struct GlobalTypeInfo { - const int type_id; + const int32_t type_id; const char* name; - const size_t extent; - const size_t num_members; - const std::int64_t* offsets; + const int32_t extent; + const int32_t num_members; + const std::int32_t* offsets; const GlobalTypeInfo** member_types; - const std::int64_t* array_sizes; - const int flag; + const std::int32_t* array_sizes; + const int32_t flag; }; class GlobalTypeTranslator::Impl { From 081e8028ed617d57eda4d4914acc33ff7da68bf3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20H=C3=BCck?= Date: Wed, 5 Nov 2025 13:31:14 +0100 Subject: [PATCH 29/35] Further save bytes --- lib/passes/instrumentation/TypeIDProvider.cpp | 42 +++++++++---------- lib/runtime/GlobalTypeDefCallbacks.cpp | 21 ++++------ 2 files changed, 30 insertions(+), 33 deletions(-) diff --git a/lib/passes/instrumentation/TypeIDProvider.cpp b/lib/passes/instrumentation/TypeIDProvider.cpp index 81920326..5364ffe1 100644 --- a/lib/passes/instrumentation/TypeIDProvider.cpp +++ b/lib/passes/instrumentation/TypeIDProvider.cpp @@ -189,16 +189,16 @@ struct TypeHelper { llvm::Type* get_type_for(IGlobalType type, bool as_array = false) { switch (type) { case IGlobalType::type_id: - case IGlobalType::type_flag: - return ir_build_.getInt32Ty(); case IGlobalType::extent: - case IGlobalType::num_members: 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_.getInt32Ty(); + return ir_build_.getInt16Ty(); } return ir_build_.getPtrTy(); } @@ -212,17 +212,17 @@ struct TypeHelper { llvm::Constant* get_constant_for(IGlobalType type, size_t value) { switch (type) { case IGlobalType::type_id: - case IGlobalType::type_flag: - return ir_build_.getInt32(value); 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_.getInt32(value); + return ir_build_.getInt16(value); default: break; } - return ir_build_.getInt64(value); + return ir_build_.getInt32(value); } }; @@ -242,13 +242,14 @@ struct GlobalTypeRegistrar { 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::extent), // size_t extent - types_helper.get_type_for(IGlobalType::num_members), // size_t num_members - types_helper.get_type_for(IGlobalType::member_offsets), // const size_t* offsets + 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 - types_helper.get_type_for(IGlobalType::member_count), // const size_t* count - types_helper.get_type_for(IGlobalType::type_flag), // int type_flag + }); } @@ -301,16 +302,15 @@ struct GlobalTypeRegistrar { std::vector members = { types_helper.get_constant_for(IGlobalType::type_id, type_id), - name_str, types_helper.get_constant_for(IGlobalType::extent, type_size), types_helper.get_constant_for(IGlobalType::member_count, member_count), - offset_ptr, - members_data_ptr, - count_ptr, - types_helper.get_constant_for(IGlobalType::type_flag, static_cast(flag))}; // TODO: use real type - + 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( @@ -410,7 +410,7 @@ struct GlobalTypeRegistrar { return global; }); } -}; +}; // namespace typedb } // namespace typedb class TypeRegistryGlobals final : public TypeRegistry { diff --git a/lib/runtime/GlobalTypeDefCallbacks.cpp b/lib/runtime/GlobalTypeDefCallbacks.cpp index 79e798d5..acb1303f 100644 --- a/lib/runtime/GlobalTypeDefCallbacks.cpp +++ b/lib/runtime/GlobalTypeDefCallbacks.cpp @@ -1,6 +1,5 @@ #include "GlobalTypeDefCallbacks.h" -#include "AllocationTracking.h" #include "CallbackInterface.h" #include "Runtime.h" #include "RuntimeData.h" @@ -8,12 +7,9 @@ #include "support/Logger.h" #include "typelib/TypeDatabase.h" -#include #include #include -#include #include -#include #include namespace typeart { @@ -29,14 +25,15 @@ namespace typeart { } struct GlobalTypeInfo { - const int32_t type_id; + const 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 int32_t extent; - const int32_t num_members; - const std::int32_t* offsets; + const std::uint16_t* offsets; + const std::uint16_t* array_sizes; const GlobalTypeInfo** member_types; - const std::int32_t* array_sizes; - const int32_t flag; }; class GlobalTypeTranslator::Impl { @@ -64,7 +61,7 @@ class GlobalTypeTranslator::Impl { return id; } - int register_t(const GlobalTypeInfo* type) { + 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; @@ -90,7 +87,7 @@ class GlobalTypeTranslator::Impl { type_descriptor.array_sizes.reserve(type->num_members); type_descriptor.offsets.reserve(type->num_members); type_descriptor.member_types.reserve(type->num_members); - for (auto i = 0UL; i < type->num_members; ++i) { + 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]; From c30b6fbe406963a1d129b127c2d79e4e11537b36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20H=C3=BCck?= Date: Thu, 6 Nov 2025 10:17:44 +0100 Subject: [PATCH 30/35] Reduce data emitted for builtins --- .../instrumentation/TypeARTFunctions.cpp | 1 + lib/passes/instrumentation/TypeIDProvider.cpp | 29 ++++++++++++++----- 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/lib/passes/instrumentation/TypeARTFunctions.cpp b/lib/passes/instrumentation/TypeARTFunctions.cpp index 027c0223..887827e3 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. diff --git a/lib/passes/instrumentation/TypeIDProvider.cpp b/lib/passes/instrumentation/TypeIDProvider.cpp index 5364ffe1..76c00e9d 100644 --- a/lib/passes/instrumentation/TypeIDProvider.cpp +++ b/lib/passes/instrumentation/TypeIDProvider.cpp @@ -224,6 +224,10 @@ struct TypeHelper { } return ir_build_.getInt32(value); } + + llvm::Constant* get_constant_nullptr() { + return llvm::ConstantPointerNull::get(llvm::dyn_cast(get_type_for(IGlobalType::ptr))); + } }; struct GlobalTypeRegistrar { @@ -235,6 +239,7 @@ struct GlobalTypeRegistrar { llvm::StructType* struct_layout_type_; GlobalTypeData global_types_; TypeHelper types_helper; + const bool builtin_emit_name{false}; private: void declare_layout() { @@ -280,6 +285,11 @@ struct GlobalTypeRegistrar { } 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) { @@ -296,9 +306,15 @@ struct GlobalTypeRegistrar { 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; + const auto name_struct = flag == StructTypeFlag::FWD_DECL ? helper::concat(name, "_fwd") : name; + llvm::GlobalVariable* global_struct = create_global(name_struct, struct_layout_type_); - llvm::Constant* name_str = create_global_constant_string(name); + + // 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), @@ -350,9 +366,8 @@ struct GlobalTypeRegistrar { 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 = llvm::ConstantPointerNull::get( - llvm::dyn_cast(types_helper.get_type_for(IGlobalType::ptr))); - members_array = null_member; + 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, @@ -362,8 +377,8 @@ struct GlobalTypeRegistrar { 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, {0}, - {}, {1}, StructTypeFlag::BUILTIN}; + StructTypeInfo type_struct{type_id, type_name, type_db_->getTypeSize(type_id), 1, {}, + {}, {}, StructTypeFlag::BUILTIN}; return registerTypeStruct(&type_struct); } From fdc9cc188ac3e72edc2eb7c185305cb35dde8887 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20H=C3=BCck?= Date: Fri, 7 Nov 2025 11:04:59 +0100 Subject: [PATCH 31/35] Refactoring --- lib/runtime/Runtime.h | 8 ++++---- lib/runtime/RuntimeData.h | 12 +++++------- lib/runtime/TypeResolution.cpp | 2 +- 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/lib/runtime/Runtime.h b/lib/runtime/Runtime.h index d0ec3864..b17aaf43 100644 --- a/lib/runtime/Runtime.h +++ b/lib/runtime/Runtime.h @@ -10,8 +10,8 @@ // 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" @@ -45,7 +45,7 @@ struct RuntimeSystem { rtScope = true; } - void reset() { + void reset() const { // Reset rtScope to old value. rtScope = rtScopeWasSet; } @@ -126,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 01f9b6d5..8bb5bde3 100644 --- a/lib/runtime/RuntimeData.h +++ b/lib/runtime/RuntimeData.h @@ -68,7 +68,6 @@ struct RuntimeT { static constexpr char StackName[] = "std::vector"; #ifdef TYPEART_PHMAP using PointerMapBaseT = phmap::btree_map; - using TypeLookupMapT = phmap::flat_hash_map; template using HashmapT = phmap::flat_hash_map; static constexpr char MapName[] = "phmap::btree_map"; @@ -77,14 +76,12 @@ struct RuntimeT { using PointerMapBaseT = absl::btree_map; template using HashmapT = absl::flat_hash_map; - using TypeLookupMapT = absl::flat_hash_map; static constexpr char MapName[] = "absl::btree_map"; #endif #if !defined(TYPEART_PHMAP) && !defined(TYPEART_ABSEIL) using PointerMapBaseT = std::map; template using HashmapT = std::unordered_map; - using TypeLookupMapT = std::unordered_map; static constexpr char MapName[] = "std::map"; #endif #ifdef USE_SAFEPTR @@ -94,10 +91,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 9fd661fa..8552d326 100644 --- a/lib/runtime/TypeResolution.cpp +++ b/lib/runtime/TypeResolution.cpp @@ -366,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().get_type_resolution().getContainingTypeInfo( + const auto result = typeart::RuntimeSystem::get().type_resolution().getContainingTypeInfo( type.address, containing_type->address, info, &containing_type->count, byte_offset); return result; From a468a110dae7b01a3f2691bf2f3bd7ff423ff812 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20H=C3=BCck?= Date: Fri, 7 Nov 2025 12:37:24 +0100 Subject: [PATCH 32/35] Update type id in global data --- lib/passes/instrumentation/TypeIDProvider.cpp | 1 + lib/runtime/AllocationTracking.cpp | 13 ++++++++----- lib/runtime/GlobalTypeDefCallbacks.cpp | 18 ++++-------------- lib/runtime/Runtime.cpp | 2 +- lib/runtime/RuntimeData.h | 12 ++++++++++++ 5 files changed, 26 insertions(+), 20 deletions(-) diff --git a/lib/passes/instrumentation/TypeIDProvider.cpp b/lib/passes/instrumentation/TypeIDProvider.cpp index 76c00e9d..7b5473c9 100644 --- a/lib/passes/instrumentation/TypeIDProvider.cpp +++ b/lib/passes/instrumentation/TypeIDProvider.cpp @@ -309,6 +309,7 @@ struct GlobalTypeRegistrar { 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; diff --git a/lib/runtime/AllocationTracking.cpp b/lib/runtime/AllocationTracking.cpp index 3357bcf5..f90d6603 100644 --- a/lib/runtime/AllocationTracking.cpp +++ b/lib/runtime/AllocationTracking.cpp @@ -300,31 +300,34 @@ void __typeart_alloc_mty(const void* addr, const void* info, size_t count) { void __typeart_alloc_stack_mty(const void* addr, const void* info, size_t count) { TYPEART_RUNTIME_GUARD; const void* retAddr = __builtin_return_address(0); - auto& rt = typeart::RuntimeSystem::get(); - const auto type_id = rt.type_translator().get_type_id_for(info); + + const auto type_id = reinterpret_cast(info)->type_id; + auto& rt = typeart::RuntimeSystem::get(); + // auto stored_id = rt.type_translator().get_type_id_for(info); + // LOG_FATAL(type_id << " vs. " << stored_id) 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(); - const auto type_id = rt.type_translator().get_type_id_for(info); 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(); - const auto type_id = rt.type_translator().get_type_id_for(info); 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(); - const auto type_id = rt.type_translator().get_type_id_for(info); rt.allocation_tracker().onAllocStack(addr, type_id, count, retAddr); } diff --git a/lib/runtime/GlobalTypeDefCallbacks.cpp b/lib/runtime/GlobalTypeDefCallbacks.cpp index acb1303f..3939b607 100644 --- a/lib/runtime/GlobalTypeDefCallbacks.cpp +++ b/lib/runtime/GlobalTypeDefCallbacks.cpp @@ -24,18 +24,6 @@ namespace typeart { return; \ } -struct GlobalTypeInfo { - const 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; -}; - class GlobalTypeTranslator::Impl { TypeDatabase& type_db_; RuntimeT::TypeLookupMapT& translator_map_; @@ -110,8 +98,10 @@ GlobalTypeTranslator::GlobalTypeTranslator(TypeDatabase& db) : pImpl(std::make_u GlobalTypeTranslator::~GlobalTypeTranslator() = default; void GlobalTypeTranslator::register_type(const void* type) { - const auto* info_struct = reinterpret_cast(type); - pImpl->register_t(info_struct); + const auto* info_struct = reinterpret_cast(type); + const auto type_id = pImpl->register_t(info_struct); + const_cast(info_struct)->type_id = type_id; + // LOG_DEBUG("After: " << info_struct->name << " " << info_struct->type_id) } } // namespace typeart diff --git a/lib/runtime/Runtime.cpp b/lib/runtime/Runtime.cpp index 3f6494b2..441f41cc 100644 --- a/lib/runtime/Runtime.cpp +++ b/lib/runtime/Runtime.cpp @@ -62,7 +62,7 @@ inline void printTraceStart() { static constexpr const char* defaultTypeFileName = config::ConfigStdArgValues::types; RuntimeSystem::RuntimeSystem() - : rtScopeInit(), typeResolution_(typeDB_, recorder), allocTracker_(typeDB_, recorder), type_translator_(typeDB_) { + : typeResolution_(typeDB_, recorder), allocTracker_(typeDB_, recorder), type_translator_(typeDB_) { debug::printTraceStart(); auto loadTypes = [this](const std::string& file, std::error_code& ec) -> bool { diff --git a/lib/runtime/RuntimeData.h b/lib/runtime/RuntimeData.h index 8bb5bde3..1d7df353 100644 --- a/lib/runtime/RuntimeData.h +++ b/lib/runtime/RuntimeData.h @@ -62,6 +62,18 @@ 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}; From e9694af372069b1c065125919561a922a8a25ccc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20H=C3=BCck?= Date: Fri, 7 Nov 2025 16:10:58 +0100 Subject: [PATCH 33/35] CI fixes --- .github/workflows/basic-ci.yml | 10 +++--- .github/workflows/ext-ci.yml | 12 +++---- .../instrumentation/TypeARTFunctions.cpp | 1 + lib/passes/instrumentation/TypeIDProvider.cpp | 11 +++++-- lib/runtime/GlobalTypeDefCallbacks.cpp | 6 ++-- lib/runtime/RuntimeData.h | 1 + test/pass/filter/08_amg_box_algebra_mock.c | 4 +-- test/pass/filter/09_milc_gauge_stuff_mock.c | 6 ++-- test/pass/inline_types/01_simple_malloc_int.c | 6 ++-- test/pass/inline_types/04_fwd_decl.cpp | 2 +- test/pass/misc/08_config_file_default.c | 2 ++ .../17_array_cookie_dynamic_size.cpp | 2 +- .../new_delete/18_array_cookie_delete.cpp | 2 +- test/runtime/30_omp_concurrent_w.cpp | 33 +++++++++---------- test/runtime/41_array_cookie.cpp | 2 +- test/typemapping/06_anon_struct.c | 2 +- test/typemapping/16_mpi_dtype.c | 2 +- 17 files changed, 57 insertions(+), 47 deletions(-) diff --git a/.github/workflows/basic-ci.yml b/.github/workflows/basic-ci.yml index f8a39fda..5e660cd8 100644 --- a/.github/workflows/basic-ci.yml +++ b/.github/workflows/basic-ci.yml @@ -12,10 +12,10 @@ env: jobs: format-check: - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Format source code run: | @@ -24,7 +24,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 +35,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 +73,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/lib/passes/instrumentation/TypeARTFunctions.cpp b/lib/passes/instrumentation/TypeARTFunctions.cpp index 887827e3..5ddfa462 100644 --- a/lib/passes/instrumentation/TypeARTFunctions.cpp +++ b/lib/passes/instrumentation/TypeARTFunctions.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include namespace typeart { diff --git a/lib/passes/instrumentation/TypeIDProvider.cpp b/lib/passes/instrumentation/TypeIDProvider.cpp index 7b5473c9..fcfb0e26 100644 --- a/lib/passes/instrumentation/TypeIDProvider.cpp +++ b/lib/passes/instrumentation/TypeIDProvider.cpp @@ -200,11 +200,19 @@ struct TypeHelper { 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"); } @@ -241,7 +249,6 @@ struct GlobalTypeRegistrar { TypeHelper types_helper; const bool builtin_emit_name{false}; - private: void declare_layout() { auto& context = module_->getContext(); struct_layout_type_ = llvm::StructType::create(context, "struct._typeart_struct_layout_t"); @@ -483,7 +490,7 @@ std::unique_ptr get_type_id_handler(llvm::Module& m, const TypeDat TypeSerializationImplementation impl = configuration[config::ConfigStdArgs::type_serialization]; #if LLVM_VERSION_MAJOR < 15 if (impl != typeart::TypeSerializationImplementation::FILE) { - LOG_WARNING("Warning unsupported type serialization mode.") + 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(); diff --git a/lib/runtime/GlobalTypeDefCallbacks.cpp b/lib/runtime/GlobalTypeDefCallbacks.cpp index 3939b607..77812f5b 100644 --- a/lib/runtime/GlobalTypeDefCallbacks.cpp +++ b/lib/runtime/GlobalTypeDefCallbacks.cpp @@ -98,10 +98,10 @@ GlobalTypeTranslator::GlobalTypeTranslator(TypeDatabase& db) : pImpl(std::make_u 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); + 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; - // LOG_DEBUG("After: " << info_struct->name << " " << info_struct->type_id) } } // namespace typeart diff --git a/lib/runtime/RuntimeData.h b/lib/runtime/RuntimeData.h index 1d7df353..901a72d2 100644 --- a/lib/runtime/RuntimeData.h +++ b/lib/runtime/RuntimeData.h @@ -50,6 +50,7 @@ #endif #include // size_t +#include #include namespace typeart { 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 index 1ec9cadf..69c16ab5 100644 --- a/test/pass/inline_types/01_simple_malloc_int.c +++ b/test/pass/inline_types/01_simple_malloc_int.c @@ -17,14 +17,14 @@ void test() { // CHECK-NEXT: Free{{[ ]*}}:{{[ ]*}}0 // CHECK-NEXT: Alloca{{[ ]*}}:{{[ ]*}}0 -// CHECK: %struct._typeart_struct_layout_t = type { i32, ptr, i64, i64, ptr, ptr, ptr, i32 } +// 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 { i32, ptr, i64, i64, ptr, ptr, ptr, i32 } +// 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 { i32, ptr, i64, i64, ptr, ptr, ptr, i32 } +// 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/04_fwd_decl.cpp b/test/pass/inline_types/04_fwd_decl.cpp index d24a1382..01ad31c8 100644 --- a/test/pass/inline_types/04_fwd_decl.cpp +++ b/test/pass/inline_types/04_fwd_decl.cpp @@ -1,6 +1,6 @@ // RUN: %cpp-to-llvm %s | %apply-typeart -typeart-type-serialization=inline -S | %filecheck %s -// CHECK: @_typeart__ZTS6Domain_fwd = weak_odr constant %struct._typeart_struct_layout_t { i32 256, +// CHECK: @_typeart__ZTS6Domain_fwd = weak_odr global %struct._typeart_struct_layout_t { i32 256, // REQUIRES: llvm-18 || llvm-19 diff --git a/test/pass/misc/08_config_file_default.c b/test/pass/misc/08_config_file_default.c index 4bbbbb25..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 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/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/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/16_mpi_dtype.c b/test/typemapping/16_mpi_dtype.c index 27d7499c..182da9d0 100644 --- a/test/typemapping/16_mpi_dtype.c +++ b/test/typemapping/16_mpi_dtype.c @@ -19,6 +19,6 @@ int main(void) { // CHECK-NOT: Error // CHECK: call {{.*}} @__typeart_alloc_stack(ptr {{.*}}, i32 1, i64 3) -// inline: @_typeart_ptr = weak_odr constant %struct._typeart_struct_layout_t +// 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) From 976345a21e771a2daa9a036ff11d6493dbdd64f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20H=C3=BCck?= Date: Fri, 7 Nov 2025 17:47:37 +0100 Subject: [PATCH 34/35] Workaround for Abseil & ASan interaction --- lib/runtime/RuntimeData.h | 13 ++++++++++++- test/lit.cfg | 1 + 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/lib/runtime/RuntimeData.h b/lib/runtime/RuntimeData.h index 901a72d2..6253655e 100644 --- a/lib/runtime/RuntimeData.h +++ b/lib/runtime/RuntimeData.h @@ -21,6 +21,7 @@ #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" @@ -49,6 +50,12 @@ #include "safe_ptr.h" #endif +#if defined(__has_feature) +#if __has_feature(address_sanitizer) +#define __SANITIZE_ADDRESS__ +#endif +#endif + #include // size_t #include #include @@ -88,7 +95,11 @@ struct RuntimeT { #ifdef TYPEART_ABSEIL using PointerMapBaseT = absl::btree_map; template - using HashmapT = absl::flat_hash_map; +#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) 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: From cc5657dc6dcf79d6e08005ca2096660ad45791d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20H=C3=BCck?= Date: Sat, 8 Nov 2025 09:36:42 +0100 Subject: [PATCH 35/35] CI format fix. Assert in runtime. --- .github/workflows/basic-ci.yml | 12 ++++++++++++ lib/runtime/AllocationTracking.cpp | 14 ++++++++------ 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/.github/workflows/basic-ci.yml b/.github/workflows/basic-ci.yml index 5e660cd8..39044e6b 100644 --- a/.github/workflows/basic-ci.yml +++ b/.github/workflows/basic-ci.yml @@ -17,6 +17,18 @@ jobs: steps: - 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: | find demo lib test \ diff --git a/lib/runtime/AllocationTracking.cpp b/lib/runtime/AllocationTracking.cpp index f90d6603..c22c2072 100644 --- a/lib/runtime/AllocationTracking.cpp +++ b/lib/runtime/AllocationTracking.cpp @@ -292,19 +292,18 @@ void __typeart_leave_scope_omp(int alloca_count) { 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(); - const auto type_id = rt.type_translator().get_type_id_for(info); + 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(); - // auto stored_id = rt.type_translator().get_type_id_for(info); - // LOG_FATAL(type_id << " vs. " << stored_id) + 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); } @@ -313,6 +312,7 @@ void __typeart_alloc_global_mty(const void* addr, const void* info, size_t count 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); } @@ -321,6 +321,7 @@ void __typeart_alloc_omp_mty(const void* addr, const void* info, size_t count) { 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); } @@ -329,5 +330,6 @@ void __typeart_alloc_stack_omp_mty(const void* addr, const void* info, size_t co 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); }