Standard conformance

badc implements C17 (ISO/IEC 9899:2018, C11 with its corrections). Without -std= it compiles C17: __STDC_VERSION__ is 201710L. -std= selects C90, C99 or C11 instead, or C23, of which badc implements part. Where this document says nothing, badc follows C17. It records:

Contents

Implementation-defined choices

Types and sizes

Each target follows its platform ABI: LP64 on macOS and Linux, LLP64 on Windows (C99 6.2.5, 6.7.2). Sizes are in bytes, and the __SIZEOF_*__ predefines report the same values.

type macos-aarch64 linux-x64 linux-aarch64 windows-x64, windows-arm64
char 1, signed 1, signed 1, unsigned 1, signed
short 2 2 2 2
int 4 4 4 4
long 8 8 8 4
long long 8 8 8 8
pointer 8 8 8 8
float 4 4 4 4
double 8 8 8 8
long double 8 16 16 8
wchar_t 4, int 4, int 4, unsigned int 2, unsigned short

The signedness of plain char (C99 6.2.5p15) follows the platform C ABI. __CHAR_UNSIGNED__ is defined where char is unsigned, and the signedness decides how a char value widens. -funsigned-char and -fsigned-char override it. -fshort-wchar makes wchar_t a 2-byte unsigned short, as in gcc.

Byte order is little-endian on every target: __BYTE_ORDER__ is __ORDER_LITTLE_ENDIAN__ and __LITTLE_ENDIAN__ is defined.

long double

long double is stored in the format of the target ABI; C99 6.2.5p10 allows any format at least as wide as double. sizeof, _Alignof, struct offsets, array stride, static initializers, <float.h> and the __LDBL_* and __SIZEOF_LONG_DOUBLE__ predefines all follow it:

target format size / align
linux-x64 x87 80-bit extended 16 / 16
linux-aarch64 IEEE binary128 16 / 16
macos-aarch64, windows-x64, windows-arm64 IEEE binary64 8 / 8

An object has the platform’s layout and encoding, so a struct, an array or a .data object shared with code built by the platform toolchain agrees byte for byte. A load converts the stored value to binary64, and a store converts it back exactly. On linux-x64 the conversions are fld and fstp, which match the hardware bit for bit, noncanonical encodings included. linux-aarch64 has no quad-precision unit; there the conversions are inline integer sequences that match gcc’s __extenddftf2 and __trunctfdf2 bit for bit.

Calls follow the platform convention, so the type crosses calls to code built by the platform toolchain, printf("%Lf", x) and strtold included:

Precision. badc computes long double arithmetic in binary64 on every target. A value that needs more than 53 significand bits does not round-trip: (unsigned long long)(long double)((1ULL<<53)+1) loses the low bit, which gcc and clang keep on linux-x64 and linux-aarch64. The stored object has the full significand of its format, but a value that went through arithmetic is already rounded to binary64. A <float.h> constant outside binary64’s range, such as LDBL_MAX on linux-x64 and linux-aarch64, evaluates to infinity. On Linux, <math.h> binds C99 7.12’s l functions to libm’s l entry points: the library computes in the full format, and the caller rounds the result to binary64 when it reads it.

Floating-point contraction

#pragma STDC FP_CONTRACT is on by default (C99 6.5p8, 7.12.2). Under -O, badc fuses a multiply with the add or subtract that uses it into one fused multiply-add when both are in one expression and the pragma is on. Without -O nothing is fused. -ffp-contract=off disables fusion. -ffp-contract=fast ignores the pragma and also fuses across expressions when the product has no other use.

#pragma STDC FENV_ACCESS and #pragma STDC CX_LIMITED_RANGE are accepted and have no effect.

_Atomic objects

_Atomic qualifies a type (C17 6.7.2.4, 6.7.3), so _Atomic int and int are different types: a pointer to one does not convert to a pointer to the other without a cast, as under gcc and clang. Reading an _Atomic object, assigning to it, ++, -- and compound assignment are seq_cst atomic operations (C17 6.2.6.1p9, 6.5.2.4p2, 6.5.16.2p3). They take the lowering of the <stdatomic.h> functions (C11 and C23):

