Skip to content

port: Use __cpuid only, when available.#1887

Merged
Dead2 merged 1 commit intozlib-ng:developfrom
winspool:cpuid
Apr 15, 2025
Merged

port: Use __cpuid only, when available.#1887
Dead2 merged 1 commit intozlib-ng:developfrom
winspool:cpuid

Conversation

@winspool
Copy link
Copy Markdown
Contributor

@winspool winspool commented Mar 23, 2025

Add a fallback, when __cpuid is not available.

This allows other compiler to build zlib-ng.
tcc as example
(compiling zlib-ng with OpenWatcom needs a C99 feature, which has issues in OW)

Regards ... Detlef

Summary by CodeRabbit

  • New Features
    • Improved detection of CPU instruction support for different compilers, enhancing compatibility on x86 systems.
  • Bug Fixes
    • More robust handling of CPU feature detection to ensure correct functionality across various compiler environments.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 23, 2025

Walkthrough

The changes introduce improved detection and handling of x86 CPU feature intrinsics in the build system and runtime code. Specifically, the build configuration (both CMake and configure script) now checks for the availability of GNU-style (__cpuid_count) and MSVC-style (__cpuidex) CPU instruction intrinsics, defining HAVE_CPUID_GNU or HAVE_CPUID_MS macros accordingly. The runtime x86 feature detection code is refactored to use these macros for more granular and accurate compiler-specific code paths, with explicit fallback behavior when neither intrinsic is available. No public APIs or exported declarations are altered.

Changes

File(s) Change Summary
CMakeLists.txt, configure Added feature detection for GNU and MSVC x86 CPU intrinsics (__cpuid_count, __cpuidex) and defined HAVE_CPUID_GNU/HAVE_CPUID_MS macros.
arch/x86/x86_features.c Refactored to use HAVE_CPUID_GNU/HAVE_CPUID_MS macros for conditional compilation of cpuid, cpuidex, and xgetbv implementations.

Sequence Diagram(s)

sequenceDiagram
    participant BuildSystem as Build System (CMake/configure)
    participant Compiler as Compiler
    participant Source as x86_features.c

    BuildSystem->>Compiler: Test for __cpuid_count (GNU)
    alt Supported
        BuildSystem->>BuildSystem: Define HAVE_CPUID_GNU
    else Not Supported
        BuildSystem->>Compiler: Test for __cpuidex (MSVC)
        alt Supported
            BuildSystem->>BuildSystem: Define HAVE_CPUID_MS
        else Not Supported
            BuildSystem->>BuildSystem: No CPUID macro defined
        end
    end

    Source->>Source: Use HAVE_CPUID_GNU or HAVE_CPUID_MS for feature detection
    Source->>Source: Fallback to zeroed registers if neither defined
Loading

Suggested labels

Architecture

Suggested reviewers

  • Dead2

Tip

⚡💬 Agentic Chat (Pro Plan, General Availability)
  • We're introducing multi-step agentic chat in review comments and issue comments, within and outside of PR's. This feature enhances review and issue discussions with the CodeRabbit agentic chat by enabling advanced interactions, including the ability to create pull requests directly from comments and add commits to existing pull requests.

📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d106b20 and 731dfd6.

