From 21b68e2f6a1fae63d6b2558a8a3031055cfa1905 Mon Sep 17 00:00:00 2001 From: Katelyn Gadd Date: Wed, 22 May 2024 13:08:06 -0700 Subject: [PATCH 1/6] Add IsNullRef/NullRef intrinsics --- src/mono/mono/mini/interp/transform.c | 31 +++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/mono/mono/mini/interp/transform.c b/src/mono/mono/mini/interp/transform.c index db713f12bd930d..d76176ccf575cb 100644 --- a/src/mono/mono/mini/interp/transform.c +++ b/src/mono/mono/mini/interp/transform.c @@ -2252,7 +2252,38 @@ interp_handle_intrinsics (TransformData *td, MonoMethod *target_method, MonoClas #endif } else if (!strcmp (tm, "InitBlockUnaligned") || !strcmp (tm, "InitBlock")) { *op = MINT_INITBLK; + } else if (!strcmp (tm, "IsNullRef")) { + *op = MINT_CEQ0_I4; + } else if (!strcmp (tm, "NullRef")) { + *op = MINT_LDC_I4_0; + } + /* + } else if (!strcmp (tm, "Add")) { + MonoGenericContext *ctx = mono_method_get_context (target_method); + g_assert (ctx); + g_assert (ctx->method_inst); + g_assert (ctx->method_inst->type_argc == 1); + + // (ldarg 1) = (ldarg 1) mul (sizeof !!T) + MonoType *t = ctx->method_inst->type_argv [0]; + int align; + int esize = mono_type_size (t, &align); + interp_add_ins (td, MINT_MUL_I4_IMM); + interp_ins_set_sreg (td->last_ins, td->sp [1].var); + push_simple_type (td, STACK_TYPE_I4); + interp_ins_set_dreg (td->last_ins, td->sp [1].var); + td->ip += 4; + + // (ldarg 0) add (ldarg 1) + interp_add_ins (td, MINT_ADD_I4); + push_simple_type (td, STACK_TYPE_I4); + interp_ins_set_sregs2 (td->last_ins, td->sp [0].var, td->sp [1].var); + interp_ins_set_dreg (td->last_ins, td->sp [-1].var); + + return TRUE; } + */ + // FIXME: ReadUnaligned } else if (in_corlib && !strcmp (klass_name_space, "System.Runtime.CompilerServices") && !strcmp (klass_name, "RuntimeHelpers")) { if (!strcmp (tm, "get_OffsetToStringData")) { g_assert (csignature->param_count == 0); From f829d7cb9a85dc51ded9afd33506b37a3993855c Mon Sep 17 00:00:00 2001 From: Katelyn Gadd Date: Fri, 24 May 2024 10:46:35 -0700 Subject: [PATCH 2/6] Checkpoint --- src/mono/mono/mini/interp/transform.c | 49 +++++++++++++++++---------- 1 file changed, 31 insertions(+), 18 deletions(-) diff --git a/src/mono/mono/mini/interp/transform.c b/src/mono/mono/mini/interp/transform.c index d76176ccf575cb..4b3d44ed9065af 100644 --- a/src/mono/mono/mini/interp/transform.c +++ b/src/mono/mono/mini/interp/transform.c @@ -2253,37 +2253,50 @@ interp_handle_intrinsics (TransformData *td, MonoMethod *target_method, MonoClas } else if (!strcmp (tm, "InitBlockUnaligned") || !strcmp (tm, "InitBlock")) { *op = MINT_INITBLK; } else if (!strcmp (tm, "IsNullRef")) { +#if SIZEOF_VOID_P == 4 *op = MINT_CEQ0_I4; +#else + // FIXME: No CEQ0_I8 +#endif } else if (!strcmp (tm, "NullRef")) { +#if SIZEOF_VOID_P == 4 *op = MINT_LDC_I4_0; - } - /* - } else if (!strcmp (tm, "Add")) { +#else + *op = MINT_LDC_I8_0; +#endif + } /* else if (!strcmp (tm, "Add")) { MonoGenericContext *ctx = mono_method_get_context (target_method); g_assert (ctx); g_assert (ctx->method_inst); g_assert (ctx->method_inst->type_argc == 1); - - // (ldarg 1) = (ldarg 1) mul (sizeof !!T) MonoType *t = ctx->method_inst->type_argv [0]; - int align; - int esize = mono_type_size (t, &align); - interp_add_ins (td, MINT_MUL_I4_IMM); - interp_ins_set_sreg (td->last_ins, td->sp [1].var); - push_simple_type (td, STACK_TYPE_I4); - interp_ins_set_dreg (td->last_ins, td->sp [1].var); + + int base_var = td->sp[-2].var, + offset_var = td->sp[-1].var, + temp, align, esize; + + push_simple_type (td, STACK_TYPE_I); + temp = td->sp [-1].var; + td->sp -= 3; + + // temp = (ldarg 1) mul (sizeof !!T) + esize = mono_type_size (t, &align); + g_assert (esize <= 32767); + interp_add_ins (td, MINT_MUL_P_IMM); + td->last_ins->data[0] = (gint16)esize; + interp_ins_set_sreg (td->last_ins, offset_var); + interp_ins_set_dreg (td->last_ins, temp); td->ip += 4; - // (ldarg 0) add (ldarg 1) - interp_add_ins (td, MINT_ADD_I4); - push_simple_type (td, STACK_TYPE_I4); - interp_ins_set_sregs2 (td->last_ins, td->sp [0].var, td->sp [1].var); + // (ldarg 0) add temp + interp_add_ins (td, MINT_ADD_P); + interp_ins_set_sregs2 (td->last_ins, base_var, temp); + push_simple_type (td, STACK_TYPE_MP); interp_ins_set_dreg (td->last_ins, td->sp [-1].var); + td->ip += 4; return TRUE; - } - */ - // FIXME: ReadUnaligned + } */ } else if (in_corlib && !strcmp (klass_name_space, "System.Runtime.CompilerServices") && !strcmp (klass_name, "RuntimeHelpers")) { if (!strcmp (tm, "get_OffsetToStringData")) { g_assert (csignature->param_count == 0); From 71cf8427331034e90a194636ec89f0bcbc2372e7 Mon Sep 17 00:00:00 2001 From: Katelyn Gadd Date: Tue, 28 May 2024 12:35:44 -0700 Subject: [PATCH 3/6] Fix the add intrinsic --- src/mono/mono/mini/interp/transform.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/mono/mono/mini/interp/transform.c b/src/mono/mono/mini/interp/transform.c index 4b3d44ed9065af..00fde0f305b335 100644 --- a/src/mono/mono/mini/interp/transform.c +++ b/src/mono/mono/mini/interp/transform.c @@ -2264,7 +2264,7 @@ interp_handle_intrinsics (TransformData *td, MonoMethod *target_method, MonoClas #else *op = MINT_LDC_I8_0; #endif - } /* else if (!strcmp (tm, "Add")) { + } else if (!strcmp (tm, "Add")) { MonoGenericContext *ctx = mono_method_get_context (target_method); g_assert (ctx); g_assert (ctx->method_inst); @@ -2286,17 +2286,17 @@ interp_handle_intrinsics (TransformData *td, MonoMethod *target_method, MonoClas td->last_ins->data[0] = (gint16)esize; interp_ins_set_sreg (td->last_ins, offset_var); interp_ins_set_dreg (td->last_ins, temp); - td->ip += 4; // (ldarg 0) add temp interp_add_ins (td, MINT_ADD_P); interp_ins_set_sregs2 (td->last_ins, base_var, temp); push_simple_type (td, STACK_TYPE_MP); interp_ins_set_dreg (td->last_ins, td->sp [-1].var); - td->ip += 4; + + td->ip += 5; return TRUE; - } */ + } } else if (in_corlib && !strcmp (klass_name_space, "System.Runtime.CompilerServices") && !strcmp (klass_name, "RuntimeHelpers")) { if (!strcmp (tm, "get_OffsetToStringData")) { g_assert (csignature->param_count == 0); From ddd01beac80fb7d33d42e625c6a1699497c0c7f9 Mon Sep 17 00:00:00 2001 From: Vlad Brezae Date: Tue, 18 Jun 2024 13:17:58 +0300 Subject: [PATCH 4/6] Add conversion to I8 if offset is I4 --- src/mono/mono/mini/interp/transform.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/mono/mono/mini/interp/transform.c b/src/mono/mono/mini/interp/transform.c index 00fde0f305b335..c37b871dca5d78 100644 --- a/src/mono/mono/mini/interp/transform.c +++ b/src/mono/mono/mini/interp/transform.c @@ -2275,6 +2275,14 @@ interp_handle_intrinsics (TransformData *td, MonoMethod *target_method, MonoClas offset_var = td->sp[-1].var, temp, align, esize; +#if SIZEOF_VOID_P == 8 + if (td->sp [-1].type == STACK_TYPE_I4) { + interp_add_ins (td, MINT_CONV_I8_I4); + interp_ins_set_sreg (td->last_ins, offset_var); + interp_ins_set_dreg (td->last_ins, offset_var); + } +#endif + push_simple_type (td, STACK_TYPE_I); temp = td->sp [-1].var; td->sp -= 3; From a21eb463e33a15a36eb8d126c26069e1ebfa7889 Mon Sep 17 00:00:00 2001 From: Vlad Brezae Date: Tue, 18 Jun 2024 13:22:11 +0300 Subject: [PATCH 5/6] Small cleanup Don't allocate unnecessary temp var. Don't generate mul if type size is 1. --- src/mono/mono/mini/interp/transform.c | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/src/mono/mono/mini/interp/transform.c b/src/mono/mono/mini/interp/transform.c index c37b871dca5d78..49f97d62dee7d5 100644 --- a/src/mono/mono/mini/interp/transform.c +++ b/src/mono/mono/mini/interp/transform.c @@ -2271,9 +2271,9 @@ interp_handle_intrinsics (TransformData *td, MonoMethod *target_method, MonoClas g_assert (ctx->method_inst->type_argc == 1); MonoType *t = ctx->method_inst->type_argv [0]; - int base_var = td->sp[-2].var, - offset_var = td->sp[-1].var, - temp, align, esize; + int base_var = td->sp [-2].var, + offset_var = td->sp [-1].var, + align, esize; #if SIZEOF_VOID_P == 8 if (td->sp [-1].type == STACK_TYPE_I4) { @@ -2283,21 +2283,19 @@ interp_handle_intrinsics (TransformData *td, MonoMethod *target_method, MonoClas } #endif - push_simple_type (td, STACK_TYPE_I); - temp = td->sp [-1].var; - td->sp -= 3; + td->sp -= 2; - // temp = (ldarg 1) mul (sizeof !!T) esize = mono_type_size (t, &align); - g_assert (esize <= 32767); - interp_add_ins (td, MINT_MUL_P_IMM); - td->last_ins->data[0] = (gint16)esize; - interp_ins_set_sreg (td->last_ins, offset_var); - interp_ins_set_dreg (td->last_ins, temp); + if (esize != 1) { + g_assert (esize <= 32767); + interp_add_ins (td, MINT_MUL_P_IMM); + td->last_ins->data [0] = (gint16)esize; + interp_ins_set_sreg (td->last_ins, offset_var); + interp_ins_set_dreg (td->last_ins, offset_var); + } - // (ldarg 0) add temp interp_add_ins (td, MINT_ADD_P); - interp_ins_set_sregs2 (td->last_ins, base_var, temp); + interp_ins_set_sregs2 (td->last_ins, base_var, offset_var); push_simple_type (td, STACK_TYPE_MP); interp_ins_set_dreg (td->last_ins, td->sp [-1].var); From 1d360edc5b016308e73796c247857d81a1666876 Mon Sep 17 00:00:00 2001 From: Katelyn Gadd Date: Thu, 6 Jun 2024 15:30:10 -0700 Subject: [PATCH 6/6] Fix interp PGO WBT --- .../TestAppScenarios/InterpPgoTests.cs | 12 ++++++------ .../testassets/WasmBasicTestApp/App/InterpPgoTest.cs | 11 ++++++++--- .../testassets/WasmBasicTestApp/App/wwwroot/main.js | 6 ++---- 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/InterpPgoTests.cs b/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/InterpPgoTests.cs index 24e052f96d3fb4..e2719713b02ab6 100644 --- a/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/InterpPgoTests.cs +++ b/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/InterpPgoTests.cs @@ -28,9 +28,9 @@ public InterpPgoTests(ITestOutputHelper output, SharedBuildPerTestClassFixture b [InlineData("Release")] public async Task FirstRunGeneratesTableAndSecondRunLoadsIt(string config) { - // We need to invoke Greeting enough times to cause BCL code to tier so we can exercise interpreter PGO + // We need to invoke Random enough times to cause BCL code to tier so we can exercise interpreter PGO // Invoking it too many times makes the test meaningfully slower. - const int iterationCount = 70; + const int iterationCount = 50; _testOutput.WriteLine("/// Creating project"); CopyTestAsset("WasmBasicTestApp", "InterpPgoTest", "App"); @@ -61,13 +61,13 @@ public async Task FirstRunGeneratesTableAndSecondRunLoadsIt(string config) lock (runner.OutputLines) output = string.Join(Environment.NewLine, runner.OutputLines); - Assert.Contains("Hello, World!", output); + Assert.Contains("I filled a buffer with random items", output); // Verify that no PGO table was located in cache Assert.Contains("Failed to load interp_pgo table", output); // Verify that the table was saved after the app ran Assert.Contains("Saved interp_pgo table", output); // Verify that a specific method was tiered by the Greeting calls and recorded by PGO - Assert.Contains("added System.Runtime.CompilerServices.Unsafe:Add (byte&,int) to table", output); + Assert.Contains(" System.Random:Next () to table", output); } { @@ -81,7 +81,7 @@ public async Task FirstRunGeneratesTableAndSecondRunLoadsIt(string config) lock (runner.OutputLines) output = string.Join(Environment.NewLine, runner.OutputLines); - Assert.Contains("Hello, World!", output); + Assert.Contains("I filled a buffer with random items", output); // Verify that table data was loaded from cache // if this breaks, it could be caused by change in config which affects the config hash and the cache storage hash key Assert.Contains(" bytes of interp_pgo data (table size == ", output); @@ -90,7 +90,7 @@ public async Task FirstRunGeneratesTableAndSecondRunLoadsIt(string config) // Verify that method(s) were found in the table and eagerly tiered Assert.Contains("because it was in the interp_pgo table", output); // Verify that a specific method was tiered by the Greeting calls and recorded by PGO - Assert.Contains("added System.Runtime.CompilerServices.Unsafe:Add (byte&,int) to table", output); + Assert.Contains(" System.Random:Next () to table", output); } _testOutput.WriteLine("/// Done"); diff --git a/src/mono/wasm/testassets/WasmBasicTestApp/App/InterpPgoTest.cs b/src/mono/wasm/testassets/WasmBasicTestApp/App/InterpPgoTest.cs index 6d093133b3771c..07705d9f34f216 100644 --- a/src/mono/wasm/testassets/WasmBasicTestApp/App/InterpPgoTest.cs +++ b/src/mono/wasm/testassets/WasmBasicTestApp/App/InterpPgoTest.cs @@ -12,10 +12,15 @@ public partial class InterpPgoTest internal static partial string GetHRef(); [JSExport] - internal static string Greeting() + internal static void TryToTier(int iterationCount) { - var text = $"Hello, World! Greetings from {GetHRef()}"; + var buffer = new int[4096]; + var random = new Random(); + for (int i = 0; i < iterationCount; i++) { + for (int j = 0; j < buffer.Length; j++) + buffer[j] = random.Next(); + } + var text = $"Greetings from {GetHRef()}. I filled a buffer with random items {iterationCount} times."; Console.WriteLine(text); - return text; } } diff --git a/src/mono/wasm/testassets/WasmBasicTestApp/App/wwwroot/main.js b/src/mono/wasm/testassets/WasmBasicTestApp/App/wwwroot/main.js index 3c8e36199d25e8..21cc18cc3e7157 100644 --- a/src/mono/wasm/testassets/WasmBasicTestApp/App/wwwroot/main.js +++ b/src/mono/wasm/testassets/WasmBasicTestApp/App/wwwroot/main.js @@ -139,10 +139,8 @@ try { } } }); - const iterationCount = params.get("iterationCount") ?? 70; - for (let i = 0; i < iterationCount; i++) { - exports.InterpPgoTest.Greeting(); - }; + const iterationCount = params.get("iterationCount") ?? "70"; + exports.InterpPgoTest.TryToTier(parseInt(iterationCount)); await INTERNAL.interp_pgo_save_data(); exit(0); break;