A unit compiled with -ffreestanding or -fno-hosted takes the Windows layout and access on every target, so a freestanding image needs no runtime function for its atomic objects. A freestanding unit and a hosted one lay out such an object differently and cannot share it. MSVC does not document the values of its lock word, so an _Atomic object of a size other than 1, 2, 4 or 8 bytes cannot be shared with code MSVC compiled.

A lock word starts clear in a static object (zero-initialized), an automatic object, a compound literal and a parameter, and atomic_init clears it without taking it, so an object in allocated storage becomes valid through atomic_init (C17 7.17.2.2). A copy of an atomic object’s bytes, by memcpy or by assigning a structure holding one, copies its lock word, which is clear unless another thread holds the lock during the copy. No array type and no bit-field is _Atomic. A member of an atomic structure or union is not accessed atomically (C17 6.5.2.3p5); badc refuses the access, as clang does.

Standard predefined macros

macro value
__STDC__ 1
__STDC_HOSTED__ 1; 0 under -ffreestanding or -fno-hosted, and -fhosted restores 1
__STDC_VERSION__ 201710L; -std= selects another (Command-line compatibility)
__DATE__, __TIME__ the time of translation in UTC; SOURCE_DATE_EPOCH fixes it, as in gcc and clang
__STDC_NO_COMPLEX__, __STDC_NO_THREADS__ 1
__STDC_UTF_16__, __STDC_UTF_32__ 1
__STDC_IEC_559__, __STDC_NO_ATOMICS__, __STDC_NO_VLA__ not defined

-ffreestanding also implies -fno-builtin. --freestanding, the link option that leaves out the startup runtime, does not change __STDC_HOSTED__. __STDC_NO_ATOMICS__ is undefined: _Atomic objects are atomic (_Atomic objects).

Divergences

Features not implemented

In the same areas, these are implemented: digraphs (C99 6.4.6); universal character names in literals (6.4.3) and in identifiers, where 6.4.2.1 limits them to the Annex D ranges and the UTF-8 spelling of a character names the same identifier; and K&R identifier-list function definitions (6.11.7). A call to a _Noreturn function ends control flow for the reachability analysis behind -Wreturn-type (B3003), which reports a non-void function other than main that can reach its end. That warning is off by default and enabled by -Wall; clang enables its counterpart by default.

An inline definition serves the calls of its unit

This applies to the ELF and Mach-O targets. A function whose file-scope declarations all say inline and none says extern has an inline definition, which provides no external definition (C99 6.7.4p7), and badc emits none. gcc and clang without optimization leave a call to such a function undefined, for another unit’s external definition to satisfy. badc gives the body internal linkage and binds the unit’s calls to it, which 6.7.4p7 permits. Taking the address, with &f or by passing f, still references the external symbol, so the link fails when no unit defines it, as under gcc and clang. The PE targets use MSVC’s inline linkage instead (MSVC).

-O defines NDEBUG

-O and each of -O1, -O2, -O3, -Os, -Oz, -Ofast and -Og define NDEBUG and __OPTIMIZE__ as 1. gcc and clang define only __OPTIMIZE__. Under badc’s -O, assert (C99 7.2) expands to nothing unless the command line also has -UNDEBUG.

gcc options badc does not implement are refused

badc implements a subset of gcc’s options and has no list of options it accepts and ignores. Any other option is an error. Options that fail this way include -static, -nostdlib, -fno-common, -fomit-frame-pointer, -pipe and -march=native. A build that passes another compiler’s full flag set has to filter it. Command-line compatibility lists the options badc accepts with a narrower meaning than gcc’s.

ELF imports take their versions from a pinned manifest

