Skip to content

C programs

xcc builds a C program the way it builds an xc one:

Terminal window
xcc -o mandel mandel.c
xcc --par-auto -o mandel mandel.c

The second form turns the program’s loops into par blocks wherever their shape allows, so the same unchanged C runs on every core and on the GPU. The source needs no pragmas or annotations. See par blocks for how a block chooses its devices.

C is an add-on: xcc uses the C compiler and headers already on the machine and ships none of its own. clang must be on the PATH:

PlatformWhat to install
macOSthe Xcode Command Line Tools (xcode-select --install)
Linuxthe distribution’s clang package
WindowsLLVM for Windows (clang on the PATH) and Microsoft’s C headers and libraries (the Visual Studio Build Tools or the Windows SDK), which that clang uses

Without clang, building a .c file stops with a C file needs clang, which compiles it. xc programs never need it.

A C program is built for the machine xcc runs on; -A does not cross-compile C.

clang turns the C into LLVM IR, before any of LLVM’s own optimisation, and xcc reads each function of it into its own IR. From there the function takes the same path as an xc one: xcc’s optimiser, its vectoriser (with SIMD copies picked at load on x86-64), the outliner that makes par blocks, and its back end and linker.

A function xcc cannot read yet is compiled by clang instead, and so are the program’s global variables; the two halves are linked into one executable. A global array of a numeric type, 64 KB or more, gets pages of its own in clang’s half, so a par block on a unified-memory GPU uses it in place (see global arrays). A variadic function’s definition is one of these, as is anything using an intrinsic, an atomic or a construct the reader does not know. Set XC_C_TRACE=1 to list each function left to clang and why:

Terminal window
XC_C_TRACE=1 xcc -o prog prog.c
xcc: C path: left to clang: @log_line
xcc: C path: because of a parameter of a type not read (in log_line: ...)

-I <dir> and -D<name>[=<value>] are passed to clang; the optimisation level (-O0 to -O3, -O3 by default) and every code-generation option are xcc’s, as for an xc program. --par-auto and the par environment variables (XC_PAR, XC_PAR_THREADS and the rest) behave as they do for xc.

On arm64 xcc fuses a multiply into the add or subtract that uses it (one rounding instead of two), as C allows and as clang does by default. A result can therefore differ from the separately rounded one in its last bits; x86-64 rounds each operation separately unless an FMA instruction is in use.

C++ is planned, through the same path: see Future work.