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(®s, 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(®s, 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(®s, 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