A GNU linker takes each import’s symbol version from the shared library on its link path, so the image depends on the C library of the build machine. badc reads the versions from libc/versions/elf-<arch>.txt instead. Each entry is the newest version at or below a glibc 2.17 floor, or the symbol’s oldest version where the floor predates it. libc/versions/minimums.txt lists the symbols whose floor definition behaves differently from the current one, states which interface the bundled headers declare, and raises the version where only the newer definition implements it. A library named with -l supplies its own version data, so -L <sysroot>/lib -lc takes that sysroot’s versions on any host. An import the manifest gives no version stays unversioned.

Argument passing the ABI documents leave open

In the cases below the ABI document gives no rule, and gcc and clang place the value differently. badc follows one of them, so a call to or from code built by the other compiler finds the value in a different place. The Microsoft x64 convention places each of these shapes by size and is not affected.

System V AMD64: an unnamed bit-field is classified INTEGER. The psABI (3.2.3) does not say whether an unnamed bit-field takes part in classifying an eightbyte. badc follows gcc. In a structure, the bytes a non-zero width spans are INTEGER. In a union, the leading bytes its width spans are, and a zero width covers the first byte. An anonymous member’s unnamed bit-fields count at the member’s offset. clang gives an unnamed bit-field no class:

argument badc and gcc clang
struct { int :32; int :32; double d; } first eightbyte in rdi, d in xmm0, next integer in rsi d in xmm0, next integer in rdi
struct { float a; int :8; float b; } eightbyte of a in rdi, b in xmm0, next integer in rsi a in xmm0, b in xmm1, next integer in rdi
union { int :0; double d; } rdi xmm0
struct { char c[5]; union { int :24; char x; } u; float f[2]; } memory rdi and xmm0

The last row comes from the union: gcc types a union’s bit-field, named or not, as the narrowest integer mode that holds its width, and an aggregate whose union sits off that mode’s alignment is MEMORY class. AAPCS64 passes these structures in general-purpose registers under either compiler.

System V AMD64: a misaligned member past an array’s first element. The psABI sends an aggregate with an unaligned field to memory without saying how array elements count. badc follows gcc, which examines an array’s first element only: struct { struct __attribute__((packed)) { int x; char c; } a[2]; } passes in rdi and rsi. clang finds a[1].x at offset 5 and passes the structure in memory.

System V AMD64: a floating-point vector of one element. The psABI classes __m64, __m128 and the wider vector types. A float or double vector of its own width is none of them. badc follows gcc: such a vector is MEMORY class, alone or as a member of a struct, union or array, so it is passed on the stack and returned through the pointer the caller passes in rdi. clang passes the float vector, and a struct holding it, in a general-purpose register, and returns a lone double vector in xmm0. The compilers therefore disagree on float __attribute__((vector_size(4))), alone or in an aggregate, as an argument or a result, and on a lone double __attribute__((vector_size(8))) result. AAPCS64 passes a struct holding the float vector in general-purpose registers and the double vector in d0 under either compiler.

AAPCS64: a vector narrower than 8 bytes. AAPCS64 (6.4.2) defines short vectors of 8 and 16 bytes and has no rule for a narrower one. badc follows clang on every AArch64 target. Such a vector is passed as a 32-bit integer: in the low word of the next general-purpose register, else in the stack slot an int takes, which is 4 bytes at a 4-byte boundary for a named argument on macOS and 8 bytes elsewhere. It is returned in v0. float __attribute__((vector_size(4))) and a one-element vector occupy the low bytes (s0, h0 or b0). A vector of several integer elements has each element widened to an equal lane of d0: 16-bit lanes for four chars, 32-bit lanes for two shorts or two chars. gcc on Linux passes the float vector, and the arguments after it, on the stack, and returns it and the integer vectors in w0. A struct holding such a vector is passed in general-purpose registers under either compiler.

Command-line compatibility

badc accepts these gcc options with a narrower meaning than gcc’s:

