From ecd849908573b4e659b017e2a0759dbe90c3c50b Mon Sep 17 00:00:00 2001 From: Ryan Lamansky <13633345+RyanLamansky@users.noreply.github.com> Date: Sat, 30 Jul 2022 10:27:36 -0500 Subject: [PATCH] BitOperations are now used for native performance of certain WASM instructions when the target framework supports it. --- .../Instructions/Int32CountLeadingZeroes.cs | 16 ++++++++++++++-- WebAssembly/Instructions/Int32CountOneBits.cs | 15 +++++++++++++-- .../Instructions/Int32CountTrailingZeroes.cs | 14 +++++++++++++- WebAssembly/Instructions/Int32RotateLeft.cs | 14 +++++++++++++- WebAssembly/Instructions/Int32RotateRight.cs | 14 +++++++++++++- .../Instructions/Int64CountLeadingZeroes.cs | 14 +++++++++++++- WebAssembly/Instructions/Int64CountOneBits.cs | 14 +++++++++++++- .../Instructions/Int64CountTrailingZeroes.cs | 14 +++++++++++++- WebAssembly/Instructions/Int64RotateLeft.cs | 15 ++++++++++++++- WebAssembly/Instructions/Int64RotateRight.cs | 15 ++++++++++++++- WebAssembly/Runtime/Compilation/HelperMethod.cs | 2 ++ 11 files changed, 135 insertions(+), 12 deletions(-) diff --git a/WebAssembly/Instructions/Int32CountLeadingZeroes.cs b/WebAssembly/Instructions/Int32CountLeadingZeroes.cs index 5652549..156b8c9 100644 --- a/WebAssembly/Instructions/Int32CountLeadingZeroes.cs +++ b/WebAssembly/Instructions/Int32CountLeadingZeroes.cs @@ -1,4 +1,8 @@ -using System.Reflection.Emit; +#if NETCOREAPP3_0_OR_GREATER +using System.Numerics; +using System.Reflection; +#endif +using System.Reflection.Emit; using WebAssembly.Runtime.Compilation; namespace WebAssembly.Instructions; @@ -20,11 +24,18 @@ public Int32CountLeadingZeroes() { } +#if NETCOREAPP3_0_OR_GREATER + private static readonly MethodInfo leadingZeroCount = typeof(BitOperations).GetMethod(nameof(BitOperations.LeadingZeroCount), new[] { typeof(uint) })!; +#endif + internal sealed override void Compile(CompilationContext context) { //Assuming validation passes, the remaining type will be Int32. context.ValidateStack(OpCode.Int32CountLeadingZeroes, WebAssemblyValueType.Int32); +#if NETCOREAPP3_0_OR_GREATER + context.Emit(OpCodes.Call, leadingZeroCount); +#else context.Emit(OpCodes.Call, context[HelperMethod.Int32CountLeadingZeroes, (helper, c) => { var result = context.CheckedExportsBuilder.DefineMethod( @@ -80,6 +91,7 @@ internal sealed override void Compile(CompilationContext context) return result; } - ]); + ]); +#endif } } diff --git a/WebAssembly/Instructions/Int32CountOneBits.cs b/WebAssembly/Instructions/Int32CountOneBits.cs index ad5a540..b85472b 100644 --- a/WebAssembly/Instructions/Int32CountOneBits.cs +++ b/WebAssembly/Instructions/Int32CountOneBits.cs @@ -1,4 +1,8 @@ -using System.Reflection.Emit; +#if NETCOREAPP3_0_OR_GREATER +using System.Numerics; +using System.Reflection; +#endif +using System.Reflection.Emit; using WebAssembly.Runtime.Compilation; namespace WebAssembly.Instructions; @@ -20,11 +24,18 @@ public Int32CountOneBits() { } +#if NETCOREAPP3_0_OR_GREATER + private static readonly MethodInfo popCount = typeof(BitOperations).GetMethod(nameof(BitOperations.PopCount), new[] { typeof(uint) })!; +#endif + internal sealed override void Compile(CompilationContext context) { //Assuming validation passes, the remaining type will be Int32. context.ValidateStack(OpCode.Int32CountOneBits, WebAssemblyValueType.Int32); +#if NETCOREAPP3_0_OR_GREATER + context.Emit(OpCodes.Call, popCount); +#else context.Emit(OpCodes.Call, context[HelperMethod.Int32CountOneBits, CreateHelper]); } @@ -71,7 +82,7 @@ internal static MethodBuilder CreateHelper(HelperMethod helper, CompilationConte il.Emit(OpCodes.Ldc_I4_S, 24); il.Emit(OpCodes.Shr_Un); il.Emit(OpCodes.Ret); - return result; +#endif } } diff --git a/WebAssembly/Instructions/Int32CountTrailingZeroes.cs b/WebAssembly/Instructions/Int32CountTrailingZeroes.cs index d52ed89..6de7232 100644 --- a/WebAssembly/Instructions/Int32CountTrailingZeroes.cs +++ b/WebAssembly/Instructions/Int32CountTrailingZeroes.cs @@ -1,4 +1,8 @@ -using System.Reflection.Emit; +#if NETCOREAPP3_0_OR_GREATER +using System.Numerics; +using System.Reflection; +#endif +using System.Reflection.Emit; using WebAssembly.Runtime.Compilation; namespace WebAssembly.Instructions; @@ -20,11 +24,18 @@ public Int32CountTrailingZeroes() { } +#if NETCOREAPP3_0_OR_GREATER + private static readonly MethodInfo trailingZeroCount = typeof(BitOperations).GetMethod(nameof(BitOperations.TrailingZeroCount), new[] { typeof(uint) })!; +#endif + internal sealed override void Compile(CompilationContext context) { //Assuming validation passes, the remaining type will be this. context.ValidateStack(OpCode.Int32CountTrailingZeroes, WebAssemblyValueType.Int32); +#if NETCOREAPP3_0_OR_GREATER + context.Emit(OpCodes.Call, trailingZeroCount); +#else context.Emit(OpCodes.Call, context[HelperMethod.Int32CountTrailingZeroes, (helper, c) => { var result = context.CheckedExportsBuilder.DefineMethod( @@ -49,5 +60,6 @@ internal sealed override void Compile(CompilationContext context) return result; } ]); +#endif } } diff --git a/WebAssembly/Instructions/Int32RotateLeft.cs b/WebAssembly/Instructions/Int32RotateLeft.cs index 5098b94..04f8d81 100644 --- a/WebAssembly/Instructions/Int32RotateLeft.cs +++ b/WebAssembly/Instructions/Int32RotateLeft.cs @@ -1,4 +1,8 @@ -using System.Reflection.Emit; +#if NETCOREAPP3_0_OR_GREATER +using System.Numerics; +using System.Reflection; +#endif +using System.Reflection.Emit; using WebAssembly.Runtime.Compilation; namespace WebAssembly.Instructions; @@ -20,6 +24,10 @@ public Int32RotateLeft() { } +#if NETCOREAPP3_0_OR_GREATER + private static readonly MethodInfo rotateLeft = typeof(BitOperations).GetMethod(nameof(BitOperations.RotateLeft), new[] { typeof(uint), typeof(int) })!; +#endif + internal sealed override void Compile(CompilationContext context) { var stack = context.Stack; @@ -27,6 +35,9 @@ internal sealed override void Compile(CompilationContext context) context.PopStackNoReturn(OpCode.Int32RotateLeft, WebAssemblyValueType.Int32, WebAssemblyValueType.Int32); stack.Push(WebAssemblyValueType.Int32); +#if NETCOREAPP3_0_OR_GREATER + context.Emit(OpCodes.Call, rotateLeft); +#else context.Emit(OpCodes.Call, context[HelperMethod.Int32RotateLeft, (helper, c) => { var builder = c.CheckedExportsBuilder.DefineMethod( @@ -60,5 +71,6 @@ internal sealed override void Compile(CompilationContext context) return builder; } ]); +#endif } } diff --git a/WebAssembly/Instructions/Int32RotateRight.cs b/WebAssembly/Instructions/Int32RotateRight.cs index 976d2f6..7284da5 100644 --- a/WebAssembly/Instructions/Int32RotateRight.cs +++ b/WebAssembly/Instructions/Int32RotateRight.cs @@ -1,4 +1,8 @@ -using System.Reflection.Emit; +#if NETCOREAPP3_0_OR_GREATER +using System.Numerics; +using System.Reflection; +#endif +using System.Reflection.Emit; using WebAssembly.Runtime.Compilation; namespace WebAssembly.Instructions; @@ -20,6 +24,10 @@ public Int32RotateRight() { } +#if NETCOREAPP3_0_OR_GREATER + private static readonly MethodInfo rotateRight = typeof(BitOperations).GetMethod(nameof(BitOperations.RotateRight), new[] { typeof(uint), typeof(int) })!; +#endif + internal sealed override void Compile(CompilationContext context) { var stack = context.Stack; @@ -27,6 +35,9 @@ internal sealed override void Compile(CompilationContext context) context.PopStackNoReturn(OpCode.Int32RotateRight, WebAssemblyValueType.Int32, WebAssemblyValueType.Int32); stack.Push(WebAssemblyValueType.Int32); +#if NETCOREAPP3_0_OR_GREATER + context.Emit(OpCodes.Call, rotateRight); +#else context.Emit(OpCodes.Call, context[HelperMethod.Int32RotateRight, (helper, c) => { var builder = c.CheckedExportsBuilder.DefineMethod( @@ -60,5 +71,6 @@ internal sealed override void Compile(CompilationContext context) return builder; } ]); +#endif } } diff --git a/WebAssembly/Instructions/Int64CountLeadingZeroes.cs b/WebAssembly/Instructions/Int64CountLeadingZeroes.cs index cc4d08f..2513162 100644 --- a/WebAssembly/Instructions/Int64CountLeadingZeroes.cs +++ b/WebAssembly/Instructions/Int64CountLeadingZeroes.cs @@ -1,4 +1,8 @@ -using System.Reflection.Emit; +#if NETCOREAPP3_0_OR_GREATER +using System.Numerics; +using System.Reflection; +#endif +using System.Reflection.Emit; using WebAssembly.Runtime.Compilation; namespace WebAssembly.Instructions; @@ -20,11 +24,18 @@ public Int64CountLeadingZeroes() { } +#if NETCOREAPP3_0_OR_GREATER + private static readonly MethodInfo leadingZeroCount = typeof(BitOperations).GetMethod(nameof(BitOperations.LeadingZeroCount), new[] { typeof(ulong) })!; +#endif + internal sealed override void Compile(CompilationContext context) { //Assuming validation passes, the remaining type will be Int64. context.ValidateStack(OpCode.Int64CountLeadingZeroes, WebAssemblyValueType.Int64); +#if NETCOREAPP3_0_OR_GREATER + context.Emit(OpCodes.Call, leadingZeroCount); +#else context.Emit(OpCodes.Call, context[HelperMethod.Int64CountLeadingZeroes, (helper, c) => { var result = context.CheckedExportsBuilder.DefineMethod( @@ -89,5 +100,6 @@ internal sealed override void Compile(CompilationContext context) return result; } ]); +#endif } } diff --git a/WebAssembly/Instructions/Int64CountOneBits.cs b/WebAssembly/Instructions/Int64CountOneBits.cs index b0d1443..4807986 100644 --- a/WebAssembly/Instructions/Int64CountOneBits.cs +++ b/WebAssembly/Instructions/Int64CountOneBits.cs @@ -1,4 +1,8 @@ -using System.Reflection.Emit; +#if NETCOREAPP3_0_OR_GREATER +using System.Numerics; +using System.Reflection; +#endif +using System.Reflection.Emit; using WebAssembly.Runtime.Compilation; namespace WebAssembly.Instructions; @@ -20,11 +24,18 @@ public Int64CountOneBits() { } +#if NETCOREAPP3_0_OR_GREATER + private static readonly MethodInfo popCount = typeof(BitOperations).GetMethod(nameof(BitOperations.PopCount), new[] { typeof(ulong) })!; +#endif + internal sealed override void Compile(CompilationContext context) { //Assuming validation passes, the remaining type will be Int64. context.ValidateStack(OpCode.Int64CountOneBits, WebAssemblyValueType.Int64); +#if NETCOREAPP3_0_OR_GREATER + context.Emit(OpCodes.Call, popCount); +#else context.Emit(OpCodes.Call, context[HelperMethod.Int64CountOneBits, CreateHelper]); } @@ -73,5 +84,6 @@ internal static MethodBuilder CreateHelper(HelperMethod helper, CompilationConte il.Emit(OpCodes.Ret); return result; +#endif } } diff --git a/WebAssembly/Instructions/Int64CountTrailingZeroes.cs b/WebAssembly/Instructions/Int64CountTrailingZeroes.cs index d54ab9d..6a1f5fc 100644 --- a/WebAssembly/Instructions/Int64CountTrailingZeroes.cs +++ b/WebAssembly/Instructions/Int64CountTrailingZeroes.cs @@ -1,4 +1,8 @@ -using System.Reflection.Emit; +#if NETCOREAPP3_0_OR_GREATER +using System.Numerics; +using System.Reflection; +#endif +using System.Reflection.Emit; using WebAssembly.Runtime.Compilation; namespace WebAssembly.Instructions; @@ -20,11 +24,18 @@ public Int64CountTrailingZeroes() { } +#if NETCOREAPP3_0_OR_GREATER + private static readonly MethodInfo trailingZeroCount = typeof(BitOperations).GetMethod(nameof(BitOperations.TrailingZeroCount), new[] { typeof(ulong) })!; +#endif + internal sealed override void Compile(CompilationContext context) { //Assuming validation passes, the remaining type will be Int64. context.ValidateStack(OpCode.Int64CountTrailingZeroes, WebAssemblyValueType.Int64); +#if NETCOREAPP3_0_OR_GREATER + context.Emit(OpCodes.Call, trailingZeroCount); +#else context.Emit(OpCodes.Call, context[HelperMethod.Int64CountTrailingZeroes, (helper, c) => { var result = context.CheckedExportsBuilder.DefineMethod( @@ -50,5 +61,6 @@ internal sealed override void Compile(CompilationContext context) return result; } ]); +#endif } } diff --git a/WebAssembly/Instructions/Int64RotateLeft.cs b/WebAssembly/Instructions/Int64RotateLeft.cs index eb416d5..f4d6ca9 100644 --- a/WebAssembly/Instructions/Int64RotateLeft.cs +++ b/WebAssembly/Instructions/Int64RotateLeft.cs @@ -1,4 +1,8 @@ -using System.Reflection.Emit; +#if NETCOREAPP3_0_OR_GREATER +using System.Numerics; +using System.Reflection; +#endif +using System.Reflection.Emit; using WebAssembly.Runtime.Compilation; namespace WebAssembly.Instructions; @@ -20,6 +24,10 @@ public Int64RotateLeft() { } +#if NETCOREAPP3_0_OR_GREATER + private static readonly MethodInfo rotateLeft = typeof(BitOperations).GetMethod(nameof(BitOperations.RotateLeft), new[] { typeof(ulong), typeof(int) })!; +#endif + internal sealed override void Compile(CompilationContext context) { var stack = context.Stack; @@ -27,6 +35,10 @@ internal sealed override void Compile(CompilationContext context) context.PopStackNoReturn(OpCode.Int64RotateLeft, WebAssemblyValueType.Int64, WebAssemblyValueType.Int64); stack.Push(WebAssemblyValueType.Int64); +#if NETCOREAPP3_0_OR_GREATER + context.Emit(OpCodes.Conv_I4); + context.Emit(OpCodes.Call, rotateLeft); +#else context.Emit(OpCodes.Call, context[HelperMethod.Int64RotateLeft, (helper, c) => { var builder = c.CheckedExportsBuilder.DefineMethod( @@ -62,5 +74,6 @@ internal sealed override void Compile(CompilationContext context) return builder; } ]); +#endif } } diff --git a/WebAssembly/Instructions/Int64RotateRight.cs b/WebAssembly/Instructions/Int64RotateRight.cs index 187bf83..642fec9 100644 --- a/WebAssembly/Instructions/Int64RotateRight.cs +++ b/WebAssembly/Instructions/Int64RotateRight.cs @@ -1,4 +1,8 @@ -using System.Reflection.Emit; +#if NETCOREAPP3_0_OR_GREATER +using System.Numerics; +using System.Reflection; +#endif +using System.Reflection.Emit; using WebAssembly.Runtime.Compilation; namespace WebAssembly.Instructions; @@ -20,6 +24,10 @@ public Int64RotateRight() { } +#if NETCOREAPP3_0_OR_GREATER + private static readonly MethodInfo rotateRight = typeof(BitOperations).GetMethod(nameof(BitOperations.RotateRight), new[] { typeof(ulong), typeof(int) })!; +#endif + internal sealed override void Compile(CompilationContext context) { var stack = context.Stack; @@ -27,6 +35,10 @@ internal sealed override void Compile(CompilationContext context) context.PopStackNoReturn(OpCode.Int64RotateRight, WebAssemblyValueType.Int64, WebAssemblyValueType.Int64); stack.Push(WebAssemblyValueType.Int64); +#if NETCOREAPP3_0_OR_GREATER + context.Emit(OpCodes.Conv_I4); + context.Emit(OpCodes.Call, rotateRight); +#else context.Emit(OpCodes.Call, context[HelperMethod.Int64RotateRight, (helper, c) => { var builder = c.CheckedExportsBuilder.DefineMethod( @@ -62,5 +74,6 @@ internal sealed override void Compile(CompilationContext context) return builder; } ]); +#endif } } diff --git a/WebAssembly/Runtime/Compilation/HelperMethod.cs b/WebAssembly/Runtime/Compilation/HelperMethod.cs index f7b5ce9..8aeab69 100644 --- a/WebAssembly/Runtime/Compilation/HelperMethod.cs +++ b/WebAssembly/Runtime/Compilation/HelperMethod.cs @@ -26,6 +26,7 @@ enum HelperMethod Float32CopySign, Float64CopySign, GrowMemory, +#if !NETCOREAPP3_0_OR_GREATER Int32CountOneBits, Int64CountOneBits, Int32CountLeadingZeroes, @@ -36,6 +37,7 @@ enum HelperMethod Int32RotateRight, Int64RotateLeft, Int64RotateRight, +#endif Int32TruncateSaturateFloat32Signed, Int32TruncateSaturateFloat32Unsigned, Int32TruncateSaturateFloat64Signed,