mirror_zfs/include/sys/simd_config.h

103 lines
3.5 KiB
C
Raw Normal View History

// SPDX-License-Identifier: CDDL-1.0
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or https://opensource.org/licenses/CDDL-1.0.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright (c) 2026, TrueNAS.
*/
#ifndef _SYS_SIMD_CONFIG_H
#define _SYS_SIMD_CONFIG_H
/*
* Goal: a HAVE_SIMD(x) macro that expands to either 1 or 0 depending on
* the availabilty of that extension on the wanted toolchain.
*
* We need to allow the following:
* - #define HAVE_TOOLCHAIN_AVX 1 (zfs_config.h, detected by configure)
* - #undef HAVE_TOOLCHAIN_AVX (zfs_config.h, probed but not detected)
* - -DHAVE_TOOLCHAIN_AVX (Makefile.bsd)
*
* For completeness, we also allow disabling by defined HAVE_TOOLCHAIN_AVX=0.
*
* The "obvious" implementation of this would be a macro that includes
* defined(...) in its expansion, but unfortunately that is not portable, and
* can produce compiler warnings (see -Wexpansion-to-defined). So we need to
* build our own version.
*/
/*
* 1. Expand incoming token to its defined value, if anything:
* eg HAVE_SIMD(AVX)
* -> _zfs_deftrue(HAVE_TOOLCHAIN_AVX)
* or -> __zfs_deftrue() (HAVE_TOOLCHAIN_AVX defined)
* or -> __zfs_deftrue(1) (HAVE_TOOLCHAIN_AVX = 1)
* -> __zfs_deftrue(0) (HAVE_TOOLCHAIN_AVX = 0)
* or -> __zfs_deftrue(HAVE_TOOLCHAIN_AVX) (HAVE_TOOLCHAIN_AVX undef)
*/
#define _zfs_deftrue(x) __zfs_deftrue(x)
/*
* 2. Replace know values with a token that we control:
* __zfs_deftrue()
* -> ___zfs_deftrue(___zfs_deftrue_arg_)
* __zfs_deftrue(1)
* -> ___zfs_deftrue(___zfs_deftrue_arg_1)
* __zfs_deftrue(0)
* -> ___zfs_deftrue(___zfs_deftrue_arg_0)
* __zfs_deftrue(HAVE_TOOLCHAIN_AVX)
* -> ___zfs_deftrue(___zfs_deftrue_arg_HAVE_TOOLCHAIN_AVX)
*/
#define __zfs_deftrue(v) ___zfs_deftrue(___zfs_deftrue_arg_##v)
/*
* 3. Expand the incoming token into positional parameters for the next call:
* ___zfs_deftrue(___zfs_deftrue_arg_0)
* -> ____zfs_deftrue(0, 0, 0)
* ___zfs_deftrue(___zfs_deftrue_arg_1)
* -> ____zfs_deftrue(0, 1, 0)
* ___zfs_deftrue(___zfs_deftrue_arg_HAVE_TOOLCHAIN_AVX)
* -> ____zfs_deftrue(___zfs_deftrue_arg_HAVE_TOOLCHAIN_AVX, 0)
*/
#define ___zfs_deftrue_arg_ 0, 1
#define ___zfs_deftrue_arg_1 0, 1
#define ___zfs_deftrue_arg_0 0, 0
#define ___zfs_deftrue(t, ...) ____zfs_deftrue(t, 0)
/*
* 4. Emit the second argument, either the original value or the default 0.
* ____zfs_deftrue(0, 0, 0) -> 0
* ____zfs_deftrue(0, 1, 0) -> 1
* ____zfs_deftrue(___zfs_deftrue_arg_HAVE_TOOLCHAIN_AVX, 0) -> 0
*/
#define ____zfs_deftrue(_n, v, ...) v
/*
* The Linux kernel requires a specific toolchain. Everything else uses the
* regular compiler toolchain.
*/
#if defined(_KERNEL) && defined(__linux__)
#define HAVE_SIMD(ext) _zfs_deftrue(HAVE_KERNEL_##ext)
#else
#define HAVE_SIMD(ext) _zfs_deftrue(HAVE_TOOLCHAIN_##ext)
#endif
#endif