Home | History | Annotate | Line # | Download | only in x86
      1  1.3  riastrad /*	$NetBSD: sig_fpu.c,v 1.3 2026/07/15 02:08:18 riastradh Exp $	*/
      2  1.1  riastrad 
      3  1.1  riastrad /*
      4  1.1  riastrad  * Copyright (c) 2026 The NetBSD Foundation, Inc.
      5  1.1  riastrad  * All rights reserved.
      6  1.1  riastrad  *
      7  1.1  riastrad  * Redistribution and use in source and binary forms, with or without
      8  1.1  riastrad  * modification, are permitted provided that the following conditions
      9  1.1  riastrad  * are met:
     10  1.1  riastrad  * 1. Redistributions of source code must retain the above copyright
     11  1.1  riastrad  *    notice, this list of conditions and the following disclaimer.
     12  1.1  riastrad  * 2. Redistributions in binary form must reproduce the above copyright
     13  1.1  riastrad  *    notice, this list of conditions and the following disclaimer in the
     14  1.1  riastrad  *    documentation and/or other materials provided with the distribution.
     15  1.1  riastrad  *
     16  1.1  riastrad  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     17  1.1  riastrad  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     18  1.1  riastrad  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     19  1.1  riastrad  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     20  1.1  riastrad  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     21  1.1  riastrad  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     22  1.1  riastrad  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     23  1.1  riastrad  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     24  1.1  riastrad  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     25  1.1  riastrad  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     26  1.1  riastrad  * POSSIBILITY OF SUCH DAMAGE.
     27  1.1  riastrad  */
     28  1.1  riastrad 
     29  1.1  riastrad #include <sys/cdefs.h>
     30  1.3  riastrad __RCSID("$NetBSD: sig_fpu.c,v 1.3 2026/07/15 02:08:18 riastradh Exp $");
     31  1.1  riastrad 
     32  1.1  riastrad #include "sig_fpu.h"
     33  1.1  riastrad 
     34  1.1  riastrad #include <sys/types.h>
     35  1.1  riastrad 
     36  1.1  riastrad #include <x86/cpu_extended_state.h>
     37  1.1  riastrad 
     38  1.1  riastrad #include <cpuid.h>
     39  1.1  riastrad #include <inttypes.h>
     40  1.1  riastrad #include <sched.h>
     41  1.1  riastrad #include <signal.h>
     42  1.1  riastrad #include <stdbool.h>
     43  1.1  riastrad #include <stdio.h>
     44  1.1  riastrad 
     45  1.1  riastrad #include "h_macros.h"
     46  1.1  riastrad 
     47  1.1  riastrad #ifdef __x86_64__
     48  1.2  riastrad #  define	NXMMREGS	16
     49  1.2  riastrad #  define	NYMMREGS	16
     50  1.2  riastrad #  define	NZMMREGS	32
     51  1.1  riastrad #else  /* 32-bit */
     52  1.2  riastrad #  define	NXMMREGS	8
     53  1.2  riastrad #  define	NYMMREGS	8
     54  1.2  riastrad #  define	NZMMREGS	8
     55  1.1  riastrad #endif
     56  1.1  riastrad 
     57  1.1  riastrad #define	X87_CW_RC	__BITS(11,10) /* rounding control (mode) */
     58  1.1  riastrad #define	X87_CW_PC	__BITS(9,8)   /* precision control */
     59  1.1  riastrad #define	X87_CW_SW_EXC	__BITS(5,0)   /* exception bits */
     60  1.1  riastrad 
     61  1.1  riastrad struct cpuid {
     62  1.1  riastrad 	uint32_t edx;
     63  1.1  riastrad 	uint32_t ecx;
     64  1.1  riastrad 	uint32_t ebx;
     65  1.1  riastrad 	uint32_t eax;
     66  1.1  riastrad };
     67  1.1  riastrad 
     68  1.1  riastrad static struct cpuid
     69  1.1  riastrad cpuid(uint32_t eax_fn, uint32_t ecx_idx)
     70  1.1  riastrad {
     71  1.1  riastrad 	struct cpuid c;
     72  1.1  riastrad 
     73  1.1  riastrad 	if (!__get_cpuid_count(eax_fn, ecx_idx,
     74  1.1  riastrad 		&c.eax, &c.ebx, &c.ecx, &c.edx))
     75  1.1  riastrad 		memset(&c, 0, sizeof(c));
     76  1.1  riastrad 
     77  1.1  riastrad 	return c;
     78  1.1  riastrad }
     79  1.1  riastrad 
     80  1.1  riastrad __printflike(4,5)
     81  1.1  riastrad __noinline
     82  1.1  riastrad static void
     83  1.1  riastrad hexdump(FILE *fp, const void *buf, size_t len, const char *title, ...)
     84  1.1  riastrad {
     85  1.1  riastrad 	va_list va;
     86  1.1  riastrad 	const uint8_t *p = buf;
     87  1.1  riastrad 	size_t i;
     88  1.1  riastrad 
     89  1.1  riastrad 	fprintf(fp, "# ");
     90  1.1  riastrad 	va_start(va, title);
     91  1.1  riastrad 	vfprintf(fp, title, va);
     92  1.1  riastrad 	va_end(va);
     93  1.1  riastrad 	fprintf(fp, "\n");
     94  1.1  riastrad 	for (i = 0; i < len; i++) {
     95  1.1  riastrad 		if ((i % 8) == 0)
     96  1.1  riastrad 			fprintf(fp, " ");
     97  1.1  riastrad 		fprintf(fp, " %02hhx", p[i]);
     98  1.1  riastrad 		if ((i % 16) == 15)
     99  1.1  riastrad 			fprintf(fp, "\n");
    100  1.1  riastrad 	}
    101  1.1  riastrad 	if (i % 16)
    102  1.1  riastrad 		fprintf(fp, "\n");
    103  1.1  riastrad }
    104  1.1  riastrad 
    105  1.1  riastrad bool
    106  1.1  riastrad x87_supported(void)
    107  1.1  riastrad {
    108  1.1  riastrad #ifdef __x86_64__
    109  1.1  riastrad 	return true;
    110  1.1  riastrad #else  /* 32-bit */
    111  1.1  riastrad 	return cpuid(0x00000001, 0).edx & __BIT(0);
    112  1.1  riastrad #endif
    113  1.1  riastrad }
    114  1.1  riastrad 
    115  1.1  riastrad int
    116  1.1  riastrad test_x87(volatile bool *ready, const volatile bool *done)
    117  1.1  riastrad {
    118  1.1  riastrad 	struct save87 s, s1;
    119  1.1  riastrad 	uint32_t rcpc_exc;
    120  1.1  riastrad 	int error = 0;
    121  1.1  riastrad 
    122  1.1  riastrad 	/*
    123  1.1  riastrad 	 * Gather the current FPU state so we have some reasonable
    124  1.1  riastrad 	 * content for the weird stuff when we restore from it.
    125  1.1  riastrad 	 */
    126  1.1  riastrad 	asm("wait\n"
    127  1.1  riastrad 	    "	fnsave	%0"
    128  1.1  riastrad 	    : /*out*/ "=m"(s));
    129  1.1  riastrad 
    130  1.1  riastrad 	/*
    131  1.1  riastrad 	 * Randomize the floating-point stack entries ST(0),...,ST(7).
    132  1.1  riastrad 	 */
    133  1.1  riastrad 	arc4random_buf(s.s87_ac, sizeof(s.s87_ac));
    134  1.1  riastrad 
    135  1.1  riastrad 	/*
    136  1.1  riastrad 	 * Randomize rounding control, precision control, and a set of
    137  1.1  riastrad 	 * exception bits.  We don't want to raise any unmasked
    138  1.1  riastrad 	 * exceptions, so we'll raise _and_ mask them.
    139  1.1  riastrad 	 *
    140  1.1  riastrad 	 * XXX Consider testing the condition code, exception status,
    141  1.1  riastrad 	 * and top of stack bits in the status word too.
    142  1.1  riastrad 	 */
    143  1.1  riastrad 	rcpc_exc = arc4random() & (X87_CW_RC | X87_CW_PC | X87_CW_SW_EXC);
    144  1.1  riastrad 	if (__SHIFTOUT(rcpc_exc, X87_CW_PC) == 1) /* reserved */
    145  1.1  riastrad 		rcpc_exc |= __SHIFTIN(3, X87_CW_PC); /* extended */
    146  1.1  riastrad 	s.s87_cw &= ~(X87_CW_RC | X87_CW_PC | X87_CW_SW_EXC);
    147  1.1  riastrad 	s.s87_cw |= rcpc_exc;
    148  1.1  riastrad 	s.s87_sw &= ~X87_CW_SW_EXC;
    149  1.1  riastrad 	s.s87_sw |= rcpc_exc & X87_CW_SW_EXC;
    150  1.1  riastrad 
    151  1.1  riastrad 	/*
    152  1.1  riastrad 	 * Load up the registers, report that we're ready, busy-wait
    153  1.1  riastrad 	 * with the registers still live -- so no subroutine calls --
    154  1.1  riastrad 	 * until we're done, and then store the registers back to
    155  1.1  riastrad 	 * memory so we can check them.
    156  1.1  riastrad 	 */
    157  1.1  riastrad 	asm("\n"
    158  1.1  riastrad 	    "	frstor	%[s]\n"
    159  1.1  riastrad 	    "	lock\n"
    160  1.1  riastrad 	    "	orb	$1,%[ready]\n"
    161  1.1  riastrad 	    "0:	pause\n"
    162  1.1  riastrad 	    "	cmpb	$0,%[done]\n"
    163  1.1  riastrad 	    "	lfence\n"
    164  1.1  riastrad 	    "	je	0b\n"
    165  1.1  riastrad 	    "	wait\n"
    166  1.1  riastrad 	    "	fnsave	%[s1]\n"
    167  1.1  riastrad 	    : /*out*/ [ready]"=m"(*ready), [s1]"=m"(s1)
    168  1.1  riastrad 	    : /*in*/ [done]"m"(*done), [s]"m"(s));
    169  1.1  riastrad 
    170  1.1  riastrad 	/*
    171  1.1  riastrad 	 * If there are any mismatches between the before and after
    172  1.1  riastrad 	 * ST(i) registers, or the control word, or the status word,
    173  1.1  riastrad 	 * print them and fail.
    174  1.1  riastrad 	 */
    175  1.1  riastrad 	if (memcmp(s.s87_ac, s1.s87_ac, sizeof(s.s87_ac)) != 0) {
    176  1.1  riastrad 		unsigned i;
    177  1.1  riastrad 
    178  1.1  riastrad 		for (i = 0; i < 8; i++) {
    179  1.1  riastrad 			if (memcmp(&s.s87_ac[i], &s1.s87_ac[i],
    180  1.1  riastrad 				sizeof(s.s87_ac[i])) == 0)
    181  1.1  riastrad 				continue;
    182  1.1  riastrad 			fprintf(stderr, "ST(%u)=0x%08x%016"PRIx64","
    183  1.1  riastrad 			    " expected 0x%08x%016"PRIx64"\n",
    184  1.1  riastrad 			    i,
    185  1.1  riastrad 			    s1.s87_ac[i].f87_exp_sign,
    186  1.1  riastrad 			    s1.s87_ac[i].f87_mantissa,
    187  1.1  riastrad 			    s.s87_ac[i].f87_exp_sign,
    188  1.1  riastrad 			    s.s87_ac[i].f87_mantissa);
    189  1.1  riastrad 			error |= 1 << i;
    190  1.1  riastrad 		}
    191  1.1  riastrad 	}
    192  1.1  riastrad 	if ((s1.s87_cw & (X87_CW_RC | X87_CW_PC | X87_CW_SW_EXC)) !=
    193  1.1  riastrad 	    (s.s87_cw & (X87_CW_RC | X87_CW_PC | X87_CW_SW_EXC))) {
    194  1.1  riastrad 		fprintf(stderr, "cw=0x%04x, expected 0x%04x,"
    195  1.1  riastrad 		    " diff 0x%04x\n",
    196  1.1  riastrad 		    s1.s87_cw, s.s87_cw,
    197  1.1  riastrad 		    (uint32_t)((s1.s87_cw ^ s.s87_cw) &
    198  1.1  riastrad 			(X87_CW_RC | X87_CW_PC | X87_CW_SW_EXC)));
    199  1.1  riastrad 		error |= 1 << 8;
    200  1.1  riastrad 	}
    201  1.1  riastrad 	if ((s1.s87_sw & X87_CW_SW_EXC) !=
    202  1.1  riastrad 	    (s.s87_cw & X87_CW_SW_EXC)) {
    203  1.1  riastrad 		fprintf(stderr, "sw=0x%04x, expected 0x%04x,"
    204  1.1  riastrad 		    " diff 0x%04x\n",
    205  1.1  riastrad 		    s1.s87_sw, s.s87_sw,
    206  1.1  riastrad 		    (uint32_t)((s1.s87_sw ^ s.s87_sw) &
    207  1.1  riastrad 			X87_CW_SW_EXC));
    208  1.1  riastrad 		error |= 1 << 9;
    209  1.1  riastrad 	}
    210  1.1  riastrad 
    211  1.1  riastrad 	return error;
    212  1.1  riastrad }
    213  1.1  riastrad 
    214  1.1  riastrad void
    215  1.1  riastrad trash_x87(void)
    216  1.1  riastrad {
    217  1.1  riastrad 	struct save87 s;
    218  1.1  riastrad 	uint32_t rcpc_exc;
    219  1.1  riastrad 
    220  1.1  riastrad 	/*
    221  1.1  riastrad 	 * Gather the current FPU state so we have some reasonable
    222  1.1  riastrad 	 * content for the weird stuff when we restore from it.
    223  1.1  riastrad 	 */
    224  1.1  riastrad 	asm("wait\n"
    225  1.1  riastrad 	    "	fnsave	%0"
    226  1.1  riastrad 	    : /*out*/ "=m"(s));
    227  1.1  riastrad 
    228  1.1  riastrad 	/*
    229  1.1  riastrad 	 * Randomize the floating-point stack entries ST(0),...,ST(7).
    230  1.1  riastrad 	 */
    231  1.1  riastrad 	arc4random_buf(s.s87_ac, sizeof(s.s87_ac));
    232  1.1  riastrad 
    233  1.1  riastrad 	/*
    234  1.1  riastrad 	 * Randomize rounding control, precision control, and a set of
    235  1.1  riastrad 	 * exception bits.  We don't want to raise any unmasked
    236  1.1  riastrad 	 * exceptions, so we'll raise _and_ mask them.
    237  1.1  riastrad 	 *
    238  1.1  riastrad 	 * XXX Consider trashing the condition code, exception status,
    239  1.1  riastrad 	 * and top of stack bits in the status word too.
    240  1.1  riastrad 	 */
    241  1.1  riastrad 	rcpc_exc = arc4random() & (X87_CW_RC | X87_CW_PC | X87_CW_SW_EXC);
    242  1.1  riastrad 	s.s87_cw &= ~(X87_CW_RC | X87_CW_PC | X87_CW_SW_EXC);
    243  1.1  riastrad 	s.s87_cw |= rcpc_exc;
    244  1.1  riastrad 	s.s87_sw &= ~X87_CW_SW_EXC;
    245  1.1  riastrad 	s.s87_sw |= rcpc_exc & X87_CW_SW_EXC;
    246  1.1  riastrad 
    247  1.1  riastrad 	/*
    248  1.1  riastrad 	 * Load the state into the FPU.
    249  1.1  riastrad 	 */
    250  1.1  riastrad 	asm volatile("frstor %0" :: /*in*/ "m"(s));
    251  1.1  riastrad }
    252  1.1  riastrad 
    253  1.1  riastrad #define	MXCSR_MISALIGNEDEXC	__BIT(17)	/* misaligned exc fault */
    254  1.1  riastrad #define	MXCSR_FTZ		__BIT(15)	/* flush to zero */
    255  1.1  riastrad #define	MXCSR_RC		__BITS(14,13)	/* rounding control */
    256  1.1  riastrad #define	MXCSR_EXCMASK		__BITS(12,7)	/* exceptions masked */
    257  1.1  riastrad #define	MXCSR_DAZ		__BIT(6)	/* denormals are zero */
    258  1.1  riastrad #define	MXCSR_EXCFLAG		__BITS(5,0)	/* exceptions raised */
    259  1.1  riastrad 
    260  1.1  riastrad struct xmmregs {
    261  1.1  riastrad 	struct {
    262  1.1  riastrad 		uint8_t b[16];
    263  1.2  riastrad 	} __aligned(16)	xmm[NXMMREGS];
    264  1.1  riastrad 	uint32_t mxcsr;
    265  1.1  riastrad };
    266  1.1  riastrad 
    267  1.1  riastrad bool
    268  1.1  riastrad xmm_supported(void)
    269  1.1  riastrad {
    270  1.1  riastrad #ifdef __x86_64__
    271  1.1  riastrad 	return true;
    272  1.1  riastrad #else  /* 32-bit */
    273  1.1  riastrad 	return cpuid(0x00000001, 0).edx & __BIT(25);
    274  1.1  riastrad #endif
    275  1.1  riastrad }
    276  1.1  riastrad 
    277  1.1  riastrad __attribute__((target("sse")))
    278  1.1  riastrad int
    279  1.1  riastrad test_xmm(volatile bool *ready, const volatile bool *done)
    280  1.1  riastrad {
    281  1.1  riastrad 	struct xmmregs before, after;
    282  1.1  riastrad 	uint32_t exc;
    283  1.1  riastrad 	unsigned i;
    284  1.1  riastrad 	int error = 0;
    285  1.1  riastrad 
    286  1.1  riastrad 	/*
    287  1.1  riastrad 	 * Randomize the xmm register content.  Randomize plausible
    288  1.1  riastrad 	 * bits for the mxcsr.
    289  1.1  riastrad 	 */
    290  1.1  riastrad 	arc4random_buf(before.xmm, sizeof(before.xmm));
    291  1.1  riastrad 	before.mxcsr = arc4random() & (MXCSR_FTZ | MXCSR_RC | MXCSR_DAZ);
    292  1.1  riastrad 	exc = arc4random() & 0x3f;
    293  1.1  riastrad 	before.mxcsr |= __SHIFTIN(exc, MXCSR_EXCMASK);
    294  1.1  riastrad 	before.mxcsr |= __SHIFTIN(exc, MXCSR_EXCFLAG);
    295  1.1  riastrad 
    296  1.1  riastrad 	/*
    297  1.1  riastrad 	 * Load up the registers, report that we're ready, busy-wait
    298  1.1  riastrad 	 * with the registers still live -- so no subroutine calls --
    299  1.1  riastrad 	 * until we're done, and then store the registers back to
    300  1.1  riastrad 	 * memory so we can check them.
    301  1.1  riastrad 	 */
    302  1.1  riastrad 	asm("\n"
    303  1.1  riastrad 	    "	ldmxcsr	%[mxcsr_before]\n"
    304  1.1  riastrad 	    "	movdqa	0*16(%[xmm_before]),%%xmm0\n"
    305  1.1  riastrad 	    "	movdqa	1*16(%[xmm_before]),%%xmm1\n"
    306  1.1  riastrad 	    "	movdqa	2*16(%[xmm_before]),%%xmm2\n"
    307  1.1  riastrad 	    "	movdqa	3*16(%[xmm_before]),%%xmm3\n"
    308  1.1  riastrad 	    "	movdqa	4*16(%[xmm_before]),%%xmm4\n"
    309  1.1  riastrad 	    "	movdqa	5*16(%[xmm_before]),%%xmm5\n"
    310  1.1  riastrad 	    "	movdqa	6*16(%[xmm_before]),%%xmm6\n"
    311  1.1  riastrad 	    "	movdqa	7*16(%[xmm_before]),%%xmm7\n"
    312  1.1  riastrad #ifdef __x86_64__
    313  1.1  riastrad 	    "	movdqa	8*16(%[xmm_before]),%%xmm8\n"
    314  1.1  riastrad 	    "	movdqa	9*16(%[xmm_before]),%%xmm9\n"
    315  1.1  riastrad 	    "	movdqa	10*16(%[xmm_before]),%%xmm10\n"
    316  1.1  riastrad 	    "	movdqa	11*16(%[xmm_before]),%%xmm11\n"
    317  1.1  riastrad 	    "	movdqa	12*16(%[xmm_before]),%%xmm12\n"
    318  1.1  riastrad 	    "	movdqa	13*16(%[xmm_before]),%%xmm13\n"
    319  1.1  riastrad 	    "	movdqa	14*16(%[xmm_before]),%%xmm14\n"
    320  1.1  riastrad 	    "	movdqa	15*16(%[xmm_before]),%%xmm15\n"
    321  1.1  riastrad #endif
    322  1.1  riastrad 	    "	lock\n"
    323  1.1  riastrad 	    "	orb	$1,%[ready]\n"
    324  1.1  riastrad 	    "0:	pause\n"
    325  1.1  riastrad 	    "	cmpb	$0,%[done]\n"
    326  1.1  riastrad 	    "	lfence\n"
    327  1.1  riastrad 	    "	je	0b\n"
    328  1.1  riastrad 	    "	movdqa	%%xmm0,0*16(%[xmm_after])\n"
    329  1.1  riastrad 	    "	movdqa	%%xmm1,1*16(%[xmm_after])\n"
    330  1.1  riastrad 	    "	movdqa	%%xmm2,2*16(%[xmm_after])\n"
    331  1.1  riastrad 	    "	movdqa	%%xmm3,3*16(%[xmm_after])\n"
    332  1.1  riastrad 	    "	movdqa	%%xmm4,4*16(%[xmm_after])\n"
    333  1.1  riastrad 	    "	movdqa	%%xmm5,5*16(%[xmm_after])\n"
    334  1.1  riastrad 	    "	movdqa	%%xmm6,6*16(%[xmm_after])\n"
    335  1.1  riastrad 	    "	movdqa	%%xmm7,7*16(%[xmm_after])\n"
    336  1.1  riastrad #ifdef __x86_64__
    337  1.1  riastrad 	    "	movdqa	%%xmm8,8*16(%[xmm_after])\n"
    338  1.1  riastrad 	    "	movdqa	%%xmm9,9*16(%[xmm_after])\n"
    339  1.1  riastrad 	    "	movdqa	%%xmm10,10*16(%[xmm_after])\n"
    340  1.1  riastrad 	    "	movdqa	%%xmm11,11*16(%[xmm_after])\n"
    341  1.1  riastrad 	    "	movdqa	%%xmm12,12*16(%[xmm_after])\n"
    342  1.1  riastrad 	    "	movdqa	%%xmm13,13*16(%[xmm_after])\n"
    343  1.1  riastrad 	    "	movdqa	%%xmm14,14*16(%[xmm_after])\n"
    344  1.1  riastrad 	    "	movdqa	%%xmm15,15*16(%[xmm_after])\n"
    345  1.1  riastrad #endif
    346  1.1  riastrad 	    "	stmxcsr	%[mxcsr_after]\n"
    347  1.1  riastrad 	    : /*out*/ [ready]"=m"(*ready), "=m"(after.xmm),
    348  1.1  riastrad 	      [mxcsr_after]"=m"(after.mxcsr)
    349  1.1  riastrad 	    : /*in*/ [done]"m"(*done), "m"(before.xmm),
    350  1.1  riastrad 	      [mxcsr_before]"m"(before.mxcsr),
    351  1.1  riastrad 	      [xmm_before]"r"(&before.xmm), [xmm_after]"r"(&after.xmm)
    352  1.1  riastrad 	    : /*clobber*/ "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5",
    353  1.1  riastrad 	      "xmm6", "xmm7"
    354  1.1  riastrad #ifdef __x86_64__
    355  1.1  riastrad 	    , "xmm8", "xmm9", "xmm10", "xmm11", "xmm12",
    356  1.1  riastrad 	      "xmm13", "xmm14", "xmm15"
    357  1.1  riastrad #endif
    358  1.1  riastrad 	);
    359  1.1  riastrad 
    360  1.1  riastrad 	/*
    361  1.1  riastrad 	 * If there are any mismatches between the before and after xmm
    362  1.1  riastrad 	 * registers, or the mxcsr, print them and fail.
    363  1.1  riastrad 	 */
    364  1.1  riastrad 	for (i = 0; i < __arraycount(before.xmm); i++) {
    365  1.1  riastrad 		if (memcmp(&before.xmm[i], &after.xmm[i],
    366  1.1  riastrad 			sizeof(before.xmm[i]))) {
    367  1.1  riastrad 			fprintf(stderr, "xmm%u clobbered\n", i);
    368  1.1  riastrad 			hexdump(stderr, &before.xmm[i], sizeof(before.xmm[i]),
    369  1.1  riastrad 			    "before");
    370  1.1  riastrad 			hexdump(stderr, &after.xmm[i], sizeof(after.xmm[i]),
    371  1.1  riastrad 			    "after");
    372  1.1  riastrad 			error |= 1 << i;
    373  1.1  riastrad 		}
    374  1.1  riastrad 	}
    375  1.1  riastrad 
    376  1.1  riastrad 	if (before.mxcsr != after.mxcsr) {
    377  1.1  riastrad 		fprintf(stderr, "mxcsr clobbered:"
    378  1.1  riastrad 		    " before=0x%08"PRIx32", after=0x%08"PRIx32"\n",
    379  1.1  riastrad 		    before.mxcsr, after.mxcsr);
    380  1.1  riastrad 		error |= 1 << 16;
    381  1.1  riastrad 	}
    382  1.1  riastrad 
    383  1.1  riastrad 	return error;
    384  1.1  riastrad }
    385  1.1  riastrad 
    386  1.1  riastrad __attribute__((target("sse")))
    387  1.1  riastrad void
    388  1.1  riastrad trash_xmm(void)
    389  1.1  riastrad {
    390  1.1  riastrad 	struct xmmregs regs;
    391  1.1  riastrad 
    392  1.1  riastrad 	arc4random_buf(&regs, sizeof(regs));
    393  1.1  riastrad 
    394  1.1  riastrad 	asm("\n"
    395  1.3  riastrad 	    "	movdqa	0*16(%[xmm]),%%xmm0\n"
    396  1.3  riastrad 	    "	movdqa	1*16(%[xmm]),%%xmm1\n"
    397  1.3  riastrad 	    "	movdqa	2*16(%[xmm]),%%xmm2\n"
    398  1.3  riastrad 	    "	movdqa	3*16(%[xmm]),%%xmm3\n"
    399  1.3  riastrad 	    "	movdqa	4*16(%[xmm]),%%xmm4\n"
    400  1.3  riastrad 	    "	movdqa	5*16(%[xmm]),%%xmm5\n"
    401  1.3  riastrad 	    "	movdqa	6*16(%[xmm]),%%xmm6\n"
    402  1.3  riastrad 	    "	movdqa	7*16(%[xmm]),%%xmm7\n"
    403  1.3  riastrad #ifdef __x86_64__
    404  1.3  riastrad 	    "	movdqa	8*16(%[xmm]),%%xmm8\n"
    405  1.3  riastrad 	    "	movdqa	9*16(%[xmm]),%%xmm9\n"
    406  1.3  riastrad 	    "	movdqa	10*16(%[xmm]),%%xmm10\n"
    407  1.3  riastrad 	    "	movdqa	11*16(%[xmm]),%%xmm11\n"
    408  1.3  riastrad 	    "	movdqa	12*16(%[xmm]),%%xmm12\n"
    409  1.3  riastrad 	    "	movdqa	13*16(%[xmm]),%%xmm13\n"
    410  1.3  riastrad 	    "	movdqa	14*16(%[xmm]),%%xmm14\n"
    411  1.3  riastrad 	    "	movdqa	15*16(%[xmm]),%%xmm15\n"
    412  1.1  riastrad #endif
    413  1.1  riastrad 	    : /*out*/
    414  1.1  riastrad 	    : /*in*/ [xmm]"r"(regs.xmm), "m"(regs.xmm)
    415  1.1  riastrad 	    : /*clobber*/ "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5",
    416  1.1  riastrad 	      "xmm6", "xmm7"
    417  1.1  riastrad #ifdef __x86_64__
    418  1.1  riastrad 	    , "xmm8", "xmm9", "xmm10", "xmm11", "xmm12",
    419  1.1  riastrad 	      "xmm13", "xmm14", "xmm15"
    420  1.1  riastrad #endif
    421  1.1  riastrad 	);
    422  1.1  riastrad }
    423  1.1  riastrad 
    424  1.1  riastrad bool
    425  1.1  riastrad ymm_supported(void)
    426  1.1  riastrad {
    427  1.1  riastrad 	return cpuid(0x00000001, 0).ecx & __BIT(28);
    428  1.1  riastrad }
    429  1.1  riastrad 
    430  1.1  riastrad struct ymmregs {
    431  1.1  riastrad 	struct {
    432  1.1  riastrad 		uint8_t b[32];
    433  1.2  riastrad 	} __aligned(32)	ymm[NYMMREGS];
    434  1.1  riastrad };
    435  1.1  riastrad 
    436  1.1  riastrad __attribute__((target("avx")))
    437  1.1  riastrad int
    438  1.1  riastrad test_ymm(volatile bool *ready, const volatile bool *done)
    439  1.1  riastrad {
    440  1.1  riastrad 	struct ymmregs before, after;
    441  1.1  riastrad 	unsigned i;
    442  1.1  riastrad 	int error = 0;
    443  1.1  riastrad 
    444  1.1  riastrad 	/*
    445  1.1  riastrad 	 * Randomize the ymm register content.
    446  1.1  riastrad 	 */
    447  1.1  riastrad 	arc4random_buf(&before, sizeof(before));
    448  1.1  riastrad 
    449  1.1  riastrad 	/*
    450  1.1  riastrad 	 * Load up the registers, report that we're ready, busy-wait
    451  1.1  riastrad 	 * with the registers still live -- so no subroutine calls --
    452  1.1  riastrad 	 * until we're done, and then store the registers back to
    453  1.1  riastrad 	 * memory so we can check them.
    454  1.1  riastrad 	 */
    455  1.1  riastrad 	asm("\n"
    456  1.1  riastrad 	    "	vmovdqa	0*32(%[before_ymm]),%%ymm0\n"
    457  1.1  riastrad 	    "	vmovdqa	1*32(%[before_ymm]),%%ymm1\n"
    458  1.1  riastrad 	    "	vmovdqa	2*32(%[before_ymm]),%%ymm2\n"
    459  1.1  riastrad 	    "	vmovdqa	3*32(%[before_ymm]),%%ymm3\n"
    460  1.1  riastrad 	    "	vmovdqa	4*32(%[before_ymm]),%%ymm4\n"
    461  1.1  riastrad 	    "	vmovdqa	5*32(%[before_ymm]),%%ymm5\n"
    462  1.1  riastrad 	    "	vmovdqa	6*32(%[before_ymm]),%%ymm6\n"
    463  1.1  riastrad 	    "	vmovdqa	7*32(%[before_ymm]),%%ymm7\n"
    464  1.1  riastrad #ifdef __x86_64__
    465  1.1  riastrad 	    "	vmovdqa	8*32(%[before_ymm]),%%ymm8\n"
    466  1.1  riastrad 	    "	vmovdqa	9*32(%[before_ymm]),%%ymm9\n"
    467  1.1  riastrad 	    "	vmovdqa	10*32(%[before_ymm]),%%ymm10\n"
    468  1.1  riastrad 	    "	vmovdqa	11*32(%[before_ymm]),%%ymm11\n"
    469  1.1  riastrad 	    "	vmovdqa	12*32(%[before_ymm]),%%ymm12\n"
    470  1.1  riastrad 	    "	vmovdqa	13*32(%[before_ymm]),%%ymm13\n"
    471  1.1  riastrad 	    "	vmovdqa	14*32(%[before_ymm]),%%ymm14\n"
    472  1.1  riastrad 	    "	vmovdqa	15*32(%[before_ymm]),%%ymm15\n"
    473  1.1  riastrad #endif
    474  1.1  riastrad 	    "	lock\n"
    475  1.1  riastrad 	    "	orb	$1,%[ready]\n"
    476  1.1  riastrad 	    "0:	pause\n"
    477  1.1  riastrad 	    "	cmpb	$0,%[done]\n"
    478  1.1  riastrad 	    "	lfence\n"
    479  1.1  riastrad 	    "	je	0b\n"
    480  1.1  riastrad 	    "	vmovdqa	%%ymm0,0*32(%[after_ymm])\n"
    481  1.1  riastrad 	    "	vmovdqa	%%ymm1,1*32(%[after_ymm])\n"
    482  1.1  riastrad 	    "	vmovdqa	%%ymm2,2*32(%[after_ymm])\n"
    483  1.1  riastrad 	    "	vmovdqa	%%ymm3,3*32(%[after_ymm])\n"
    484  1.1  riastrad 	    "	vmovdqa	%%ymm4,4*32(%[after_ymm])\n"
    485  1.1  riastrad 	    "	vmovdqa	%%ymm5,5*32(%[after_ymm])\n"
    486  1.1  riastrad 	    "	vmovdqa	%%ymm6,6*32(%[after_ymm])\n"
    487  1.1  riastrad 	    "	vmovdqa	%%ymm7,7*32(%[after_ymm])\n"
    488  1.1  riastrad #ifdef __x86_64__
    489  1.1  riastrad 	    "	vmovdqa	%%ymm8,8*32(%[after_ymm])\n"
    490  1.1  riastrad 	    "	vmovdqa	%%ymm9,9*32(%[after_ymm])\n"
    491  1.1  riastrad 	    "	vmovdqa	%%ymm10,10*32(%[after_ymm])\n"
    492  1.1  riastrad 	    "	vmovdqa	%%ymm11,11*32(%[after_ymm])\n"
    493  1.1  riastrad 	    "	vmovdqa	%%ymm12,12*32(%[after_ymm])\n"
    494  1.1  riastrad 	    "	vmovdqa	%%ymm13,13*32(%[after_ymm])\n"
    495  1.1  riastrad 	    "	vmovdqa	%%ymm14,14*32(%[after_ymm])\n"
    496  1.1  riastrad 	    "	vmovdqa	%%ymm15,15*32(%[after_ymm])\n"
    497  1.1  riastrad #endif
    498  1.1  riastrad 	    : /*out*/ [ready]"=m"(*ready), "=m"(after.ymm)
    499  1.1  riastrad 	    : /*in*/ [done]"m"(*done), "m"(before.ymm),
    500  1.1  riastrad 	      [before_ymm]"r"(before.ymm), [after_ymm]"r"(after.ymm)
    501  1.1  riastrad 	    : /*clobber*/ "ymm0", "ymm1", "ymm2", "ymm3", "ymm4", "ymm5",
    502  1.1  riastrad 	      "ymm6", "ymm7"
    503  1.1  riastrad #ifdef __x86_64__
    504  1.1  riastrad 	    , "ymm8", "ymm9", "ymm10", "ymm11", "ymm12",
    505  1.1  riastrad 	      "ymm13", "ymm14", "ymm15"
    506  1.1  riastrad #endif
    507  1.1  riastrad 	);
    508  1.1  riastrad 
    509  1.1  riastrad 	for (i = 0; i < __arraycount(before.ymm); i++) {
    510  1.1  riastrad 		if (memcmp(&before.ymm[i], &after.ymm[i],
    511  1.1  riastrad 			sizeof(before.ymm[i]))) {
    512  1.1  riastrad 			fprintf(stderr, "ymm%u clobbered\n", i);
    513  1.1  riastrad 			hexdump(stderr, &before.ymm[i], sizeof(before.ymm[i]),
    514  1.1  riastrad 			    "before");
    515  1.1  riastrad 			hexdump(stderr, &after.ymm[i], sizeof(after.ymm[i]),
    516  1.1  riastrad 			    "after");
    517  1.1  riastrad 			error |= 1 << i;
    518  1.1  riastrad 		}
    519  1.1  riastrad 	}
    520  1.1  riastrad 
    521  1.1  riastrad 	return error;
    522  1.1  riastrad }
    523  1.1  riastrad 
    524  1.1  riastrad __attribute__((target("avx")))
    525  1.1  riastrad void
    526  1.1  riastrad trash_ymm(void)
    527  1.1  riastrad {
    528  1.1  riastrad 	struct ymmregs regs;
    529  1.1  riastrad 
    530  1.1  riastrad 	arc4random_buf(&regs, sizeof(regs));
    531  1.1  riastrad 
    532  1.1  riastrad 	asm("\n"
    533  1.1  riastrad 	    "	vmovdqa	0*32(%[ymm]),%%ymm0\n"
    534  1.1  riastrad 	    "	vmovdqa	1*32(%[ymm]),%%ymm1\n"
    535  1.1  riastrad 	    "	vmovdqa	2*32(%[ymm]),%%ymm2\n"
    536  1.1  riastrad 	    "	vmovdqa	3*32(%[ymm]),%%ymm3\n"
    537  1.1  riastrad 	    "	vmovdqa	4*32(%[ymm]),%%ymm4\n"
    538  1.1  riastrad 	    "	vmovdqa	5*32(%[ymm]),%%ymm5\n"
    539  1.1  riastrad 	    "	vmovdqa	6*32(%[ymm]),%%ymm6\n"
    540  1.1  riastrad 	    "	vmovdqa	7*32(%[ymm]),%%ymm7\n"
    541  1.1  riastrad #ifdef __x86_64__
    542  1.1  riastrad 	    "	vmovdqa	8*32(%[ymm]),%%ymm8\n"
    543  1.1  riastrad 	    "	vmovdqa	9*32(%[ymm]),%%ymm9\n"
    544  1.1  riastrad 	    "	vmovdqa	10*32(%[ymm]),%%ymm10\n"
    545  1.1  riastrad 	    "	vmovdqa	11*32(%[ymm]),%%ymm11\n"
    546  1.1  riastrad 	    "	vmovdqa	12*32(%[ymm]),%%ymm12\n"
    547  1.1  riastrad 	    "	vmovdqa	13*32(%[ymm]),%%ymm13\n"
    548  1.1  riastrad 	    "	vmovdqa	14*32(%[ymm]),%%ymm14\n"
    549  1.1  riastrad 	    "	vmovdqa	15*32(%[ymm]),%%ymm15\n"
    550  1.1  riastrad #endif
    551  1.1  riastrad 	    : /*out*/
    552  1.1  riastrad 	    : /*in*/ "m"(regs.ymm), [ymm]"r"(regs.ymm)
    553  1.1  riastrad 	    : /*clobber*/ "ymm0", "ymm1", "ymm2", "ymm3", "ymm4", "ymm5",
    554  1.1  riastrad 	      "ymm6", "ymm7"
    555  1.1  riastrad #ifdef __x86_64__
    556  1.1  riastrad 	    , "ymm8", "ymm9", "ymm10", "ymm11", "ymm12",
    557  1.1  riastrad 	      "ymm13", "ymm14", "ymm15"
    558  1.1  riastrad #endif
    559  1.1  riastrad 	);
    560  1.1  riastrad }
    561  1.2  riastrad 
    562  1.2  riastrad bool
    563  1.2  riastrad zmm_supported(void)
    564  1.2  riastrad {
    565  1.2  riastrad 	return cpuid(0x00000007, 0).ebx & __BIT(16);
    566  1.2  riastrad }
    567  1.2  riastrad 
    568  1.2  riastrad struct zmmregs {
    569  1.2  riastrad 	struct {
    570  1.2  riastrad 		uint8_t b[64];
    571  1.2  riastrad 	} __aligned(64)	zmm[NZMMREGS];
    572  1.2  riastrad };
    573  1.2  riastrad 
    574  1.2  riastrad __attribute__((target("avx512f")))
    575  1.2  riastrad int
    576  1.2  riastrad test_zmm(volatile bool *ready, const volatile bool *done)
    577  1.2  riastrad {
    578  1.2  riastrad 	struct zmmregs before, after;
    579  1.2  riastrad 	unsigned i;
    580  1.2  riastrad 	int error = 0;
    581  1.2  riastrad 
    582  1.2  riastrad 	/*
    583  1.2  riastrad 	 * Randomize the zmm register content.
    584  1.2  riastrad 	 */
    585  1.2  riastrad 	arc4random_buf(&before, sizeof(before));
    586  1.2  riastrad 
    587  1.2  riastrad 	/*
    588  1.2  riastrad 	 * Load up the registers, report that we're ready, busy-wait
    589  1.2  riastrad 	 * with the registers still live -- so no subroutine calls --
    590  1.2  riastrad 	 * until we're done, and then store the registers back to
    591  1.2  riastrad 	 * memory so we can check them.
    592  1.2  riastrad 	 */
    593  1.2  riastrad 	asm("\n"
    594  1.2  riastrad 	    "	vmovdqa64	0*64(%[before_zmm]),%%zmm0\n"
    595  1.2  riastrad 	    "	vmovdqa64	1*64(%[before_zmm]),%%zmm1\n"
    596  1.2  riastrad 	    "	vmovdqa64	2*64(%[before_zmm]),%%zmm2\n"
    597  1.2  riastrad 	    "	vmovdqa64	3*64(%[before_zmm]),%%zmm3\n"
    598  1.2  riastrad 	    "	vmovdqa64	4*64(%[before_zmm]),%%zmm4\n"
    599  1.2  riastrad 	    "	vmovdqa64	5*64(%[before_zmm]),%%zmm5\n"
    600  1.2  riastrad 	    "	vmovdqa64	6*64(%[before_zmm]),%%zmm6\n"
    601  1.2  riastrad 	    "	vmovdqa64	7*64(%[before_zmm]),%%zmm7\n"
    602  1.2  riastrad #ifdef __x86_64__
    603  1.2  riastrad 	    "	vmovdqa64	8*64(%[before_zmm]),%%zmm8\n"
    604  1.2  riastrad 	    "	vmovdqa64	9*64(%[before_zmm]),%%zmm9\n"
    605  1.2  riastrad 	    "	vmovdqa64	10*64(%[before_zmm]),%%zmm10\n"
    606  1.2  riastrad 	    "	vmovdqa64	11*64(%[before_zmm]),%%zmm11\n"
    607  1.2  riastrad 	    "	vmovdqa64	12*64(%[before_zmm]),%%zmm12\n"
    608  1.2  riastrad 	    "	vmovdqa64	13*64(%[before_zmm]),%%zmm13\n"
    609  1.2  riastrad 	    "	vmovdqa64	14*64(%[before_zmm]),%%zmm14\n"
    610  1.2  riastrad 	    "	vmovdqa64	15*64(%[before_zmm]),%%zmm15\n"
    611  1.2  riastrad 	    "	vmovdqa64	16*64(%[before_zmm]),%%zmm16\n"
    612  1.2  riastrad 	    "	vmovdqa64	17*64(%[before_zmm]),%%zmm17\n"
    613  1.2  riastrad 	    "	vmovdqa64	18*64(%[before_zmm]),%%zmm18\n"
    614  1.2  riastrad 	    "	vmovdqa64	19*64(%[before_zmm]),%%zmm19\n"
    615  1.2  riastrad 	    "	vmovdqa64	20*64(%[before_zmm]),%%zmm20\n"
    616  1.2  riastrad 	    "	vmovdqa64	21*64(%[before_zmm]),%%zmm21\n"
    617  1.2  riastrad 	    "	vmovdqa64	22*64(%[before_zmm]),%%zmm22\n"
    618  1.2  riastrad 	    "	vmovdqa64	23*64(%[before_zmm]),%%zmm23\n"
    619  1.2  riastrad 	    "	vmovdqa64	24*64(%[before_zmm]),%%zmm24\n"
    620  1.2  riastrad 	    "	vmovdqa64	25*64(%[before_zmm]),%%zmm25\n"
    621  1.2  riastrad 	    "	vmovdqa64	26*64(%[before_zmm]),%%zmm26\n"
    622  1.2  riastrad 	    "	vmovdqa64	27*64(%[before_zmm]),%%zmm27\n"
    623  1.2  riastrad 	    "	vmovdqa64	28*64(%[before_zmm]),%%zmm28\n"
    624  1.2  riastrad 	    "	vmovdqa64	29*64(%[before_zmm]),%%zmm29\n"
    625  1.2  riastrad 	    "	vmovdqa64	30*64(%[before_zmm]),%%zmm30\n"
    626  1.2  riastrad 	    "	vmovdqa64	31*64(%[before_zmm]),%%zmm31\n"
    627  1.2  riastrad #endif
    628  1.2  riastrad 	    "	lock\n"
    629  1.2  riastrad 	    "	orb	$1,%[ready]\n"
    630  1.2  riastrad 	    "0:	pause\n"
    631  1.2  riastrad 	    "	cmpb	$0,%[done]\n"
    632  1.2  riastrad 	    "	lfence\n"
    633  1.2  riastrad 	    "	je	0b\n"
    634  1.2  riastrad 	    "	vmovdqa64	%%zmm0,0*64(%[after_zmm])\n"
    635  1.2  riastrad 	    "	vmovdqa64	%%zmm1,1*64(%[after_zmm])\n"
    636  1.2  riastrad 	    "	vmovdqa64	%%zmm2,2*64(%[after_zmm])\n"
    637  1.2  riastrad 	    "	vmovdqa64	%%zmm3,3*64(%[after_zmm])\n"
    638  1.2  riastrad 	    "	vmovdqa64	%%zmm4,4*64(%[after_zmm])\n"
    639  1.2  riastrad 	    "	vmovdqa64	%%zmm5,5*64(%[after_zmm])\n"
    640  1.2  riastrad 	    "	vmovdqa64	%%zmm6,6*64(%[after_zmm])\n"
    641  1.2  riastrad 	    "	vmovdqa64	%%zmm7,7*64(%[after_zmm])\n"
    642  1.2  riastrad #ifdef __x86_64__
    643  1.2  riastrad 	    "	vmovdqa64	%%zmm8,8*64(%[after_zmm])\n"
    644  1.2  riastrad 	    "	vmovdqa64	%%zmm9,9*64(%[after_zmm])\n"
    645  1.2  riastrad 	    "	vmovdqa64	%%zmm10,10*64(%[after_zmm])\n"
    646  1.2  riastrad 	    "	vmovdqa64	%%zmm11,11*64(%[after_zmm])\n"
    647  1.2  riastrad 	    "	vmovdqa64	%%zmm12,12*64(%[after_zmm])\n"
    648  1.2  riastrad 	    "	vmovdqa64	%%zmm13,13*64(%[after_zmm])\n"
    649  1.2  riastrad 	    "	vmovdqa64	%%zmm14,14*64(%[after_zmm])\n"
    650  1.2  riastrad 	    "	vmovdqa64	%%zmm15,15*64(%[after_zmm])\n"
    651  1.2  riastrad 	    "	vmovdqa64	%%zmm16,16*64(%[after_zmm])\n"
    652  1.2  riastrad 	    "	vmovdqa64	%%zmm17,17*64(%[after_zmm])\n"
    653  1.2  riastrad 	    "	vmovdqa64	%%zmm18,18*64(%[after_zmm])\n"
    654  1.2  riastrad 	    "	vmovdqa64	%%zmm19,19*64(%[after_zmm])\n"
    655  1.2  riastrad 	    "	vmovdqa64	%%zmm20,20*64(%[after_zmm])\n"
    656  1.2  riastrad 	    "	vmovdqa64	%%zmm21,21*64(%[after_zmm])\n"
    657  1.2  riastrad 	    "	vmovdqa64	%%zmm22,22*64(%[after_zmm])\n"
    658  1.2  riastrad 	    "	vmovdqa64	%%zmm23,23*64(%[after_zmm])\n"
    659  1.2  riastrad 	    "	vmovdqa64	%%zmm24,24*64(%[after_zmm])\n"
    660  1.2  riastrad 	    "	vmovdqa64	%%zmm25,25*64(%[after_zmm])\n"
    661  1.2  riastrad 	    "	vmovdqa64	%%zmm26,26*64(%[after_zmm])\n"
    662  1.2  riastrad 	    "	vmovdqa64	%%zmm27,27*64(%[after_zmm])\n"
    663  1.2  riastrad 	    "	vmovdqa64	%%zmm28,28*64(%[after_zmm])\n"
    664  1.2  riastrad 	    "	vmovdqa64	%%zmm29,29*64(%[after_zmm])\n"
    665  1.2  riastrad 	    "	vmovdqa64	%%zmm30,30*64(%[after_zmm])\n"
    666  1.2  riastrad 	    "	vmovdqa64	%%zmm31,31*64(%[after_zmm])\n"
    667  1.2  riastrad #endif
    668  1.2  riastrad 	    : /*out*/ [ready]"=m"(*ready), "=m"(after.zmm)
    669  1.2  riastrad 	    : /*in*/ [done]"m"(*done), "m"(before.zmm),
    670  1.2  riastrad 	      [before_zmm]"r"(before.zmm), [after_zmm]"r"(after.zmm)
    671  1.2  riastrad 	    : /*clobber*/ "zmm0", "zmm1", "zmm2", "zmm3", "zmm4", "zmm5",
    672  1.2  riastrad 	      "zmm6", "zmm7"
    673  1.2  riastrad #ifdef __x86_64__
    674  1.2  riastrad 	    , "zmm8", "zmm9", "zmm10", "zmm11", "zmm12",
    675  1.2  riastrad 	      "zmm13", "zmm14", "zmm15", "zmm16", "zmm17",
    676  1.2  riastrad 	      "zmm18", "zmm19", "zmm20", "zmm21", "zmm22",
    677  1.2  riastrad 	      "zmm23", "zmm24", "zmm25", "zmm26", "zmm27",
    678  1.2  riastrad 	      "zmm28", "zmm29", "zmm30", "zmm31"
    679  1.2  riastrad #endif
    680  1.2  riastrad 	);
    681  1.2  riastrad 
    682  1.2  riastrad 	for (i = 0; i < __arraycount(before.zmm); i++) {
    683  1.2  riastrad 		if (memcmp(&before.zmm[i], &after.zmm[i],
    684  1.2  riastrad 			sizeof(before.zmm[i]))) {
    685  1.2  riastrad 			fprintf(stderr, "zmm%u clobbered\n", i);
    686  1.2  riastrad 			hexdump(stderr, &before.zmm[i], sizeof(before.zmm[i]),
    687  1.2  riastrad 			    "before");
    688  1.2  riastrad 			hexdump(stderr, &after.zmm[i], sizeof(after.zmm[i]),
    689  1.2  riastrad 			    "after");
    690  1.2  riastrad 			error |= 1 << i;
    691  1.2  riastrad 		}
    692  1.2  riastrad 	}
    693  1.2  riastrad 
    694  1.2  riastrad 	return error;
    695  1.2  riastrad }
    696  1.2  riastrad 
    697  1.2  riastrad __attribute__((target("avx512f")))
    698  1.2  riastrad void
    699  1.2  riastrad trash_zmm(void)
    700  1.2  riastrad {
    701  1.2  riastrad 	struct zmmregs regs;
    702  1.2  riastrad 
    703  1.2  riastrad 	arc4random_buf(&regs, sizeof(regs));
    704  1.2  riastrad 
    705  1.2  riastrad 	asm("\n"
    706  1.2  riastrad 	    "	vmovdqa64	0*64(%[zmm]),%%zmm0\n"
    707  1.2  riastrad 	    "	vmovdqa64	1*64(%[zmm]),%%zmm1\n"
    708  1.2  riastrad 	    "	vmovdqa64	2*64(%[zmm]),%%zmm2\n"
    709  1.2  riastrad 	    "	vmovdqa64	3*64(%[zmm]),%%zmm3\n"
    710  1.2  riastrad 	    "	vmovdqa64	4*64(%[zmm]),%%zmm4\n"
    711  1.2  riastrad 	    "	vmovdqa64	5*64(%[zmm]),%%zmm5\n"
    712  1.2  riastrad 	    "	vmovdqa64	6*64(%[zmm]),%%zmm6\n"
    713  1.2  riastrad 	    "	vmovdqa64	7*64(%[zmm]),%%zmm7\n"
    714  1.2  riastrad #ifdef __x86_64__
    715  1.2  riastrad 	    "	vmovdqa64	8*64(%[zmm]),%%zmm8\n"
    716  1.2  riastrad 	    "	vmovdqa64	9*64(%[zmm]),%%zmm9\n"
    717  1.2  riastrad 	    "	vmovdqa64	10*64(%[zmm]),%%zmm10\n"
    718  1.2  riastrad 	    "	vmovdqa64	11*64(%[zmm]),%%zmm11\n"
    719  1.2  riastrad 	    "	vmovdqa64	12*64(%[zmm]),%%zmm12\n"
    720  1.2  riastrad 	    "	vmovdqa64	13*64(%[zmm]),%%zmm13\n"
    721  1.2  riastrad 	    "	vmovdqa64	14*64(%[zmm]),%%zmm14\n"
    722  1.2  riastrad 	    "	vmovdqa64	15*64(%[zmm]),%%zmm15\n"
    723  1.2  riastrad 	    "	vmovdqa64	16*64(%[zmm]),%%zmm16\n"
    724  1.2  riastrad 	    "	vmovdqa64	17*64(%[zmm]),%%zmm17\n"
    725  1.2  riastrad 	    "	vmovdqa64	18*64(%[zmm]),%%zmm18\n"
    726  1.2  riastrad 	    "	vmovdqa64	19*64(%[zmm]),%%zmm19\n"
    727  1.2  riastrad 	    "	vmovdqa64	20*64(%[zmm]),%%zmm20\n"
    728  1.2  riastrad 	    "	vmovdqa64	21*64(%[zmm]),%%zmm21\n"
    729  1.2  riastrad 	    "	vmovdqa64	22*64(%[zmm]),%%zmm22\n"
    730  1.2  riastrad 	    "	vmovdqa64	23*64(%[zmm]),%%zmm23\n"
    731  1.2  riastrad 	    "	vmovdqa64	24*64(%[zmm]),%%zmm24\n"
    732  1.2  riastrad 	    "	vmovdqa64	25*64(%[zmm]),%%zmm25\n"
    733  1.2  riastrad 	    "	vmovdqa64	26*64(%[zmm]),%%zmm26\n"
    734  1.2  riastrad 	    "	vmovdqa64	27*64(%[zmm]),%%zmm27\n"
    735  1.2  riastrad 	    "	vmovdqa64	28*64(%[zmm]),%%zmm28\n"
    736  1.2  riastrad 	    "	vmovdqa64	29*64(%[zmm]),%%zmm29\n"
    737  1.2  riastrad 	    "	vmovdqa64	30*64(%[zmm]),%%zmm30\n"
    738  1.2  riastrad 	    "	vmovdqa64	31*64(%[zmm]),%%zmm31\n"
    739  1.2  riastrad #endif
    740  1.2  riastrad 	    : /*out*/
    741  1.2  riastrad 	    : /*in*/ "m"(regs.zmm), [zmm]"r"(regs.zmm)
    742  1.2  riastrad 	    : /*clobber*/ "zmm0", "zmm1", "zmm2", "zmm3", "zmm4", "zmm5",
    743  1.2  riastrad 	      "zmm6", "zmm7"
    744  1.2  riastrad #ifdef __x86_64__
    745  1.2  riastrad 	    , "zmm8", "zmm9", "zmm10", "zmm11", "zmm12",
    746  1.2  riastrad 	      "zmm13", "zmm14", "zmm15", "zmm16", "zmm17",
    747  1.2  riastrad 	      "zmm18", "zmm19", "zmm20", "zmm21", "zmm22",
    748  1.2  riastrad 	      "zmm23", "zmm24", "zmm25", "zmm26", "zmm27",
    749  1.2  riastrad 	      "zmm28", "zmm29", "zmm30", "zmm31"
    750  1.2  riastrad #endif
    751  1.2  riastrad 	);
    752  1.2  riastrad }
    753