i#1312 AVX-512 support: Separate [xfp]state/sigcontext sse/avx no. of registers internally. (#3731)

Adds the functions proc_num_simd_sse_avx_registers() and proc_num_simd_sse_avx_saved()
that replace proc_num_simd_registers() and proc_num_simd_saved() internally when they
are used to access fixed size structures like sigcontext, fpstate or xstate, i.e. the
structure sizes don't contiguously extend to AVX-512. The new functions need to be used
in favor of the existing ones, e.g. to access xmm and ymmh data of formerly mentioned
structures.

Adds the define MCXT_NUM_SIMD_SSE_AVX_SLOTS used in the same manner as described above.

This patch prepares DynamoRIO to switch the exported proc_num_simd_registers() to AVX-512
extended number of registers if there is feature support of the processor and OS.

Issue: #1312
This commit is contained in:
Hendrik Greving
2019-07-15 09:25:20 -07:00
committed by GitHub
parent 6ff52d9d17
commit e20fec8225
12 changed files with 126 additions and 47 deletions
+1 -1
View File
@@ -1766,7 +1766,7 @@ endif (CLIENT_INTERFACE OR APP_EXPORTS)
# Style checks:
find_package(vera++ QUIET)
if (vera++_FOUND)
if (0 AND vera++_FOUND)
message(STATUS "Using vera++ for code style checks")
include(${VERA++_USE_FILE})
# We use our own modified copy in order to pass --error and for
+14
View File
@@ -81,6 +81,20 @@ proc_num_simd_registers(void)
return num_simd_registers;
}
int
proc_num_simd_sse_avx_registers(void)
{
CLIENT_ASSERT(false, "Incorrect usage for ARM/AArch64.");
return 0;
}
int
proc_num_simd_sse_avx_saved(void)
{
CLIENT_ASSERT(false, "Incorrect usage for ARM/AArch64.");
return 0;
}
DR_API
size_t
proc_save_fpstate(byte *buf)
+2 -1
View File
@@ -66,7 +66,8 @@
# define YMM_ENABLED() (proc_avx_enabled())
# define ZMM_ENABLED() (proc_avx512_enabled())
# define YMMH_REG_SIZE (YMM_REG_SIZE / 2) /* upper half */
# define MCXT_YMMH_SLOTS_SIZE (MCXT_NUM_SIMD_SLOTS * YMMH_REG_SIZE)
# define MCXT_YMMH_SLOTS_SIZE (MCXT_NUM_SIMD_SSE_AVX_SLOTS * YMMH_REG_SIZE)
/* XXX i#1312: needs support for ZMM_HI256 and HI16_ZMM. */
#endif /* X86 */
/* Number of slots for spills from inlined clean calls. */
+14
View File
@@ -106,6 +106,20 @@ proc_num_simd_registers(void)
return num_simd_registers;
}
int
proc_num_simd_sse_avx_registers(void)
{
CLIENT_ASSERT(false, "Incorrect usage for ARM/AArch64.");
return 0;
}
int
proc_num_simd_sse_avx_saved(void)
{
CLIENT_ASSERT(false, "Incorrect usage for ARM/AArch64.");
return 0;
}
DR_API
size_t
proc_save_fpstate(byte *buf)
+24
View File
@@ -498,6 +498,30 @@ DR_API
int
proc_num_simd_registers(void);
/*
* This function is internal only.
*
* Returns the number of SIMD registers, but excluding AVX-512 extended registers. The
* function is only used internally. It shall be primarily used for xstate, fpstate,
* or sigcontext state access. For example, the xmm or ymmh fields are always of SSE or
* AVX size, while the extended AVX-512 register state is stored on top of that.
* proc_num_simd_registers() and proc_num_simd_saved() are not suitable to use in this
* case.
*/
int
proc_num_simd_sse_avx_registers(void);
/*
* This function is internal only.
*
* Returns the number of SIMD registers preserved for a context switch, but excluding
* AVX-512 extended registers. Its usage model is the same as
* proc_num_simd_sse_avx_registers(), but reflects the actual number of saved registers,
* the same way as proc_num_simd_saved() does.
*/
int
proc_num_simd_sse_avx_saved(void);
DR_API
/**
* Saves the floating point state into the buffer \p buf.
+23
View File
@@ -72,6 +72,8 @@ static bool avx512_enabled;
static int num_simd_saved;
static int num_simd_registers;
static int num_simd_sse_avx_registers;
static int num_simd_sse_avx_saved;
/* global writable variable for debug registers value */
DECLARE_NEVERPROT_VAR(app_pc d_r_debug_register[DEBUG_REGISTERS_NB], { 0 });
@@ -355,8 +357,17 @@ proc_init_arch(void)
(!proc_has_feature(FEATURE_FXSR) && !proc_has_feature(FEATURE_SSE)),
"Unsupported processor type: SSE and FXSR must match");
/* TODO i#1312: this will default to MCXT_NUM_SIMD_SSE_AVX_SLOTS and then be switched
* to MCXT_NUM_SIMD_SLOTS based on feature support in processor and OS in a future
* patch.
*/
num_simd_saved = MCXT_NUM_SIMD_SLOTS;
num_simd_registers = MCXT_NUM_SIMD_SLOTS;
/* Please note that this constant is not assigned based on feature support. It
* represents the xstate/fpstate/sigcontext structure sizes for non-AVX-512 state.
*/
num_simd_sse_avx_registers = MCXT_NUM_SIMD_SSE_AVX_SLOTS;
num_simd_sse_avx_saved = MCXT_NUM_SIMD_SSE_AVX_SLOTS;
if (proc_has_feature(FEATURE_OSXSAVE)) {
uint bv_high = 0, bv_low = 0;
@@ -455,6 +466,18 @@ proc_num_simd_registers(void)
return num_simd_registers;
}
int
proc_num_simd_sse_avx_registers(void)
{
return num_simd_sse_avx_registers;
}
int
proc_num_simd_sse_avx_saved(void)
{
return num_simd_sse_avx_saved;
}
DR_API
size_t
proc_save_fpstate(byte *buf)
+18 -19
View File
@@ -1899,29 +1899,28 @@ typedef union _dr_simd_t {
# endif
# ifdef X64
# ifdef WINDOWS
/*xmm0-5*/
# define MCXT_NUM_SIMD_SLOTS \
6 /**< Number of [xy]mm reg slots in dr_mcontext_t */
/**< Number of [xyz]mm0-5 reg slots in dr_mcontext_t pre AVX-512 in-use. */
# define MCXT_NUM_SIMD_SSE_AVX_SLOTS 6
/**< Number of [xyz]mm0-5 reg slots in dr_mcontext_t */
# define MCXT_NUM_SIMD_SLOTS 6
# else
/*xmm0-15*/
# define MCXT_NUM_SIMD_SLOTS \
16 /**< Number of [xy]mm reg slots in dr_mcontext_t \
*/
/**< Number of [xyz]mm-15 reg slots in dr_mcontext_t pre AVX-512 in-use. */
# define MCXT_NUM_SIMD_SSE_AVX_SLOTS 16
/**< Number of [xyz]mm0-31 reg slots in dr_mcontext_t */
# define MCXT_NUM_SIMD_SLOTS 16
# endif
# define PRE_XMM_PADDING \
48 /**< Bytes of padding before xmm/ymm dr_mcontext_t slots */
/**< Bytes of padding before simd dr_mcontext_t slots */
# define PRE_XMM_PADDING 48
# else
/*xmm0-7*/
# define MCXT_NUM_SIMD_SLOTS \
8 /**< Number of [xy]mm reg slots in dr_mcontext_t \
*/
# define PRE_XMM_PADDING \
24 /**< Bytes of padding before xmm/ymm dr_mcontext_t slots */
/**< Number of [xyz]mm0-7 reg slots in dr_mcontext_t pre AVX-512 in-use. */
# define MCXT_NUM_SIMD_SSE_AVX_SLOTS 8
/**< Number of [xyz]mm0-7 reg slots in dr_mcontext_t */
# define MCXT_NUM_SIMD_SLOTS 8
/**< Bytes of padding before simd dr_mcontext_t slots */
# define PRE_XMM_PADDING 24
# endif
# define MCXT_NUM_OPMASK_SLOTS \
8 /**< Number of 16-64-bit OpMask Kn slots in dr_mcontext_t, \
* if architecture supports. \
*/
/**< Number of 16-64-bit OpMask Kn slots in dr_mcontext_t, if architecture supports. */
# define MCXT_NUM_OPMASK_SLOTS 8
#else
# error NYI
#endif /* AARCHXX/X86 */
+10 -10
View File
@@ -219,7 +219,6 @@ save_xmm(dcontext_t *dcontext, sigframe_rt_t *frame)
asm volatile("xsave %0" : "=m"(*xstate));
#endif
}
/* XXX i#1312: this needs to get extended to AVX-512. */
if (YMM_ENABLED()) {
/* all ymm regs are in our mcontext. the only other thing
* in xstate is the xgetbv.
@@ -228,7 +227,7 @@ save_xmm(dcontext_t *dcontext, sigframe_rt_t *frame)
dr_xgetbv(&bv_high, &bv_low);
xstate->xstate_hdr.xstate_bv = (((uint64)bv_high) << 32) | bv_low;
}
for (i = 0; i < proc_num_simd_saved(); i++) {
for (i = 0; i < proc_num_simd_sse_avx_saved(); i++) {
/* we assume no padding */
#ifdef X64
/* __u32 xmm_space[64] */
@@ -250,6 +249,7 @@ save_xmm(dcontext_t *dcontext, sigframe_rt_t *frame)
}
#endif
}
/* XXX i#1312: AVX-512 extended register copies missing yet. */
}
/* We can't tell whether the app has used fpstate yet so we preserve every time
@@ -369,7 +369,6 @@ dump_fpstate(dcontext_t *dcontext, kernel_fpstate_t *fp)
LOG(THREAD, LOG_ASYNCH, 1, "\n");
}
# endif
/* XXX i#1312: this needs to get extended to AVX-512. */
/* Ignore padding. */
if (YMM_ENABLED()) {
kernel_xstate_t *xstate = (kernel_xstate_t *)fp;
@@ -381,7 +380,7 @@ dump_fpstate(dcontext_t *dcontext, kernel_fpstate_t *fp)
ASSERT(TEST(XCR0_AVX, fp->sw_reserved.xstate_bv));
LOG(THREAD, LOG_ASYNCH, 1, "\txstate_bv = 0x" HEX64_FORMAT_STRING "\n",
xstate->xstate_hdr.xstate_bv);
for (i = 0; i < proc_num_simd_registers(); i++) {
for (i = 0; i < proc_num_simd_sse_avx_registers(); i++) {
LOG(THREAD, LOG_ASYNCH, 1, "\tymmh%d = ", i);
for (j = 0; j < 4; j++) {
LOG(THREAD, LOG_ASYNCH, 1, "%04x ",
@@ -391,6 +390,7 @@ dump_fpstate(dcontext_t *dcontext, kernel_fpstate_t *fp)
}
}
}
/* XXX i#1312: Dumping AVX-512 extended registers missing yet. */
}
void
@@ -444,11 +444,10 @@ dump_sigcontext(dcontext_t *dcontext, sigcontext_t *sc)
void
sigcontext_to_mcontext_simd(priv_mcontext_t *mc, sig_full_cxt_t *sc_full)
{
/* XXX i#1312: this needs to get extended to AVX-512. */
sigcontext_t *sc = sc_full->sc;
if (sc->fpstate != NULL) {
int i;
for (i = 0; i < proc_num_simd_registers(); i++) {
for (i = 0; i < proc_num_simd_sse_avx_registers(); i++) {
memcpy(&mc->simd[i], &sc->fpstate->IF_X64_ELSE(xmm_space[i * 4], _xmm[i]),
XMM_REG_SIZE);
}
@@ -460,23 +459,23 @@ sigcontext_to_mcontext_simd(priv_mcontext_t *mc, sig_full_cxt_t *sc_full)
*/
ASSERT(sc->fpstate->sw_reserved.extended_size >= sizeof(*xstate));
ASSERT(TEST(XCR0_AVX, sc->fpstate->sw_reserved.xstate_bv));
for (i = 0; i < proc_num_simd_registers(); i++) {
for (i = 0; i < proc_num_simd_sse_avx_registers(); i++) {
memcpy(&mc->simd[i].u32[4], &xstate->ymmh.ymmh_space[i * 4],
YMMH_REG_SIZE);
}
}
}
}
/* XXX i#1312: AVX-512 extended register copies missing yet. */
}
void
mcontext_to_sigcontext_simd(sig_full_cxt_t *sc_full, priv_mcontext_t *mc)
{
/* XXX i#1312: this needs to get extended to AVX-512. */
sigcontext_t *sc = sc_full->sc;
if (sc->fpstate != NULL) {
int i;
for (i = 0; i < proc_num_simd_registers(); i++) {
for (i = 0; i < proc_num_simd_sse_avx_registers(); i++) {
memcpy(&sc->fpstate->IF_X64_ELSE(xmm_space[i * 4], _xmm[i]), &mc->simd[i],
XMM_REG_SIZE);
}
@@ -488,13 +487,14 @@ mcontext_to_sigcontext_simd(sig_full_cxt_t *sc_full, priv_mcontext_t *mc)
*/
ASSERT(sc->fpstate->sw_reserved.extended_size >= sizeof(*xstate));
ASSERT(TEST(XCR0_AVX, sc->fpstate->sw_reserved.xstate_bv));
for (i = 0; i < proc_num_simd_registers(); i++) {
for (i = 0; i < proc_num_simd_sse_avx_registers(); i++) {
memcpy(&xstate->ymmh.ymmh_space[i * 4], &mc->simd[i].u32[4],
YMMH_REG_SIZE);
}
}
}
}
/* XXX i#1312: AVX-512 extended register copies missing yet. */
}
size_t
+9 -6
View File
@@ -156,15 +156,16 @@ sigcontext_to_mcontext_simd(priv_mcontext_t *mc, sig_full_cxt_t *sc_full)
/* XXX i#1312: This assumption will change and the code below may need
* to take this into account.
*/
ASSERT(MCXT_NUM_SIMD_SLOTS == proc_num_simd_registers());
ASSERT(MCXT_NUM_SIMD_SLOTS == proc_num_simd_sse_avx_registers());
for (i = 0; i < proc_num_simd_registers(); i++) {
memcpy(&mc->simd[i], &sc->__fs.__fpu_xmm0 + i, XMM_REG_SIZE);
}
if (YMM_ENABLED()) {
for (i = 0; i < proc_num_simd_registers(); i++) {
for (i = 0; i < proc_num_simd_sse_avx_registers(); i++) {
memcpy(&mc->simd[i].u32[4], &sc->__fs.__fpu_ymmh0 + i, YMMH_REG_SIZE);
}
}
/* XXX i#1312: AVX-512 extended register copies missing yet. */
}
void
@@ -175,15 +176,16 @@ mcontext_to_sigcontext_simd(sig_full_cxt_t *sc_full, priv_mcontext_t *mc)
/* XXX i#1312: This assumption will change and the code below may need
* to take this into account.
*/
ASSERT(MCXT_NUM_SIMD_SLOTS == proc_num_simd_registers());
ASSERT(MCXT_NUM_SIMD_SLOTS == proc_num_simd_sse_avx_registers());
for (i = 0; i < proc_num_simd_registers(); i++) {
memcpy(&sc->__fs.__fpu_xmm0 + i, &mc->simd[i], XMM_REG_SIZE);
}
if (YMM_ENABLED()) {
for (i = 0; i < proc_num_simd_registers(); i++) {
for (i = 0; i < proc_num_simd_sse_avx_registers(); i++) {
memcpy(&sc->__fs.__fpu_ymmh0 + i, &mc->simd[i].u32[4], YMMH_REG_SIZE);
}
}
/* XXX i#1312: AVX-512 extended register copies missing yet. */
}
static void
@@ -209,7 +211,7 @@ dump_fpstate(dcontext_t *dcontext, sigcontext_t *sc)
LOG(THREAD, LOG_ASYNCH, 1, "\n");
}
/* XXX i#1312: this needs to get extended to AVX-512. */
for (i = 0; i < proc_num_simd_registers(); i++) {
for (i = 0; i < proc_num_simd_sse_avx_registers(); i++) {
LOG(THREAD, LOG_ASYNCH, 1, "\txmm%d = ", i);
for (j = 0; j < 4; j++) {
LOG(THREAD, LOG_ASYNCH, 1, "%08x ",
@@ -218,7 +220,7 @@ dump_fpstate(dcontext_t *dcontext, sigcontext_t *sc)
LOG(THREAD, LOG_ASYNCH, 1, "\n");
}
if (YMM_ENABLED()) {
for (i = 0; i < proc_num_simd_registers(); i++) {
for (i = 0; i < proc_num_simd_sse_avx_registers(); i++) {
LOG(THREAD, LOG_ASYNCH, 1, "\tymmh%d = ", i);
for (j = 0; j < 4; j++) {
LOG(THREAD, LOG_ASYNCH, 1, "%08x ",
@@ -227,6 +229,7 @@ dump_fpstate(dcontext_t *dcontext, sigcontext_t *sc)
LOG(THREAD, LOG_ASYNCH, 1, "\n");
}
}
/* XXX i#1312: AVX-512 extended register copies missing yet. */
}
void
+1 -1
View File
@@ -4726,7 +4726,7 @@ dump_context_info(CONTEXT *context, file_t file, bool all)
TESTALL(CONTEXT_XMM_FLAG, context->ContextFlags)) {
int i, j;
byte *ymmh_area;
for (i = 0; i < proc_num_simd_saved(); i++) {
for (i = 0; i < proc_num_simd_sse_avx_saved(); i++) {
LOG(file, LOG_ASYNCH, 2, "xmm%d=0x", i);
/* This would be simpler if we had uint64 fields in dr_xmm_t but
* that complicates our struct layouts */
+1 -3
View File
@@ -242,9 +242,7 @@ inject_into_thread(HANDLE phandle, CONTEXT *cxt, HANDLE thandle, char *dynamo_pa
int i, j;
/* For x86, ensure we have ExtendedRegisters space (i#1223) */
IF_NOT_X64(ASSERT(TEST(CONTEXT_XMM_FLAG, cxt->ContextFlags)));
/* XXX i#1312: This should be proc_num_simd_registers() which is part of
* the dynamorio lib.
*/
/* XXX i#1312: This should be proc_num_simd_sse_avx_registers(). */
ASSERT(MCXT_SIMD_SLOT_SIZE == ZMM_REG_SIZE);
for (i = 0; i < MCXT_NUM_SIMD_SLOTS; i++) {
for (j = 0; j < XMM_REG_SIZE / sizeof(*bufptr); j++) {
+9 -6
View File
@@ -1130,7 +1130,7 @@ context_to_mcontext_internal(priv_mcontext_t *mcontext, CONTEXT *cxt)
/* no harm done if no sse support */
/* CONTEXT_FLOATING_POINT or CONTEXT_EXTENDED_REGISTERS */
int i;
for (i = 0; i < proc_num_simd_registers(); i++)
for (i = 0; i < proc_num_simd_sse_avx_registers(); i++)
memcpy(&mcontext->simd[i], CXT_XMM(cxt, i), XMM_REG_SIZE);
}
/* if XSTATE is NOT set, the app has NOT used any ymm state and
@@ -1140,12 +1140,13 @@ context_to_mcontext_internal(priv_mcontext_t *mcontext, CONTEXT *cxt)
byte *ymmh_area = context_ymmh_saved_area(cxt);
if (ymmh_area != NULL) {
int i;
for (i = 0; i < proc_num_simd_registers(); i++) {
for (i = 0; i < proc_num_simd_sse_avx_registers(); i++) {
memcpy(&mcontext->simd[i].u32[4], &YMMH_AREA(ymmh_area, i).u32[0],
YMMH_REG_SIZE);
}
}
}
/* XXX i#1312: AVX-512 extended register copies missing yet. */
/* CONTEXT_CONTROL without the segments */
mcontext->xbp = cxt->CXT_XBP;
@@ -1231,11 +1232,11 @@ mcontext_to_context(CONTEXT *cxt, priv_mcontext_t *mcontext, bool set_cur_seg)
memcpy(&cxt->ExtendedRegisters, fpstate, written);
# endif
/* Now update w/ the xmm values from mcontext */
for (i = 0; i < proc_num_simd_registers(); i++)
for (i = 0; i < proc_num_simd_sse_avx_registers(); i++)
memcpy(CXT_XMM(cxt, i), &mcontext->simd[i], XMM_REG_SIZE);
}
/* XXX i#1312: This will need attention for AVX-512, specifically the different
* xstate formats supported by the processor, compacted and standard, as well as
/* XXX i#1312: This may need attention for AVX-512, specifically the different
* xstate formats supported by the kernel, compacted and standard, as well as
* MPX.
*/
if (CONTEXT_PRESERVE_YMM && TESTALL(CONTEXT_XSTATE, cxt->ContextFlags)) {
@@ -1265,10 +1266,11 @@ mcontext_to_context(CONTEXT *cxt, priv_mcontext_t *mcontext, bool set_cur_seg)
memcpy(&YMMH_AREA(ymmh_area, 6).u32[0], &ymms[0].u32[4], YMMH_REG_SIZE);
memcpy(&YMMH_AREA(ymmh_area, 7).u32[0], &ymms[1].u32[4], YMMH_REG_SIZE);
# endif
for (i = 0; i < proc_num_simd_registers(); i++) {
for (i = 0; i < proc_num_simd_sse_avx_registers(); i++) {
memcpy(&YMMH_AREA(ymmh_area, i).u32[0], &mcontext->simd[i].u32[4],
YMMH_REG_SIZE);
}
/* XXX i#1312: AVX-512 extended register copies missing yet. */
/* The only un-reserved part of the AVX header saved by OP_xsave is
* the XSTATE_BV byte.
*/
@@ -1276,6 +1278,7 @@ mcontext_to_context(CONTEXT *cxt, priv_mcontext_t *mcontext, bool set_cur_seg)
*header_bv = (((uint64)bv_high) << 32) | bv_low;
}
}
/* XXX i#1312: AVX-512 extended register copies missing yet. */
/* CONTEXT_CONTROL without the segments */
cxt->CXT_XBP = mcontext->xbp;
cxt->CXT_XSP = mcontext->xsp;