diff --git a/External/FEXCore/Scripts/config_generator.py b/External/FEXCore/Scripts/config_generator.py index c662a62a5..a050ff148 100644 --- a/External/FEXCore/Scripts/config_generator.py +++ b/External/FEXCore/Scripts/config_generator.py @@ -27,7 +27,9 @@ def print_header(): #ifndef OPT_STRARRAY #define OPT_STRARRAY(group, enum, json, default) OPT_BASE(fextl::string, group, enum, json, default) #endif - +#ifndef OPT_STRENUM +#define OPT_STRENUM(group, enum, json, default) OPT_BASE(uint64_t, group, enum, json, default) +#endif ''' output_file.write(header) @@ -40,6 +42,7 @@ def print_tail(): #undef OPT_UINT64 #undef OPT_STR #undef OPT_STRARRAY +#undef OPT_STRENUM ''' output_file.write(tail) @@ -127,12 +130,13 @@ def print_man_options(options): short = op_vals["ShortArg"] default = op_vals["Default"] + value_type = op_vals["Type"] # Textual default rather than enum based if ("TextDefault" in op_vals): default = op_vals["TextDefault"] - if (op_vals["Type"] == "str" or op_vals["Type"] == "strarray"): + if (value_type == "str" or value_type == "strarray" or value_type == "strenum"): # Wrap the string argument in quotes default = "'" + default + "'" print_man_option( @@ -141,6 +145,12 @@ def print_man_options(options): op_vals["Desc"], default ) + if (value_type == "strenum"): + Enums = op_vals["Enums"] + output_man.write("\\fBAvailable Options:\\fR\n") + for enum_op_key, enum_op_vals in Enums.items(): + output_man.write("{}, ".format(enum_op_vals)) + output_man.write("\n") output_man.write(".El\n") @@ -150,12 +160,13 @@ def print_man_environment(options): for op_group, group_vals in options.items(): for op_key, op_vals in group_vals.items(): default = op_vals["Default"] + value_type = op_vals["Type"] # Textual default rather than enum based if ("TextDefault" in op_vals): default = op_vals["TextDefault"] - if (op_vals["Type"] == "str" or op_vals["Type"] == "strarray"): + if (value_type == "str" or value_type == "strarray" or value_type == "strenum"): # Wrap the string argument in quotes default = "'" + default + "'" print_man_env_option( @@ -165,6 +176,13 @@ def print_man_environment(options): False ) + if (value_type == "strenum"): + Enums = op_vals["Enums"] + output_man.write("\\fBAvailable Options:\\fR\n") + for enum_op_key, enum_op_vals in Enums.items(): + output_man.write("{}, ".format(enum_op_vals)) + output_man.write("\n") + print_man_environment_tail() output_man.write(".El\n") @@ -334,7 +352,7 @@ def print_argloader_options(options): for op_key, op_vals in group_vals.items(): default = op_vals["Default"] - if (op_vals["Type"] == "str" or op_vals["Type"] == "strarray"): + if (op_vals["Type"] == "str" or op_vals["Type"] == "strarray" or op_vals["Type"] == "strenum"): # Wrap the string argument in quotes default = "\"" + default + "\"" @@ -382,7 +400,10 @@ def print_parse_argloader_options(options): # boolean values need a decimal specifier. Otherwise fmt prints strings. conversion_func = "fextl::fmt::format(\"{:d}\", " - if (value_type == "strarray"): + if (value_type == "strenum"): + output_argloader.write("\tfextl::string UserValue = Options[\"{0}\"];\n".format(op_key)) + output_argloader.write("\tSet(FEXCore::Config::ConfigOption::CONFIG_{}, FEXCore::Config::EnumParser(FEXCore::Config::{}_EnumPairs, UserValue));\n".format(op_key.upper(), op_key, op_key)) + elif (value_type == "strarray"): # these need a bit more help output_argloader.write("\tauto Array = Options.all(\"{0}\");\n".format(op_key)) output_argloader.write("\tfor (auto iter = Array.begin(); iter != Array.end(); ++iter) {\n") @@ -407,6 +428,12 @@ def print_parse_envloader_options(options): for op_group, group_vals in options.items(): for op_key, op_vals in group_vals.items(): + value_type = op_vals["Type"] + if (value_type == "strenum"): + output_argloader.write("else if (Key == \"FEX_{0}\") {{\n".format(op_key.upper())) + output_argloader.write("Value = FEXCore::Config::EnumParser(FEXCore::Config::{}_EnumPairs, Value);\n".format(op_key, op_key)) + output_argloader.write("}\n") + if ("ArgumentHandler" in op_vals): conversion_func = "FEXCore::Config::Handler::{0}".format(op_vals["ArgumentHandler"]) output_argloader.write("else if (Key == \"FEX_{0}\") {{\n".format(op_key.upper())) @@ -414,6 +441,41 @@ def print_parse_envloader_options(options): output_argloader.write("}\n") output_argloader.write("#endif\n") +def print_parse_enum_options(options): + output_argloader.write("#ifdef ENUMDEFINES\n") + output_argloader.write("#undef ENUMDEFINES\n") + for op_group, group_vals in options.items(): + for op_key, op_vals in group_vals.items(): + if (op_vals["Type"] == "strenum"): + output_argloader.write("enum {} : uint64_t {{\n".format(op_key)) + Enums = op_vals["Enums"] + i = 0 + # Always have an OFF. + output_argloader.write("\tOFF = 0,\n") + for enum_op_key, enum_op_vals in Enums.items(): + output_argloader.write("\t{} = 1ULL << {},\n".format(enum_op_key.upper(), i)) + i += 1 + + output_argloader.write("};\n") + + for op_group, group_vals in options.items(): + for op_key, op_vals in group_vals.items(): + if (op_vals["Type"] == "strenum"): + Enums = op_vals["Enums"] + + output_argloader.write("using {}ConfigPair = std::pair;\n".format(op_key, op_key)) + output_argloader.write("constexpr static std::array<{}ConfigPair, {}> {}_EnumPairs = {{{{\n".format(op_key, len(Enums) + 1, op_key)) + i = 0 + # Always have an OFF. + output_argloader.write("\t{{ \"off\", FEXCore::Config::{}::OFF }},\n".format(op_key)) + for enum_op_key, enum_op_vals in Enums.items(): + output_argloader.write("\t{{ \"{}\", FEXCore::Config::{}::{} }},\n".format(enum_op_vals, op_key, enum_op_key.upper())) + i += 1 + + output_argloader.write("}};\n") + + output_argloader.write("#endif\n") + def check_for_duplicate_options(options): short_map = [] long_map = [] @@ -492,4 +554,7 @@ print_parse_argloader_options(options); # Generate environment loader code print_parse_envloader_options(options); +# Generate enum variable options +print_parse_enum_options(options); + output_argloader.close() diff --git a/External/FEXCore/Source/Interface/Config/Config.cpp b/External/FEXCore/Source/Interface/Config/Config.cpp index 152c96b34..0e4258db4 100644 --- a/External/FEXCore/Source/Interface/Config/Config.cpp +++ b/External/FEXCore/Source/Interface/Config/Config.cpp @@ -1,5 +1,6 @@ #include "Common/StringConv.h" #include "Common/StringUtils.h" +#include "FEXCore/Utils/EnumUtils.h" #include #include @@ -37,6 +38,7 @@ namespace DefaultValues { #define OPT_BASE(type, group, enum, json, default) const P(type) P(enum) = P(default); #define OPT_STR(group, enum, json, default) const std::string_view P(enum) = P(default); #define OPT_STRARRAY(group, enum, json, default) OPT_STR(group, enum, json, default) +#define OPT_STRENUM(group, enum, json, default) const uint64_t P(enum) = FEXCore::ToUnderlying(P(default)); #include } diff --git a/External/FEXCore/Source/Interface/Config/Config.json.in b/External/FEXCore/Source/Interface/Config/Config.json.in index 6f3c98d1f..5e872fc54 100644 --- a/External/FEXCore/Source/Interface/Config/Config.json.in +++ b/External/FEXCore/Source/Interface/Config/Config.json.in @@ -251,6 +251,20 @@ "Set this in an application configuration for injecting in to only specific applications.", "\tNote: If x86/x86_64 libSegFault.so isn't installed then this option won't work." ] + }, + "Disassemble": { + "Type": "strenum", + "Default": "FEXCore::Config::Disassemble::OFF", + "Enums": { + "DISPATCHER": "dispatcher", + "BLOCKS": "blocks" + }, + "Desc": [ + "Allows controlling of the vixl disassembler.", + "\toff: No disassembly will be output", + "\tdispatcher: Will enable disassembly of the JIT dispatcher loop", + "\tblocks: Will enable disassembly of the translated instruction code blocks" + ] } }, "Logging": { diff --git a/External/FEXCore/Source/Interface/Core/ArchHelpers/Arm64Emitter.h b/External/FEXCore/Source/Interface/Core/ArchHelpers/Arm64Emitter.h index 4a3a45cc6..545851552 100644 --- a/External/FEXCore/Source/Interface/Core/ArchHelpers/Arm64Emitter.h +++ b/External/FEXCore/Source/Interface/Core/ArchHelpers/Arm64Emitter.h @@ -175,6 +175,7 @@ protected: #endif #ifdef VIXL_DISASSEMBLER vixl::aarch64::PrintDisassembler Disasm {stderr}; + FEX_CONFIG_OPT(Disassemble, DISASSEMBLE); #endif FEX_CONFIG_OPT(StaticRegisterAllocation, SRA); }; diff --git a/External/FEXCore/Source/Interface/Core/Dispatcher/Arm64Dispatcher.cpp b/External/FEXCore/Source/Interface/Core/Dispatcher/Arm64Dispatcher.cpp index db326ccd4..a5ee66ff7 100644 --- a/External/FEXCore/Source/Interface/Core/Dispatcher/Arm64Dispatcher.cpp +++ b/External/FEXCore/Source/Interface/Core/Dispatcher/Arm64Dispatcher.cpp @@ -503,8 +503,10 @@ void Arm64Dispatcher::EmitDispatcher() { } #ifdef VIXL_DISASSEMBLER - const auto DisasmEnd = GetCursorAddress(); - Disasm.DisassembleBuffer(DisasmBegin, DisasmEnd); + if (Disassemble() & FEXCore::Config::Disassemble::DISPATCHER) { + const auto DisasmEnd = GetCursorAddress(); + Disasm.DisassembleBuffer(DisasmBegin, DisasmEnd); + } #endif } diff --git a/External/FEXCore/Source/Interface/Core/JIT/Arm64/JIT.cpp b/External/FEXCore/Source/Interface/Core/JIT/Arm64/JIT.cpp index f7654cad2..9e9da877e 100644 --- a/External/FEXCore/Source/Interface/Core/JIT/Arm64/JIT.cpp +++ b/External/FEXCore/Source/Interface/Core/JIT/Arm64/JIT.cpp @@ -1142,8 +1142,10 @@ CPUBackend::CompiledCode Arm64JITCore::CompileCode(uint64_t Entry, ClearICache(CodeData.BlockBegin, CodeOnlySize); #ifdef VIXL_DISASSEMBLER - const auto DisasmEnd = reinterpret_cast(JITBlockTailLocation); - Disasm.DisassembleBuffer(DisasmBegin, DisasmEnd); + if (Disassemble() & FEXCore::Config::Disassemble::BLOCKS) { + const auto DisasmEnd = reinterpret_cast(JITBlockTailLocation); + Disasm.DisassembleBuffer(DisasmBegin, DisasmEnd); + } #endif if (DebugData) { diff --git a/External/FEXCore/include/FEXCore/Config/Config.h b/External/FEXCore/include/FEXCore/Config/Config.h index 0cd4348cf..6bf77bbdc 100644 --- a/External/FEXCore/include/FEXCore/Config/Config.h +++ b/External/FEXCore/include/FEXCore/Config/Config.h @@ -2,12 +2,16 @@ #include #include +#include +#include #include +#include #include #include #include #include +#include #include #include @@ -52,6 +56,9 @@ namespace Handler { #include }; +#define ENUMDEFINES +#include + enum ConfigCore { CONFIG_INTERPRETER, CONFIG_IRJIT, @@ -83,6 +90,42 @@ namespace Handler { LAYER_TOP, }; + template + static inline fextl::string EnumParser(PairTypes const &EnumPairs, std::string_view const View) { + uint64_t EnumMask{}; + auto Results = std::from_chars(View.data(), View.data() + View.size(), EnumMask); + if (Results.ec == std::errc()) { + // If the data is a valid number, just pass it through. + return View.data(); + } + + auto Begin = 0; + auto End = View.find_first_of(','); + std::string_view Option = View.substr(Begin, End); + while (Option.size() != 0) { + auto EnumValue = std::find_if(EnumPairs.begin(), EnumPairs.end(), + [Option](const DisassembleConfigPair &Value) -> bool { + return Value.first == Option; + }); + + if (EnumValue == EnumPairs.end()) { + LogMan::Msg::IFmt("Skipping Unknown option: {}", Option); + } + else { + EnumMask |= FEXCore::ToUnderlying(EnumValue->second); + } + + if (End == std::string::npos) { + break; + } + Begin = End + 1; + End = View.find_first_of(',', Begin); + Option = View.substr(Begin, End); + } + + return fextl::fmt::format("{}", EnumMask); + } + namespace DefaultValues { #define P(x) x #define OPT_BASE(type, group, enum, json, default) extern const P(type) P(enum); diff --git a/Source/Tools/FEXConfig/Main.cpp b/Source/Tools/FEXConfig/Main.cpp index 5f76e4a2f..fc8140a33 100644 --- a/Source/Tools/FEXConfig/Main.cpp +++ b/Source/Tools/FEXConfig/Main.cpp @@ -1,6 +1,7 @@ #include "Common/Config.h" #include "Common/FileFormatCheck.h" #include "FEXCore/Config/Config.h" +#include "FEXCore/Utils/EnumUtils.h" #include "Tools/CommonGUI/IMGui.h" #include @@ -75,6 +76,8 @@ namespace { #define OPT_STR(group, enum, json, default) \ LoadedConfig->Set(FEXCore::Config::ConfigOption::CONFIG_##enum, default); #define OPT_STRARRAY(group, enum, json, default) // Do nothing +#define OPT_STRENUM(group, enum, json, default) \ + LoadedConfig->Set(FEXCore::Config::ConfigOption::CONFIG_##enum, std::to_string(FEXCore::ToUnderlying(default))); #include // Erase unnamed options which shouldn't be set @@ -108,6 +111,8 @@ namespace { #define OPT_STR(group, enum, json, default) \ if (!LoadedConfig->OptionExists(FEXCore::Config::ConfigOption::CONFIG_##enum)) { LoadedConfig->EraseSet(FEXCore::Config::ConfigOption::CONFIG_##enum, default); } #define OPT_STRARRAY(group, enum, json, default) // Do nothing +#define OPT_STRENUM(group, enum, json, default) \ + if (!LoadedConfig->OptionExists(FEXCore::Config::ConfigOption::CONFIG_##enum)) { LoadedConfig->EraseSet(FEXCore::Config::ConfigOption::CONFIG_##enum, std::to_string(FEXCore::ToUnderlying(default))); } #include // Erase unnamed options which shouldn't be set