options what badc does
-O1, -O2, -O3, -Os, -Oz, -Ofast, -Og Select badc’s one optimization level, as -O does. -O0 turns it off.
-g, -g1 to -g3, -ggdb, -ggdb0 to -ggdb3 Select badc’s one level of debug information.
-gdwarf, -gdwarf-<n>, -gdwarf32, -gdwarf64, -gstrict-dwarf, -gno-strict-dwarf badc writes DWARF version 4 in the 32-bit format. A request for another version from 2 to 5, or for the 64-bit format, is reported as dwarf-output (B7011) with what is written instead, and the compile continues. A version outside 2 to 5, a level above 3 or a non-integer version is refused with gcc’s message.
-gsplit-dwarf, -gz, -gline-tables-only Refused.
-mcpu=<part>[+ext...] AArch64 only. The part must be one badc knows. It selects no scheduling model, and the instructions stay the baseline. +aes, +sha2 and +crypto define the __ARM_FEATURE_* macros as gcc does.
-Wa,<opt>, -Xassembler <opt> Checked against the built-in assembler. -L and --keep-locals keep the local labels in the symbol table, as GNU as does. --fatal-warnings, -mrelax-relocations=, --noexecstack, --no-warn-rwx-segments and -march= are accepted and change nothing, because the assembler already behaves that way; -march= does not reject instructions above a lower ceiling. Any other option is refused as unsupported assembler option.

Warnings. -w, -Werror, -Wno-error, -Werror=<sel>, -Wno-error=<sel>, -W<sel>, -Wno-<sel>, -Wall, -Wextra and -Wpedantic are implemented. A selector is a diagnostic’s name, one of its aliases, its B code or a group name; --list-diagnostics prints the catalogue. A gcc or clang warning badc does not implement is accepted and reported as unimplemented-warning-option (B7012). -Wno- takes any name, as in gcc. Any other selector is refused.

#pragma GCC diagnostic, #pragma clang diagnostic and MSVC’s #pragma warning(...) take the same selectors. Each sets a diagnostic’s level from the position it appears at, for preprocessor and parser diagnostics alike. A pragma that covers a position overrides the command line, and push and pop bound the region it covers. A link diagnostic has no source position, so only the command line controls it.

Dialects. -std= takes the dialect names gcc 16 takes and refuses any other. It sets __STDC_VERSION__ as gcc does:

-std= __STDC_VERSION__
c89, c90, gnu89, gnu90, iso9899:1990 not defined
iso9899:199409 199409L
c99, c9x, gnu99, gnu9x, iso9899:1999 199901L
c11, c1x, gnu11, gnu1x, iso9899:2011 201112L
c17, c18, gnu17, gnu18, iso9899:2017, iso9899:2018; the default 201710L
c23, c2x, gnu23, gnu2x, iso9899:2024 202311L
c2y, gnu2y 202500L

From c23 on, bool, true and false are keywords, 1 and 0 in #if as well, and <stdbool.h> defines only __bool_true_false_are_defined. The GNU extensions are available in every dialect. __STRICT_ANSI__ is defined only under --gnu (GCC): a gnu* name leaves it undefined, and a c* or iso9899:* name defines it, as in gcc and clang. With --gnu and no -std=, __STRICT_ANSI__ is defined, so a header takes its standard-C path for the GNU features badc lacks. The dialect does not select the GNU89 inline model; only -fgnu89-inline does.

Extensions implemented

C11 and C23

POSIX

On macOS and Linux the bundled headers declare the platform C library’s POSIX interfaces, <dlfcn.h>, <pthread.h>, <dirent.h> and <setjmp.h> among them. struct dirent has the host C library’s layout, so readdir finds d_name where the library writes it.

On the Windows targets a header declares what mingw-w64’s header of the same name declares (native-compilation.md states the rule). Sources in libc/lib/ define the POSIX names mingw-w64 declares and msvcrt.dll does not, over kernel32, msvcrt and ucrtbase:

