From 34ffd2d6e255aaec009b0721445740b6744d8af3 Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Thu, 27 Aug 2026 15:08:20 -0700 Subject: [PATCH] FEXCore/Config: Annotate all config options that can affect codegen Instead serializing the world, allow the config to be data driven. A couple host feature options aren't serialized as they get explained elsewhere. --- FEXCore/Scripts/config_generator.py | 28 ++++++ FEXCore/Source/Interface/Config/Config.cpp | 13 ++- .../Source/Interface/Config/Config.json.in | 85 ++++++++++++++++++- 3 files changed, 115 insertions(+), 11 deletions(-) diff --git a/FEXCore/Scripts/config_generator.py b/FEXCore/Scripts/config_generator.py index 882f906a3..f4e9b1e7a 100644 --- a/FEXCore/Scripts/config_generator.py +++ b/FEXCore/Scripts/config_generator.py @@ -407,6 +407,32 @@ def print_parse_enum_options(options): output_argloader.write("#endif\n") +def print_affects_codegen_options(options, unnamed_options): + output_argloader.write("#ifdef CONFIG_AFFECTSCODEGEN\n") + output_argloader.write("#undef CONFIG_AFFECTSCODEGEN\n") + + TotalConfigOptions = 0 + for op_group, group_vals in options.items(): + for op_key, op_vals in group_vals.items(): + TotalConfigOptions += 1 + for op_group, group_vals in unnamed_options.items(): + for op_key, op_vals in group_vals.items(): + TotalConfigOptions += 1 + + output_argloader.write("constexpr static std::array Config_AffectsCodeGen = {{{{\n".format(TotalConfigOptions)) + for op_group, group_vals in options.items(): + for op_key, op_vals in group_vals.items(): + assert "AffectsCodeGen" in op_vals, "All config options must be marked if they affect codegen." + output_argloader.write("\t{}, // {}\n".format(op_vals["AffectsCodeGen"], op_key)) + + for op_group, group_vals in unnamed_options.items(): + for op_key, op_vals in group_vals.items(): + assert "AffectsCodeGen" in op_vals, "All config options must be marked if they affect codegen." + output_argloader.write("\t{}, // {}\n".format(op_vals["AffectsCodeGen"], op_key)) + output_argloader.write("}};\n") + + output_argloader.write("#endif\n") + if (len(sys.argv) < 5): sys.exit() @@ -451,4 +477,6 @@ print_parse_jsonloader_options(options); # Generate enum variable options print_parse_enum_options(options); +print_affects_codegen_options(options, unnamed_options); + output_argloader.close() diff --git a/FEXCore/Source/Interface/Config/Config.cpp b/FEXCore/Source/Interface/Config/Config.cpp index 995ed090f..cd452b9bd 100644 --- a/FEXCore/Source/Interface/Config/Config.cpp +++ b/FEXCore/Source/Interface/Config/Config.cpp @@ -520,6 +520,9 @@ void Value::GetListIfExists(FEXCore::Config::ConfigOption Option, StringArray } template void Value::GetListIfExists(FEXCore::Config::ConfigOption Option, StringArrayType* List); +#define CONFIG_AFFECTSCODEGEN +#include + fextl::string SerializeForCache() { fextl::string Config {}; @@ -533,16 +536,10 @@ fextl::string SerializeForCache() { }; const auto SerializeValue = [&Config, append_string_triple](auto ConfigVal, const auto Default) { - if constexpr (Option == ConfigOption::CONFIG_ENV || Option == ConfigOption::CONFIG_HOSTENV || - Option == ConfigOption::CONFIG_ADDITIONALARGUMENTS || Option == ConfigOption::CONFIG_APP_CONFIG_NAME || - Option == ConfigOption::CONFIG_APP_FILENAME || Option == ConfigOption::CONFIG_IS64BIT_MODE || - Option == ConfigOption::CONFIG_INTERPRETER_INSTALLED || Option == ConfigOption::CONFIG_DISABLE_VIXL_INDIRECT_RUNTIME_CALLS || - Option == ConfigOption::CONFIG_HOSTFEATURES || Option == ConfigOption::CONFIG_CPUFEATUREREGISTERS) { - // Skip environment variables, meta arguments, and HostFeatures. - // Also skip CPUFeatureRegisters because it contains unfiltered data that is used in HostFeatures. + if (!Config_AffectsCodeGen[FEXCore::ToUnderlying(Option)]) { + // Skip everything that the config says doesn't affect codegen. return; } - append_string_triple(Config, FEXCore::Config::GetConfigJSONName(Option), Option, ConfigVal()); }; diff --git a/FEXCore/Source/Interface/Config/Config.json.in b/FEXCore/Source/Interface/Config/Config.json.in index b225b680a..7ad190004 100644 --- a/FEXCore/Source/Interface/Config/Config.json.in +++ b/FEXCore/Source/Interface/Config/Config.json.in @@ -4,6 +4,7 @@ "Multiblock": { "Type": "bool", "Default": "true", + "AffectsCodeGen": "true", "Desc": [ "Controls multiblock code compilation", "Can cause long JIT compilation times and stutter" @@ -12,6 +13,7 @@ "MaxInst": { "Type": "int32", "Default": "5000", + "AffectsCodeGen": "true", "Desc": [ "Maximum number of instruction to store in a block" ] @@ -19,6 +21,7 @@ "EnableCodeCachingWIP": { "Type": "bool", "Default": "false", + "AffectsCodeGen": "true", "Desc": [ "Enable the code caching subsystem" ] @@ -26,6 +29,7 @@ "EnableLazyCodeCachingWIP": { "Type": "bool", "Default": "false", + "AffectsCodeGen": "false", "Desc": [ "Enable lazy loading of chunks in code caches" ] @@ -33,6 +37,7 @@ "EnableCodeCacheValidation": { "Type": "bool", "Default": "false", + "AffectsCodeGen": "false", "Desc": [ "Enable expensive validation when loading code caches" ] @@ -40,6 +45,8 @@ "HostFeatures": { "Type": "strenum", "Default": "FEXCore::Config::HostFeatures::OFF", + "AffectsCodeGen": "true", + "Comment": "Technically affects codegen, but this is serialized elsewhere.", "Enums": { "ENABLESVE": "enablesve", "DISABLESVE": "disablesve", @@ -115,6 +122,7 @@ "SmallTSCScale": { "Type": "bool", "Default": "true", + "AffectsCodeGen": "true", "Desc": [ "Scales the cycle counter on systems that have low frequencies." ] @@ -122,6 +130,7 @@ "HideHybrid": { "Type": "bool", "Default": "true", + "AffectsCodeGen": "false", "Desc": [ "Hides hybrid CPU core arrangement." ] @@ -129,6 +138,8 @@ "CPUFeatureRegisters": { "Type": "str", "Default": "", + "AffectsCodeGen": "false", + "Comment": "Technically affects codegen, but this is serialized in to HostFeatures.", "Desc": [ "Allows overriding cpu feature flags for manual testing" ] @@ -136,6 +147,7 @@ "DiskCache": { "Type": "bool", "Default": "false", + "AffectsCodeGen": "false", "Desc": [ "Enables disk caching for code blocks" ] @@ -143,6 +155,7 @@ "DiskCacheRelocationFilter": { "Type": "bool", "Default": "true", + "AffectsCodeGen": "false", "Desc": [ "Don't cache blocks with relocations pointing outside of any known region" ] @@ -150,6 +163,7 @@ "DiskCachePath": { "Type": "str", "Default": "", + "AffectsCodeGen": "false", "Desc": [ "Optional base directory override for disk cache" ] @@ -157,6 +171,7 @@ "DiskCacheRODBNames": { "Type": "str", "Default": "", + "AffectsCodeGen": "false", "Desc": [ "Optional list of extra read-only disk cache DBs to consider" ] @@ -166,6 +181,7 @@ "RootFS": { "Type": "str", "Default": "", + "AffectsCodeGen": "false", "Desc": [ "Which Root filesystem prefix to use", "This can be a filesystem path", @@ -180,6 +196,7 @@ "ThunkHostLibs": { "Type": "str", "Default": "@CMAKE_INSTALL_FULL_LIBDIR@/fex-emu/HostThunks", + "AffectsCodeGen": "false", "Desc": [ "Folder to find the host-side thunking libraries." ] @@ -187,6 +204,7 @@ "ThunkGuestLibs": { "Type": "str", "Default": "@CMAKE_INSTALL_PREFIX@/share/fex-emu/GuestThunks", + "AffectsCodeGen": "false", "Desc": [ "Folder to find the guest-side thunking libraries." ] @@ -194,6 +212,7 @@ "ThunkConfig": { "Type": "str", "Default": "", + "AffectsCodeGen": "false", "Desc": [ "A json file specifying where to overlay the thunks.", "This can be a filesystem path", @@ -208,6 +227,7 @@ "Env": { "Type": "strarray", "Default": "", + "AffectsCodeGen": "false", "Desc": [ "Adds an environment variable to the emulated environment." ] @@ -215,6 +235,7 @@ "HostEnv": { "Type": "strarray", "Default": "", + "AffectsCodeGen": "false", "Desc": [ "Adds an environment variable to the host environment.", "This can be useful for setting environment variables that thunks can pick up.", @@ -224,6 +245,7 @@ "AdditionalArguments": { "Type": "strarray", "Default": "", + "AffectsCodeGen": "false", "Desc": [ "Allows the user to pass additional arguments to the application" ] @@ -231,6 +253,7 @@ "DisableL2Cache": { "Type": "bool", "Default": "true", + "AffectsCodeGen": "false", "Desc": [ "Disables FEXCore's JIT L2 cache lookup. Saving memory.", "Can potentially introduce more stutters." @@ -239,6 +262,7 @@ "DynamicL1Cache": { "Type": "bool", "Default": "true", + "AffectsCodeGen": "false", "Desc": [ "Switches FEXCore's JIT L1 cache to be dynamically sized. Saving memory.", "Can potentially introduce more stutters." @@ -247,6 +271,7 @@ "DynamicL1CacheIncreaseCountHeuristic": { "Type": "uint64", "Default": "250", + "AffectsCodeGen": "false", "Desc": [ "Threshold of lookups per second that the L1 dynamic cache should increase its size.", "Lower numbers means more aggressive scaling upward to the maximum size.", @@ -258,6 +283,7 @@ "DynamicL1CacheDecreaseCountHeuristic": { "Type": "uint64", "Default": "50", + "AffectsCodeGen": "false", "Desc": [ "Threshold of lookups per second that the L1 dynamic cache should decrease its size.", "The higher the number, the more aggressively it reduces the L1 cache size.", @@ -271,6 +297,7 @@ "SingleStep": { "Type": "bool", "Default": "false", + "AffectsCodeGen": "true", "Desc": [ "Single stepping configuration." ] @@ -278,6 +305,7 @@ "GdbServer": { "Type": "bool", "Default": "false", + "AffectsCodeGen": "true", "Desc": [ "Enables the GDB server." ] @@ -285,6 +313,7 @@ "DumpIR": { "Type": "str", "Default": "no", + "AffectsCodeGen": "false", "Desc": [ "Folder to dump the IR in to.", "[no, stdout, stderr, server, ]" @@ -293,6 +322,7 @@ "PassManagerDumpIR": { "Type": "strenum", "Default": "FEXCore::Config::PassManagerDumpIR::OFF", + "AffectsCodeGen": "false", "Enums": { "BEFOREOPT": "beforeopt", "AFTEROPT": "afteropt", @@ -311,6 +341,7 @@ "DumpGPRs": { "Type": "bool", "Default": "false", + "AffectsCodeGen": "false", "Desc": [ "When the test harness ends, print the GPR state." ] @@ -318,6 +349,7 @@ "O0": { "Type": "bool", "Default": "false", + "AffectsCodeGen": "true", "Desc": [ "Disables optimizations passes for debugging." ] @@ -325,6 +357,7 @@ "GlobalJITNaming": { "Type": "bool", "Default": "false", + "AffectsCodeGen": "false", "Desc": [ "Uses JITSymbols to name all JIT state as one symbol", "Useful for querying how much time is spent inside of the JIT", @@ -334,6 +367,7 @@ "LibraryJITNaming": { "Type": "bool", "Default": "false", + "AffectsCodeGen": "false", "Desc": [ "Uses JITSymbols to name JIT symbols grouped by library", "Useful for querying how much time is spent in each guest library", @@ -343,6 +377,7 @@ "BlockJITNaming": { "Type": "bool", "Default": "false", + "AffectsCodeGen": "false", "Desc": [ "Uses JITSymbols to name JIT symbols", "Useful for determining hot blocks of code", @@ -352,6 +387,7 @@ "GDBSymbols": { "Type": "bool", "Default": "false", + "AffectsCodeGen": "false", "Desc": [ "Integrates with GDB using the JIT interface.", "Needs the fex jit loader in GDB, which can be loaded via `jit-reader-load libFEXGDBReader.so.`", @@ -362,6 +398,7 @@ "InjectLibSegFault": { "Type": "bool", "Default": "false", + "AffectsCodeGen": "false", "Desc": [ "Sets the environment variable LD_PRELOAD=libSegFault.so", "This allows the user to very easily enable libSegFault without dealing with environment variables", @@ -373,6 +410,7 @@ "Disassemble": { "Type": "strenum", "Default": "FEXCore::Config::Disassemble::OFF", + "AffectsCodeGen": "false", "Enums": { "DISPATCHER": "dispatcher", "BLOCKS": "blocks", @@ -389,6 +427,7 @@ "X86Disassemble": { "Type": "bool", "Default": "false", + "AffectsCodeGen": "false", "Desc": [ "Enables x86/x86-64 guest disassembly output for compiled blocks.", "Requires FEX to be built with -DENABLE_ZYDIS=TRUE" @@ -397,6 +436,7 @@ "ForceSVEWidth": { "Type": "uint32", "Default": "0", + "AffectsCodeGen": "true", "Desc": [ "Allows overriding the SVE width in the vixl simulator.", "Useful as a debugging feature." @@ -405,6 +445,7 @@ "DisableTelemetry": { "Type": "bool", "Default": "false", + "AffectsCodeGen": "true", "Desc": [ "Disables telemetry at runtime.", "Useful for CI instcountCI mostly" @@ -415,6 +456,7 @@ "SilentLog": { "Type": "bool", "Default": "true", + "AffectsCodeGen": "false", "Desc": [ "Disables logging" ] @@ -422,6 +464,7 @@ "OutputLog": { "Type": "str", "Default": "server", + "AffectsCodeGen": "false", "Desc": [ "File to write FEX output to.", "[stderr, server, ]" @@ -430,6 +473,7 @@ "TelemetryDirectory": { "Type": "str", "Default": "", + "AffectsCodeGen": "false", "Desc": [ "Redirects the telemetry folder that FEX usually writes to.", "By default telemetry data is stored in {$FEX_APP_DATA_LOCATION,{$XDG_DATA_HOME,$HOME}/fex-emu/Telemetry/}" @@ -438,6 +482,7 @@ "ProfileStats": { "Type": "bool", "Default": "false", + "AffectsCodeGen": "false", "Desc": [ "Enables FEX's low-overhead sampling profile statistics.", "Requires a supported version of Mangohud to see the results" @@ -446,6 +491,7 @@ "EnableGpuvisProfiling": { "Type": "bool", "Default": "false", + "AffectsCodeGen": "false", "Desc": [ "Enables profiling when FEX was built with the gpuvis profiler backend." ] @@ -455,6 +501,7 @@ "SMCChecks": { "Type": "uint8", "Default": "FEXCore::Config::CONFIG_SMC_MTRACK", + "AffectsCodeGen": "true", "TextDefault": "mtrack", "ArgumentHandler": "SMCCheckHandler", "Desc": [ @@ -467,6 +514,7 @@ "TSOEnabled": { "Type": "bool", "Default": "true", + "AffectsCodeGen": "true", "Desc": [ "Controls TSO IR ops.", "Highly likely to break any multithreaded application if disabled." @@ -475,6 +523,7 @@ "VectorTSOEnabled": { "Type": "bool", "Default": "false", + "AffectsCodeGen": "true", "Desc": [ "When TSO emulation is enabled, controls if vector loadstores should also be atomic." ] @@ -482,6 +531,7 @@ "MemcpySetTSOEnabled": { "Type": "bool", "Default": "false", + "AffectsCodeGen": "true", "Desc": [ "When TSO emulation is enabled, controls if memcpy and memset should also be atomic.", "Only affects REP MOVS and REP STOS instructions" @@ -490,6 +540,7 @@ "HalfBarrierTSOEnabled": { "Type": "bool", "Default": "true", + "AffectsCodeGen": "true", "Desc": [ "When TSO emulation is enabled, controls if unaligned loads and stores should be backpatched to half-barrier atomics.", "Can be dangerous due to aligned loadstores through the same code now become non-atomic." @@ -498,6 +549,7 @@ "StrictInProcessSplitLocks": { "Type": "bool", "Default": "false", + "AffectsCodeGen": "false", "Desc": [ "Strict global lock when handling an unaligned atomic that crosses a 16-byte or cacheline granularity", "This is required to ensure a split-lock doesn't tear inside the process" @@ -506,6 +558,7 @@ "KernelUnalignedAtomicBackpatching": { "Type": "bool", "Default": "true", + "AffectsCodeGen": "false", "Desc": [ "When the kernel unaligned atomic handler is enabled, use backpatching to reduce kernel context switches." ] @@ -513,6 +566,7 @@ "VolatileMetadata": { "Type": "bool", "Default": "true", + "AffectsCodeGen": "true", "Desc": [ "Use volatile metadata in PE files to inform TSO instructions when available.", "When metadata is unavailable falls back to the currently enabled TSO options." @@ -521,6 +575,7 @@ "X87ReducedPrecision": { "Type": "bool", "Default": "false", + "AffectsCodeGen": "true", "Desc": [ "Emulates X87 floating point using 64-bit precision. This reduces emulation accuracy and may result in rendering bugs." ] @@ -528,6 +583,7 @@ "StallProcess": { "Type": "bool", "Default": "false", + "AffectsCodeGen": "false", "Desc": [ "Forces a process to stall out on initialization", "Useful for a process that keeps restarting and doesn't work" @@ -536,6 +592,7 @@ "HideHypervisorBit": { "Type": "bool", "Default": "false", + "AffectsCodeGen": "false", "Desc": [ "Hides the hypervisor CPUID bit when set.", "Should only be used for applications that have issues with this set." @@ -544,6 +601,7 @@ "StartupSleep": { "Type": "uint32", "Default": "0", + "AffectsCodeGen": "false", "Desc": [ "Sleeps the process at startup for a duration of seconds.", "Useful if an application crashes too quickly to attach a debugger." @@ -552,6 +610,7 @@ "StartupSleepProcName": { "Type": "str", "Default": "", + "AffectsCodeGen": "false", "Desc": [ "Contrains the startup sleep to only apply to processes that match this name." ] @@ -559,6 +618,7 @@ "MonoHacks": { "Type": "bool", "Default": "true", + "AffectsCodeGen": "true", "Desc": [ "Permits a hook-based SMC approach and smaller JIT blocks when mono is detected." ] @@ -568,6 +628,7 @@ "ServerSocketPath": { "Type": "str", "Default": "", + "AffectsCodeGen": "false", "Desc": [ "Override for a FEXServer socket path. Only useful for chroots." ] @@ -575,6 +636,7 @@ "NeedsSeccomp": { "Type": "bool", "Default": "false", + "AffectsCodeGen": "false", "Desc": [ "Disables inline syscalls in order to support seccomp handling" ] @@ -582,6 +644,7 @@ "ExtendedVolatileMetadata": { "Type": "str", "Default": "", + "AffectsCodeGen": "true", "Desc": [ "Configuration provided volatile metadata. Only implemented for WoW64/arm64ec.", "Limited in its use but can be handy.", @@ -606,15 +669,18 @@ "Misc": { "INTERPRETER_INSTALLED": { "Type": "bool", - "Default": "false" + "Default": "false", + "AffectsCodeGen": "false" }, "APP_FILENAME": { "Type": "str", - "Default": "" + "Default": "", + "AffectsCodeGen": "false" }, "APP_CONFIG_NAME": { "Type": "str", "Default": "", + "AffectsCodeGen": "false", "Desc": [ "This is the application config name that has been loaded.", "This differs from APP_FILENAME in two ways", @@ -625,16 +691,29 @@ }, "IS64BIT_MODE": { "Type": "bool", - "Default": "false" + "Default": "false", + "AffectsCodeGen": "false", + "Comment": "Technically affects codegen, but this is serialized elsewhere." }, "DISABLE_VIXL_INDIRECT_RUNTIME_CALLS": { "Type": "bool", "Default": "true", + "AffectsCodeGen": "false", + "Comment": "Technically affects codegen, but only shows up in the test harness.", "Desc": [ "This option is used for the InstructionCountCI so it can generate the same codegen between Arm64 hosts and vixl simulator hosts.", "Vixl simulator indirect runtime calls are a special hlt instruction with metadata after it. Effectively making a custom call instruction.", "With visual simulator calls disabled, the code generation would be the same as on a native Arm64 host, but running the code is broken." ] + }, + "CONFIG_VERSION": { + "Type": "uint32", + "Default": "0", + "AffectsCodeGen": "true", + "Comment": [ + "Meta option that if config has ever changed definitions dramatically enough that we can rev the version.", + "Be mindful that this will invalidate all caches!" + ] } } }