diff --git a/demo/02_broken_struct_example.c b/demo/02_broken_struct_example.c index 7a9d5cd1..bac9124f 100644 --- a/demo/02_broken_struct_example.c +++ b/demo/02_broken_struct_example.c @@ -6,7 +6,7 @@ #define COUNT 5 // Comment out for heap allocation -//#define USE_STACK +// #define USE_STACK struct particle { int id; diff --git a/lib/passes/Commandline.cpp b/lib/passes/Commandline.cpp index e80b15a9..97e2ee08 100644 --- a/lib/passes/Commandline.cpp +++ b/lib/passes/Commandline.cpp @@ -238,7 +238,7 @@ CommandLineOptions::CommandLineOptions() { std::optional CommandLineOptions::getValue(std::string_view opt_path) const { auto key = llvm::StringRef(opt_path.data()); - if (mapping_.count(key) != 0U) { + if (occurence_mapping_.lookup(key)) { return mapping_.lookup(key); } return {}; diff --git a/lib/passes/TypeARTConfiguration.cpp b/lib/passes/TypeARTConfiguration.cpp index 7a2ec887..e7b2d2d5 100644 --- a/lib/passes/TypeARTConfiguration.cpp +++ b/lib/passes/TypeARTConfiguration.cpp @@ -33,58 +33,46 @@ TypeARTConfiguration::TypeARTConfiguration(std::unique_ptr co } std::optional TypeARTConfiguration::getValue(std::string_view opt_path) const { - auto get_value = [&](const auto& options, const char* source) -> std::optional { - LOG_DEBUG("Query " << source << " " << opt_path.data()) - if (prioritize_commandline && options.valueSpecified(opt_path)) { - LOG_DEBUG("Take " << source << " arg for " << opt_path.data()); - return options.getValue(opt_path); + if (prioritize_commandline) { + if (auto value = env_options_->getValue(opt_path)) { + LOG_DEBUG("Take ENV " << opt_path << "=" << (std::string(value.value()))); + return value.value(); + } + if (auto value = commandline_options_->getValue(opt_path)) { + LOG_DEBUG("Take CL " << opt_path << "=" << (std::string(value.value()))); + return value.value(); } - return std::nullopt; - }; - if (auto value = get_value(*env_options_, "ENV")) { - return value; - } - if (auto value = get_value(*commandline_options_, "CL")) { - return value; } return configuration_options_->getValue(opt_path); } OptionValue TypeARTConfiguration::getValueOr(std::string_view opt_path, OptionValue alt) const { - auto get_value = [&](const auto& options, const char* source) -> std::optional { - LOG_DEBUG("Query " << source << " " << opt_path.data()) - if (prioritize_commandline && options.valueSpecified(opt_path)) { - LOG_DEBUG("Take " << source << " arg for " << opt_path.data()); - return options.getValueOr(opt_path, alt); + if (prioritize_commandline) { + if (auto value = env_options_->getValue(opt_path)) { + LOG_DEBUG("Take ENV " << opt_path << "=" << (std::string(value.value()))); + return value.value(); + } + if (auto value = commandline_options_->getValue(opt_path)) { + LOG_DEBUG("Take CL " << opt_path << "=" << (std::string(value.value()))); + return value.value(); } - return std::nullopt; - }; - if (auto value = get_value(*env_options_, "ENV")) { - return value.value(); - } - if (auto value = get_value(*commandline_options_, "CL")) { - return value.value(); } return configuration_options_->getValueOr(opt_path, alt); } OptionValue TypeARTConfiguration::operator[](std::string_view opt_path) const { - auto get_value = [&](const auto& options, const char* source) -> std::optional { - LOG_DEBUG("Query " << source << " " << opt_path.data()) - if (prioritize_commandline && options.valueSpecified(opt_path)) { - LOG_DEBUG("Take " << source << " arg for " << opt_path.data()); - return options.operator[](opt_path); + if (prioritize_commandline) { + if (auto value = env_options_->getValue(opt_path)) { + LOG_DEBUG("Take ENV " << opt_path << "=" << (std::string(value.value()))); + return value.value(); + } + if (auto value = commandline_options_->getValue(opt_path)) { + LOG_DEBUG("Take CL " << opt_path << "=" << (std::string(value.value()))); + return value.value(); } - return std::nullopt; - }; - if (auto value = get_value(*env_options_, "ENV")) { - return value.value(); - } - if (auto value = get_value(*commandline_options_, "CL")) { - return value.value(); } auto result = configuration_options_->operator[](opt_path); - LOG_DEBUG("Query file " << static_cast(result)) + LOG_DEBUG("Take File " << opt_path << "=" << (std::string(result))); return result; } diff --git a/lib/passes/TypeARTPass.cpp b/lib/passes/TypeARTPass.cpp index e8ec3a27..63ec31d2 100644 --- a/lib/passes/TypeARTPass.cpp +++ b/lib/passes/TypeARTPass.cpp @@ -16,6 +16,9 @@ #include "configuration/Configuration.h" #include "configuration/EnvironmentConfiguration.h" #include "configuration/FileConfiguration.h" +#include "configuration/PassBuilderUtil.h" +#include "configuration/PassConfiguration.h" +#include "configuration/TypeARTOptions.h" #include "instrumentation/MemOpArgCollector.h" #include "instrumentation/MemOpInstrumentation.h" #include "instrumentation/TypeARTFunctions.h" @@ -41,6 +44,7 @@ #include #include +#include #include #include #include @@ -84,6 +88,7 @@ std::optional get_configuration_file_path() { } class TypeArtPass : public llvm::PassInfoMixin { + std::optional pass_opts{std::nullopt}; std::unique_ptr pass_config; struct TypeArtFunc { @@ -109,20 +114,26 @@ class TypeArtPass : public llvm::PassInfoMixin { std::unique_ptr instrumentation_context; public: + TypeArtPass() = default; + explicit TypeArtPass(config::TypeARTConfigOptions opts) : pass_opts(opts) { + // LOG_INFO("Created with \n" << opts) + } + bool doInitialization(Module& m) { auto config_file_path = get_configuration_file_path(); - const auto init = config_file_path.has_value() - ? config::TypeARTConfigInit{config_file_path.value()} - : config::TypeARTConfigInit{{}, config::TypeARTConfigInit::FileConfigurationMode::Empty}; - auto typeart_config = config::make_typeart_configuration(init); + const auto init = config_file_path.has_value() + ? config::TypeARTConfigInit{config_file_path.value()} + : config::TypeARTConfigInit{{}, config::TypeARTConfigInit::FileConfigurationMode::Empty}; + + auto typeart_config = [&](const auto& init) { + if (init.mode == config::TypeARTConfigInit::FileConfigurationMode::Empty) { + return config::make_typeart_configuration_from_opts(pass_opts.value_or(config::TypeARTConfigOptions{})); + } + return config::make_typeart_configuration(init); + }(init); + if (typeart_config) { - // { - // std::string typeart_conf_str; - // llvm::raw_string_ostream conf_out_stream{typeart_conf_str}; - // typeart_config->get()->emitTypeartFileConfiguration(conf_out_stream); - // LOG_INFO("Emitting TypeART file content\n" << conf_out_stream.str()) - // } LOG_INFO("Emitting TypeART configuration content\n" << typeart_config.get()->getOptions()) pass_config = std::move(*typeart_config); } else { @@ -214,8 +225,9 @@ class TypeArtPass : public llvm::PassInfoMixin { meminst_finder->printStats(out); const auto get_ta_mode = [&]() { - const bool heap = (*pass_config)[config::ConfigStdArgs::heap]; - const bool stack = (*pass_config)[config::ConfigStdArgs::stack]; + const bool heap = (*pass_config)[config::ConfigStdArgs::heap]; + const bool stack = (*pass_config)[config::ConfigStdArgs::stack]; + const bool global = (*pass_config)[config::ConfigStdArgs::global]; if (heap) { if (stack) { @@ -228,7 +240,13 @@ class TypeArtPass : public llvm::PassInfoMixin { return " [Stack]"; } - llvm_unreachable("Did not find heap or stack, or combination thereof!"); + if (global) { + return " [Global]"; + } + + LOG_ERROR("Did not find heap or stack, or combination thereof!"); + assert((heap || stack || global) && "Needs stack, heap, global or combination thereof"); + return " [Unknown]"; }; Table stats("TypeArtPass"); @@ -363,13 +381,21 @@ bool LegacyTypeArtPass::doFinalization(llvm::Module&) { // New PM //..................... llvm::PassPluginLibraryInfo getTypeartPassPluginInfo() { + using namespace llvm; return {LLVM_PLUGIN_API_VERSION, "TypeART", LLVM_VERSION_STRING, [](PassBuilder& pass_builder) { pass_builder.registerPipelineParsingCallback( [](StringRef name, ModulePassManager& module_pm, ArrayRef) { - if (name == "typeart") { - module_pm.addPass(typeart::pass::TypeArtPass()); + if (typeart::util::pass::checkParametrizedPassName(name, "typeart")) { + auto parameters = typeart::util::pass::parsePassParameters( + typeart::config::pass::parse_typeart_config, name, "typeart"); + if (!parameters) { + LOG_FATAL("Error parsing params: " << parameters.takeError()) + return false; + } + module_pm.addPass(typeart::pass::TypeArtPass(parameters.get())); return true; } + LOG_FATAL("Not a valid parametrized pass name: " << name) return false; }); }}; diff --git a/lib/passes/analysis/MemInstFinder.cpp b/lib/passes/analysis/MemInstFinder.cpp index 6ea08ded..55c3718b 100644 --- a/lib/passes/analysis/MemInstFinder.cpp +++ b/lib/passes/analysis/MemInstFinder.cpp @@ -22,6 +22,7 @@ #include "filter/Filter.h" #include "filter/Matcher.h" #include "filter/StdForwardFilter.h" +#include "support/ConfigurationBase.h" #include "support/Logger.h" #include "support/Table.h" #include "support/TypeUtil.h" @@ -43,6 +44,7 @@ #include #include #include +#include #include using namespace llvm; @@ -61,7 +63,7 @@ ALWAYS_ENABLED_STATISTIC(NumCallFilteredGlobals, "Number of filtered globals"); namespace typeart::analysis { -using MemInstFinderConfig = config::TypeARTConfigOptions; +using MemInstFinderConfig = config::Configuration; namespace filter { class CallFilter { @@ -85,25 +87,27 @@ namespace filter { namespace detail { static std::unique_ptr make_filter(const MemInstFinderConfig& config) { using namespace typeart::filter; - const auto filter_id = config.filter_config.implementation; - const std::string glob = config.filter_config.glob; + const bool filter = config[config::ConfigStdArgs::filter]; + const FilterImplementation filter_id = config[config::ConfigStdArgs::filter_impl]; + const std::string glob = config[config::ConfigStdArgs::filter_glob]; - if (filter_id == FilterImplementation::none || !config.filter) { + if (filter_id == FilterImplementation::none || !filter) { LOG_DEBUG("Return no-op filter") return std::make_unique(); } else if (filter_id == FilterImplementation::cg) { - if (config.filter_config.cg_file.empty()) { + const std::string cg_file = config[config::ConfigStdArgs::filter_cg_file]; + if (cg_file.empty()) { LOG_FATAL("CG File not set!"); std::exit(1); } - LOG_DEBUG("Return CG filter with CG file @ " << config.filter_config.cg_file) - auto json_cg = JSONCG::getJSON(config.filter_config.cg_file); + LOG_DEBUG("Return CG filter with CG file @ " << cg_file) + auto json_cg = JSONCG::getJSON(cg_file); auto matcher = std::make_unique(util::glob2regex(glob)); return std::make_unique(glob, std::move(json_cg), std::move(matcher)); } else { LOG_DEBUG("Return default filter") auto matcher = std::make_unique(util::glob2regex(glob)); - const auto deep_glob = config.filter_config.glob_deep; + const auto deep_glob = config[config::ConfigStdArgs::filter_glob_deep]; auto deep_matcher = std::make_unique(util::glob2regex(deep_glob)); return std::make_unique(std::move(matcher), std::move(deep_matcher)); } @@ -150,7 +154,7 @@ class MemInstFinderPass : public MemInstFinder { MemOpVisitor mOpsCollector; filter::CallFilter filter; llvm::DenseMap functionMap; - MemInstFinderConfig config; + const MemInstFinderConfig& config; public: explicit MemInstFinderPass(const MemInstFinderConfig&); @@ -167,14 +171,14 @@ class MemInstFinderPass : public MemInstFinder { }; MemInstFinderPass::MemInstFinderPass(const MemInstFinderConfig& conf_) - : mOpsCollector(conf_.stack, conf_.heap), filter(conf_), config(conf_) { + : mOpsCollector(conf_), filter(conf_), config(conf_) { } bool MemInstFinderPass::runOnModule(Module& module) { mOpsCollector.collectGlobals(module); auto& globals = mOpsCollector.globals; NumDetectedGlobals += globals.size(); - if (config.analysis_config.filter_global) { + if (config[config::ConfigStdArgs::analysis_filter_global]) { globals.erase(llvm::remove_if( globals, [&](const auto gdata) { // NOLINT @@ -295,7 +299,7 @@ bool MemInstFinderPass::runOnFunction(llvm::Function& function) { NumDetectedAllocs += mOpsCollector.allocas.size(); - if (config.analysis_config.filter_alloca_non_array) { + if (config[config::ConfigStdArgs::analysis_filter_alloca_non_array]) { auto& allocs = mOpsCollector.allocas; allocs.erase(llvm::remove_if(allocs, [&](const auto& data) { @@ -308,7 +312,7 @@ bool MemInstFinderPass::runOnFunction(llvm::Function& function) { allocs.end()); } - if (config.analysis_config.filter_heap_alloc) { + if (config[config::ConfigStdArgs::analysis_filter_heap_alloc]) { auto& allocs = mOpsCollector.allocas; auto& mallocs = mOpsCollector.mallocs; @@ -344,7 +348,7 @@ bool MemInstFinderPass::runOnFunction(llvm::Function& function) { allocs.end()); } - if (config.analysis_config.filter_pointer_alloc) { + if (config[config::ConfigStdArgs::analysis_filter_pointer_alloc]) { auto& allocs = mOpsCollector.allocas; allocs.erase(llvm::remove_if(allocs, [&](const auto& data) { @@ -359,7 +363,7 @@ bool MemInstFinderPass::runOnFunction(llvm::Function& function) { } // if (config.filter.useCallFilter) { - if (config.filter) { + if (config[config::ConfigStdArgs::filter]) { auto& allocs = mOpsCollector.allocas; allocs.erase(llvm::remove_if(allocs, [&](const auto& data) { @@ -414,7 +418,8 @@ void MemInstFinderPass::printStats(llvm::raw_ostream& out) const { Table stats("MemInstFinderPass"); stats.wrap_header = true; stats.wrap_length = true; - stats.put(Row::make("Filter string", config.filter_config.glob)); + std::string glob = config[config::ConfigStdArgs::filter_glob]; + stats.put(Row::make("Filter string", glob)); stats.put(Row::make_row("> Heap Memory")); stats.put(Row::make("Heap alloc", NumDetectedHeap.getValue())); stats.put(Row::make("Heap call filtered %", call_filter_heap_p)); @@ -449,8 +454,8 @@ const GlobalDataList& MemInstFinderPass::getModuleGlobals() const { std::unique_ptr create_finder(const config::Configuration& config) { LOG_DEBUG("Constructing MemInstFinder") - const auto meminst_conf = config::helper::config_to_options(config); - return std::make_unique(meminst_conf); + // const auto meminst_conf = config::helper::config_to_options(config); + return std::make_unique(config); } } // namespace typeart::analysis diff --git a/lib/passes/analysis/MemOpVisitor.cpp b/lib/passes/analysis/MemOpVisitor.cpp index 5aa1d34c..5e64dc2b 100644 --- a/lib/passes/analysis/MemOpVisitor.cpp +++ b/lib/passes/analysis/MemOpVisitor.cpp @@ -14,6 +14,8 @@ #include "analysis/MemOpData.h" #include "compat/CallSite.h" +#include "configuration/Configuration.h" +#include "support/ConfigurationBase.h" #include "support/Error.h" #include "support/Logger.h" #include "support/TypeUtil.h" @@ -48,6 +50,9 @@ using namespace llvm; MemOpVisitor::MemOpVisitor() : MemOpVisitor(true, true) { } +MemOpVisitor::MemOpVisitor(const config::Configuration& config) + : MemOpVisitor(config[config::ConfigStdArgs::stack], config[config::ConfigStdArgs::heap]) { +} MemOpVisitor::MemOpVisitor(bool collect_allocas, bool collect_heap) : collect_allocas(collect_allocas), collect_heap(collect_heap) { } diff --git a/lib/passes/analysis/MemOpVisitor.h b/lib/passes/analysis/MemOpVisitor.h index bfcd71e4..345043cb 100644 --- a/lib/passes/analysis/MemOpVisitor.h +++ b/lib/passes/analysis/MemOpVisitor.h @@ -14,6 +14,7 @@ #define LIB_MEMOPVISITOR_H_ #include "MemOpData.h" +#include "configuration/Configuration.h" #include "llvm/IR/InstVisitor.h" @@ -41,6 +42,7 @@ struct MemOpVisitor : public llvm::InstVisitor { public: MemOpVisitor(); + explicit MemOpVisitor(const config::Configuration& config); MemOpVisitor(bool collect_allocas, bool collect_heap); void collect(llvm::Function& function); void collectGlobals(llvm::Module& module); diff --git a/lib/passes/configuration/CMakeLists.txt b/lib/passes/configuration/CMakeLists.txt index 99058066..c589b114 100644 --- a/lib/passes/configuration/CMakeLists.txt +++ b/lib/passes/configuration/CMakeLists.txt @@ -1,6 +1,7 @@ set(CONFIG_SOURCES FileConfiguration.cpp EnvironmentConfiguration.cpp + PassConfiguration.cpp TypeARTOptions.cpp ) diff --git a/lib/passes/configuration/EnvironmentConfiguration.cpp b/lib/passes/configuration/EnvironmentConfiguration.cpp index 10c6fecf..ad3f24fe 100644 --- a/lib/passes/configuration/EnvironmentConfiguration.cpp +++ b/lib/passes/configuration/EnvironmentConfiguration.cpp @@ -13,11 +13,12 @@ #include "EnvironmentConfiguration.h" #include "Configuration.h" -#include "analysis/MemInstFinder.h" +#include "OptionsUtil.h" +#include "PassConfiguration.h" +#include "configuration/TypeARTOptions.h" #include "support/ConfigurationBase.h" #include "support/Logger.h" #include "support/Util.h" -#include "typegen/TypeGenerator.h" #include "llvm/ADT/StringSwitch.h" @@ -44,64 +45,42 @@ std::optional get_env_flag(std::string_view flag) { namespace typeart::config::env { -namespace detail { -template -bool with_any_of(std::string_view lhs, Strings&&... rhs) { - return !lhs.empty() && ((lhs == rhs) || ...); -} +struct EnvironmentStdArgsValues final { +#define TYPEART_CONFIG_OPTION(name, path, type, def_value, description, upper_path) \ + static constexpr char name[] = #def_value; +#include "support/ConfigurationBaseOptions.h" +#undef TYPEART_CONFIG_OPTION +}; -template -ClType string_to_enum(std::string_view cl_value) { - using ::typeart::TypegenImplementation; - using ::typeart::analysis::FilterImplementation; - if constexpr (std::is_same_v) { - auto val = llvm::StringSwitch(cl_value.data()) - .Case("ir", TypegenImplementation::IR) - .Case("dimeta", TypegenImplementation::DIMETA) - .Default(TypegenImplementation::DIMETA); - return val; - } else { - auto val = llvm::StringSwitch(cl_value.data()) - .Case("cg", FilterImplementation::cg) - .Case("none", FilterImplementation::none) - .Case("std", FilterImplementation::standard) - .Default(FilterImplementation::standard); - return val; - } -} +struct EnvironmentStdArgs final { +#define TYPEART_CONFIG_OPTION(name, path, type, def_value, description, upper_path) \ + static constexpr char name[] = "TYPEART_" upper_path; +#include "support/ConfigurationBaseOptions.h" +#undef TYPEART_CONFIG_OPTION +}; +namespace detail { template -config::OptionValue make_opt(std::string_view cl_value) { +OptionValue make_opt(std::string_view cl_value) { LOG_DEBUG("Parsing value " << cl_value) - if constexpr (std::is_same_v) { - const bool is_true_val = with_any_of(cl_value, "true", "TRUE", "1"); - const bool is_false_val = with_any_of(cl_value, "false", "FALSE", "0"); - if (!(is_true_val || is_false_val)) { - LOG_WARNING("Illegal bool value") - } - assert((is_true_val || is_false_val) && "Illegal bool value for environment flag"); - return config::OptionValue{is_true_val}; + auto value = util::make_opt(cl_value.data()); + if constexpr (std::is_enum_v) { + return OptionValue{static_cast(value)}; } else { - if constexpr (std::is_enum_v) { - auto enum_value = string_to_enum(cl_value); - return config::OptionValue{static_cast(enum_value)}; - } else { - return config::OptionValue{std::string{cl_value}}; - } + return OptionValue{value}; } } template -std::pair make_entry(std::string&& key, std::string_view cl_opt, +std::pair make_entry(std::string_view key, std::string_view cl_opt, const std::string& default_value) { const auto env_value = get_env_flag(cl_opt); - return {key, make_opt(env_value.value_or(default_value))}; + return {key, detail::make_opt(env_value.value_or(default_value))}; } template -std::pair make_occurr_entry(std::string&& key, ClOpt&& cl_opt) { +std::pair make_occurr_entry(std::string_view key, ClOpt&& cl_opt) { const bool occurred = (get_env_flag(cl_opt).has_value()); - // LOG_DEBUG("Key :" << key << ":" << occurred) return {key, occurred}; } } // namespace detail @@ -177,11 +156,28 @@ EnvironmentFlagsOptions::EnvironmentFlagsOptions() { mapping_[ConfigStdArgs::global] = OptionValue{static_cast(stack_value)}; occurence_mapping_[ConfigStdArgs::global] = true; } + + auto result = pass::parse_typeart_config_with_occurrence(get_env_flag("TYPEART_OPTIONS").value_or("")); + if (!result.first) { + LOG_INFO("No parseable TYPEART_OPTIONS: " << result.first.takeError()) + } else { + LOG_DEBUG("Parsed TYPEART_OPTIONS\n" << *result.first) + const auto typeart_options = helper::options_to_map(result.first.get()); + for (const auto& entry : result.second) { + const auto key = entry.getKey(); + // LOG_DEBUG("Looking at " << key << " " << entry.second << ":" << occurence_mapping_[key]) + if (entry.second && !occurence_mapping_[key]) { // single ENV priority over TYPEART_OPTIONS + LOG_DEBUG("Replacing " << key) + mapping_[key] = typeart_options.lookup(key); + occurence_mapping_[key] = true; + } + } + } } std::optional EnvironmentFlagsOptions::getValue(std::string_view opt_path) const { auto key = llvm::StringRef(opt_path.data()); - if (mapping_.count(key) != 0U) { + if (occurence_mapping_.lookup(key)) { // only have value if it occurred return mapping_.lookup(key); } return {}; diff --git a/lib/passes/configuration/EnvironmentConfiguration.h b/lib/passes/configuration/EnvironmentConfiguration.h index 0ff24cc3..126d0d6d 100644 --- a/lib/passes/configuration/EnvironmentConfiguration.h +++ b/lib/passes/configuration/EnvironmentConfiguration.h @@ -19,20 +19,6 @@ namespace typeart::config::env { std::optional get_env_flag(std::string_view flag); -struct EnvironmentStdArgsValues final { -#define TYPEART_CONFIG_OPTION(name, path, type, def_value, description, upper_path) \ - static constexpr char name[] = #def_value; -#include "support/ConfigurationBaseOptions.h" -#undef TYPEART_CONFIG_OPTION -}; - -struct EnvironmentStdArgs final { -#define TYPEART_CONFIG_OPTION(name, path, type, def_value, description, upper_path) \ - static constexpr char name[] = "TYPEART_" upper_path; -#include "support/ConfigurationBaseOptions.h" -#undef TYPEART_CONFIG_OPTION -}; - class EnvironmentFlagsOptions final : public config::Configuration { private: OptionsMap mapping_; diff --git a/lib/passes/configuration/FileConfiguration.h b/lib/passes/configuration/FileConfiguration.h index 64dac45a..5ed453d9 100644 --- a/lib/passes/configuration/FileConfiguration.h +++ b/lib/passes/configuration/FileConfiguration.h @@ -20,12 +20,10 @@ namespace typeart::config { struct TypeARTConfigOptions; -} +} // namespace typeart::config namespace typeart::config::file { -// using FileOptionsMap = llvm::StringMap; - class FileOptions : public config::Configuration { public: [[nodiscard]] std::optional getValue(std::string_view opt_path) const override = 0; diff --git a/lib/passes/configuration/OptionsUtil.h b/lib/passes/configuration/OptionsUtil.h new file mode 100644 index 00000000..1c308565 --- /dev/null +++ b/lib/passes/configuration/OptionsUtil.h @@ -0,0 +1,72 @@ +// TypeART library +// +// Copyright (c) 2017-2025 TypeART Authors +// Distributed under the BSD 3-Clause license. +// (See accompanying file LICENSE.txt or copy at +// https://opensource.org/licenses/BSD-3-Clause) +// +// Project home: https://github.com/tudasc/TypeART +// +// SPDX-License-Identifier: BSD-3-Clause +// + +#ifndef TYPEART_CONFIGURATION_OPTIONS_UTIL_H +#define TYPEART_CONFIGURATION_OPTIONS_UTIL_H + +#include "analysis/MemInstFinder.h" +#include "support/Logger.h" +#include "typegen/TypeGenerator.h" + +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringSwitch.h" + +namespace typeart::config::util { + +template +bool with_any_of(llvm::StringRef lhs, Strings&&... rhs) { + return !lhs.empty() && ((lhs == rhs) || ...); +} + +template +ClType string_to_enum(llvm::StringRef cl_value) { + using ::typeart::TypegenImplementation; + using ::typeart::analysis::FilterImplementation; + if constexpr (std::is_same_v) { + auto val = llvm::StringSwitch(cl_value) + .Case("ir", TypegenImplementation::IR) + .Case("dimeta", TypegenImplementation::DIMETA) + .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; + } +} + +template +ClType make_opt(llvm::StringRef cl_value) { + LOG_DEBUG("Parsing value " << cl_value) + if constexpr (std::is_same_v) { + const bool is_true_val = with_any_of(cl_value, "true", "TRUE", "1"); + const bool is_false_val = with_any_of(cl_value, "false", "FALSE", "0"); + if (!(is_true_val || is_false_val)) { + LOG_WARNING("Illegal bool value") + } + assert((is_true_val || is_false_val) && "Illegal bool value for environment flag"); + return is_true_val; + } else { + if constexpr (std::is_enum_v) { + auto enum_value = string_to_enum(cl_value); + return enum_value; + } else { + return std::string{cl_value}; + } + } +} + +} // namespace typeart::config::util +#endif /* TYPEART_CONFIGURATION_OPTIONS_UTIL_H */ diff --git a/lib/passes/configuration/PassBuilderUtil.h b/lib/passes/configuration/PassBuilderUtil.h new file mode 100644 index 00000000..f4e8493c --- /dev/null +++ b/lib/passes/configuration/PassBuilderUtil.h @@ -0,0 +1,75 @@ + +// TypeART library +// +// Copyright (c) 2017-2025 TypeART Authors +// Distributed under the BSD 3-Clause license. +// (See accompanying file LICENSE.txt or copy at +// https://opensource.org/licenses/BSD-3-Clause) +// +// Project home: https://github.com/tudasc/TypeART +// +// SPDX-License-Identifier: BSD-3-Clause +// + +// Taken and adapted from llvm/Passes/PassBuilder.h +#ifndef TYPEART_PASS_BUILDER_UTIL_H +#define TYPEART_PASS_BUILDER_UTIL_H + +#include "support/Logger.h" + +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Error.h" + +namespace typeart::util::pass { + +inline bool checkParametrizedPassName(llvm::StringRef Name, llvm::StringRef PassName) { + using namespace llvm; + if (!Name.consume_front(PassName)) + return false; + // normal pass name w/o parameters == default parameters + if (Name.empty()) + return true; +#if LLVM_VERSION_MAJOR > 14 + return Name.starts_with("<") && Name.ends_with(">"); +#else + return Name.startswith("<") && Name.endswith(">"); +#endif +} + +/// This performs customized parsing of pass name with parameters. +/// +/// We do not need parametrization of passes in textual pipeline very often, +/// yet on a rare occasion ability to specify parameters right there can be +/// useful. +/// +/// \p Name - parameterized specification of a pass from a textual pipeline +/// is a string in a form of : +/// PassName '<' parameter-list '>' +/// +/// Parameter list is being parsed by the parser callable argument, \p Parser, +/// It takes a string-ref of parameters and returns either StringError or a +/// parameter list in a form of a custom parameters type, all wrapped into +/// Expected<> template class. +/// +template +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; + + StringRef Params = Name; + if (!Params.consume_front(PassName)) { + llvm_unreachable("unable to strip pass name from parametrized pass specification"); + } + if (!Params.empty() && (!Params.consume_front("<") || !Params.consume_back(">"))) { + llvm_unreachable("invalid format for parametrized pass name"); + } + + Expected Result = Parser(Params); + assert((Result || Result.template errorIsA()) && "Pass parameter parser can only return StringErrors."); + return Result; +} + +} // namespace typeart::util::pass + +#endif /* TYPEART_PASS_BUILDER_UTIL_H */ diff --git a/lib/passes/configuration/PassConfiguration.cpp b/lib/passes/configuration/PassConfiguration.cpp new file mode 100644 index 00000000..24177765 --- /dev/null +++ b/lib/passes/configuration/PassConfiguration.cpp @@ -0,0 +1,158 @@ +// TypeART library +// +// Copyright (c) 2017-2025 TypeART Authors +// Distributed under the BSD 3-Clause license. +// (See accompanying file LICENSE.txt or copy at +// https://opensource.org/licenses/BSD-3-Clause) +// +// Project home: https://github.com/tudasc/TypeART +// +// SPDX-License-Identifier: BSD-3-Clause +// + +#include "PassConfiguration.h" + +#include "OptionsUtil.h" +#include "analysis/MemInstFinder.h" +#include "configuration/Configuration.h" +#include "support/ConfigurationBase.h" +#include "support/ConfigurationBaseOptions.h" +#include "support/Error.h" +#include "support/Logger.h" + +#include "llvm/Support/FormatVariadicDetails.h" + +#include +#include +#include + +namespace typeart::config::pass { + +struct PassStdArgsEq final { +#define TYPEART_CONFIG_OPTION(name, path, type, def_value, description, upper_path) \ + static constexpr char name[] = path "="; +#include "support/ConfigurationBaseOptions.h" +#undef TYPEART_CONFIG_OPTION +}; + +llvm::Expected parse_typeart_config(llvm::StringRef parameters) { + return parse_typeart_config_with_occurrence(parameters).first; +} + +PassConfig parse_typeart_config_with_occurrence(llvm::StringRef parameters) { + LOG_DEBUG("Parsing string: " << parameters) + TypeARTConfigOptions result; + OptOccurrenceMap occurrence_map; + bool global_set{false}; + bool stack_set{false}; + + while (!parameters.empty()) { + llvm::StringRef parameter_name; + std::tie(parameter_name, parameters) = parameters.split(';'); + + const bool enable = !parameter_name.consume_front("no-"); + + if (parameter_name == ConfigStdArgs::heap) { + result.heap = enable; + occurrence_map[ConfigStdArgs::heap] = true; + continue; + } + + if (parameter_name == ConfigStdArgs::stack) { + result.stack = enable; + occurrence_map[ConfigStdArgs::stack] = true; + stack_set = true; + continue; + } + + if (parameter_name == ConfigStdArgs::global) { + global_set = true; + result.global = enable; + occurrence_map[ConfigStdArgs::global] = true; + continue; + } + + if (parameter_name == ConfigStdArgs::filter) { + result.filter = enable; + occurrence_map[ConfigStdArgs::filter] = true; + continue; + } + + if (parameter_name == ConfigStdArgs::stats) { + result.statistics = enable; + occurrence_map[ConfigStdArgs::stats] = true; + continue; + } + + if (parameter_name == ConfigStdArgs::stack_lifetime) { + result.stack_lifetime = enable; + occurrence_map[ConfigStdArgs::stack_lifetime] = true; + continue; + } + + if (parameter_name.consume_front(PassStdArgsEq::typegen)) { + result.typegen = util::string_to_enum(parameter_name); + occurrence_map[ConfigStdArgs::typegen] = true; + continue; + } + + if (parameter_name.consume_front(PassStdArgsEq::filter_impl)) { + result.filter_config.implementation = util::string_to_enum(parameter_name); + occurrence_map[ConfigStdArgs::filter_impl] = true; + continue; + } + + if (parameter_name.consume_front(PassStdArgsEq::filter_glob)) { + result.filter_config.glob = parameter_name; + occurrence_map[ConfigStdArgs::filter_glob] = true; + continue; + } + if (parameter_name.consume_front(PassStdArgsEq::filter_glob_deep)) { + result.filter_config.glob_deep = parameter_name; + occurrence_map[ConfigStdArgs::filter_glob_deep] = true; + continue; + } + if (parameter_name == ConfigStdArgs::analysis_filter_global) { + result.analysis_config.filter_global = enable; + occurrence_map[ConfigStdArgs::analysis_filter_global] = true; + continue; + } + + if (parameter_name == ConfigStdArgs::analysis_filter_alloca_non_array) { + result.analysis_config.filter_alloca_non_array = enable; + occurrence_map[ConfigStdArgs::analysis_filter_alloca_non_array] = true; + continue; + } + + if (parameter_name == ConfigStdArgs::analysis_filter_heap_alloc) { + result.analysis_config.filter_heap_alloc = enable; + occurrence_map[ConfigStdArgs::analysis_filter_heap_alloc] = true; + continue; + } + + if (parameter_name == ConfigStdArgs::analysis_filter_pointer_alloc) { + result.analysis_config.filter_pointer_alloc = enable; + occurrence_map[ConfigStdArgs::analysis_filter_pointer_alloc] = true; + continue; + } + { + // undefined symbol issue: llvm::formatv("Unknown TypeART option {0} with unparsed list {1}", parameter_name, + // parameters).str() + std::string out_string; + llvm::raw_string_ostream out_stream(out_string); + out_stream << "Unknown TypeART option " << parameter_name; + if (!parameters.empty()) { + out_stream << " with unparsed list " << parameters; + } + return {error::make_string_error(out_stream.str()), occurrence_map}; + } + } + if (!global_set && stack_set) { + // Stack implies global + result.global = result.stack; + occurrence_map[ConfigStdArgs::global] = true; + } + return {result, occurrence_map}; +} + +} // namespace typeart::config::pass \ No newline at end of file diff --git a/lib/passes/configuration/PassConfiguration.h b/lib/passes/configuration/PassConfiguration.h new file mode 100644 index 00000000..9dda8566 --- /dev/null +++ b/lib/passes/configuration/PassConfiguration.h @@ -0,0 +1,31 @@ +// TypeART library +// +// Copyright (c) 2017-2025 TypeART Authors +// Distributed under the BSD 3-Clause license. +// (See accompanying file LICENSE.txt or copy at +// https://opensource.org/licenses/BSD-3-Clause) +// +// Project home: https://github.com/tudasc/TypeART +// +// SPDX-License-Identifier: BSD-3-Clause +// + +#ifndef TYPEART_PASS_CONFIGURATION_H +#define TYPEART_PASS_CONFIGURATION_H + +#include "Configuration.h" +#include "TypeARTOptions.h" + +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Error.h" + +namespace typeart::config::pass { + +using PassConfig = std::pair, OptOccurrenceMap>; + +llvm::Expected parse_typeart_config(llvm::StringRef parameters); +PassConfig parse_typeart_config_with_occurrence(llvm::StringRef parameters); + +} // namespace typeart::config::pass + +#endif /* TYPEART_PASS_CONFIGURATION_H */ diff --git a/lib/passes/configuration/TypeARTOptions.h b/lib/passes/configuration/TypeARTOptions.h index 466c92fe..7110bed1 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_OPTIONS_H -#define TYPEART_OPTIONS_H +#ifndef TYPEART_CONFIGURATION_OPTIONS_H +#define TYPEART_CONFIGURATION_OPTIONS_H #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_OPTIONS_H */ +#endif /* TYPEART_CONFIGURATION_OPTIONS_H */ diff --git a/lib/passes/support/Error.h b/lib/passes/support/Error.h index 50b2e7e9..c759a8a6 100644 --- a/lib/passes/support/Error.h +++ b/lib/passes/support/Error.h @@ -23,7 +23,13 @@ namespace typeart::error { } inline llvm::Error make_string_error(const char* message) { - return llvm::make_error(llvm::inconvertibleErrorCode(), message); + return llvm::createStringError(llvm::inconvertibleErrorCode(), message); + // return llvm::make_error(llvm::inconvertibleErrorCode(), message); +} + +inline llvm::Error make_string_error(std::string message) { + return llvm::createStringError(llvm::inconvertibleErrorCode(), message); + // return llvm::make_error( message); } #define RETURN_ERROR_IF(condition, ...) \ diff --git a/lib/passes/support/Util.h b/lib/passes/support/Util.h index c541b8f4..52ccfbf1 100644 --- a/lib/passes/support/Util.h +++ b/lib/passes/support/Util.h @@ -13,7 +13,7 @@ #ifndef LIB_UTIL_H_ #define LIB_UTIL_H_ -//#include "Logger.h" +// #include "Logger.h" #include "compat/CallSite.h" diff --git a/lib/passes/typegen/TypeGenerator.cpp b/lib/passes/typegen/TypeGenerator.cpp index 37969d89..176aa30c 100644 --- a/lib/passes/typegen/TypeGenerator.cpp +++ b/lib/passes/typegen/TypeGenerator.cpp @@ -73,6 +73,10 @@ std::unique_ptr make_typegen(std::string_view file, TypegenImplem default: break; } +#if LLVM_VERSION_MAJOR > 14 + LOG_ERROR("TypeGen for LLVM IR (typegen=ir) unsupported with LLVM version > 14. Returning typegen=dimeta") + return types::make_dimeta_typeidgen(file, std::move(database)); +#endif LOG_DEBUG("Loading IR type parser") return make_ir_typeidgen(file, std::move(database)); } diff --git a/lib/runtime/Runtime.cpp b/lib/runtime/Runtime.cpp index 0727f613..1e3042a5 100644 --- a/lib/runtime/Runtime.cpp +++ b/lib/runtime/Runtime.cpp @@ -18,7 +18,7 @@ #include "TypeIO.h" #include "support/Logger.h" -//#include "llvm/Support/raw_ostream.h" +// #include "llvm/Support/raw_ostream.h" #include #include diff --git a/test/lit.cfg b/test/lit.cfg index 0cf9a193..7e575369 100644 --- a/test/lit.cfg +++ b/test/lit.cfg @@ -64,7 +64,8 @@ typeart_script_dir = getattr(config, 'typeart_script_dir', None) transform_name = getattr(config, 'typeart_pass', None) typelib_name = getattr(config, 'typeart_types', None) transform_pass = '{}/{}'.format(typeart_lib_root, transform_name) -std_plugin_args = 'typeart --typeart-stats' +std_plugin_args = 'typeart --typeart-stats=true' +std_plugin_args_newpm = 'typeart