Controlled using MONO_HAVE_SIMD_REG_AVX define, disabled by default.
Co-authored-by: lateralusX <lateralusX@users.noreply.github.com>
#include <mono/utils/mono-logger-internals.h>
#include <mono/utils/mono-mmap.h>
#include <mono/utils/dtrace.h>
+#include <mono/utils/mono-context.h>
#include <mono/utils/w32subset.h>
#include "mini.h"
mono_setup_thread_context(DWORD thread_id, MonoContext *mono_context)
{
HANDLE handle;
- CONTEXT context;
+#if defined(MONO_HAVE_SIMD_REG_AVX) && HAVE_API_SUPPORT_WIN32_CONTEXT_XSTATE
+ BYTE context_buffer [2048];
+ DWORD context_buffer_len = G_N_ELEMENTS (context_buffer);
+ PCONTEXT context = NULL;
+ BOOL success = InitializeContext (context_buffer, CONTEXT_INTEGER | CONTEXT_FLOATING_POINT | CONTEXT_CONTROL | CONTEXT_XSTATE, &context, &context_buffer_len);
+ success &= SetXStateFeaturesMask (context, XSTATE_MASK_AVX);
+ g_assert (success == TRUE);
+#else
+ CONTEXT context_buffer;
+ PCONTEXT context = &context_buffer;
+ context->ContextFlags = CONTEXT_INTEGER | CONTEXT_FLOATING_POINT | CONTEXT_CONTROL;
+#endif
g_assert (thread_id != GetCurrentThreadId ());
handle = OpenThread (THREAD_ALL_ACCESS, FALSE, thread_id);
g_assert (handle);
- context.ContextFlags = CONTEXT_INTEGER | CONTEXT_FLOATING_POINT | CONTEXT_CONTROL;
-
- if (!GetThreadContext (handle, &context)) {
+ if (!GetThreadContext (handle, context)) {
CloseHandle (handle);
return FALSE;
}
memset (mono_context, 0, sizeof (MonoContext));
- mono_sigctx_to_monoctx (&context, mono_context);
+ mono_sigctx_to_monoctx (context, mono_context);
CloseHandle (handle);
return TRUE;
DWORD id = mono_thread_info_get_tid (info);
mono_setup_thread_context (id, &tctx->ctx);
} else {
+#ifdef ENABLE_CHECKED_BUILD
g_assert (((CONTEXT *)sigctx)->ContextFlags & CONTEXT_INTEGER);
g_assert (((CONTEXT *)sigctx)->ContextFlags & CONTEXT_CONTROL);
+ g_assert (((CONTEXT *)sigctx)->ContextFlags & CONTEXT_FLOATING_POINT);
+#if defined(MONO_HAVE_SIMD_REG_AVX) && HAVE_API_SUPPORT_WIN32_CONTEXT_XSTATE
+ DWORD64 features = 0;
+ g_assert (((CONTEXT *)sigctx)->ContextFlags & CONTEXT_XSTATE);
+ g_assert (GetXStateFeaturesMask (((CONTEXT *)sigctx), &features) == TRUE);
+ g_assert ((features & XSTATE_MASK_LEGACY_SSE) != 0);
+ g_assert ((features & XSTATE_MASK_AVX) != 0);
+#endif
+#endif
mono_sigctx_to_monoctx (sigctx, &tctx->ctx);
}
#ifdef HOST_WIN32
#include <windows.h>
+#include <mono/utils/w32subset.h>
#endif
void
mctx->gregs [AMD64_R13] = context->R13;
mctx->gregs [AMD64_R14] = context->R14;
mctx->gregs [AMD64_R15] = context->R15;
+
memcpy (&(mctx->fregs [AMD64_XMM0]), &(context->Xmm0), sizeof (MonoContextSimdReg));
memcpy (&(mctx->fregs [AMD64_XMM1]), &(context->Xmm1), sizeof (MonoContextSimdReg));
memcpy (&(mctx->fregs [AMD64_XMM2]), &(context->Xmm2), sizeof (MonoContextSimdReg));
memcpy (&(mctx->fregs [AMD64_XMM13]), &(context->Xmm13), sizeof (MonoContextSimdReg));
memcpy (&(mctx->fregs [AMD64_XMM14]), &(context->Xmm14), sizeof (MonoContextSimdReg));
memcpy (&(mctx->fregs [AMD64_XMM15]), &(context->Xmm15), sizeof (MonoContextSimdReg));
+
+#ifdef MONO_HAVE_SIMD_REG_AVX
+#if HAVE_API_SUPPORT_WIN32_CONTEXT_XSTATE
+ DWORD64 features = 0;
+ if (((context->ContextFlags & CONTEXT_XSTATE) != 0) && (GetXStateFeaturesMask (context, &features) == TRUE) && ((features & XSTATE_MASK_AVX) != 0)) {
+ DWORD feature_len = 0;
+ PM128A ymm = (PM128A)LocateXStateFeature (context, XSTATE_AVX, &feature_len);
+#ifdef ENABLE_CHECKED_BUILD
+ g_assert (ymm);
+ g_assert (feature_len == (sizeof (MonoContextSimdReg) * AMD64_XMM_NREG));
+#endif
+ memcpy (&(mctx->fregs [AMD64_XMM_NREG]), ymm, feature_len);
+ } else {
+ memset (&(mctx->fregs [AMD64_XMM_NREG]), 0, sizeof (MonoContextSimdReg) * AMD64_XMM_NREG);
+ }
+#else
+ memset (&(mctx->fregs [AMD64_XMM_NREG]), 0, sizeof (MonoContextSimdReg) * AMD64_XMM_NREG);
+#endif
+#endif
+
#elif defined(__HAIKU__)
// Haiku uses sigcontext because there's no ucontext
struct sigcontext *ctx = (struct sigcontext *)sigctx;
context->R13 = mctx->gregs [AMD64_R13];
context->R14 = mctx->gregs [AMD64_R14];
context->R15 = mctx->gregs [AMD64_R15];
+
+ // When using MONO_HAVE_SIMD_REG_AVX, Mono won't change YMM (read only), so no need to
+ // write extended context state.
memcpy (&(context->Xmm0), &(mctx->fregs [AMD64_XMM0]), sizeof (MonoContextSimdReg));
memcpy (&(context->Xmm1), &(mctx->fregs [AMD64_XMM1]), sizeof (MonoContextSimdReg));
memcpy (&(context->Xmm2), &(mctx->fregs [AMD64_XMM2]), sizeof (MonoContextSimdReg));
memcpy (&(context->Xmm13), &(mctx->fregs [AMD64_XMM13]), sizeof (MonoContextSimdReg));
memcpy (&(context->Xmm14), &(mctx->fregs [AMD64_XMM14]), sizeof (MonoContextSimdReg));
memcpy (&(context->Xmm15), &(mctx->fregs [AMD64_XMM15]), sizeof (MonoContextSimdReg));
+
#elif defined(__HAIKU__)
// Haiku uses sigcontext because there's no ucontext
struct sigcontext *ctx = (struct sigcontext *)sigctx;
typedef struct _libc_xmmreg MonoContextSimdReg;
#elif defined(HOST_WIN32)
#define MONO_HAVE_SIMD_REG
+//#define MONO_HAVE_SIMD_REG_AVX
#include <emmintrin.h>
typedef __m128d MonoContextSimdReg;
#elif defined(HOST_ANDROID)
typedef struct {
host_mgreg_t gregs [AMD64_NREG];
-#if defined(MONO_HAVE_SIMD_REG)
+#if defined(MONO_HAVE_SIMD_REG_AVX)
+ // Lower AMD64_XMM_NREG fregs holds lower 128 bit YMM. Upper AMD64_XMM_NREG fregs holds upper 128-bit YMM.
+ MonoContextSimdReg fregs [AMD64_XMM_NREG * 2];
+#elif defined(MONO_HAVE_SIMD_REG)
MonoContextSimdReg fregs [AMD64_XMM_NREG];
#else
double fregs [AMD64_XMM_NREG];
#define MONO_CONTEXT_GET_BP(ctx) ((gpointer)(gsize)((ctx)->gregs [AMD64_RBP]))
#define MONO_CONTEXT_GET_SP(ctx) ((gpointer)(gsize)((ctx)->gregs [AMD64_RSP]))
-#if defined (HOST_WIN32) && !defined(__GNUC__)
+#if defined(HOST_WIN32) && !defined(__GNUC__)
/* msvc doesn't support inline assembly, so have to use a separate .asm file */
// G_EXTERN_C due to being written in assembly.
+#if defined(MONO_HAVE_SIMD_REG_AVX) && defined(__AVX__)
+G_EXTERN_C void mono_context_get_current_avx (void *);
+#define MONO_CONTEXT_GET_CURRENT(ctx) \
+do { \
+ mono_context_get_current_avx((void*)&(ctx)); \
+} while (0)
+#elif defined(MONO_HAVE_SIMD_REG_AVX)
G_EXTERN_C void mono_context_get_current (void *);
-#define MONO_CONTEXT_GET_CURRENT(ctx) do { mono_context_get_current((void*)&(ctx)); } while (0)
+#define MONO_CONTEXT_GET_CURRENT(ctx) \
+do { \
+ mono_context_get_current((void*)&(ctx)); \
+ memset (&(ctx.fregs [AMD64_XMM_NREG]), 0, sizeof (MonoContextSimdReg) * AMD64_XMM_NREG); \
+} while (0)
+#else
+G_EXTERN_C void mono_context_get_current (void *);
+#define MONO_CONTEXT_GET_CURRENT(ctx) \
+do { \
+ mono_context_get_current((void*)&(ctx)); \
+} while (0)
+#endif
#else
#include <mono/utils/mono-threads-coop.h>
#include <mono/utils/mono-threads-debug.h>
#include <mono/utils/mono-os-wait.h>
-#include <limits.h>
+#include <mono/utils/mono-context.h>
#include <mono/utils/w32subset.h>
+#include <limits.h>
enum Win32APCInfo {
WIN32_APC_INFO_CLEARED = 0,
/* in mono's thread state machine implementation on Windows. By requesting a threads context after issuing a */
/* suspended request, this will wait until thread is suspended and thread context has been collected */
/* and returned. */
- CONTEXT context;
- context.ContextFlags = CONTEXT_INTEGER | CONTEXT_FLOATING_POINT | CONTEXT_CONTROL;
- if (!GetThreadContext (handle, &context)) {
+#if defined(MONO_HAVE_SIMD_REG_AVX) && HAVE_API_SUPPORT_WIN32_CONTEXT_XSTATE
+ BYTE context_buffer [2048];
+ DWORD context_buffer_len = G_N_ELEMENTS (context_buffer);
+ PCONTEXT context = NULL;
+ BOOL success = InitializeContext (context_buffer, CONTEXT_INTEGER | CONTEXT_FLOATING_POINT | CONTEXT_CONTROL | CONTEXT_XSTATE, &context, &context_buffer_len);
+ success &= SetXStateFeaturesMask (context, XSTATE_MASK_AVX);
+ g_assert (success == TRUE);
+#else
+ CONTEXT context_buffer;
+ PCONTEXT context = &context_buffer;
+ context->ContextFlags = CONTEXT_INTEGER | CONTEXT_FLOATING_POINT | CONTEXT_CONTROL;
+#endif
+ if (!GetThreadContext (handle, context)) {
result = ResumeThread (handle);
g_assert (result == 1);
if (!mono_threads_transition_abort_async_suspend (info)) {
//XXX interrupt_kernel doesn't make sense in this case as the target is not in a syscall
return TRUE;
}
- info->suspend_can_continue = mono_threads_get_runtime_callbacks ()->thread_state_init_from_handle (&info->thread_saved_state [ASYNC_SUSPEND_STATE_INDEX], info, &context);
+ info->suspend_can_continue = mono_threads_get_runtime_callbacks ()->thread_state_init_from_handle (&info->thread_saved_state [ASYNC_SUSPEND_STATE_INDEX], info, context);
THREADS_SUSPEND_DEBUG ("thread state %p -> %u\n", GUINT_TO_POINTER (id), result);
if (info->suspend_can_continue) {
if (interrupt_kernel)
info->async_target = NULL;
info->user_data = NULL;
+ // When using MONO_HAVE_SIMD_REG_AVX, Mono won't change YMM (read only), so no need to
+ // read extended context state.
context.ContextFlags = CONTEXT_INTEGER | CONTEXT_FLOATING_POINT | CONTEXT_CONTROL;
if (!GetThreadContext (handle, &context)) {
mono_monoctx_to_sigctx (&ctx, &context);
+ // When using MONO_HAVE_SIMD_REG_AVX, Mono won't change YMM (read only), so no need to
+ // write extended context state.
context.ContextFlags = CONTEXT_INTEGER | CONTEXT_FLOATING_POINT | CONTEXT_CONTROL;
res = SetThreadContext (handle, &context);
if (!res) {
mono_context_get_current endP
+PUBLIC mono_context_get_current_avx
+
+mono_context_get_current_avx PROC
+;rcx has the ctx ptr
+ mov [rcx + 00h], rax
+ mov [rcx + 08h], rcx
+ mov [rcx + 10h], rdx
+ mov [rcx + 18h], rbx
+ mov [rcx + 28h], rbp
+ mov [rcx + 30h], rsi
+ mov [rcx + 38h], rdi
+ mov [rcx + 40h], r8
+ mov [rcx + 48h], r9
+ mov [rcx + 50h], r10
+ mov [rcx + 58h], r11
+ mov [rcx + 60h], r12
+ mov [rcx + 68h], r13
+ mov [rcx + 70h], r14
+ mov [rcx + 78h], r15
+
+ lea rax, [rsp+8]
+ mov [rcx + 20h], rax
+
+ mov rax, qword ptr [rsp]
+ mov [rcx + 80h], rax
+
+ movaps xmmword ptr [rcx + 90h], xmm0
+ movaps xmmword ptr [rcx + 0A0h], xmm1
+ movaps xmmword ptr [rcx + 0B0h], xmm2
+ movaps xmmword ptr [rcx + 0C0h], xmm3
+ movaps xmmword ptr [rcx + 0D0h], xmm4
+ movaps xmmword ptr [rcx + 0E0h], xmm5
+ movaps xmmword ptr [rcx + 0F0h], xmm6
+ movaps xmmword ptr [rcx + 100h], xmm7
+ movaps xmmword ptr [rcx + 110h], xmm8
+ movaps xmmword ptr [rcx + 120h], xmm9
+ movaps xmmword ptr [rcx + 130h], xmm10
+ movaps xmmword ptr [rcx + 140h], xmm11
+ movaps xmmword ptr [rcx + 150h], xmm12
+ movaps xmmword ptr [rcx + 160h], xmm13
+ movaps xmmword ptr [rcx + 170h], xmm14
+ movaps xmmword ptr [rcx + 180h], xmm15
+
+ vextractf128 xmmword ptr [rcx + 190h],ymm0,1
+ vextractf128 xmmword ptr [rcx + 1A0h],ymm1,1
+ vextractf128 xmmword ptr [rcx + 1B0h],ymm2,1
+ vextractf128 xmmword ptr [rcx + 1C0h],ymm3,1
+ vextractf128 xmmword ptr [rcx + 1D0h],ymm4,1
+ vextractf128 xmmword ptr [rcx + 1E0h],ymm5,1
+ vextractf128 xmmword ptr [rcx + 1F0h],ymm6,1
+ vextractf128 xmmword ptr [rcx + 200h],ymm7,1
+ vextractf128 xmmword ptr [rcx + 210h],ymm8,1
+ vextractf128 xmmword ptr [rcx + 220h],ymm9,1
+ vextractf128 xmmword ptr [rcx + 230h],ymm10,1
+ vextractf128 xmmword ptr [rcx + 240h],ymm11,1
+ vextractf128 xmmword ptr [rcx + 250h],ymm12,1
+ vextractf128 xmmword ptr [rcx + 260h],ymm13,1
+ vextractf128 xmmword ptr [rcx + 270h],ymm14,1
+ vextractf128 xmmword ptr [rcx + 280h],ymm15,1
+
+ ret
+
+mono_context_get_current_avx endP
+
; Implementation of __builtin_unwind_init under MSVC, dumping
; nonvolatile registers into MonoBuiltinUnwindInfo *.