1

I'm trying to work through this C coding exercise, but I want to do so in Zig.

In the exercise they #import <nmmintrin.h> (@~18:15) to use __builtin_popcount. From a brief search it looks like this is a gcc-specific header file? Not sure what compiler they're using, but IIUC Zig compiles C code via clang/LLVM != gcc/GNU, right? =_=

How do I use this header from Zig? Are gcc headers supported?

CrepeGoat
  • 2,315
  • 20
  • 24
  • 1
    `__builtin_popcount` is a GNU C builtin. Headers like that define Intel intrinsics like `_mm_popcnt_u32` or `_popcnt32` as a wrapper for `__builtin_popcount` (with `#pragma GCC target("popcnt")` so it requires `-mpopcnt`, no fallback to a bithack helper function.) – Peter Cordes May 04 '23 at 20:11
  • `nmmintrin.h` is not among the headers described by the C language specification. GCC and / or Glibc do provide it, at least for x86 and x86_64. Other toolchains may provide headers with the same name and similar contents, but that does not in any way make it standard. I have no idea whether you can use it from Zig, or if so, how. – John Bollinger May 04 '23 at 20:12
  • Fun fact: GCC/clang recognize the [bithack idiom](https://stackoverflow.com/questions/109023/count-the-number-of-set-bits-in-a-32-bit-integer) and optimize it into a `popcnt` instruction if you compile with `-march=x86-64-v2` (Nehalem) or higher, so you may be able to work around it in other languages if Zig doesn't give direct access to GNU C builtins. – Peter Cordes May 04 '23 at 20:12
  • Are you interested in scalar popcount specifically, or also SIMD intrinsics like SSE4.2 `_mm_cmpgt_epi64`? (And also scalar `_mm_crc32_u64`?) Unlikely that other languages would group those all together. – Peter Cordes May 04 '23 at 22:54
  • @PeterCordes I’m pretty focused on JUST following the material for this one video lecture atm (i.e., just __builtin_popcount). For example, they DO describe your fun fact (it IS fun :]) in the video, but I’d like to call the intrinsic directly to do precisely what they do. – CrepeGoat May 05 '23 at 13:25
  • Part of the reason I’m asking is because zig is advertised heavily as “C, minus the footguns”. So I assumed I could just do an arbitrary C exercise in zig w/o too much issue – CrepeGoat May 05 '23 at 13:32
  • 1
    Ok. `__builtin_popcount` isn't from `nmmintrin.h`. It's *used by* some of the wrapper functions in `nmmintrin.h`, but it's pre-defined in GNU C by the compiler itself. https://godbolt.org/z/bKebrz9Kf is an example of using it in C without needing any headers. – Peter Cordes May 05 '23 at 19:11
  • Hmmm interesting, thanks for clarifying that! But also problematic (?): how do I import a C builtin into Zig? cImport can import C header files into Zig code, but I imagine GNU C didn’t put its builtins into a header file… – CrepeGoat May 08 '23 at 01:23
  • They aren't functions in a library that you want the compiler to generate a `call foo` for, the whole point of a builtin function is that it expands inline, often to a single instruction. Or zero instructions for something like `__atomic_thread_fence(__ATOMIC_RELEASE)` or `__builtin___clear_cache` when targeting x86, with its strong memory model and coherent I-cache. So it's not about *importing* them as C library functions. – Peter Cordes May 10 '23 at 15:47
  • 1
    Possibly since Zig compiles to C, importing might work by emitting a normal looking function-call, in which case maybe you could write your own `.h` with a prototype you wrote yourself for builtin functions like `int __builtin_popcountll(unsigned long long);` if you really wanted to do things that way instead of using Zig builtins. – Peter Cordes May 10 '23 at 15:48
  • @PeterCordes rephrasing for my understanding. so builtins in general: they're not functions per se, and they're also not macros, because they're not a "user-code" construct at all. they're just a thing that's recognized and expanded internally by the compiler. do I have that right? – CrepeGoat May 10 '23 at 17:37
  • 1
    Yes, `a = __builtin_popcount(b);` is close to `a = !b;` or `a = b+b;` in terms of how the compiler understands it - the fact that ISO C has operators for integer addition and boolean negation but not for integer popcount is just a quirk of the language. Compilers *do* support popcount as an equally primitive operation. It's not at all like a function call to an actual function in terms of how the compiler "thinks about" it, especially not to a library function. – Peter Cordes May 10 '23 at 17:40

1 Answers1

4

You wouldn't, as some comments mention these refer to GCC builtins which aren't available in Zig. Zig does expose most of these types of instructions via its own builtins though, so for instance you have @popCount, @ctz, @clz... and vector operations via the builtin @Vector type.

If for some reason you do need to use C builtins instead of the equivalents from Zig, you can always write the code using that in C and call that code from Zig (although you shouldn't have to, if a useful instruction is missing you can raise that as an issue on the compiler).

Cubic
  • 14,902
  • 5
  • 47
  • 92
  • ahhh Zig has its own popcount! and (to recap) if there's a built-in in C that I want, and Zig doesn't have an equivalent, then 1) I can request that Zig adds an equivalent and 2) as a stopgap wrap the builtin in a C function and import into Zig that wrapper func's .h file (also rec'd by @PeterCordes'). Thanks! – CrepeGoat May 10 '23 at 17:42
  • @CrepeGoat well, not all intrinsics you may find in any C compiler, but if it's a genuinely useful one it's definitely worth asking about. – Cubic May 11 '23 at 06:12