Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@
"Castclass",
"Conv",
"cref",
"Diagnoser",
"Dmark",
"dont",
"Funcs",
"gotos",
"Hasher",
"idxs",
"iface",
"ifaces",
"ifthen",
Expand Down
2 changes: 1 addition & 1 deletion bm.bat
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
@echo off
dotnet run -c:Release -f:net9.0 --project test/FastExpressionCompiler.Benchmarks/FastExpressionCompiler.Benchmarks.csproj
dotnet run -c:Release -f:net10.0 --project test/FastExpressionCompiler.Benchmarks/FastExpressionCompiler.Benchmarks.csproj
2 changes: 1 addition & 1 deletion bt.bat
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
echo:
echo:## Running TESTS on the Latest Supported .NET...
echo:
dotnet run -p:DevMode=true -f:net9.0 -c:Release --project test/FastExpressionCompiler.TestsRunner/FastExpressionCompiler.TestsRunner.csproj
dotnet run -p:DevMode=true -f:net10.0 -c:Release --project test/FastExpressionCompiler.TestsRunner/FastExpressionCompiler.TestsRunner.csproj
if %ERRORLEVEL% neq 0 goto :error

echo:
Expand Down
2 changes: 1 addition & 1 deletion build.bat
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ dotnet run --no-build -f:net10.0 -c:Release --project test/FastExpressionCompile
if %ERRORLEVEL% neq 0 goto :error

echo:
echo:running on .NET 9.0 (Latest)
echo:running on .NET 9.0
dotnet run --no-build -f:net9.0 -c:Release --project test/FastExpressionCompiler.TestsRunner
if %ERRORLEVEL% neq 0 goto :error

Expand Down
2,577 changes: 1,446 additions & 1,131 deletions src/FastExpressionCompiler.LightExpression/FlatExpression.cs

Large diffs are not rendered by default.

119 changes: 113 additions & 6 deletions src/FastExpressionCompiler/ImTools.cs
Original file line number Diff line number Diff line change
Expand Up @@ -326,14 +326,18 @@ public interface ISize
/// <summary>Returns the size of the collection or container</summary>
int Size { get; }
}
/// <summary>Marker for collection or container holding 2 or items</summary>
public interface ISize2Plus : ISize { }
/// <summary>Marker for collection or container holding 1 or more items</summary>
public interface ISize1Plus : ISize { }
/// <summary>Marker for collection or container holding 2 or more items</summary>
public interface ISize2Plus : ISize1Plus { }
/// <summary>Marker for collection or container holding 4 or more items</summary>
public interface ISize4Plus : ISize2Plus { }
/// <summary>Marker for collection or container holding 8 or more items</summary>
public interface ISize8Plus : ISize4Plus { }
/// <summary>Marker for collection or container holding 16 or more items</summary>
public interface ISize16Plus : ISize8Plus { }
/// <summary>Marker for collection or container holding 32 or more items</summary>
public interface ISize32Plus : ISize16Plus { }

/// <summary>Marker for collection or container holding 0 items</summary>
public struct Size0 : ISize
Expand All @@ -342,7 +346,14 @@ public struct Size0 : ISize
public int Size => 0;
}

/// <summary>Marker for collection or container holding 4 items</summary>
/// <summary>Marker for collection or container holding 1 item</summary>
public struct Size1 : ISize1Plus
{
/// <inheritdoc/>
public int Size => 1;
}

/// <summary>Marker for collection or container holding 2 items</summary>
public struct Size2 : ISize2Plus
{
/// <inheritdoc/>
Expand All @@ -366,6 +377,13 @@ public struct Size16 : ISize16Plus
/// <inheritdoc/>
public int Size => 16;
}
/// <summary>Marker for collection or container holding 32 items</summary>
public struct Size32 : ISize32Plus
{
/// <inheritdoc/>
public int Size => 32;
}


