aboutsummaryrefslogtreecommitdiff
path: root/sys/contrib/openzfs/module/zstd/lib/common/cpu.h
diff options
context:
space:
mode:
Diffstat (limited to 'sys/contrib/openzfs/module/zstd/lib/common/cpu.h')
-rw-r--r--sys/contrib/openzfs/module/zstd/lib/common/cpu.h40
1 files changed, 37 insertions, 3 deletions
diff --git a/sys/contrib/openzfs/module/zstd/lib/common/cpu.h b/sys/contrib/openzfs/module/zstd/lib/common/cpu.h
index 8e02d30bf9ba..0cd7aa09c758 100644
--- a/sys/contrib/openzfs/module/zstd/lib/common/cpu.h
+++ b/sys/contrib/openzfs/module/zstd/lib/common/cpu.h
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0-only
/*
- * Copyright (c) 2018-2020, Facebook, Inc.
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
* All rights reserved.
*
* This source code is licensed under both the BSD-style license (found in the
@@ -17,8 +17,6 @@
* https://github.com/facebook/folly/blob/master/folly/CpuId.h
*/
-#include <string.h>
-
#include "mem.h"
#ifdef _MSC_VER
@@ -38,6 +36,7 @@ MEM_STATIC ZSTD_cpuid_t ZSTD_cpuid(void) {
U32 f7b = 0;
U32 f7c = 0;
#if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_IX86))
+#if !defined(_M_X64) || !defined(__clang__) || __clang_major__ >= 16
int reg[4];
__cpuid((int*)reg, 0);
{
@@ -53,6 +52,41 @@ MEM_STATIC ZSTD_cpuid_t ZSTD_cpuid(void) {
f7c = (U32)reg[2];
}
}
+#else
+ /* Clang compiler has a bug (fixed in https://reviews.llvm.org/D101338) in
+ * which the `__cpuid` intrinsic does not save and restore `rbx` as it needs
+ * to due to being a reserved register. So in that case, do the `cpuid`
+ * ourselves. Clang supports inline assembly anyway.
+ */
+ U32 n;
+ __asm__(
+ "pushq %%rbx\n\t"
+ "cpuid\n\t"
+ "popq %%rbx\n\t"
+ : "=a"(n)
+ : "a"(0)
+ : "rcx", "rdx");
+ if (n >= 1) {
+ U32 f1a;
+ __asm__(
+ "pushq %%rbx\n\t"
+ "cpuid\n\t"
+ "popq %%rbx\n\t"
+ : "=a"(f1a), "=c"(f1c), "=d"(f1d)
+ : "a"(1)
+ :);
+ }
+ if (n >= 7) {
+ __asm__(
+ "pushq %%rbx\n\t"
+ "cpuid\n\t"
+ "movq %%rbx, %%rax\n\t"
+ "popq %%rbx"
+ : "=a"(f7b), "=c"(f7c)
+ : "a"(7), "c"(0)
+ : "rdx");
+ }
+#endif
#elif defined(__i386__) && defined(__PIC__) && !defined(__clang__) && defined(__GNUC__)
/* The following block like the normal cpuid branch below, but gcc
* reserves ebx for use of its pic register so we must specially