header names
<time.h>, <sys/time.h> clock_gettime, clock_getres, clock_settime and clock_nanosleep with mingw-w64’s clock ids; nanosleep; gettimeofday; localtime_r, gmtime_r and ctime_r under _POSIX_C_SOURCE
<dlfcn.h> dlopen, dlsym, dlclose, dlerror
<dirent.h> mingw-w64’s: opendir, readdir, closedir, rewinddir, telldir and seekdir over the kernel32 file search, with its struct dirent (d_name, d_namlen). Under msvc_compat.h’s _MSC_VER it declares nothing, as cl ships none.
<pthread.h> winpthreads’ types and numbering: threads, mutexes (normal, recursive and error-checking), condition variables on either clock, once controls, thread-specific data and creation attributes. Thread-specific data destructors also run when a thread started with CreateThread exits, and none run at process exit. Cancellation, pthread_kill and the scheduling setters of a running thread are not declared.
<semaphore.h> winpthreads’: unnamed semaphores; sem_open, sem_close and sem_unlink fail with ENOSYS
<getopt.h>, <unistd.h> libmingwex’s getopt, getopt_long and getopt_long_only with their state (getopt stops at the first operand, the long forms permute); sleep, usleep, ftruncate, truncate
<libgen.h>, <ftw.h> basename and dirname, which handle \ and drive letters; ftw
<stdlib.h>, <stdio.h>, <string.h> mkstemp, mkdtemp; getline, getdelim, dprintf, vdprintf; strndup, memmem
<fnmatch.h>, <regex.h>, <search.h> fnmatch; regcomp, regexec, regerror and regfree (basic and extended syntax); tsearch, tfind, tdelete, twalk, tdestroy
<fenv.h> feraiseexcept

The CRT’s chmod, mktemp and exec family are bound under their POSIX names. iswblank, wctype, wctrans and towctrans, which msvcrt.dll lacks, are bound to ucrtbase.dll. A POSIX name mingw-w64 does not declare is not declared.

GCC

Builtins. These are available without a header:

__builtin_clz(0) and __builtin_ctz(0) return the operand width on every target and in the interpreter; gcc leaves them undefined. __builtin_unreachable becomes a trap instruction, so reaching it aborts. __builtin_has_attribute is accepted and always yields 0.

The __builtin_ spelling of a library function that gcc or clang provide as the function itself calls the library function of that name. This covers the stdio, stdlib, string, ctype, wide-character and math functions, among others. The parser binds the call through the symbol table. The call takes the function’s declaration, a header the unit did not include is included as for the plain name, and a macro of the library name in the unit, as fortified string headers define, does not capture the builtin spelling. gcc’s __builtin_setjmp and __builtin_longjmp, which take a five-word buffer, are not provided. __builtin_isdigit, __builtin_isascii and __builtin_toascii fold from their operand as gcc folds them. __builtin_strlen, strcmp, strncmp, memcmp, abs and its wider forms also fold with literal operands. __builtin_expect, __builtin_prefetch, __builtin_assume_aligned and the infinity and NaN constants are parsed at the call site with gcc’s signatures and operand checks, so they work in preprocessed input too. __builtin_nan folds a string literal’s payload as gcc does and calls nan for any other operand.

The __sync_* and __atomic_* families are recognized by prefix and lowered at the call site, so a name outside the C11 set also compiles. The memory order of an __atomic_* call selects the instructions as for <stdatomic.h>. __sync_lock_release is a release store, __sync_synchronize a seq_cst fence, and the other __sync_* operations are seq_cst.

Inline assembly. asm and __asm__ (C99 J.5.10) on both architectures: the basic form, the extended form asm(template : outputs : inputs : clobbers) with register, memory and immediate constraints, asm goto, __attribute__((naked)) function bodies, and file-scope asm(...). The same assembler builds .s and .S files (badc -c foo.S -o foo.o). It implements a subset of GNU as; linux-kernel.md has coverage figures. File-scope asm(...) belongs to no function: its text reaches the object as written, and the assembler and linker resolve the names in it. Naming a static definition there does not keep the definition; mark it __attribute__((used)), as gcc requires at -O2. A static named in a template inside a function body is kept.

Where the Intel SDM and GNU as encode an x86 instruction differently, badc follows the SDM, and the operand width as written selects the encoding. Six forms differ from GNU as. With a 64-bit register, mov to and from a segment register (8C, 8E), sldt, str, lar and lsl (0F 00 /0, 0F 00 /1, 0F 02, 0F 03) take the REX.W prefix, which GNU as omits and clang emits. Both forms write 16 bits and zero the rest. smsw with a 64-bit register keeps REX.W in GNU as too, and the control- and debug-register moves take no prefix in either.