/// <summary>Implementation of `IStack` for 2 items on stack</summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
Expand Down Expand Up @@ -580,6 +598,86 @@ public ref T this[int index]
#endif
}

// todo: @perf create variant with Stack32
/// <summary>Implementation of `IStack` for 16 items on stack</summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct Stack32<T> : IStack<T, Size32, Stack32<T>>
{
/// <inheritdoc/>
public int Capacity => 32;
int IIndexed<T>.Count => Capacity;

internal T _it0, _it1, _it2, _it3, _it4, _it5, _it6, _it7;
internal T _it8, _it9, _it10, _it11, _it12, _it13, _it14, _it15;
internal T _it16, _it17, _it18, _it19, _it20, _it21, _it22, _it23;
internal T _it24, _it25, _it26, _it27, _it28, _it29, _it30, _it31;

/// <inheritdoc/>
[UnscopedRef]
[MethodImpl((MethodImplOptions)256)]
public ref T GetSurePresentRef(int index)
{
#if SUPPORTS_UNSAFE
return ref Unsafe.Add(ref _it0, index);
#else
switch (index)
{
case 0: return ref _it0;
case 1: return ref _it1;
case 2: return ref _it2;
case 3: return ref _it3;
case 4: return ref _it4;
case 5: return ref _it5;
case 6: return ref _it6;
case 7: return ref _it7;
case 8: return ref _it8;
case 9: return ref _it9;
case 10: return ref _it10;
case 11: return ref _it11;
case 12: return ref _it12;
case 13: return ref _it13;
case 14: return ref _it14;
case 15: return ref _it15;
case 16: return ref _it16;
case 17: return ref _it17;
case 18: return ref _it18;
case 19: return ref _it19;
case 20: return ref _it20;
case 21: return ref _it21;
case 22: return ref _it22;
case 23: return ref _it23;
case 24: return ref _it24;
case 25: return ref _it25;
case 26: return ref _it26;
case 27: return ref _it27;
case 28: return ref _it28;
case 29: return ref _it29;
case 30: return ref _it30;
default: return ref _it31;
}
#endif
}

/// <inheritdoc/>
[UnscopedRef]
public ref T this[int index]
{
[MethodImpl((MethodImplOptions)256)]
get
{
if (index >= 0 & index < Capacity)
return ref GetSurePresentRef(index);
return ref Stack.ThrowIndexOutOfBounds<T>(index, Capacity);
}
}

#if SUPPORTS_CREATE_SPAN
/// <inheritdoc/>
[MethodImpl((MethodImplOptions)256)]
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _it0, Capacity);
#endif
}

/// <summary>Abstraction over the small array pool to rent and return the arrays of small sizes, from 1 to N</summary>
public interface ISmallArrayPool<T>
{
Expand Down Expand Up @@ -799,12 +897,11 @@ public ref T GetSurePresentRef(int index)
Debug.Assert(_count != 0, "List should not be empty");
Debug.Assert(index >= 0 & index < _count, $"Index {index} should be less than Count {_count}");

var stackCap = Stack.Capacity;
if (index < stackCap)
if (index < Stack.Capacity)
return ref Stack.GetSurePresentRef(index);

Debug.Assert(Rest != null);
return ref Rest.GetSurePresentRef(index - stackCap);
return ref Rest.GetSurePresentRef(index - Stack.Capacity);
}

/// <summary>Returns surely present item by ref</summary>
Expand Down Expand Up @@ -838,6 +935,16 @@ public ref T AddDefaultAndGetRef()
return ref SmallList.AddDefaultAndGetRef(ref Rest, ref Pool, index - stackCap);
}

/// <summary>Adds the item to the end of the list aka the Stack.Push. Returns the ref to the added item.</summary>
[UnscopedRef]
[MethodImpl((MethodImplOptions)256)]
public ref T AddAndGetRef(in T item)
{
ref T r = ref AddDefaultAndGetRef();
r = item;
return ref r;
}

