#include <sys/cdefs.h>
__RCSID("$NetBSD: sig_fpu.c,v 1.3 2026/07/15 02:08:18 riastradh Exp $");
#include "sig_fpu.h"
#include <sys/types.h>
#include <x86/cpu_extended_state.h>
#include <cpuid.h>
#include <inttypes.h>
#include <sched.h>
#include <signal.h>
#include <stdbool.h>
#include <stdio.h>
#include "h_macros.h"
#ifdef __x86_64__
# define NXMMREGS 16
# define NYMMREGS 16
# define NZMMREGS 32
#else
# define NXMMREGS 8
# define NYMMREGS 8
# define NZMMREGS 8
#endif
#define X87_CW_RC __BITS(11,10)
#define X87_CW_PC __BITS(9,8)
#define X87_CW_SW_EXC __BITS(5,0)
struct cpuid {
uint32_t edx;
uint32_t ecx;
uint32_t ebx;
uint32_t eax;
};
static struct cpuid
cpuid(uint32_t eax_fn, uint32_t ecx_idx)
{
struct cpuid c;
if (!__get_cpuid_count(eax_fn, ecx_idx,
&c.eax, &c.ebx, &c.ecx, &c.edx))
memset(&c, 0, sizeof(c));
return c;
}
__printflike(4,5)
__noinline
static void
hexdump(FILE *fp, const void *buf, size_t len, const char *title, ...)
{
va_list va;
const uint8_t *p = buf;
size_t i;
fprintf(fp, "# ");
va_start(va, title);
vfprintf(fp, title, va);
va_end(va);
fprintf(fp, "\n");
for (i = 0; i < len; i++) {
if ((i % 8) == 0)
fprintf(fp, " ");
fprintf(fp, " %02hhx", p[i]);
if ((i % 16) == 15)
fprintf(fp, "\n");
}
if (i % 16)
fprintf(fp, "\n");
}
bool
x87_supported(void)
{
#ifdef __x86_64__
return true;
#else
return cpuid(0x00000001, 0).edx & __BIT(0);
#endif
}
int
test_x87(volatile bool *ready, const volatile bool *done)
{
struct save87 s, s1;
uint32_t rcpc_exc;
int error = 0;
asm("wait\n"
" fnsave %0"
: "=m"(s));
arc4random_buf(s.s87_ac, sizeof(s.s87_ac));
rcpc_exc = arc4random() & (X87_CW_RC | X87_CW_PC | X87_CW_SW_EXC);
if (__SHIFTOUT(rcpc_exc, X87_CW_PC) == 1)
rcpc_exc |= __SHIFTIN(3, X87_CW_PC);
s.s87_cw &= ~(X87_CW_RC | X87_CW_PC | X87_CW_SW_EXC);
s.s87_cw |= rcpc_exc;
s.s87_sw &= ~X87_CW_SW_EXC;
s.s87_sw |= rcpc_exc & X87_CW_SW_EXC;
asm("\n"
" frstor %[s]\n"
" lock\n"
" orb $1,%[ready]\n"
"0: pause\n"
" cmpb $0,%[done]\n"
" lfence\n"
" je 0b\n"
" wait\n"
" fnsave %[s1]\n"
: [ready]"=m"(*ready), [s1]"=m"(s1)
: [done]"m"(*done), [s]"m"(s));
if (memcmp(s.s87_ac, s1.s87_ac, sizeof(s.s87_ac)) != 0) {
unsigned i;
for (i = 0; i < 8; i++) {
if (memcmp(&s.s87_ac[i], &s1.s87_ac[i],
sizeof(s.s87_ac[i])) == 0)
continue;
fprintf(stderr, "ST(%u)=0x%08x%016"PRIx64","
" expected 0x%08x%016"PRIx64"\n",
i,
s1.s87_ac[i].f87_exp_sign,
s1.s87_ac[i].f87_mantissa,
s.s87_ac[i].f87_exp_sign,
s.s87_ac[i].f87_mantissa);
error |= 1 << i;
}
}
if ((s1.s87_cw & (X87_CW_RC | X87_CW_PC | X87_CW_SW_EXC)) !=
(s.s87_cw & (X87_CW_RC | X87_CW_PC | X87_CW_SW_EXC))) {
fprintf(stderr, "cw=0x%04x, expected 0x%04x,"
" diff 0x%04x\n",
s1.s87_cw, s.s87_cw,
(uint32_t)((s1.s87_cw ^ s.s87_cw) &
(X87_CW_RC | X87_CW_PC | X87_CW_SW_EXC)));
error |= 1 << 8;
}
if ((s1.s87_sw & X87_CW_SW_EXC) !=
(s.s87_cw & X87_CW_SW_EXC)) {
fprintf(stderr, "sw=0x%04x, expected 0x%04x,"
" diff 0x%04x\n",
s1.s87_sw, s.s87_sw,
(uint32_t)((s1.s87_sw ^ s.s87_sw) &
X87_CW_SW_EXC));
error |= 1 << 9;
}
return error;
}
void
trash_x87(void)
{
struct save87 s;
uint32_t rcpc_exc;
asm("wait\n"
" fnsave %0"
: "=m"(s));
arc4random_buf(s.s87_ac, sizeof(s.s87_ac));
rcpc_exc = arc4random() & (X87_CW_RC | X87_CW_PC | X87_CW_SW_EXC);
s.s87_cw &= ~(X87_CW_RC | X87_CW_PC | X87_CW_SW_EXC);
s.s87_cw |= rcpc_exc;
s.s87_sw &= ~X87_CW_SW_EXC;
s.s87_sw |= rcpc_exc & X87_CW_SW_EXC;
asm volatile("frstor %0" :: "m"(s));
}
#define MXCSR_MISALIGNEDEXC __BIT(17)
#define MXCSR_FTZ __BIT(15)
#define MXCSR_RC __BITS(14,13)
#define MXCSR_EXCMASK __BITS(12,7)
#define MXCSR_DAZ __BIT(6)
#define MXCSR_EXCFLAG __BITS(5,0)
struct xmmregs {
struct {
uint8_t b[16];
} __aligned(16) xmm[NXMMREGS];
uint32_t mxcsr;
};
bool
xmm_supported(void)
{
#ifdef __x86_64__
return true;
#else
return cpuid(0x00000001, 0).edx & __BIT(25);
#endif
}
__attribute__((target("sse")))
int
test_xmm(volatile bool *ready, const volatile bool *done)
{
struct xmmregs before, after;
uint32_t exc;
unsigned i;
int error = 0;
arc4random_buf(before.xmm, sizeof(before.xmm));
before.mxcsr = arc4random() & (MXCSR_FTZ | MXCSR_RC | MXCSR_DAZ);
exc = arc4random() & 0x3f;
before.mxcsr |= __SHIFTIN(exc, MXCSR_EXCMASK);
before.mxcsr |= __SHIFTIN(exc, MXCSR_EXCFLAG);
asm("\n"
" ldmxcsr %[mxcsr_before]\n"
" movdqa 0*16(%[xmm_before]),%%xmm0\n"
" movdqa 1*16(%[xmm_before]),%%xmm1\n"
" movdqa 2*16(%[xmm_before]),%%xmm2\n"
" movdqa 3*16(%[xmm_before]),%%xmm3\n"
" movdqa 4*16(%[xmm_before]),%%xmm4\n"
" movdqa 5*16(%[xmm_before]),%%xmm5\n"
" movdqa 6*16(%[xmm_before]),%%xmm6\n"
" movdqa 7*16(%[xmm_before]),%%xmm7\n"
#ifdef __x86_64__
" movdqa 8*16(%[xmm_before]),%%xmm8\n"
" movdqa 9*16(%[xmm_before]),%%xmm9\n"
" movdqa 10*16(%[xmm_before]),%%xmm10\n"
" movdqa 11*16(%[xmm_before]),%%xmm11\n"
" movdqa 12*16(%[xmm_before]),%%xmm12\n"
" movdqa 13*16(%[xmm_before]),%%xmm13\n"
" movdqa 14*16(%[xmm_before]),%%xmm14\n"
" movdqa 15*16(%[xmm_before]),%%xmm15\n"
#endif
" lock\n"
" orb $1,%[ready]\n"
"0: pause\n"
" cmpb $0,%[done]\n"
" lfence\n"
" je 0b\n"
" movdqa %%xmm0,0*16(%[xmm_after])\n"
" movdqa %%xmm1,1*16(%[xmm_after])\n"
" movdqa %%xmm2,2*16(%[xmm_after])\n"
" movdqa %%xmm3,3*16(%[xmm_after])\n"
" movdqa %%xmm4,4*16(%[xmm_after])\n"
" movdqa %%xmm5,5*16(%[xmm_after])\n"
" movdqa %%xmm6,6*16(%[xmm_after])\n"
" movdqa %%xmm7,7*16(%[xmm_after])\n"
#ifdef __x86_64__
" movdqa %%xmm8,8*16(%[xmm_after])\n"
" movdqa %%xmm9,9*16(%[xmm_after])\n"
" movdqa %%xmm10,10*16(%[xmm_after])\n"
" movdqa %%xmm11,11*16(%[xmm_after])\n"
" movdqa %%xmm12,12*16(%[xmm_after])\n"
" movdqa %%xmm13,13*16(%[xmm_after])\n"
" movdqa %%xmm14,14*16(%[xmm_after])\n"
" movdqa %%xmm15,15*16(%[xmm_after])\n"
#endif
" stmxcsr %[mxcsr_after]\n"
: [ready]"=m"(*ready), "=m"(after.xmm),
[mxcsr_after]"=m"(after.mxcsr)
: [done]"m"(*done), "m"(before.xmm),
[mxcsr_before]"m"(before.mxcsr),
[xmm_before]"r"(&before.xmm), [xmm_after]"r"(&after.xmm)
: "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5",
"xmm6", "xmm7"
#ifdef __x86_64__
, "xmm8", "xmm9", "xmm10", "xmm11", "xmm12",
"xmm13", "xmm14", "xmm15"
#endif
);
for (i = 0; i < __arraycount(before.xmm); i++) {
if (memcmp(&before.xmm[i], &after.xmm[i],
sizeof(before.xmm[i]))) {
fprintf(stderr, "xmm%u clobbered\n", i);
hexdump(stderr, &before.xmm[i], sizeof(before.xmm[i]),
"before");
hexdump(stderr, &after.xmm[i], sizeof(after.xmm[i]),
"after");
error |= 1 << i;
}
}
if (before.mxcsr != after.mxcsr) {
fprintf(stderr, "mxcsr clobbered:"
" before=0x%08"PRIx32", after=0x%08"PRIx32"\n",
before.mxcsr, after.mxcsr);
error |= 1 << 16;
}
return error;
}
__attribute__((target("sse")))
void
trash_xmm(void)
{
struct xmmregs regs;
arc4random_buf(®s, sizeof(regs));
asm("\n"
" movdqa 0*16(%[xmm]),%%xmm0\n"
" movdqa 1*16(%[xmm]),%%xmm1\n"
" movdqa 2*16(%[xmm]),%%xmm2\n"
" movdqa 3*16(%[xmm]),%%xmm3\n"
" movdqa 4*16(%[xmm]),%%xmm4\n"
" movdqa 5*16(%[xmm]),%%xmm5\n"
" movdqa 6*16(%[xmm]),%%xmm6\n"
" movdqa 7*16(%[xmm]),%%xmm7\n"
#ifdef __x86_64__
" movdqa 8*16(%[xmm]),%%xmm8\n"
" movdqa 9*16(%[xmm]),%%xmm9\n"
" movdqa 10*16(%[xmm]),%%xmm10\n"
" movdqa 11*16(%[xmm]),%%xmm11\n"
" movdqa 12*16(%[xmm]),%%xmm12\n"
" movdqa 13*16(%[xmm]),%%xmm13\n"
" movdqa 14*16(%[xmm]),%%xmm14\n"
" movdqa 15*16(%[xmm]),%%xmm15\n"
#endif
:
: [xmm]"r"(regs.xmm), "m"(regs.xmm)
: "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5",
"xmm6", "xmm7"
#ifdef __x86_64__
, "xmm8", "xmm9", "xmm10", "xmm11", "xmm12",
"xmm13", "xmm14", "xmm15"
#endif
);
}
bool
ymm_supported(void)
{
return cpuid(0x00000001, 0).ecx & __BIT(28);
}
struct ymmregs {
struct {
uint8_t b[32];
} __aligned(32) ymm[NYMMREGS];
};
__attribute__((target("avx")))
int
test_ymm(volatile bool *ready, const volatile bool *done)
{
struct ymmregs before, after;
unsigned i;
int error = 0;
arc4random_buf(&before, sizeof(before));
asm("\n"
" vmovdqa 0*32(%[before_ymm]),%%ymm0\n"
" vmovdqa 1*32(%[before_ymm]),%%ymm1\n"
" vmovdqa 2*32(%[before_ymm]),%%ymm2\n"
" vmovdqa 3*32(%[before_ymm]),%%ymm3\n"
" vmovdqa 4*32(%[before_ymm]),%%ymm4\n"
" vmovdqa 5*32(%[before_ymm]),%%ymm5\n"
" vmovdqa 6*32(%[before_ymm]),%%ymm6\n"
" vmovdqa 7*32(%[before_ymm]),%%ymm7\n"
#ifdef __x86_64__
" vmovdqa 8*32(%[before_ymm]),%%ymm8\n"
" vmovdqa 9*32(%[before_ymm]),%%ymm9\n"
" vmovdqa 10*32(%[before_ymm]),%%ymm10\n"
" vmovdqa 11*32(%[before_ymm]),%%ymm11\n"
" vmovdqa 12*32(%[before_ymm]),%%ymm12\n"
" vmovdqa 13*32(%[before_ymm]),%%ymm13\n"
" vmovdqa 14*32(%[before_ymm]),%%ymm14\n"
" vmovdqa 15*32(%[before_ymm]),%%ymm15\n"
#endif
" lock\n"
" orb $1,%[ready]\n"
"0: pause\n"
" cmpb $0,%[done]\n"
" lfence\n"
" je 0b\n"
" vmovdqa %%ymm0,0*32(%[after_ymm])\n"
" vmovdqa %%ymm1,1*32(%[after_ymm])\n"
" vmovdqa %%ymm2,2*32(%[after_ymm])\n"
" vmovdqa %%ymm3,3*32(%[after_ymm])\n"
" vmovdqa %%ymm4,4*32(%[after_ymm])\n"
" vmovdqa %%ymm5,5*32(%[after_ymm])\n"
" vmovdqa %%ymm6,6*32(%[after_ymm])\n"
" vmovdqa %%ymm7,7*32(%[after_ymm])\n"
#ifdef __x86_64__
" vmovdqa %%ymm8,8*32(%[after_ymm])\n"
" vmovdqa %%ymm9,9*32(%[after_ymm])\n"
" vmovdqa %%ymm10,10*32(%[after_ymm])\n"
" vmovdqa %%ymm11,11*32(%[after_ymm])\n"
" vmovdqa %%ymm12,12*32(%[after_ymm])\n"
" vmovdqa %%ymm13,13*32(%[after_ymm])\n"
" vmovdqa %%ymm14,14*32(%[after_ymm])\n"
" vmovdqa %%ymm15,15*32(%[after_ymm])\n"
#endif
: [ready]"=m"(*ready), "=m"(after.ymm)
: [done]"m"(*done), "m"(before.ymm),
[before_ymm]"r"(before.ymm), [after_ymm]"r"(after.ymm)
: "ymm0", "ymm1", "ymm2", "ymm3", "ymm4", "ymm5",
"ymm6", "ymm7"
#ifdef __x86_64__
, "ymm8", "ymm9", "ymm10", "ymm11", "ymm12",
"ymm13", "ymm14", "ymm15"
#endif
);
for (i = 0; i < __arraycount(before.ymm); i++) {
if (memcmp(&before.ymm[i], &after.ymm[i],
sizeof(before.ymm[i]))) {
fprintf(stderr, "ymm%u clobbered\n", i);
hexdump(stderr, &before.ymm[i], sizeof(before.ymm[i]),
"before");
hexdump(stderr, &after.ymm[i], sizeof(after.ymm[i]),
"after");
error |= 1 << i;
}
}
return error;
}
__attribute__((target("avx")))
void
trash_ymm(void)
{
struct ymmregs regs;
arc4random_buf(®s, sizeof(regs));
asm("\n"
" vmovdqa 0*32(%[ymm]),%%ymm0\n"
" vmovdqa 1*32(%[ymm]),%%ymm1\n"
" vmovdqa 2*32(%[ymm]),%%ymm2\n"
" vmovdqa 3*32(%[ymm]),%%ymm3\n"
" vmovdqa 4*32(%[ymm]),%%ymm4\n"
" vmovdqa 5*32(%[ymm]),%%ymm5\n"
" vmovdqa 6*32(%[ymm]),%%ymm6\n"
" vmovdqa 7*32(%[ymm]),%%ymm7\n"
#ifdef __x86_64__
" vmovdqa 8*32(%[ymm]),%%ymm8\n"
" vmovdqa 9*32(%[ymm]),%%ymm9\n"
" vmovdqa 10*32(%[ymm]),%%ymm10\n"
" vmovdqa 11*32(%[ymm]),%%ymm11\n"
" vmovdqa 12*32(%[ymm]),%%ymm12\n"
" vmovdqa 13*32(%[ymm]),%%ymm13\n"
" vmovdqa 14*32(%[ymm]),%%ymm14\n"
" vmovdqa 15*32(%[ymm]),%%ymm15\n"
#endif
:
: "m"(regs.ymm), [ymm]"r"(regs.ymm)
: "ymm0", "ymm1", "ymm2", "ymm3", "ymm4", "ymm5",
"ymm6", "ymm7"
#ifdef __x86_64__
, "ymm8", "ymm9", "ymm10", "ymm11", "ymm12",
"ymm13", "ymm14", "ymm15"
#endif
);
}
bool
zmm_supported(void)
{
return cpuid(0x00000007, 0).ebx & __BIT(16);
}
struct zmmregs {
struct {
uint8_t b[64];
} __aligned(64) zmm[NZMMREGS];
};
__attribute__((target("avx512f")))
int
test_zmm(volatile bool *ready, const volatile bool *done)
{
struct zmmregs before, after;
unsigned i;
int error = 0;
arc4random_buf(&before, sizeof(before));
asm("\n"
" vmovdqa64 0*64(%[before_zmm]),%%zmm0\n"
" vmovdqa64 1*64(%[before_zmm]),%%zmm1\n"
" vmovdqa64 2*64(%[before_zmm]),%%zmm2\n"
" vmovdqa64 3*64(%[before_zmm]),%%zmm3\n"
" vmovdqa64 4*64(%[before_zmm]),%%zmm4\n"
" vmovdqa64 5*64(%[before_zmm]),%%zmm5\n"
" vmovdqa64 6*64(%[before_zmm]),%%zmm6\n"
" vmovdqa64 7*64(%[before_zmm]),%%zmm7\n"
#ifdef __x86_64__
" vmovdqa64 8*64(%[before_zmm]),%%zmm8\n"
" vmovdqa64 9*64(%[before_zmm]),%%zmm9\n"
" vmovdqa64 10*64(%[before_zmm]),%%zmm10\n"
" vmovdqa64 11*64(%[before_zmm]),%%zmm11\n"
" vmovdqa64 12*64(%[before_zmm]),%%zmm12\n"
" vmovdqa64 13*64(%[before_zmm]),%%zmm13\n"
" vmovdqa64 14*64(%[before_zmm]),%%zmm14\n"
" vmovdqa64 15*64(%[before_zmm]),%%zmm15\n"
" vmovdqa64 16*64(%[before_zmm]),%%zmm16\n"
" vmovdqa64 17*64(%[before_zmm]),%%zmm17\n"
" vmovdqa64 18*64(%[before_zmm]),%%zmm18\n"
" vmovdqa64 19*64(%[before_zmm]),%%zmm19\n"
" vmovdqa64 20*64(%[before_zmm]),%%zmm20\n"
" vmovdqa64 21*64(%[before_zmm]),%%zmm21\n"
" vmovdqa64 22*64(%[before_zmm]),%%zmm22\n"
" vmovdqa64 23*64(%[before_zmm]),%%zmm23\n"
" vmovdqa64 24*64(%[before_zmm]),%%zmm24\n"
" vmovdqa64 25*64(%[before_zmm]),%%zmm25\n"
" vmovdqa64 26*64(%[before_zmm]),%%zmm26\n"
" vmovdqa64 27*64(%[before_zmm]),%%zmm27\n"
" vmovdqa64 28*64(%[before_zmm]),%%zmm28\n"
" vmovdqa64 29*64(%[before_zmm]),%%zmm29\n"
" vmovdqa64 30*64(%[before_zmm]),%%zmm30\n"
" vmovdqa64 31*64(%[before_zmm]),%%zmm31\n"
#endif
" lock\n"
" orb $1,%[ready]\n"
"0: pause\n"
" cmpb $0,%[done]\n"
" lfence\n"
" je 0b\n"
" vmovdqa64 %%zmm0,0*64(%[after_zmm])\n"
" vmovdqa64 %%zmm1,1*64(%[after_zmm])\n"
" vmovdqa64 %%zmm2,2*64(%[after_zmm])\n"
" vmovdqa64 %%zmm3,3*64(%[after_zmm])\n"
" vmovdqa64 %%zmm4,4*64(%[after_zmm])\n"
" vmovdqa64 %%zmm5,5*64(%[after_zmm])\n"
" vmovdqa64 %%zmm6,6*64(%[after_zmm])\n"
" vmovdqa64 %%zmm7,7*64(%[after_zmm])\n"
#ifdef __x86_64__
" vmovdqa64 %%zmm8,8*64(%[after_zmm])\n"
" vmovdqa64 %%zmm9,9*64(%[after_zmm])\n"
" vmovdqa64 %%zmm10,10*64(%[after_zmm])\n"
" vmovdqa64 %%zmm11,11*64(%[after_zmm])\n"
" vmovdqa64 %%zmm12,12*64(%[after_zmm])\n"
" vmovdqa64 %%zmm13,13*64(%[after_zmm])\n"
" vmovdqa64 %%zmm14,14*64(%[after_zmm])\n"
" vmovdqa64 %%zmm15,15*64(%[after_zmm])\n"
" vmovdqa64 %%zmm16,16*64(%[after_zmm])\n"
" vmovdqa64 %%zmm17,17*64(%[after_zmm])\n"
" vmovdqa64 %%zmm18,18*64(%[after_zmm])\n"
" vmovdqa64 %%zmm19,19*64(%[after_zmm])\n"
" vmovdqa64 %%zmm20,20*64(%[after_zmm])\n"
" vmovdqa64 %%zmm21,21*64(%[after_zmm])\n"
" vmovdqa64 %%zmm22,22*64(%[after_zmm])\n"
" vmovdqa64 %%zmm23,23*64(%[after_zmm])\n"
" vmovdqa64 %%zmm24,24*64(%[after_zmm])\n"
" vmovdqa64 %%zmm25,25*64(%[after_zmm])\n"
" vmovdqa64 %%zmm26,26*64(%[after_zmm])\n"
" vmovdqa64 %%zmm27,27*64(%[after_zmm])\n"
" vmovdqa64 %%zmm28,28*64(%[after_zmm])\n"
" vmovdqa64 %%zmm29,29*64(%[after_zmm])\n"
" vmovdqa64 %%zmm30,30*64(%[after_zmm])\n"
" vmovdqa64 %%zmm31,31*64(%[after_zmm])\n"
#endif
: [ready]"=m"(*ready), "=m"(after.zmm)
: [done]"m"(*done), "m"(before.zmm),
[before_zmm]"r"(before.zmm), [after_zmm]"r"(after.zmm)
: "zmm0", "zmm1", "zmm2", "zmm3", "zmm4", "zmm5",
"zmm6", "zmm7"
#ifdef __x86_64__
, "zmm8", "zmm9", "zmm10", "zmm11", "zmm12",
"zmm13", "zmm14", "zmm15", "zmm16", "zmm17",
"zmm18", "zmm19", "zmm20", "zmm21", "zmm22",
"zmm23", "zmm24", "zmm25", "zmm26", "zmm27",
"zmm28", "zmm29", "zmm30", "zmm31"
#endif
);
for (i = 0; i < __arraycount(before.zmm); i++) {
if (memcmp(&before.zmm[i], &after.zmm[i],
sizeof(before.zmm[i]))) {
fprintf(stderr, "zmm%u clobbered\n", i);
hexdump(stderr, &before.zmm[i], sizeof(before.zmm[i]),
"before");
hexdump(stderr, &after.zmm[i], sizeof(after.zmm[i]),
"after");
error |= 1 << i;
}
}
return error;
}
__attribute__((target("avx512f")))
void
trash_zmm(void)
{
struct zmmregs regs;
arc4random_buf(®s, sizeof(regs));
asm("\n"
" vmovdqa64 0*64(%[zmm]),%%zmm0\n"
" vmovdqa64 1*64(%[zmm]),%%zmm1\n"
" vmovdqa64 2*64(%[zmm]),%%zmm2\n"
" vmovdqa64 3*64(%[zmm]),%%zmm3\n"
" vmovdqa64 4*64(%[zmm]),%%zmm4\n"
" vmovdqa64 5*64(%[zmm]),%%zmm5\n"
" vmovdqa64 6*64(%[zmm]),%%zmm6\n"
" vmovdqa64 7*64(%[zmm]),%%zmm7\n"
#ifdef __x86_64__
" vmovdqa64 8*64(%[zmm]),%%zmm8\n"
" vmovdqa64 9*64(%[zmm]),%%zmm9\n"
" vmovdqa64 10*64(%[zmm]),%%zmm10\n"
" vmovdqa64 11*64(%[zmm]),%%zmm11\n"
" vmovdqa64 12*64(%[zmm]),%%zmm12\n"
" vmovdqa64 13*64(%[zmm]),%%zmm13\n"
" vmovdqa64 14*64(%[zmm]),%%zmm14\n"
" vmovdqa64 15*64(%[zmm]),%%zmm15\n"
" vmovdqa64 16*64(%[zmm]),%%zmm16\n"
" vmovdqa64 17*64(%[zmm]),%%zmm17\n"
" vmovdqa64 18*64(%[zmm]),%%zmm18\n"
" vmovdqa64 19*64(%[zmm]),%%zmm19\n"
" vmovdqa64 20*64(%[zmm]),%%zmm20\n"
" vmovdqa64 21*64(%[zmm]),%%zmm21\n"
" vmovdqa64 22*64(%[zmm]),%%zmm22\n"
" vmovdqa64 23*64(%[zmm]),%%zmm23\n"
" vmovdqa64 24*64(%[zmm]),%%zmm24\n"
" vmovdqa64 25*64(%[zmm]),%%zmm25\n"
" vmovdqa64 26*64(%[zmm]),%%zmm26\n"
" vmovdqa64 27*64(%[zmm]),%%zmm27\n"
" vmovdqa64 28*64(%[zmm]),%%zmm28\n"
" vmovdqa64 29*64(%[zmm]),%%zmm29\n"
" vmovdqa64 30*64(%[zmm]),%%zmm30\n"
" vmovdqa64 31*64(%[zmm]),%%zmm31\n"
#endif
:
: "m"(regs.zmm), [zmm]"r"(regs.zmm)
: "zmm0", "zmm1", "zmm2", "zmm3", "zmm4", "zmm5",
"zmm6", "zmm7"
#ifdef __x86_64__
, "zmm8", "zmm9", "zmm10", "zmm11", "zmm12",
"zmm13", "zmm14", "zmm15", "zmm16", "zmm17",
"zmm18", "zmm19", "zmm20", "zmm21", "zmm22",
"zmm23", "zmm24", "zmm25", "zmm26", "zmm27",
"zmm28", "zmm29", "zmm30", "zmm31"
#endif
);
}