support running both with/without simd optionally with a (really horrible) shared codepath

This commit is contained in:
profan 2026-06-05 19:57:40 +01:00
parent 838887f06c
commit 0129200964
2 changed files with 249 additions and 28 deletions

View File

@ -32,7 +32,7 @@ void Main()
void main() void main()
{ {
float v = texture(texture0, fragTexCoord).r< 0 ? 1.0 : 0.0; float v = texture(texture0, fragTexCoord).r < 0 ? 1.0 : 0.0;
outputColor = vec4(v, v, v, 1.0f) * fragColor; outputColor = vec4(v, v, v, 1.0f) * fragColor;
} }
"""; """;
@ -63,6 +63,7 @@ void Main()
// options?? // options??
bool shouldUseParallelism = true; bool shouldUseParallelism = true;
bool shouldUseSimd = true;
bool isEvaluating = false; bool isEvaluating = false;
bool shouldEvaluate = false; bool shouldEvaluate = false;
@ -84,13 +85,23 @@ void Main()
{ {
isEvaluating = true; isEvaluating = true;
shouldUpdateTexture = true; shouldUpdateTexture = true;
InterpreterOptions interpreterOptions = (shouldUseParallelism ? InterpreterOptions.Parallelism : default); InterpreterOptions interpreterOptions = (shouldUseParallelism ? InterpreterOptions.Parallelism : default)
| (shouldUseSimd ? InterpreterOptions.Simd : default);
Task.Run(() => Task.Run(() =>
{ {
Instruction[] instructions = Parsing.Parse(programsProsperoVm); Instruction[] instructions = Parsing.Parse(programsProsperoVm);
currentOutputImageData.AsSpan()[..currentOutputImageData.Length].Clear(); currentOutputImageData.AsSpan()[..currentOutputImageData.Length].Clear();
Interpreter.Evaluate(instructions, imageSize: currentOutputImageSize, interpreterOptions, currentOutputImageData);
if ((interpreterOptions & InterpreterOptions.Simd) != 0)
{
Interpreter.Evaluate<Vector<float>>(instructions, imageSize: currentOutputImageSize, interpreterOptions, currentOutputImageData);
}
else
{
Interpreter.Evaluate<float>(instructions, imageSize: currentOutputImageSize, interpreterOptions, currentOutputImageData);
}
Raylib.UpdateTexture(currentOutputTexture, currentOutputImageData); Raylib.UpdateTexture(currentOutputTexture, currentOutputImageData);
shouldCancelUpdateTexture = true; shouldCancelUpdateTexture = true;
isEvaluating = false; isEvaluating = false;
@ -114,7 +125,7 @@ void Main()
Raylib.EndShaderMode(); Raylib.EndShaderMode();
Raylib.DrawText("Sharpero (press R to evaluate, O to output to file)", 12, 12, 20, Color.White); Raylib.DrawText("Sharpero (press R to evaluate, O to output to file)", 12, 12, 20, Color.White);
Raylib.DrawText($" - parallelism {(shouldUseParallelism ? "enabled" : "disabled")} (P to toggle)", 12, 32, 20, Color.White); Raylib.DrawText($" - parallelism {(shouldUseParallelism ? "enabled" : "disabled")} (P to toggle), simd {(shouldUseSimd ? "enabled" : "disabled")} (S to toggle)", 12, 32, 20, Color.White);
if (Raylib.IsKeyPressed(KeyboardKey.R)) if (Raylib.IsKeyPressed(KeyboardKey.R))
{ {
@ -134,6 +145,11 @@ void Main()
shouldUseParallelism = !shouldUseParallelism; shouldUseParallelism = !shouldUseParallelism;
} }
if (Raylib.IsKeyPressed(KeyboardKey.S))
{
shouldUseSimd = !shouldUseSimd;
}
Raylib.EndDrawing(); Raylib.EndDrawing();
} }
@ -151,7 +167,8 @@ float[] GenerateOutputImage(int currentImageSize, bool shouldWriteOutputImage =
(float[] result, double timeTakenSecondsEvaluate) = BenchmarkFunction(() => (float[] result, double timeTakenSecondsEvaluate) = BenchmarkFunction(() =>
{ {
Instruction[] instructions = Parsing.Parse(programsProsperoVm); Instruction[] instructions = Parsing.Parse(programsProsperoVm);
return Interpreter.Evaluate(instructions, imageSize: currentImageSize); InterpreterOptions interpreterOptions = InterpreterOptions.Parallelism | InterpreterOptions.Simd;
return Interpreter.Evaluate<Vector<float>>(instructions, imageSize: currentImageSize, interpreterOptions);
}); });
combinedOutputString += $" - took: {timeTakenSecondsEvaluate} seconds to evaluate the image!" + Environment.NewLine; combinedOutputString += $" - took: {timeTakenSecondsEvaluate} seconds to evaluate the image!" + Environment.NewLine;
@ -401,12 +418,31 @@ internal static class Parsing
[Flags] [Flags]
internal enum InterpreterOptions internal enum InterpreterOptions
{ {
Parallelism = 0x1 Parallelism = 0x1,
Simd = 0x2
} }
internal static class Interpreter internal static class Interpreter
{ {
public static float[] Evaluate(Instruction[] instructions, int imageSize, InterpreterOptions options = default, float[]? result = null) [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static T GetElement<T>(Span<float> values)
{
if (typeof(T) == typeof(float))
{
return (T)(object)values[0];
}
else if (typeof(T) == typeof(Vector<float>))
{
return (T)(object)new Vector<float>(values);
}
else
{
throw new InvalidOperationException();
}
}
public static float[] Evaluate<T>(Instruction[] instructions, int imageSize, InterpreterOptions options = default, float[]? result = null)
where T : unmanaged
{ {
result ??= new float[imageSize * imageSize]; result ??= new float[imageSize * imageSize];
@ -415,7 +451,7 @@ internal static class Interpreter
MaxDegreeOfParallelism = (options & InterpreterOptions.Parallelism) != 0 ? -1 : 1 MaxDegreeOfParallelism = (options & InterpreterOptions.Parallelism) != 0 ? -1 : 1
}; };
int chunkSize = Vector<float>.Count; int chunkSize = typeof(T) == typeof(Vector<float>) ? Vector<float>.Count : 1;
Parallel.For(0, (imageSize * imageSize) / chunkSize, parallelOptions, chunkIdx => Parallel.For(0, (imageSize * imageSize) / chunkSize, parallelOptions, chunkIdx =>
{ {
Span<float> xs = stackalloc float[chunkSize]; Span<float> xs = stackalloc float[chunkSize];
@ -433,24 +469,207 @@ internal static class Interpreter
(xs[idx], ys[idx]) = (vx, vy); (xs[idx], ys[idx]) = (vx, vy);
} }
Vector<float> results = Evaluate(instructions, new Vector<float>(xs), new Vector<float>(ys)); T results = Evaluate(instructions, GetElement<T>(xs), GetElement<T>(ys));
for (int idx = 0; idx < chunkSize; ++idx) for (int idx = 0; idx < chunkSize; ++idx)
{ {
int currentIdx = chunkIdx * chunkSize + idx; int currentIdx = chunkIdx * chunkSize + idx;
(int x, int y) = Parsing.IndexToCoord(currentIdx, width: imageSize); (int x, int y) = Parsing.IndexToCoord(currentIdx, width: imageSize);
result[Parsing.CoordToIndex(x, y, width: imageSize)] = results[idx];
result[Parsing.CoordToIndex(x, y, width: imageSize)] = Unsafe.Add(ref Unsafe.As<T, float>(ref results), idx);
} }
}); });
return result; return result;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static T Add<T>(T a, T b)
where T : unmanaged
{
if (typeof(T) == typeof(float))
{
return (T)(object)(Unsafe.As<T, float>(ref a) + Unsafe.As<T, float>(ref b));
}
else if (typeof(T) == typeof(Vector<float>))
{
return (T)(object)(Unsafe.As<T, Vector<float>>(ref a) + Unsafe.As<T, Vector<float>>(ref b));
}
else
{
throw new InvalidOperationException();
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static T Sub<T>(T a, T b)
where T : unmanaged
{
if (typeof(T) == typeof(float))
{
return (T)(object)(Unsafe.As<T, float>(ref a) - Unsafe.As<T, float>(ref b));
}
else if (typeof(T) == typeof(Vector<float>))
{
return (T)(object)(Unsafe.As<T, Vector<float>>(ref a) - Unsafe.As<T, Vector<float>>(ref b));
}
else
{
throw new InvalidOperationException();
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static T Mul<T>(T a, T b)
where T : unmanaged
{
if (typeof(T) == typeof(float))
{
return (T)(object)(Unsafe.As<T, float>(ref a) * Unsafe.As<T, float>(ref b));
}
else if (typeof(T) == typeof(Vector<float>))
{
return (T)(object)(Unsafe.As<T, Vector<float>>(ref a) * Unsafe.As<T, Vector<float>>(ref b));
}
else
{
throw new InvalidOperationException();
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static T Mul<T>(T a, float b)
where T : unmanaged
{
if (typeof(T) == typeof(float))
{
return (T)(object)(Unsafe.As<T, float>(ref a) * b);
}
else if (typeof(T) == typeof(Vector<float>))
{
return (T)(object)(Unsafe.As<T, Vector<float>>(ref a) * b);
}
else
{
throw new InvalidOperationException();
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static T Neg<T>(T v)
where T : unmanaged
{
if (typeof(T) == typeof(float))
{
return (T)(object)(-Unsafe.As<T, float>(ref v));
}
else if (typeof(T) == typeof(Vector<float>))
{
return (T)(object)(-Unsafe.As<T, Vector<float>>(ref v));
}
else
{
throw new InvalidOperationException();
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static T Max<T>(T a, T b)
where T : unmanaged
{
if (typeof(T) == typeof(float))
{
return (T)(object)Math.Max(Unsafe.As<T, float>(ref a), Unsafe.As<T, float>(ref b));
}
else if (typeof(T) == typeof(Vector<float>))
{
return (T)(object)Vector.Max(Unsafe.As<T, Vector<float>>(ref a), Unsafe.As<T, Vector<float>>(ref b));
}
else
{
throw new InvalidOperationException();
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static T Min<T>(T a, T b)
where T : unmanaged
{
if (typeof(T) == typeof(float))
{
return (T)(object)Math.Min(Unsafe.As<T, float>(ref a), Unsafe.As<T, float>(ref b));
}
else if (typeof(T) == typeof(Vector<float>))
{
return (T)(object)Vector.Min(Unsafe.As<T, Vector<float>>(ref a), Unsafe.As<T, Vector<float>>(ref b));
}
else
{
throw new InvalidOperationException();
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static T SquareRoot<T>(T v)
where T : unmanaged
{
if (typeof(T) == typeof(float))
{
return (T)(object)MathF.Sqrt(Unsafe.As<T, float>(ref v));
}
else if (typeof(T) == typeof(Vector<float>))
{
return (T)(object)Vector.SquareRoot(Unsafe.As<T, Vector<float>>(ref v));
}
else
{
throw new InvalidOperationException();
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static T EvaluateConstant<T>(float c)
where T : unmanaged
{
if (typeof(T) == typeof(float))
{
return (T)(object)c;
}
else if (typeof(T) == typeof(Vector<float>))
{
return (T)(object)new Vector<float>(c);
}
else
{
throw new InvalidOperationException();
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static T One<T>()
where T : unmanaged
{
if (typeof(T) == typeof(float))
{
return (T)(object)1.0f;
}
else if (typeof(T) == typeof(Vector<float>))
{
return (T)(object)Vector<float>.One;
}
else
{
throw new InvalidOperationException();
}
}
[SkipLocalsInit] [SkipLocalsInit]
public static Vector<float> Evaluate(Instruction[] instructions, Vector<float> xs, Vector<float> ys) public static T Evaluate<T>(Instruction[] instructions, T xs, T ys)
where T : unmanaged
{ {
// #TODO: this construction is just a little bit unhinged lol // #TODO: this construction is just a little bit unhinged lol
Span<Vector<float>> variables = stackalloc Vector<float>[instructions.Length]; Span<T> variables = stackalloc T[instructions.Length];
foreach (ref Instruction instruction in instructions.AsSpan()) foreach (ref Instruction instruction in instructions.AsSpan())
{ {
variables[instruction.Out] = instruction switch variables[instruction.Out] = instruction switch
@ -458,25 +677,25 @@ internal static class Interpreter
{ OpCode: OpCode.VarX } => xs, { OpCode: OpCode.VarX } => xs,
{ OpCode: OpCode.VarY } => ys, { OpCode: OpCode.VarY } => ys,
{ OpCode: OpCode.Add, A: { IsConstant: false } a, B: { IsConstant: false } b } => variables[a] + variables[b], { OpCode: OpCode.Add, A: { IsConstant: false } a, B: { IsConstant: false } b } => Add(variables[a], variables[b]),
{ OpCode: OpCode.Add, A.IsConstant: true, B: { IsConstant: false } b } => new Vector<float>(instruction.C) + variables[b], { OpCode: OpCode.Add, A.IsConstant: true, B: { IsConstant: false } b } => Add(EvaluateConstant<T>(instruction.C), variables[b]),
{ OpCode: OpCode.Add, A: { IsConstant: false } a, B.IsConstant: true } => variables[a] + new Vector<float>(instruction.C), { OpCode: OpCode.Add, A: { IsConstant: false } a, B.IsConstant: true } => Add(variables[a], EvaluateConstant<T>(instruction.C)),
{ OpCode: OpCode.Sub, A: { IsConstant: false } a, B: { IsConstant: false } b } => variables[a] - variables[b], { OpCode: OpCode.Sub, A: { IsConstant: false } a, B: { IsConstant: false } b } => Sub(variables[a], variables[b]),
{ OpCode: OpCode.Sub, A.IsConstant: true, B: { IsConstant: false } b } => new Vector<float>(instruction.C) - variables[b], { OpCode: OpCode.Sub, A.IsConstant: true, B: { IsConstant: false } b } => Sub(EvaluateConstant<T>(instruction.C), variables[b]),
{ OpCode: OpCode.Sub, A: { IsConstant: false } a, B.IsConstant: true } => variables[a] - new Vector<float>(instruction.C), { OpCode: OpCode.Sub, A: { IsConstant: false } a, B.IsConstant: true } => Sub(variables[a], EvaluateConstant<T>(instruction.C)),
{ OpCode: OpCode.Mul, A: { IsConstant: false } a, B: { IsConstant: false } b } => variables[a] * variables[b], { OpCode: OpCode.Mul, A: { IsConstant: false } a, B: { IsConstant: false } b } => Mul(variables[a], variables[b]),
{ OpCode: OpCode.Mul, A.IsConstant: true, B: { IsConstant: false } b } => new Vector<float>(instruction.C) * variables[b], { OpCode: OpCode.Mul, A.IsConstant: true, B: { IsConstant: false } b } => Mul(EvaluateConstant<T>(instruction.C), variables[b]),
{ OpCode: OpCode.Mul, A: { IsConstant: false } a, B.IsConstant: true } => variables[a] * new Vector<float>(instruction.C), { OpCode: OpCode.Mul, A: { IsConstant: false } a, B.IsConstant: true } => Mul(variables[a], EvaluateConstant<T>(instruction.C)),
{ OpCode: OpCode.Max, A: var a, B: var b } => Vector.Max(variables[a], variables[b]), { OpCode: OpCode.Max, A: var a, B: var b } => Max(variables[a], variables[b]),
{ OpCode: OpCode.Min, A: var a, B: var b } => Vector.Min(variables[a], variables[b]), { OpCode: OpCode.Min, A: var a, B: var b } => Min(variables[a], variables[b]),
{ OpCode: OpCode.Neg, A: var a } => -variables[a], { OpCode: OpCode.Neg, A: var a } => Neg(variables[a]),
{ OpCode: OpCode.Sqrt, A: var a } => Vector.SquareRoot(variables[a]), { OpCode: OpCode.Sqrt, A: var a } => SquareRoot(variables[a]),
{ OpCode: OpCode.Square, A: var a } => variables[a] * variables[a], { OpCode: OpCode.Square, A: var a } => Mul(variables[a], variables[a]),
{ OpCode: OpCode.Const, C: var v } => Vector<float>.One * v, { OpCode: OpCode.Const, C: var v } => Mul(One<T>(), v),
_ => variables[instruction.Out] _ => variables[instruction.Out]
}; };
} }

View File

@ -1,6 +1,8 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation"> <wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AArrayPool_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FSourcesCache_003Fc8beccd33913594a240a8bed807798632452943eba5864a26bfec56b2e617_003FArrayPool_002Ecs/@EntryIndexedValue">ForceIncluded</s:String> <s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AArrayPool_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FSourcesCache_003Fc8beccd33913594a240a8bed807798632452943eba5864a26bfec56b2e617_003FArrayPool_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AColor_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F6a9fabe8949749a5835bf490db09a4cc272a00_003F66_003F1010c222_003FColor_002Ecs/@EntryIndexedValue">ForceIncluded</s:String> <s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AColor_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F6a9fabe8949749a5835bf490db09a4cc272a00_003F66_003F1010c222_003FColor_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AIAdditionOperators_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FSourcesCache_003F8c272ae9f746341d3142ee8e616ec652d57d3bf8faa768267b7c048c9a9e7d8_003FIAdditionOperators_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AISimdVector_005F2_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FSourcesCache_003F4a7e82cbc39f2ce5352b03d8a8890a0dad9611ce64fbbba26f3e898898a6_003FISimdVector_005F2_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ANumber_002EParsing_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FSourcesCache_003Fde8a243f75215d958afa80cf80a41b4981a44efea7db93bffcdaf7bd6ba378c0_003FNumber_002EParsing_002Ecs/@EntryIndexedValue">ForceIncluded</s:String> <s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ANumber_002EParsing_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FSourcesCache_003Fde8a243f75215d958afa80cf80a41b4981a44efea7db93bffcdaf7bd6ba378c0_003FNumber_002EParsing_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AParallel_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FSourcesCache_003F1e8c32362ff486e4e342292ccce957781165d4f6305c795c1d6b1b473e4c0a3_003FParallel_002Ecs/@EntryIndexedValue">ForceIncluded</s:String> <s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AParallel_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FSourcesCache_003F1e8c32362ff486e4e342292ccce957781165d4f6305c795c1d6b1b473e4c0a3_003FParallel_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003APersistedAssemblyBuilder_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FSourcesCache_003F479daf628d169411ac8526d497865727d69e6e7f4832a1ba6e65e18abf4f90_003FPersistedAssemblyBuilder_002Ecs/@EntryIndexedValue">ForceIncluded</s:String> <s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003APersistedAssemblyBuilder_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FSourcesCache_003F479daf628d169411ac8526d497865727d69e6e7f4832a1ba6e65e18abf4f90_003FPersistedAssemblyBuilder_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>