From 3197602b46619c4c683d4ae25459979ded97b591 Mon Sep 17 00:00:00 2001 From: David Wrighton Date: Tue, 21 Oct 2025 15:16:21 -0700 Subject: [PATCH 1/5] [clr-interp] Enhance InterpMode and CI testing - Enhance InterpMode flag to autoimply various other flags like ReadyToRun=0 EnableHWIntrinsic=0 consistently, so that InterpMode can be used on its own to control interpretation behavior - The comments around InterpMode are now accurate as to what they imply - Enhance CI to allow testing of various interpreter scenarios (The existing model + InterModes 1, 2, and 3) --- .../templates/runtimes/run-test-job.yml | 18 ++++++++- src/coreclr/interpreter/eeinterp.cpp | 4 +- src/coreclr/vm/codeman.cpp | 23 ++++++++++-- src/coreclr/vm/eeconfig.cpp | 37 +++++++++++++++++++ src/coreclr/vm/eeconfig.h | 11 ++++++ src/coreclr/vm/jithost.cpp | 5 +++ src/coreclr/vm/jitinterface.cpp | 8 +--- src/tests/Common/CLRTest.Execute.Bash.targets | 10 ++++- .../Common/CLRTest.Execute.Batch.targets | 9 ++++- src/tests/Common/testenvironment.proj | 7 ++++ 10 files changed, 116 insertions(+), 16 deletions(-) diff --git a/eng/pipelines/common/templates/runtimes/run-test-job.yml b/eng/pipelines/common/templates/runtimes/run-test-job.yml index 932cef5f035e07..44a5d48a7b478e 100644 --- a/eng/pipelines/common/templates/runtimes/run-test-job.yml +++ b/eng/pipelines/common/templates/runtimes/run-test-job.yml @@ -332,7 +332,23 @@ jobs: msbuildParallelism: '/maxcpucount:55' ${{ if in(parameters.testGroup, 'innerloop', 'outerloop') }}: - ${{ if eq(parameters.runtimeFlavor, 'mono') }}: + ${{ if and(eq(parameters.runInterpreter, 'true'),eq(variables['Build.Reason'], 'PullRequest')) }}: + scenarios: + - interpmode3_no_tiered_compilation + - interpmode2_no_tiered_compilation + - interpmode1_no_tiered_compilation + - no_tiered_compilation + ${{ elseif eq(parameters.runInterpreter, 'true') }}: + scenarios: + - interpmode3_no_tiered_compilation + - interpmode3 + - interpmode2_no_tiered_compilation + - interpmode2 + - normal + - no_tiered_compilation + - interpmode1_no_tiered_compilation + - interpmode1 + ${{ elseif eq(parameters.runtimeFlavor, 'mono') }}: # tiered compilation isn't done on mono yet scenarios: - normal diff --git a/src/coreclr/interpreter/eeinterp.cpp b/src/coreclr/interpreter/eeinterp.cpp index 1762477c0fc2fc..38acc3593f2d77 100644 --- a/src/coreclr/interpreter/eeinterp.cpp +++ b/src/coreclr/interpreter/eeinterp.cpp @@ -70,12 +70,12 @@ CorJitResult CILInterp::compileMethod(ICorJitInfo* compHnd, break; } - // 2: use interpreter for everything except intrinsics. All intrinsics fallback to JIT. Implies DOTNET_ReadyToRun=0. + // 2: use interpreter for everything except intrinsics. All intrinsics fallback to JIT. Implies DOTNET_ReadyToRun=0 case 2: doInterpret = !(compHnd->getMethodAttribs(methodInfo->ftn) & CORINFO_FLG_INTRINSIC); break; - // 3: use interpreter for everything, the full interpreter-only mode, no fallbacks to R2R or JIT whatsoever. Implies DOTNET_ReadyToRun=0, DOTNET_EnableHWIntrinsic=0 + // 3: use interpreter for everything, the full interpreter-only mode, no fallbacks to R2R or JIT whatsoever. Implies DOTNET_ReadyToRun=0, DOTNET_EnableHWIntrinsic=0, DOTNET_MaxVectorTBitWidth=128, DOTNET_PreferredVectorBitWidth=128 case 3: doInterpret = true; break; diff --git a/src/coreclr/vm/codeman.cpp b/src/coreclr/vm/codeman.cpp index 3fe0aaf192bb89..9ba1a5adc1982d 100644 --- a/src/coreclr/vm/codeman.cpp +++ b/src/coreclr/vm/codeman.cpp @@ -1195,6 +1195,15 @@ void EEJitManager::SetCpuInfo() // Get the maximum bitwidth of Vector, rounding down to the nearest multiple of 128-bits uint32_t maxVectorTBitWidth = (CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_MaxVectorTBitWidth) / 128) * 128; + bool allowHWIntrinsic = true; + +#if defined(FEATURE_INTERPRETER) + if (maxVectorTBitWidth != 128 && CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_InterpMode) == 3) + { + // Disable larger Vector sizes when interpreter is enabled + maxVectorTBitWidth = 128; + } +#endif #if defined(TARGET_X86) || defined(TARGET_AMD64) CPUCompileFlags.Set(InstructionSet_VectorT128); @@ -1213,7 +1222,7 @@ void EEJitManager::SetCpuInfo() // x86-64-v2 - if (CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_EnableHWIntrinsic)) + if (allowHWIntrinsic && g_pConfig->EnableHWIntrinsic()) { CPUCompileFlags.Set(InstructionSet_X86Base); } @@ -1324,7 +1333,7 @@ void EEJitManager::SetCpuInfo() #elif defined(TARGET_ARM64) CPUCompileFlags.Set(InstructionSet_VectorT128); - if (CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_EnableHWIntrinsic)) + if (allowHWIntrinsic && g_pConfig->EnableHWIntrinsic()) { CPUCompileFlags.Set(InstructionSet_ArmBase); CPUCompileFlags.Set(InstructionSet_AdvSimd); @@ -1408,7 +1417,7 @@ void EEJitManager::SetCpuInfo() g_arm64_atomics_present = true; } #elif defined(TARGET_RISCV64) - if (CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_EnableHWIntrinsic)) + if (allowHWIntrinsic && g_pConfig->EnableHWIntrinsic()) { CPUCompileFlags.Set(InstructionSet_RiscV64Base); } @@ -1509,6 +1518,14 @@ void EEJitManager::SetCpuInfo() uint32_t preferredVectorBitWidth = (CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_PreferredVectorBitWidth) / 128) * 128; +#ifdef FEATURE_INTERPRETER + if (CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_InterpMode) == 3) + { + // Disable larger Vector sizes when interpreter is enabled, and not compiling S.P.Corelib + preferredVectorBitWidth = 128; + } +#endif + if ((preferredVectorBitWidth == 0) && throttleVector512) { preferredVectorBitWidth = 256; diff --git a/src/coreclr/vm/eeconfig.cpp b/src/coreclr/vm/eeconfig.cpp index 3747a07d3295f9..16e45e0291358d 100644 --- a/src/coreclr/vm/eeconfig.cpp +++ b/src/coreclr/vm/eeconfig.cpp @@ -454,8 +454,45 @@ HRESULT EEConfig::sync() pReadyToRunExcludeList = NULL; +#ifdef FEATURE_INTERPRETER +#ifdef FEATURE_JIT + LPWSTR interpreterConfig; + IfFailThrow(CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_Interpreter, &interpreterConfig)); + if (interpreterConfig == NULL) + { + if ((CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_InterpMode) != 0)) + { + enableInterpreter = true; + } + } + else + { + enableInterpreter = true; + } +#else + enableInterpreter = true; +#endif // FEATURE_JIT +#endif // FEATURE_INTERPRETER + + enableHWIntrinsic = CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_EnableHWIntrinsic); +#ifdef FEATURE_INTERPRETER + if (CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_InterpMode) == 3) + { + // InterpMode 3 disables all hw intrinsics + enableHWIntrinsic = 0; + } +#endif // FEATURE_INTERPRETER + #if defined(FEATURE_READYTORUN) fReadyToRun = CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_ReadyToRun); +#if defined(FEATURE_INTERPRETER) + if (fReadyToRun && CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_InterpMode) >= 2) + { + // ReadyToRun and Interpreter modes 2 and 3 are mutually exclusive. + // If both are set, Interpreter wins. + fReadyToRun = false; + } +#endif // defined(FEATURE_INTERPRETER) if (fReadyToRun) { diff --git a/src/coreclr/vm/eeconfig.h b/src/coreclr/vm/eeconfig.h index 9c008ae7647cc2..9f22e5034cbd4c 100644 --- a/src/coreclr/vm/eeconfig.h +++ b/src/coreclr/vm/eeconfig.h @@ -441,6 +441,11 @@ class EEConfig bool RuntimeAsync() const { LIMITED_METHOD_CONTRACT; return runtimeAsync; } +#ifdef FEATURE_INTERPRETER + bool EnableInterpreter() const { LIMITED_METHOD_CONTRACT; return enableInterpreter; } +#endif + bool EnableHWIntrinsic() const { LIMITED_METHOD_CONTRACT; return enableHWIntrinsic; } + private: //---------------------------------------------------------------- bool fInited; // have we synced to the registry at least once? @@ -612,6 +617,12 @@ class EEConfig bool fReadyToRun; #endif + bool enableHWIntrinsic; + +#ifdef FEATURE_INTERPRETER + bool enableInterpreter; +#endif + #if defined(FEATURE_ON_STACK_REPLACEMENT) DWORD dwOSR_HitLimit; DWORD dwOSR_CounterBump; diff --git a/src/coreclr/vm/jithost.cpp b/src/coreclr/vm/jithost.cpp index 44b10f66c103e5..3975ae23efff4b 100644 --- a/src/coreclr/vm/jithost.cpp +++ b/src/coreclr/vm/jithost.cpp @@ -26,6 +26,11 @@ int JitHost::getIntConfigValue(const char* name, int defaultValue) { WRAPPER_NO_CONTRACT; + if (!strcmp(name, "EnableHWIntrinsic")) + { + return g_pConfig->EnableHWIntrinsic() ? 1 : 0; + } + StackSString str; SString(SString::Utf8Literal, name).ConvertToUnicode(str); diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index ce70de8e40b8af..c931b759ec50d4 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -13423,15 +13423,9 @@ PCODE UnsafeJitFunction(PrepareCodeConfig* config, #ifdef FEATURE_INTERPRETER InterpreterJitManager* interpreterMgr = ExecutionManager::GetInterpreterJitManager(); - if (!interpreterMgr->IsInterpreterLoaded()) + if (!interpreterMgr->IsInterpreterLoaded() && g_pConfig->EnableInterpreter()) { - LPWSTR interpreterConfig; - IfFailThrow(CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_Interpreter, &interpreterConfig)); if ( -#ifdef FEATURE_JIT - // If both JIT and interpret are available, load the interpreter for testing purposes only if the config switch is set - (interpreterConfig != NULL) && -#endif !interpreterMgr->LoadInterpreter()) { EEPOLICY_HANDLE_FATAL_ERROR_WITH_MESSAGE(COR_E_EXECUTIONENGINE, W("Failed to load interpreter")); diff --git a/src/tests/Common/CLRTest.Execute.Bash.targets b/src/tests/Common/CLRTest.Execute.Bash.targets index c819c72e4af625..14fb506d33ba7c 100644 --- a/src/tests/Common/CLRTest.Execute.Bash.targets +++ b/src/tests/Common/CLRTest.Execute.Bash.targets @@ -84,6 +84,11 @@ fi + DOTNET_InterpMode; DOTNET_TieredCompilation; DOTNET_DbgEnableMiniDump; DOTNET_EnableCrashReport; @@ -95,6 +96,12 @@ while other scenarios use the default values of DOTNET_* variables defined in ItemDefinitionGroup above --> + + + + + + From b72108c010d9e13d4b40c8f5f2f38dd48601d600 Mon Sep 17 00:00:00 2001 From: David Wrighton Date: Tue, 21 Oct 2025 15:34:35 -0700 Subject: [PATCH 2/5] Update src/tests/Common/CLRTest.Execute.Batch.targets Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/tests/Common/CLRTest.Execute.Batch.targets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tests/Common/CLRTest.Execute.Batch.targets b/src/tests/Common/CLRTest.Execute.Batch.targets index 2ecf43b5fb4ca9..80b737c59ed930 100644 --- a/src/tests/Common/CLRTest.Execute.Batch.targets +++ b/src/tests/Common/CLRTest.Execute.Batch.targets @@ -350,7 +350,7 @@ if defined RunCrossGen2 ( ) if defined RunInterpreter ( - if "DOTNET_InterpMode"=="" ( + if "%DOTNET_InterpMode%"=="" ( SET "DOTNET_Interpreter=$(AssemblyName)^!*" ) ) From 5c24c65473cfd1c67d1a8638f5c3490986196b12 Mon Sep 17 00:00:00 2001 From: David Wrighton Date: Tue, 21 Oct 2025 15:34:41 -0700 Subject: [PATCH 3/5] Update src/coreclr/vm/eeconfig.cpp Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/coreclr/vm/eeconfig.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/vm/eeconfig.cpp b/src/coreclr/vm/eeconfig.cpp index 16e45e0291358d..4e19283ffda47b 100644 --- a/src/coreclr/vm/eeconfig.cpp +++ b/src/coreclr/vm/eeconfig.cpp @@ -474,7 +474,7 @@ HRESULT EEConfig::sync() #endif // FEATURE_JIT #endif // FEATURE_INTERPRETER - enableHWIntrinsic = CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_EnableHWIntrinsic); + enableHWIntrinsic = (CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_EnableHWIntrinsic) != 0); #ifdef FEATURE_INTERPRETER if (CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_InterpMode) == 3) { From 5b875dff11a7c198183151cc02b313900e9559e0 Mon Sep 17 00:00:00 2001 From: David Wrighton Date: Tue, 21 Oct 2025 15:34:49 -0700 Subject: [PATCH 4/5] Update src/coreclr/vm/eeconfig.cpp Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/coreclr/vm/eeconfig.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/vm/eeconfig.cpp b/src/coreclr/vm/eeconfig.cpp index 4e19283ffda47b..b80f99e76e049e 100644 --- a/src/coreclr/vm/eeconfig.cpp +++ b/src/coreclr/vm/eeconfig.cpp @@ -479,7 +479,7 @@ HRESULT EEConfig::sync() if (CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_InterpMode) == 3) { // InterpMode 3 disables all hw intrinsics - enableHWIntrinsic = 0; + enableHWIntrinsic = false; } #endif // FEATURE_INTERPRETER From 478e116a000e1085ebebacd84cc9c94174e269fb Mon Sep 17 00:00:00 2001 From: David Wrighton Date: Wed, 22 Oct 2025 10:38:51 -0700 Subject: [PATCH 5/5] Remove useless boolean flag --- src/coreclr/vm/codeman.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/coreclr/vm/codeman.cpp b/src/coreclr/vm/codeman.cpp index 9ba1a5adc1982d..e8273bf99cd236 100644 --- a/src/coreclr/vm/codeman.cpp +++ b/src/coreclr/vm/codeman.cpp @@ -1195,7 +1195,6 @@ void EEJitManager::SetCpuInfo() // Get the maximum bitwidth of Vector, rounding down to the nearest multiple of 128-bits uint32_t maxVectorTBitWidth = (CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_MaxVectorTBitWidth) / 128) * 128; - bool allowHWIntrinsic = true; #if defined(FEATURE_INTERPRETER) if (maxVectorTBitWidth != 128 && CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_InterpMode) == 3) @@ -1222,7 +1221,7 @@ void EEJitManager::SetCpuInfo() // x86-64-v2 - if (allowHWIntrinsic && g_pConfig->EnableHWIntrinsic()) + if (g_pConfig->EnableHWIntrinsic()) { CPUCompileFlags.Set(InstructionSet_X86Base); } @@ -1333,7 +1332,7 @@ void EEJitManager::SetCpuInfo() #elif defined(TARGET_ARM64) CPUCompileFlags.Set(InstructionSet_VectorT128); - if (allowHWIntrinsic && g_pConfig->EnableHWIntrinsic()) + if (g_pConfig->EnableHWIntrinsic()) { CPUCompileFlags.Set(InstructionSet_ArmBase); CPUCompileFlags.Set(InstructionSet_AdvSimd); @@ -1417,7 +1416,7 @@ void EEJitManager::SetCpuInfo() g_arm64_atomics_present = true; } #elif defined(TARGET_RISCV64) - if (allowHWIntrinsic && g_pConfig->EnableHWIntrinsic()) + if (g_pConfig->EnableHWIntrinsic()) { CPUCompileFlags.Set(InstructionSet_RiscV64Base); }