Assembler names. T name asm("label") on an object or a function, at file or block scope, sets the assembler symbol name the declaration emits. The identifier stays the lookup key, the redeclaration match and the name diagnostics use. The label composes with extern, static, weak, alias and the visibility attributes, and reaches the object writers, the linker and inline-asm references to the name. Two declarations of one identifier with different labels are rejected. A label on an automatic object is ignored with a warning (ignored-asm-label). On ELF and PE the symbol is the label as written. On Mach-O badc prefixes the label with the _ it gives every C name, where gcc and clang emit the label as written.

Attributes. __attribute__((...)), __declspec(...) and C23 [[...]] attributes are parsed. These take effect:

attribute effect
packed Packs a structure or union. An anonymous union inside a packed structure keeps its members overlapping.
aligned(N), aligned, _Alignas Sets the alignment; bare aligned is 16.
section("name") Places the object or function in that section.
alias("target") Defines the name as an alias of target.
visibility("kind") default, hidden, protected or internal, written to the ELF symbol.
weak A weak definition or reference. On Mach-O a reference binds as a weak import, and the link fails when no input defines the name, as under ld64.
weak_import Mach-O only: as weak.
selectany The link keeps one unit’s definition.
used Keeps a definition nothing references.
naked The function has no prologue or epilogue.
always_inline, noinline, gnu_inline Inlining control. always_inline applies without -O too.
ms_abi, sysv_abi The x86-64 calling convention of a function or of a function pointer’s pointee. Ignored on AArch64, as in gcc.
cleanup(fn) Calls fn on every exit from the scope, goto and asm goto included. A jump into the scope past the declaration is rejected, as clang does; gcc accepts it.
constructor, destructor Runs the function before or after main, with an optional priority.
noreturn As _Noreturn.
unused, maybe_unused Silences the unused-entity warnings.
vector_size(N) Makes a vector type.
mode(M) The integer or floating type of machine mode M.
transparent_union A parameter of the union type accepts an argument of any member’s type.
designated_init A positional initializer for the structure is diagnosed.
no_instrument_function No -pg profiling call.
no_stack_protector No stack canary under -fstack-protector*.
uninitialized The automatic object is exempt from -ftrivial-auto-var-init.
patchable_function_entry(N[,M]) NOP padding at the function entry, as -fpatchable-function-entry.
__declspec(thread) As _Thread_local.
dllexport, dllimport PE targets: exports the definition; a dllimport reference reads the import-address slot __imp_<name>, as MSVC, mingw-w64 gcc and clang emit it. Elsewhere dllimport is ignored with a warning and dllexport without one.

Other attributes, such as format, pure, const, deprecated and fallthrough, are parsed and discarded without a diagnostic. __has_attribute answers 1 for a fixed list of gcc attribute names wider than the set above. It answers 0 for vector_size, mode, ms_abi, sysv_abi, selectany and weak_import, although badc honours them, and for dllexport and dllimport outside the PE targets, as gcc does. The [[...]] form honours the attributes without arguments plus aligned, constructor and destructor. It drops any other attribute with arguments, so [[gnu::section("x")]] has no effect while __attribute__((section("x"))) does.

Vector arguments. A vector_size(N) value crosses a call in the SIMD argument registers. The System V AMD64 psABI (3.2.3) classes a 16-byte vector SSE and SSEUP and gives it one xmm0-xmm7 register. AAPCS64 (6.4.2, stage C.1) assigns a 64- or 128-bit short vector to v0-v7. A result is returned in xmm0 or v0. A variadic vector uses the same registers, counted in al on System V and read back from the vector save area. Windows x64 passes a 16-byte vector by implicit reference, as its convention states, and macOS arm64 puts variadic arguments on the stack, as its variant of AAPCS64 states. On System V a vector wider than a register (32 bytes and up) goes to memory, as gcc places it without -mavx; AAPCS64 passes it by reference. A floating-point vector of one element also goes to memory on System V (Divergences). A struct of two to four vectors of one width, an AAPCS64 homogeneous vector aggregate, takes one of v0-v7 per vector.

