While debugging can be helpful to just pre-process files.

gcc -E [-dM] ...
  • -E run only preprocessor
  • -dM list only #define statements
  • -### dry-run, outputting exact compiler/linker invocations
  • -print-multi-lib print available multilib configurations
  • --help=<class> print description of cmdline options for given class, eg warnings, optimizers, target, c, c++

Target options

# List all target options with their description.
gcc --help=target

# Configure for current cpu arch and query (-Q) value of options.
gcc -march=native -Q --help=target

Warnings / optimizations

# List available warnings with short description.
gcc --help=warnings
# List available optimizations with short description.
gcc --help=optimizers

# Prepend --help with `-Q` to print wheter options are enabled or disabled
# instead showing their description.


__builtin_expect(expr, cond)

Give the compiler a hint which branch is hot, so it can lay out the code accordingly to reduce number of jump instructions. See on compiler explorer.

The semantics of this hint are as follows, the compiler prioritises expr == cond. So __builtin_expect(expr, 0) means that we expect the expr to be 0 most of the time.

echo "
extern void foo();
extern void bar();
void run0(int x) {
  if (__builtin_expect(x,0)) { foo(); }
  else { bar(); }
void run1(int x) {
  if (__builtin_expect(x,1)) { foo(); }
  else { bar(); }
" | gcc -O2 -S -masm=intel -o /dev/stdout -xc -

Will generate something similar to the following.

  • run0: bar is on the path without branch
  • run1: foo is on the path without branch
        test    edi, edi
        jne     .L4
        xor     eax, eax
        jmp     bar
        xor     eax, eax
        jmp     foo
        test    edi, edi
        je      .L6
        xor     eax, eax
        jmp     foo
        xor     eax, eax
        jmp     bar

ABI (Linux)