1 // SPDX-License-Identifier: CDDL-1.0 2 /* 3 * CDDL HEADER START 4 * 5 * The contents of this file are subject to the terms of the 6 * Common Development and Distribution License (the "License"). 7 * You may not use this file except in compliance with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or https://opensource.org/licenses/CDDL-1.0. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright (c) 2026, TrueNAS. 24 */ 25 26 #ifndef _SYS_SIMD_CONFIG_H 27 #define _SYS_SIMD_CONFIG_H 28 29 /* 30 * Goal: a HAVE_SIMD(x) macro that expands to either 1 or 0 depending on 31 * the availabilty of that extension on the wanted toolchain. 32 * 33 * We need to allow the following: 34 * - #define HAVE_TOOLCHAIN_AVX 1 (zfs_config.h, detected by configure) 35 * - #undef HAVE_TOOLCHAIN_AVX (zfs_config.h, probed but not detected) 36 * - -DHAVE_TOOLCHAIN_AVX (Makefile.bsd) 37 * 38 * For completeness, we also allow disabling by defined HAVE_TOOLCHAIN_AVX=0. 39 * 40 * The "obvious" implementation of this would be a macro that includes 41 * defined(...) in its expansion, but unfortunately that is not portable, and 42 * can produce compiler warnings (see -Wexpansion-to-defined). So we need to 43 * build our own version. 44 */ 45 46 /* 47 * 1. Expand incoming token to its defined value, if anything: 48 * eg HAVE_SIMD(AVX) 49 * -> _zfs_deftrue(HAVE_TOOLCHAIN_AVX) 50 * or -> __zfs_deftrue() (HAVE_TOOLCHAIN_AVX defined) 51 * or -> __zfs_deftrue(1) (HAVE_TOOLCHAIN_AVX = 1) 52 * -> __zfs_deftrue(0) (HAVE_TOOLCHAIN_AVX = 0) 53 * or -> __zfs_deftrue(HAVE_TOOLCHAIN_AVX) (HAVE_TOOLCHAIN_AVX undef) 54 */ 55 #define _zfs_deftrue(x) __zfs_deftrue(x) 56 57 /* 58 * 2. Replace know values with a token that we control: 59 * __zfs_deftrue() 60 * -> ___zfs_deftrue(___zfs_deftrue_arg_) 61 * __zfs_deftrue(1) 62 * -> ___zfs_deftrue(___zfs_deftrue_arg_1) 63 * __zfs_deftrue(0) 64 * -> ___zfs_deftrue(___zfs_deftrue_arg_0) 65 * __zfs_deftrue(HAVE_TOOLCHAIN_AVX) 66 * -> ___zfs_deftrue(___zfs_deftrue_arg_HAVE_TOOLCHAIN_AVX) 67 */ 68 #define __zfs_deftrue(v) ___zfs_deftrue(___zfs_deftrue_arg_##v) 69 70 /* 71 * 3. Expand the incoming token into positional parameters for the next call: 72 * ___zfs_deftrue(___zfs_deftrue_arg_0) 73 * -> ____zfs_deftrue(0, 0, 0) 74 * ___zfs_deftrue(___zfs_deftrue_arg_1) 75 * -> ____zfs_deftrue(0, 1, 0) 76 * ___zfs_deftrue(___zfs_deftrue_arg_HAVE_TOOLCHAIN_AVX) 77 * -> ____zfs_deftrue(___zfs_deftrue_arg_HAVE_TOOLCHAIN_AVX, 0) 78 */ 79 #define ___zfs_deftrue_arg_ 0, 1 80 #define ___zfs_deftrue_arg_1 0, 1 81 #define ___zfs_deftrue_arg_0 0, 0 82 #define ___zfs_deftrue(t, ...) ____zfs_deftrue(t, 0) 83 84 /* 85 * 4. Emit the second argument, either the original value or the default 0. 86 * ____zfs_deftrue(0, 0, 0) -> 0 87 * ____zfs_deftrue(0, 1, 0) -> 1 88 * ____zfs_deftrue(___zfs_deftrue_arg_HAVE_TOOLCHAIN_AVX, 0) -> 0 89 */ 90 #define ____zfs_deftrue(_n, v, ...) v 91 92 /* 93 * The Linux kernel requires a specific toolchain. Everything else uses the 94 * regular compiler toolchain. 95 */ 96 #if defined(_KERNEL) && defined(__linux__) 97 #define HAVE_SIMD(ext) _zfs_deftrue(HAVE_KERNEL_##ext) 98 #else 99 #define HAVE_SIMD(ext) _zfs_deftrue(HAVE_TOOLCHAIN_##ext) 100 #endif 101 102 #endif 103