Intrinsic headers

On the x86-64 targets the compiler’s own headers provide a subset of the Intel intrinsics, reached through <x86intrin.h> or <immintrin.h>. Most operations lower to the instruction the Intel SDM gives for them, through __builtin_ia32_* builtins with gcc’s names. The composition intrinsics (_mm_set*, _mm_setr*, _mm_cvtsi*), _mm_loadl_epi64, _mm_storel_epi64, the SSE3 floating operations and the __m64 operations are written lane by lane over the vector extension; the __m64 ones use no MMX register. An operation outside the subset is absent, so a unit that needs one fails at the undeclared name.

header contents
<mmintrin.h> MMX: gcc’s __m64 operations and their _m_ names; _mm_empty executes emms.
<xmmintrin.h> SSE: __m128, _MM_SHUFFLE, MXCSR access, _mm_sfence, _mm_pause and the __m64 operations. No packed-single arithmetic.
<emmintrin.h> SSE2 on __m128i: add and subtract, _mm_mullo_epi16, _mm_mulhi_epi16, _mm_madd_epi16, logic, compares, packs, interleaves, immediate shifts, shuffles, element access, _mm_movemask_epi8, loads and stores; _mm_set*, _mm_setr* and _mm_cvtsi*; _mm_shuffle_pd; the __m128i / __m128d casts; the fences.
<pmmintrin.h> SSE3: addsub, horizontal add and subtract, lddqu, the duplicating moves and loads, monitor and mwait.
<tmmintrin.h> SSSE3: _mm_shuffle_epi8 and the __m64 forms.
<smmintrin.h> SSE4.1: _mm_cmpeq_epi64, _mm_extract_epi32, _mm_insert_epi32.
<wmmintrin.h> AES-NI and _mm_clmulepi64_si128.
<immintrin.h> The above, _rdrand16_step, _rdrand32_step, _rdrand64_step, _xgetbv, _mm_popcnt_u32 and _mm_popcnt_u64.
<x86intrin.h> The above and the scalar set: byte swaps, bit scans, rotates, rdtsc, rdtscp, rdpmc and the RFLAGS access.

Not provided: packed-single arithmetic, packed-double operations other than _mm_shuffle_pd and the SSE3 ones, the 128-bit saturating, averaging, minimum, maximum and absolute-difference integer operations, shifts by a vector count, the 128-bit non-temporal stores, and everything past SSE4.1 (AVX, AVX2, AVX-512, FMA). _mm_load_si128 and _mm_store_si128 use the unaligned move. An intrinsic whose last operand is an imm8 is a macro, as gcc’s are without -O. The rest are static inline functions, which -O inlines so the instruction appears at the call site; without -O they stay calls.

On the AArch64 targets <arm_neon.h> provides a subset of the ACLE NEON intrinsics. For the integer vectors: vld1 and vst1, bitwise operations, immediate shifts, vdup, the polynomial byte multiply, table lookups, byte equality, halfword reversal, the across-lanes minimum and 64-bit lane composition. The FEAT_AES rounds and the 64-bit carry-less multiply. For float32x2_t, float32x4_t, float64x1_t and float64x2_t: loads and stores, arithmetic, square root, fused multiply-add, compares, vbsl, conversions, lane access, vget_low, vget_high, vcombine and the reinterpretations. Lane-indexed multiplies, rounding, estimates, structure loads (vld2 to vld4), float16 and bfloat16 are not provided.

MSVC

badc-specific

Roadmap

  1. long double arithmetic at the precision of the target’s storage format.
  2. Structured exception handling under --interp and --jit.
  3. ELF import versions for a named library: a link that names a real shared object (-L <sysroot>/lib -lc) takes that library’s version data, so it can bind a definition whose interface differs from the one the bundled headers declare.

^ To the top