📒 Files selected for processing (3)
  • CMakeLists.txt (1 hunks)
  • arch/x86/x86_features.c (2 hunks)
  • configure (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • arch/x86/x86_features.c
  • CMakeLists.txt
  • configure
⏰ Context from checks skipped due to timeout of 90000ms (70)
  • GitHub Check: macOS GCC UBSAN (ARM64)
  • GitHub Check: macOS Clang ASAN (ARM64)
  • GitHub Check: Ubuntu GCC No Chorba
  • GitHub Check: Ubuntu GCC Native Instructions (AVX)
  • GitHub Check: Ubuntu GCC -O1 UBSAN
  • GitHub Check: Ubuntu GCC -O3 OSB
  • GitHub Check: macOS GCC Symbol Prefix
  • GitHub Check: macOS GCC UBSAN (ARM64)
  • GitHub Check: macOS Clang ASAN (ARM64)
  • GitHub Check: Ubuntu GCC No Chorba
  • GitHub Check: Ubuntu GCC Native Instructions (AVX)
  • GitHub Check: Ubuntu GCC -O1 UBSAN
  • GitHub Check: Ubuntu GCC -O3 OSB
  • GitHub Check: macOS GCC Symbol Prefix
  • GitHub Check: macOS GCC UBSAN (ARM64)
  • GitHub Check: macOS Clang ASAN (ARM64)
  • GitHub Check: Ubuntu GCC No Chorba
  • GitHub Check: Ubuntu GCC Native Instructions (AVX)
  • GitHub Check: Ubuntu GCC -O1 UBSAN
  • GitHub Check: Ubuntu GCC -O3 OSB
  • GitHub Check: macOS GCC Symbol Prefix
  • GitHub Check: macOS GCC UBSAN (ARM64)
  • GitHub Check: macOS Clang ASAN (ARM64)
  • GitHub Check: Ubuntu GCC No Chorba
  • GitHub Check: Ubuntu GCC Native Instructions (AVX)
  • GitHub Check: Ubuntu GCC -O1 UBSAN
  • GitHub Check: Ubuntu GCC -O3 OSB
  • GitHub Check: macOS GCC Symbol Prefix
  • GitHub Check: macOS GCC UBSAN (ARM64)
  • GitHub Check: macOS Clang ASAN (ARM64)
  • GitHub Check: Ubuntu GCC No Chorba
  • GitHub Check: Ubuntu GCC Native Instructions (AVX)
  • GitHub Check: Ubuntu GCC -O1 UBSAN
  • GitHub Check: Ubuntu GCC -O3 OSB
  • GitHub Check: macOS GCC Symbol Prefix
  • GitHub Check: macOS GCC UBSAN (ARM64)
  • GitHub Check: macOS Clang ASAN (ARM64)
  • GitHub Check: Ubuntu GCC No Chorba
  • GitHub Check: Ubuntu GCC Native Instructions (AVX)
  • GitHub Check: Ubuntu GCC -O1 UBSAN
  • GitHub Check: Ubuntu GCC -O3 OSB
  • GitHub Check: macOS GCC Symbol Prefix
  • GitHub Check: macOS GCC UBSAN (ARM64)
  • GitHub Check: macOS Clang ASAN (ARM64)
  • GitHub Check: Ubuntu GCC No Chorba
  • GitHub Check: Ubuntu GCC Native Instructions (AVX)
  • GitHub Check: Ubuntu GCC -O1 UBSAN
  • GitHub Check: Ubuntu GCC -O3 OSB
  • GitHub Check: macOS GCC Symbol Prefix
  • GitHub Check: macOS GCC UBSAN (ARM64)
  • GitHub Check: macOS Clang ASAN (ARM64)
  • GitHub Check: Ubuntu GCC No Chorba
  • GitHub Check: Ubuntu GCC Native Instructions (AVX)
  • GitHub Check: Ubuntu GCC -O1 UBSAN
  • GitHub Check: Ubuntu GCC -O3 OSB
  • GitHub Check: macOS GCC Symbol Prefix
  • GitHub Check: macOS GCC UBSAN (ARM64)
  • GitHub Check: macOS Clang ASAN (ARM64)
  • GitHub Check: Ubuntu GCC No Chorba
  • GitHub Check: Ubuntu GCC Native Instructions (AVX)
  • GitHub Check: Ubuntu GCC -O1 UBSAN
  • GitHub Check: Ubuntu GCC -O3 OSB
  • GitHub Check: macOS GCC Symbol Prefix
  • GitHub Check: macOS GCC UBSAN (ARM64)
  • GitHub Check: macOS Clang ASAN (ARM64)
  • GitHub Check: Ubuntu GCC No Chorba
  • GitHub Check: Ubuntu GCC Native Instructions (AVX)
  • GitHub Check: Ubuntu GCC -O1 UBSAN
  • GitHub Check: Ubuntu GCC -O3 OSB
  • GitHub Check: macOS GCC Symbol Prefix

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@codecov
Copy link
Copy Markdown

codecov bot commented Mar 23, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 81.68%. Comparing base (00a3168) to head (731dfd6).
Report is 2 commits behind head on develop.

Additional details and impacted files
@@             Coverage Diff              @@
##           develop    #1887       +/-   ##
============================================
+ Coverage    40.29%   81.68%   +41.39%     
============================================
  Files           73      145       +72     
  Lines         7684    13067     +5383     
  Branches      1281     2914     +1633     
============================================
+ Hits          3096    10674     +7578     
+ Misses        4363     1444     -2919     
- Partials       225      949      +724     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
CMakeLists.txt (1)

493-500: Robust Check for GNU-style cpuid Support

The new hunk clearly checks for the availability of the GNU-specific __cpuid_count in cpuid.h. The comment explains that even though gcc/clang and MSVC have a built-in __cpuid, this check ensures that the proper GNU extension is available before defining HAVE_CPUID_GNU. Also, resetting CMAKE_REQUIRED_DEFINITIONS after the check is a good practice to avoid side effects in subsequent tests.

Consider adding a brief inline note on when this macro will be used in the source code (i.e., in place of the traditional MSVC check) for future maintainers.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fd0d263 and 192acfa.

📒 Files selected for processing (3)
  • CMakeLists.txt (1 hunks)
  • arch/x86/x86_features.c (2 hunks)
  • configure (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (40)
  • GitHub Check: Windows GCC Native Instructions (AVX)
  • GitHub Check: EL9 GCC S390X DFLTCC ASAN
  • GitHub Check: Ubuntu GCC AARCH64 Compat No Opt
  • GitHub Check: macOS GCC Symbol Prefix & Compat
  • GitHub Check: Windows GCC Native Instructions (AVX)
  • GitHub Check: EL9 GCC S390X DFLTCC ASAN
  • GitHub Check: Ubuntu GCC AARCH64 Compat No Opt
  • GitHub Check: macOS GCC Symbol Prefix & Compat
  • GitHub Check: Windows GCC Native Instructions (AVX)
  • GitHub Check: EL9 GCC S390X DFLTCC ASAN
  • GitHub Check: Ubuntu GCC AARCH64 Compat No Opt
  • GitHub Check: macOS GCC Symbol Prefix & Compat
  • GitHub Check: Windows GCC Native Instructions (AVX)
  • GitHub Check: EL9 GCC S390X DFLTCC ASAN
  • GitHub Check: Ubuntu GCC AARCH64 Compat No Opt
  • GitHub Check: macOS GCC Symbol Prefix & Compat
  • GitHub Check: Windows GCC Native Instructions (AVX)
  • GitHub Check: EL9 GCC S390X DFLTCC ASAN
  • GitHub Check: Ubuntu GCC AARCH64 Compat No Opt
  • GitHub Check: macOS GCC Symbol Prefix & Compat
  • GitHub Check: Windows GCC Native Instructions (AVX)
  • GitHub Check: EL9 GCC S390X DFLTCC ASAN
  • GitHub Check: Ubuntu GCC AARCH64 Compat No Opt
  • GitHub Check: macOS GCC Symbol Prefix & Compat
  • GitHub Check: Windows GCC Native Instructions (AVX)
  • GitHub Check: EL9 GCC S390X DFLTCC ASAN
  • GitHub Check: Ubuntu GCC AARCH64 Compat No Opt
  • GitHub Check: macOS GCC Symbol Prefix & Compat
  • GitHub Check: Windows GCC Native Instructions (AVX)
  • GitHub Check: EL9 GCC S390X DFLTCC ASAN
  • GitHub Check: Ubuntu GCC AARCH64 Compat No Opt
  • GitHub Check: macOS GCC Symbol Prefix & Compat
  • GitHub Check: Windows GCC Native Instructions (AVX)
  • GitHub Check: EL9 GCC S390X DFLTCC ASAN
  • GitHub Check: Ubuntu GCC AARCH64 Compat No Opt
  • GitHub Check: macOS GCC Symbol Prefix & Compat
  • GitHub Check: Windows GCC Native Instructions (AVX)
  • GitHub Check: EL9 GCC S390X DFLTCC ASAN
  • GitHub Check: Ubuntu GCC AARCH64 Compat No Opt
  • GitHub Check: macOS GCC Symbol Prefix & Compat
🔇 Additional comments (9)
CMakeLists.txt (1)

502-510: Robust Check for MSVC-style cpuid Support

This block mirrors the GNU check for the MSVC-specific __cpuidex using intrin.h. It correctly defines HAVE_CPUID_MS if the symbol is available. The comments and the structure make it easy to understand that the fallback mechanism now distinguishes between GNU and MSVC extensions.

arch/x86/x86_features.c (5)

13-17: Improved preprocessor conditionals for better portability.

This change replaces direct compiler checks with feature-based macros, improving portability across different compilers.


31-42: Refactored implementation selection for better maintainability.

This change uses feature-based macros instead of compiler-specific checks, making the code more maintainable and easier to extend for additional compilers.


43-44: Enhanced fallback mechanism with clear performance implications.

The added comment provides important context about performance implications when falling back to the non-optimized path.


61-62: Consistent error handling in cpuidex function.

Good addition of the comment explaining performance implications, consistent with other similar changes in the file.


74-75: Improved xgetbv fallback with explicit return value.

The fallback now returns 0 instead of no operation, and includes a comment about performance implications, making the code more robust and clear.

configure (3)

810-837: Added GNU-style __cpuid detection.

This new block adds runtime detection of GNU compiler's __cpuid support, enhancing compatibility with various compilers by conditionally defining HAVE_CPUID_GNU when available.


838-865: Added Microsoft-style __cpuid detection.

This block implements detection for Microsoft's __cpuid intrinsic, which complements the GNU-style detection and properly defines HAVE_CPUID_MS when available.


867-870: Well-structured separation markers.

These separators maintain the script's readability with clear section boundaries between the new cpuid detection blocks and the rest of the configure checks.

@mtl1979
Copy link
Copy Markdown
Collaborator

mtl1979 commented Mar 24, 2025

Detection doesn't seem to work most of the time with Visual C++ and breaks build...

@winspool
Copy link
Copy Markdown
Contributor Author

winspool commented Mar 24, 2025

Detection doesn't seem to work most of the time with Visual C++ and breaks build...

Upps, sorry.
Using cmake or configure?
Can you please give me the failure message?

I have no MSVC installed had hoped, everything was ok.

I will take a look next weekend.

@mtl1979
Copy link
Copy Markdown
Collaborator

mtl1979 commented Apr 1, 2025

Detection doesn't seem to work most of the time with Visual C++ and breaks build...

Upps, sorry. Using cmake or configure? Can you please give me the failure message?

I have no MSVC installed had hoped, everything was ok.

I will take a look next weekend.

One can only use CMake with Visual C++. It fails while configuring the build in CI...

The error while configuring is:
error C7552: '__cpuidex': purely intrinsic functions have no address

@winspool
Copy link
Copy Markdown
Contributor Author

winspool commented Apr 1, 2025

Thanks, that helps.

(I don't have Windows with Visual Studio running yet...)

I found a list of MSVC x86 intinsics,
so cmake will also also fail to detect "__cpuid".

I have to find a different way.

@mtl1979
Copy link
Copy Markdown
Collaborator

mtl1979 commented Apr 2, 2025

Thanks, that helps.

(I don't have Windows with Visual Studio running yet...)

I found a list of MSVC x86 intinsics, so cmake will also also fail to detect "__cpuid".

I have to find a different way.

Best solution I think is to just try to compile small snippet of code using the intrinsic like we do in other places. When I want to make sure nothing gets optimized away when compiler does dead code elimination, I just coarse the result of intrinsic call to fit in the return value of "main" function. Because the snippet isn't (doesn't need to) actually run, not returning 0 doesn't matter.

@winspool
Copy link
Copy Markdown
Contributor Author

winspool commented Apr 5, 2025

That's what i prepared (similar code, wht is used in configure)

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 192acfa and 740c987.

📒 Files selected for processing (3)
  • CMakeLists.txt (1 hunks)
  • arch/x86/x86_features.c (2 hunks)
  • configure (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • arch/x86/x86_features.c
  • CMakeLists.txt
🔇 Additional comments (2)
configure (2)

835-862:

Details

❓ Verification inconclusive

Check for MS-style __cpuid function support added

This block adds detection of Microsoft-style __cpuid support by testing compilation of code that uses the function from <intrin.h>, setting HAVE_CPUID_MS when available.

Based on the PR comments, there might be issues with MSVC and intrinsic functions. This detection mechanism might fail because intrinsic functions don't have addresses. Run this script to verify behavior with different compilers:


🏁 Script executed:

#!/bin/bash
# Create test file for MS-style __cpuid
cat > test_ms_cpuid.c << 'EOF'
#include <intrin.h>
#include <stdio.h>
static inline void cpuid_ms(int info, unsigned int *eax, unsigned int *ebx, unsigned int *ecx, unsigned int *edx) {
    unsigned int registers[4];
    __cpuid((int *)registers, info);
    *eax = registers[0];
    *ebx = registers[1];
    *ecx = registers[2];
    *edx = registers[3];
}

int main(void) {
  unsigned int eax, ebx, ecx, edx;
  cpuid_ms(0, &eax, &ebx, &ecx, &edx);
  printf("%d\n", eax);
  return 0;
}
EOF

# Check which compilers are available and test compilation
for compiler in gcc clang cl cc; do
  if command -v $compiler > /dev/null 2>&1; then
    echo "Testing MS-style __cpuid with $compiler:"
    if [ "$compiler" = "cl" ]; then
      $compiler test_ms_cpuid.c -c 2>&1 | grep -i cpuid
    else
      $compiler -c test_ms_cpuid.c 2>&1 | grep -i cpuid
    fi
    echo "Exit code: $?"
  fi
done

Length of output: 209


Action Required: Manually Verify MS-style __cpuid Detection

The added code block correctly tests for the availability of Microsoft-style __cpuid by attempting to compile a snippet that uses the intrinsic from <intrin.h>. However, the automated test script produced no output or errors, leaving uncertainty as to whether the detection might fail (particularly with MSVC, where intrinsic functions might not behave as expected with regards to addressability).

  • Verify manually with MSVC and other supported compilers to ensure that the intrinsic behaves as assumed and that HAVE_CPUID_MS is correctly set.
  • Check that the detection logic accounts for potential issues with intrinsic function addresses.

810-833:

Details

✅ Verification successful

Check for GNU-style __cpuid function support added

This block adds detection of GNU-style __cpuid support by testing compilation of code that uses the function, setting HAVE_CPUID_GNU when available.

Verify that this detection works consistently across different compilers:


🏁 Script executed:

#!/bin/bash
# Check how GNU-style __cpuid is implemented in cpuid.h across different compilers
if [ -f /usr/include/cpuid.h ]; then
  echo "Found cpuid.h in system includes. Examining its contents:"
  grep -A 10 "__cpuid" /usr/include/cpuid.h
else
  echo "cpuid.h not found in standard location"
fi

# Check which compilers are available and how they handle __cpuid
for compiler in gcc clang cc; do
  if command -v $compiler > /dev/null 2>&1; then
    echo "Testing $compiler:"
    $compiler -dM -E -x c /dev/null | grep -i cpuid
  fi
done

Length of output: 265


GNU-style __cpuid Detection Block Verified
The detection code in configure (lines 810–833) successfully compiles the test snippet and correctly sets the HAVE_CPUID_GNU flag when GNU-style __cpuid support is available. Note that on the test system the script did not find a cpuid.h in /usr/include, which can be expected in environments where the header is provided via alternate include paths. Please ensure that your target environments have the appropriate include paths so that the compile test in configure works reliably across different compilers.

Comment on lines +810 to +865
# check for cpuid support: GNU extensions
cat > $test.c <<EOF
#include <cpuid.h>
#include <stdio.h>
static inline void cpuid_gnu(int info, unsigned int *eax, unsigned int *ebx, unsigned int *ecx, unsigned int *edx) {
*eax = *ebx = *ecx = *edx = 0;
__cpuid(info, *eax, *ebx, *ecx, *edx);
}

int main(void) {
unsigned int eax, ebx, ecx, edx;
cpuid_gnu(0, &eax, &ebx, &ecx, &edx);
printf("%d\n", eax);
return eax;
}
EOF
if try $CC $CFLAGS -o $test $test.c $LDSHAREDLIBC; then
echo "Checking for GNU style __cpuid... Yes." | tee -a configure.log
CFLAGS="${CFLAGS} -DHAVE_CPUID_GNU"
SFLAGS="${SFLAGS} -DHAVE_CPUID_GNU"
else
echo "Checking for GNU style __cpuid... No." | tee -a configure.log
fi
echo >> configure.log

# check for cpuid support: MSVC extensions
cat > $test.c <<EOF
#include <intrin.h>
#include <stdio.h>
static inline void cpuid_ms(int info, unsigned int *eax, unsigned int *ebx, unsigned int *ecx, unsigned int *edx) {
unsigned int registers[4];
__cpuid((int *)registers, info);
*eax = registers[0];
*ebx = registers[1];
*ecx = registers[2];
*edx = registers[3];
}

int main(void) {
unsigned int eax, ebx, ecx, edx;
cpuid_ms(0, &eax, &ebx, &ecx, &edx);
printf("%d\n", eax);
return 0;
}
EOF
if try $CC $CFLAGS -o $test $test.c $LDSHAREDLIBC; then
echo "Checking for MS style __cpuid... Yes." | tee -a configure.log
CFLAGS="${CFLAGS} -DHAVE_CPUID_MS"
SFLAGS="${SFLAGS} -DHAVE_CPUID_MS"
else
echo "Checking for MS style __cpuid... No." | tee -a configure.log
fi
echo >> configure.log

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot Apr 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Consider alternative detection approach for MSVC

The detection methods for both GNU and MSVC-style __cpuid functions rely on successful compilation of test programs. However, according to the PR comments, this may not work reliably with Visual C++ due to intrinsic functions not having addresses.

Consider implementing an alternative detection approach for MSVC similar to mtl1979's suggestion in the PR comments - try compiling a small code snippet that uses the intrinsic and coerces the result into the return value of the main function to prevent the compiler from optimizing it away. This would be more reliable for detecting intrinsic function availability.

-cat > $test.c <<EOF
-#include <intrin.h>
-#include <stdio.h>
-static inline void cpuid_ms(int info, unsigned int *eax, unsigned int *ebx, unsigned int *ecx, unsigned int *edx) {
-    unsigned int registers[4];
-    __cpuid((int *)registers, info);
-    *eax = registers[0];
-    *ebx = registers[1];
-    *ecx = registers[2];
-    *edx = registers[3];
-}
-
-int main(void) {
-  unsigned int eax, ebx, ecx, edx;
-  cpuid_ms(0, &eax, &ebx, &ecx, &edx);
-  printf("%d\n", eax);
-  return 0;
-}
+cat > $test.c <<EOF
+#include <intrin.h>
+int main(void) {
+    int cpu_info[4] = {0};
+    __cpuid(cpu_info, 0);
+    return cpu_info[0] & 0x1; /* Just to prevent optimization, actual value doesn't matter */
+}
EOF
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
# check for cpuid support: GNU extensions
cat > $test.c <<EOF
#include <cpuid.h>
#include <stdio.h>
static inline void cpuid_gnu(int info, unsigned int *eax, unsigned int *ebx, unsigned int *ecx, unsigned int *edx) {
*eax = *ebx = *ecx = *edx = 0;
__cpuid(info, *eax, *ebx, *ecx, *edx);
}
int main(void) {
unsigned int eax, ebx, ecx, edx;
cpuid_gnu(0, &eax, &ebx, &ecx, &edx);
printf("%d\n", eax);
return eax;
}
EOF
if try $CC $CFLAGS -o $test $test.c $LDSHAREDLIBC; then
echo "Checking for GNU style __cpuid... Yes." | tee -a configure.log
CFLAGS="${CFLAGS} -DHAVE_CPUID_GNU"
SFLAGS="${SFLAGS} -DHAVE_CPUID_GNU"
else
echo "Checking for GNU style __cpuid... No." | tee -a configure.log
fi
echo >> configure.log
# check for cpuid support: MSVC extensions
cat > $test.c <<EOF
#include <intrin.h>
#include <stdio.h>
static inline void cpuid_ms(int info, unsigned int *eax, unsigned int *ebx, unsigned int *ecx, unsigned int *edx) {
unsigned int registers[4];
__cpuid((int *)registers, info);
*eax = registers[0];
*ebx = registers[1];
*ecx = registers[2];
*edx = registers[3];
}
int main(void) {
unsigned int eax, ebx, ecx, edx;
cpuid_ms(0, &eax, &ebx, &ecx, &edx);
printf("%d\n", eax);
return 0;
}
EOF
if try $CC $CFLAGS -o $test $test.c $LDSHAREDLIBC; then
echo "Checking for MS style __cpuid... Yes." | tee -a configure.log
CFLAGS="${CFLAGS} -DHAVE_CPUID_MS"
SFLAGS="${SFLAGS} -DHAVE_CPUID_MS"
else
echo "Checking for MS style __cpuid... No." | tee -a configure.log
fi
echo >> configure.log
# check for cpuid support: GNU extensions
cat > $test.c <<EOF
#include <cpuid.h>
#include <stdio.h>
static inline void cpuid_gnu(int info, unsigned int *eax, unsigned int *ebx, unsigned int *ecx, unsigned int *edx) {
*eax = *ebx = *ecx = *edx = 0;
__cpuid(info, *eax, *ebx, *ecx, *edx);
}
int main(void) {
unsigned int eax, ebx, ecx, edx;
cpuid_gnu(0, &eax, &ebx, &ecx, &edx);
printf("%d\n", eax);
return eax;
}
EOF
if try $CC $CFLAGS -o $test $test.c $LDSHAREDLIBC; then
echo "Checking for GNU style __cpuid... Yes." | tee -a configure.log
CFLAGS="${CFLAGS} -DHAVE_CPUID_GNU"
SFLAGS="${SFLAGS} -DHAVE_CPUID_GNU"
else
echo "Checking for GNU style __cpuid... No." | tee -a configure.log
fi
echo >> configure.log
# check for cpuid support: MSVC extensions
cat > $test.c <<EOF
#include <intrin.h>
int main(void) {
int cpu_info[4] = {0};
__cpuid(cpu_info, 0);
return cpu_info[0] & 0x1; /* Just to prevent optimization, actual value doesn't matter */
}
EOF
if try $CC $CFLAGS -o $test $test.c $LDSHAREDLIBC; then
echo "Checking for MS style __cpuid... Yes." | tee -a configure.log
CFLAGS="${CFLAGS} -DHAVE_CPUID_MS"
SFLAGS="${SFLAGS} -DHAVE_CPUID_MS"
else
echo "Checking for MS style __cpuid... No." | tee -a configure.log
fi
echo >> configure.log

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment from coderabbitai
uses shorter code to test for "__cpuid" availability on MSVC,
but my test code is similar to the code, what "zlib-ng" is using.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@winspool I understand your reasoning. Using test code that closely resembles how zlib-ng actually uses the __cpuid function in the codebase is a valid approach. This helps ensure that detection works correctly for the specific usage patterns in the project. Your implementation will likely be more robust for your specific use case since it tests the function in a way that matches its actual usage.

@phprus
Copy link
Copy Markdown
Contributor

phprus commented Apr 5, 2025

Missing HAVE_CPUID_MS macro in https://github.com/zlib-ng/zlib-ng/blob/develop/win32/Makefile.msc

@winspool
Copy link
Copy Markdown
Contributor Author

winspool commented Apr 5, 2025

Missing HAVE_CPUID_MS macro in develop/win32/Makefile.msc

Thanks for the hint.
I added the missing flags for my recent code changes.
Should work now.

@mtl1979
Copy link
Copy Markdown
Collaborator

mtl1979 commented Apr 10, 2025

All the relevant CI runs are now passing, so last remaining check is verifying the tests give correct results...

@winspool
Copy link
Copy Markdown
Contributor Author

What else can i do to get this change accepted?

Copy link
Copy Markdown
Member

@Dead2 Dead2 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@Dead2
Copy link
Copy Markdown
Member

Dead2 commented Apr 14, 2025

@winspool Sorry, this needs a rebase now.

Add a fallback, when __cpuid is not available
@winspool
Copy link
Copy Markdown
Contributor Author

@winspool Sorry, this needs a rebase now.

np. Rebased to current head.

@Dead2 Dead2 merged commit 5a23268 into zlib-ng:develop Apr 15, 2025
136 of 141 checks passed

#
# Check for x86 __cpuid / __cpuidex support: MSVC extensions
# gcc/clang and MSVC have __cpuid, so check __cpuidex instead
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so check __cpuidex

but the code bellow checks for __cpuid? Kind of confusing

@Dead2 Dead2 mentioned this pull request Nov 5, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants