xref: /src/sys/contrib/openzfs/include/sys/simd_config.h (revision 80aae8a3f8aa70712930664572be9e6885dc0be7)
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