/// <summary>Adds the item to the end of the list aka the Stack.Push. Returns the index of the added item.</summary>
[MethodImpl((MethodImplOptions)256)]
public int Add(in T item)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks Condition="'$(DevMode)' != 'true'">net9.0;net8.0</TargetFrameworks>
<TargetFrameworks Condition="'$(DevMode)' == 'true'">net9.0</TargetFrameworks>
<TargetFrameworks Condition="'$(DevMode)' != 'true'">net10.0;net9.0;net8.0</TargetFrameworks>
<TargetFrameworks Condition="'$(DevMode)' == 'true'">net10.0</TargetFrameworks>

<OutputType>Exe</OutputType>
<IsTestProject>false</IsTestProject>
Expand All @@ -17,8 +17,8 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="0.15.0"/>
<PackageReference Include="BenchmarkDotNet.Diagnostics.Windows" Version="0.15.0" />
<PackageReference Include="BenchmarkDotNet" Version="0.15.8"/>
<PackageReference Include="BenchmarkDotNet.Diagnostics.Windows" Version="0.15.8" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,17 @@

namespace FastExpressionCompiler.Benchmarks
{
/*
.NET SDK 10.0.400
[Host] : .NET 10.0.11 (10.0.11, 10.0.1126.37416), X64 RyuJIT x86-64-v3
DefaultJob : .NET 10.0.11 (10.0.11, 10.0.1126.37416), X64 RyuJIT x86-64-v3

| Method | Mean | Error | StdDev | Ratio | RatioSD | Rank | Gen0 | Allocated | Alloc Ratio |
|----------------------- |---------:|---------:|---------:|------:|--------:|-----:|-------:|----------:|------------:|
| Create_LightExpression | 175.0 ns | 3.29 ns | 4.17 ns | 1.00 | 0.03 | 1 | 0.0827 | 520 B | 1.00 |
| Create_FlatExpression | 525.5 ns | 10.47 ns | 12.86 ns | 3.00 | 0.10 | 2 | - | - | 0.00 |

*/
[MemoryDiagnoser, RankColumn, Orderer(BenchmarkDotNet.Order.SummaryOrderPolicy.FastestToSlowest)]
public class LightExprVsFlatExpr_Create_ComplexExpr
{
Expand Down
4 changes: 2 additions & 2 deletions test/FastExpressionCompiler.Benchmarks/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public static void Main()
// BenchmarkRunner.Run<ManuallyComposedLambdaBenchmark.Create_and_Compile>(); // not included in README.md, may be it needs to

// BenchmarkRunner.Run<LightExprVsExpr_Create_ComplexExpr>();
// BenchmarkRunner.Run<LightExprVsFlatExpr_Create_ComplexExpr>();
BenchmarkRunner.Run<LightExprVsFlatExpr_Create_ComplexExpr>();
// BenchmarkRunner.Run<LightExprVsExpr_CreateAndCompile_ComplexExpr>();

//--------------------------------------------
Expand Down Expand Up @@ -54,7 +54,7 @@ public static void Main()
// BenchmarkRunner.Run<Issue489_Switch_BranchElimination.Compile>();
// BenchmarkRunner.Run<Issue489_Switch_BranchElimination.Invoke>();

BenchmarkRunner.Run<StackSearch>();
// BenchmarkRunner.Run<StackSearch>();
// BenchmarkRunner.Run<SmallList_Switch_vs_AsSpan_ByRef_Add>();
// BenchmarkRunner.Run<SmallList_Switch_vs_AsSpan_ByRef_Access>();
// BenchmarkRunner.Run<ArrayCopy_vs_ArrayResize_vs_ForLoop>();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks Condition="'$(DevMode)' != 'true'">net472;net6.0;net8.0;net9.0</TargetFrameworks>
<TargetFrameworks Condition="'$(DevMode)' == 'true'">net472;net9.0</TargetFrameworks>
<TargetFrameworks Condition="'$(DevMode)' != 'true'">net472;net6.0;net8.0;net9.0;net10.0</TargetFrameworks>
<TargetFrameworks Condition="'$(DevMode)' == 'true'">net472;net9.0;net10.0</TargetFrameworks>

<DefineConstants>LIGHT_EXPRESSION</DefineConstants>
</PropertyGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks Condition="'$(DevMode)' != 'true'">net472;net6.0;net8.0;net9.0</TargetFrameworks>
<TargetFrameworks Condition="'$(DevMode)' == 'true'">net472;net9.0</TargetFrameworks>
<DefineConstants>LIGHT_EXPRESSION</DefineConstants>
</PropertyGroup>
<ItemGroup>
<None Remove="*.ncrunchproject" />
<Compile Include="..\FastExpressionCompiler.UnitTests\**\*.cs" Exclude="..\FastExpressionCompiler.UnitTests\obj\**\*.*" />
</ItemGroup>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks Condition="'$(DevMode)' != 'true'">net472;net6.0;net8.0;net9.0;net10.0</TargetFrameworks>
<TargetFrameworks Condition="'$(DevMode)' == 'true'">net472;net9.0;net10.0</TargetFrameworks>

<DefineConstants>LIGHT_EXPRESSION</DefineConstants>
</PropertyGroup>

<ItemGroup>
<None Remove="*.ncrunchproject" />
<Compile Include="..\FastExpressionCompiler.UnitTests\**\*.cs" Exclude="..\FastExpressionCompiler.UnitTests\obj\**\*.*" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\src\FastExpressionCompiler.LightExpression\FastExpressionCompiler.LightExpression.csproj" />
</ItemGroup>
Expand All @@ -19,8 +19,8 @@
<Reference Include="Microsoft.CSharp" />
</ItemGroup>

<ItemGroup Condition="'$(TargetFramework)' == 'net8.0' OR '$(TargetFramework)' == 'net9.0'">
<PackageReference Include="CsCheck" Version="4.6.2" />
<ItemGroup Condition="'$(TargetFramework)' == 'net8.0' OR '$(TargetFramework)' == 'net9.0' OR '$(TargetFramework)' == 'net10.0'">
<PackageReference Include="CsCheck" Version="4.8.0" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ private static FastExpressionCompiler.LightExpression.Expression BuildLightInt(I
_ => throw new NotSupportedException(spec.GetType().Name)
};

private static int BuildFlatInt(ref ExprTree fe, IntSpec spec, int[] ints) =>
private static ushort BuildFlatInt(ref ExprTree fe, IntSpec spec, ushort[] ints) =>
spec switch
{
IntSpec.ParameterRef parameter => ints[parameter.Index],
Expand Down Expand Up @@ -86,7 +86,7 @@ private static FastExpressionCompiler.LightExpression.Expression BuildLightBool(
_ => throw new NotSupportedException(spec.GetType().Name)
};

private static int BuildFlatBool(ref ExprTree fe, BoolSpec spec, int[] ints) =>
private static ushort BuildFlatBool(ref ExprTree fe, BoolSpec spec, ushort[] ints) =>
spec switch
{
BoolSpec.Constant constant => fe.ConstantOf(constant.Value),
Expand Down Expand Up @@ -115,10 +115,10 @@ private static FastExpressionCompiler.LightExpression.Expression BuildLightBlock
return Block(locals, expressions);
}

private static int BuildFlatBlock(ref ExprTree fe, IntSpec.LetMany letMany, int[] ints)
private static ushort BuildFlatBlock(ref ExprTree fe, IntSpec.LetMany letMany, ushort[] ints)
{
var locals = new int[letMany.Values.Length];
var expressions = new int[letMany.Values.Length + 1];
var locals = new ushort[letMany.Values.Length];
var expressions = new ushort[letMany.Values.Length + 1];
for (var i = 0; i < locals.Length; ++i)
{
locals[i] = fe.Variable(typeof(int), $"v{i}");
Expand Down
Loading
Loading