GCC(1)

๐Ÿ“ฆ
version 9.5.0 ยท 2 versions
, in ubuntu noble

๐Ÿ’– GCC(1) ๐Ÿ’–

Heyyy bestie ๐Ÿซถ this is the manual page for gcc, the GNU project C and C++ compiler, and it is about to be SO good. Let's go ๐Ÿ’…

โœจ NAME โœจ

gcc - GNU project C and C++ compiler ๐ŸŒธ

โœจ SYNOPSIS โœจ

gcc [-c|-S|-E] [-std=standard]
    [-g] [-pg] [-Olevel]
    [-Wwarn...] [-Wpedantic]
    [-Idir...] [-Ldir...]
    [-Dmacro[=defn]...] [-Umacro]
    [-foption...] [-mmachine-option...]
    [-o outfile] [@file] infile...

Okay so this is only the most useful options ๐Ÿงš The rest are down below. Also, g++ takes mostly the same options as gcc, so you're not learning two whole different vibes ๐Ÿ’œ

โœจ DESCRIPTION โœจ

Okay so when you invoke GCC, it normally does preprocessing, compilation, assembly and linking, all in one go โœจ The "overall options" let you stop that whole process at an intermediate stage. For example, the -c option says don't run the linker ๐Ÿฆ‹ Then what you get back is object files spit out by the assembler.

Other options get passed along to one or more stages. Some control the preprocessor, some control the compiler itself, and yet others control the assembler and linker. Most of those last ones aren't documented here, because honestly you almost never need them ๐Ÿ™ˆ

Most of the command-line options are useful for C programs. When an option is only useful with another language (usually C++), the explanation will say so explicitly. If an option's description doesn't mention a source language, you can use it with all supported languages ๐ŸŒˆ

The usual way to run GCC is the executable called gcc, or machine-gcc when you're cross-compiling, or machine-gcc-version if you want one specific version of GCC. When you compile C++ programs, you should invoke GCC as g++ instead ๐Ÿ‘‘

The gcc program takes options and file names as operands. Lots of options have multi-letter names, so multiple single-letter options can't be grouped together. -dv is very different from -d -v ๐Ÿ’€

You can mix options and other arguments, and for the most part the order doesn't matter. Order does matter when you use several options of the same kind. For example, if you specify -L more than once, the directories get searched in the order you specified them. Also, where you put the -l option is significant ๐Ÿ”ฅ

Many options have long names starting with -f or with -W---for example, -fmove-loop-invariants, -Wformat and so on. Most of these have both a positive and a negative form, and the negative form of -ffoo is -fno-foo. This manual only documents one of the two forms, whichever one is not the default โœจ

Some options take one or more arguments, usually separated from the option name by either a space or an equals sign (=). Unless documented otherwise, an argument can be numeric or a string. Numeric arguments must typically be small unsigned decimal or hexadecimal integers, and hexadecimal arguments must begin with the 0x prefix ๐Ÿ“

Arguments to options that set a size threshold can be arbitrarily large decimal or hexadecimal integers followed by a byte size suffix. That suffix is a multiple of bytes, like "kB" and "KiB" for kilobyte and kibibyte, respectively, "MB" and "MiB" for megabyte and mebibyte, "GB" and "GiB" for gigabyte and gigibyte, and so on. These arguments get called byte-size in the rest of the text. For the full listing of the binary and decimal byte size prefixes, check the NIST, IEC, and other relevant national and international standards ๐ŸŽ€

โœจ OPTIONS โœจ

โœจ Option Summary โœจ

Here's a summary of all the options, grouped by type, so you can get the big picture first ๐Ÿฆ‹ The explanations come in the sections after this.

๐ŸŒธ Overall Options

-c  -S  -E  -o file  -x language -v  -###  --help[=class[,...]]
--target-help  --version -pass-exit-codes  -pipe  -specs=file
-wrapper @file  -ffile-prefix-map=old=new -fplugin=file
-fplugin-arg-name=arg -fdump-ada-spec[-slim]  -fada-spec-parent=unit
-fdump-go-spec=file

๐Ÿ’œ C Language Options

-ansi  -std=standard  -fgnu89-inline
-fpermitted-flt-eval-methods=standard -aux-info filename
-fallow-parameterless-variadic-functions -fno-asm  -fno-builtin
-fno-builtin-function  -fgimple -fhosted  -ffreestanding -fopenacc
-fopenacc-dim=geom -fopenmp  -fopenmp-simd -fms-extensions
-fplan9-extensions  -fsso-struct=endianness -fallow-single-precision
-fcond-mismatch  -flax-vector-conversions -fsigned-bitfields
-fsigned-char -funsigned-bitfields  -funsigned-char

๐Ÿ”ฅ C++ Language Options

-fabi-version=n  -fno-access-control -faligned-new=n
-fargs-in-order=n  -fchar8_t  -fcheck-new -fconstexpr-depth=n
-fconstexpr-loop-limit=n -fconstexpr-ops-limit=n
-fno-elide-constructors -fno-enforce-eh-specs -fno-gnu-keywords
-fno-implicit-templates -fno-implicit-inline-templates
-fno-implement-inlines  -fms-extensions -fnew-inheriting-ctors
-fnew-ttp-matching -fno-nonansi-builtins  -fnothrow-opt
-fno-operator-names -fno-optional-diags  -fpermissive
-fno-pretty-templates -frepo  -fno-rtti  -fsized-deallocation
-ftemplate-backtrace-limit=n -ftemplate-depth=n
-fno-threadsafe-statics  -fuse-cxa-atexit -fno-weak  -nostdinc++
-fvisibility-inlines-hidden -fvisibility-ms-compat
-fext-numeric-literals -Wabi=n  -Wabi-tag  -Wconversion-null
-Wctor-dtor-privacy -Wdelete-non-virtual-dtor  -Wdeprecated-copy
-Wdeprecated-copy-dtor -Wliteral-suffix -Wmultiple-inheritance
-Wno-init-list-lifetime -Wnamespaces  -Wnarrowing -Wpessimizing-move
-Wredundant-move -Wnoexcept  -Wnoexcept-type  -Wclass-memaccess
-Wnon-virtual-dtor  -Wreorder  -Wregister -Weffc++
-Wstrict-null-sentinel  -Wtemplates -Wno-non-template-friend
-Wold-style-cast -Woverloaded-virtual  -Wno-pmf-conversions
-Wno-class-conversion  -Wno-terminate -Wsign-promo
-Wvirtual-inheritance

๐Ÿฆ‹ Objective-C and Objective-C++ Language Options

-fconstant-string-class=class-name -fgnu-runtime  -fnext-runtime
-fno-nil-receivers -fobjc-abi-version=n -fobjc-call-cxx-cdtors
-fobjc-direct-dispatch -fobjc-exceptions -fobjc-gc -fobjc-nilcheck
-fobjc-std=objc1 -fno-local-ivars
-fivar-visibility=[public|protected|private|package]
-freplace-objc-classes -fzero-link -gen-decls -Wassign-intercept
-Wno-protocol  -Wselector -Wstrict-selector-match
-Wundeclared-selector

๐Ÿงš Diagnostic Message Formatting Options

-fmessage-length=n -fdiagnostics-show-location=[once|every-line]
-fdiagnostics-color=[auto|never|always]
-fdiagnostics-format=[text|json] -fno-diagnostics-show-option
-fno-diagnostics-show-caret -fno-diagnostics-show-labels
-fno-diagnostics-show-line-numbers
-fdiagnostics-minimum-margin-width=width
-fdiagnostics-parseable-fixits  -fdiagnostics-generate-patch
-fdiagnostics-show-template-tree  -fno-elide-type -fno-show-column

โš ๏ธ Warning Options โš ๏ธ

Okay bestie, this is the warning squad, and it is THICK ๐Ÿ’€ The original just drops these names with no explanations in this part, so I'm lining up the whole crew exactly as written ๐Ÿ’…

  • -fsyntax-only
  • -fmax-errors=n
  • -Wpedantic
  • -pedantic-errors
  • -w
  • -Wextra
  • -Wall
  • -Waddress
  • -Waddress-of-packed-member
  • -Waggregate-return
  • -Waligned-new
  • -Walloc-zero
  • -Walloc-size-larger-than=byte-size
  • -Walloca
  • -Walloca-larger-than=byte-size
  • -Wno-aggressive-loop-optimizations
  • -Warray-bounds
  • -Warray-bounds=n
  • -Wno-attributes
  • -Wattribute-alias=n
  • -Wbool-compare
  • -Wbool-operation
  • -Wno-builtin-declaration-mismatch
  • -Wno-builtin-macro-redefined
  • -Wc90-c99-compat
  • -Wc99-c11-compat
  • -Wc11-c2x-compat
  • -Wc++-compat
  • -Wc++11-compat
  • -Wc++14-compat
  • -Wc++17-compat
  • -Wcast-align
  • -Wcast-align=strict
  • -Wcast-function-type
  • -Wcast-qual
  • -Wchar-subscripts
  • -Wcatch-value
  • -Wcatch-value=n
  • -Wclobbered
  • -Wcomment
  • -Wconditionally-supported
  • -Wconversion
  • -Wcoverage-mismatch
  • -Wno-cpp
  • -Wdangling-else
  • -Wdate-time
  • -Wdelete-incomplete
  • -Wno-attribute-warning
  • -Wno-deprecated
  • -Wno-deprecated-declarations
  • -Wno-designated-init
  • -Wdisabled-optimization
  • -Wno-discarded-qualifiers
  • -Wno-discarded-array-qualifiers
  • -Wno-div-by-zero
  • -Wdouble-promotion
  • -Wduplicated-branches
  • -Wduplicated-cond
  • -Wempty-body
  • -Wenum-compare
  • -Wno-endif-labels
  • -Wexpansion-to-defined
  • -Werror
  • -Werror=*
  • -Wextra-semi
  • -Wfatal-errors
  • -Wfloat-equal
  • -Wformat
  • -Wformat=2
  • -Wno-format-contains-nul
  • -Wno-format-extra-args
  • -Wformat-nonliteral
  • -Wformat-overflow=n
  • -Wformat-security
  • -Wformat-signedness
  • -Wformat-truncation=n
  • -Wformat-y2k
  • -Wframe-address
  • -Wframe-larger-than=byte-size
  • -Wno-free-nonheap-object
  • -Wjump-misses-init
  • -Whsa
  • -Wif-not-aligned
  • -Wignored-qualifiers
  • -Wignored-attributes
  • -Wincompatible-pointer-types
  • -Wimplicit
  • -Wimplicit-fallthrough
  • -Wimplicit-fallthrough=n
  • -Wimplicit-function-declaration
  • -Wimplicit-int
  • -Winit-self
  • -Winline
  • -Wno-int-conversion
  • -Wint-in-bool-context
  • -Wno-int-to-pointer-cast
  • -Winvalid-memory-model
  • -Wno-invalid-offsetof
  • -Winvalid-pch
  • -Wlarger-than=byte-size
  • -Wlogical-op
  • -Wlogical-not-parentheses
  • -Wlong-long
  • -Wmain
  • -Wmaybe-uninitialized
  • -Wmemset-elt-size
  • -Wmemset-transposed-args
  • -Wmisleading-indentation
  • -Wmissing-attributes
  • -Wmissing-braces
  • -Wmissing-field-initializers
  • -Wmissing-format-attribute
  • -Wmissing-include-dirs
  • -Wmissing-noreturn
  • -Wmissing-profile
  • -Wno-multichar
  • -Wmultistatement-macros
  • -Wnonnull
  • -Wnonnull-compare
  • -Wnormalized=[none|id|nfc|nfkc]
  • -Wnull-dereference
  • -Wodr
  • -Wno-overflow
  • -Wopenmp-simd
  • -Woverride-init-side-effects
  • -Woverlength-strings
  • -Wpacked
  • -Wpacked-bitfield-compat
  • -Wpacked-not-aligned
  • -Wpadded
  • -Wparentheses
  • -Wno-pedantic-ms-format
  • -Wplacement-new
  • -Wplacement-new=n
  • -Wpointer-arith
  • -Wpointer-compare
  • -Wno-pointer-to-int-cast
  • -Wno-pragmas
  • -Wno-prio-ctor-dtor
  • -Wredundant-decls
  • -Wrestrict
  • -Wno-return-local-addr
  • -Wreturn-type
  • -Wsequence-point
  • -Wshadow
  • -Wno-shadow-ivar
  • -Wshadow=global,
  • -Wshadow=local,
  • -Wshadow=compatible-local
  • -Wshift-overflow
  • -Wshift-overflow=n
  • -Wshift-count-negative
  • -Wshift-count-overflow
  • -Wshift-negative-value
  • -Wsign-compare
  • -Wsign-conversion
  • -Wfloat-conversion
  • -Wno-scalar-storage-order
  • -Wsizeof-pointer-div
  • -Wsizeof-pointer-memaccess
  • -Wsizeof-array-argument
  • -Wstack-protector
  • -Wstack-usage=byte-size
  • -Wstrict-aliasing
  • -Wstrict-aliasing=n
  • -Wstrict-overflow
  • -Wstrict-overflow=n
  • -Wstringop-overflow=n
  • -Wstringop-truncation
  • -Wsubobject-linkage
  • -Wsuggest-attribute=[pure|const|noreturn|format|malloc]
  • -Wsuggest-final-types
  • -Wsuggest-final-methods
  • -Wsuggest-override
  • -Wswitch
  • -Wswitch-bool
  • -Wswitch-default
  • -Wswitch-enum
  • -Wswitch-unreachable
  • -Wsync-nand
  • -Wsystem-headers
  • -Wtautological-compare
  • -Wtrampolines
  • -Wtrigraphs
  • -Wtype-limits
  • -Wundef
  • -Wuninitialized
  • -Wunknown-pragmas
  • -Wunsuffixed-float-constants
  • -Wunused
  • -Wunused-function
  • -Wunused-label
  • -Wunused-local-typedefs
  • -Wunused-macros
  • -Wunused-parameter
  • -Wno-unused-result
  • -Wunused-value
  • -Wunused-variable
  • -Wunused-const-variable
  • -Wunused-const-variable=n
  • -Wunused-but-set-parameter
  • -Wunused-but-set-variable
  • -Wuseless-cast
  • -Wvariadic-macros
  • -Wvector-operation-performance
  • -Wvla
  • -Wvla-larger-than=byte-size
  • -Wvolatile-register-var
  • -Wwrite-strings
  • -Wzero-as-null-pointer-constant

โœจ C and Objective-C-only Warning Options โœจ

These ones are the C and Objective-C-only crew ๐Ÿงš Same deal, just the names, no cap:

  • -Wbad-function-cast
  • -Wmissing-declarations
  • -Wmissing-parameter-type
  • -Wmissing-prototypes
  • -Wnested-externs
  • -Wold-style-declaration
  • -Wold-style-definition
  • -Wstrict-prototypes
  • -Wtraditional
  • -Wtraditional-conversion
  • -Wdeclaration-after-statement
  • -Wpointer-sign

๐Ÿž Debugging Options ๐Ÿž

Debugging era, bestie ๐Ÿฆ‹ Here's the whole glow-up lineup:

  • -g
  • -glevel
  • -gdwarf
  • -gdwarf-version
  • -ggdb
  • -grecord-gcc-switches
  • -gno-record-gcc-switches
  • -gstabs
  • -gstabs+
  • -gstrict-dwarf
  • -gno-strict-dwarf
  • -gas-loc-support
  • -gno-as-loc-support
  • -gas-locview-support
  • -gno-as-locview-support
  • -gcolumn-info
  • -gno-column-info
  • -gstatement-frontiers
  • -gno-statement-frontiers
  • -gvariable-location-views
  • -gno-variable-location-views
  • -ginternal-reset-location-views
  • -gno-internal-reset-location-views
  • -ginline-points
  • -gno-inline-points
  • -gvms
  • -gxcoff
  • -gxcoff+
  • -gz[=type]
  • -gsplit-dwarf
  • -gdescribe-dies
  • -gno-describe-dies
  • -fdebug-prefix-map=old=new
  • -fdebug-types-section
  • -fno-eliminate-unused-debug-types
  • -femit-struct-debug-baseonly
  • -femit-struct-debug-reduced
  • -femit-struct-debug-detailed[=spec-list]
  • -feliminate-unused-debug-symbols
  • -femit-class-debug-always
  • -fno-merge-debug-strings
  • -fno-dwarf2-cfi-asm
  • -fvar-tracking
  • -fvar-tracking-assignments

๐Ÿš€ Optimization Options ๐Ÿš€

And finally the optimization squad ๐Ÿ‘‘ This list is absolutely massive, so get comfy ๐Ÿ’–

  • -faggressive-loop-optimizations
  • -falign-functions[=n[:m:[n2[:m2]]]]
  • -falign-jumps[=n[:m:[n2[:m2]]]]
  • -falign-labels[=n[:m:[n2[:m2]]]]
  • -falign-loops[=n[:m:[n2[:m2]]]]
  • -fassociative-math
  • -fauto-profile
  • -fauto-profile[=path]
  • -fauto-inc-dec
  • -fbranch-probabilities
  • -fbranch-target-load-optimize
  • -fbranch-target-load-optimize2
  • -fbtr-bb-exclusive
  • -fcaller-saves
  • -fcombine-stack-adjustments
  • -fconserve-stack
  • -fcompare-elim
  • -fcprop-registers
  • -fcrossjumping
  • -fcse-follow-jumps
  • -fcse-skip-blocks
  • -fcx-fortran-rules
  • -fcx-limited-range
  • -fdata-sections
  • -fdce
  • -fdelayed-branch
  • -fdelete-null-pointer-checks
  • -fdevirtualize
  • -fdevirtualize-speculatively
  • -fdevirtualize-at-ltrans
  • -fdse
  • -fearly-inlining
  • -fipa-sra
  • -fexpensive-optimizations
  • -ffat-lto-objects
  • -ffast-math
  • -ffinite-math-only
  • -ffloat-store
  • -fexcess-precision=style
  • -fforward-propagate
  • -ffp-contract=style
  • -ffunction-sections
  • -fgcse
  • -fgcse-after-reload
  • -fgcse-las
  • -fgcse-lm
  • -fgraphite-identity
  • -fgcse-sm
  • -fhoist-adjacent-loads
  • -fif-conversion
  • -fif-conversion2
  • -findirect-inlining
  • -finline-functions
  • -finline-functions-called-once
  • -finline-limit=n
  • -finline-small-functions
  • -fipa-cp
  • -fipa-cp-clone
  • -fipa-bit-cp
  • -fipa-vrp
  • -fipa-pta
  • -fipa-profile
  • -fipa-pure-const
  • -fipa-reference
  • -fipa-reference-addressable
  • -fipa-stack-alignment
  • -fipa-icf
  • -fira-algorithm=algorithm
  • -flive-patching=level
  • -fira-region=region
  • -fira-hoist-pressure
  • -fira-loop-pressure
  • -fno-ira-share-save-slots
  • -fno-ira-share-spill-slots
  • -fisolate-erroneous-paths-dereference
  • -fisolate-erroneous-paths-attribute
  • -fivopts
  • -fkeep-inline-functions
  • -fkeep-static-functions
  • -fkeep-static-consts
  • -flimit-function-alignment
  • -flive-range-shrinkage
  • -floop-block
  • -floop-interchange
  • -floop-strip-mine
  • -floop-unroll-and-jam
  • -floop-nest-optimize
  • -floop-parallelize-all
  • -flra-remat
  • -flto
  • -flto-compression-level
  • -flto-partition=alg
  • -fmerge-all-constants
  • -fmerge-constants
  • -fmodulo-sched
  • -fmodulo-sched-allow-regmoves
  • -fmove-loop-invariants
  • -fno-branch-count-reg
  • -fno-defer-pop
  • -fno-fp-int-builtin-inexact
  • -fno-function-cse
  • -fno-guess-branch-probability
  • -fno-inline
  • -fno-math-errno
  • -fno-peephole
  • -fno-peephole2
  • -fno-printf-return-value
  • -fno-sched-interblock
  • -fno-sched-spec
  • -fno-signed-zeros
  • -fno-toplevel-reorder
  • -fno-trapping-math
  • -fno-zero-initialized-in-bss
  • -fomit-frame-pointer
  • -foptimize-sibling-calls
  • -fpartial-inlining
  • -fpeel-loops
  • -fpredictive-commoning
  • -fprefetch-loop-arrays
  • -fprofile-correction
  • -fprofile-use
  • -fprofile-use=path
  • -fprofile-values
  • -fprofile-reorder-functions
  • -freciprocal-math
  • -free
  • -frename-registers
  • -freorder-blocks
  • -freorder-blocks-algorithm=algorithm
  • -freorder-blocks-and-partition
  • -freorder-functions
  • -frerun-cse-after-loop
  • -freschedule-modulo-scheduled-loops
  • -frounding-math
  • -fsave-optimization-record
  • -fsched2-use-superblocks
  • -fsched-pressure
  • -fsched-spec-load
  • -fsched-spec-load-dangerous
  • -fsched-stalled-insns-dep[=n]
  • -fsched-stalled-insns[=n]
  • -fsched-group-heuristic
  • -fsched-critical-path-heuristic
  • -fsched-spec-insn-heuristic
  • -fsched-rank-heuristic
  • -fsched-last-insn-heuristic
  • -fsched-dep-count-heuristic
  • -fschedule-fusion
  • -fschedule-insns
  • -fschedule-insns2
  • -fsection-anchors
  • -fselective-scheduling
  • -fselective-scheduling2
  • -fsel-sched-pipelining
  • -fsel-sched-pipelining-outer-loops
  • -fsemantic-interposition
  • -fshrink-wrap
  • -fshrink-wrap-separate
  • -fsignaling-nans
  • -fsingle-precision-constant
  • -fsplit-ivs-in-unroller
  • -fsplit-loops
  • -fsplit-paths
  • -fsplit-wide-types
  • -fssa-backprop
  • -fssa-phiopt
  • -fstdarg-opt
  • -fstore-merging
  • -fstrict-aliasing
  • -fthread-jumps
  • -ftracer
  • -ftree-bit-ccp
  • -ftree-builtin-call-dce
  • -ftree-ccp
  • -ftree-ch
  • -ftree-coalesce-vars
  • -ftree-copy-prop
  • -ftree-dce
  • -ftree-dominator-opts
  • -ftree-dse
  • -ftree-forwprop
  • -ftree-fre
  • -fcode-hoisting
  • -ftree-loop-if-convert
  • -ftree-loop-im
  • -ftree-phiprop
  • -ftree-loop-distribution
  • -ftree-loop-distribute-patterns
  • -ftree-loop-ivcanon
  • -ftree-loop-linear
  • -ftree-loop-optimize
  • -ftree-loop-vectorize
  • -ftree-parallelize-loops=n
  • -ftree-pre
  • -ftree-partial-pre
  • -ftree-pta
  • -ftree-reassoc
  • -ftree-scev-cprop
  • -ftree-sink
  • -ftree-slsr
  • -ftree-sra
  • -ftree-switch-conversion
  • -ftree-tail-merge
  • -ftree-ter
  • -ftree-vectorize
  • -ftree-vrp
  • -funconstrained-commons
  • -funit-at-a-time
  • -funroll-all-loops
  • -funroll-loops
  • -funsafe-math-optimizations
  • -funswitch-loops
  • -fipa-ra
  • -fvariable-expansion-in-unroller
  • -fvect-cost-model
  • -fvpt
  • -fweb
  • -fwhole-program
  • -fwpa
  • -fuse-linker-plugin
  • --param name=value
  • -O
  • -O0
  • -O1
  • -O2
  • -O3
  • -Os
  • -Ofast
  • -Og

โœจ Program Instrumentation Options โœจ

okay bestie, this group is all about profiling, coverage, and sanitizers ๐Ÿ”๐Ÿ’– here's the whole lineup:

  • -p
  • -pg
  • -fprofile-arcs
  • --coverage
  • -ftest-coverage
  • -fprofile-abs-path
  • -fprofile-dir=path
  • -fprofile-generate
  • -fprofile-generate=path
  • -fprofile-update=method
  • -fprofile-filter-files=regex
  • -fprofile-exclude-files=regex
  • -fsanitize=style
  • -fsanitize-recover
  • -fsanitize-recover=style
  • -fasan-shadow-offset=number
  • -fsanitize-sections=s1,s2,...
  • -fsanitize-undefined-trap-on-error
  • -fbounds-check
  • -fcf-protection=[full|branch|return|none|check]
  • -fstack-protector
  • -fstack-protector-all
  • -fstack-protector-strong
  • -fstack-protector-explicit
  • -fstack-check
  • -fstack-limit-register=reg
  • -fstack-limit-symbol=sym
  • -fno-stack-limit
  • -fsplit-stack
  • -fvtable-verify=[std|preinit|none]
  • -fvtv-counts
  • -fvtv-debug
  • -finstrument-functions
  • -finstrument-functions-exclude-function-list=sym,sym,...
  • -finstrument-functions-exclude-file-list=file,file,...

โœจ Preprocessor Options โœจ

the preprocessor flags, where macros and headers get sorted out ๐Ÿงš๐ŸŽ€

  • -Aquestion=answer
  • -A-question[=answer]
  • -C
  • -CC
  • -Dmacro[=defn]
  • -dD
  • -dI
  • -dM
  • -dN
  • -dU
  • -fdebug-cpp
  • -fdirectives-only
  • -fdollars-in-identifiers
  • -fexec-charset=charset
  • -fextended-identifiers
  • -finput-charset=charset
  • -fmacro-prefix-map=old=new
  • -fno-canonical-system-headers
  • -fpch-deps
  • -fpch-preprocess
  • -fpreprocessed
  • -ftabstop=width
  • -ftrack-macro-expansion
  • -fwide-exec-charset=charset
  • -fworking-directory
  • -H
  • -imacros file
  • -include file
  • -M
  • -MD
  • -MF
  • -MG
  • -MM
  • -MMD
  • -MP
  • -MQ
  • -MT
  • -no-integrated-cpp
  • -P
  • -pthread
  • -remap
  • -traditional
  • -traditional-cpp
  • -trigraphs
  • -Umacro
  • -undef
  • -Wp,option
  • -Xpreprocessor option

โœจ Assembler Options โœจ

just two, but they're doing the most ๐Ÿฆ‹

  • -Wa,option
  • -Xassembler option

โœจ Linker Options โœจ

the final step where everything gets glued together ๐Ÿ”—๐Ÿ’…

  • object-file-name
  • -fuse-ld=linker
  • -llibrary
  • -nostartfiles
  • -nodefaultlibs
  • -nolibc
  • -nostdlib
  • -e entry
  • --entry=entry
  • -pie
  • -pthread
  • -r
  • -rdynamic
  • -s
  • -static
  • -static-pie
  • -static-libgcc
  • -static-libstdc++
  • -static-libasan
  • -static-libtsan
  • -static-liblsan
  • -static-libubsan
  • -shared
  • -shared-libgcc
  • -symbolic
  • -T script
  • -Wl,option
  • -Xlinker option
  • -u symbol
  • -z keyword

โœจ Directory Options โœจ

where the compiler goes looking for stuff, main character energy ๐Ÿ—บ๏ธ๐ŸŒธ

  • -Bprefix
  • -Idir
  • -I-
  • -idirafter dir
  • -imacros file
  • -imultilib dir
  • -iplugindir=dir
  • -iprefix file
  • -iquote dir
  • -isysroot dir
  • -isystem dir
  • -iwithprefix dir
  • -iwithprefixbefore dir
  • -Ldir
  • -no-canonical-prefixes
  • --no-sysroot-suffix
  • -nostdinc
  • -nostdinc++
  • --sysroot=dir

โœจ Code Generation Options โœจ

this is where the actual machine code gets shaped ๐Ÿ”ฅ๐Ÿ’œ

  • -fcall-saved-reg
  • -fcall-used-reg
  • -ffixed-reg
  • -fexceptions
  • -fnon-call-exceptions
  • -fdelete-dead-exceptions
  • -funwind-tables
  • -fasynchronous-unwind-tables
  • -fno-gnu-unique
  • -finhibit-size-directive
  • -fno-common
  • -fno-ident
  • -fpcc-struct-return
  • -fpic
  • -fPIC
  • -fpie
  • -fPIE
  • -fno-plt
  • -fno-jump-tables
  • -frecord-gcc-switches
  • -freg-struct-return
  • -fshort-enums
  • -fshort-wchar
  • -fverbose-asm
  • -fpack-struct[=n]
  • -fleading-underscore
  • -ftls-model=model
  • -fstack-reuse=reuse_level
  • -ftrampolines
  • -ftrapv
  • -fwrapv
  • -fvisibility=[default|internal|hidden|protected]
  • -fstrict-volatile-bitfields
  • -fsync-libcalls

โœจ Developer Options โœจ

the debugging and diagnostics drawer, for when you're feeling extra ๐Ÿ•ต๏ธโ€โ™€๏ธ๐Ÿ” these are a lot, so grab a snack

  • -dletters
  • -dumpspecs
  • -dumpmachine
  • -dumpversion
  • -dumpfullversion
  • -fchecking
  • -fchecking=n
  • -fdbg-cnt-list
  • -fdbg-cnt=counter-value-list
  • -fdisable-ipa-pass_name
  • -fdisable-rtl-pass_name
  • -fdisable-rtl-pass-name=range-list
  • -fdisable-tree-pass_name
  • -fdisable-tree-pass-name=range-list
  • -fdump-debug
  • -fdump-earlydebug
  • -fdump-noaddr
  • -fdump-unnumbered
  • -fdump-unnumbered-links
  • -fdump-final-insns[=file]
  • -fdump-ipa-all
  • -fdump-ipa-cgraph
  • -fdump-ipa-inline
  • -fdump-lang-all
  • -fdump-lang-switch
  • -fdump-lang-switch-options
  • -fdump-lang-switch-options=filename
  • -fdump-passes
  • -fdump-rtl-pass
  • -fdump-rtl-pass=filename
  • -fdump-statistics
  • -fdump-tree-all
  • -fdump-tree-switch
  • -fdump-tree-switch-options
  • -fdump-tree-switch-options=filename
  • -fcompare-debug[=opts]
  • -fcompare-debug-second
  • -fenable-kind-pass
  • -fenable-kind-pass=range-list
  • -fira-verbose=n
  • -flto-report
  • -flto-report-wpa
  • -fmem-report-wpa
  • -fmem-report
  • -fpre-ipa-mem-report
  • -fpost-ipa-mem-report
  • -fopt-info
  • -fopt-info-options[=file]
  • -fprofile-report
  • -frandom-seed=string
  • -fsched-verbose=n
  • -fsel-sched-verbose
  • -fsel-sched-dump-cfg
  • -fsel-sched-pipelining-verbose
  • -fstats
  • -fstack-usage
  • -ftime-report
  • -ftime-report-details
  • -fvar-tracking-assignments-toggle
  • -gtoggle
  • -print-file-name=library
  • -print-libgcc-file-name
  • -print-multi-directory
  • -print-multi-lib
  • -print-multi-os-directory
  • -print-prog-name=program
  • -print-search-dirs
  • -Q
  • -print-sysroot
  • -print-sysroot-headers-suffix
  • -save-temps
  • -save-temps=cwd
  • -save-temps=obj
  • -time[=file]

โœจ Machine-Dependent Options โœจ

every chip has its own vibe, so these are the target-specific flags ๐ŸŒˆ๐Ÿ‘‘

๐Ÿฆ‹ AArch64 Options

  • -mabi=name
  • -mbig-endian
  • -mlittle-endian
  • -mgeneral-regs-only
  • -mcmodel=tiny
  • -mcmodel=small
  • -mcmodel=large
  • -mstrict-align
  • -mno-strict-align
  • -momit-leaf-frame-pointer
  • -mtls-dialect=desc
  • -mtls-dialect=traditional
  • -mtls-size=size
  • -mfix-cortex-a53-835769
  • -mfix-cortex-a53-843419
  • -mlow-precision-recip-sqrt
  • -mlow-precision-sqrt
  • -mlow-precision-div
  • -mpc-relative-literal-loads
  • -msign-return-address=scope
  • -mbranch-protection=none|standard|pac-ret[+leaf]|bti
  • -mharden-sls=opts
  • -march=name
  • -mcpu=name
  • -mtune=name
  • -moverride=string
  • -mverbose-cost-dump
  • -mstack-protector-guard=guard
  • -mstack-protector-guard-reg=sysreg
  • -mstack-protector-guard-offset=offset
  • -mtrack-speculation
  • -moutline-atomics

๐ŸŒธ Adapteva Epiphany Options

  • -mhalf-reg-file
  • -mprefer-short-insn-regs
  • -mbranch-cost=num
  • -mcmove
  • -mnops=num
  • -msoft-cmpsf
  • -msplit-lohi
  • -mpost-inc
  • -mpost-modify
  • -mstack-offset=num
  • -mround-nearest
  • -mlong-calls
  • -mshort-calls
  • -msmall16
  • -mfp-mode=mode
  • -mvect-double
  • -max-vect-align=num
  • -msplit-vecmove-early
  • -m1reg-reg

๐Ÿ’– AMD GCN Options

  • -march=gpu
  • -mtune=gpu
  • -mstack-size=bytes

๐Ÿ”ฅ ARC Options

  • -mbarrel-shifter
  • -mjli-always
  • -mcpu=cpu
  • -mA6
  • -mARC600
  • -mA7
  • -mARC700
  • -mdpfp
  • -mdpfp-compact
  • -mdpfp-fast
  • -mno-dpfp-lrsr
  • -mea
  • -mno-mpy
  • -mmul32x16
  • -mmul64
  • -matomic
  • -mnorm
  • -mspfp
  • -mspfp-compact
  • -mspfp-fast
  • -msimd
  • -msoft-float
  • -mswap
  • -mcrc
  • -mdsp-packa
  • -mdvbf
  • -mlock
  • -mmac-d16
  • -mmac-24
  • -mrtsc
  • -mswape
  • -mtelephony
  • -mxy
  • -misize
  • -mannotate-align
  • -marclinux
  • -marclinux_prof
  • -mlong-calls
  • -mmedium-calls
  • -msdata
  • -mirq-ctrl-saved
  • -mrgf-banked-regs
  • -mlpc-width=width
  • -G num
  • -mvolatile-cache
  • -mtp-regno=regno
  • -malign-call
  • -mauto-modify-reg
  • -mbbit-peephole
  • -mno-brcc
  • -mcase-vector-pcrel
  • -mcompact-casesi
  • -mno-cond-exec
  • -mearly-cbranchsi
  • -mexpand-adddi
  • -mindexed-loads
  • -mlra
  • -mlra-priority-none
  • -mlra-priority-compact
  • mlra-priority-noncompact
  • -mmillicode
  • -mmixed-code
  • -mq-class
  • -mRcq
  • -mRcw
  • -msize-level=level
  • -mtune=cpu
  • -mmultcost=num
  • -mcode-density-frame
  • -munalign-prob-threshold=probability
  • -mmpy-option=multo
  • -mdiv-rem
  • -mcode-density
  • -mll64
  • -mfpu=fpu
  • -mrf16
  • -mbranch-index

๐ŸŽ€ ARM Options

  • -mapcs-frame
  • -mno-apcs-frame
  • -mabi=name
  • -mapcs-stack-check
  • -mno-apcs-stack-check
  • -mapcs-reentrant
  • -mno-apcs-reentrant
  • -mgeneral-regs-only
  • -msched-prolog
  • -mno-sched-prolog
  • -mlittle-endian
  • -mbig-endian
  • -mbe8
  • -mbe32
  • -mfloat-abi=name
  • -mfp16-format=name
  • -mthumb-interwork
  • -mno-thumb-interwork
  • -mcpu=name
  • -march=name
  • -mfpu=name
  • -mtune=name
  • -mprint-tune-info
  • -mstructure-size-boundary=n
  • -mabort-on-noreturn
  • -mlong-calls
  • -mno-long-calls
  • -msingle-pic-base
  • -mno-single-pic-base
  • -mpic-register=reg
  • -mnop-fun-dllimport
  • -mpoke-function-name
  • -mthumb
  • -marm
  • -mflip-thumb
  • -mtpcs-frame
  • -mtpcs-leaf-frame
  • -mcaller-super-interworking
  • -mcallee-super-interworking
  • -mtp=name
  • -mtls-dialect=dialect
  • -mword-relocations
  • -mfix-cortex-m3-ldrd
  • -munaligned-access
  • -mneon-for-64bits
  • -mslow-flash-data
  • -masm-syntax-unified
  • -mrestrict-it
  • -mverbose-cost-dump
  • -mpure-code
  • -mcmse

๐Ÿงš AVR Options

  • -mmcu=mcu
  • -mabsdata
  • -maccumulate-args
  • -mbranch-cost=cost
  • -mcall-prologues
  • -mgas-isr-prologues
  • -mint8
  • -mn_flash=size
  • -mno-interrupts
  • -mmain-is-OS_task
  • -mrelax
  • -mrmw
  • -mstrict-X
  • -mtiny-stack
  • -mfract-convert-truncate
  • -mshort-calls
  • -nodevicelib
  • -nodevicespecs
  • -Waddr-space-convert
  • -Wmisspelled-isr

๐Ÿ’œ Blackfin Options

  • -mcpu=cpu[-sirevision]
  • -msim
  • -momit-leaf-frame-pointer
  • -mno-omit-leaf-frame-pointer
  • -mspecld-anomaly
  • -mno-specld-anomaly
  • -mcsync-anomaly
  • -mno-csync-anomaly
  • -mlow-64k
  • -mno-low64k
  • -mstack-check-l1
  • -mid-shared-library
  • -mno-id-shared-library
  • -mshared-library-id=n
  • -mleaf-id-shared-library
  • -mno-leaf-id-shared-library
  • -msep-data
  • -mno-sep-data
  • -mlong-calls
  • -mno-long-calls
  • -mfast-fp
  • -minline-plt
  • -mmulticore
  • -mcorea
  • -mcoreb
  • -msdram
  • -micplb

๐Ÿ“ C6X Options

  • -mbig-endian
  • -mlittle-endian
  • -march=cpu
  • -msim
  • -msdata=sdata-type

๐ŸŒˆ CRIS Options

  • -mcpu=cpu
  • -march=cpu
  • -mtune=cpu
  • -mmax-stack-frame=n
  • -melinux-stacksize=n
  • -metrax4
  • -metrax100
  • -mpdebug
  • -mcc-init
  • -mno-side-effects
  • -mstack-align
  • -mdata-align
  • -mconst-align
  • -m32-bit
  • -m16-bit
  • -m8-bit
  • -mno-prologue-epilogue
  • -mno-gotplt
  • -melf
  • -maout
  • -melinux
  • -mlinux
  • -sim
  • -sim2
  • -mmul-bug-workaround
  • -mno-mul-bug-workaround

๐Ÿซถ CR16 Options

  • -mmac
  • -mcr16cplus
  • -mcr16c
  • -msim
  • -mint32
  • -mbit-ops
  • -mdata-model=model

๐Ÿ”ฎ C-SKY Options

  • -march=arch
  • -mcpu=cpu
  • -mbig-endian
  • -EB
  • -mlittle-endian
  • -EL
  • -mhard-float
  • -msoft-float
  • -mfpu=fpu
  • -mdouble-float
  • -mfdivdu
  • -melrw
  • -mistack
  • -mmp
  • -mcp
  • -mcache
  • -msecurity
  • -mtrust
  • -mdsp
  • -medsp
  • -mvdsp
  • -mdiv
  • -msmart
  • -mhigh-registers
  • -manchor
  • -mpushpop
  • -mmultiple-stld
  • -mconstpool
  • -mstack-size
  • -mccrt
  • -mbranch-cost=n
  • -mcse-cc
  • -msched-prolog

๐ŸŽ Darwin Options ๐ŸŽ

okay bestie, the Darwin ones are up first and there are a LOT of them ๐Ÿ˜ญ no descriptions in this part, just the flags themselves, so here they are in full ๐Ÿ’…

  • -all_load
  • -allowable_client
  • -arch
  • -arch_errors_fatal
  • -arch_only
  • -bind_at_load
  • -bundle
  • -bundle_loader
  • -client_name
  • -compatibility_version
  • -current_version
  • -dead_strip
  • -dependency-file
  • -dylib_file
  • -dylinker_install_name
  • -dynamic
  • -dynamiclib
  • -exported_symbols_list
  • -filelist
  • -flat_namespace
  • -force_cpusubtype_ALL
  • -force_flat_namespace
  • -headerpad_max_install_names
  • -iframework
  • -image_base
  • -init
  • -install_name
  • -keep_private_externs
  • -multi_module
  • -multiply_defined
  • -multiply_defined_unused
  • -noall_load
  • -no_dead_strip_inits_and_terms
  • -nofixprebinding
  • -nomultidefs
  • -noprebind
  • -noseglinkedit
  • -pagezero_size
  • -prebind
  • -prebind_all_twolevel_modules
  • -private_bundle
  • -read_only_relocs
  • -sectalign
  • -sectobjectsymbols
  • -whyload
  • -seg1addr
  • -sectcreate
  • -sectobjectsymbols
  • -sectorder
  • -segaddr
  • -segs_read_only_addr
  • -segs_read_write_addr
  • -seg_addr_table
  • -seg_addr_table_filename
  • -seglinkedit
  • -segprot
  • -segs_read_only_addr
  • -segs_read_write_addr
  • -single_module
  • -static
  • -sub_library
  • -sub_umbrella
  • -twolevel_namespace
  • -umbrella
  • -undefined
  • -unexported_symbols_list
  • -weak_reference_mismatches
  • -whatsloaded
  • -F
  • -gused
  • -gfull
  • -mmacosx-version-min=version
  • -mkernel
  • -mone-byte-bool

๐Ÿงš DEC Alpha Options ๐Ÿงš

the Alpha crew next, bestie ๐Ÿ’œ

  • -mno-fp-regs
  • -msoft-float
  • -mieee
  • -mieee-with-inexact
  • -mieee-conformant
  • -mfp-trap-mode=mode
  • -mfp-rounding-mode=mode
  • -mtrap-precision=mode
  • -mbuild-constants
  • -mcpu=cpu-type
  • -mtune=cpu-type
  • -mbwx
  • -mmax
  • -mfix
  • -mcix
  • -mfloat-vax
  • -mfloat-ieee
  • -mexplicit-relocs
  • -msmall-data
  • -mlarge-data
  • -msmall-text
  • -mlarge-text
  • -mmemory-latency=time

๐ŸŒธ FR30 Options ๐ŸŒธ

  • -msmall-model
  • -mno-lsim

๐Ÿฆ‹ FT32 Options ๐Ÿฆ‹

  • -msim
  • -mlra
  • -mnodiv
  • -mft32b
  • -mcompress
  • -mnopm

๐Ÿ’– FRV Options ๐Ÿ’–

the FRV set is giving main character energy, no cap ๐Ÿ”ฅ

  • -mgpr-32
  • -mgpr-64
  • -mfpr-32
  • -mfpr-64
  • -mhard-float
  • -msoft-float
  • -malloc-cc
  • -mfixed-cc
  • -mdword
  • -mno-dword
  • -mdouble
  • -mno-double
  • -mmedia
  • -mno-media
  • -mmuladd
  • -mno-muladd
  • -mfdpic
  • -minline-plt
  • -mgprel-ro
  • -multilib-library-pic
  • -mlinked-fp
  • -mlong-calls
  • -malign-labels
  • -mlibrary-pic
  • -macc-4
  • -macc-8
  • -mpack
  • -mno-pack
  • -mno-eflags
  • -mcond-move
  • -mno-cond-move
  • -moptimize-membar
  • -mno-optimize-membar
  • -mscc
  • -mno-scc
  • -mcond-exec
  • -mno-cond-exec
  • -mvliw-branch
  • -mno-vliw-branch
  • -mmulti-cond-exec
  • -mno-multi-cond-exec
  • -mnested-cond-exec
  • -mno-nested-cond-exec
  • -mtomcat-stats
  • -mTLS
  • -mtls
  • -mcpu=cpu

๐Ÿง GNU/Linux Options ๐Ÿง

  • -mglibc
  • -muclibc
  • -mmusl
  • -mbionic
  • -mandroid
  • -tno-android-cc
  • -tno-android-ld

๐Ÿ“ H8/300 Options ๐Ÿ“

  • -mrelax
  • -mh
  • -ms
  • -mn
  • -mexr
  • -mno-exr
  • -mint32
  • -malign-300

๐ŸŽ€ HPPA Options ๐ŸŽ€

  • -march=architecture-type
  • -mcaller-copies
  • -mdisable-fpregs
  • -mdisable-indexing
  • -mfast-indirect-calls
  • -mgas
  • -mgnu-ld
  • -mhp-ld
  • -mfixed-range=register-range
  • -mjump-in-delay
  • -mlinker-opt
  • -mlong-calls
  • -mlong-load-store
  • -mno-disable-fpregs
  • -mno-disable-indexing
  • -mno-fast-indirect-calls
  • -mno-gas
  • -mno-jump-in-delay
  • -mno-long-load-store
  • -mno-portable-runtime
  • -mno-soft-float
  • -mno-space-regs
  • -msoft-float
  • -mpa-risc-1-0
  • -mpa-risc-1-1
  • -mpa-risc-2-0
  • -mportable-runtime
  • -mschedule=cpu-type
  • -mspace-regs
  • -msio
  • -mwsio
  • -munix=unix-std
  • -nolibdld
  • -static
  • -threads

๐Ÿง IA-64 Options ๐Ÿง

this list is LONG, bestie, pace yourself ๐Ÿ˜ญ

  • -mbig-endian
  • -mlittle-endian
  • -mgnu-as
  • -mgnu-ld
  • -mno-pic
  • -mvolatile-asm-stop
  • -mregister-names
  • -msdata
  • -mno-sdata
  • -mconstant-gp
  • -mauto-pic
  • -mfused-madd
  • -minline-float-divide-min-latency
  • -minline-float-divide-max-throughput
  • -mno-inline-float-divide
  • -minline-int-divide-min-latency
  • -minline-int-divide-max-throughput
  • -mno-inline-int-divide
  • -minline-sqrt-min-latency
  • -minline-sqrt-max-throughput
  • -mno-inline-sqrt
  • -mdwarf2-asm
  • -mearly-stop-bits
  • -mfixed-range=register-range
  • -mtls-size=tls-size
  • -mtune=cpu-type
  • -milp32
  • -mlp64
  • -msched-br-data-spec
  • -msched-ar-data-spec
  • -msched-control-spec
  • -msched-br-in-data-spec
  • -msched-ar-in-data-spec
  • -msched-in-control-spec
  • -msched-spec-ldc
  • -msched-spec-control-ldc
  • -msched-prefer-non-data-spec-insns
  • -msched-prefer-non-control-spec-insns
  • -msched-stop-bits-after-every-cycle
  • -msched-count-spec-in-critical-path
  • -msel-sched-dont-check-control-spec
  • -msched-fp-mem-deps-zero-cost
  • -msched-max-memory-insns-hard-limit
  • -msched-max-memory-insns=max-insns

๐Ÿ’œ LM32 Options ๐Ÿ’œ

  • -mbarrel-shift-enabled
  • -mdivide-enabled
  • -mmultiply-enabled
  • -msign-extend-enabled
  • -muser-enabled

๐ŸŒˆ M32R/D Options ๐ŸŒˆ

  • -m32r2
  • -m32rx
  • -m32r
  • -mdebug
  • -malign-loops
  • -mno-align-loops
  • -missue-rate=number
  • -mbranch-cost=number
  • -mmodel=code-size-model-type
  • -msdata=sdata-type
  • -mno-flush-func
  • -mflush-func=name
  • -mno-flush-trap
  • -mflush-trap=number
  • -G num

โญ M32C Options โญ

  • -mcpu=cpu
  • -msim
  • -memregs=number

๐Ÿซถ M680x0 Options ๐Ÿซถ

  • -march=arch
  • -mcpu=cpu
  • -mtune=tune
  • -m68000
  • -m68020
  • -m68020-40
  • -m68020-60
  • -m68030
  • -m68040
  • -m68060
  • -mcpu32
  • -m5200
  • -m5206e
  • -m528x
  • -m5307
  • -m5407
  • -mcfv4e
  • -mbitfield
  • -mno-bitfield
  • -mc68000
  • -mc68020
  • -mnobitfield
  • -mrtd
  • -mno-rtd
  • -mdiv
  • -mno-div
  • -mshort
  • -mno-short
  • -mhard-float
  • -m68881
  • -msoft-float
  • -mpcrel
  • -malign-int
  • -mstrict-align
  • -msep-data
  • -mno-sep-data
  • -mshared-library-id=n
  • -mid-shared-library
  • -mno-id-shared-library
  • -mxgot
  • -mno-xgot
  • -mlong-jump-table-offsets

๐Ÿ”ฅ MCore Options ๐Ÿ”ฅ

  • -mhardlit
  • -mno-hardlit
  • -mdiv
  • -mno-div
  • -mrelax-immediates
  • -mno-relax-immediates
  • -mwide-bitfields
  • -mno-wide-bitfields
  • -m4byte-functions
  • -mno-4byte-functions
  • -mcallgraph-data
  • -mno-callgraph-data
  • -mslow-bytes
  • -mno-slow-bytes
  • -mno-lsim
  • -mlittle-endian
  • -mbig-endian
  • -m210
  • -m340
  • -mstack-increment

๐ŸŒท MeP Options ๐ŸŒท

  • -mabsdiff
  • -mall-opts
  • -maverage
  • -mbased=n
  • -mbitops
  • -mc=n
  • -mclip
  • -mconfig=name
  • -mcop
  • -mcop32
  • -mcop64
  • -mivc2
  • -mdc
  • -mdiv
  • -meb
  • -mel
  • -mio-volatile
  • -ml
  • -mleadz
  • -mm
  • -mminmax
  • -mmult
  • -mno-opts
  • -mrepeat
  • -ms
  • -msatur
  • -msdram
  • -msim
  • -msimnovec
  • -mtf
  • -mtiny=n

๐Ÿฆ– MicroBlaze Options ๐Ÿฆ–

  • -msoft-float
  • -mhard-float
  • -msmall-divides
  • -mcpu=cpu
  • -mmemcpy
  • -mxl-soft-mul
  • -mxl-soft-div
  • -mxl-barrel-shift
  • -mxl-pattern-compare
  • -mxl-stack-check
  • -mxl-gp-opt
  • -mno-clearbss
  • -mxl-multiply-high
  • -mxl-float-convert
  • -mxl-float-sqrt
  • -mbig-endian
  • -mlittle-endian
  • -mxl-reorder
  • -mxl-mode-app-model
  • -mpic-data-is-text-relative

๐Ÿพ MIPS Options ๐Ÿพ

okay this is the BIGGEST one, bestie, it's giving "I have too many flags" energy ๐Ÿ’€

  • -EL
  • -EB
  • -march=arch
  • -mtune=arch
  • -mips1
  • -mips2
  • -mips3
  • -mips4
  • -mips32
  • -mips32r2
  • -mips32r3
  • -mips32r5
  • -mips32r6
  • -mips64
  • -mips64r2
  • -mips64r3
  • -mips64r5
  • -mips64r6
  • -mips16
  • -mno-mips16
  • -mflip-mips16
  • -minterlink-compressed
  • -mno-interlink-compressed
  • -minterlink-mips16
  • -mno-interlink-mips16
  • -mabi=abi
  • -mabicalls
  • -mno-abicalls
  • -mshared
  • -mno-shared
  • -mplt
  • -mno-plt
  • -mxgot
  • -mno-xgot
  • -mgp32
  • -mgp64
  • -mfp32
  • -mfpxx
  • -mfp64
  • -mhard-float
  • -msoft-float
  • -mno-float
  • -msingle-float
  • -mdouble-float
  • -modd-spreg
  • -mno-odd-spreg
  • -mabs=mode
  • -mnan=encoding
  • -mdsp
  • -mno-dsp
  • -mdspr2
  • -mno-dspr2
  • -mmcu
  • -mmno-mcu
  • -meva
  • -mno-eva
  • -mvirt
  • -mno-virt
  • -mxpa
  • -mno-xpa
  • -mcrc
  • -mno-crc
  • -mginv
  • -mno-ginv
  • -mmicromips
  • -mno-micromips
  • -mmsa
  • -mno-msa
  • -mloongson-mmi
  • -mno-loongson-mmi
  • -mloongson-ext
  • -mno-loongson-ext
  • -mloongson-ext2
  • -mno-loongson-ext2
  • -mfpu=fpu-type
  • -msmartmips
  • -mno-smartmips
  • -mpaired-single
  • -mno-paired-single
  • -mdmx
  • -mno-mdmx
  • -mips3d
  • -mno-mips3d
  • -mmt
  • -mno-mt
  • -mllsc
  • -mno-llsc
  • -mlong64
  • -mlong32
  • -msym32
  • -mno-sym32
  • -Gnum
  • -mlocal-sdata
  • -mno-local-sdata
  • -mextern-sdata
  • -mno-extern-sdata
  • -mgpopt
  • -mno-gopt
  • -membedded-data
  • -mno-embedded-data
  • -muninit-const-in-rodata
  • -mno-uninit-const-in-rodata
  • -mcode-readable=setting
  • -msplit-addresses
  • -mno-split-addresses
  • -mexplicit-relocs
  • -mno-explicit-relocs
  • -mcheck-zero-division
  • -mno-check-zero-division
  • -mdivide-traps
  • -mdivide-breaks
  • -mload-store-pairs
  • -mno-load-store-pairs
  • -mmemcpy
  • -mno-memcpy
  • -mlong-calls
  • -mno-long-calls
  • -mmad
  • -mno-mad
  • -mimadd
  • -mno-imadd
  • -mfused-madd
  • -mno-fused-madd
  • -nocpp
  • -mfix-24k
  • -mno-fix-24k
  • -mfix-r4000
  • -mno-fix-r4000
  • -mfix-r4400
  • -mno-fix-r4400
  • -mfix-r5900
  • -mno-fix-r5900
  • -mfix-r10000
  • -mno-fix-r10000
  • -mfix-rm7000
  • -mno-fix-rm7000
  • -mfix-vr4120
  • -mno-fix-vr4120
  • -mfix-vr4130
  • -mno-fix-vr4130
  • -mfix-sb1
  • -mno-fix-sb1
  • -mflush-func=func
  • -mno-flush-func
  • -mbranch-cost=num
  • -mbranch-likely
  • -mno-branch-likely
  • -mcompact-branches=policy
  • -mfp-exceptions
  • -mno-fp-exceptions
  • -mvr4130-align
  • -mno-vr4130-align
  • -msynci
  • -mno-synci
  • -mlxc1-sxc1
  • -mno-lxc1-sxc1
  • -mmadd4
  • -mno-madd4
  • -mrelax-pic-calls
  • -mno-relax-pic-calls
  • -mmcount-ra-address
  • -mframe-header-opt
  • -mno-frame-header-opt

๐Ÿงฉ MMIX Options ๐Ÿงฉ

  • -mlibfuncs
  • -mno-libfuncs
  • -mepsilon
  • -mno-epsilon
  • -mabi=gnu
  • -mabi=mmixware
  • -mzero-extend
  • -mknuthdiv
  • -mtoplevel-symbols
  • -melf
  • -mbranch-predict
  • -mno-branch-predict
  • -mbase-addresses
  • -mno-base-addresses
  • -msingle-exit
  • -mno-single-exit

๐ŸŒ™ MN10300 Options ๐ŸŒ™

  • -mmult-bug
  • -mno-mult-bug
  • -mno-am33
  • -mam33
  • -mam33-2
  • -mam34
  • -mtune=cpu-type
  • -mreturn-pointer-on-d0
  • -mno-crt0
  • -mrelax
  • -mliw
  • -msetlb

๐ŸŒ€ Moxie Options ๐ŸŒ€

  • -meb
  • -mel
  • -mmul.x
  • -mno-crt0

โ„๏ธ MSP430 Options โ„๏ธ

  • -msim
  • -masm-hex
  • -mmcu=
  • -mcpu=
  • -mlarge
  • -msmall
  • -mrelax
  • -mwarn-mcu
  • -mcode-region=
  • -mdata-region=
  • -msilicon-errata=
  • -msilicon-errata-warn=
  • -mhwmult=
  • -minrt

๐Ÿซง NDS32 Options ๐Ÿซง

  • -mbig-endian
  • -mlittle-endian
  • -mreduced-regs
  • -mfull-regs
  • -mcmov
  • -mno-cmov
  • -mext-perf
  • -mno-ext-perf
  • -mext-perf2
  • -mno-ext-perf2
  • -mext-string
  • -mno-ext-string
  • -mv3push
  • -mno-v3push
  • -m16bit
  • -mno-16bit
  • -misr-vector-size=num
  • -mcache-block-size=num
  • -march=arch
  • -mcmodel=code-model
  • -mctor-dtor
  • -mrelax

๐ŸŽฎ Nios II Options ๐ŸŽฎ

  • -G num
  • -mgpopt=option
  • -mgpopt
  • -mno-gpopt
  • -mgprel-sec=regexp
  • -mr0rel-sec=regexp
  • -mel
  • -meb
  • -mno-bypass-cache
  • -mbypass-cache
  • -mno-cache-volatile
  • -mcache-volatile
  • -mno-fast-sw-div
  • -mfast-sw-div
  • -mhw-mul
  • -mno-hw-mul
  • -mhw-mulx
  • -mno-hw-mulx
  • -mno-hw-div
  • -mhw-div
  • -mcustom-insn=N
  • -mno-custom-insn
  • -mcustom-fpu-cfg=name
  • -mhal
  • -msmallc
  • -msys-crt0=name
  • -msys-lib=name
  • -march=arch
  • -mbmx
  • -mno-bmx
  • -mcdx
  • -mno-cdx

๐Ÿ‘พ Nvidia PTX Options ๐Ÿ‘พ

  • -m32
  • -m64
  • -mmainkernel
  • -moptimize

๐ŸŒป OpenRISC Options ๐ŸŒป

  • -mboard=name
  • -mnewlib
  • -mhard-mul
  • -mhard-div
  • -msoft-mul
  • -msoft-div
  • -mcmov
  • -mror
  • -msext
  • -msfimm
  • -mshftimm

๐Ÿ’พ PDP-11 Options ๐Ÿ’พ

  • -mfpu
  • -msoft-float
  • -mac0
  • -mno-ac0
  • -m40
  • -m45
  • -m10
  • -mint32
  • -mno-int16
  • -mint16
  • -mno-int32
  • -msplit
  • -munix-asm
  • -mdec-asm
  • -mgnu-asm
  • -mlra

๐Ÿฉต picoChip Options ๐Ÿฉต

  • -mae=ae_type
  • -mvliw-lookahead=N
  • -msymbol-as-address
  • -mno-inefficient-warnings

๐Ÿ”ฎ PowerPC Options ๐Ÿ”ฎ

See RS/6000 and PowerPC Options.

๐Ÿฆ‹ RISC-V Options ๐Ÿฆ‹

-mbranch-cost=N-instruction -mplt  -mno-plt
-mabi=ABI-string -mfdiv  -mno-fdiv -mdiv  -mno-div -march=ISA-string
-mtune=processor-string -mpreferred-stack-boundary=num
-msmall-data-limit=N-bytes -msave-restore  -mno-save-restore
-mstrict-align  -mno-strict-align -mcmodel=medlow  -mcmodel=medany
-mexplicit-relocs  -mno-explicit-relocs -mrelax  -mno-relax
-mriscv-attribute  -mmo-riscv-attribute

๐ŸŒˆ RL78 Options ๐ŸŒˆ

-msim  -mmul=none  -mmul=g13  -mmul=g14  -mallregs
-mcpu=g10  -mcpu=g13  -mcpu=g14  -mg10  -mg13  -mg14 -m64bit-doubles
-m32bit-doubles  -msave-mduc-in-interrupts

๐Ÿ‘‘ RS/6000 and PowerPC Options ๐Ÿ‘‘

Okay this one is LONG, bestie. Grab a snack. ๐Ÿ“

-mcpu=cpu-type -mtune=cpu-type
-mcmodel=code-model -mpowerpc64 -maltivec  -mno-altivec
-mpowerpc-gpopt  -mno-powerpc-gpopt -mpowerpc-gfxopt
-mno-powerpc-gfxopt -mmfcrf  -mno-mfcrf  -mpopcntb  -mno-popcntb
-mpopcntd  -mno-popcntd -mfprnd  -mno-fprnd -mcmpb  -mno-cmpb
-mmfpgpr  -mno-mfpgpr  -mhard-dfp  -mno-hard-dfp -mfull-toc
-mminimal-toc  -mno-fp-in-toc  -mno-sum-in-toc -m64  -m32
-mxl-compat  -mno-xl-compat  -mpe -malign-power  -malign-natural
-msoft-float  -mhard-float  -mmultiple  -mno-multiple -mupdate
-mno-update -mavoid-indexed-addresses  -mno-avoid-indexed-addresses
-mfused-madd  -mno-fused-madd  -mbit-align  -mno-bit-align
-mstrict-align  -mno-strict-align  -mrelocatable -mno-relocatable
-mrelocatable-lib  -mno-relocatable-lib -mtoc  -mno-toc  -mlittle
-mlittle-endian  -mbig  -mbig-endian -mdynamic-no-pic  -mswdiv
-msingle-pic-base -mprioritize-restricted-insns=priority
-msched-costly-dep=dependence_type -minsert-sched-nops=scheme
-mcall-aixdesc  -mcall-eabi  -mcall-freebsd -mcall-linux
-mcall-netbsd  -mcall-openbsd -mcall-sysv  -mcall-sysv-eabi
-mcall-sysv-noeabi -mtraceback=traceback_type -maix-struct-return
-msvr4-struct-return -mabi=abi-type  -msecure-plt  -mbss-plt
-mlongcall  -mno-longcall  -mpltseq  -mno-pltseq
-mblock-move-inline-limit=num -mblock-compare-inline-limit=num
-mblock-compare-inline-loop-limit=num
-mstring-compare-inline-limit=num -misel  -mno-isel -mvrsave
-mno-vrsave -mmulhw  -mno-mulhw -mdlmzb  -mno-dlmzb -mprototype
-mno-prototype -msim  -mmvme  -mads  -myellowknife  -memb  -msdata
-msdata=opt  -mreadonly-in-sdata  -mvxworks  -G num -mrecip
-mrecip=opt  -mno-recip  -mrecip-precision -mno-recip-precision
-mveclibabi=type  -mfriz  -mno-friz -mpointers-to-nested-functions
-mno-pointers-to-nested-functions -msave-toc-indirect
-mno-save-toc-indirect -mpower8-fusion  -mno-mpower8-fusion
-mpower8-vector  -mno-power8-vector -mcrypto  -mno-crypto  -mhtm
-mno-htm -mquad-memory  -mno-quad-memory -mquad-memory-atomic
-mno-quad-memory-atomic -mcompat-align-parm  -mno-compat-align-parm
-mfloat128  -mno-float128  -mfloat128-hardware
-mno-float128-hardware -mgnu-attribute  -mno-gnu-attribute
-mstack-protector-guard=guard -mstack-protector-guard-reg=reg
-mstack-protector-guard-offset=offset

๐ŸŽ€ RX Options ๐ŸŽ€

-m64bit-doubles  -m32bit-doubles  -fpu  -nofpu -mcpu=
-mbig-endian-data  -mlittle-endian-data -msmall-data -msim  -mno-sim
-mas100-syntax  -mno-as100-syntax -mrelax -mmax-constant-size=
-mint-register= -mpid -mallow-string-insns  -mno-allow-string-insns
-mjsr -mno-warn-multiple-fast-interrupts -msave-acc-in-interrupts

๐Ÿงš S/390 and zSeries Options ๐Ÿงš

-mtune=cpu-type  -march=cpu-type
-mhard-float  -msoft-float  -mhard-dfp  -mno-hard-dfp
-mlong-double-64  -mlong-double-128 -mbackchain  -mno-backchain
-mpacked-stack  -mno-packed-stack -msmall-exec  -mno-small-exec
-mmvcle  -mno-mvcle -m64  -m31  -mdebug  -mno-debug  -mesa  -mzarch
-mhtm  -mvx  -mzvector -mtpf-trace  -mno-tpf-trace  -mfused-madd
-mno-fused-madd -mwarn-framesize  -mwarn-dynamicstack  -mstack-size
-mstack-guard -mhotpatch=halfwords,halfwords

๐Ÿ’œ Score Options ๐Ÿ’œ

-meb  -mel -mnhwloop -muls -mmac -mscore5  -mscore5u
-mscore7  -mscore7d

๐ŸŒธ SH Options ๐ŸŒธ

-m1  -m2  -m2e -m2a-nofpu  -m2a-single-only  -m2a-single
-m2a -m3  -m3e -m4-nofpu  -m4-single-only  -m4-single  -m4
-m4a-nofpu  -m4a-single-only  -m4a-single  -m4a  -m4al -mb  -ml
-mdalign  -mrelax -mbigtable  -mfmovd  -mrenesas  -mno-renesas
-mnomacsave -mieee  -mno-ieee  -mbitops  -misize
-minline-ic_invalidate  -mpadstruct -mprefergot  -musermode
-multcost=number  -mdiv=strategy -mdivsi3_libfunc=name
-mfixed-range=register-range -maccumulate-outgoing-args
-matomic-model=atomic-model -mbranch-cost=num  -mzdcbranch
-mno-zdcbranch -mcbranch-force-delay-slot -mfused-madd
-mno-fused-madd  -mfsca  -mno-fsca  -mfsrra  -mno-fsrra
-mpretend-cmove  -mtas

๐Ÿซถ Solaris 2 Options ๐Ÿซถ

-mclear-hwcap  -mno-clear-hwcap  -mimpure-text
-mno-impure-text -pthreads

๐Ÿ”ฅ SPARC Options ๐Ÿ”ฅ

-mcpu=cpu-type -mtune=cpu-type -mcmodel=code-model
-mmemory-model=mem-model -m32  -m64  -mapp-regs  -mno-app-regs
-mfaster-structs  -mno-faster-structs  -mflat  -mno-flat -mfpu
-mno-fpu  -mhard-float  -msoft-float -mhard-quad-float
-msoft-quad-float -mstack-bias  -mno-stack-bias -mstd-struct-return
-mno-std-struct-return -munaligned-doubles  -mno-unaligned-doubles
-muser-mode  -mno-user-mode -mv8plus  -mno-v8plus  -mvis  -mno-vis
-mvis2  -mno-vis2  -mvis3  -mno-vis3 -mvis4  -mno-vis4  -mvis4b
-mno-vis4b -mcbcond  -mno-cbcond  -mfmaf  -mno-fmaf  -mfsmuld
-mno-fsmuld -mpopc  -mno-popc  -msubxc  -mno-subxc -mfix-at697f
-mfix-ut699  -mfix-ut700  -mfix-gr712rc -mlra  -mno-lra

๐Ÿฆ„ SPU Options ๐Ÿฆ„

-mwarn-reloc  -merror-reloc -msafe-dma  -munsafe-dma
-mbranch-hints -msmall-mem  -mlarge-mem  -mstdmain
-mfixed-range=register-range -mea32  -mea64
-maddress-space-conversion  -mno-address-space-conversion
-mcache-size=cache-size -matomic-updates  -mno-atomic-updates

๐Ÿ’… System V Options ๐Ÿ’…

-Qy  -Qn  -YP,paths  -Ym,dir

๐ŸŒŸ TILE-Gx Options ๐ŸŒŸ

-mcpu=CPU  -m32  -m64  -mbig-endian  -mlittle-endian
-mcmodel=code-model

โœจ TILEPro Options โœจ

-mcpu=cpu  -m32

๐Ÿ“ V850 Options ๐Ÿ“

-mlong-calls  -mno-long-calls  -mep  -mno-ep
-mprolog-function  -mno-prolog-function  -mspace -mtda=n  -msda=n
-mzda=n -mapp-regs  -mno-app-regs -mdisable-callt
-mno-disable-callt -mv850e2v3  -mv850e2  -mv850e1  -mv850es -mv850e
-mv850  -mv850e3v5 -mloop -mrelax -mlong-jumps -msoft-float
-mhard-float -mgcc-abi -mrh850-abi -mbig-switch

๐ŸŒ™ VAX Options ๐ŸŒ™

-mg  -mgnu  -munix

๐Ÿซง Visium Options ๐Ÿซง

-mdebug  -msim  -mfpu  -mno-fpu  -mhard-float
-msoft-float -mcpu=cpu-type  -mtune=cpu-type  -msv-mode  -muser-mode

๐ŸŒบ VMS Options ๐ŸŒบ

-mvms-return-codes  -mdebug-main=prefix  -mmalloc64
-mpointer-size=size

๐Ÿฆ‹ VxWorks Options ๐Ÿฆ‹

-mrtp  -non-static  -Bstatic  -Bdynamic -Xbind-lazy
-Xbind-now

๐Ÿ’– x86 Options ๐Ÿ’–

This is the biggest list in the whole page, no cap. ๐Ÿ˜ญ

-mtune=cpu-type  -march=cpu-type -mtune-ctrl=feature-
list  -mdump-tune-features  -mno-default -mfpmath=unit -masm=dialect
-mno-fancy-math-387 -mno-fp-ret-in-387  -m80387  -mhard-float
-msoft-float -mno-wide-multiply  -mrtd  -malign-double
-mpreferred-stack-boundary=num -mincoming-stack-boundary=num -mcld
-mcx16  -msahf  -mmovbe  -mcrc32 -mrecip  -mrecip=opt -mvzeroupper
-mprefer-avx128  -mprefer-vector-width=opt -mmmx  -msse  -msse2
-msse3  -mssse3  -msse4.1  -msse4.2  -msse4  -mavx -mavx2  -mavx512f
-mavx512pf  -mavx512er  -mavx512cd  -mavx512vl -mavx512bw
-mavx512dq  -mavx512ifma  -mavx512vbmi  -msha  -maes -mpclmul
-mfsgsbase  -mrdrnd  -mf16c  -mfma  -mpconfig  -mwbnoinvd -mptwrite
-mprefetchwt1  -mclflushopt  -mclwb  -mxsavec  -mxsaves -msse4a
-m3dnow  -m3dnowa  -mpopcnt  -mabm  -mbmi  -mtbm  -mfma4  -mxop
-madx  -mlzcnt  -mbmi2  -mfxsr  -mxsave  -mxsaveopt  -mrtm  -mhle
-mlwp -mmwaitx  -mclzero  -mpku  -mthreads  -mgfni  -mvaes
-mwaitpkg -mshstk -mmanual-endbr -mforce-indirect-call
-mavx512vbmi2 -mvpclmulqdq  -mavx512bitalg  -mmovdiri  -mmovdir64b
-mavx512vpopcntdq -mavx5124fmaps  -mavx512vnni  -mavx5124vnniw
-mprfchw  -mrdpid -mrdseed  -msgx -mcldemote  -mms-bitfields
-mno-align-stringops  -minline-all-stringops
-minline-stringops-dynamically  -mstringop-strategy=alg
-mmemcpy-strategy=strategy  -mmemset-strategy=strategy -mpush-args
-maccumulate-outgoing-args  -m128bit-long-double -m96bit-long-double
-mlong-double-64  -mlong-double-80  -mlong-double-128 -mregparm=num
-msseregparm -mveclibabi=type  -mvect8-ret-in-mem -mpc32  -mpc64
-mpc80  -mstackrealign -momit-leaf-frame-pointer  -mno-red-zone
-mno-tls-direct-seg-refs -mcmodel=code-model  -mabi=name
-maddress-mode=mode -m32  -m64  -mx32  -m16  -miamcu
-mlarge-data-threshold=num -msse2avx  -mfentry  -mrecord-mcount
-mnop-mcount  -m8bit-idiv -minstrument-return=type
-mfentry-name=name -mfentry-section=name
-mavx256-split-unaligned-load  -mavx256-split-unaligned-store
-malign-data=type  -mstack-protector-guard=guard
-mstack-protector-guard-reg=reg
-mstack-protector-guard-offset=offset
-mstack-protector-guard-symbol=symbol -mgeneral-regs-only
-mcall-ms2sysv-xlogues -mindirect-branch=choice
-mfunction-return=choice -mindirect-branch-register

๐ŸชŸ x86 Windows Options ๐ŸชŸ

-mconsole  -mcygwin  -mno-cygwin  -mdll
-mnop-fun-dllimport  -mthread -municode  -mwin32  -mwindows
-fno-set-stack-executable

๐ŸŒˆ Xstormy16 Options ๐ŸŒˆ

-msim

๐Ÿง Xtensa Options ๐Ÿง

-mconst16  -mno-const16 -mfused-madd  -mno-fused-madd
-mforce-no-pic -mserialize-volatile  -mno-serialize-volatile
-mtext-section-literals  -mno-text-section-literals -mauto-litpools
-mno-auto-litpools -mtarget-align  -mno-target-align -mlongcalls
-mno-longcalls

zSeries Options โ€” See S/390 and zSeries Options.


๐ŸŒธ Options Controlling the Kind of Output ๐ŸŒธ

Okay so compilation can have up to four stages ๐Ÿ”ฅ: preprocessing, compilation proper, assembly, and linking. They always happen in that order, no exceptions, bestie.

GCC can preprocess and compile several files into several assembler input files, or squish them all into one assembler input file. Then each assembler input file makes an object file, and linking combines all the object files (the ones just compiled AND the ones you handed it as input) into an executable file. Iconic pipeline. ๐Ÿ’…

For any given input file, the file name suffix decides what kind of compilation happens. Here's the vibe check:

  • file.c โ€” C source code that must be preprocessed first. ๐Ÿงš
  • file.i โ€” C source code that should not be preprocessed. ๐ŸŽ€
  • file.ii โ€” C++ source code that should not be preprocessed. ๐Ÿ’œ
  • file.m โ€” Objective-C source code. Heads up, bestie: you MUST link with the libobjc library or your Objective-C program won't work. ๐Ÿ˜ญ
  • file.mi โ€” Objective-C source code that should not be preprocessed. ๐Ÿฆ‹
  • file.mm, file.M โ€” ๐Ÿ’œ Objective-C++ source code! Bestie, you have to link with the libobjc library or your Objective-C++ program won't work ๐Ÿ’€. Also, .M means a literal capital M, not a typo.
  • file.mii โ€” Objective-C++ source that should not get preprocessed ๐Ÿ™ˆ.
  • file.h โ€” A C, C++, Objective-C or Objective-C++ header that gets turned into a precompiled header by default โœจ. Or, if it's a C or C++ header, it can become an Ada spec instead, using the -fdump-ada-spec switch ๐Ÿฆ‹.
  • file.cc, file.cp, file.cxx, file.cpp, file.CPP, file.c++, file.C โ€” C++ source that must be preprocessed ๐ŸŒธ. In .cxx, the last two letters have to be literally x, and .C means a literal capital C.
  • file.mm, file.M โ€” Objective-C++ source that must be preprocessed ๐Ÿ’….
  • file.mii โ€” Objective-C++ source that should not be preprocessed (yep, same as above ๐Ÿ™ˆ).
  • file.hh, file.H, file.hp, file.hxx, file.hpp, file.HPP, file.h++, file.tcc โ€” C++ headers that get turned into a precompiled header or an Ada spec ๐Ÿงš.
  • file.f, file.for, file.ftn โ€” Fixed form Fortran source that should not be preprocessed ๐Ÿ“.
  • file.F, file.FOR, file.fpp, file.FPP, file.FTN โ€” Fixed form Fortran source that must be preprocessed, using the traditional preprocessor ๐Ÿ”ฅ.
  • file.f90, file.f95, file.f03, file.f08 โ€” Free form Fortran source that should not be preprocessed ๐ŸŒˆ.
  • file.F90, file.F95, file.F03, file.F08 โ€” Free form Fortran source that must be preprocessed, using the traditional preprocessor ๐Ÿ‘‘.
  • file.go โ€” Go source code ๐Ÿฉต.
  • file.brig โ€” BRIG files, which are the binary representation of HSAIL ๐Ÿค“.
  • file.d โ€” D source code ๐Ÿ’–.
  • file.di โ€” A D interface file ๐ŸŽ€.
  • file.dd โ€” D documentation code, aka Ddoc ๐Ÿ“š.
  • file.ads โ€” An Ada source file with a library unit declaration (a declaration of a package, subprogram, or generic, or a generic instantiation), or a library unit renaming declaration (a package, generic, or subprogram renaming declaration). These are also called specs ๐Ÿ›ก๏ธ.
  • file.adb โ€” An Ada source file containing a library unit body (a subprogram or package body). These are also called bodies ๐Ÿช„.
  • file.s โ€” Assembler code โญ.
  • file.S, file.sx โ€” Assembler code that must be preprocessed ๐Ÿซถ.
  • other โ€” An object file that gets fed straight into linking. Any file name with no recognized suffix gets treated this way ๐Ÿงƒ.

You can also be super explicit about the input language with the -x option, instead of letting the compiler guess from the file name suffix ๐Ÿ•ต๏ธโ€โ™€๏ธ.

  • -x language โ€” Tells gcc the language for the input files that come after it, instead of picking one from the suffix. It applies to every following input file until the next -x option. The possible values for language are:
c  c-header  cpp-output
c++  c++-header  c++-cpp-output
objective-c  objective-c-header  objective-c-cpp-output
objective-c++ objective-c++-header objective-c++-cpp-output
assembler  assembler-with-cpp
ada
d
f77  f77-cpp-input f95  f95-cpp-input
go
brig
  • -x none โ€” Turns off any language specification, so the files after it get handled by their suffixes, just like they would if -x had never been used at all ๐Ÿงน.

If you only want some stages of compilation, you can use -x (or filename suffixes) to tell gcc where to start, then pick one of -c, -S, or -E to say where it should stop ๐Ÿ›‘. Heads up: some combos (like -x cpp-output -E) make gcc do absolutely nothing ๐Ÿ’€.

  • -c โ€” Compiles or assembles the source files but does not link. The linking stage just doesn't happen ๐Ÿ™…โ€โ™€๏ธ. You get an object file for each source file.

By default, the object file name for a source file is made by swapping the suffix .c, .i, .s, etc. for .o ๐ŸŒท.

Unrecognized input files that don't need compiling or assembling are ignored ๐Ÿซ .

  • -S โ€” Stops after the actual compilation stage and does not assemble ๐ŸŽจ. You get an assembler code file for each non-assembler input file.

By default, the assembler file name is made by swapping the suffix .c, .i, etc. for .s ๐Ÿญ.

Input files that don't need compiling are ignored ๐Ÿ™ƒ.

  • -E โ€” Stops after the preprocessing stage and does not run the compiler proper ๐Ÿงผ. The output is preprocessed source code, which gets sent to standard output.

Input files that don't need preprocessing are ignored ๐Ÿ’ค.

  • -o file โ€” Puts the output in file. This works for whatever you're making, whether that's an executable, an object file, an assembler file, or preprocessed C code ๐ŸŽ.

If you don't use -o, the defaults are: an executable goes in a.out, the object file for source.suffix goes in source.o, its assembler file goes in source.s, a precompiled header file goes in source.suffix.gch, and all the preprocessed C source goes to standard output ๐Ÿ“ค.

  • -v โ€” Prints (on standard error output) the commands that get run for each stage of compilation ๐Ÿ”. It also prints the version number of the compiler driver program, the preprocessor, and the compiler proper ๐Ÿท๏ธ.
  • -### โ€” Basically -v, but the commands don't actually run ๐Ÿ™…. Arguments get quoted unless they only contain alphanumeric characters or "./-_". This is super useful for shell scripts that want to capture the driver-generated command lines ๐Ÿš.
  • --help โ€” Prints (on standard output) a description of the command-line options gcc understands ๐Ÿ“–. If -v is also specified, --help gets passed along to the various processes gcc invokes, so they can show the options they accept ๐Ÿช†. If -Wextra was specified before --help, command-line options with no documentation get displayed too ๐Ÿ•ต๏ธ.
  • --target-help โ€” Prints (on standard output) the target-specific command-line options for each tool ๐ŸŽฏ. For some targets, extra target-specific info might get printed too โœจ.
  • --help={class|[^]qualifier}[,...] โ€” Prints (on standard output) the command-line options the compiler understands that fit all of the classes and qualifiers you specify ๐ŸŽ€. These are the supported classes:
    • optimizers โ€” Shows all the optimization options the compiler supports ๐Ÿš€.
    • warnings โ€” Shows all the options that control warning messages ๐Ÿšจ.
    • target โ€” Shows target-specific options ๐ŸŽฏ. Unlike --target-help, target-specific options of the linker and assembler are not shown, because those tools don't support the extended --help= syntax yet ๐Ÿ™ƒ.
    • params โ€” Shows the values the --param option recognizes ๐Ÿงฎ.
    • language โ€” Shows the options supported for language, where language is the name of one of the languages this version of GCC supports ๐ŸŒ.
    • common โ€” Shows the options that are common to all languages ๐Ÿค.

These are the supported qualifiers:

  • undocumented โ€” Shows only the options that are undocumented ๐Ÿซฃ.
  • joined โ€” Shows options that take an argument appearing after an equal sign in the same continuous piece of text, like --help=target ๐Ÿ”—.
  • separate โ€” Shows options that take an argument appearing as a separate word right after the original option, like -o output-file โœ‚๏ธ.

So if you want every undocumented target-specific switch the compiler supports, use:

--help=target,undocumented

You can flip a qualifier by putting a ^ in front of it ๐Ÿ”„. For example, to see all the binary warning options (the ones that are either on or off and don't take an argument) that have a description, use:

--help=warnings,^joined,^undocumented

The argument to --help= should not be made up solely of inverted qualifiers ๐Ÿ™…โ€โ™€๏ธ.

You can combine several classes, but that usually narrows things down so much there's nothing to show ๐Ÿ’€. One case where it actually works is when one of the classes is target. For example, to show all the target-specific optimization options, use:

--help=target,optimizers

You can repeat the --help= option on the command line ๐Ÿ”. Each one shows its requested class of options, skipping anything already displayed. If --help is also anywhere on the command line, it takes precedence over any --help= option ๐Ÿ‘‘.

If -Q appears on the command line before --help=, the descriptive text changes ๐Ÿช„. Instead of describing the options, it tells you whether each option is enabled, disabled, or set to a specific value (assuming the compiler knows that at the point where --help= is used).

Here's a truncated example from the ARM port of gcc ๐Ÿฆพ:

% gcc -Q -mabi=2 --help=target -c
The following options are target specific:
-mabi=                                2
-mabort-on-noreturn                   [disabled]
-mapcs                                [disabled]

The output is sensitive to previous command-line options, so you can find out which optimizations are enabled at -O2 by using:

-Q -O2 --help=optimizers

Or, if you want to see which binary optimizations -O3 enables, you can compare the two levels like this ๐Ÿง:

gcc -c -Q -O3 --help=optimizers > /tmp/O3-opts
gcc -c -Q -O2 --help=optimizers > /tmp/O2-opts
diff /tmp/O2-opts /tmp/O3-opts | grep enabled
  • --version โ€” Displays the version number and copyrights of the GCC you invoked ๐Ÿ†.
  • -pass-exit-codes โ€” okay so normally gcc just exits with 1 if any phase of the compiler comes back with a non-success return code ๐Ÿฅฑ. But if you add -pass-exit-codes, it instead returns the numerically highest error that any phase reported. And the C, C++, and Fortran front ends return 4 if they hit an internal compiler error ๐Ÿ’€.
  • -pipe โ€” use pipes instead of temporary files to pass stuff between the stages of compilation ๐Ÿงš. Heads up though, this breaks on some systems where the assembler can't read from a pipe. The GNU assembler has zero trouble with it tho โœจ.
  • -specs=file โ€” process file after the compiler reads in the standard specs file, so you can override the defaults the gcc driver uses to decide which switches get passed to cc1, cc1plus, as, ld, etc. ๐ŸŽ€ You can stack more than one -specs=file, and they get processed in order, left to right.
  • -wrapper โ€” invoke all subcommands under a wrapper program ๐Ÿฆ‹. The wrapper's name and its parameters go in one comma separated list. Here's the vibe:
gcc -c t.c -wrapper gdb,--args

That runs every gcc subprogram under gdb --args, so the cc1 call turns into gdb --args cc1 .... ๐Ÿ’…

  • -ffile-prefix-map=old=new โ€” when compiling files that live in directory old, record any references to them in the compilation result as if they lived in directory new instead ๐ŸŒˆ. Using this is the same as specifying all the individual -f*-prefix-map options. It's a total slay for reproducible builds that don't care about location. See also -fmacro-prefix-map and -fdebug-prefix-map.
  • -fplugin=name.so โ€” load the plugin code in name.so, which is assumed to be a shared object the compiler will dlopen. The base name of the shared object is used to identify the plugin when parsing arguments (see -fplugin-arg-name-key=value below). Each plugin should define the callback functions specified in the Plugins API ๐Ÿ”Œ.
  • -fplugin-arg-name-key=value โ€” defines an argument called key with a value of value for the plugin called name โœจ.
  • -fdump-ada-spec[-slim] โ€” for C and C++ source and include files, generate corresponding Ada specs ๐ŸŒธ.
  • -fada-spec-parent=unit โ€” used together with -fdump-ada-spec[-slim] above, this generates Ada specs as child units of the parent unit ๐Ÿงธ.
  • -fdump-go-spec=file โ€” for input files in any language, generate corresponding Go declarations in file. You get const, type, var, and func declarations, which is a super useful starting point if you want to write a Go interface to code written in some other language ๐Ÿ“.
  • @file โ€” read command-line options from file, and the options read get inserted right where the original @file option was ๐Ÿซถ. If file doesn't exist or can't be read, then the option gets treated literally and isn't removed. Options in file are separated by whitespace. You can put a whitespace character inside an option by surrounding the entire option in single or double quotes. Any character (backslash included) can be included by prefixing it with a backslash. The file can even contain more @file options of its own, and those get processed recursively ๐ŸŒ€.

๐Ÿ’œ Compiling C++ Programs ๐Ÿ’œ

C++ source files usually use one of the suffixes .C, .cc, .cpp, .CPP, .c++, .cp, or .cxx ๐Ÿ’–. C++ header files often use .hh, .hpp, .H, or (for shared template code) .tcc, and preprocessed C++ files use the suffix .ii. GCC recognizes files with these names and compiles them as C++ programs, even if you call the compiler the same way you would for C programs (usually with the name gcc).

However, using gcc does not add the C++ library ๐Ÿ™ƒ. g++ is a program that calls GCC and automatically specifies linking against the C++ library. It treats .c, .h and .i files as C++ source files instead of C source files unless -x is used. This program is also useful when precompiling a C header file with a .h extension for use in C++ compilations. On many systems, g++ is also installed with the name c++ ๐Ÿ‘‘.

When you compile C++ programs, you can use many of the same command-line options you'd use for programs in any language, or command-line options meaningful for C and related languages, or options that only mean something for C++ programs ๐ŸŒˆ.


โœจ Options Controlling C Dialect โœจ

The following options control the dialect of C (or languages derived from C, such as C++, Objective-C and Objective-C++) that the compiler accepts ๐Ÿง:

  • -ansi โ€” in C mode this is equivalent to -std=c90, and in C++ mode it's equivalent to -std=c++98 ๐ŸŽ€. It turns off certain GCC features that are incompatible with ISO C90 (when compiling C code) or standard C++ (when compiling C++ code), such as the asm and typeof keywords, plus predefined macros like unix and vax that identify the type of system you're using. It also enables the undesirable and rarely used ISO trigraph feature. For the C compiler, it disables recognition of C++ style // comments as well as the inline keyword ๐Ÿ™ˆ.
    • The alternate keywords __asm__, __extension__, __inline__ and __typeof__ keep working despite -ansi. You wouldn't want to use them in an ISO C program, of course, but it's useful to put them in header files that might get included in compilations done with -ansi. Alternate predefined macros like __unix__ and __vax__ are also available, with or without -ansi ๐Ÿฆ‹.
    • The -ansi option does not cause non-ISO programs to be rejected gratuitously. For that, -Wpedantic is required in addition to -ansi ๐Ÿซ .
    • The macro __STRICT_ANSI__ is predefined when the -ansi option is used. Some header files may notice this macro and refrain from declaring certain functions or defining certain macros that the ISO standard doesn't call for. This avoids interfering with any programs that might use these names for other things ๐Ÿคซ.
    • Functions that are normally built in but don't have semantics defined by ISO C (such as alloca and ffs) are not built-in functions when -ansi is used ๐Ÿšซ.
  • -std= โ€” determine the language standard. This option is currently only supported when compiling C or C++ ๐Ÿ‘‘.
    • The compiler can accept several base standards, like c90 or c++98, plus GNU dialects of those standards, like gnu90 or gnu++98. When a base standard is specified, the compiler accepts all programs following that standard, plus those using GNU extensions that don't contradict it. For example, -std=c90 turns off certain GCC features that are incompatible with ISO C90, such as the asm and typeof keywords, but not other GNU extensions that have no meaning in ISO C90, like omitting the middle term of a ?: expression ๐Ÿฐ.
    • On the other hand, when a GNU dialect of a standard is specified, every feature the compiler supports is enabled, even when those features change the meaning of the base standard. As a result, some strict-conforming programs may get rejected ๐Ÿ˜ฌ.
    • The particular standard is used by -Wpedantic to identify which features are GNU extensions for that version of the standard. For example, -std=gnu90 -Wpedantic warns about C++ style // comments, while -std=gnu99 -Wpedantic does not โญ.

A value for this option must be provided. Possible values are:

  • c90, c89, iso9899:1990 โ€” supports all ISO C90 programs (certain GNU extensions that conflict with ISO C90 are disabled). Same as -ansi for C code ๐ŸŒธ.
  • iso9899:199409 โ€” ISO C90 as modified in amendment 1.
  • c99, c9x, iso9899:1999, iso9899:199x โ€” ISO C99. This standard is substantially completely supported, modulo bugs and floating-point issues (mainly but not entirely relating to optional C99 features from Annexes F and G). See http://gcc.gnu.org/c99status.html for more information. The names c9x and iso9899:199x are deprecated ๐Ÿฅ€.
  • c11, c1x, iso9899:2011 โ€” ISO C11, the 2011 revision of the ISO C standard. This standard is substantially completely supported, modulo bugs, floating-point issues (mainly but not entirely relating to optional C11 features from Annexes F and G) and the optional Annexes K (Bounds-checking interfaces) and L (Analyzability). The name c1x is deprecated ๐ŸŒท.
  • c17, c18, iso9899:2017, iso9899:2018 โ€” ISO C17, the 2017 revision of the ISO C standard (published in 2018). This standard is the same as C11 except for corrections of defects (all of which are also applied with -std=c11) and a new value of __STDC_VERSION__, so it's supported to the same extent as C11 ๐ŸŽ€.
  • c2x โ€” the next version of the ISO C standard, still under development. Support for this version is experimental and incomplete ๐Ÿงช.
  • gnu90, gnu89 โ€” GNU dialect of ISO C90 (including some C99 features) ๐Ÿ“.
  • gnu99, gnu9x โ€” GNU dialect of ISO C99. The name gnu9x is deprecated ๐Ÿฅ€.
  • gnu11, gnu1x โ€” GNU dialect of ISO C11. The name gnu1x is deprecated ๐Ÿฅ€.
  • gnu17, gnu18 โ€” GNU dialect of ISO C17. This is the default for C code ๐Ÿ’–.
  • gnu2x โ€” the next version of the ISO C standard, still under development, plus GNU extensions. Support for this version is experimental and incomplete ๐Ÿงช.
  • c++98, c++03 โ€” the 1998 ISO C++ standard plus the 2003 technical corrigendum and some additional defect reports. Same as -ansi for C++ code ๐Ÿฆ‹.
  • gnu++98, gnu++03 โ€” GNU dialect of -std=c++98 ๐ŸŒˆ.
  • c++11, c++0x โ€” the 2011 ISO C++ standard plus amendments. The name c++0x is deprecated ๐Ÿฅ€.
  • gnu++11, gnu++0x โ€” GNU dialect of -std=c++11. The name gnu++0x is deprecated ๐Ÿฅ€.
  • c++14, c++1y โ€” the 2014 ISO C++ standard plus amendments. The name c++1y is deprecated ๐Ÿฅ€.
  • gnu++14, gnu++1y โ€” GNU dialect of -std=c++14. This is the default for C++ code. The name gnu++1y is deprecated ๐Ÿ‘‘.
  • c++17, c++1z โ€” the 2017 ISO C++ standard plus amendments. The name c++1z is deprecated ๐Ÿฅ€.
  • gnu++17, gnu++1z: okay so this is the GNU flavour of -std=c++17 ๐Ÿ’–. Heads up, the name gnu++1z is deprecated โš ๏ธ.
  • c++2a: the next revision of the ISO C++ standard, tentatively planned for 2020 โœจ. Support is highly experimental ๐Ÿงช and will almost certainly change in incompatible ways in future releases ๐Ÿ’€.
  • gnu++2a: the GNU dialect of -std=c++2a ๐ŸŒˆ. Same energy: highly experimental, and almost certainly going to change in incompatible ways in future releases ๐Ÿ˜ญ.
  • -fgnu89-inline โ€” this tells GCC to use the traditional GNU semantics for inline functions when you're in C99 mode ๐Ÿ’….
    • Using it is roughly the same as adding the gnu_inline function attribute to every inline function ๐Ÿฆ‹.
  • -fno-gnu89-inline โ€” the opposite move ๐Ÿ™…โ€โ™€๏ธ. It tells GCC to use the C99 semantics for inline when you're in C99 or gnu99 mode, which is the default behaviour anyway ๐ŸŒธ. This option is not supported in -std=c90 or -std=gnu90 mode.
    • The macros __GNUC_GNU_INLINE__ and __GNUC_STDC_INLINE__ can be used to check which semantics are in effect for inline functions ๐Ÿ”.
  • -fpermitted-flt-eval-methods=style โ€” bestie, this one is a whole mood ๐Ÿง . ISO/IEC TS 18661-3 adds new permissible values for FLT_EVAL_METHOD, which say that operations and constants with a semantic type that's an interchange or extended format should be evaluated to the precision and range of that type ๐Ÿ“. These new values are a superset of what C99/C11 allows, and C99/C11 doesn't specify what other positive values mean, so C11 code might not have been written with them in mind ๐Ÿคทโ€โ™€๏ธ.
    • This option decides whether the compiler allows only the FLT_EVAL_METHOD values from C99/C11, or the extended set from ISO/IEC TS 18661-3 โœจ.
    • style is either c11 or ts-18661-3, as appropriate ๐ŸŽ€.
    • The default in a standards-compliant mode (-std=c11 or similar) is -fpermitted-flt-eval-methods=c11 ๐Ÿ’œ.
    • The default in a GNU dialect (-std=gnu11 or similar) is -fpermitted-flt-eval-methods=ts-18661-3 ๐ŸŒˆ.
  • -aux-info filename โ€” output to the given filename a list of prototyped declarations for all functions declared and/or defined in a translation unit, including the ones in header files ๐Ÿ“. This option is silently ignored in any language other than C ๐Ÿ™ˆ.
    • Besides the declarations, the file has comments showing where each one came from (source file and line) ๐Ÿ—บ๏ธ.
    • The first character after the line number and the colon tells you whether the declaration was implicit, prototyped or unprototyped: I, N for new, or O for old, respectively ๐Ÿ”ค.
    • The character right after that tells you whether it came from a declaration or a definition: C or F, respectively ๐Ÿงพ.
    • For function definitions, there's also a K&R-style list of arguments, followed by their declarations, inside comments after the declaration ๐Ÿ“œ.
  • -fallow-parameterless-variadic-functions โ€” accepts variadic functions without named parameters ๐ŸŒ€.
    • You can define one of these, but it's not super useful, because you can't read the arguments ๐Ÿฅฒ.
    • This is only supported for C, since C++ allows this construct too ๐Ÿ’….
  • -fno-asm โ€” stops asm, inline or typeof from being recognized as keywords, so your code can use those words as identifiers ๐Ÿ™Œ. You can use __asm__, __inline__ and __typeof__ instead ๐Ÿ’–. -ansi implies -fno-asm โœจ.
    • In C++, this switch only affects the typeof keyword, since asm and inline are standard keywords ๐Ÿงš. You may want to use -fno-gnu-keywords instead, which has the same effect ๐ŸŽ€.
    • In C99 mode (-std=c99 or -std=gnu99), this switch only affects the asm and typeof keywords, since inline is a standard keyword in ISO C99 ๐Ÿฆ‹.
  • -fno-builtin, -fno-builtin-function โ€” stops GCC from recognizing built-in functions that don't begin with __builtin_ as a prefix ๐Ÿšซ.
    • Normally GCC generates special code for certain built-in functions so they run more efficiently ๐Ÿš€. For instance, calls to alloca may turn into single instructions that adjust the stack directly, and calls to memcpy may become inline copy loops ๐Ÿ”. The result is often smaller and faster, but because the function calls no longer show up as calls, you can't set a breakpoint on them, and you can't change how they behave by linking against a different library ๐Ÿ˜ค.
    • When a function is recognized as built-in, GCC can also use what it knows about that function to warn you about problems with calls to it, or to generate more efficient code, even if the result still contains calls to that function ๐Ÿ‘€. For example, you get warnings with -Wformat for bad calls to printf when printf is built in and strlen is known not to modify global memory ๐Ÿ“.
    • With -fno-builtin-function, only that one built-in function gets disabled. The function name must not begin with __builtin_. If you name a function that isn't built-in in this version of GCC, the option is ignored ๐Ÿคทโ€โ™€๏ธ.
    • There's no matching -fbuiltin-function option. If you want to pick built-in functions selectively when using -fno-builtin or -ffreestanding, you can define macros like these ๐Ÿง :
#define abs(n)          __builtin_abs ((n))
#define strcpy(d, s)    __builtin_strcpy ((d), (s))
  • -fgimple โ€” enables parsing of function definitions marked with __GIMPLE ๐Ÿงช. This is an experimental feature that lets you unit test GIMPLE passes ๐Ÿซถ.
  • -fhosted โ€” asserts that compilation targets a hosted environment ๐Ÿ . This implies -fbuiltin ๐Ÿ’œ. A hosted environment is one where the entire standard library is available, and where main has a return type of int ๐Ÿ‘‘. Examples are nearly everything except a kernel. This is equivalent to -fno-freestanding ๐Ÿ”.
  • -ffreestanding โ€” asserts that compilation targets a freestanding environment ๐Ÿ›ธ. This implies -fno-builtin ๐Ÿšซ. A freestanding environment is one where the standard library may not exist, and program startup may not necessarily be at main ๐Ÿคฏ. The most obvious example is an OS kernel ๐Ÿ–ฅ๏ธ. This is equivalent to -fno-hosted ๐Ÿ”.
  • -fopenacc โ€” enables handling of OpenACC directives #pragma acc in C/C++ and !$acc in Fortran ๐ŸŒธ. When you specify -fopenacc, the compiler generates accelerated code according to the OpenACC Application Programming Interface v2.0 <https://www.openacc.org> โœจ. This option implies -pthread, so it's only supported on targets that support -pthread ๐Ÿงต.
  • -fopenacc-dim=geom โ€” sets default compute dimensions for parallel offload regions that don't explicitly specify their own ๐Ÿ“. The geom value is a triple of :-separated sizes, in the order gang, worker and vector ๐Ÿ”ข. A size can be left out, so the target-specific default gets used instead ๐Ÿ’….
  • -fopenmp โ€” enables handling of OpenMP directives #pragma omp in C/C++ and !$omp in Fortran ๐ŸŽ‰. When you specify -fopenmp, the compiler generates parallel code according to the OpenMP Application Program Interface v4.5 <https://www.openmp.org> ๐Ÿงต. This option implies -pthread, so it's only supported on targets that support -pthread ๐Ÿซถ. -fopenmp also implies -fopenmp-simd ๐Ÿ’–.
  • -fopenmp-simd โ€” enables handling of OpenMP's SIMD directives written as #pragma omp in C/C++ and !$omp in Fortran ๐Ÿฆ‹. Other OpenMP directives are ignored ๐Ÿ™ˆ.
  • -fgnu-tm โ€” when you specify -fgnu-tm, the compiler generates code for the Linux variant of Intel's current Transactional Memory ABI specification document (Revision 1.1, May 6 2009) ๐Ÿ’œ. This is an experimental feature, and its interface may change in future versions of GCC as the official specification changes ๐Ÿงช. Not all architectures are supported for this feature, so please check first ๐Ÿซถ.
    • For more information on GCC's support for transactional memory, (the sentence just kind of stops there in the original ๐Ÿ™ˆ)
    • Heads up: transactional memory isn't supported with non-call exceptions (-fnon-call-exceptions) โš ๏ธ.
  • -fms-extensions โ€” accepts some non-standard constructs that show up in Microsoft header files ๐ŸชŸ.
    • In C++ code, this lets member names in structures be similar to earlier type declarations ๐Ÿคญ. Like this:
typedef int UOW;
struct ABC {
  UOW UOW;
};
  • Some cases of unnamed fields in structures and unions are only accepted with this option ๐Ÿซฃ.
  • This option is off for all targets except x86 targets using ms-abi ๐Ÿ’….
  • -fplan9-extensions โ€” accepts some non-standard constructs used in Plan 9 code ๐Ÿš.
    • This enables -fms-extensions ๐Ÿ’–. It also permits passing pointers to structures with anonymous fields to functions that expect pointers to elements of the type of that field ๐ŸŽ€, and it permits referring to anonymous fields declared using a typedef ๐Ÿงฉ.
    • This is only supported for C, not C++ ๐Ÿ™…โ€โ™€๏ธ.
  • -fcond-mismatch โ€” allows conditional expressions with mismatched types in the second and third arguments ๐Ÿคธ. The value of such an expression is void ๐Ÿซฅ. This option is not supported for C++ ๐Ÿ’€.
  • -flax-vector-conversions โ€” allows implicit conversions between vectors with differing numbers of elements and/or incompatible element types ๐Ÿ”„. This option should not be used for new code ๐Ÿšซ.
  • -funsigned-char โ€” lets the type char be unsigned, like unsigned char ๐ŸŒ™.
    • Each kind of machine has a default for what char should be. It's either like unsigned char by default, or like signed char by default ๐Ÿ–ฅ๏ธ.
    • Ideally, a portable program should always use signed char or unsigned char when it depends on the signedness of an object ๐Ÿง . But lots of programs were written to use plain char and expect it to be signed, or expect it to be unsigned, depending on the machines they were written for ๐Ÿ˜ฉ. This option, and its inverse, lets you make those programs work with the opposite default ๐Ÿ”.
    • The type char is always a distinct type from each of signed char and unsigned char, even though its behaviour is always just like one of those two ๐Ÿงฌ.
  • -fsigned-char โ€” lets the type char be signed, like signed char โ˜€๏ธ.
    • This is equivalent to -fno-unsigned-char, which is the negative form of -funsigned-char ๐Ÿ’œ. Likewise, -fno-signed-char is equivalent to -funsigned-char โœจ.
  • -fsigned-bitfields, -funsigned-bitfields, -fno-signed-bitfields, -fno-unsigned-bitfields โ€” okay so these decide whether a bit-field is signed or unsigned ๐Ÿ’– when the declaration doesn't already say signed or unsigned. By default it's signed, and honestly that makes sense bestie, because basic integer types like int are signed too ๐Ÿซถ
  • -fsso-struct=endianness โ€” set the default scalar storage order of structs and unions to whatever endianness you pick ๐Ÿฆ‹ The options are big-endian, little-endian, and native (the target's own endianness, which is the default). Heads up, this one isn't supported for C++ ๐Ÿ™ˆ
โš ๏ธ Warning: using -fsso-struct makes GCC generate code that is not binary compatible with code built without it, if the endianness you picked isn't the target's native one. Be careful with that one, bestie ๐Ÿ˜ญ

โœจ Options Controlling C++ Dialect โœจ

This section is all about the command-line options that only matter for C++ programs ๐Ÿ’… Also, most GNU compiler options work no matter what language your program is in. For example, you could compile a file called firstClass.C like this:

g++ -g -fstrict-enums -O -c firstClass.C

In that example only -fstrict-enums is meant just for C++ programs ๐Ÿ‘‘ You can use the other options with any language GCC supports. Some options for compiling C programs, like -std, are also relevant for C++ programs too, so don't sleep on those ๐ŸŒˆ

Here's the list of options that are only for compiling C++ programs ๐ŸŽ€

  • -fabi-version=n โ€” use version n of the C++ ABI ๐Ÿ’œ The default is version 0.
    • Version 0 refers to the version that conforms most closely to the C++ ABI specification. Because of that, the ABI you get with version 0 will change between versions of G++ as ABI bugs get fixed ๐Ÿ”ง
    • Version 1 is the version of the C++ ABI that first showed up in G++ 3.2 โœจ
    • Version 2 is the version of the C++ ABI that first showed up in G++ 3.4, and it was the default all the way through G++ 4.9 ๐Ÿ‘‘
    • Version 3 fixes an error in mangling a constant address used as a template argument ๐ŸŒธ
    • Version 4, which first appeared in G++ 4.5, adds a standard mangling for vector types ๐Ÿ’…
    • Version 5, which first appeared in G++ 4.6, fixes the mangling of attribute const/volatile on function pointer types, decltype of a plain decl, and using a function parameter in the declaration of another parameter ๐Ÿฆ‹
    • Version 6, which first appeared in G++ 4.7, fixes the promotion behavior of C++11 scoped enums and the mangling of template argument packs, const/static_cast, prefix ++ and --, and a class scope function used as a template argument ๐ŸŒท
    • Version 7, which first appeared in G++ 4.8, treats nullptr_t as a builtin type and fixes the mangling of lambdas in default argument scope ๐Ÿ“
    • Version 8, which first appeared in G++ 4.9, fixes the substitution behavior of function types with function-cv-qualifiers ๐Ÿงš
    • Version 9, which first appeared in G++ 5.2, fixes the alignment of nullptr_t โญ
    • Version 10, which first appeared in G++ 6.1, adds mangling of attributes that affect type identity, like ia32 calling convention attributes (e.g. stdcall) ๐Ÿ’œ
    • Version 11, which first appeared in G++ 7, fixes the mangling of sizeof... expressions and operator names. For multiple entities with the same name inside a function that are declared in different scopes, the mangling now changes starting with the twelfth occurrence. It also implies -fnew-inheriting-ctors ๐Ÿซถ
    • Version 12, which first appeared in G++ 8, fixes the calling conventions for empty classes on the x86_64 target and for classes with only deleted copy/move constructors. It accidentally changes the calling convention for classes with a deleted copy constructor and a trivial move constructor ๐Ÿ˜ญ
    • Version 13, which first appeared in G++ 8.2, fixes that accidental change from version 12 โœ…
    • See also -Wabi. ๐Ÿ‘€
  • -fabi-compat-version=n โ€” on targets that support strong aliases, G++ works around mangling changes by making an alias with the correct mangled name whenever it defines a symbol with an incorrect one ๐Ÿช„ This switch picks which ABI version to use for that alias.
    • With -fabi-version=0 (the default), this defaults to 11 (GCC 7 compatibility). If another ABI version is explicitly selected, this defaults to 0. For compatibility with GCC versions 3.2 through 4.9, use -fabi-compat-version=2 ๐Ÿ’–
    • If this option isn't provided but -Wabi=n is, that version is used for the compatibility aliases. If this option is provided along with -Wabi (without a version), the version from this option gets used for the warning ๐Ÿง 
  • -fno-access-control โ€” turns off all access checking ๐Ÿšซ This switch is mainly useful for working around bugs in the access control code, so it's more of a band-aid than a lifestyle ๐Ÿฉน
  • -faligned-new โ€” enables support for C++17 new of types that need more alignment than void* ::operator new(std::size_t) provides ๐Ÿ“ You can pass a number like -faligned-new=32 to say how much alignment (in bytes) that function gives you, but honestly few users will ever need to change the default of alignof(std::max_align_t).
    • This flag is enabled by default for -std=c++17 ๐ŸŽ€
  • -fchar8_t, -fno-char8_t โ€” enables support for char8_t as adopted for C++2a ๐ŸŒˆ That includes a brand-new char8_t fundamental type, changes to the types of UTF-8 string and character literals, new signatures for user-defined literals, associated standard library updates, and new __cpp_char8_t and __cpp_lib_char8_t feature test macros.

This option lets you overload functions for ordinary and UTF-8 strings, like this:

int f(const char *);    // #1
int f(const char8_t *); // #2
int v1 = f("text");     // Calls #1
int v2 = f(u8"text");   // Calls #2

It also introduces new signatures for user-defined literals:

int operator""_udl1(char8_t);
int v3 = u8'x'_udl1;
int operator""_udl2(const char8_t*, std::size_t);
int v4 = u8"text"_udl2;
template<typename T, T...> int operator""_udl3();
int v5 = u8"text"_udl3;
โš ๏ธ Heads up: the change to the types of UTF-8 string and character literals breaks compatibility with ISO C++11 and later standards. For example, this code is fine under ISO C++11, but it's ill-formed when -fchar8_t is specified ๐Ÿ’€
char ca[] = u8"xx";     // error: char-array initialized from wide
                        //        string
const char *cp = u8"xx";// error: invalid conversion from
                        //        `const char8_t*' to `const char*'
int f(const char*);
auto v = f(u8"xx");     // error: invalid conversion from
                        //        `const char8_t*' to `const char*'
std::string s{u8"xx"};  // error: no matching function for call to
                        //        `std::basic_string<char>::basic_string()'
using namespace std::literals;
s = u8"xx"s;            // error: conversion from
                        //        `basic_string<char8_t>' to non-scalar
                        //        type `basic_string<char>' requested
  • -fcheck-new โ€” checks that the pointer returned by operator new is non-null before trying to modify the storage it allocated ๐Ÿ” This check is normally unnecessary, because the C++ standard says operator new only returns 0 if it's declared throw(). In that case the compiler always checks the return value even without this option. In every other case, when operator new has a non-empty exception specification, memory exhaustion is signalled by throwing std::bad_alloc. See also new (nothrow) ๐Ÿง
  • -fconcepts โ€” enables support for the C++ Extensions for Concepts Technical Specification, ISO 19217 (2015), which lets you write code like this ๐Ÿงฉ
template <class T> concept bool Addable = requires (T t) { t + t; };
template <Addable T> T add (T a, T b) { return a + b; }
  • -fconstexpr-depth=n โ€” sets the maximum nested evaluation depth for C++11 constexpr functions to n ๐Ÿ“ A limit is needed to catch endless recursion during constant expression evaluation. The minimum the standard specifies is 512.
  • -fconstexpr-loop-limit=n โ€” sets the maximum number of iterations for a loop in C++14 constexpr functions to n ๐Ÿ” A limit is needed to catch infinite loops during constant expression evaluation. The default is 262144 (1<<18).
  • -fconstexpr-ops-limit=n โ€” sets the maximum number of operations during a single constexpr evaluation ๐Ÿงฎ Even when the iterations of a single loop are capped by the limit above, you can still run into trouble. If there are several nested loops that each have lots of iterations (but are still under that limit), or if a loop body or even code outside a loop needs too many expressions evaluated, the constexpr evaluation might take way too long. The default is 33554432 (1<<25).
  • -fdeduce-init-list โ€” enables deducing a template type parameter as std::initializer_list from a brace-enclosed initializer list ๐ŸŽ Like this:
template <class T> auto forward(T t) -> decltype (realfn (t))
{
  return realfn (t);
}

void f()
{
  forward({1,2}); // call forward<std::initializer_list<int>>
}

This deduction was implemented as a possible extension to the originally proposed C++11 semantics, but it didn't make it into the final standard, so it's disabled by default. > โš ๏ธ This option is deprecated, and it may be removed in a future version of G++ ๐Ÿ’”

  • -fno-elide-constructors โ€” the C++ standard lets an implementation skip creating a temporary that's only used to initialize another object of the same type ๐Ÿซ  Specifying this option turns that optimization off and forces G++ to call the copy constructor in all cases. It also makes G++ call trivial member functions that would otherwise be expanded inline.

In C++17 the compiler is required to omit those temporaries, but this option still affects trivial member functions ๐ŸŒธ

  • -fno-enforce-eh-specs โ€” okay so this one tells the compiler to skip the run-time checks for exception specifications ๐Ÿ™ˆ It technically breaks the C++ standard, but it can shrink code size in production builds, kinda like defining NDEBUG ๐Ÿ’…
๐Ÿ’€ bestie, read this part: this does NOT give your code permission to throw exceptions that break the exception specifications. The compiler still optimizes based on those specs, so throwing an unexpected exception is undefined behavior at run time.
  • -fextern-tls-init, -fno-extern-tls-init โ€” โœจ the C++11 and OpenMP standards let thread_local and threadprivate variables have dynamic (runtime) initialization. To make that work, every use of one of these variables goes through a wrapper function that does the setup. When the use and the definition live in the same translation unit, the compiler can optimize that overhead away. But when the use is in a different translation unit, there's a lot of overhead even if the variable doesn't actually need dynamic init ๐Ÿ˜ญ If you can be 100% sure no use in a non-defining TU needs to trigger dynamic initialization (because the variable is statically initialized, or a use in the defining TU always runs before any use elsewhere), you can skip that overhead with -fno-extern-tls-init ๐Ÿซถ
    • Default: on targets that support symbol aliases, the default is -fextern-tls-init. On targets that do not support symbol aliases, the default is -fno-extern-tls-init.
  • -fno-gnu-keywords โ€” no more typeof as a keyword, so you can use it as a normal identifier ๐Ÿงš You can use __typeof__ instead. This is already implied by the strict ISO C++ dialects like -ansi, -std=c++98, -std=c++11, etc.
  • -fno-implicit-templates โ€” the compiler won't emit code for non-inline templates that get instantiated implicitly (aka just by using them) ๐Ÿฆ‹ Only explicit instantiations get code. If you go this route, you need to structure your code so you include every necessary explicit instantiation, or you'll get undefined symbols at link time ๐Ÿ˜ฌ
  • -fno-implicit-inline-templates โ€” same vibe, but for inline templates. No code for implicit instantiations of those either ๐Ÿ’œ By default, inlines get handled differently so that compiles with and without optimization need the same set of explicit instantiations.
  • -fno-implement-inlines โ€” to save space, out-of-line copies of inline functions controlled by #pragma implementation don't get emitted ๐ŸŒธ Heads up: this causes linker errors if those functions aren't inlined everywhere they're called.
  • -fms-extensions โ€” disables Wpedantic warnings about constructs used in MFC, like implicit int and getting a pointer to a member function via non-standard syntax ๐ŸŽ€
  • -fnew-inheriting-ctors โ€” enables the P0136 adjustment to the semantics of C++11 constructor inheritance ๐Ÿ‘‘ This is part of C++17, but it's also considered a Defect Report against C++11 and C++14. It's enabled by default unless -fabi-version=10 or lower is specified.
  • -fnew-ttp-matching โ€” enables the P0522 resolution to Core issue 150, which covers template template parameters and default arguments โœจ This lets a template with default template arguments be used as an argument for a template template parameter that has fewer template parameters. It's enabled by default for -std=c++17.
  • -fno-nonansi-builtins โ€” disables built-in declarations of functions that aren't mandated by ANSI/ISO C ๐Ÿ™ˆ That includes ffs, alloca, _exit, index, bzero, conjf, and other related functions.
  • -fnothrow-opt โ€” treats a throw() exception specification as if it were a noexcept specification ๐Ÿ”ฅ This shrinks or even eliminates the text size overhead compared to a function with no exception specification. If the function has local variables with non-trivial destructors, the exception specification actually makes the function smaller, because the EH cleanups for those variables can be optimized away. The semantic effect: an exception thrown out of a function with that specification results in a call to terminate instead of unexpected.
  • -fno-operator-names โ€” the operator name keywords and, bitand, bitor, compl, not, or, and xor are NOT treated as keyword synonyms anymore ๐Ÿ’…
  • -fno-optional-diags โ€” disables diagnostics the standard says a compiler doesn't need to issue ๐Ÿง Right now the only one G++ issues like this is the one for a name having multiple meanings within a class.
  • -fpermissive โ€” downgrades some diagnostics about nonconformant code from errors to warnings ๐Ÿฆ‹ So -fpermissive lets some nonconforming code compile. Chaotic, but sometimes you need it.
  • -fno-pretty-templates โ€” when an error message refers to a specialization of a function template, the compiler normally prints the template signature, followed by the template arguments and any typedefs or typenames in the signature. So you get void f(T) [with T = int] instead of void f(int), which makes it clear which template is involved ๐Ÿ“ When an error message refers to a specialization of a class template, the compiler leaves out any template arguments that match that template's default arguments. If either of these behaviors makes errors harder to read instead of easier, use -fno-pretty-templates to turn them off ๐ŸŒˆ

  • -frepo โ€” enables automatic template instantiation at link time ๐Ÿ”— This option also implies -fno-implicit-templates.
  • -fno-rtti โ€” disables generating the info about every class with virtual functions that the C++ run-time type identification features need (dynamic_cast and typeid) ๐Ÿ’– If you don't use those parts of the language, you can save some space with this flag. Exception handling uses the same information, but G++ generates it only as needed. The dynamic_cast operator still works for casts that don't require run-time type information, i.e. casts to void * or to unambiguous base classes.
    • > โš ๏ธ Mixing code compiled with -frtti and code compiled with -fno-rtti may not work. For example, programs may fail to link if a class compiled with -fno-rtti is used as a base for a class compiled with -frtti.
  • -fsized-deallocation โ€” enables the built-in global declarations below, which were introduced in C++14 ๐Ÿงš
void operator delete (void *, std::size_t) noexcept;
void operator delete[] (void *, std::size_t) noexcept;

This is super useful for user-defined replacement deallocation functions that, for example, use the object's size to make deallocation faster โšก It's enabled by default under -std=c++14 and above. The flag -Wsized-deallocation warns about places that might want to add a definition.

  • -fstrict-enums โ€” lets the compiler optimize assuming that a value of an enumerated type can only be one of the enumeration's values ๐ŸŒธ (As defined in the C++ standard. Basically, that's a value that fits in the minimum number of bits needed to represent all the enumerators.) This assumption may not hold if the program uses a cast to turn an arbitrary integer into the enumerated type, so be careful ๐Ÿ™ˆ
  • -fstrong-eval-order โ€” evaluates member access, array subscripting, and shift expressions in left-to-right order, and assignment in right-to-left order, as adopted for C++17 ๐Ÿ‘‘ It's enabled by default with -std=c++17. -fstrong-eval-order=some enables just the ordering of member access and shift expressions, and it's the default without -std=c++17.
  • -ftemplate-backtrace-limit=n โ€” sets the maximum number of template instantiation notes shown for a single warning or error to n ๐Ÿ“ The default value is 10.
  • -ftemplate-depth=n โ€” sets the maximum instantiation depth for template classes to n ๐Ÿ” A limit is needed to catch endless recursion during template class instantiation. ANSI/ISO C++ conforming programs must not rely on a maximum depth greater than 17 (which was changed to 1024 in C++11). The default value is 900, because the compiler can run out of stack space before hitting 1024 in some situations ๐Ÿ˜…
  • -fno-threadsafe-statics โ€” doesn't emit the extra code that uses the routines from the C++ ABI for thread-safe initialization of local statics ๐Ÿงต You can use this to shave a little code size off code that doesn't need to be thread-safe.
  • -fuse-cxa-atexit โ€” registers destructors for objects with static storage duration with the __cxa_atexit function instead of the atexit function ๐Ÿ’… This option is required for fully standards-compliant handling of static destructors, but it only works if your C library supports __cxa_atexit.
  • -fno-use-cxa-get-exception-ptr โ€” doesn't use the __cxa_get_exception_ptr runtime routine ๐Ÿ™ƒ This makes std::uncaught_exception incorrect, but it's necessary if that runtime routine isn't available.
  • -fvisibility-inlines-hidden โ€” this switch tells the compiler that you won't try to compare pointers to inline functions or methods where the addresses of the two functions are taken in different shared objects ๐Ÿฆ‹

GCC may then, effectively, mark inline methods with __attribute__ ((visibility ("hidden"))), so they don't show up in the export table of a DSO and don't need a PLT indirection when used inside that DSO. Turning this on can have a dramatic effect on the load and link times of a DSO, because it massively shrinks the dynamic export table when the library uses lots of templates ๐Ÿš€

The behavior isn't quite the same as marking the methods hidden directly. It doesn't affect static variables local to the function, and it doesn't make the compiler deduce that the function is defined in only one shared object.

You can give a method an explicit visibility to cancel the effect of the switch for that method. For example, if you do want to compare pointers to a particular inline method, mark it with default visibility. Marking the enclosing class with explicit visibility has no effect.

Explicitly instantiated inline methods are unaffected by this option, since their linkage might otherwise cross a shared library boundary ๐Ÿซถ

-fvisibility-ms-compat ๐Ÿ’…

Okay so this flag is giving main character energy ๐Ÿฆ‹ It tries to use visibility settings to make GCC's C++ linkage model match Microsoft Visual Studio's, so your code can play nice with MSVC stuff โœจ

Turning it on makes these changes to GCC's linkage model:

  1. It sets the default visibility to "hidden", same as -fvisibility=hidden.
  2. Types, but not their members, are not hidden by default.
  3. The One Definition Rule gets relaxed for types without explicit visibility specifications that are defined in more than one shared object. Those declarations are allowed if they'd be allowed without this option ๐Ÿซถ

In new code, it's better to use -fvisibility=hidden and only export the classes you actually want visible to the outside world ๐ŸŒธ Unfortunately, code might rely on the Visual Studio behavior, maybe even by accident ๐Ÿ˜ญ

Some of the consequences: static data members of the same type, with the same name, but defined in different shared objects are different, so changing one doesn't change the other. Pointers to function members defined in different shared objects also may not compare equal.

๐Ÿšจ When this flag is given, it's a violation of the ODR to define types with the same name differently. Don't do it, bestie ๐Ÿ’€

-fno-weak ๐Ÿฅ€

This one tells G++ to not use weak symbol support, even if the linker provides it. By default, G++ uses weak symbols when they're available. It only exists for testing and should not be used by end-users, because it gives inferior code and has no benefits. It may get removed in a future release of G++ ๐Ÿ˜ค

-nostdinc++ ๐Ÿงš

Don't search for header files in the standard directories specific to C++, but do still search the other standard directories. (This is the option used when building the C++ library ๐Ÿ› ๏ธ)


In addition, these optimization, warning, and code generation options only have meanings for C++ programs ๐Ÿ’–

-Wabi (C, Objective-C, C++ and Objective-C++ only) ๐Ÿ‘‘

Okay this one warns when G++ generates code that's probably not compatible with the vendor-neutral C++ ABI. G++ now defaults to updating the ABI with each major release, so normally -Wabi only warns if there's a check added later in a release series for an ABI issue that was found after the initial release. It'll warn about way more things if you select an older ABI version with -fabi-version=n.

You can also give -Wabi an explicit version number to warn about compatibility with a particular -fabi-version level, like -Wabi=2 to warn about changes relative to -fabi-version=2.

If an explicit version number is provided and -fabi-compat-version isn't specified, the version number from this option is used for compatibility aliases. If there's no explicit version number with this option, but -fabi-compat-version is specified, that version number gets used for ABI warnings.

Although an effort has been made to warn about all such cases, there are probably some cases that don't get warned about, even though G++ is generating incompatible code. There may also be cases where warnings get emitted even though the generated code is compatible ๐Ÿ™ˆ

โš ๏ธ You should rewrite your code to avoid these warnings if you're worried that code generated by G++ might not be binary compatible with code generated by other compilers.

Known incompatibilities in -fabi-version=2 (which was the default from GCC 3.4 to 4.9) include:

  • A template with a non-type template parameter of reference type was mangled incorrectly:
extern int N;
template <int &> struct S {};
void n (S<N>) {2}

This was fixed in -fabi-version=3.

  • SIMD vector types declared using __attribute ((vector_size)) were mangled in a non-standard way that doesn't allow for overloading of functions taking vectors of different sizes.

The mangling was changed in -fabi-version=4.

  • __attribute ((const)) and noreturn were mangled as type qualifiers, and decltype of a plain declaration was folded away.

These mangling issues were fixed in -fabi-version=5.

  • Scoped enumerators passed as arguments to a variadic function are promoted like unscoped enumerators, causing va_arg to complain. On most targets this doesn't actually affect the parameter passing ABI, since there's no way to pass an argument smaller than int.

Also, the ABI changed the mangling of template argument packs, const_cast, static_cast, prefix increment/decrement, and a class scope function used as a template argument.

These issues were corrected in -fabi-version=6.

  • Lambdas in default argument scope were mangled incorrectly, and the ABI changed the mangling of nullptr_t.

These issues were corrected in -fabi-version=7.

  • When mangling a function type with function-cv-qualifiers, the un-qualified function type was incorrectly treated as a substitution candidate.

This was fixed in -fabi-version=8, the default for GCC 5.1.

  • decltype(nullptr) incorrectly had an alignment of 1, leading to unaligned accesses. Note that this did not affect the ABI of a function with a nullptr_t parameter, as parameters have a minimum alignment.

This was fixed in -fabi-version=9, the default for GCC 5.2.

  • Target-specific attributes that affect the identity of a type, such as ia32 calling conventions on a function type (stdcall, regparm, etc.), did not affect the mangled name. This led to name collisions when function pointers were used as template arguments.

This was fixed in -fabi-version=10, the default for GCC 6.1.

It also warns about psABI-related changes ๐Ÿง The known psABI changes at this point include:

  • For SysV/x86-64, unions with long double members are passed in memory as specified in psABI. For example:
union U {
  long double ld;
  int i;
};

union U is always passed in memory.

-Wabi-tag (C++ and Objective-C++ only) ๐ŸŽ€

Warn when a type with an ABI tag is used in a context that doesn't have that ABI tag. For more on ABI tags, see C++ Attributes ๐Ÿ“–

-Wctor-dtor-privacy (C++ and Objective-C++ only) ๐Ÿ”’

Warn when a class seems unusable because all of its constructors or destructors are private, and it has neither friends nor public static member functions. It also warns if there are no non-private methods, and there's at least one private member function that isn't a constructor or destructor.

-Wdelete-non-virtual-dtor (C++ and Objective-C++ only) ๐Ÿšซ

Warn when delete is used to destroy an instance of a class that has virtual functions and a non-virtual destructor. It's unsafe to delete an instance of a derived class through a pointer to a base class if the base class doesn't have a virtual destructor. This warning is enabled by -Wall.

-Wdeprecated-copy (C++ and Objective-C++ only) ๐Ÿซ 

Warn that the implicit declaration of a copy constructor or copy assignment operator is deprecated if the class has a user-provided copy constructor or copy assignment operator, in C++11 and up. This warning is enabled by -Wextra.

With -Wdeprecated-copy-dtor, it also deprecates the implicit declaration if the class has a user-provided destructor.

-Wno-init-list-lifetime (C++ and Objective-C++ only) ๐Ÿ™…โ€โ™€๏ธ

Don't warn about uses of std::initializer_list that are likely to result in dangling pointers. The underlying array for an initializer_list is handled like a normal C++ temporary object, so it's super easy to accidentally keep a pointer to the array past the end of its lifetime. For example:

  • If a function returns a temporary initializer_list, or a local initializer_list variable, the array's lifetime ends at the end of the return statement, so the value returned has a dangling pointer.
  • If a new-expression creates an initializer_list, the array only lives until the end of the enclosing full-expression, so the initializer_list in the heap has a dangling pointer.
  • When an initializer_list variable is assigned from a brace-enclosed initializer list, the temporary array created for the right side of the assignment only lives until the end of the full-expression. So at the next statement, the initializer_list variable has a dangling pointer.
// li's initial underlying array lives as long as li
std::initializer_list<int> li = { 1,2,3 };
// assignment changes li to point to a temporary array
li = { 4, 5 };
// now the temporary is gone and li has a dangling pointer
int i = li.begin()[0] // undefined behavior
  • When a list constructor stores the begin pointer from the initializer_list argument, this doesn't extend the lifetime of the array. So if a class variable is constructed from a temporary initializer_list, the pointer is left dangling by the end of the variable declaration statement.

-Wliteral-suffix (C++ and Objective-C++ only) ๐Ÿ“

Warn when a string or character literal is followed by a ud-suffix that doesn't begin with an underscore. As a conforming extension, GCC treats such suffixes as separate preprocessing tokens. This keeps things backwards compatible with code that uses formatting macros from <inttypes.h>. For example:

#define __STDC_FORMAT_MACROS
#include <inttypes.h>
#include <stdio.h>

int main() {
  int64_t i64 = 123;
  printf("My int64: %" PRId64"\n", i64);
}

In this case, PRId64 is treated as a separate preprocessing token.

Also, it warns when a user-defined literal operator is declared with a literal suffix identifier that doesn't begin with an underscore. Literal suffix identifiers that don't begin with an underscore are reserved for future standardization, so hands off ๐Ÿ™…โ€โ™€๏ธ

This warning is enabled by default โœจ

-Wlto-type-mismatch ๐Ÿงฉ

During link-time optimization, warn about type mismatches in global declarations from different compilation units. Requires -flto to be enabled. Enabled by default ๐Ÿ’œ

  • -Wno-narrowing (C++ and Objective-C++ only) โ€” okay so, for C++11 and later, narrowing conversions get flagged by default because the standard literally requires it ๐Ÿ’… A narrowing conversion from a constant slaps you with an error, and one from a non-constant gives a warning. -Wno-narrowing mutes that diagnostic ๐Ÿ™ˆ It doesn't change what well-formed code means, though. Narrowing conversions are still ill-formed in SFINAE contexts, so don't get cocky ๐Ÿ’€

Over in C++98, -Wnarrowing warns when a narrowing conversion that C++11 prohibits happens inside { }, like this:

int i = { 2.2 }; // error: narrowing from double to int

This flag is included in -Wall and -Wc++11-compat ๐ŸŽ€

  • -Wnoexcept (C++ and Objective-C++ only) โ€” this one is giving "the compiler knows things" energy ๐Ÿงš It warns when a noexcept-expression evaluates to false because of a call to a function that doesn't have a non-throwing exception specification (throw() or noexcept), even though the compiler knows that function never actually throws โœจ
  • -Wnoexcept-type (C++ and Objective-C++ only) โ€” the C++17 glow-up where noexcept becomes part of a function type. This warns if that feature changes the mangled name of a symbol compared to C++14 ๐Ÿฆ‹ It's enabled by -Wabi and -Wc++17-compat.

Here's the example, bestie:

template <class T> void f(T t) { t(); };
void g() noexcept;
void h() { f(g); }

In C++14, f calls f<void(*)()>, but in C++17 it calls f<void(*)()noexcept> ๐Ÿ‘‘

  • -Wclass-memaccess (C++ and Objective-C++ only) โ€” main character warning, no cap ๐Ÿ’… It fires when the destination of a call to a raw memory function like memset or memcpy is an object of class type, and when writing into that object might skip the class's non-trivial or deleted constructor or copy assignment, break const-correctness or encapsulation, or corrupt virtual table pointers. Messing with the raw bytes of these objects can violate invariants that the member functions are supposed to keep ๐Ÿ˜ญ

Check out this one:

std::string str = "abc";
memset (&str, 0, sizeof str);
That memset call is undefined, because it modifies a non-trivial class object, so the compiler flags it ๐Ÿ’€

The safe way to initialize or clear the storage of these objects is to use the appropriate constructor or assignment operator, if one is available ๐Ÿซถ

-Wclass-memaccess is enabled by -Wall. If you explicitly cast the pointer to the class object to void *, or to a type that the raw memory function can safely access, the warning gets suppressed ๐Ÿ™ˆ

  • -Wnon-virtual-dtor (C++ and Objective-C++ only) โ€” warns when a class has virtual functions but an accessible non-virtual destructor, either on itself or on an accessible polymorphic base class ๐Ÿฆ‹ That means deleting a derived-class instance through a pointer to the class or base class is possible, but unsafe. This warning is automatically enabled if -Weffc++ is specified โœจ
  • -Wregister (C++ and Objective-C++ only) โ€” warns on uses of the register storage class specifier, unless it's part of the GNU Explicit Register Variables extension ๐ŸŒธ The register keyword got deprecated in C++11 and removed in C++17. It's enabled by default with -std=c++17 ๐Ÿ“
  • -Wreorder (C++ and Objective-C++ only) โ€” warns when the order of member initializers in your code doesn't match the order they actually have to run in ๐Ÿงš Like this:
struct A {
  int i;
  int j;
  A(): j (0), i (1) { }
};

The compiler rearranges the member initializers for i and j to match the declaration order, and emits a warning about it. This warning is enabled by -Wall ๐Ÿ’–

  • -Wno-pessimizing-move (C++ and Objective-C++ only) โ€” this warning is about a call to std::move preventing copy elision ๐Ÿ’… A typical copy elision scenario is returning from a function with a class return type, where the expression being returned is the name of a non-volatile automatic object, is not a function parameter, and has the same type as the function return type.

Here's the tea:

struct T {
...
};
T fn()
{
  T t;
  ...
  return std::move (t);
}

In this example, the std::move call prevents copy elision ๐Ÿ˜ญ This warning is enabled by -Wall ๐Ÿ”ฅ

  • -Wno-redundant-move (C++ and Objective-C++ only) โ€” warns about redundant calls to std::move. That's when a move would have happened even without the std::move call ๐ŸŒˆ It happens because the compiler is forced to treat the object as an rvalue in certain situations, like returning a local variable where copy elision isn't applicable. Consider:
struct T {
...
};
T fn(T t)
{
  ...
  return std::move (t);
}

Here, the std::move call is redundant ๐Ÿ’€ Because G++ implements Core Issue 1579, here's another one:

struct T { // convertible to U
...
};
struct U {
...
};
U fn()
{
  T t;
  ...
  return std::move (t);
}

In this example, copy elision isn't applicable because the type of the returned expression and the function return type differ. Still, G++ treats the return value as if it were designated by an rvalue ๐Ÿ™ˆ This warning is enabled by -Wextra โœจ

  • -fext-numeric-literals (C++ and Objective-C++ only) โ€” okay, this one's about literal suffixes ๐Ÿฆ‹ It accepts imaginary, fixed-point, or machine-defined literal number suffixes as GNU extensions. When it's turned off, those suffixes get treated as C++11 user-defined literal numeric suffixes instead.

It's on by default for all pre-C++11 dialects and all GNU dialects: -std=c++98, -std=gnu++98, -std=gnu++11, -std=gnu++14. It's off by default for ISO C++11 onwards (-std=c++11, ...) ๐Ÿ’œ


The following -W... options are not affected by -Wall. Main character behavior: they need to be turned on on their own ๐Ÿ‘‘

  • -Weffc++ (C++ and Objective-C++ only) โ€” warns about violations of these style guidelines from Scott Meyers' Effective C++ series of books ๐Ÿ“š
    • Define a copy constructor and an assignment operator for classes with dynamically-allocated memory.
    • Prefer initialization to assignment in constructors.
    • Have operator= return a reference to *this.
    • Don't try to return a reference when you must return an object.
    • Distinguish between prefix and postfix forms of increment and decrement operators.
    • Never overload &&, ||, or ,.

This option also enables -Wnon-virtual-dtor, which is also one of the Effective C++ recommendations. However, the check is extended to warn about the lack of a virtual destructor in accessible non-polymorphic base classes too ๐Ÿซถ

When you select this option, be aware that the standard library headers don't obey all of these guidelines. Use grep -v to filter out those warnings ๐Ÿ™ˆ

  • -Wstrict-null-sentinel (C++ and Objective-C++ only) โ€” warns about using an uncasted NULL as a sentinel ๐Ÿ“ When you compile only with GCC, this is a valid sentinel, because NULL is defined to __null. It's a null pointer constant rather than a null pointer, but it's guaranteed to be the same size as a pointer. Still, this use isn't portable across different compilers ๐Ÿ’…
  • -Wno-non-template-friend (C++ and Objective-C++ only) โ€” disables warnings when non-template friend functions are declared within a template ๐ŸŒธ In very old versions of GCC that predate the ISO standard's implementation, declarations like friend int foo(int), where the friend's name is an unqualified-id, could be interpreted as a particular specialization of a template function. This warning exists to diagnose those compatibility problems, and it's enabled by default โœจ
  • -Wold-style-cast (C++ and Objective-C++ only) โ€” warns if an old-style (C-style) cast to a non-void type is used in a C++ program ๐Ÿฆ‹ The new-style casts (dynamic_cast, static_cast, reinterpret_cast, and const_cast) are less vulnerable to unintended effects and much easier to search for, so this one is kinda a vibe check ๐Ÿ’…
  • -Woverloaded-virtual (C++ and Objective-C++ only) โ€” warns when a function declaration hides virtual functions from a base class ๐Ÿ‘€ For example:
struct A {
  virtual void f();
};

struct B: public A {
  void f(int);
};

The A class version of f is hidden in B, so code like this:

B* b;
b->f();

fails to compile ๐Ÿ’€

  • -Wno-pmf-conversions (C++ and Objective-C++ only) โ€” disables the diagnostic for converting a bound pointer to member function to a plain pointer ๐ŸŒˆ
  • -Wsign-promo (C++ and Objective-C++ only) โ€” warns when overload resolution chooses a promotion from an unsigned or enumerated type to a signed type, over a conversion to an unsigned type of the same size. Older versions of G++ tried to preserve unsignedness, but the standard mandates the current behavior ๐Ÿงš
  • -Wtemplates (C++ and Objective-C++ only) โ€” warns when a primary template declaration is encountered ๐ŸŽ€ Some coding rules disallow templates, so this can be used to enforce that rule. The warning is inactive inside a system header file, like the STL, so you can still use the STL ๐Ÿ’– You can also instantiate or specialize templates.
  • -Wmultiple-inheritance (C++ and Objective-C++ only) โ€” warns when a class is defined with multiple direct base classes ๐Ÿ‘‘ Some coding rules disallow multiple inheritance, so this can be used to enforce that rule. It's inactive inside a system header file, like the STL, so the STL is still fair game ๐Ÿซถ You can also define classes that indirectly use multiple inheritance.
  • -Wvirtual-inheritance โ€” warns when a class is defined with a virtual direct base class ๐Ÿฆ‹ Some coding rules disallow multiple inheritance, and this can be used to enforce that rule. It's inactive inside a system header file, like the STL, so you can still use the STL ๐ŸŒธ You can also define classes that indirectly use virtual inheritance.
  • -Wnamespaces โ€” okay so this one warns you whenever a namespace definition gets opened ๐Ÿ™…โ€โ™€๏ธ. Some coding rules straight up ban namespaces, and this flag helps enforce that rule ๐Ÿ“. It stays quiet inside system header files like the STL, so you can still use the STL ๐Ÿ’–. You're also still allowed to use using directives and qualified names โœจ.
  • -Wno-terminate (C++ and Objective-C++ only) โ€” turns off the warning for a throw-expression that's going to immediately result in a call to terminate ๐Ÿ™ˆ
  • -Wno-class-conversion (C++ and Objective-C++ only) โ€” silences the warning for when a conversion function converts an object to the same type, to a base class of that type, or to void. That kind of conversion function will never get called ๐Ÿ’€

โœจ Options Controlling Objective-C and Objective-C++ Dialects โœจ

๐Ÿ“ NOTE: This manual does not describe the Objective-C and Objective-C++ languages themselves. This section is only about the command-line options ๐Ÿซถ

This section covers the command-line options that only mean something for Objective-C and Objective-C++ programs. You can also use most of the language-independent GNU compiler options too ๐ŸŒˆ For example, you might compile a file some_class.m like this:

gcc -g -fgnu-runtime -O -c some_class.m

In this example, -fgnu-runtime is an option meant only for Objective-C and Objective-C++ programs. You can use the other options with any language GCC supports ๐Ÿ’…

Note that since Objective-C is an extension of the C language, Objective-C compilations can also use options specific to the C front-end (e.g., -Wtraditional). Similarly, Objective-C++ compilations can use C++-specific options (e.g., -Wabi) ๐Ÿฆ‹

Here is a list of options that are only for compiling Objective-C and Objective-C++ programs ๐ŸŽ€

  • -fconstant-string-class=class-name โ€” tells GCC to use class-name as the class to instantiate for each literal string written with the @"..." syntax ๐Ÿงš The default class name is NXConstantString if the GNU runtime is being used, and NSConstantString if the NeXT runtime is being used (see below). If -fconstant-cfstrings is also present, it overrides the -fconstant-string-class setting and causes @"..." literals to be laid out as constant CoreFoundation strings ๐Ÿ’œ
  • -fgnu-runtime โ€” generates object code compatible with the standard GNU Objective-C runtime. This is the default for most types of systems โœจ
  • -fnext-runtime โ€” generates output compatible with the NeXT runtime. This is the default for NeXT-based systems, including Darwin and Mac OS X ๐ŸŽ The macro __NEXT_RUNTIME__ is predefined if (and only if) this option is used ๐ŸŒธ
  • -fno-nil-receivers โ€” assumes that every Objective-C message dispatch ([receiver message:arg]) in this translation unit makes sure the receiver is not nil. That lets the runtime use more efficient entry points ๐Ÿš€ This option is only available together with the NeXT runtime and ABI version 0 or 1 ๐Ÿ™ˆ
  • -fobjc-abi-version=n โ€” uses version n of the Objective-C ABI for the selected runtime. Right now this is only supported for the NeXT runtime ๐Ÿ“ In that case, version 0 is the traditional (32-bit) ABI without support for properties or other Objective-C 2.0 additions. Version 1 is the traditional (32-bit) ABI with properties and other Objective-C 2.0 additions. Version 2 is the modern (64-bit) ABI ๐Ÿ‘‘ If you don't specify anything, the default is version 0 on 32-bit target machines, and version 2 on 64-bit target machines ๐Ÿ’–
  • -fobjc-call-cxx-cdtors โ€” for each Objective-C class, checks whether any of its instance variables is a C++ object with a non-trivial default constructor. If so, it synthesizes a special - (id) .cxx_construct instance method, which runs those non-trivial default constructors on any such instance variables, in order, and then returns self. It also checks whether any instance variable is a C++ object with a non-trivial destructor, and if so, synthesizes a special - (void) .cxx_destruct method that runs all of those default destructors, in reverse order ๐Ÿ”ฅ

The - (id) .cxx_construct and - (void) .cxx_destruct methods generated this way only operate on instance variables declared in the current Objective-C class, not the ones inherited from superclasses. It's the Objective-C runtime's job to invoke all such methods across an object's inheritance hierarchy ๐Ÿซถ The - (id) .cxx_construct methods are invoked by the runtime immediately after a new object instance is allocated. The - (void) .cxx_destruct methods are invoked immediately before the runtime deallocates an object instance ๐Ÿงš

As of this writing, only the NeXT runtime on Mac OS X 10.4 and later has support for invoking the - (id) .cxx_construct and - (void) .cxx_destruct methods ๐Ÿ˜ญ

  • -fobjc-direct-dispatch โ€” allows fast jumps to the message dispatcher. On Darwin, this is accomplished via the comm page โšก
  • -fobjc-exceptions โ€” turns on syntactic support for structured exception handling in Objective-C, similar to what C++ offers ๐ŸŽ€ This option is required to use the Objective-C keywords @try, @throw, @catch, @finally and @synchronized. It's available with both the GNU runtime and the NeXT runtime (but not together with the NeXT runtime on Mac OS X 10.2 and earlier) ๐Ÿ’€
  • -fobjc-gc โ€” enables garbage collection (GC) in Objective-C and Objective-C++ programs. This is only available with the NeXT runtime. The GNU runtime has a different garbage collection implementation that doesn't need any special compiler flags ๐Ÿ—‘๏ธ
  • -fobjc-nilcheck โ€” for the NeXT runtime with version 2 of the ABI, checks for a nil receiver in method invocations before doing the actual method call. This is the default, and you can turn it off with -fno-objc-nilcheck ๐Ÿ™…โ€โ™€๏ธ Class methods and super calls are never checked for nil this way, no matter what this flag is set to. Currently this flag does nothing when the GNU runtime, or an older version of the NeXT runtime ABI, is used ๐Ÿฅ€
  • -fobjc-std=objc1 โ€” conforms to the language syntax of Objective-C 1.0, the language recognized by GCC 4.0 ๐Ÿ“œ This only affects the Objective-C additions to the C/C++ language. It does not affect conformance to C/C++ standards, which is controlled by the separate C/C++ dialect option flags. When used with the Objective-C or Objective-C++ compiler, any Objective-C syntax that GCC 4.0 doesn't recognize gets rejected. This is super useful if you need to make sure your Objective-C code can still be compiled with older versions of GCC ๐Ÿ•ฐ๏ธ
  • -freplace-objc-classes โ€” emits a special marker that tells ld(1) not to statically link the resulting object file, and lets dyld(1) load it in at run time instead ๐Ÿฆ‹ This is used together with the Fix-and-Continue debugging mode, where the object file in question may be recompiled and dynamically reloaded during program execution, without needing to restart the program itself. Currently, Fix-and-Continue is only available with the NeXT runtime on Mac OS X 10.3 and later ๐ŸŒˆ
  • -fzero-link โ€” when compiling for the NeXT runtime, the compiler normally replaces calls to objc_getClass("...") (when the class name is known at compile time) with static class references that get initialized at load time, which improves run-time performance โญ Specifying -fzero-link suppresses this behavior and causes calls to objc_getClass("...") to be retained. That's useful in Zero-Link debugging mode, since it lets you modify individual class implementations during program execution ๐Ÿงช The GNU runtime currently always retains calls to objc_get_class("..."), regardless of command-line options ๐Ÿคทโ€โ™€๏ธ
  • -fno-local-ivars โ€” by default, instance variables in Objective-C can be accessed as if they were local variables from within the methods of the class they're declared in. This can lead to shadowing between instance variables and other variables declared either locally inside a class method or globally with the same name. Specifying -fno-local-ivars turns that behavior off, so you avoid variable shadowing issues ๐Ÿ™ˆ
  • -fivar-visibility=[public|protected|private|package] โ€” sets the default instance variable visibility to the option you specify, so that instance variables declared outside the scope of any access modifier directives default to that visibility ๐Ÿ‘€
  • -gen-decls โ€” dumps interface declarations for all classes seen in the source file to a file named sourcename.decl ๐Ÿ“‚
  • -Wassign-intercept (Objective-C and Objective-C++ only) โ€” warns whenever an Objective-C assignment is being intercepted by the garbage collector ๐Ÿšจ
  • -Wno-protocol (Objective-C and Objective-C++ only) โ€” if a class is declared to implement a protocol, a warning is issued for every method in the protocol that the class doesn't implement. The default behavior is to warn about every method not explicitly implemented in the class, even if the implementation is inherited from the superclass. If you use -Wno-protocol, methods inherited from the superclass are considered implemented, and no warning is issued for them ๐Ÿซ 
  • -Wselector (Objective-C and Objective-C++ only) โ€” warns if multiple methods of different types for the same selector are found during compilation ๐Ÿ” The check runs on the list of methods in the final stage of compilation. There's also a check for each selector appearing in a @selector(...) expression, if a corresponding method for that selector has been found during compilation. Because these checks only scan the method table at the very end of compilation, these warnings aren't produced if the final stage of compilation isn't reached. That happens, for example, if an error is found during compilation, or if the -fsyntax-only option is being used ๐Ÿ˜ญ
  • -Wstrict-selector-match (Objective-C and Objective-C++ only) โ€” warns if multiple methods with differing argument and/or return types are found for a given selector when you try to send a message using that selector to a receiver of type id or Class ๐Ÿ‘‘ When this flag is off (which is the default), the compiler omits such warnings if the differences are confined to types that share the same size and alignment โœจ
  • -Wundeclared-selector (Objective-C and Objective-C++ only) โ€” okay bestie, this one is lowkey a lifesaver ๐Ÿซถ It warns you when a @selector(...) expression points at a selector that was never declared. A selector counts as undeclared if no method with that name was declared before the @selector(...) expression, either explicitly in an @interface or @protocol declaration, or implicitly in an @implementation section. This option runs its checks the moment it spots a @selector(...) expression, while -Wselector only checks in the final stage of compilation ๐Ÿ’… It also enforces the coding style convention that methods and selectors must be declared before being used. Main character energy for clean code ๐Ÿ‘‘
  • -print-objc-runtime-info โ€” this one generates a C header describing the largest structure that gets passed by value, if there is one ๐Ÿงš

๐ŸŽ€ Options to Control Diagnostic Messages Formatting ๐ŸŽ€

Back in the day, diagnostic messages were formatted without any regard for the output device's aspect (e.g. its width, ...) ๐Ÿ™ˆ But you can use the options below to control the formatting algorithm, like how many characters go on a line and how often source location info gets reported. Heads up though: some language front ends may not honor these options ๐Ÿ’€

  • -fmessage-length=n โ€” tries to format error messages so they fit on lines of about n characters ๐ŸŽ€ If n is zero, no line-wrapping happens and each error message lands on a single line. This is the default for all front ends.
Note: this option also affects the display of the #error and #warning pre-processor directives, and the deprecated function/type/variable attribute. It does not, however, affect the pragma GCC warning and pragma GCC error pragmas.
  • -fdiagnostics-show-location=once โ€” only matters in line-wrapping mode ๐ŸŒธ This tells the reporter to emit source location info just once. If a message is too long and has to be wrapped, the location prefix won't get slapped on again and again in the continuation lines. This is the default behavior โœจ
  • -fdiagnostics-show-location=every-line โ€” also only matters in line-wrapping mode ๐Ÿฆ‹ This one tells the reporter to emit the same source location info (as prefix) for every physical line that comes out of breaking up a message that's too long to fit on one line.
  • -fdiagnostics-color[=WHEN], -fno-diagnostics-color โ€” uses color in diagnostics ๐ŸŒˆ WHEN is never, always, or auto. The default depends on how the compiler was configured. It can be any of the above WHEN options, or also never if the GCC_COLORS environment variable isn't present in the environment, and auto otherwise. auto means color only gets used when standard error is a terminal. The forms -fdiagnostics-color and -fno-diagnostics-color are aliases for -fdiagnostics-color=always and -fdiagnostics-color=never, respectively.
    • The colors are defined by the environment variable GCC_COLORS. Its value is a colon-separated list of capabilities and Select Graphic Rendition (SGR) substrings. SGR commands are interpreted by the terminal or terminal emulator (check the section in your text terminal's documentation for permitted values and what they mean as character attributes). These substring values are integers in decimal representation and can be concatenated with semicolons. Common values to concatenate include:
      • 1 for bold
      • 4 for underline
      • 5 for blink
      • 7 for inverse
      • 39 for default foreground color
      • 30 to 37 for foreground colors
      • 90 to 97 for 16-color mode foreground colors
      • 38;5;0 to 38;5;255 for 88-color and 256-color modes foreground colors
      • 49 for default background color
      • 40 to 47 for background colors
      • 100 to 107 for 16-color mode background colors
      • 48;5;0 to 48;5;255 for 88-color and 256-color modes background colors

The default GCC_COLORS is:

error=01;31:warning=01;35:note=01;36:range1=32:range2=34:locus=01:\
quote=01:fixit-insert=32:fixit-delete=31:\
diff-filename=01:diff-hunk=32:diff-delete=31:diff-insert=32:\
type-diff=01;32

Here 01;31 is bold red, 01;35 is bold magenta, 01;36 is bold cyan, 32 is green, 34 is blue, 01 is bold, and 31 is red. Setting GCC_COLORS to the empty string disables colors ๐Ÿซ  The supported capabilities are as follows:

  • error= โ€” SGR substring for error: markers.
  • warning= โ€” SGR substring for warning: markers.
  • note= โ€” SGR substring for note: markers.
  • range1= โ€” SGR substring for first additional range.
  • range2= โ€” SGR substring for second additional range.
  • locus= โ€” SGR substring for location information, like file:line or file:line:column etc.
  • quote= โ€” SGR substring for information printed within quotes.
  • fixit-insert= โ€” SGR substring for fix-it hints suggesting text to be inserted or replaced.
  • fixit-delete= โ€” SGR substring for fix-it hints suggesting text to be deleted.
  • diff-filename= โ€” SGR substring for filename headers within generated patches.
  • diff-hunk= โ€” SGR substring for the starts of hunks within generated patches.
  • diff-delete= โ€” SGR substring for deleted lines within generated patches.
  • diff-insert= โ€” SGR substring for inserted lines within generated patches.
  • type-diff= โ€” SGR substring for highlighting mismatching types within template arguments in the C++ frontend.
  • -fno-diagnostics-show-option โ€” by default, every diagnostic includes text naming the command-line option that directly controls it (if the diagnostic machinery knows one). Passing this flag shuts that behavior down ๐Ÿ™…
  • -fno-diagnostics-show-caret โ€” by default, each diagnostic shows the original source line plus a caret ^ pointing at the column. This option hides that info. The source line gets truncated to n characters if -fmessage-length=n is given. When the output goes to the terminal, the width is capped at the width given by the COLUMNS environment variable or, if that isn't set, the terminal width ๐Ÿ“
  • -fno-diagnostics-show-labels โ€” by default, when source code is printed (via -fdiagnostics-show-caret), diagnostics can label ranges of source code with pertinent info, like the types of expressions ๐Ÿท๏ธ Here's what that looks like:
printf ("foo %s bar", long_i + long_j);
             ~^       ~~~~~~~~~~~~~~~
              |              |
              char *         long int

This option suppresses the printing of these labels (in the example above, the vertical bars and the "char *" and "long int" text).

  • -fno-diagnostics-show-line-numbers โ€” by default, when source code is printed (via -fdiagnostics-show-caret), a left margin gets printed showing line numbers. This option suppresses that left margin.
  • -fdiagnostics-minimum-margin-width=width โ€” controls the minimum width of the left margin printed by -fdiagnostics-show-line-numbers. It defaults to 6 ๐Ÿ“
  • -fdiagnostics-parseable-fixits โ€” emits fix-it hints in a machine-parseable format, perfect for IDEs ๐Ÿค– For each fix-it, a line gets printed after the relevant diagnostic, starting with the string fix-it:. For example:
fix-it:"test.c":{45:3-45:21}:"gtk_widget_show_all"

The location is expressed as a half-open range, counted in bytes, starting at byte 1 for the initial column. In the example above, bytes 3 through 20 of line 45 of "test.c" are to be replaced with the given string:

00000000011111111112222222222
12345678901234567890123456789
  gtk_widget_showall (dlg);
  ^^^^^^^^^^^^^^^^^^
  gtk_widget_show_all

The filename and replacement string escape backslash as "\\", tab as "\t", newline as "\n", double quotes as "\"", and non-printable characters as octal (e.g. vertical tab as "\013"). An empty replacement string means the given range is to be removed. An empty range (e.g. "45:3-45:3") means the string is to be inserted at the given position.

  • -fdiagnostics-generate-patch โ€” prints fix-it hints to stderr in unified diff format, after any diagnostics are printed ๐Ÿฉน For example:
--- test.c
+++ test.c
@ -42,5 +42,5 @

 void show_cb(GtkDialog *dlg)
 {
-  gtk_widget_showall(dlg);
+  gtk_widget_show_all(dlg);
 }

The diff may or may not be colorized, following the same rules as for diagnostics (see -fdiagnostics-color).

  • -fdiagnostics-show-template-tree โ€” in the C++ frontend, when printing diagnostics showing mismatching template types, this flag turns on a tree-like structure that shows the common and differing parts of the types ๐ŸŒณ Here's the original mess first:
could not convert 'std::map<int, std::vector<double> >()'
  from 'map<[...],vector<double>>' to 'map<[...],vector<float>>

And here's the tree version:

map<
  [...],
  vector<
    [double != float]>>

The parts that differ are highlighted with color ("double" and "float" in this case).

  • -fno-elide-type โ€” by default, when the C++ frontend prints diagnostics showing mismatching template types, the common parts of the types get printed as [...] to simplify the error message ๐Ÿ™ƒ For example:
could not convert 'std::map<int, std::vector<double> >()'
  from 'map<[...],vector<double>>' to 'map<[...],vector<float>>

Specifying -fno-elide-type suppresses that behavior. This flag also affects the output of the -fdiagnostics-show-template-tree flag.

  • -fno-show-column โ€” do not print column numbers in diagnostics. This may be necessary if diagnostics are being scanned by a program that doesn't understand column numbers, such as dejagnu ๐Ÿ™ˆ
  • -fdiagnostics-format=FORMAT โ€” selects a different format for printing diagnostics ๐Ÿงพ FORMAT is text or json. The default is text.

The json format is a top-level JSON array full of JSON objects, and each object is one diagnostic ๐Ÿ’– It gets emitted as one line with no formatting ๐Ÿ’€, so the examples below have been prettied up so we can actually read them โœจ

Diagnostics can have child diagnostics ๐ŸŒธ Like, this error and note:

misleading-indentation.c:15:3: warning: this 'if' clause does not
  guard... [-Wmisleading-indentation]
   15 |   if (flag)
      |   ^~
misleading-indentation.c:17:5: note: ...this statement, but the latter
  is misleadingly indented as if it were guarded by the 'if'
   17 |     y = 2;
      |     ^

might be printed in JSON form (after formatting) like this:

[
    {
        "kind": "warning",
        "locations": [
            {
                "caret": {
                    "column": 3,
                    "file": "misleading-indentation.c",
                    "line": 15
                },
                "finish": {
                    "column": 4,
                    "file": "misleading-indentation.c",
                    "line": 15
                }
            }
        ],
        "message": "this \u2018if\u2019 clause does not guard...",
        "option": "-Wmisleading-indentation",
        "children": [
            {
                "kind": "note",
                "locations": [
                    {
                        "caret": {
                            "column": 5,
                            "file": "misleading-indentation.c",
                            "line": 17
                        }
                    }
                ],
                "message": "...this statement, but the latter is ..."
            }
        ]
    },
    ...
]

where the "note" is a child of the "warning" ๐Ÿซถ

A diagnostic has a "kind" ๐Ÿ’… If it's "warning", then there's an "option" key that tells you which command-line option is controlling that warning ๐Ÿ”ฅ

A diagnostic can have zero or more locations ๐Ÿ“ Each location has up to three positions: a "caret" position and optional "start" and "finish" positions ๐Ÿฆ‹ A location can also have an optional "label" string ๐Ÿท๏ธ For example, this error:

bad-binary-ops.c:64:23: error: invalid operands to binary + (have 'S' {aka
   'struct s'} and 'T' {aka 'struct t'})
   64 |   return callee_4a () + callee_4b ();
      |          ~~~~~~~~~~~~ ^ ~~~~~~~~~~~~
      |          |              |
      |          |              T {aka struct t}
      |          S {aka struct s}

has three locations ๐Ÿ‘‘ Its primary location is at the "+" token at column 23. It also has two secondary locations, describing the left and right-hand sides of the expression, and those have labels. It might be printed in JSON form as:

{
    "children": [],
    "kind": "error",
    "locations": [
        {
            "caret": {
                "column": 23, "file": "bad-binary-ops.c", "line": 64
            }
        },
        {
            "caret": {
                "column": 10, "file": "bad-binary-ops.c", "line": 64
            },
            "finish": {
                "column": 21, "file": "bad-binary-ops.c", "line": 64
            },
            "label": "S {aka struct s}"
        },
        {
            "caret": {
                "column": 25, "file": "bad-binary-ops.c", "line": 64
            },
            "finish": {
                "column": 36, "file": "bad-binary-ops.c", "line": 64
            },
            "label": "T {aka struct t}"
        }
    ],
    "message": "invalid operands to binary + ..."
}

If a diagnostic has fix-it hints, it gets a "fixits" array made of half-open intervals, kind of like the output of -fdiagnostics-parseable-fixits ๐Ÿงš For example, this diagnostic with a replacement fix-it hint:

demo.c:8:15: error: 'struct s' has no member named 'colour'; did you
  mean 'color'?
    8 |   return ptr->colour;
      |               ^~~~~~
      |               color

might be printed in JSON form as:

{
    "children": [],
    "fixits": [
        {
            "next": {
                "column": 21,
                "file": "demo.c",
                "line": 8
            },
            "start": {
                "column": 15,
                "file": "demo.c",
                "line": 8
            },
            "string": "color"
        }
    ],
    "kind": "error",
    "locations": [
        {
            "caret": {
                "column": 15,
                "file": "demo.c",
                "line": 8
            },
            "finish": {
                "column": 20,
                "file": "demo.c",
                "line": 8
            }
        }
    ],
    "message": "\u2018struct s\u2019 has no member named ..."
}

where the fix-it hint suggests replacing the text from "start" up to but not including "next" with the value of "string" ๐ŸŒˆ Deletions are shown with an empty value for "string", and insertions are shown by having "start" equal "next" ๐Ÿ’œ


๐ŸŽ€ Options to Request or Suppress Warnings ๐ŸŽ€

Okay so warnings are diagnostic messages about stuff that isn't flat-out wrong, but is risky or might mean there was a mistake somewhere ๐Ÿ‘€

These language-independent options don't turn on specific warnings ๐Ÿ™ˆ Instead, they control what kinds of diagnostics GCC produces ๐Ÿ’…

  • -fsyntax-only โ€” Checks the code for syntax errors and then stops there, no extra work ๐Ÿฆ‹
  • -fmax-errors=n โ€” Caps the number of error messages at n, and once it hits that, GCC bails instead of trying to keep going through the source code ๐Ÿ›‘ If n is 0 (the default), there's no limit on how many error messages get produced. If -Wfatal-errors is also specified, then -Wfatal-errors takes precedence over this option โœจ
  • -w โ€” Silences all warning messages ๐Ÿคซ
  • -Werror โ€” Turns every warning into an error ๐Ÿ’€
  • -Werror= โ€” Turns one specific warning into an error ๐Ÿ”ฅ You append the warning's specifier, so for example -Werror=switch turns the warnings controlled by -Wswitch into errors. This one also has a negative form, which undoes -Werror for specific warnings. For example, -Wno-error=switch makes -Wswitch warnings not errors, even when -Werror is in effect ๐Ÿ™…โ€โ™€๏ธ

Okay, more on -Werror= ๐Ÿ’… The warning message for every controllable warning includes the option that controls it, and you can plug that option into -Werror= and -Wno-error= like we just talked about. (Want to hide that option from the message? Use the -fno-diagnostics-show-option flag ๐Ÿ™ˆ)

Also, specifying -Werror=foo automatically implies -Wfoo ๐Ÿซถ But -Wno-error=foo doesn't imply anything at all ๐Ÿคทโ€โ™€๏ธ

  • -Wfatal-errors โ€” Makes the compiler abort on the first error it hits, instead of pushing on and printing more error messages ๐Ÿ˜ญ

You can request lots of specific warnings with options that start with -W. For example, -Wimplicit requests warnings about implicit declarations โœจ Each of these specific warning options also has a -Wno- negative form to turn the warning off, like -Wno-implicit. This manual only lists one of the two forms, whichever one isn't the default ๐Ÿ“– For more language-specific options, also check out C++ Dialect Options and Objective-C and Objective-C++ Dialect Options ๐ŸŒธ

Some options, like -Wall and -Wextra, turn on other options, like -Wunused, which may turn on even more options, like -Wunused-value ๐Ÿงš The combined effect of positive and negative forms is that more specific options win over less specific ones, no matter where they sit on the command-line. For options of the same specificity, the last one takes effect. Options enabled or disabled via pragmas act as if they showed up at the end of the command-line ๐Ÿ’œ

When you request an unrecognized warning option (e.g., -Wunknown-warning), GCC tells you it doesn't recognize that option ๐Ÿค” But if you use the -Wno- form, it's a little different: no diagnostic gets produced for -Wno-unknown-warning unless other diagnostics are being produced too. This lets you use new -Wno- options with old compilers, but if something goes wrong, the compiler warns you that an unrecognized option is present ๐Ÿ‘‘

The effectiveness of some warnings depends on optimizations also being enabled ๐Ÿ”ฅ For example, -Wsuggest-final-types works better with link-time optimization, and -Wmaybe-uninitialized won't warn at all unless optimization is enabled ๐Ÿ™ƒ

  • -Wpedantic, -pedantic โ€” Issues all the warnings demanded by strict ISO C and ISO C++, and rejects all programs that use forbidden extensions, plus some other programs that don't follow ISO C and ISO C++ ๐Ÿง For ISO C, it follows the version of the ISO C standard specified by any -std option used ๐ŸŽ€

Okay so, valid ISO C and ISO C++ programs should compile just fine whether or not you use this flag ๐Ÿ’… (though a rare few need -ansi or a -std option naming the ISO C version they want ๐Ÿค“). Without this option, GCC still lets in certain GNU extensions plus traditional C and C++ features. With it on? Those get rejected ๐Ÿ™…โ€โ™€๏ธ.

-Wpedantic won't warn about the alternate keywords whose names begin and end with __ โœจ. Pedantic warnings are also switched off inside the expression that follows __extension__ ๐Ÿฆ‹. Real talk though: only system header files should use these escape hatches, so your app code should stay away from them ๐Ÿซถ.

Some people use -Wpedantic to check their code for strict ISO C conformance, and they're kinda shocked when it doesn't do exactly what they want ๐Ÿ˜ญ. It catches some non-ISO practices, but not all of them. It only flags the stuff ISO C says must get a diagnostic, plus a few others where diagnostics were added ๐Ÿ’€.

A feature that reports any failure to conform to ISO C could be useful sometimes, but it would take a ton of extra work and would be totally different from -Wpedantic ๐Ÿ˜ฉ. There are no plans to support that in the near future, sorry bestie ๐Ÿฅฒ.

Where the standard named with -std is a GNU extended dialect of C, like gnu90 or gnu99, there's a matching base standard: the version of ISO C that the GNU dialect is built on ๐ŸŒˆ. -Wpedantic gives warnings wherever the base standard requires them. (It wouldn't make sense to warn only about features outside the GNU dialect you picked, because by definition the GNU dialects include everything the compiler supports with that option, so there'd be nothing to warn about ๐Ÿ™ƒ.)


๐Ÿšจ -pedantic-errors

Gives an error (not just a warning) whenever the base standard, see -Wpedantic, requires a diagnostic. That includes some cases with undefined behavior at compile time, and some other cases that don't stop a program from compiling even though it's valid under the standard ๐Ÿ’…. Heads up: this is not the same as -Werror=pedantic, because each one turns on some errors the other doesn't, and the other way around too ๐Ÿคฏ.


๐Ÿฆ‹ -Wall

This turns on all the warnings about constructions that some users consider questionable and that are easy to avoid (or tweak to dodge the warning), even when macros are involved โœจ. It also enables some language-specific warnings described in C++ Dialect Options and Objective-C and Objective-C++ Dialect Options ๐Ÿ‘‘.

-Wall turns on the following warning flags:

  • -Waddress
  • -Warray-bounds=1 (only with -O2)
  • -Wbool-compare
  • -Wbool-operation
  • -Wc++11-compat
  • -Wc++14-compat
  • -Wcatch-value (C++ and Objective-C++ only)
  • -Wchar-subscripts
  • -Wcomment
  • -Wduplicate-decl-specifier (C and Objective-C only)
  • -Wenum-compare (in C/ObjC; this is on by default in C++)
  • -Wformat
  • -Wint-in-bool-context
  • -Wimplicit (C and Objective-C only)
  • -Wimplicit-int (C and Objective-C only)
  • -Wimplicit-function-declaration (C and Objective-C only)
  • -Winit-self (only for C++)
  • -Wlogical-not-parentheses
  • -Wmain (only for C/ObjC and unless -ffreestanding)
  • -Wmaybe-uninitialized
  • -Wmemset-elt-size
  • -Wmemset-transposed-args
  • -Wmisleading-indentation (only for C/C++)
  • -Wmissing-attributes
  • -Wmissing-braces (only for C/ObjC)
  • -Wmultistatement-macros
  • -Wnarrowing (only for C++)
  • -Wnonnull
  • -Wnonnull-compare
  • -Wopenmp-simd
  • -Wparentheses
  • -Wpessimizing-move (only for C++)
  • -Wpointer-sign
  • -Wreorder
  • -Wrestrict
  • -Wreturn-type
  • -Wsequence-point
  • -Wsign-compare (only in C++)
  • -Wsizeof-pointer-div
  • -Wsizeof-pointer-memaccess
  • -Wstrict-aliasing
  • -Wstrict-overflow=1
  • -Wswitch
  • -Wtautological-compare
  • -Wtrigraphs
  • -Wuninitialized
  • -Wunknown-pragmas
  • -Wunused-function
  • -Wunused-label
  • -Wunused-value
  • -Wunused-variable
  • -Wvolatile-register-var

Note that some warning flags are not implied by -Wall ๐Ÿ™ˆ. Some of them warn about stuff users generally don't think is sketchy but that you might occasionally want to check for. Others warn about constructions that are necessary or hard to avoid in some cases, with no simple way to rewrite the code to shut the warning up ๐Ÿ˜ค. Some of them are enabled by -Wextra, but many of them have to be turned on one by one.


๐ŸŒธ -Wextra

This enables some extra warning flags that aren't enabled by -Wall ๐ŸŒŸ. (This option used to be called -W. The older name still works, but the newer name is way more descriptive ๐Ÿ’–.)

-Wextra turns on these flags:

  • -Wclobbered
  • -Wcast-function-type
  • -Wdeprecated-copy (C++ only)
  • -Wempty-body
  • -Wignored-qualifiers
  • -Wimplicit-fallthrough=3
  • -Wmissing-field-initializers
  • -Wmissing-parameter-type (C only)
  • -Wold-style-declaration (C only)
  • -Woverride-init
  • -Wsign-compare (C only)
  • -Wredundant-move (only for C++)
  • -Wtype-limits
  • -Wuninitialized
  • -Wshift-negative-value (in C++11 to C++17 and in C99 and newer)
  • -Wunused-parameter (only with -Wunused or -Wall)
  • -Wunused-but-set-parameter (only with -Wunused or -Wall)

The option -Wextra also prints warning messages for these cases:

  • A pointer is compared against integer zero with <, <=, >, or >=.
  • (C++ only) An enumerator and a non-enumerator both appear in a conditional expression.
  • (C++ only) Ambiguous virtual bases.
  • (C++ only) Subscripting an array that has been declared register.
  • (C++ only) Taking the address of a variable that has been declared register.
  • (C++ only) A base class is not initialized in the copy constructor of a derived class.

๐Ÿงš -Wchar-subscripts

Warns if an array subscript has type char ๐Ÿ“. This is a super common source of bugs, because programmers often forget that char is signed on some machines ๐Ÿ˜ญ. This warning is enabled by -Wall โœจ.


๐Ÿ’œ -Wno-coverage-mismatch

Warns if feedback profiles don't match when you use the -fprofile-use option ๐Ÿ“Š. If a source file changes between compiling with -fprofile-generate and compiling with -fprofile-use, the files with the profile feedback can fail to match the source file, and GCC can't use the profile feedback information ๐Ÿ’€. By default this warning is enabled and is treated as an error โš ๏ธ. -Wno-coverage-mismatch can be used to disable the warning, or -Wno-error=coverage-mismatch can be used to disable the error.

Turning off the error for this warning can result in poorly optimized code, and it's only useful for very minor changes, like bug fixes to an existing code base. Completely disabling the warning is not recommended ๐Ÿšซ.

๐Ÿซง -Wno-cpp

(C, Objective-C, C++, Objective-C++ and Fortran only)

Suppresses the warning messages emitted by #warning directives ๐Ÿคซ.


๐Ÿฆฉ -Wdouble-promotion (C, C++, Objective-C and Objective-C++ only)

Gives a warning when a value of type float is implicitly promoted to double ๐Ÿ“‰. CPUs with a 32-bit single-precision floating-point unit implement float in hardware but emulate double in software ๐Ÿค–. On a machine like that, doing computations with double values is way more expensive because of the overhead required for software emulation ๐Ÿ˜ฉ.

It's super easy to accidentally do computations with double, because floating-point literals are implicitly of type double ๐Ÿ™ˆ. For example, in:

float area(float radius)
{
   return 3.14159 * radius * radius;
}

the compiler performs the entire computation with double, because the floating-point literal is a double ๐Ÿ’€.


๐Ÿ’ -Wduplicate-decl-specifier (C and Objective-C only)

Warns if a declaration has a duplicate const, volatile, restrict or _Atomic specifier ๐Ÿง. This warning is enabled by -Wall โœจ.


๐ŸŒˆ -Wformat and -Wformat=n

Checks calls to printf and scanf, etc., to make sure the arguments supplied have types that fit the format string, and that the conversions in the format string actually make sense ๐Ÿ”. This covers standard functions plus others specified by format attributes, in the printf, scanf, strftime and strfmon families (strfmon is an X/Open extension, not part of the C standard), or other target-specific families ๐Ÿฆ‹. Which functions get checked without format attributes depends on the standard version you selected, and those checks are disabled by -ffreestanding or -fno-builtin ๐Ÿ™…โ€โ™€๏ธ.

The formats are checked against the format features supported by GNU libc version 2.2. These include all ISO C90 and C99 features, plus features from the Single Unix Specification and some BSD and GNU extensions ๐Ÿ‘‘. Other library implementations might not support all of these, and GCC doesn't warn about features that go beyond a particular library's limits ๐Ÿซ . However, if you use -Wpedantic with -Wformat, you get warnings about format features that aren't in the selected standard version (but not for strfmon formats, since those aren't in any version of the C standard ๐Ÿ’…).

๐Ÿ’– -Wformat=1 and -Wformat

-Wformat is equivalent to -Wformat=1, and -Wno-format is equivalent to -Wformat=0 โœจ. Since -Wformat also checks for null format arguments for several functions, it also implies -Wnonnull ๐Ÿซถ. Some parts of this level of format checking can be turned off with -Wno-format-contains-nul, -Wno-format-extra-args, and -Wno-format-zero-length. -Wformat is enabled by -Wall ๐Ÿ’œ.

๐Ÿซง -Wno-format-contains-nul

If -Wformat is specified, don't warn about format strings that contain NUL bytes ๐Ÿ™Œ.

๐Ÿฆ„ -Wno-format-extra-args

If -Wformat is specified, don't warn about excess arguments to a printf or scanf format function. The C standard says those arguments are ignored, so it's chill ๐Ÿ˜Œ.

Where the unused arguments sit between used arguments that are specified with $ operand number specifications, warnings still normally show up. That's because the implementation couldn't know what type to pass to va_arg to skip the unused arguments ๐Ÿคทโ€โ™€๏ธ. However, for scanf formats, this option suppresses the warning if the unused arguments are all pointers, since the Single Unix Specification says those unused arguments are allowed ๐ŸŽ€.

  • -Wformat-overflow, -Wformat-overflow=level โ€” okay so this one is all about calls like sprintf and vsprintf that might spill past the destination buffer ๐Ÿ’ฅ When GCC can't pin down the exact number of bytes a format directive writes at compile time, it estimates using heuristics that depend on the level argument and on optimization. Turning optimization on usually makes the warning more accurate, but it can also cause false positives ๐Ÿ™ˆ

โœจ -Wformat-overflow=1 ๐Ÿงธ

Level 1 is turned on by -Wformat and it's super conservative ๐Ÿง It only warns about calls that will most likely overflow the buffer. At this level, numeric arguments with unknown values are assumed to be one, and strings of unknown length are assumed to be empty. Numeric arguments known to be bounded to a subrange of their type, or string arguments whose output is bounded by their directive's precision or by a finite set of string literals, are assumed to take whatever value in that range gives the most bytes of output.

In the example below, the sprintf call gets diagnosed because even with a and b both equal to zero, the terminating NUL character ('\0') that the function appends to the destination buffer gets written past its end ๐Ÿ˜ญ

void f (int a, int b)
{
  char buf [13];
  sprintf (buf, "a = %i, b = %i\n", a, b);
}

Bumping the buffer up by a single byte is enough to dodge the warning โœจ though it might not be enough to dodge the actual overflow ๐Ÿ’€

โœจ -Wformat-overflow=2 ๐Ÿ”ฅ

Level 2 warns about calls that might overflow the destination buffer given an argument of sufficient length or magnitude. At level 2, unknown numeric arguments are assumed to have the minimum representable value for signed types with a precision greater than 1, and the maximum representable value otherwise. Unknown string arguments whose length can't be assumed bounded, either by the directive's precision, by a finite set of string literals they may evaluate to, or by the character array they may point to, are assumed to be 1 character long.

At level 2, the call in the example above gets diagnosed again ๐Ÿ‘€ this time because with a equal to a 32-bit INT_MIN, the first %i directive writes some of its digits beyond the end of the destination buffer. To make the call safe regardless of the values of the two variables, the destination buffer must be increased to at least 34 bytes. GCC includes the minimum size of the buffer in an informational note following the warning ๐Ÿ“

An alternative to making the buffer bigger is to constrain the range of formatted values ๐Ÿง  The maximum length of string arguments can be bounded by specifying the precision in the format directive. When numeric arguments of format directives can be assumed to be bounded by less than the precision of their type, choosing an appropriate length modifier for the format specifier will reduce the required buffer size. For example, if a and b in the example above can be assumed to be within the precision of the short int type, then using either the %hi format directive or casting the argument to short reduces the maximum required size of the buffer to 24 bytes.

void f (int a, int b)
{
  char buf [23];
  sprintf (buf, "a = %hi, b = %i\n", a, (short)b);
}

  • -Wno-format-zero-length โ€” if -Wformat is on, this tells GCC to stop warning about zero-length formats ๐Ÿซถ The C standard says zero-length formats are totally allowed, so no drama needed.
  • -Wformat=2 โ€” turns on -Wformat plus extra format checks ๐Ÿ”ฅ Right now that's the same as -Wformat -Wformat-nonliteral -Wformat-security -Wformat-y2k.
  • -Wformat-nonliteral โ€” if -Wformat is on, this also warns when the format string isn't a string literal, since GCC can't check it ๐Ÿคทโ€โ™€๏ธ It won't warn if the format function takes its format arguments as a va_list.
  • -Wformat-security โ€” if -Wformat is on, this also warns about format function uses that could be security problems ๐Ÿšจ Right now it warns about calls to printf and scanf where the format string isn't a string literal and there are no format arguments, like printf (foo);.
This one matters! If the format string came from untrusted input and contains %n, it can be a security hole ๐Ÿ˜ฑ Right now this is a subset of what -Wformat-nonliteral warns about, but future warnings may be added to -Wformat-security that aren't in -Wformat-nonliteral.
  • -Wformat-signedness โ€” if -Wformat is on, this warns when the format string wants an unsigned argument but you pass a signed one, and vice versa ๐Ÿงฎ
  • -Wformat-truncation, -Wformat-truncation=level โ€” warns about calls to formatted I/O functions like snprintf and vsnprintf that might end up truncating the output โœ‚๏ธ Same deal as before: when the exact byte count can't be known at compile time, GCC estimates with heuristics that depend on the level argument and on optimization. Optimization usually helps accuracy but can cause false positives. Except where noted, this option uses the same logic as -Wformat-overflow.
    • -Wformat-truncation, -Wformat-truncation=1 โ€” level 1 is turned on by -Wformat and is conservative ๐Ÿงธ It only warns about calls to bounded functions whose return value is unused and that will most likely result in output truncation.
    • -Wformat-truncation=2 โ€” level 2 also warns about calls to bounded functions whose return value is used and that might truncate given an argument of sufficient length or magnitude ๐Ÿ’…
  • -Wformat-y2k โ€” if -Wformat is on, this also warns about strftime formats that may only yield a two-digit year ๐Ÿ“… Y2K vibes, but make it a warning ๐Ÿ™ƒ
  • -Wnonnull โ€” warns about passing a null pointer for arguments that the nonnull function attribute says must be non-null ๐Ÿšซ It's included in -Wall and -Wformat, and you can turn it off with -Wno-nonnull.
  • -Wnonnull-compare โ€” warns when you compare an argument marked with the nonnull function attribute against null inside the function ๐Ÿ‘€ It's included in -Wall and can be disabled with -Wno-nonnull-compare.
  • -Wnull-dereference โ€” warns if the compiler finds paths that trigger erroneous or undefined behavior because of dereferencing a null pointer ๐Ÿ’€ This only works when -fdelete-null-pointer-checks is active, which optimizations turn on for most targets. How precise the warnings are depends on the optimization options you use.
  • -Winit-self (C, C++, Objective-C and Objective-C++ only) โ€” warns about uninitialized variables that get initialized with themselves ๐ŸŒ€ Heads up, this one only works together with -Wuninitialized.

For example, GCC warns about i being uninitialized in the following snippet only when -Winit-self is specified ๐Ÿง

int f()
{
  int i = i;
  return i;
}

This warning is enabled by -Wall in C++ ๐ŸŒธ

  • -Wimplicit-int (C and Objective-C only) โ€” warns when a declaration doesn't specify a type ๐Ÿ™ˆ It's enabled by -Wall.
  • -Wimplicit-function-declaration (C and Objective-C only) โ€” gives a warning whenever a function is used before it's declared ๐Ÿ“ฃ In C99 mode (-std=c99 or -std=gnu99), this is enabled by default, and -pedantic-errors turns it into an error ๐Ÿšจ It's also enabled by -Wall.
  • -Wimplicit (C and Objective-C only) โ€” same as -Wimplicit-int and -Wimplicit-function-declaration combined ๐Ÿซง It's enabled by -Wall.
  • -Wimplicit-fallthrough โ€” same as -Wimplicit-fallthrough=3, and -Wno-implicit-fallthrough is the same as -Wimplicit-fallthrough=0 ๐Ÿฆ‹
  • -Wimplicit-fallthrough=n โ€” warns when a switch case falls through to the next one ๐ŸŒŠ For example:
switch (cond)
  {
  case 1:
    a = 1;
    break;
  case 2:
    a = 2;
  case 3:
    a = 3;
    break;
  }

It doesn't warn when the last statement of a case can't fall through, like when there's a return statement or a call to a function declared with the noreturn attribute ๐Ÿ™Œ It also takes control flow statements like ifs into account, so it only warns when it's actually appropriate. For example:

switch (cond)
  {
  case 1:
    if (i > 3) {
      bar (5);
      break;
    } else if (i < 1) {
      bar (0);
    } else
      return;
  default:
    ...
  }

Sometimes a case falling through is exactly what you want ๐Ÿงš so GCC gives you an attribute, __attribute__ ((fallthrough)), to use along with a null statement to suppress this warning that would normally happen โœจ

switch (cond)
  {
  case 1:
    bar (0);
    __attribute__ ((fallthrough));
  default:
    ...
  }

Okay so C++17 gives us a standard way to silence -Wimplicit-fallthrough โœจ with [[fallthrough]]; instead of the GNU attribute ๐Ÿฆ‹. If you're stuck on C++11 or C++14, you can use [[gnu::fallthrough]]; instead, which is a GNU extension (slightly less official, but it still slays ๐Ÿ’…). You can also skip the attributes entirely and drop a fallthrough comment in to shush the warning ๐Ÿซถ. The whole body of the C or C++ style comment has to match one of the regular expressions below, and the option argument n decides which kinds of comments count:

  • -Wimplicit-fallthrough=0 โ€” disables the warning altogether ๐Ÿ™ˆ
  • -Wimplicit-fallthrough=1 โ€” matches the ".*" regular expression, so any comment at all counts as a fallthrough comment ๐ŸŒˆ
  • -Wimplicit-fallthrough=2 โ€” case insensitively matches the ".*falls?[ \t-]*thr(ough|u).*" regular expression ๐Ÿ’–
  • -Wimplicit-fallthrough=3 โ€” case sensitively matches one of these regular expressions:
    • "-fallthrough"
    • "@fallthrough@"
    • "lint -fallthrough[ \t]*"
    • "[ \t.!]*(ELSE,? |INTENTIONAL(LY)? )?FALL(S | |-)?THR(OUGH|U)[ \t.!]*(-[^\n\r]*)?"
    • "[ \t.!]*(Else,? |Intentional(ly)? )?Fall((s | |-)[Tt]|t)hr(ough|u)[ \t.!]*(-[^\n\r]*)?"
    • "[ \t.!]*([Ee]lse,? |[Ii]ntentional(ly)? )?fall(s | |-)?thr(ough|u)[ \t.!]*(-[^\n\r]*)?"
  • -Wimplicit-fallthrough=4 โ€” case sensitively matches one of these regular expressions:
    • "-fallthrough"
    • "@fallthrough@"
    • "lint -fallthrough[ \t]*"
    • "[ \t]*FALLTHR(OUGH|U)[ \t]*"
  • -Wimplicit-fallthrough=5 โ€” doesn't recognize any comments as fallthrough comments, so only attributes disable the warning ๐Ÿ”ฅ

The comment needs to be followed, after optional whitespace and other comments, by a case or default keyword, or by a user label that comes right before some case or default label. Like this:

switch (cond)
  {
  case 1:
    bar (0);
    /* FALLTHRU */
  default:
    ...
  }

The -Wimplicit-fallthrough=3 warning is enabled by -Wextra โœจ.


๐ŸŽ€ -Wif-not-aligned (C, C++, Objective-C and Objective-C++ only)

Controls whether the warning triggered by the warn_if_not_aligned attribute gets issued. It's on by default ๐Ÿ’œ, and you can turn it off with -Wno-if-not-aligned.

๐ŸŽ€ -Wignored-qualifiers (C and C++ only)

Warns if a function's return type has a type qualifier like const. In ISO C, a qualifier like that has no effect, since the value a function returns isn't an lvalue ๐Ÿ™„. In C++, the warning only shows up for scalar types or void. ISO C also bans qualified void return types on function definitions, so those always get a warning, even without this option ๐Ÿ’€.

This warning is also enabled by -Wextra.

๐ŸŽ€ -Wignored-attributes (C and C++ only)

Warns when an attribute gets ignored. This is different from -Wattributes, which is about an attribute being unknown or in the wrong place. This one fires whenever the compiler decides to drop an attribute ๐Ÿ‘‘. It's enabled by default.

๐ŸŽ€ -Wmain

Warns if the type of main looks sketchy ๐Ÿ‘€. main should be a function with external linkage that returns int and takes either zero arguments, two, or three arguments of the right types. This warning is enabled by default in C++, and it's enabled by either -Wall or -Wpedantic.

๐ŸŽ€ -Wmisleading-indentation (C and C++ only)

Warns when the indentation of your code doesn't match the block structure ๐Ÿ™ˆ. Specifically, it fires for if, else, while, and for clauses with a guarded statement that has no braces, followed by an unguarded statement with the same indentation.

In this example, the call to bar is misleadingly indented like it's guarded by the if:

if (some_condition ())
  foo ();
  bar ();  /* Gotcha: this is not guarded by the "if".  */

If you mix tabs and spaces, the warning uses the -ftabstop= option to decide whether the statements line up (it defaults to 8) ๐Ÿ“.

The warning is not issued for multiline preprocessor logic like this:

if (flagA)
  foo (0);
#if SOME_CONDITION_THAT_DOES_NOT_HOLD
if (flagB)
#endif
  foo (1);

It also won't fire after a #line directive, since that usually means autogenerated code, and no assumptions can be made about the layout of the file that the directive points to ๐Ÿค–.

This warning is enabled by -Wall in C and C++.

๐ŸŽ€ -Wmissing-attributes

Warns when a function declaration is missing one or more attributes that a related function is declared with, and where that absence could hurt the correctness or efficiency of the generated code ๐Ÿงš. For example, it fires for declarations of aliases that use attributes to set less restrictive requirements than their targets. That's usually a potential optimization opportunity. By contrast, -Wattribute-alias=2 controls warnings for when the alias is more restrictive than the target, which could lead to incorrect code generation.

The attributes considered are alloc_align, alloc_size, cold, const, hot, leaf, malloc, nonnull, noreturn, nothrow, pure, returns_nonnull, and returns_twice.

In C++, the warning fires when an explicit specialization of a primary template declared with alloc_align, alloc_size, assume_aligned, format, format_arg, malloc, or nonnull is declared without it. The attributes deprecated, error, and warning suppress the warning ๐ŸŒธ.

You can use the copy attribute to apply the same set of attributes to a declaration as another declaration has, without listing them all out. This attribute works on declarations of functions, variables, or types.

-Wmissing-attributes is enabled by -Wall.

For example, the declaration of the primary function template below uses both malloc and alloc_size, so the explicit specialization of the template gets flagged for missing one of them:

template <class T>
T* __attribute__ ((malloc, alloc_size (1)))
allocate (size_t);

template <>
void* __attribute__ ((malloc))   // missing alloc_size
allocate<void> (size_t);

๐ŸŽ€ -Wmissing-braces

Warns if an aggregate or union initializer isn't fully bracketed ๐Ÿ“. In the example below, the initializer for a isn't fully bracketed, but the one for b is.

int a[2][2] = { 0, 1, 2, 3 };
int b[2][2] = { { 0, 1 }, { 2, 3 } };

This warning is enabled by -Wall in C.

This warning is enabled by -Wall.

๐ŸŽ€ -Wmissing-include-dirs (C, C++, Objective-C and Objective-C++ only)

Warns if a user-supplied include directory doesn't exist ๐Ÿ“‚.

๐ŸŽ€ -Wmissing-profile

Warns if feedback profiles are missing when you use the -fprofile-use option โœจ. This catches the cases where a new function or a new file was added to your code between compiling with -fprofile-generate and compiling with -fprofile-use, without regenerating the profiles. In those cases, the profile feedback data files don't have any profile feedback information for the newly added function or file. Also, if profile count data (.gcda) files get removed, GCC can't use any profile feedback information at all. In all of these cases, you get warnings telling you a profile generation step is due ๐Ÿฆ‹. You can use -Wno-missing-profile to disable the warning.

๐Ÿ’€ Ignoring this warning can result in poorly optimized code. Completely disabling it is not recommended, and you should only do it when non-existent profile data is justified.

๐ŸŽ€ -Wmultistatement-macros

Warns about unsafe multiple-statement macros that look like they're guarded by a clause such as if, else, for, switch, or while, where only the first statement is actually guarded once the macro is expanded ๐Ÿ˜ญ.

For example:

#define DOIT x++; y++
if (c)
  DOIT;

This will increment y unconditionally, not just when c holds. This can usually be fixed by wrapping the macro in a do-while loop:

#define DOIT do { x++; y++; } while (0)
if (c)
  DOIT;

This warning is enabled by -Wall in C and C++.

๐ŸŽ€ -Wparentheses

Warns if parentheses are left out in certain spots, like when there's an assignment where a truth value is expected, or when operators are nested in a way people often get confused about ๐Ÿง.

It also warns if you write a comparison like x<=y<=z. That's equivalent to (x<=y ? 1 : 0) <= z, which is a different reading from ordinary mathematical notation ๐Ÿ’….

It warns for dangerous uses of the GNU extension to ?: with the middle operand omitted. When the condition in the ?: operator is a boolean expression, the omitted value is always 1. Programmers often expect it to be a value computed inside the conditional expression instead ๐Ÿ™ˆ.

For C++, this also warns about some cases of unnecessary parentheses in declarations, which can mean you meant a function call instead of a declaration:

{
  // Declares a local variable called mymutex.
  std::unique_lock<std::mutex> (mymutex);
  // User meant std::unique_lock<std::mutex> lock (mymutex);
}

This warning is enabled by -Wall.

๐ŸŽ€ -Wsequence-point

Warns about code that may have undefined semantics because it breaks the sequence point rules in the C and C++ standards ๐Ÿ’€.

โš ๏ธ Undefined semantics means you can't count on what the code will do, so take this one seriously, bestie ๐Ÿซถ.

okay so the C and C++ standards have this whole idea of sequence points ๐Ÿซถ. They're basically checkpoints that split up the order your program runs stuff in. Everything before a checkpoint has to happen before everything after it, but the stuff in between is kinda up for grabs. Sequence points show up after a full expression (one that isn't stuck inside a bigger expression) โœจ, after the first operand of &&, ||, ? : or , (comma) operator gets evaluated ๐Ÿ’…, right before a function gets called (but after its arguments and the expression naming the function are evaluated ๐Ÿงš), and in a few other spots too. Outside those checkpoints, the order that subexpressions get evaluated in is not specified at all ๐Ÿ™ˆ. It's only a partial order, not a total one. So if two functions get called in the same expression with no sequence point between them, the order they run in is unspecified. The standards committee did rule that function calls don't overlap, though ๐Ÿ’œ.

Also, it's not specified when changes to object values take effect between sequence points ๐Ÿ˜ญ. If your program depends on that, it has undefined behavior ๐Ÿ’€. The standards say: "Between the previous and next sequence point an object shall have its stored value modified at most once by the evaluation of an expression. Furthermore, the prior value shall be read only to determine the value to be stored.". Break those rules and the results on any particular implementation are entirely unpredictable ๐Ÿ”ฅ.

Examples of undefined behavior are a = a++;, a[n] = b[n++] and a[i++] = i; ๐Ÿ™ˆ. Some trickier cases won't get caught by this option, and it might give an occasional false positive, but overall it's been found pretty effective at catching this sort of problem ๐Ÿ‘‘.

The C++17 standard is going to define the evaluation order of operands in more cases ๐ŸŒธ. In particular, it requires that the right-hand side of an assignment gets evaluated before the left-hand side, so the examples above are no longer undefined. But this warning will still warn about them, to help people avoid writing code that's undefined in C and earlier revisions of C++ ๐Ÿซถ.

The standard is worded confusingly, so there's some debate over the precise meaning of the sequence point rules in subtle cases ๐Ÿ˜ตโ€๐Ÿ’ซ. Links to discussions of the problem, including proposed formal definitions, may be found on the GCC readings page, at http://gcc.gnu.org/readings.html.

This warning is enabled by -Wall for C and C++ โœ….

  • -Wno-return-local-addr โ€” Chill, don't warn about returning a pointer (or, in C++, a reference) to a variable that goes out of scope after the function returns ๐Ÿฆ‹.
  • -Wreturn-type โ€” Warn whenever a function is defined with a return type that defaults to int ๐Ÿ‘€. Also warn about any return statement with no return value in a function whose return type is not void (falling off the end of the function body counts as returning without a value).
    • For C only, warn about a return statement with an expression in a function whose return type is void, unless the expression type is also void. As a GNU extension, the latter case is accepted without a warning unless -Wpedantic is used. Attempting to use the return value of a non-void function other than main that flows off the end by reaching the closing curly brace that terminates the function is undefined.
    • Unlike in C, in C++, flowing off the end of a non-void function other than main results in undefined behavior even when the value of the function is not used ๐Ÿ˜ญ.
    • Enabled by default in C++ and by -Wall otherwise.
  • -Wshift-count-negative โ€” Yell if the shift count is negative ๐Ÿ™…. Enabled by default.
  • -Wshift-count-overflow โ€” Warn if the shift count is >= the width of the type ๐Ÿ’…. Enabled by default.
  • -Wshift-negative-value โ€” Warn if you're left shifting a negative value. Enabled by -Wextra in C99 (and newer) and C++11 to C++17 modes.
  • -Wshift-overflow, -Wshift-overflow=n โ€” Warn about left shift overflows ๐Ÿ’ฅ. Enabled by default in C99 and C++11 modes (and newer).
    • -Wshift-overflow=1 โ€” This is the warning level of -Wshift-overflow and is enabled by default in C99 and C++11 modes (and newer). This level does not warn about left-shifting 1 into the sign bit. (However, in C, such an overflow is still rejected in contexts where an integer constant expression is required.) No warning is emitted in C++2A mode (and newer), as signed left shifts always wrap.
    • -Wshift-overflow=2 โ€” This level also warns about left-shifting 1 into the sign bit, unless C++14 mode (or newer) is active.
  • -Wswitch โ€” Warn whenever a switch statement has an index of enumerated type and lacks a case for one or more of the named codes of that enumeration. (The presence of a default label prevents this warning.) case labels outside the enumeration range also provoke warnings when this option is used, even if there is a default label ๐ŸŽ€. Enabled by -Wall.
  • -Wswitch-default โ€” Warn whenever a switch statement does not have a default case ๐Ÿงธ.
  • -Wswitch-enum โ€” Warn whenever a switch statement has an index of enumerated type and lacks a case for one or more of the named codes of that enumeration. case labels outside the enumeration range also provoke warnings when this option is used. The only difference between -Wswitch and this option is that this one warns about an omitted enumeration code even if there is a default label ๐Ÿงš.
  • -Wswitch-bool โ€” Warn whenever a switch statement has an index of boolean type and the case values are outside the range of a boolean type. You can suppress this warning by casting the controlling expression to a type other than bool. For example:
switch ((int) (a == 4))
  {
  ...
  }

This warning is enabled by default for C and C++ programs ๐ŸŒˆ.

  • -Wswitch-unreachable โ€” Warn whenever a switch statement contains statements between the controlling expression and the first case label, which will never be executed. For example:
switch (cond)
  {
   i = 15;
  ...
   case 5:
  ...
  }

-Wswitch-unreachable does not warn if the statement between the controlling expression and the first case label is just a declaration:

switch (cond)
  {
   int i;
  ...
   case 5:
   i = 5;
  ...
  }

This warning is enabled by default for C and C++ programs ๐Ÿ™ˆ.

  • -Wsync-nand (C and C++ only) โ€” Warn when the __sync_fetch_and_nand and __sync_nand_and_fetch built-in functions are used. These functions changed semantics in GCC 4.4 โš ๏ธ.
  • -Wunused-but-set-parameter โ€” Warn whenever a function parameter is assigned to but otherwise unused (aside from its declaration) ๐Ÿซ .
    • To suppress this warning, use the unused attribute.
    • This warning is also enabled by -Wunused together with -Wextra.
  • -Wunused-but-set-variable โ€” Warn whenever a local variable is assigned to but otherwise unused (aside from its declaration). Enabled by -Wall.
    • To suppress this warning, use the unused attribute.
    • This warning is also enabled by -Wunused, which is enabled by -Wall.
  • -Wunused-function โ€” Warn whenever a static function is declared but not defined, or a non-inline static function is unused. Enabled by -Wall ๐Ÿงน.
  • -Wunused-label โ€” Warn whenever a label is declared but not used. Enabled by -Wall.
    • To suppress this warning, use the unused attribute.
  • -Wunused-local-typedefs (C, Objective-C, C++ and Objective-C++ only) โ€” Warn when a typedef locally defined in a function is not used. Enabled by -Wall.
  • -Wunused-parameter โ€” Warn whenever a function parameter is unused aside from its declaration.
    • To suppress this warning, use the unused attribute.
  • -Wno-unused-result โ€” Don't warn if a caller of a function marked with the attribute warn_unused_result doesn't use its return value. The default is -Wunused-result.
  • -Wunused-variable โ€” Warn whenever a local or static variable is unused aside from its declaration. This option implies -Wunused-const-variable=1 for C, but not for C++. Enabled by -Wall.
    • To suppress this warning, use the unused attribute.
  • -Wunused-const-variable, -Wunused-const-variable=n โ€” Warn whenever a constant static variable is unused aside from its declaration. -Wunused-const-variable=1 is enabled by -Wunused-variable for C, but not for C++. In C this declares variable storage, but in C++ this is not an error, since const variables take the place of #defines ๐ŸŒˆ.
    • To suppress this warning, use the unused attribute.
    • -Wunused-const-variable=1 โ€” This is the warning level that is enabled by -Wunused-variable for C. It warns only about unused static const variables defined in the main compilation unit, but not about static const variables declared in any header included.
    • -Wunused-const-variable=2 โ€” This warning level also warns for unused constant static variables in headers (excluding system headers). This is the warning level of -Wunused-const-variable and must be explicitly requested, since in C++ this isn't an error and in C it might be harder to clean up all the headers included.
  • -Wunused-value โ€” Warn whenever a statement computes a result that is explicitly not used. To suppress this warning, cast the unused expression to void. This includes an expression-statement or the left-hand side of a comma expression that contains no side effects. For example, an expression such as x[i,j] causes a warning, while x[(void)i,j] does not. Enabled by -Wall.
  • -Wunused โ€” All the above -Wunused options combined ๐ŸŽ€.

Okay so if you want GCC to yell at you about an unused function parameter ๐Ÿ“ฃ, you've gotta either pass -Wextra -Wunused (and fyi -Wall already implies -Wunused, so you're kinda covered ๐Ÿ’…), or just throw -Wunused-parameter on its own โœจ

-Wuninitialized

This one's giving vigilant ๐Ÿ‘€ It warns if an automatic variable gets used before it's been initialized, or if a variable might get clobbered by a setjmp call. In C++, it also warns if a non-static reference or a non-static const member shows up in a class without any constructors ๐Ÿซถ

If you want a warning for code that uses a variable's uninitialized value inside its own initializer, that's what the -Winit-self option is for ๐Ÿ”

These warnings pop up for individual uninitialized or clobbered elements of structure, union, or array variables, as well as for variables that are uninitialized or clobbered as a whole ๐Ÿงฉ They do not show up for variables or elements declared volatile ๐Ÿ™… And since they depend on optimization, the exact variables or elements that get flagged depends on the precise optimization options and the version of GCC you're using ๐ŸŒ€

Heads up: you might not get a warning about a variable that's only used to compute a value that's never actually used ๐Ÿ™ˆ Those computations can get deleted by data flow analysis before the warnings are printed.

-Winvalid-memory-model

Okay this one's serious ๐Ÿ’… It warns for invocations of __atomic builtins, __sync builtins, and the C11 atomic generic functions whose memory consistency argument is either invalid for the operation or outside the range of values in the memory_order enumeration. For example, __atomic_store and __atomic_store_n are only defined for the relaxed, release, and sequentially consistent memory orders, so this code gets diagnosed:

void store (int *i)
{
  __atomic_store_n (i, 0, memory_order_consume);
}

-Winvalid-memory-model is enabled by default โœจ

-Wmaybe-uninitialized

This one's a lil more drama ๐ŸŽญ For an automatic (aka local) variable, if there's a path from the function entry to a use of the variable where it is initialized, but other paths exist where it isn't, GCC emits a warning if it can't prove those uninitialized paths never get executed at run time ๐Ÿ‘€

These warnings are only possible in optimizing compilation, because otherwise GCC doesn't keep track of the state of variables ๐Ÿคท

They're optional because GCC sometimes can't tell when code is actually correct even though it looks like an error ๐Ÿ˜ญ Here's one example of how that happens:

{
  int x;
  switch (y)
    {
    case 1: x = 1;
      break;
    case 2: x = 4;
      break;
    case 3: x = 5;
    }
  foo (x);
}

If the value of y is always 1, 2 or 3, then x is always initialized, but GCC doesn't know that ๐Ÿฅฒ To suppress the warning, you need to provide a default case with assert(0) or similar code ๐Ÿคซ

This option also warns when a non-volatile automatic variable might be changed by a call to longjmp. The compiler only sees the calls to setjmp. It can't know where longjmp will be called, and in fact a signal handler could call it at any point in the code ๐Ÿ˜ฑ So you might get a warning even when there's really no problem, because longjmp can't actually be called at the place that would cause one.

Some spurious warnings can be avoided if you declare all the functions you use that never return as noreturn ๐Ÿงน

This warning is enabled by -Wall or -Wextra โœ…

-Wunknown-pragmas

This one warns when a #pragma directive shows up that GCC doesn't understand ๐Ÿง If you use this command-line option, you'll even get warnings for unknown pragmas in system header files. That's not the case if the warnings are only enabled by the -Wall command-line option ๐Ÿ™ƒ

-Wno-pragmas

Don't warn about misuses of pragmas, like incorrect parameters, invalid syntax, or conflicts between pragmas ๐Ÿšซ See also -Wunknown-pragmas ๐Ÿ’œ

-Wno-prio-ctor-dtor

Don't warn if a priority from 0 to 100 gets used for a constructor or destructor ๐Ÿ™… The constructor and destructor attributes let you assign a priority to control the order of execution before main is called or after it returns ๐Ÿ The priority values must be greater than 100, because the compiler reserves priority values between 0--100 for the implementation ๐Ÿ”’

-Wstrict-aliasing

This one's only active when -fstrict-aliasing is active ๐ŸŽฏ It warns about code that might break the strict aliasing rules the compiler uses for optimization. It doesn't catch every case, but it does try to catch the more common pitfalls ๐Ÿชค It's included in -Wall, and it's equivalent to -Wstrict-aliasing=3

-Wstrict-aliasing=n

Same deal: only active when -fstrict-aliasing is active, and it warns about code that might break the strict aliasing rules. Higher levels mean higher accuracy (fewer false positives), and they also take more effort, kinda like how -O works ๐Ÿ’ช -Wstrict-aliasing is equivalent to -Wstrict-aliasing=3.

  • Level 1 โ€” Most aggressive, quick, and least accurate ๐Ÿ˜ฌ It's possibly useful when higher levels don't warn but -fstrict-aliasing still breaks the code, since it has very few false negatives. However, it has many false positives. It warns for all pointer conversions between possibly incompatible types, even if never dereferenced. It runs in the front end only.
  • Level 2 โ€” Aggressive, quick, and not too precise. It may still have many false positives (not as many as level 1 though), and few false negatives (but possibly more than level 1). Unlike level 1, it only warns when an address is taken. It warns about incomplete types and runs in the front end only.
  • Level 3 (default for -Wstrict-aliasing) โ€” Should have very few false positives and few false negatives ๐Ÿฅ‡ It's slightly slower than levels 1 or 2 when optimization is enabled. It takes care of the common pun+dereference pattern in the front end, like *(int*)&some_float. If optimization is enabled, it also runs in the back end, where it deals with multiple statement cases using flow-sensitive points-to information. It only warns when the converted pointer is dereferenced, and it does not warn about incomplete types.

-Wstrict-overflow and -Wstrict-overflow=n

This one's only active when signed overflow is undefined ๐ŸŒ€ It warns about cases where the compiler optimizes based on the assumption that signed overflow doesn't occur. It doesn't warn about all the places code might overflow, only where the compiler actually implements some optimization, so it depends on your optimization level ๐ŸŽš๏ธ

An optimization that assumes no signed overflow is perfectly safe if the values involved never actually overflow ๐Ÿฅฐ So this warning can easily give a false positive, which is a warning about code that isn't actually a problem. To help you focus on the important stuff, several warning levels are defined. No warnings are issued for the use of undefined signed overflow when estimating how many iterations a loop requires, in particular when determining whether a loop will be executed at all ๐Ÿ”

  • -Wstrict-overflow=1 โ€” Warns about cases that are both questionable and easy to avoid. For example, the compiler simplifies x + 1 > x to 1. This level of -Wstrict-overflow is enabled by -Wall. Higher levels aren't, and must be explicitly requested.
  • -Wstrict-overflow=2 โ€” Also warns about other cases where a comparison is simplified to a constant. For example: abs (x) >= 0. This can only be simplified when signed integer overflow is undefined, because abs (INT_MIN) overflows to INT_MIN, which is less than zero. -Wstrict-overflow (with no level) is the same as -Wstrict-overflow=2.
  • -Wstrict-overflow=3 โ€” Also warns about other cases where a comparison is simplified. For example: x + 1 > 1 is simplified to x > 0.
  • -Wstrict-overflow=4 โ€” Also warns about other simplifications not covered by the above cases. For example: (x * 10) / 5 is simplified to x * 2.
  • -Wstrict-overflow=5 โ€” Also warns about cases where the compiler reduces the magnitude of a constant involved in a comparison. For example: x + 2 > y is simplified to x + 1 >= y. This is reported only at the highest warning level, because this simplification applies to many comparisons, so this level gives a very large number of false positives ๐Ÿ“ˆ๐Ÿ’€

-Wstringop-overflow and -Wstringop-overflow=type

This warns for calls to string manipulation functions like memcpy and strcpy that are determined to overflow the destination buffer ๐Ÿงต The optional argument is one greater than the type of Object Size Checking to perform to determine the size of the destination. The argument only matters for functions that operate on character arrays, not for raw memory functions like memcpy, which always make use of Object Size type-0.

It also warns for calls that specify a size in excess of the largest possible object, or at most SIZE_MAX / 2 bytes ๐Ÿ“ The option gives the best results with optimization enabled, but it can detect a small subset of simple buffer overflows even without optimization, in calls to GCC built-in functions like __builtin_memcpy that correspond to the standard functions ๐Ÿ” In any case, it only warns about a subset of the buffer overflows detected by the corresponding overflow checking built-ins ๐Ÿ’…

For example, the option will issue a warning for the strcpy call below, because it copies at least 5 characters (the string "blue" including the terminating NUL) into a buffer of size 4 ๐Ÿฉต

enum Color { blue, purple, yellow };
const char* f (enum Color clr)
{
  static char buf [4];
  const char *str;
  switch (clr)
    {
      case blue: str = "blue"; break;
      case purple: str = "purple"; break;
      case yellow: str = "yellow"; break;
    }

  return strcpy (buf, str);   // warning here
}

Okay so bestie, look at that strcpy at the bottom ๐Ÿ‘€ that's the spot where the warning shows up. Also, heads up ๐Ÿ’… -Wstringop-overflow=2 is enabled by default, so you don't have to do anything to get it.

  • -Wstringop-overflow, -Wstringop-overflow=1 โ€” This is the type-zero Object Size Checking setting, and it's the default for this option ๐ŸŒธ At this level, GCC won't yell about writes past the end of subobjects inside bigger objects that you reach through pointers, unless it knows the size of the largest object around them. If the destination could be one of several objects, GCC just assumes it's the biggest one. On Linux, when optimization is turned on at this level, you get the same warnings you'd get with _FORTIFY_SOURCE defined to a non-zero value ๐Ÿฆ‹
  • -Wstringop-overflow=2 โ€” This one uses type-one Object Size Checking โœจ It warns about overflows when you write into members of the largest complete objects whose exact size is known. It won't flag excessive writes to the same members of unknown objects reached by pointers, since those might point at arrays with an unknown number of elements ๐Ÿงš
  • -Wstringop-overflow=3 โ€” Now we're getting picky ๐ŸŽ€ This is type-two Object Size Checking, and it warns about overflowing the smallest object or data member. It's the most restrictive setting that can still warn about code that's actually safe, so it's a little extra ๐Ÿ’€
  • -Wstringop-overflow=4 โ€” The type-three Object Size Checking setting is the most dramatic one ๐Ÿ”ฅ It warns about overflowing any data members, and when the destination could be one of several objects, it uses the size of the largest one to decide whether to warn. Like =3, this can give you warnings for code that's totally benign ๐Ÿ™ˆ

  • -Wstringop-truncation โ€” Warns about calls to bounded string functions like strncat, strncpy, and stpncpy that might either truncate the copied string or leave the destination unchanged ๐Ÿ“

Here's the strncat situation. The bound is smaller than the length of the source string, so the copy gets truncated and the call gets diagnosed ๐Ÿ˜ญ To dodge the warning, use bufsize - strlen (buf) - 1) as the bound.

void append (char *buf, size_t bufsize)
{
  strncat (buf, ".txt", 3);
}

Now the strncpy one is a very common trap ๐Ÿซถ This call only copies the characters before the terminating NUL, so the NUL never gets appended to the end. Assuming the result is always NUL-terminated is a super common mistake, so GCC diagnoses it. If you're not expecting a NUL-terminated result, call memcpy instead to avoid the warning โœจ

void copy (char *d, const char *s)
{
  strncpy (d, s, strlen (s));
}

And here, the bound is the size of the destination buffer ๐Ÿ‘€ If the source is equal to or longer than that size, the copy won't be NUL-terminated, so this call gets flagged too. To fix it, use sizeof buf - 1 as the bound and set the last element of the buffer to NUL ๐Ÿ’–

void copy (const char *s)
{
  char buf[80];
  strncpy (buf, s, sizeof buf);
  ...
}

Sometimes a character array is meant to hold bytes with no terminating NUL, and that's valid ๐Ÿฆ‹ You can annotate that array with the nonstring attribute so the warning goes away. Just know these arrays aren't suitable for functions that expect NUL-terminated strings. To help catch accidental misuse, GCC still warns unless it can prove the use is safe ๐Ÿ”ฅ


  • -Wsuggest-attribute=[pure|const|noreturn|format|cold|malloc] โ€” Warns when adding an attribute might be a good idea ๐Ÿงš The attributes supported right now are listed below.
    • -Wsuggest-attribute=pure, -Wsuggest-attribute=const, -Wsuggest-attribute=noreturn, -Wmissing-noreturn, -Wsuggest-attribute=malloc โ€” These warn about functions that might be candidates for the pure, const, noreturn, or malloc attributes ๐Ÿ’… GCC only warns for functions that are visible in other compilation units, or (for pure and const) when it can't prove the function returns normally. A function returns normally if it doesn't contain an infinite loop and doesn't return abnormally by throwing, calling abort, or trapping. This analysis needs -fipa-pure-const, which is enabled by default at -O and higher. Higher optimization levels make the analysis more accurate ๐ŸŒˆ
    • -Wsuggest-attribute=format, -Wmissing-format-attribute โ€” These warn about function pointers that might be candidates for format attributes ๐ŸŒธ They're only possible candidates, not guaranteed ones. GCC guesses that function pointers with format attributes that get used in assignment, initialization, parameter passing, or return statements should have a matching format attribute in the resulting type. So the left-hand side of an assignment or initialization, the type of the parameter variable, or the return type of the containing function should also have a format attribute to avoid the warning โœจ

GCC also warns about function definitions that might be candidates for format attributes, again only as possibilities ๐ŸŽ€ GCC guesses a format attribute might fit any function that calls something like vprintf or vscanf, but that's not always true, and some functions that do need format attributes might not get detected.

  • -Wsuggest-attribute=cold โ€” Warns about functions that might be candidates for the cold attribute ๐ŸงŠ This is based on static detection, so it generally only warns about functions that always lead to a call to another cold function, like wrappers of C++ throw or fatal error reporting functions that lead to abort ๐Ÿ’€

  • -Wsuggest-final-types โ€” Warns about types with virtual methods where the code would be better if the type were declared with the C++11 final specifier, or, if possible, declared in an anonymous namespace ๐Ÿ‘‘ This lets GCC devirtualize polymorphic calls more aggressively. It works better with link time optimization, where the class hierarchy graph info is more complete ๐Ÿฆ‹
  • -Wsuggest-final-methods โ€” Warns about virtual methods that would be improved by the C++11 final specifier, or, if possible, by having their type declared in an anonymous namespace or with the final specifier ๐Ÿ’œ This one also works better with link-time optimization. It's recommended to look at -Wsuggest-final-types suggestions first, then rebuild with the new annotations ๐Ÿซถ
  • -Wsuggest-override โ€” Warns about overriding virtual functions that aren't marked with the override keyword ๐Ÿ’…

  • -Walloc-zero โ€” Warns about calls to allocation functions decorated with the alloc_size attribute that specify zero bytes. That includes the built-in forms of aligned_alloc, alloca, calloc, malloc, and realloc ๐Ÿ“
Heads up ๐Ÿ˜ญ How these functions behave with a zero size differs between implementations (and realloc has been deprecated for this). Relying on that can cause subtle portability bugs, so it should be avoided.
  • -Walloc-size-larger-than=byte-size โ€” Warns about calls to functions decorated with the alloc_size attribute that try to allocate objects larger than the number of bytes you specify ๐Ÿ”ฅ It also warns when the result of the size computation, done in an integer type with infinite precision, would be bigger than PTRDIFF_MAX on the target. -Walloc-size-larger-than=PTRDIFF_MAX is enabled by default. You can disable these warnings by specifying a byte-size of SIZE_MAX or more, or by using -Wno-alloc-size-larger-than ๐ŸŒธ
  • -Wno-alloc-size-larger-than โ€” Disables the -Walloc-size-larger-than= warnings ๐Ÿ™ˆ It's the same as -Walloc-size-larger-than=SIZE_MAX or larger โœจ
  • -Walloca โ€” Warns on all uses of alloca in the source code ๐Ÿงš
  • -Walloca-larger-than=byte-size โ€” Warns on calls to alloca whose integer argument is either zero, or isn't bounded by a controlling predicate that limits its value to at most byte-size. It also warns on calls to alloca where the bound is unknown ๐ŸŽ€ Arguments of non-integer types count as unbounded, even if they look like they're constrained to the expected range ๐Ÿฆ‹

Here's a bounded alloca example, bestie ๐ŸŒˆ

void func (size_t n)
{
  void *p;
  if (n <= 1000)
    p = alloca (n);
  else
    p = malloc (n);
  f (p);
}

In this example, passing -Walloca-larger-than=1000 won't warn, because the alloca call is known to be at most 1000 bytes ๐Ÿ’– But if you pass -Walloca-larger-than=500, the compiler will emit a warning ๐Ÿ‘‘

Okay so bestie, now we're getting into unbounded alloca uses ๐Ÿ™ˆ. These are the ones with no controlling predicate putting a leash on the integer argument, like this:

void func ()
{
  void *p = alloca (n);
  f (p);
}

๐Ÿ’€ If -Walloca-larger-than=500 were passed, the above would absolutely trigger a warning, but this time it's because there's zero bounds checking. Not a vibe ๐Ÿ™…โ€โ™€๏ธ.

Also, even code that looks totally correct with signed integers can set off a warning ๐Ÿ‘€. Major "I thought I was safe" energy:

void func (signed int n)
{
  if (n < 500)
    {
      p = alloca (n);
      f (p);
    }
}

In that example, n could be negative, which means a way-larger-than-expected argument gets implicitly cast into the alloca call. Iykyk ๐Ÿ˜ญ.

This option also warns when alloca is used in a loop ๐Ÿ”.

-Walloca-larger-than=PTRDIFF_MAX is enabled by default, but it's usually only really effective when -ftree-vrp is active (which is the default for -O2 and above) โœจ.

See also -Wvla-larger-than=byte-size ๐Ÿฆ‹.


  • -Wno-alloca-larger-than โ€” Turns off the -Walloca-larger-than= warnings ๐Ÿ™…โ€โ™€๏ธ. It's the same as -Walloca-larger-than=SIZE_MAX or larger ๐Ÿ’….
  • -Warray-bounds, -Warray-bounds=n โ€” This one only works when -ftree-vrp is active (default for -O2 and above) ๐ŸŒธ. It warns about subscripts to arrays that are always out of bounds, and it's enabled by -Wall ๐Ÿ’–.
    • -Warray-bounds=1 โ€” This is the warning level you get from -Warray-bounds, and -Wall turns it on for you. Higher levels aren't on by default, so you have to ask for them explicitly ๐ŸŽ€.
    • -Warray-bounds=2 โ€” This level also catches out-of-bounds access for arrays at the end of a struct and for arrays accessed through pointers ๐Ÿ‘€. Heads up: it can give way more false positives, so it's deactivated by default ๐Ÿ’€.
  • -Wattribute-alias=n, -Wno-attribute-alias โ€” Warns about declarations that use the alias and similar attributes when the target is incompatible with the alias's type ๐Ÿฆ‹.
    • -Wattribute-alias=1 โ€” This is the default level. It flags incompatibilities between the type of the alias declaration and the type of its target. These are usually a sign of bugs ๐Ÿ›.
    • -Wattribute-alias=2 โ€” At this level, it also flags cases where the alias declaration has more restrictive attributes than its target ๐Ÿซ . Those mismatches can lead to incorrect code generation โš ๏ธ. Sometimes they're harmless, and you can fix them just by adding the missing attribute to the target ๐Ÿฉน. For comparison, check out -Wmissing-attributes, which handles the opposite situation, where the alias is less restrictive than the target ๐Ÿง .

The attributes it considers are "alloc_align", "alloc_size", "cold", "const", "hot", "leaf", "malloc", "nonnull", "noreturn", "nothrow", "pure", "returns_nonnull", and "returns_twice" โœจ.

-Wattribute-alias is the same as -Wattribute-alias=1, and that's the default ๐Ÿ’…. If you want these warnings gone, use either -Wno-attribute-alias or -Wattribute-alias=0 ๐Ÿ™ˆ.

  • -Wbool-compare โ€” Warns when a boolean expression gets compared to an integer value that isn't "true"/"false" ๐Ÿง. Like, this one is always false:
int n = 5;
...
if ((n > 1) == 2) { ... }

It's enabled by -Wall ๐Ÿ’œ.

  • -Wbool-operation โ€” Flags suspicious operations on boolean expressions ๐Ÿšฉ. For example, bitwise negation of a boolean is very likely a bug ๐Ÿ˜ญ. In C, it also warns about incrementing or decrementing a boolean, which almost never makes sense ๐Ÿคจ. (In C++, decrementing a boolean is always invalid, and incrementing one is invalid in C++17 and deprecated before that ๐Ÿ“œ.) It's enabled by -Wall โœจ.
  • -Wduplicated-branches โ€” Warns when an if-else has identical branches ๐Ÿ‘ฏ. It catches stuff like this:
if (p != NULL)
  return 0;
else
  return 0;

It won't warn if both branches contain just a null statement ๐Ÿซถ. This one also warns about conditional operators:

  int i = x ? *p : *p;
  • -Wduplicated-cond โ€” Warns about duplicated conditions in an if-else-if chain ๐Ÿ”. For instance, it'll warn about this:
if (p->q != NULL) { ... }
else if (p->q != NULL) { ... }
  • -Wframe-address โ€” Warns when __builtin_frame_address or __builtin_return_address gets called with an argument greater than 0 ๐Ÿšจ. Those calls can return indeterminate values or crash the program ๐Ÿ’ฅ. It's included in -Wall ๐ŸŒˆ.
  • -Wno-discarded-qualifiers (C and Objective-C only) โ€” Stops the compiler from warning when type qualifiers on pointers get dropped ๐Ÿ™…โ€โ™€๏ธ. The usual case is passing a "const char *" variable to a function that wants a "char *" parameter, and this option lets you silence that ๐Ÿคซ.
  • -Wno-discarded-array-qualifiers (C and Objective-C only) โ€” Stops the warning when type qualifiers on arrays that are pointer targets get dropped ๐Ÿ“. The usual case is passing a "const int (*)[]" variable to a function that takes an "int (*)[]" parameter, and this option can shush that warning too ๐Ÿ”‡.
  • -Wno-incompatible-pointer-types (C and Objective-C only) โ€” No warning when pointers with incompatible types get converted between each other ๐ŸŒ€. This one covers cases that -Wno-pointer-sign doesn't, since that one handles pointer argument passing or assignment with different signedness ๐Ÿงฉ.
  • -Wno-int-conversion (C and Objective-C only) โ€” No warnings about incompatible integer-to-pointer and pointer-to-integer conversions ๐Ÿซ . This one is about implicit conversions. For explicit ones, you can use -Wno-int-to-pointer-cast and -Wno-pointer-to-int-cast instead ๐Ÿงš.
  • -Wno-div-by-zero โ€” Stops the warning about compile-time integer division by zero ๐Ÿ™ƒ. Floating-point division by zero doesn't get warned about anyway, because it can be a legit way to get infinities and NaNs ๐ŸŒŒ.
  • -Wsystem-headers โ€” Prints warning messages for constructs found in system header files ๐Ÿ—๏ธ. Normally those warnings are suppressed, on the assumption that they usually aren't real problems and would just make the compiler output harder to read ๐Ÿ™„. This option tells GCC to emit them as if they came from user code ๐Ÿ“ฃ. Be aware that using -Wall together with this option does not warn about unknown pragmas in system headers---for that, -Wunknown-pragmas also has to be used ๐Ÿง.
  • -Wtautological-compare โ€” Warns if a self-comparison always evaluates to true or false ๐Ÿชž. It catches mistakes like this:
int i = 1;
...
if (i > i) { ... }

It also warns about bitwise comparisons that always come out true or false. For example, this one will always be false:

if ((a & 16) == 10) { ... }

It's enabled by -Wall ๐Ÿ’….

  • -Wtrampolines โ€” Warns about trampolines generated for pointers to nested functions ๐ŸŽช. A trampoline is a small chunk of data or code created at run time on the stack when the address of a nested function is taken, and it's used to call that nested function indirectly ๐Ÿงฉ. Some targets only use data for this, so they don't need any special treatment ๐ŸŒท. But most targets use code, which means the stack has to be made executable for the program to work properly ๐Ÿ˜ฌ.
  • -Wfloat-equal โ€” Warns if floating-point values get used in equality comparisons ๐Ÿ”ข. The reasoning is that sometimes it's handy to treat floats as approximations of infinitely precise real numbers. If you're doing that, you need to figure out (by analyzing the code or some other way) the maximum or likely maximum error the computation introduces, and account for it when you compare values (and when you produce output, but that's a whole different problem ๐Ÿ“„). So instead of testing for equality, check whether the two values have ranges that overlap ๐Ÿซง. That's done with the relational operators, so equality comparisons are probably a mistake ๐Ÿ™…โ€โ™€๏ธ.
  • -Wtraditional (C and Objective-C only) โ€” Warns about certain constructs that behave differently in traditional C and ISO C ๐Ÿ•ฐ๏ธ. It also warns about ISO C constructs that have no traditional C equivalent, and about problematic constructs you should avoid ๐Ÿšซ. Here's the tea:
    • Macro parameters that show up inside string literals in the macro body ๐Ÿงต. In traditional C, macro replacement happens inside string literals, but in ISO C it doesn't ๐Ÿคฏ.
    • In traditional C, some preprocessor directives didn't exist. Traditional preprocessors only treated a line as a directive if the # was in column 1 ๐Ÿงฑ. So -Wtraditional warns about directives that traditional C understands but ignores, because the # isn't the first character on the line ๐Ÿ‘€. It also suggests hiding directives like #pragma, which traditional C doesn't understand, by indenting them ๐Ÿซฃ. Some traditional implementations don't recognize #elif, so this option suggests avoiding it altogether ๐Ÿšซ.
    • A function-like macro that appears without arguments ๐Ÿ™ˆ.
    • The unary plus operator โž•.
    • The U integer constant suffix, or the F or L floating-point constant suffixes ๐Ÿ”ค. (Traditional C does support the L suffix on integer constants ๐Ÿ’โ€โ™€๏ธ.) Heads up, these suffixes show up in macros defined in the system headers of most modern systems, like the _MIN/_MAX macros in "<limits.h>" ๐Ÿ“š. Using those macros in user code would normally cause spurious warnings, but GCC's integrated preprocessor has enough context to avoid warning in these cases ๐Ÿง โœจ.
    • A function declared external in one block and then used after the end of that block ๐Ÿงญ.
    • A switch statement with an operand of type "long" ๐ŸŒ€.
  • โœจ okay so a non-"static" function declaration that shows up after a "static" one is giving chaos ๐Ÿ™ˆ some traditional C compilers straight-up refuse this construct, so watch out, bestie ๐Ÿซถ
  • ๐Ÿ”ข the ISO type of an integer constant can end up with a different width or signedness than its traditional type ๐Ÿ’… this only gets flagged when the base is ten ๐Ÿ“ so hexadecimal or octal values (the bit-pattern ones) are totally safe, no cap
  • ๐Ÿงต usage of ISO string concatenation gets detected here ๐ŸŽ€
  • ๐Ÿ“ฆ initialization of automatic aggregates ๐Ÿ‘€
  • ๐Ÿท๏ธ identifier conflicts with labels ๐Ÿฆ‹ traditional C doesn't have a separate namespace for labels, so that's the whole drama
  • ๐Ÿช„ initialization of unions ๐Ÿ’œ if the initializer is zero, the warning gets skipped ๐Ÿ™ˆ that's because a zero initializer in user code is usually conditioned on something like "__STDC__" to dodge missing-initializer warnings, and it relies on default zero-initialization in the traditional C case
  • ๐Ÿ” conversions by prototypes between fixed and floating-point values, and vice versa โš ๏ธ if those prototypes are missing when you compile with traditional C, things get seriously messy ๐Ÿ˜ญ this is only a subset of the possible conversion warnings, so for the full set use -Wtraditional-conversion
  • ๐ŸŽ€ use of ISO C style function definitions ๐Ÿ’… this one is intentionally not issued for prototype declarations or variadic functions, since those ISO features show up in your code when you're using libiberty's traditional C compatibility macros, "PARAMS" and "VPARAMS" ๐ŸŒธ it's also skipped for nested functions, because that's already a GCC extension and totally irrelevant to traditional C compatibility ๐Ÿงš

  • -Wtraditional-conversion (C and Objective-C only) โ€” okay this one is giving prototype drama ๐Ÿ’ซ it warns if a prototype causes a type conversion that's different from what would happen to the same argument with no prototype ๐Ÿ”ฅ that includes fixed-point to floating and vice versa, plus conversions that change the width or signedness of a fixed-point argument, except when it matches the default promotion โœจ
  • -Wdeclaration-after-statement (C and Objective-C only) โ€” warns when a declaration shows up after a statement in a block ๐Ÿ™ƒ this one is borrowed from C++ and was introduced with ISO C99, and GCC lets it slide by default ๐Ÿ’– it is not supported by ISO C90, so ngl, be careful there ๐Ÿ’€
  • -Wshadow โ€” this is the main character warning ๐Ÿ‘‘ it warns whenever a local variable or type declaration shadows another variable, parameter, type, class member (in C++), or instance variable (in Objective-C), or whenever a built-in function gets shadowed ๐ŸŒˆ in C++ it warns if a local variable shadows an explicit typedef, but not if it shadows a struct, class, or enum ๐Ÿซ  this is the same as -Wshadow=global
  • -Wno-shadow-ivar (Objective-C only) โ€” turns off the warning for when a local variable shadows an instance variable inside an Objective-C method ๐Ÿ™ˆ
  • -Wshadow=global โ€” the default for -Wshadow ๐Ÿ” warns for any (global) shadowing, no exceptions bestie
  • -Wshadow=local โ€” warns when a local variable shadows another local variable or a parameter ๐ŸŽฏ this one gets turned on by -Wshadow=global
  • -Wshadow=compatible-local โ€” same vibe as -Wshadow=local, but it only warns when the shadowed variable's type is compatible with the shadowing one ๐Ÿง  in C++, "compatible" means the shadowing variable's type can be converted to the shadowed variable's type ๐Ÿ’… this flag exists because when a local variable shadows one of an incompatible type, it's most likely on purpose and not a bug or a typo ๐Ÿฆ‹ like in this example:
for (SomeIterator i = SomeObj.begin(); i != SomeObj.end(); ++i)
{
  for (int i = 0; i < N; ++i)
  {
    ...
  }
  ...
}

okay so the two i variables in that example have incompatible types, which means enabling only -Wshadow=compatible-local won't emit a warning ๐Ÿ™ˆ and that's fine, because if a programmer accidentally uses one in place of the other, type checking will catch it and emit an error or warning ๐Ÿซถ so skipping the shadowing warning here won't lead to any undetected bugs ๐ŸŒธ using this flag instead of -Wshadow=local can possibly cut down on the number of warnings triggered by intentional shadowing โœจ

This warning gets enabled by -Wshadow=local ๐Ÿ’–

  • -Wlarger-than=byte-size โ€” warns whenever an object is defined whose size goes over byte-size ๐Ÿ“ -Wlarger-than=PTRDIFF_MAX is turned on by default ๐ŸŒˆ you can disable these warnings either by specifying a byte-size of SIZE_MAX or more, or by using -Wno-larger-than ๐Ÿซถ
  • -Wno-larger-than โ€” disables the -Wlarger-than= warnings ๐Ÿ™… it's the same as -Wlarger-than=SIZE_MAX or larger ๐Ÿ’…
  • -Wframe-larger-than=byte-size โ€” warns if the size of a function frame goes over byte-size ๐Ÿ–ผ๏ธ heads up, the math used to figure out the stack frame size is approximate and not conservative ๐Ÿ˜ฌ the actual requirements might be somewhat greater than byte-size even if you never get a warning ๐Ÿ’€ also, any space allocated via alloca, variable-length arrays, or related constructs is not counted by the compiler when it decides whether to warn ๐Ÿ™ˆ -Wframe-larger-than=PTRDIFF_MAX is on by default ๐ŸŒธ you can disable these warnings by specifying a byte-size of SIZE_MAX or more, or by using -Wno-frame-larger-than โœจ
  • -Wno-frame-larger-than โ€” disables the -Wframe-larger-than= warnings ๐Ÿ™… it's equivalent to -Wframe-larger-than=SIZE_MAX or larger ๐Ÿงš
  • -Wno-free-nonheap-object โ€” don't warn when someone tries to free an object that wasn't allocated on the heap ๐Ÿ™ƒ
  • -Wstack-usage=byte-size โ€” warns if the stack usage of a function might go over byte-size ๐Ÿ“š the math here is conservative, and any space allocated via alloca, variable-length arrays, or related constructs is included when deciding whether to warn ๐Ÿซถ the message matches the output of -fstack-usage ๐Ÿ’–
    • if the stack usage is fully static but goes over the amount, it's: warning: stack usage is 1120 bytes
    • if the stack usage is (partly) dynamic but bounded, it's: warning: stack usage might be 1648 bytes
    • if the stack usage is (partly) dynamic and not bounded, it's: warning: stack usage might be unbounded

-Wstack-usage=PTRDIFF_MAX is enabled by default ๐ŸŒˆ you can disable these warnings by specifying a byte-size of SIZE_MAX or more, or by using -Wno-stack-usage ๐Ÿซ 

  • -Wno-stack-usage โ€” disables the -Wstack-usage= warnings ๐Ÿ™… it's equivalent to -Wstack-usage=SIZE_MAX or larger โœจ
  • -Wunsafe-loop-optimizations โ€” warns if a loop can't be optimized because the compiler can't assume anything about the bounds of the loop indices ๐Ÿ” with -funsafe-loop-optimizations, it warns if the compiler makes those assumptions instead ๐Ÿ‘€
  • -Wno-pedantic-ms-format (MinGW targets only) โ€” when you use it together with -Wformat and -pedantic without GNU extensions, this turns off the warnings about non-ISO "printf" / "scanf" format width specifiers "I32", "I64", and "I" used on Windows targets ๐ŸชŸ those depend on the MS runtime, so they're not exactly a crime ๐Ÿฅน
  • -Waligned-new โ€” warns about a new-expression of a type that needs greater alignment than alignof(std::max_align_t) but uses an allocation function without an explicit alignment parameter ๐Ÿ“ this one is enabled by -Wall ๐ŸŒธ normally it only warns about global allocation functions, but -Waligned-new=all also warns about class member allocation functions ๐Ÿ’…
  • -Wplacement-new, -Wplacement-new=n โ€” warns about placement new expressions with undefined behavior, like constructing an object in a buffer that's smaller than the object's type ๐Ÿ˜ฑ for example, this placement new gets diagnosed because it tries to construct an array of 64 integers in a buffer that's only 64 bytes large:
char buf [64];
new (buf) int[64];

this warning is enabled by default ๐Ÿซถ

  • -Wplacement-new=1 โ€” this is the default warning level for -Wplacement-new ๐Ÿ™‚ at this level, the warning is not issued for some strictly undefined constructs that GCC allows as extensions for compatibility with legacy code ๐Ÿง“ for example, this new expression isn't diagnosed at this level, even though it's undefined behavior according to the C++ standard, because it writes past the end of the one-element array:
struct S { int n, a[1]; };
S *s = (S *)malloc (sizeof *s + 31 * sizeof s->a[0]);
new (s->a)int [32]();
  • -Wplacement-new=2 โ€” at this level, in addition to diagnosing everything level 1 catches, it also issues a diagnostic for placement new expressions that construct an object in the last member of a structure whose type is an array of a single element and whose size is less than the size of the object being constructed ๐Ÿšจ the previous example gets diagnosed here, but the following construct uses the flexible member array extension to avoid the warning at level 2 ๐Ÿ’–
struct S { int n, a[]; };
S *s = (S *)malloc (sizeof *s + 32 * sizeof s->a[0]);
new (s->a)int [32]();
  • -Wpointer-arith โ€” warns about anything that depends on the "size of" a function type or of void ๐Ÿงฎ GNU C gives these types a size of 1, for convenience when doing math with void * pointers and pointers to functions ๐Ÿฆ‹ in C++, it also warns when an arithmetic operation involves NULL โš ๏ธ this warning is also enabled by -Wpedantic โœจ
  • -Wpointer-compare โ€” warns if a pointer is compared with a zero character constant ๐Ÿ‘€ this usually means the pointer was meant to be dereferenced ๐Ÿ™ƒ for example:
const char *p = foo ();
if (p == '\0')
  return 42;

the code above is invalid in C++11, bestie ๐Ÿ’€ this warning is enabled by default ๐Ÿซถ

  • -Wtype-limits โ€” okay so this one is a total vibe check ๐Ÿ’… It warns if a comparison is always true or always false just because the data type has a limited range, like an unsigned variable compared against zero with < or >= ๐Ÿ™ˆ It won't bother you about constant expressions though. This one also comes along for the ride with -Wextra โœจ
  • -Wabsolute-value (C and Objective-C only) โ€” warns when you call a standard absolute-value function on something it doesn't fit, when there's a more appropriate standard function to use ๐Ÿ”ฅ For example, abs(3.14) gets flagged because a double should use fabs. It also warns when the argument to one of these calls has an unsigned type ๐Ÿซถ You can shut the warning up with an explicit type cast, and it's enabled by -Wextra too ๐Ÿ’–
  • -Wcomment, -Wcomments โ€” flags a /* showing up inside a /* comment, or a backslash-newline showing up inside a // comment ๐ŸŒธ This one is enabled by -Wall ๐ŸŽ€
  • -Wtrigraphs โ€” warns about any trigraphs that could change what your program means ๐Ÿฆ‹ Trigraphs sitting inside comments are left alone, except the ones that would form escaped newlines.

This option is implied by -Wall. If -Wall isn't given, it's still switched on unless trigraphs are enabled. If you want trigraph conversion without the warnings, but still want the other -Wall warnings, use -trigraphs -Wall -Wno-trigraphs ๐Ÿ’…

  • -Wundef โ€” warns if an undefined identifier gets evaluated in an #if directive ๐Ÿงš Those identifiers get replaced with zero, so keep an eye out ๐Ÿ‘€
  • -Wexpansion-to-defined โ€” warns whenever defined shows up in the expansion of a macro, including when the macro gets expanded by an #if directive ๐Ÿ˜ญ That kind of usage isn't portable, so it's a no-go. This warning is also enabled by -Wpedantic and -Wextra โœจ
  • -Wunused-macros โ€” warns about macros that are defined in the main file but never used ๐Ÿ“ A macro counts as used if it gets expanded or tested for existence at least once. The preprocessor also warns if the macro hasn't been used by the time it gets redefined or undefined.

Built-in macros, macros defined on the command line, and macros defined in include files are never warned about ๐ŸŒˆ

Note: If a macro is actually used, but only used in skipped conditional blocks, then the preprocessor reports it as unused. To dodge the warning in that situation, you might improve the scope of the macro's definition by, for example, moving it into the first skipped block. Or you could give it a dummy use with something like this:
#if defined the_macro_causing_the_warning
#endif
  • -Wno-endif-labels โ€” don't warn when an #else or an #endif has text following it ๐Ÿ™ˆ This happens sometimes in older programs with code that looks like this:
#if FOO
...
#else FOO
...
#endif FOO

The second and third FOO are supposed to be in comments, honestly ๐Ÿ’€ This warning is on by default.

  • -Wbad-function-cast (C and Objective-C only) โ€” warns when a function call gets cast to a type that doesn't match ๐ŸŽ€ For example, it warns if a call to a function returning an integer type gets cast to a pointer type.
  • -Wc90-c99-compat (C and Objective-C only) โ€” warns about features that aren't in ISO C90 but are in ISO C99 โœจ Think variable length arrays, the long long type, the bool type, compound literals, designated initializers, and so on. This option doesn't care what standards mode you're in. Warnings are turned off in the expression that follows __extension__ ๐Ÿ’œ
  • -Wc99-c11-compat (C and Objective-C only) โ€” warns about features that aren't in ISO C99 but are in ISO C11 ๐Ÿฆ‹ Stuff like anonymous structures and unions, the _Atomic type qualifier, the _Thread_local storage-class specifier, the _Alignas specifier, the Alignof operator, the _Generic keyword, and so on. Again, it doesn't matter which standards mode you're in, and warnings are disabled in the expression that follows __extension__ ๐ŸŒธ
  • -Wc11-c2x-compat (C and Objective-C only) โ€” warns about features that aren't in ISO C11 but are in ISO C2X ๐Ÿงš For instance, it warns about leaving out the string in _Static_assert. It's independent of the standards mode, and warnings are disabled in the expression that follows __extension__ ๐Ÿ’…
  • -Wc++-compat (C and Objective-C only) โ€” warns about ISO C constructs that live outside the common subset of ISO C and ISO C++ ๐Ÿ‘‘ A classic example is asking for an implicit conversion from void * to a pointer to a non-void type.
  • -Wc++11-compat (C++ and Objective-C++ only) โ€” warns about C++ constructs whose meaning changes between ISO C++ 1998 and ISO C++ 2011 ๐Ÿ”ฅ For example, identifiers that were fine in ISO C++ 1998 but are keywords in ISO C++ 2011. This warning turns on -Wnarrowing and is enabled by -Wall โœจ
  • -Wc++14-compat (C++ and Objective-C++ only) โ€” warns about C++ constructs whose meaning differs between ISO C++ 2011 and ISO C++ 2014 ๐Ÿ’– It's enabled by -Wall.
  • -Wc++17-compat (C++ and Objective-C++ only) โ€” warns about C++ constructs whose meaning differs between ISO C++ 2014 and ISO C++ 2017 ๐ŸŒˆ It's enabled by -Wall too.
  • -Wcast-qual โ€” warns whenever a pointer gets cast in a way that removes a type qualifier from the target type ๐Ÿ™ˆ For example, it warns if a const char * gets cast to a plain char *.

It also warns when you make a cast that adds a type qualifier in an unsafe way ๐Ÿ’€ Casting char ** to const char ** is unsafe, as in this example:

/* p is char ** value.  */
const char **q = (const char **) p;
/* Assignment of readonly string to const char * is OK.  */
*q = "string";
/* Now char** pointer points to read-only memory.  */
**p = 'b';
  • -Wcast-align โ€” warns whenever a pointer gets cast so the required alignment of the target goes up ๐Ÿฆ‹ For example, it warns if a char * gets cast to an int * on machines where integers can only be accessed at two- or four-byte boundaries.
  • -Wcast-align=strict โ€” same deal as -Wcast-align, but stricter ๐Ÿ˜ค It warns whenever a pointer gets cast so the required alignment of the target goes up, regardless of the target machine. For example, it warns if a char * gets cast to an int * no matter what machine you're on.
  • -Wcast-function-type โ€” warns when a function pointer gets cast to an incompatible function pointer ๐Ÿ“ For a cast involving function types with a variable argument list, only the types of the initial arguments that are actually provided get considered. Any parameter of pointer type matches any other pointer type. Harmless differences in integral types get ignored, like int vs. long on ILP32 targets, and type qualifiers are ignored too. The function type void (*) (void) is special and matches everything, so you can use it to suppress this warning ๐Ÿงš For a cast involving pointer to member types, this warning fires whenever the cast changes the pointer to member type. It's enabled by -Wextra โœจ
  • -Wwrite-strings โ€” when you're compiling C, string constants get the type const char[length], so copying the address of one into a non-const char * pointer produces a warning ๐Ÿ’œ These warnings help you find code at compile time that could try to write into a string constant, but only if you've been super careful about using const in declarations and prototypes. Otherwise, honestly, it's just a nuisance. That's why -Wall doesn't ask for these warnings.

When you're compiling C++, it warns about the deprecated conversion from string literals to char *. This warning is enabled by default for C++ programs ๐Ÿ‘‘

  • -Wcatch-value, -Wcatch-value=n (C++ and Objective-C++ only) โ€” warns about catch handlers that don't catch via reference ๐Ÿ’… With -Wcatch-value=1 (or -Wcatch-value for short), it warns about polymorphic class types that are caught by value. With -Wcatch-value=2, it warns about all class types that are caught by value. With -Wcatch-value=3, it warns about all types that aren't caught by reference. -Wcatch-value is enabled by -Wall ๐Ÿ”ฅ
  • -Wclobbered โ€” warns for variables that might be changed by longjmp or vfork ๐ŸŒธ This warning is also enabled by -Wextra.
  • -Wconditionally-supported (C++ and Objective-C++ only) โ€” warns for conditionally-supported constructs (C++11 [intro.defs]) โœจ
  • -Wconversion โ€” warns for implicit conversions that might alter a value ๐Ÿซถ That includes conversions between real and integer types, like abs (x) when x is a double. It also covers conversions between signed and unsigned, like unsigned ui = -1, and conversions to smaller types, like sqrtf (M_PI). It does not warn for explicit casts like abs ((int) x) and ui = (unsigned) -1, or if the value doesn't actually change because of the conversion, like abs (2.0). Warnings about conversions between signed and unsigned integers can be turned off with -Wno-sign-conversion ๐Ÿฆ‹

For C++, it also warns about confusing overload resolution for user-defined conversions, and about conversions that never use a type conversion operator: conversions to void, to the same type, to a base class, or to a reference to them ๐Ÿ’– Warnings about conversions between signed and unsigned integers are disabled by default in C++ unless -Wsign-conversion is explicitly enabled.

  • -Wno-conversion-null (C++ and Objective-C++ only) โ€” don't warn about conversions between NULL and non-pointer types ๐Ÿ™ˆ Heads up, -Wconversion-null is enabled by default.
  • -Wzero-as-null-pointer-constant (C++ and Objective-C++ only) โ€” warns when a literal 0 is used as a null pointer constant ๐Ÿงš This can be super useful for making the jump to nullptr in C++11 ๐Ÿ’…
  • -Wsubobject-linkage (C++ and Objective-C++ only) โ€” warns if a class type has a base or a field whose type uses the anonymous namespace or depends on a type with no linkage ๐Ÿ˜ญ If a type A depends on a type B with no or internal linkage, defining it in multiple translation units would be an ODR violation, because the meaning of B is different in each translation unit. If A only shows up in a single translation unit, the best way to silence the warning is to give it internal linkage by putting it in an anonymous namespace as well โœจ The compiler doesn't give this warning for types defined in the main .C file, since those are unlikely to have multiple definitions. -Wsubobject-linkage is enabled by default ๐Ÿ‘‘
  • -Wdangling-else โ€” okay so this one is about the sneaky dangling else ๐Ÿ™ˆ It warns when it's unclear which if an else belongs to. In C/C++, every else attaches to the innermost possible if, which in this example is if (b), even though the indentation makes it look like it's with if (a). Not what the programmer expected, bestie ๐Ÿ’€ When that confusion is possible, GCC warns if you turn this on. To shut it up, add explicit braces around the innermost if so the else can't possibly belong to the outer one. Like this:
{
  if (a)
    if (b)
      foo ();
  else
    bar ();
}
{
  if (a)
    {
      if (b)
        foo ();
      else
        bar ();
    }
}

This warning is enabled by -Wparentheses โœจ

  • -Wdate-time โ€” โฐ warns when the macros __TIME__, __DATE__ or __TIMESTAMP__ show up, since they can stop your compilations from being bit-wise-identical reproducible ๐ŸŽ€
  • -Wdelete-incomplete (C++ and Objective-C++ only) โ€” warns when you delete a pointer to an incomplete type, which can cause undefined behavior at runtime ๐Ÿ’€ This one is enabled by default, so you get it for free ๐Ÿซถ
  • -Wuseless-cast (C++ and Objective-C++ only) โ€” warns when an expression gets cast to its own type. Iconic, but pointless ๐Ÿ’…
  • -Wempty-body โ€” warns if there's an empty body in an if, else or do while statement ๐Ÿงš This one also comes along for the ride with -Wextra
  • -Wenum-compare โ€” warns about comparisons between values of different enumerated types ๐ŸŒˆ In C++, enum mismatches in conditional expressions get flagged too, and that one is enabled by default. In C, this warning is turned on by -Wall ๐Ÿ’œ
  • -Wextra-semi (C++, Objective-C++ only) โ€” warns about a redundant semicolon after an in-class function definition ๐Ÿ™„ extra semicolon, who dis ๐Ÿ’€
  • -Wjump-misses-init (C, Objective-C only) โ€” ๐Ÿฆ‹ warns if a goto or a switch statement jumps forward across the initialization of a variable, or jumps backward to a label after that variable has already been initialized. It only cares about variables that get initialized when they're declared. This is only supported for C and Objective-C, because in C++ this sort of branch is an error anyway ๐Ÿ™ƒ -Wjump-misses-init is included in -Wc++-compat, and you can turn it off with the -Wno-jump-misses-init option.
  • -Wsign-compare โ€” warns when a comparison between signed and unsigned values could give you an incorrect result, because the signed value gets converted to unsigned ๐Ÿ‘€ In C++, this is also enabled by -Wall. In C, it's enabled by -Wextra.
  • -Wsign-conversion โ€” warns about implicit conversions that might change the sign of an integer value, like assigning a signed integer expression to an unsigned integer variable ๐ŸŒธ An explicit cast silences the warning. In C, this option is also enabled by -Wconversion.
  • -Wfloat-conversion โ€” warns about implicit conversions that reduce the precision of a real value ๐Ÿ“‰ That includes real to integer, and higher precision real to lower precision real. This option is also enabled by -Wconversion.
  • -Wno-scalar-storage-order โ€” tells GCC to chill and not warn about suspicious constructs involving reverse scalar storage order ๐Ÿ˜Œ
  • -Wsized-deallocation (C++ and Objective-C++ only) โ€” warns about an unsized deallocation function definition, like these:
void operator delete (void *) noexcept;
void operator delete[] (void *) noexcept;

when the matching sized deallocation function is missing, like these:

void operator delete (void *, std::size_t) noexcept;
void operator delete[] (void *, std::size_t) noexcept;

Or vice versa, so you can't just have one half of the pair ๐Ÿงฉ This is enabled by -Wextra along with -fsized-deallocation.

  • -Wsizeof-pointer-div โ€” ๐Ÿ” warns about suspicious divisions of two sizeof expressions that divide the pointer size by the element size. That's the usual way people compute array size, but it won't work right with pointers. For example, this warns about sizeof (ptr) / sizeof (ptr[0]) if ptr is a pointer and not an array. This warning is enabled by -Wall.
  • -Wsizeof-pointer-memaccess โ€” warns about suspicious length parameters passed to certain string and memory built-in functions when the argument uses sizeof ๐ŸŽ€ It triggers for things like memset (ptr, 0, sizeof (ptr)); if ptr is a pointer and not an array (and suggests a possible fix), or memcpy (&foo, ptr, sizeof (&foo));. It also warns about bounded string copy functions like strncat or strncpy that use a sizeof expression of the source array as the bound. In the example below, the strncat call uses the size of the source string as its bound. That's almost certainly a mistake, so the call gets flagged ๐Ÿšฉ
void make_file (const char *name)
{
  char path[PATH_MAX];
  strncpy (path, name, sizeof path - 1);
  strncat (path, ".text", sizeof ".text");
  ...
}

The -Wsizeof-pointer-memaccess option is enabled by -Wall.

  • -Wsizeof-array-argument โ€” warns when the sizeof operator is applied to a parameter that's declared as an array in a function definition ๐Ÿ“ This one is enabled by default for C and C++ programs.
  • -Wmemset-elt-size โ€” warns about suspicious calls to the memset built-in function, when the first argument references an array and the third argument is a number equal to the number of elements, but not equal to the size of the array in memory. That's a sign you forgot to multiply by the element size ๐Ÿซ  This warning is enabled by -Wall.
  • -Wmemset-transposed-args โ€” warns about suspicious memset calls where the second argument isn't zero and the third argument is zero ๐Ÿ”„ For example, memset (buf, sizeof buf, 0) gets diagnosed, because memset (buf, 0, sizeof buf) was what you meant. The diagnostic only fires if the third argument is a literal zero. If it's an expression that folds to zero, or a cast of zero to some type, the arguments are far less likely to have been mixed up by accident, so no warning is emitted. This warning is enabled by -Wall.
  • -Waddress โ€” warns about suspicious uses of memory addresses ๐Ÿ‘ป That includes using the address of a function in a conditional expression, like void func(void); if (func), and comparing against the memory address of a string literal, like if (x == "abc"). The first one is a classic programmer error, since a function's address always evaluates to true, so you probably forgot the parentheses in a function call. The second one leads to unspecified behavior and isn't portable in C, so you probably meant to use strcmp. This warning is enabled by -Wall.
  • -Waddress-of-packed-member โ€” warns when the address of a packed member of a struct or union is taken, which usually results in an unaligned pointer value ๐Ÿ“ฆ This one is enabled by default.
  • -Wlogical-op โ€” warns about suspicious uses of logical operators in expressions ๐Ÿง That includes using logical operators in places where a bit-wise operator is probably what you wanted. It also warns when both operands of a logical operator are the same, like this:
extern int a;
if (a < 0 && a < 0) { ... }
  • -Wlogical-not-parentheses โ€” warns about a logical not used on the left hand side of a comparison ๐Ÿ™ƒ This option won't warn if the right operand is considered a boolean expression. It's there to catch code like this:
int a;
...
if (!a > 1) { ... }

You can suppress the warning by wrapping the left hand side in parentheses:

if ((!a) > 1) { ... }

This warning is enabled by -Wall โœจ

  • -Waggregate-return โ€” warns if any functions that return structures or unions are defined or called ๐Ÿงฑ In languages where you can return an array, this also triggers a warning.
  • -Wno-aggressive-loop-optimizations โ€” warns if, in a loop with a constant number of iterations, the compiler detects undefined behavior in some statement during one or more of the iterations ๐Ÿ”
  • -Wno-attributes โ€” don't warn if an unexpected __attribute__ is used, like unrecognized attributes, function attributes applied to variables, and so on ๐Ÿคทโ€โ™€๏ธ This doesn't stop errors for incorrect use of supported attributes, so those still show up.
  • -Wno-builtin-declaration-mismatch โ€” warns if a built-in function is declared with an incompatible signature or as a non-function ๐Ÿšซ It also warns when a built-in function that's declared with a type lacking a prototype gets called with arguments whose promoted types don't match what the function expects. When -Wextra is specified, it also warns when a built-in function that takes arguments gets declared without a prototype. This -Wno-builtin-declaration-mismatch warning is enabled by default. To avoid it, include the appropriate header so the prototypes of built-in functions are in scope ๐Ÿ“š

For example, the memset call below gets diagnosed, because the function expects a value of type size_t as its argument but the type of 32 is int. With -Wextra, the declaration of the function gets diagnosed too.

extern void* memset ();
void f (void *d)
{
  memset (d, '\0', 32);
}
  • -Wno-builtin-macro-redefined โ€” don't warn if certain built-in macros get redefined ๐ŸŒท This suppresses warnings for redefinitions of __TIMESTAMP__, __TIME__, __DATE__, __FILE__, and __BASE_FILE__.
  • -Wstrict-prototypes (C and Objective-C only) โ€” warns if a function is declared or defined without specifying its argument types ๐Ÿ“ An old-style function definition is allowed without a warning if it's preceded by a declaration that specifies the argument types.
  • -Wold-style-declaration (C and Objective-C only) โ€” ๐Ÿง“ Okay bestie, this one is for old-school declaration vibes. It warns about obsolescent usages in a declaration, according to the C Standard. For example, it warns if storage-class specifiers like static aren't the very first thing in a declaration. This warning is also enabled by -Wextra โœจ
  • -Wold-style-definition (C and Objective-C only) โ€” ๐Ÿ“œ Warns if you use an old-style function definition, and it does this even if there's already a previous prototype. Ngl, that's a lot of side-eye for a prototype that already exists ๐Ÿ’€
  • -Wmissing-parameter-type (C and Objective-C only) โ€” ๐Ÿ™ˆ Flags a function parameter that's declared without a type specifier in K&R-style functions. Like this:
void foo(bar) { }

This warning is also enabled by -Wextra ๐Ÿ’œ

  • -Wmissing-prototypes (C and Objective-C only) โ€” ๐Ÿ” Warns if a global function is defined without a previous prototype declaration. This still fires even when the definition itself provides a prototype. Use it to catch global functions that don't have a matching prototype in a header file. Not valid for C++, though, because every function declaration there already provides a prototype, and a non-matching declaration just makes an overload instead of conflicting with an earlier one. For missing declarations in C++, use -Wmissing-declarations instead ๐Ÿฆ‹
  • -Wmissing-declarations โ€” ๐Ÿ—‚๏ธ Warns if a global function is defined without a previous declaration, even if the definition itself provides a prototype. Use it to find global functions that aren't declared in header files. In C, no warnings are issued for functions with previous non-prototype declarations, so use -Wmissing-prototypes to catch missing prototypes there. In C++, no warnings are issued for function templates, inline functions, or functions in anonymous namespaces ๐ŸŒธ
  • -Wmissing-field-initializers โ€” ๐Ÿ“ Warns if a structure's initializer is missing some fields. In the example below, that causes a warning, because x.h is implicitly zero:
struct s { int f, g, h; };
struct s x = { 3, 4 };

This option doesn't warn about designated initializers, so this version doesn't trigger a warning:

struct s { int f, g, h; };
struct s x = { .f = 3, .g = 4 };

In C, this option also doesn't warn about the universal zero initializer { 0 }:

struct s { int f, g, h; };
struct s x = { 0 };

Likewise, in C++, this option doesn't warn about the empty { } initializer:

struct s { int f, g, h; };
s x = { };

This warning is included in -Wextra. If you want the other -Wextra warnings without this one, use -Wextra -Wno-missing-field-initializers ๐Ÿซถ

  • -Wno-multichar โ€” ๐Ÿ™… Stops the warning for multicharacter constants like 'FOOF'. Those usually mean there's a typo in your code, since they have implementation-defined values, so they shouldn't be used in portable code ๐Ÿ’…
  • -Wnormalized=[none|id|nfc|nfkc] โ€” ๐Ÿ”ค Okay, this one is giving Unicode drama. In ISO C and ISO C++, two identifiers are different if they're different sequences of characters. But when you use characters outside basic ASCII, you can end up with two different sequences that look exactly the same. To stop that confusion, the ISO 10646 standard has normalization rules that turn look-alike sequences into the same sequence. GCC can warn you if your identifiers haven't been normalized, and this option controls that warning โœจ

There are four warning levels. The default is -Wnormalized=nfc, which warns about any identifier that isn't in the ISO 10646 "C" normalized form, NFC. NFC is the recommended form for most uses, and it's equivalent to -Wnormalized ๐Ÿ’–

Here's the catch: some characters that ISO C and ISO C++ allow in identifiers stop being allowed once they're turned into NFC. So there's no way to use those symbols in portable ISO C or C++ and still have all your identifiers in NFC. -Wnormalized=id suppresses the warning for those characters. The hope is that future versions of the standards will fix this, which is why this isn't the default ๐Ÿฅบ

You can switch the warning off for all characters with -Wnormalized=none or -Wno-normalized. Only do this if you're using some other normalization scheme, like "D", because otherwise you can easily create bugs that are literally impossible to see ๐Ÿ˜ญ

Some characters in ISO 10646 have distinct meanings but look identical in some fonts or display methods, especially once formatting is applied. For instance, "\u207F", "SUPERSCRIPT LATIN SMALL LETTER N", displays just like a regular "n" placed in a superscript. ISO 10646 defines the NFKC normalization scheme to convert all of these into a standard form too, and GCC warns if your code isn't in NFKC when you use -Wnormalized=nfkc. This is kind of like warning about every identifier that contains the letter O because it might be confused with the digit 0, so it isn't the default. But it can be a useful local coding convention if your programming environment can't be fixed to display these characters distinctly ๐Ÿง

  • -Wno-attribute-warning โ€” ๐Ÿ™‰ Stops warnings about using functions declared with the "warning" attribute. This warning is enabled by default. You can use -Wno-attribute-warning to disable the warning, or -Wno-error=attribute-warning to disable the error when you compile with the -Werror flag ๐Ÿ”•
  • -Wno-deprecated โ€” ๐Ÿซฅ Doesn't warn about usage of deprecated features.
  • -Wno-deprecated-declarations โ€” ๐Ÿชฆ Doesn't warn about uses of functions, variables, and types marked as deprecated with the "deprecated" attribute.
  • -Wno-overflow โ€” ๐ŸŒŠ Doesn't warn about compile-time overflow in constant expressions.
  • -Wno-odr โ€” โš–๏ธ Warns about One Definition Rule violations during link-time optimization. It requires -flto-odr-type-merging to be enabled, and it's enabled by default โœ…
  • -Wopenmp-simd โ€” ๐ŸŽ๏ธ Warns if the vectorizer cost model overrides the OpenMP simd directive that the user set. You can use -fsimd-cost-model=unlimited to relax the cost model ๐Ÿ”“
  • -Woverride-init (C and Objective-C only) โ€” ๐Ÿ” Warns if an initialized field without side effects gets overridden when you use designated initializers.

This warning is included in -Wextra. If you want the other -Wextra warnings without this one, use -Wextra -Wno-override-init ๐Ÿ’…

  • -Woverride-init-side-effects (C and Objective-C only) โ€” โš ๏ธ Warns if an initialized field with side effects gets overridden when you use designated initializers. This warning is enabled by default ๐Ÿ”ฅ
  • -Wpacked โ€” ๐Ÿ“ฆ Warns if a structure has the packed attribute, but that attribute doesn't actually change the layout or size of the structure. Those structures can end up misaligned for basically no benefit. For instance, in this code, the variable f.x in struct bar is misaligned, even though struct bar doesn't have the packed attribute itself:
struct foo {
  int x;
  char a, b, c, d;
} __attribute__((packed));
struct bar {
  char z;
  struct foo f;
};
  • -Wpacked-bitfield-compat โ€” ๐Ÿงฉ The 4.1, 4.2, and 4.3 series of GCC ignored the "packed" attribute on bit-fields of type "char." That got fixed in GCC 4.4, but the change can lead to differences in structure layout. GCC tells you when the offset of such a field has changed in GCC 4.4. For example, there's no longer a 4-bit padding between field "a" and "b" in this structure:
struct foo
{
  char a:4;
  char b:8;
} __attribute__ ((packed));

This warning is enabled by default. Use -Wno-packed-bitfield-compat to disable it ๐ŸŽ€

  • -Wpacked-not-aligned (C, C++, Objective-C and Objective-C++ only) โ€” ๐Ÿ“ Warns if a structure field with explicitly specified alignment in a packed struct or union is misaligned. For example, a warning gets issued on "struct S", something like "warning: alignment 1 of 'struct S' is less than 8", in this code:
struct __attribute__ ((aligned (8))) S8 { char a[8]; };
struct __attribute__ ((packed)) S {
  struct S8 s8;
};

This warning is enabled by -Wall ๐ŸŒˆ

  • -Wpadded โ€” ๐Ÿง Warns if padding is included in a structure, either to align one of its elements or to align the whole structure. Sometimes you can rearrange the fields to reduce the padding and make the structure smaller ๐Ÿฐ
  • -Wredundant-decls โ€” ๐Ÿ‘ฏ Warns if anything is declared more than once in the same scope, even when multiple declarations are valid and change nothing ๐Ÿ™„
  • -Wno-restrict โ€” ๐Ÿšซ Warns when an object referenced by a "restrict"-qualified parameter (or, in C++, a "__restrict"-qualified parameter) is aliased by another argument, or when copies between those objects overlap. In the example below, the call to the strcpy function tries to truncate the string by replacing its first characters with the last four. But because the call writes the terminating NUL into a[4], the copies overlap, and the call gets diagnosed:
void foo (void)
{
  char a[] = "abcd1234";
  strcpy (a, a + 4);
  ...
}

The -Wrestrict option detects some instances of simple overlap even without optimization, but it works best at -O2 and above. It's included in -Wall ๐Ÿ”

  • -Wnested-externs (C and Objective-C only) โ€” ๐Ÿช† Warns if an extern declaration shows up inside a function.
  • -Wno-inherited-variadic-ctor โ€” ๐Ÿคซ Suppresses warnings about using C++11 inheriting constructors when the inherited base class has a C variadic constructor. The warning is on by default, because the ellipsis isn't inherited ๐Ÿงš
  • -Winline โ€” ๐Ÿช„ Warns if a function declared as inline can't be inlined. Even with this option, the compiler doesn't warn about failures to inline functions declared in system headers ๐Ÿ’œ

Okay so the compiler is basically doing a vibe check ๐Ÿ”ฎ before it decides whether to inline a function โœจ. It looks at how big the function is and how much inlining has already happened in the current function ๐Ÿ’…. That means tiny edits to your source can make -Winline warnings pop up or vanish ๐Ÿซ 

  • -Wno-invalid-offsetof (C++ and Objective-C++ only) โ€” Shuts up warnings about using the "offsetof" macro on a non-POD type ๐Ÿ™ˆ. According to the 2014 ISO C++ standard, using "offsetof" on a non-standard-layout type is undefined ๐Ÿ’€. Existing C++ implementations usually still give meaningful results, though โœจ. This flag is for people who know their code is nonportable and have deliberately chosen to ignore the warning ๐Ÿ’….

The restrictions on "offsetof" may be relaxed in a future version of the C++ standard ๐Ÿฆ‹.

  • -Wint-in-bool-context โ€” Warns about sketchy integer stuff sneaking into boolean spots ๐Ÿง. That includes conditional expressions (?:) using non-boolean integer constants in a boolean context, like if (a <= b ? 2 : 3). It also covers left shifting signed integers in a boolean context, like for (a = 0; 1 << a; a++);. And it's the same deal for all kinds of multiplications, no matter the data type โœ–๏ธ. This warning is enabled by -Wall ๐ŸŒธ.
  • -Wno-int-to-pointer-cast โ€” Silences warnings about casting an integer of a different size to a pointer type ๐Ÿ™ƒ. In C++, casting to a pointer type of smaller size is an error ๐Ÿšซ. Wint-to-pointer-cast is enabled by default ๐Ÿ“.
  • -Wno-pointer-to-int-cast (C and Objective-C only) โ€” Silences warnings about casting from a pointer to an integer type of a different size ๐Ÿงƒ.
  • -Winvalid-pch โ€” Warns if a precompiled header is found in the search path but can't actually be used ๐Ÿฅฒ.
  • -Wlong-long โ€” Warns whenever the "long long" type is used ๐Ÿ‘€. It's turned on by either -Wpedantic or -Wtraditional in ISO C90 and C++98 modes. To inhibit the warning messages, use -Wno-long-long ๐Ÿคซ.
  • -Wvariadic-macros โ€” Warns if variadic macros are used in ISO C90 mode, or if the GNU alternate syntax is used in ISO C99 mode ๐ŸŒ€. It's enabled by either -Wpedantic or -Wtraditional. To inhibit the warning messages, use -Wno-variadic-macros ๐Ÿ’œ.
  • -Wvarargs โ€” Warns about questionable usage of the macros that handle variable arguments, like "va_start" ๐Ÿง. This one is the default. To inhibit the warning messages, use -Wno-varargs ๐Ÿ™….
  • -Wvector-operation-performance โ€” Warns if a vector operation isn't implemented using the SIMD capabilities of the architecture ๐Ÿ“ˆ. It's mainly useful for performance tuning โšก. There are three ways a vector operation can get implemented:
    • "piecewise" means the scalar operation runs on every vector element ๐Ÿงฉ.
    • "in parallel" means the vector operation is implemented using scalars of a wider type, which is normally more performance efficient ๐ŸŽ๏ธ.
    • "as a single scalar" means the vector fits into a scalar type ๐ŸŽฏ.
  • -Wno-virtual-move-assign โ€” Suppresses warnings about inheriting from a virtual base with a non-trivial C++11 move assignment operator ๐Ÿ™ˆ.
This is dangerous, bestie ๐Ÿ’€ If the virtual base is reachable along more than one path, it gets moved multiple times, which can mean both objects end up in the moved-from state.

If the move assignment operator is written to avoid moving from a moved-from object, this warning can be disabled ๐Ÿซถ.

  • -Wvla โ€” Warns if a variable-length array is used in the code ๐Ÿ“. -Wno-vla prevents the -Wpedantic warning of the variable-length array ๐Ÿ™Œ.
  • -Wvla-larger-than=byte-size โ€” If you use this, the compiler will warn about declarations of variable-length arrays whose size is either unbounded, or bounded by an argument that lets the array size exceed byte-size bytes ๐Ÿฐ. It's kinda like how -Walloca-larger-than=byte-size works, just for variable-length arrays.

Note that GCC may optimize small variable-length arrays of a known value into plain arrays, so this warning may not get triggered for those ๐Ÿค.

-Wvla-larger-than=PTRDIFF_MAX is enabled by default, but it's typically only effective when -ftree-vrp is active, which is the default for -O2 and above ๐Ÿ‘‘.

See also -Walloca-larger-than=byte-size ๐Ÿ”—.

  • -Wno-vla-larger-than โ€” Disables -Wvla-larger-than= warnings ๐Ÿšซ. It's equivalent to -Wvla-larger-than=SIZE_MAX or larger ๐Ÿง .
  • -Wvolatile-register-var โ€” Warns if a register variable is declared volatile ๐ŸงŠ. The volatile modifier doesn't stop every optimization that might eliminate reads and/or writes to register variables. This warning is enabled by -Wall ๐ŸŒˆ.
  • -Wdisabled-optimization โ€” Warns if a requested optimization pass gets disabled ๐Ÿฅบ. This doesn't usually mean anything's wrong with your code. It just means GCC's optimizers can't handle it effectively ๐Ÿคทโ€โ™€๏ธ. Often the problem is that your code is too big or too complex, since GCC refuses to optimize programs when the optimization would likely take inordinate amounts of time โณ.
  • -Wpointer-sign (C and Objective-C only) โ€” Warns for pointer argument passing or assignment with different signedness ๐Ÿงถ. This option is only supported for C and Objective-C. It's implied by -Wall and by -Wpedantic, and it can be disabled with -Wno-pointer-sign ๐Ÿ™…โ€โ™€๏ธ.
  • -Wstack-protector โ€” This one only works when -fstack-protector is active ๐Ÿ›ก๏ธ. It warns about functions that aren't protected against stack smashing ๐Ÿ’ฅ.
  • -Woverlength-strings โ€” Warns about string constants that are longer than the "minimum maximum" length from the C standard ๐Ÿ“œ. Modern compilers are pretty chill and allow string constants way longer than that minimum, but very portable programs should avoid longer strings ๐ŸŒ.

The limit applies after string constant concatenation, and it doesn't count the trailing NUL ๐Ÿงฎ. In C90 the limit was 509 characters, and in C99 it got raised to 4095 ๐Ÿ“ˆ. C++98 doesn't specify a normative minimum maximum, so we don't diagnose overlength strings in C++ ๐Ÿ™ƒ.

This option is implied by -Wpedantic, and it can be disabled with -Wno-overlength-strings ๐Ÿ’….

  • -Wunsuffixed-float-constants (C and Objective-C only) โ€” Issues a warning for any floating constant that doesn't have a suffix ๐Ÿ”ข. When you use it together with -Wsystem-headers, it also warns about those constants in system header files ๐Ÿ—‚๏ธ. This can be super useful when you're prepping code to use with the "FLOAT_CONST_DECIMAL64" pragma from the decimal floating-point extension to C99 ๐ŸŽ€.
  • -Wno-designated-init (C and Objective-C only) โ€” Suppresses warnings when a positional initializer is used to initialize a structure that's been marked with the "designated_init" attribute ๐Ÿ™ˆ.
  • -Whsa โ€” Issues a warning when HSAIL can't be emitted for the compiled function or OpenMP construct โš ๏ธ.

๐Ÿž Options for Debugging Your Program

Okay so if you want GCC to emit extra info for a debugger, you almost always just need to add -g to your other options ๐Ÿงš. That's it, that's the tea ๐Ÿซ–.

GCC lets you use -g with -O too โœจ. The shortcuts optimized code takes can be a little surprising, ngl ๐Ÿ˜ญ. Some variables you declared might not exist at all ๐Ÿ‘ป. Flow of control might briefly jump somewhere you didn't expect ๐ŸŒ€. Some statements might not run because they compute constant results or their values are already at hand ๐Ÿงฎ. And some statements might execute in different places because they got moved out of loops ๐Ÿ”. Nevertheless, it's totally possible to debug optimized output ๐Ÿ’ช, which makes it reasonable to use the optimizer for programs that might have bugs ๐Ÿซถ.

If you aren't using some other optimization option, consider using -Og with -g ๐Ÿฆ‹. With no -O option at all, some compiler passes that collect debugging info don't run at all, so -Og may give you a better debugging experience ๐Ÿ’–.

  • -g โ€” Produces debugging information in the operating system's native format (stabs, COFF, XCOFF, or DWARF) ๐Ÿ”. GDB can work with this debugging information ๐Ÿ’œ.

On most systems that use stabs format, -g enables extra debugging info that only GDB can use ๐Ÿ™ˆ. That makes debugging work better in GDB, but it probably makes other debuggers crash or refuse to read the program ๐Ÿ’€. If you want to control for certain whether to generate the extra info, use -gstabs+, -gstabs, -gxcoff+, -gxcoff, or -gvms (see below) ๐ŸŽฏ.

  • -ggdb โ€” Produces debugging information for GDB ๐ŸŒธ. It uses the most expressive format available (DWARF, stabs, or the native format if neither of those are supported), including GDB extensions if at all possible ๐Ÿ‘‘.
  • -gdwarf, -gdwarf-version โ€” Produces debugging information in DWARF format (if that's supported) ๐Ÿงœโ€โ™€๏ธ. The value of version may be 2, 3, 4 or 5 ๐Ÿ”ข. The default version for most targets is 4 โœ…. DWARF Version 5 is only experimental ๐Ÿงช.

Note that with DWARF Version 2, some ports require and always use some non-conflicting DWARF 3 extensions in the unwind tables ๐Ÿงต.

Version 4 may require GDB 7.0 and -fvar-tracking-assignments for maximum benefit ๐Ÿ†.

GCC no longer supports DWARF Version 1, which is substantially different than Version 2 and later ๐Ÿšซ. For historical reasons, some other DWARF-related options such as -fno-dwarf2-cfi-asm) retain a reference to DWARF Version 2 in their names, but they apply to all currently-supported versions of DWARF ๐Ÿค“.
  • -gstabs โ€” Produces debugging information in stabs format (if that's supported), without GDB extensions ๐Ÿงพ. This is the format DBX uses on most BSD systems ๐Ÿก. On MIPS, Alpha and System V Release 4 systems, this option produces stabs debugging output that DBX doesn't understand ๐Ÿ˜ต. On System V Release 4 systems, this option requires the GNU assembler ๐Ÿ› ๏ธ.
  • -gstabs+ โ€” Produces debugging information in stabs format (if that's supported), using GNU extensions that only the GNU debugger (GDB) understands โœจ. Using these extensions will likely make other debuggers crash or refuse to read the program ๐Ÿ’€.
  • -gxcoff โ€” Produces debugging information in XCOFF format (if that's supported) ๐Ÿ–ฅ๏ธ. This is the format the DBX debugger uses on IBM RS/6000 systems ๐Ÿงก.
  • -gxcoff+ โ€” okay bestie, this one spits out debug info in XCOFF format ๐Ÿงš (if your setup even supports it). It uses GNU extensions that only GDB (the GNU debugger) understands, so other debuggers might crash or straight up refuse to read your program ๐Ÿ’€. Other assemblers besides GAS (the GNU assembler) might also throw an error on it.
  • -gvms โ€” Alpha/VMS debug format ๐Ÿฆ‹ (again, only if it's supported). This is the format DEBUG uses on Alpha/VMS systems, so if that's your world, slay.
  • -glevel, -ggdblevel, -gstabslevel, -gxcofflevel, -gvmslevel โ€” you ask for debug info AND pick how much with a level ๐ŸŒธ. The default is 2, obviously iconic.
    • Level 0 โ€” zero debug info at all ๐Ÿ™…โ€โ™€๏ธ. So -g0 cancels out -g, periodt.
    • Level 1 โ€” minimal vibes, just enough for backtraces in the parts you don't plan to debug. You get descriptions of functions and external variables plus line number tables, but no info about local variables.
    • Level 3 โ€” the extra-extra stuff, like all the macro definitions in the program ๐Ÿ”ฅ. Some debuggers can do macro expansion when you use -g3.
    • If you stack multiple -g options, with or without level numbers, the last one is the one that counts ๐Ÿ‘‘.
    • -gdwarf doesn't accept a concatenated debug level, so it won't get mixed up with -gdwarf-level. Use an additional -glevel option to change the debug level for DWARF instead ๐Ÿ’œ.
  • -feliminate-unused-debug-symbols โ€” produces debug info in stabs format (if supported), but only for symbols that are actually used ๐Ÿงน. Lean and mean.
  • -femit-class-debug-always โ€” instead of dropping a C++ class's debug info into just one object file, it goes into every object file that uses the class ๐ŸŽ€. Only use this with debuggers that can't handle GCC's normal way of emitting class debug info.
โš ๏ธ Warning, bestie: this can make your debug info up to a factor of two bigger ๐Ÿ˜ญ.
  • -fno-merge-debug-strings โ€” tells the linker to NOT merge together strings in the debug info that are identical across different object files ๐Ÿงต. Merging isn't supported by every assembler or linker. It shrinks the debug info in your output file, but costs more link time. Merging is enabled by default โœจ.
  • -fdebug-prefix-map=old=new โ€” when compiling files living in directory old, the debug info describes them as if they lived in directory new instead ๐Ÿ—บ๏ธ. It's great for swapping a build-time path for an install-time path. You can also turn an absolute path into a relative one by using . for new. This can give you more reproducible, location-independent builds ๐ŸŒˆ, but you may need an extra command to tell GDB where to find the source files. See also -ffile-prefix-map.
  • -fvar-tracking โ€” runs the variable tracking pass ๐Ÿ•ต๏ธ, which works out where variables are stored at each position in the code. That gives you better debug info, as long as the debug info format supports it. It's on by default when you compile with optimization (-Os, -O, -O2, ...), with debug info (-g), and the debug info format supports it.
  • -fvar-tracking-assignments โ€” annotates assignments to user variables early in compilation and tries to carry those annotations all the way to the end ๐Ÿง . The goal is better debug info while optimizing. Using -gdwarf-4 alongside it is recommended ๐Ÿ’…. It can be enabled even if var-tracking is disabled. In that case the annotations are still created and maintained, but thrown away at the end. By default this flag is enabled together with -fvar-tracking, except when selective scheduling is enabled.
  • -gsplit-dwarf โ€” separates as much DWARF debug info as possible into its own output file with the extension .dwo ๐Ÿ“ฆ. This lets your build system avoid linking files that have debug info. To be useful, you need a debugger that can read .dwo files.
  • -gdescribe-dies โ€” adds description attributes to some DWARF DIEs that have no name attribute ๐Ÿท๏ธ, like artificial variables, external references, and call site parameter DIEs.
  • -gpubnames โ€” generates the DWARF ".debug_pubnames" and ".debug_pubtypes" sections ๐Ÿ“š.
  • -ggnu-pubnames โ€” generates ".debug_pubnames" and ".debug_pubtypes" sections in a format suitable for conversion into a GDB index ๐Ÿงฉ. This is only useful with a linker that can produce GDB index version 7.
  • -fdebug-types-section โ€” when you're using DWARF Version 4 or higher, type DIEs can get their own ".debug_types" section instead of living in ".debug_info" ๐Ÿงฉ. Putting them in a separate comdat section is more efficient, since the linker can then remove duplicates โœ‚๏ธ. But not all DWARF consumers support ".debug_types" sections yet, and on some objects it makes the debug info bigger instead of smaller ๐Ÿ˜ฌ.
  • -grecord-gcc-switches, -gno-record-gcc-switches โ€” this one tacks the command-line options that may affect code generation onto the DW_AT_producer attribute in DWARF debug info ๐Ÿ“. The options are joined with spaces, separating them from each other and from the compiler version. It's enabled by default. See also -frecord-gcc-switches for another way to store compiler options in the object file.
  • -gstrict-dwarf โ€” disallows extensions from a later DWARF standard version than the one selected with -gdwarf-version ๐Ÿšซ. On most targets, though, using non-conflicting DWARF extensions from later standard versions is allowed.
  • -gno-strict-dwarf โ€” allows extensions from a later DWARF standard version than the one selected with -gdwarf-version ๐Ÿ”“.
  • -gas-loc-support โ€” tells the compiler that the assembler supports .loc directives ๐Ÿ“, so it can use them to generate DWARF2+ line number tables. This is generally desirable, because assembler-generated line number tables are a lot more compact than the ones the compiler can make itself. It's enabled by default if the assembler was found to support these directives at GCC configure time.
  • -gno-as-loc-support โ€” forces GCC to generate DWARF2+ line number tables internally, if DWARF2+ line number tables are going to be generated at all ๐Ÿ› ๏ธ.
  • gas-locview-support โ€” tells the compiler that the assembler supports "view" assignment and reset assertion checking in .loc directives ๐Ÿ‘€. It's enabled by default if the assembler was found to support them at GCC configure time.
  • gno-as-locview-support โ€” forces GCC to assign view numbers internally, if -gvariable-location-views is explicitly requested ๐Ÿ™….
  • -gcolumn-info, -gno-column-info โ€” emits location column information into DWARF debug info, not just file and line ๐Ÿ“. It's enabled by default.
  • -gstatement-frontiers, -gno-statement-frontiers โ€” makes GCC create markers in its internal representation at the beginning of statements ๐Ÿšฉ and keep them roughly in place throughout compilation. Those markers guide the output of "is_stmt" markers in the line number table. This is enabled by default when compiling with optimization (-Os, -O, -O2, ...) and outputting DWARF 2 debug info at the normal level ๐ŸŒŸ.
  • -gvariable-location-views, -gvariable-location-views=incompat5, -gno-variable-location-views โ€” augments variable location lists with progressive view numbers implied from the line number table ๐Ÿ‘๏ธ. This lets debug info consumers inspect state at certain points in the program, even if no instructions associated with the corresponding source locations are present there. If the assembler lacks support for view numbers in line number tables, the compiler will emit the line number table, which generally makes them somewhat less compact. The augmented line number tables and location lists are fully backward-compatible, so consumers that aren't aware of these augmentations can still read them, but they won't get any benefit from them either ๐Ÿคท.

This is enabled by default when outputting DWARF 2 debug info at the normal level, as long as there's assembler support, -fvar-tracking-assignments is enabled, and -gstrict-dwarf is not. When assembler support isn't available, it may still be enabled, but it forces GCC to output internal line number tables. And if -ginternal-reset-location-views is not enabled, that will most certainly lead to silently mismatching location views ๐Ÿ˜ต.

๐Ÿšจ There's a proposed representation for view numbers that is not backward compatible with the location list format introduced in DWARF 5. You can enable it with -gvariable-location-views=incompat5. This option may be removed in the future, and it's only provided as a reference implementation of the proposed representation. Debug info consumers aren't expected to support this extended format, and they would be unable to decode location lists using it.
  • -ginternal-reset-location-views, -gno-internal-reset-location-views โ€” attempts to determine which location views can be omitted from location view lists ๐Ÿง. This requires the compiler to have very accurate instruction length estimates, which isn't always the case. It may cause incorrect view lists to be generated silently when using an assembler that doesn't support location view lists. The GNU assembler will flag any such error as a "view number mismatch". This is only enabled on ports that define a reliable estimation function.
  • -ginline-points, -gno-inline-points โ€” generates extended debug info for inlined functions ๐Ÿช„. Location view tracking markers are inserted at inlined entry points, so address and view numbers can be computed and output in the debug info. This can be enabled independently of location views, in which case the view numbers won't be output. It can only be enabled along with statement frontiers, and it's only enabled by default if location views are enabled ๐Ÿ’–.
  • -gz[=type]. Okay so this one makes compressed debug sections in DWARF format ๐Ÿ—œ๏ธ, but only if that's supported, bestie! If you don't give a type, the default depends on what your assembler and linker can do. type can be none (don't compress the debug sections ๐Ÿ™…), zlib (zlib compression in ELF gABI format), or zlib-gnu (zlib compression in the traditional GNU format). If the linker can't write compressed debug sections, the option gets rejected ๐Ÿ’€. If the assembler can't handle them, -gz is silently ignored when producing object files ๐Ÿซฅ.
  • -femit-struct-debug-baseonly. This one is giving minimalism ๐Ÿฆ‹. Debug info for struct-like types only gets emitted when the base name of the compilation source file matches the base name of the file where the struct is defined. It substantially reduces the size of the debug info, but there's a big potential loss in type info for the debugger, so be careful ๐Ÿ’…. If you want something less aggressive, check out -femit-struct-debug-reduced, and for more detailed control, look at -femit-struct-debug-detailed. This option only works with DWARF debug output.
  • -femit-struct-debug-reduced. A slightly chiller version of the baseonly one ๐ŸŒธ. Debug info for struct-like types only gets emitted when the base name of the compilation source file matches the base name of the file where the type is defined, unless the struct is a template or defined in a system header. It significantly reduces the debug info size, with some potential loss in type info for the debugger. For a more aggressive option, see -femit-struct-debug-baseonly, and for more detailed control, see -femit-struct-debug-detailed. This option only works with DWARF debug output.
  • -femit-struct-debug-detailed[=spec-list]. This is the detailed boss-level version ๐Ÿ‘‘ of -femit-struct-debug-reduced and -femit-struct-debug-baseonly, and it handles most needs. The whole point is to reduce duplicate struct debug info across different object files in the same program. It's where you say which struct-like types get debug info.

A specification looks like this:

[dir:|ind:][ord:|gen:](any|sys|base|none)

The optional first word limits the spec to structs that are used directly (dir:) or used indirectly (ind:). A struct type is used directly when it's the type of a variable or member. Indirect uses come through pointers to structs. So when using an incomplete struct is valid, the use is indirect. For example: struct one direct; is direct, and struct two * indirect; is indirect.

The optional second word limits the spec to ordinary structs (ord:) or generic structs (gen:). Generic structs are a bit complicated to explain ๐Ÿ™ˆ. For C++, these are non-explicit specializations of template classes, or non-template classes within the above. Other programming languages have generics, but -femit-struct-debug-detailed doesn't implement them yet.

The third word specifies the source files for those structs that should get debug info. The values none and any have their normal meaning. The value base means the base of the name of the file where the type declaration appears must match the base of the name of the main compilation file. In practice, when compiling foo.c, debug info is generated for types declared in that file and foo.h, but not other header files. The value sys means those types that satisfy base or are declared in system or compiler headers.

You may need to experiment to find the best settings for your app ๐Ÿงช.

The default is -femit-struct-debug-detailed=all.

This option only works with DWARF debug output.

  • -fno-dwarf2-cfi-asm. Instead of using GAS .cfi_* directives, this one emits DWARF unwind info as a compiler-generated .eh_frame section ๐Ÿงš.
  • -fno-eliminate-unused-debug-types. Normally, when producing DWARF output, GCC skips debug symbol output for types that are nowhere used in the source file being compiled. Sometimes you actually want debug info for every type declared in a compilation unit, even unused ones. For example, if you want to cast a value to a type in the debugger that your program doesn't actually use (but does declare). Honestly though, this usually just wastes a ton of space ๐Ÿ˜ญ.

โœจ Options That Control Optimization โœจ

These options control various sorts of optimizations ๐Ÿ’–.

Without any optimization option, the compiler's goal is to reduce compilation cost and make debugging give the results you expect ๐ŸŽ€. Statements are independent: if you stop the program at a breakpoint between statements, you can assign a new value to any variable or change the program counter to any other statement in the function and get exactly the results you expect from the source code.

Turning on optimization flags makes the compiler try to improve performance and/or code size, at the expense of compilation time and possibly the ability to debug the program ๐Ÿ”ฅ.

The compiler optimizes based on what it knows about the program. Compiling multiple files at once into a single output file lets the compiler use info from all the files when compiling each of them ๐Ÿซถ.

Not all optimizations get their own flag. Only optimizations that have a flag are listed in this section ๐ŸŒˆ.

Most optimizations are completely disabled at -O0, or when no -O level is set on the command line, even if you specify individual optimization flags. Similarly, -Og suppresses many optimization passes.

Depending on the target and how GCC was configured, a slightly different set of optimizations might be enabled at each -O level than what's listed here. To find the exact set enabled at each level, run -Q --help=optimizers โœจ.

  • -O, -O1. Optimize! Optimizing compilation takes somewhat more time, and a lot more memory for a large function ๐Ÿง .

With -O, the compiler tries to reduce code size and execution time, without doing any optimizations that take a great deal of compilation time.

-O turns on the following optimization flags:

-fauto-inc-dec -fbranch-count-reg -fcombine-stack-adjustments
-fcompare-elim -fcprop-registers -fdce -fdefer-pop -fdelayed-branch
-fdse -fforward-propagate -fguess-branch-probability -fif-conversion
-fif-conversion2 -finline-functions-called-once -fipa-profile
-fipa-pure-const -fipa-reference -fipa-reference-addressable
-fmerge-constants -fmove-loop-invariants -fomit-frame-pointer
-freorder-blocks -fshrink-wrap -fshrink-wrap-separate
-fsplit-wide-types -fssa-backprop -fssa-phiopt -ftree-bit-ccp
-ftree-ccp -ftree-ch -ftree-coalesce-vars -ftree-copy-prop
-ftree-dce -ftree-dominator-opts -ftree-dse -ftree-forwprop
-ftree-fre -ftree-phiprop -ftree-pta -ftree-scev-cprop -ftree-sink
-ftree-slsr -ftree-sra -ftree-ter -funit-at-a-time
  • -O2. Optimize even more ๐Ÿ’ช. GCC does nearly all supported optimizations that don't involve a space-speed tradeoff. Compared to -O, this one increases both compilation time and the performance of the generated code.

-O2 turns on all optimization flags specified by -O. It also turns on the following:

-falign-functions  -falign-jumps -falign-labels  -falign-loops
-fcaller-saves -fcode-hoisting -fcrossjumping -fcse-follow-jumps
-fcse-skip-blocks -fdelete-null-pointer-checks -fdevirtualize
-fdevirtualize-speculatively -fexpensive-optimizations -fgcse
-fgcse-lm -fhoist-adjacent-loads -finline-small-functions
-findirect-inlining -fipa-bit-cp  -fipa-cp  -fipa-icf -fipa-ra
-fipa-sra  -fipa-vrp -fisolate-erroneous-paths-dereference
-flra-remat -foptimize-sibling-calls -foptimize-strlen
-fpartial-inlining -fpeephole2 -freorder-blocks-algorithm=stc
-freorder-blocks-and-partition  -freorder-functions
-frerun-cse-after-loop -fschedule-insns  -fschedule-insns2
-fsched-interblock  -fsched-spec -fstore-merging -fstrict-aliasing
-fthread-jumps -ftree-builtin-call-dce -ftree-pre
-ftree-switch-conversion  -ftree-tail-merge -ftree-vrp
Heads up ๐Ÿ’€: please note the warning under -fgcse about invoking -O2 on programs that use computed gotos.
NOTE: In Ubuntu 8.10 and later versions, -D_FORTIFY_SOURCE=2 is set by default, and it's activated when -O is set to 2 or higher. This enables additional compile-time and run-time checks for several libc functions. To disable it, specify either -U_FORTIFY_SOURCE or -D_FORTIFY_SOURCE=0.
  • -O3. Optimize yet more ๐Ÿ”ฅ๐Ÿ”ฅ. -O3 turns on all optimizations specified by -O2, and also turns on the following:
-fgcse-after-reload -finline-functions -fipa-cp-clone
-floop-interchange -floop-unroll-and-jam -fpeel-loops
-fpredictive-commoning -fsplit-paths -ftree-loop-distribute-patterns
-ftree-loop-distribution -ftree-loop-vectorize -ftree-partial-pre
-ftree-slp-vectorize -funswitch-loops -fvect-cost-model
-fversion-loops-for-strides
  • -O0. The chill default ๐ŸงŠ. It reduces compilation time and makes debugging give the expected results. This is the default.
  • -Os. Optimize for size ๐Ÿ“. -Os enables all -O2 optimizations except the ones that often increase code size:
-falign-functions  -falign-jumps -falign-labels  -falign-loops
-fprefetch-loop-arrays  -freorder-blocks-algorithm=stc

It also enables -finline-functions, makes the compiler tune for code size rather than execution speed, and performs further optimizations designed to shrink the code.

  • -Ofast. Disregard strict standards compliance ๐Ÿ˜ค. -Ofast enables all -O3 optimizations. It also enables optimizations that aren't valid for every standard-compliant program. It turns on -ffast-math and the Fortran-specific -fstack-arrays (unless -fmax-stack-var-size is specified), and -fno-protect-parens.
  • -Og. Optimize the debugging experience ๐Ÿฆ‹. -Og should be your go-to optimization level for the standard edit-compile-debug cycle. It offers a reasonable level of optimization while keeping compilation fast and the debugging experience good. It's a better choice than -O0 for producing debuggable code, because some compiler passes that collect debug info are disabled at -O0 ๐Ÿ’–.

Like -O0, -Og totally switches off a bunch of optimization passes, so the individual options that control those passes won't do anything ๐Ÿ™ˆ Otherwise, -Og turns on all the -O1 optimization flags, except the ones that might get in the way of debugging ๐Ÿ” Here's the skip list:

-fbranch-count-reg  -fdelayed-branch -fif-conversion
-fif-conversion2 -finline-functions-called-once
-fmove-loop-invariants  -fssa-phiopt -ftree-bit-ccp  -ftree-pta
-ftree-sra

If you use multiple -O options, with or without level numbers, the last one you write is the one that counts โœจ

Options that look like -fflag are the machine-independent flags ๐Ÿ’… Most of them come in two flavours, a positive and a negative. The negative version of -ffoo is -fno-foo. The list below only shows the one you'll usually reach for, so if you need the other one, just add or remove the no- bit ๐Ÿฆ‹

The following options control specific optimizations ๐ŸŽ€ They're either switched on by -O options or they're related to ones that are. Use these in the rare cases when you want to do some "fine-tuning" of which optimizations get performed ๐Ÿงš

  • -fno-defer-pop โ€” On machines that have to pop arguments after a function call, this makes the compiler pop them right away, as soon as each function returns. At -O1 and higher, -fdefer-pop is the default, which lets arguments pile up on the stack across several function calls and then get popped all at once ๐Ÿงน
  • -fforward-propagate โ€” Runs a forward propagation pass on RTL ๐Ÿ”ฅ The pass tries to combine two instructions and then checks whether the result can be simplified. If loop unrolling is active, two passes get performed, and the second one is scheduled after loop unrolling. This is enabled by default at optimization levels -O, -O2, -O3, -Os.
  • -ffp-contract=style โ€” Controls floating-point expression contraction ๐Ÿงฎ -ffp-contract=off turns it off. -ffp-contract=fast turns it on, forming things like fused multiply-add operations if the target has native support for them. -ffp-contract=on turns it on only if the language standard allows it. Right now this one isn't actually implemented, so it gets treated the same as -ffp-contract=off ๐Ÿ˜ญ The default is -ffp-contract=fast.
  • -fomit-frame-pointer โ€” Omits the frame pointer in functions that don't need one ๐Ÿฆ‹ This skips the instructions that save, set up and restore the frame pointer, and on many targets it also frees up an extra register. On some targets this flag does nothing, because the standard calling sequence always uses a frame pointer and it can't be left out. Also, -fno-omit-frame-pointer doesn't promise the frame pointer gets used in every function, since several targets always omit it in leaf functions. Enabled by default at -O and higher.
  • -foptimize-sibling-calls โ€” Optimizes sibling and tail recursive calls ๐Ÿ‘‘ Enabled at levels -O2, -O3, -Os.
  • -foptimize-strlen โ€” Upgrades various standard C string functions (like "strlen", "strchr" or "strcpy") and their "_FORTIFY_SOURCE" counterparts into faster alternatives ๐ŸŒˆ Enabled at levels -O2, -O3.
  • -fno-inline โ€” Doesn't expand any functions inline, except the ones marked with the "always_inline" attribute ๐Ÿ™…โ€โ™€๏ธ This is the default when you're not optimizing. Single functions can get exempted from inlining by marking them with the "noinline" attribute.
  • -finline-small-functions โ€” Integrates functions into their callers when their body is smaller than the code for the function call itself, so the overall program gets smaller ๐Ÿ“ The compiler heuristically decides which functions are simple enough to be worth it. This applies to all functions, even ones not declared inline. Enabled at levels -O2, -O3, -Os.
  • -findirect-inlining โ€” Also inlines indirect calls that are discovered to be known at compile time, thanks to previous inlining โœจ This option only has an effect when inlining itself is turned on by -finline-functions or -finline-small-functions. Enabled at levels -O2, -O3, -Os.
  • -finline-functions โ€” Considers all functions for inlining, even if they aren't declared inline ๐Ÿ’– The compiler heuristically decides which ones are worth integrating this way. If every call to a given function gets integrated, and the function is declared "static", then it's normally not output as assembler code in its own right. Enabled at levels -O3, -Os. Also enabled by -fprofile-use and -fauto-profile.
  • -finline-functions-called-once โ€” Considers all "static" functions that get called once for inlining into their caller, even if they aren't marked "inline" ๐ŸŽฏ If a call to a given function is integrated, then the function isn't output as assembler code on its own. Enabled at levels -O1, -O2, -O3 and -Os, but not -Og.
  • -fearly-inlining โ€” Inlines functions marked "always_inline", plus functions whose body seems smaller than the function call overhead, early on. This happens before the -fprofile-generate instrumentation and the real inlining pass ๐Ÿƒโ€โ™€๏ธ Doing it this way makes profiling significantly cheaper and usually makes inlining faster on programs with large chains of nested wrapper functions. Enabled by default.
  • -fipa-sra โ€” Performs interprocedural scalar replacement of aggregates, removes unused parameters, and swaps parameters passed by reference for parameters passed by value ๐Ÿงฉ Enabled at levels -O2, -O3 and -Os.
  • -finline-limit=n โ€” By default GCC limits the size of functions that can be inlined ๐Ÿ“ This flag gives you coarse control over that limit. n is the size of functions that can be inlined, measured in pseudo instructions. Inlining is actually controlled by a bunch of parameters, which you can set one at a time with --param name=value. The -finline-limit=n option sets some of those parameters like this:
    • max-inline-insns-single is set to n/2.
    • max-inline-insns-auto is set to n/2.

See below for documentation on the individual parameters that control inlining, plus their defaults ๐Ÿ“š Heads up: there may be no value of -finline-limit that gives you default behaviour ๐Ÿคทโ€โ™€๏ธ Also, a "pseudo instruction" here is just an abstract measure of a function's size. It is in no way a count of assembly instructions, so what it means might change from one release to another.

  • -fno-keep-inline-dllexport โ€” A more fine-grained version of -fkeep-inline-functions, which only applies to functions declared with the "dllexport" attribute or declspec ๐ŸŽ€
  • -fkeep-inline-functions โ€” In C, emits "static" functions declared "inline" into the object file, even if they've been inlined into all of their callers ๐Ÿซถ This switch doesn't affect functions using the "extern inline" extension in GNU C90. In C++, it emits any and all inline functions into the object file.
  • -fkeep-static-functions โ€” Emits "static" functions into the object file, even if they're never used ๐ŸŒธ
  • -fkeep-static-consts โ€” Emits variables declared "static const" when optimization isn't turned on, even if the variables aren't referenced ๐Ÿ’… GCC enables this option by default. If you want the compiler to check whether a variable is referenced, regardless of whether optimization is on, use -fno-keep-static-consts.
  • -fmerge-constants โ€” Tries to merge identical constants (string constants and floating-point constants) across compilation units ๐Ÿ’œ This is the default for optimized compilation if the assembler and linker support it. Use -fno-merge-constants to stop this from happening. Enabled at levels -O, -O2, -O3, -Os.
  • -fmerge-all-constants โ€” Tries to merge identical constants and identical variables ๐ŸŒˆ This option implies -fmerge-constants. On top of that, it also considers things like even constant initialized arrays, or initialized constant variables with integral or floating-point types. C and C++ require each variable, including multiple instances of the same variable in recursive calls, to have distinct locations, so using this option results in non-conforming behavior.
๐Ÿ’€ Bestie, seriously, this one is non-conforming! C and C++ need every variable to have its own distinct location, so -fmerge-all-constants can break that rule. Use it with your eyes open ๐Ÿ‘€
  • -fmodulo-sched โ€” Performs swing modulo scheduling right before the first scheduling pass ๐Ÿ” This pass looks at innermost loops and reorders their instructions by overlapping different iterations.
  • -fmodulo-sched-allow-regmoves โ€” Performs more aggressive SMS-based modulo scheduling, with register moves allowed ๐Ÿš€ Setting this flag deletes certain anti-dependences edges, which triggers the generation of reg-moves based on life-range analysis. This option is only effective when -fmodulo-sched is enabled.
  • -fno-branch-count-reg โ€” Disables the optimization pass that scans for chances to use "decrement and branch" instructions on a count register, instead of instruction sequences that decrement a register, compare it against zero, and then branch based on the result ๐Ÿ’ This option is only meaningful on architectures that support such instructions, which include x86, PowerPC, IA-64 and S/390. Note that -fno-branch-count-reg doesn't remove the decrement and branch instructions that other optimization passes put into the generated instruction stream. The default is -fbranch-count-reg at -O1 and higher, except for -Og.
  • -fno-function-cse โ€” Doesn't put function addresses in registers. Instead, every instruction that calls a constant function contains the function's address explicitly ๐Ÿง  This gives you less efficient code, but some strange hacks that alter the assembler output may get confused by the optimizations performed when this option isn't used. The default is -ffunction-cse
  • -fno-zero-initialized-in-bss โ€” If the target supports a BSS section, GCC by default puts variables that are initialized to zero into BSS, which can save space in the resulting code ๐Ÿ’พ This option turns that behaviour off, because some programs explicitly rely on variables living in the data section, e.g. so the resulting executable can find the beginning of that section and/or make assumptions based on it. The default is -fzero-initialized-in-bss.
  • -fthread-jumps โ€” okay so this one checks if a jump lands somewhere a comparison the first branch already covers shows up again ๐Ÿ‘€. If it does, the first branch gets redirected to either the destination of the second branch or the spot right after it, depending on whether the condition is known to be true or false ๐Ÿ’…. Enabled at levels -O2, -O3, -Os ๐ŸŒธ.
  • -fsplit-wide-types โ€” when you use a type that takes up multiple registers, like long long on a 32-bit system, this splits those registers apart and allocates each one on its own ๐Ÿฆ‹. It usually makes the code better for those types, but ngl it can make debugging harder ๐Ÿ™ˆ. Enabled at levels -O, -O2, -O3, -Os.
  • -fcse-follow-jumps โ€” during common subexpression elimination (CSE), it scans through jump instructions when no other path reaches the jump's target ๐Ÿงš. Like, when CSE hits an if with an else clause, it follows the jump when the tested condition is false. Enabled at levels -O2, -O3, -Os.
  • -fcse-skip-blocks โ€” basically the cousin of -fcse-follow-jumps, but this one makes CSE follow jumps that conditionally skip over blocks ๐ŸŽ€. For a simple if with no else clause, CSE follows the jump around the body of the if. Enabled at levels -O2, -O3, -Os.
  • -frerun-cse-after-loop โ€” runs CSE again after the loop optimizations are done ๐Ÿ”. Enabled at levels -O2, -O3, -Os.
  • -fgcse โ€” a global common subexpression elimination pass that also does global constant and copy propagation โœจ. Enabled at levels -O2, -O3, -Os.
Note: When compiling a program using computed gotos, a GCC extension, you may get better run-time performance if you disable the global common subexpression elimination pass by adding -fno-gcse to the command line. ๐Ÿ™ˆ
  • -fgcse-lm โ€” when this is on, global CSE tries to move loads that only get killed by stores into themselves ๐Ÿซถ. That lets a loop with a load/store sequence become a load outside the loop and a copy/store inside it. Enabled by default when -fgcse is enabled.
  • -fgcse-sm โ€” after global CSE, a store motion pass runs that tries to move stores out of loops ๐Ÿ’œ. Used together with -fgcse-lm, loops containing a load/store sequence can become a load before the loop and a store after it. Not enabled at any optimization level.
  • -fgcse-las โ€” eliminates redundant loads that come after stores to the same memory location, covering both partial and full redundancies ๐Ÿ“. Not enabled at any optimization level.
  • -fgcse-after-reload โ€” a redundant load elimination pass after reload, whose whole job is cleaning up redundant spilling ๐Ÿงน. Enabled by -fprofile-use and -fauto-profile.
  • -faggressive-loop-optimizations โ€” tells the loop optimizer to use language constraints to figure out bounds on how many times a loop iterates ๐Ÿง . It assumes your loop code doesn't invoke undefined behavior, for example by causing signed integer overflows or out-of-bound array accesses. Those bounds guide loop unrolling, loop peeling, and loop exit test optimizations. This option is enabled by default.
  • -funconstrained-commons โ€” tells the compiler that variables declared in common blocks (e.g. Fortran) may later be overridden with longer trailing arrays ๐Ÿ“. This stops certain optimizations that depend on knowing the array bounds.
  • -fcrossjumping โ€” performs the cross-jumping transformation, which unifies equivalent code and saves code size ๐Ÿซง. The resulting code may or may not perform better than without cross-jumping. Enabled at levels -O2, -O3, -Os.
  • -fauto-inc-dec โ€” combines increments or decrements of addresses with memory accesses โž•. This pass is always skipped on architectures that don't have instructions to support it. Enabled by default at -O and higher on architectures that support this.
  • -fdce โ€” performs dead code elimination (DCE) on RTL ๐Ÿ—‘๏ธ. Enabled by default at -O and higher.
  • -fdse โ€” performs dead store elimination (DSE) on RTL ๐Ÿ’€. Enabled by default at -O and higher.
  • -fif-conversion โ€” attempts to transform conditional jumps into branch-less equivalents ๐Ÿ”€. This includes conditional moves, min, max, set flags and abs instructions, and some tricks doable with standard arithmetic. Whether conditional execution gets used on chips that have it is controlled by -fif-conversion2. Enabled at levels -O, -O2, -O3, -Os, but not with -Og.
  • -fif-conversion2 โ€” uses conditional execution (where available) to transform conditional jumps into branch-less equivalents ๐ŸŒˆ. Enabled at levels -O, -O2, -O3, -Os, but not with -Og.
  • -fdeclone-ctor-dtor โ€” the C++ ABI requires multiple entry points for constructors and destructors: one for a base subobject, one for a complete object, and one for a virtual destructor that calls operator delete afterwards ๐Ÿ—๏ธ. For a hierarchy with virtual bases, the base and complete variants are clones, which means two copies of the function. With this option, those variants become thunks that call a common implementation. Enabled by -Os.
  • -fdelete-null-pointer-checks โ€” assumes programs can't safely dereference null pointers, and that no code or data element lives at address zero ๐Ÿšซ. This option enables simple constant folding optimizations at all optimization levels. Other GCC optimization passes use this flag to control global dataflow analyses that eliminate useless null pointer checks. Those analyses assume a memory access to address zero always results in a trap, so if a pointer gets checked after it's already been dereferenced, it can't be null.
Note however that in some environments this assumption is not true. Use -fno-delete-null-pointer-checks to disable this optimization for programs that depend on that behavior. โš ๏ธ

This option is enabled by default on most targets. On Nios II ELF, it defaults to off. On AVR, CR16, and MSP430, this option is completely disabled. Passes that use the dataflow information are enabled independently at different optimization levels.

  • -fdevirtualize โ€” tries to convert calls to virtual functions into direct calls ๐ŸŽฏ. This happens both within a procedure and interprocedurally, as part of indirect inlining (-findirect-inlining) and interprocedural constant propagation (-fipa-cp). Enabled at levels -O2, -O3, -Os.
  • -fdevirtualize-speculatively โ€” tries to convert calls to virtual functions into speculative direct calls ๐Ÿ”ฎ. Based on analysis of the type inheritance graph, it figures out the set of likely targets for a given call. If that set is small, ideally size 1, the call becomes a conditional that decides between a direct and an indirect call. The speculative calls enable more optimizations, such as inlining. If they seem useless after further optimization, they get converted back into their original form.
  • -fdevirtualize-at-ltrans โ€” streams extra information needed for aggressive devirtualization when running the link-time optimizer in local transformation mode ๐Ÿ“ฆ. This option enables more devirtualization but significantly increases the size of the streamed data. For this reason, it's disabled by default.
  • -fexpensive-optimizations โ€” performs a bunch of minor optimizations that are relatively expensive ๐Ÿ’ธ. Enabled at levels -O2, -O3, -Os.
  • -free โ€” attempts to remove redundant extension instructions ๐Ÿงฝ. This is especially helpful for the x86-64 architecture, which implicitly zero-extends in 64-bit registers after writing to their lower 32-bit half. Enabled for Alpha, AArch64 and x86 at levels -O2, -O3, -Os.
  • -fno-lifetime-dse โ€” in C++, the value of an object is only affected by changes within its lifetime ๐Ÿ•ฐ๏ธ. When the constructor begins, the object has an indeterminate value, and any changes during the object's lifetime are dead once it's destroyed. Normally dead store elimination takes advantage of this. If your code relies on the value of the object storage persisting beyond the object's lifetime, use this flag to disable the optimization. To keep stores made before the constructor starts (e.g. because your operator new clears the object storage) but still treat the object as dead after the destructor, you can use -flifetime-dse=1. The default behavior can be explicitly selected with -flifetime-dse=2. -flifetime-dse=0 is equivalent to -fno-lifetime-dse.
  • -flive-range-shrinkage โ€” tries to decrease register pressure through register live range shrinkage ๐Ÿ“‰. This is helpful for fast processors with small or moderate size register sets.
  • -fira-algorithm=algorithm โ€” uses the specified coloring algorithm for the integrated register allocator ๐ŸŽจ. The algorithm argument can be priority, which specifies Chow's priority coloring, or CB, which specifies Chaitin-Briggs coloring. Chaitin-Briggs coloring isn't implemented for all architectures, but for the targets that do support it, it's the default because it generates better code.
  • -fira-region=region โ€” uses the specified regions for the integrated register allocator ๐Ÿ—บ๏ธ. The region argument should be one of the following:
    • all โ€” uses all loops as register allocation regions. This can give the best results for machines with a small and/or irregular register set.
    • mixed โ€” uses all loops except for loops with small register pressure as the regions. This value usually gives the best results in most cases and for most architectures, and it's enabled by default when compiling with optimization for speed (-O, -O2, ...).
    • one โ€” uses all functions as a single region. This typically results in the smallest code size, and it's enabled by default for -Os or -O0.
  • -fira-hoist-pressure: okay so this one tells IRA to look at register pressure during the code hoisting pass when it decides which expressions to hoist ๐Ÿงš It usually gives you smaller code, but it can slow the compiler down ๐Ÿข Enabled at level -Os for all targets ๐Ÿ’…
  • -fira-loop-pressure: IRA checks register pressure inside loops before deciding whether to move loop invariants ๐Ÿ” On machines with large register files (>= 32 registers) this usually means faster and smaller code ๐Ÿ”ฅ The compiler might be slower though. Enabled at level -O3 for some targets โœจ
  • -fno-ira-share-save-slots: turns off sharing of stack slots used to save call-used hard registers that stay alive through a call. Every hard register gets its own slot, so your stack frames get bigger ๐Ÿ“ฆ
  • -fno-ira-share-spill-slots: turns off sharing of stack slots for pseudo-registers. Each pseudo-register that doesn't get a hard register gets its own slot, which means bigger stack frames ๐Ÿฅฒ
  • -flra-remat: enables CFG-sensitive rematerialization in LRA ๐Ÿงฎ Instead of loading spilled pseudos back in, LRA tries to recalculate the values if that's actually worth it. Enabled at levels -O2, -O3, -Os.
  • -fdelayed-branch: if the target machine supports it, GCC tries to reorder instructions so they fill the slots available after delayed branch instructions ๐ŸŽ€ Enabled at levels -O, -O2, -O3, -Os, but not at -Og ๐Ÿ™…โ€โ™€๏ธ
  • -fschedule-insns: if the target supports it, GCC reorders instructions to get rid of execution stalls caused by data that isn't ready yet โณ This helps machines with slow floating point or memory load instructions, since other instructions can get issued while the load or float op is still cooking. Enabled at levels -O2, -O3.
  • -fschedule-insns2: basically -fschedule-insns, but it also runs an extra round of instruction scheduling after register allocation ๐Ÿ”„ This is especially iconic on machines with a small number of registers where memory loads take more than one cycle. Enabled at levels -O2, -O3, -Os.
  • -fno-sched-interblock: disables instruction scheduling across basic blocks ๐Ÿšซ This is normally on when scheduling happens before register allocation, i.e. with -fschedule-insns or at -O2 or higher.
  • -fno-sched-spec: disables speculative motion of non-load instructions ๐Ÿ™…โ€โ™€๏ธ This is normally enabled when scheduling happens before register allocation, i.e. with -fschedule-insns or at -O2 or higher.
  • -fsched-pressure: enables register pressure sensitive instruction scheduling before register allocation ๐Ÿ’… This only makes sense when scheduling before register allocation is turned on, i.e. with -fschedule-insns or at -O2 or higher. It can improve the generated code and shrink it too, by stopping register pressure from climbing above the number of available hard registers (which would lead to spills later in register allocation).
  • -fsched-spec-load: allows speculative motion of some load instructions ๐Ÿ“ฅ This only makes sense when scheduling before register allocation, i.e. with -fschedule-insns or at -O2 or higher.
  • -fsched-spec-load-dangerous: allows speculative motion of more load instructions ๐ŸŒถ๏ธ The name is a little spicy, and it only makes sense when scheduling before register allocation, i.e. with -fschedule-insns or at -O2 or higher.
  • -fsched-stalled-insns, -fsched-stalled-insns=n: sets how many insns (if any) can get moved early from the queue of stalled insns into the ready list during the second scheduling pass ๐ŸŽฏ -fno-sched-stalled-insns means no insns get moved early. -fsched-stalled-insns=0 means there's no limit on how many queued insns can be moved early. Plain -fsched-stalled-insns with no value is the same as -fsched-stalled-insns=1.
  • -fsched-stalled-insns-dep, -fsched-stalled-insns-dep=n: sets how many insn groups (cycles) get checked for a dependency on a stalled insn that's a candidate for early removal from the stalled queue ๐Ÿ” This only has an effect during the second scheduling pass, and only if -fsched-stalled-insns is being used. -fno-sched-stalled-insns-dep is equivalent to -fsched-stalled-insns-dep=0. -fsched-stalled-insns-dep without a value is equivalent to -fsched-stalled-insns-dep=1.
  • -fsched2-use-superblocks: when scheduling after register allocation, this uses superblock scheduling, which lets instructions move across basic block boundaries for faster schedules ๐Ÿš€ This only makes sense when scheduling after register allocation, i.e. with -fschedule-insns2 or at -O2 or higher.
Heads up, bestie: this option is experimental! Not every machine description GCC uses models the CPU closely enough to avoid unreliable results from the algorithm ๐Ÿ’€
  • -fsched-group-heuristic: enables the group heuristic in the scheduler, which favors the instruction that belongs to a schedule group ๐Ÿ‘ฏ It's enabled by default when scheduling is on, i.e. with -fschedule-insns or -fschedule-insns2 or at -O2 or higher.
  • -fsched-critical-path-heuristic: enables the critical-path heuristic, which favors instructions on the critical path ๐Ÿ›ค๏ธ Also enabled by default when scheduling is on, i.e. with -fschedule-insns or -fschedule-insns2 or at -O2 or higher.
  • -fsched-spec-insn-heuristic: enables the speculative instruction heuristic, which favors speculative instructions with greater dependency weakness ๐Ÿง  Enabled by default when scheduling is on, i.e. with -fschedule-insns or -fschedule-insns2 or at -O2 or higher.
  • -fsched-rank-heuristic: enables the rank heuristic, which favors instructions in a basic block with greater size or frequency ๐Ÿ“Š Enabled by default when scheduling is on, i.e. with -fschedule-insns or -fschedule-insns2 or at -O2 or higher.
  • -fsched-last-insn-heuristic: enables the last-instruction heuristic, which favors instructions that depend less on the last instruction scheduled ๐Ÿซง Enabled by default when scheduling is on, i.e. with -fschedule-insns or -fschedule-insns2 or at -O2 or higher.
  • -fsched-dep-count-heuristic: enables the dependent-count heuristic, which favors instructions that have more instructions depending on them ๐ŸŒŸ Enabled by default when scheduling is on, i.e. with -fschedule-insns or -fschedule-insns2 or at -O2 or higher.
  • -freschedule-modulo-scheduled-loops: modulo scheduling happens before the traditional scheduling, and if a loop gets modulo scheduled, later scheduling passes might change its schedule ๐Ÿ” Use this one to control that behavior.
  • -fselective-scheduling: schedules instructions with the selective scheduling algorithm ๐ŸŽ›๏ธ It runs instead of the first scheduler pass.
  • -fselective-scheduling2: schedules instructions with the selective scheduling algorithm too, but this time it runs instead of the second scheduler pass ๐Ÿช„
  • -fsel-sched-pipelining: enables software pipelining of the innermost loops during selective scheduling ๐Ÿฅ This does nothing unless -fselective-scheduling or -fselective-scheduling2 is turned on.
  • -fsel-sched-pipelining-outer-loops: when pipelining loops during selective scheduling, this also pipelines the outer loops too ๐Ÿช† It does nothing unless -fsel-sched-pipelining is turned on.
  • -fsemantic-interposition: some object formats, like ELF, let the dynamic linker interpose symbols ๐Ÿงฉ That means for symbols exported from the DSO, the compiler can't do interprocedural propagation, inlining, or other optimizations, because the function or variable might get swapped out for something else. This is useful, for example, if you want to rewrite memory allocation functions with a debugging implementation, but it's expensive in terms of code quality ๐Ÿ˜ญ With -fno-semantic-interposition, the compiler assumes that if interposition happens for functions, the overwriting function will have precisely the same semantics (and side effects). Similarly, if interposition happens for variables, the constructor of the variable will be the same. This flag has no effect on functions explicitly declared inline (where interposition is never allowed to change semantics), or on symbols explicitly declared weak.
  • -fshrink-wrap: emits function prologues only before the parts of the function that actually need them, instead of at the very top ๐ŸŽ Enabled by default at -O and higher.
  • -fshrink-wrap-separate: shrink-wraps the separate parts of the prologue and epilogue separately, so each part only runs when it's needed โœจ This is on by default, but it has no effect unless -fshrink-wrap is also turned on and the target supports it.
  • -fcaller-saves: enables allocation of values to registers that get clobbered by function calls ๐Ÿ’พ It does this by emitting extra instructions to save and restore those registers around such calls. This allocation only happens when it seems to result in better code. It's always enabled by default on certain machines, usually the ones with no call-preserved registers to use instead. Enabled at levels -O2, -O3, -Os.
  • -fcombine-stack-adjustments: tracks stack adjustments (pushes and pops) and stack memory references, then tries to find ways to combine them ๐Ÿงน Enabled by default at -O1 and higher.
  • -fipa-ra: uses caller-save registers for allocation if none of the called functions use those registers ๐Ÿช„ That means there's no need to save and restore them around calls. This is only possible if the called functions are part of the same compilation unit as the current function and they get compiled before it. Enabled at levels -O2, -O3, -Os. However, the option is disabled if the generated code will be instrumented for profiling (-p, or -pg), or if the callee's register usage can't be known exactly (which happens on targets that don't expose prologues and epilogues in RTL) ๐Ÿ™ˆ

-fconserve-stack Attempt to minimize stack usage ๐Ÿงš okay so the compiler tries really hard to use less stack space, even if your program ends up a little slower because of it ๐Ÿฅบ This option also sets the large-stack-frame parameter to 100 and the large-stack-frame-growth parameter to 400 ๐Ÿ’–

-ftree-reassoc Perform reassociation on trees ๐ŸŒธ This flag is turned on by default at -O and higher โœจ

-fcode-hoisting Perform code hoisting ๐Ÿฆ‹ Code hoisting tries to move the evaluation of expressions that run on all paths to the function exit as early as possible ๐Ÿ’… This is especially useful as a code size optimization, but it often helps code speed too ๐Ÿ”ฅ This flag is enabled by default at -O2 and higher ๐Ÿ‘‘

-ftree-pre Perform partial redundancy elimination (PRE) on trees ๐ŸŽ€ This flag is enabled by default at -O2 and -O3 ๐Ÿซถ

-ftree-partial-pre Make partial redundancy elimination (PRE) more aggressive ๐Ÿ’œ This flag is enabled by default at -O3 ๐Ÿ˜ญ

-ftree-forwprop Perform forward propagation on trees ๐ŸŒˆ This flag is enabled by default at -O and higher ๐Ÿ’…

-ftree-fre Perform full redundancy elimination (FRE) on trees ๐Ÿ“ The difference between FRE and PRE is that FRE only considers expressions that are computed on all paths leading to the redundant computation โœจ This analysis is faster than PRE, though it exposes fewer redundancies ๐Ÿงš This flag is enabled by default at -O and higher ๐Ÿ’–

-ftree-phiprop Perform hoisting of loads from conditional pointers on trees ๐Ÿฆ‹ This pass is enabled by default at -O and higher ๐ŸŒธ

-fhoist-adjacent-loads Speculatively hoist loads from both branches of an if-then-else if the loads are from adjacent locations in the same structure and the target architecture has a conditional move instruction ๐Ÿ”ฅ This flag is enabled by default at -O2 and higher ๐Ÿ‘‘

-ftree-copy-prop Perform copy propagation on trees ๐Ÿ’… This pass gets rid of unnecessary copy operations ๐Ÿ™ˆ This flag is enabled by default at -O and higher โœจ

-fipa-pure-const Discover which functions are pure or constant ๐Ÿ”ฎ Enabled by default at -O and higher ๐Ÿ’œ

-fipa-reference Discover which static variables do not escape the compilation unit ๐Ÿซถ Enabled by default at -O and higher ๐ŸŒˆ

-fipa-reference-addressable Discover read-only, write-only and non-addressable static variables ๐ŸŽ€ Enabled by default at -O and higher ๐Ÿ’–

-fipa-stack-alignment Reduce stack alignment on call sites if possible ๐ŸŒธ Enabled by default ๐Ÿ’…

-fipa-pta Perform interprocedural pointer analysis and interprocedural modification and reference analysis ๐Ÿงš > Heads up, bestie: this option can cause excessive memory and compile-time usage on large compilation units ๐Ÿ’€ It is not enabled by default at any optimization level ๐Ÿ™…โ€โ™€๏ธ

-fipa-profile Perform interprocedural profile propagation ๐Ÿฆ‹ The functions called only from cold functions are marked as cold โ„๏ธ Functions executed once (such as "cold", "noreturn", static constructors or destructors) are also identified โœจ Cold functions and loop-less parts of functions executed once are then optimized for size ๐Ÿ’… Enabled by default at -O and higher ๐Ÿ‘‘

-fipa-cp Perform interprocedural constant propagation ๐Ÿ”ฅ This optimization analyzes the program to figure out when values passed to functions are constants, and then optimizes accordingly ๐Ÿ’– It can substantially boost performance if your app passes constants to functions ๐Ÿš€ This flag is enabled by default at -O2, -Os and -O3 ๐ŸŒธ It is also enabled by -fprofile-use and -fauto-profile ๐Ÿ’œ

-fipa-cp-clone Perform function cloning to make interprocedural constant propagation stronger ๐ŸŽ€ When enabled, interprocedural constant propagation performs function cloning when an externally visible function can be called with constant arguments ๐Ÿฆ‹ > Heads up: because this can create multiple copies of functions, it may significantly increase code size (see --param ipcp-unit-growth=value) ๐Ÿ˜ญ This flag is enabled by default at -O3 ๐ŸŒˆ It is also enabled by -fprofile-use and -fauto-profile โœจ

-fipa-bit-cp When enabled, perform interprocedural bitwise constant propagation ๐Ÿงš This flag is enabled by default at -O2 and by -fprofile-use and -fauto-profile ๐Ÿ’… It requires that -fipa-cp is enabled ๐Ÿซถ

-fipa-vrp When enabled, perform interprocedural propagation of value ranges ๐ŸŒธ This flag is enabled by default at -O2 ๐Ÿ’– It requires that -fipa-cp is enabled ๐Ÿ™Œ

-fipa-icf Perform Identical Code Folding for functions and read-only variables ๐Ÿ”ฅ The optimization reduces code size and may disturb unwind stacks by replacing a function with an equivalent one that has a different name ๐Ÿ’€ It works more effectively with link-time optimization enabled โœจ

Although the behavior is similar to the Gold Linker's ICF optimization, GCC ICF works on different levels, so the optimizations are not the same ๐Ÿค“ There are equivalences that only GCC finds and equivalences that only Gold finds ๐Ÿซถ

This flag is enabled by default at -O2 and -Os ๐Ÿ‘‘

-flive-patching=level Control GCC's optimizations so they produce output suitable for live-patching ๐Ÿฆ‹

If the compiler's optimization uses a function's body, or information extracted from its body, to optimize or change another function, that latter function is called an impacted function of the former ๐Ÿ’… If a function is patched, its impacted functions should be patched too ๐Ÿซถ

The impacted functions are determined by the compiler's interprocedural optimizations ๐Ÿง  For example, a caller is impacted when inlining a function into its caller, cloning a function and changing its caller to call the new clone, or extracting a function's pureness or constness information to optimize its direct or indirect callers, and so on ๐ŸŒˆ

Usually, the more IPA optimizations enabled, the larger the number of impacted functions for each function ๐Ÿ“ˆ To control the number of impacted functions and more easily compute the list of them, IPA optimizations can be partially enabled at two different levels ๐ŸŽ€

The level argument should be one of the following:

  • inline-clone Only enable inlining and cloning optimizations, which include inlining, cloning, interprocedural scalar replacement of aggregates and partial inlining ๐Ÿ’– As a result, when patching a function, all its callers and its clones' callers are impacted, so they need to be patched as well ๐Ÿซถ

-flive-patching=inline-clone disables the following optimization flags: -fwhole-program -fipa-pta -fipa-reference -fipa-ra -fipa-icf -fipa-icf-functions -fipa-icf-variables -fipa-bit-cp -fipa-vrp -fipa-pure-const -fipa-reference-addressable -fipa-stack-alignment ๐Ÿ™…โ€โ™€๏ธ

  • inline-only-static Only enable inlining of static functions ๐ŸŒธ As a result, when patching a static function, all its callers are impacted and so they need to be patched as well ๐Ÿ’œ

In addition to all the flags that -flive-patching=inline-clone disables, -flive-patching=inline-only-static disables the following additional optimization flags: -fipa-cp-clone -fipa-sra -fpartial-inlining -fipa-cp ๐Ÿšซ

When -flive-patching is specified without any value, the default value is inline-clone โœจ

This flag is disabled by default ๐Ÿ™…โ€โ™€๏ธ

Note that -flive-patching is not supported with link-time optimization (-flto) ๐Ÿ’€

-fisolate-erroneous-paths-dereference Detect paths that trigger erroneous or undefined behavior due to dereferencing a null pointer ๐Ÿšจ Isolate those paths from the main control flow and turn the statement with erroneous or undefined behavior into a trap ๐Ÿชค This flag is enabled by default at -O2 and higher and depends on -fdelete-null-pointer-checks also being enabled ๐Ÿ’œ

-fisolate-erroneous-paths-attribute Detect paths that trigger erroneous or undefined behavior due to a null value being used in a way forbidden by a "returns_nonnull" or "nonnull" attribute ๐Ÿซฃ Isolate those paths from the main control flow and turn the statement with erroneous or undefined behavior into a trap ๐Ÿชค This is not currently enabled, but it may be enabled by -O2 in the future ๐Ÿ”ฎ

-ftree-sink Perform forward store motion on trees ๐Ÿงš This flag is enabled by default at -O and higher ๐Ÿ’…

-ftree-bit-ccp Perform sparse conditional bit constant propagation on trees and propagate pointer alignment information ๐Ÿฆ‹ This pass only operates on local scalar variables and is enabled by default at -O1 and higher, except for -Og ๐ŸŒธ It requires that -ftree-ccp is enabled ๐Ÿ’–

-ftree-ccp Perform sparse conditional constant propagation (CCP) on trees ๐ŸŽ€ This pass only operates on local scalar variables and is enabled by default at -O and higher ๐Ÿซถ

-fssa-backprop Propagate information about uses of a value up the definition chain in order to simplify the definitions ๐Ÿง  For example, this pass strips sign operations if the sign of a value never matters ๐Ÿ™ˆ The flag is enabled by default at -O and higher โœจ

-fssa-phiopt Perform pattern matching on SSA PHI nodes to optimize conditional code ๐ŸŒˆ This pass is enabled by default at -O1 and higher, except for -Og ๐Ÿ’…

-ftree-switch-conversion Perform conversion of simple initializations in a switch to initializations from a scalar array ๐Ÿ“ This flag is enabled by default at -O2 and higher ๐Ÿ‘‘

-ftree-tail-merge Look for identical code sequences ๐Ÿ‘€ When found, replace one with a jump to the other ๐Ÿฆ˜ This optimization is known as tail merging or cross jumping ๐ŸŒธ This flag is enabled by default at -O2 and higher ๐Ÿ’– The compilation time in this pass can be limited using the max-tail-merge-comparisons parameter and the max-tail-merge-iterations parameter ๐Ÿง 

-ftree-dce Perform dead code elimination (DCE) on trees ๐Ÿงน This flag is enabled by default at -O and higher ๐Ÿ’œ

-ftree-builtin-call-dce Perform conditional dead code elimination (DCE) for calls to built-in functions that may set "errno" but are otherwise free of side effects ๐ŸŽ€ This flag is enabled by default at -O2 and higher if -Os is not also specified ๐Ÿ’…

  • -ftree-dominator-opts: okay so this one runs a bunch of little scalar cleanups ๐Ÿงน (constant/copy propagation, redundancy elimination, range propagation and expression simplification) by walking a dominator tree โœจ. It also does jump threading, which cuts down on jumps that just lead to other jumps ๐Ÿฆ‹. Enabled by default at -O and higher ๐Ÿ’–.
  • -ftree-dse: dead store elimination (DSE) on trees ๐Ÿ’€. A dead store is a write to a memory location that gets overwritten by a later write with no intervening loads, so the first write can be deleted ๐Ÿ—‘๏ธ. Enabled by default at -O and higher ๐Ÿซถ.
  • -ftree-ch: loop header copying on trees ๐ŸŒธ. It's super beneficial because it boosts the code motion optimizations, and it also saves one jump ๐Ÿฆ‹. Enabled by default at -O and higher.
๐Ÿ™ˆ It is not enabled for -Os, since it usually increases code size.
  • -ftree-loop-optimize: loop optimizations on trees ๐Ÿ”. Enabled by default at -O and higher โœจ.
  • -ftree-loop-linear, -floop-strip-mine, -floop-block: these are loop nest optimizations ๐Ÿงฉ, same as -floop-nest-optimize. To use this code transformation, GCC has to be configured with --with-isl so the Graphite loop transformation infrastructure is enabled ๐Ÿ› ๏ธ.
  • -fgraphite-identity: turns on the identity transformation for graphite ๐Ÿชž. For every SCoP, GCC generates the polyhedral representation and transforms it back to gimple ๐Ÿ”„. With this one you can check the costs or benefits of the GIMPLE -> GRAPHITE -> GIMPLE round trip ๐Ÿ’…. Some minimal optimizations also happen in the code generator isl, like index splitting and dead code elimination in loops ๐Ÿงš.
  • -floop-nest-optimize: enables the isl based loop nest optimizer ๐Ÿ’œ. It's a generic one based on the Pluto optimization algorithms, and it calculates a loop structure that's optimized for data-locality and parallelism ๐ŸŒˆ.
โš ๏ธ bestie, this option is experimental.
  • -floop-parallelize-all: uses the Graphite data dependence analysis to figure out which loops can be parallelized ๐Ÿงต. It parallelizes every loop that can be analyzed as not containing loop carried dependences, without checking whether parallelizing is actually profitable ๐Ÿ˜ฌ.
  • -ftree-coalesce-vars: when GCC transforms the program out of the SSA representation, it tries to cut down on copying by merging versions of different user-defined variables, not just compiler temporaries ๐Ÿงฉ. Heads up, this may severely limit your ability to debug an optimized program compiled with -fno-var-tracking-assignments ๐Ÿ˜ญ. In the negated form, this flag stops SSA coalescing of user variables ๐Ÿ™…โ€โ™€๏ธ. It's enabled by default if optimization is on, and it does very little otherwise.
  • -ftree-loop-if-convert: tries to transform conditional jumps in the innermost loops into branch-less equivalents ๐ŸŒ€. The vibe is to remove control-flow from those innermost loops so the vectorization pass can handle them better ๐Ÿ’ซ. Enabled by default if vectorization is enabled.
  • -ftree-loop-distribution: loop distribution ๐Ÿฐ. This can improve cache performance on big loop bodies and lets other loop optimizations, like parallelization or vectorization, take place ๐Ÿš€. For example, the loop:
DO I = 1, N
  A(I) = B(I) + C
  D(I) = E(I) * F
ENDDO

is transformed to:

DO I = 1, N
   A(I) = B(I) + C
ENDDO
DO I = 1, N
   D(I) = E(I) * F
ENDDO

Enabled by default at -O3. It's also enabled by -fprofile-use and -fauto-profile ๐Ÿ‘‘.

  • -ftree-loop-distribute-patterns: loop distribution of patterns that can be code generated with calls to a library ๐Ÿ“š. Enabled by default at -O3, and by -fprofile-use and -fauto-profile โœจ.

This pass distributes the initialization loops and generates a call to memset zero ๐Ÿงธ. For example, the loop:

DO I = 1, N
  A(I) = 0
  B(I) = A(I) + I
ENDDO

is transformed to:

DO I = 1, N
   A(I) = 0
ENDDO
DO I = 1, N
   B(I) = A(I) + I
ENDDO

and the initialization loop is transformed into a call to memset zero. This flag is enabled by default at -O3. It's also enabled by -fprofile-use and -fauto-profile ๐Ÿ’œ.

  • -floop-interchange: loop interchange outside of graphite ๐Ÿ”€. This can improve cache performance on loop nests and let further loop optimizations, like vectorization, take place ๐ŸŒธ. For example, the loop:
for (int i = 0; i < N; i++)
  for (int j = 0; j < N; j++)
    for (int k = 0; k < N; k++)
      c[i][j] = c[i][j] + a[i][k]*b[k][j];

is transformed to:

for (int i = 0; i < N; i++)
  for (int k = 0; k < N; k++)
    for (int j = 0; j < N; j++)
      c[i][j] = c[i][j] + a[i][k]*b[k][j];

Enabled by default at -O3. It's also enabled by -fprofile-use and -fauto-profile ๐Ÿฆ‹.

  • -floop-unroll-and-jam: applies unroll and jam transformations on feasible loops ๐Ÿซง. In a loop nest, this unrolls the outer loop by some factor and fuses the resulting multiple inner loops ๐Ÿงถ. Enabled by default at -O3, and also by -fprofile-use and -fauto-profile ๐Ÿ‘‘.
  • -ftree-loop-im: loop invariant motion on trees ๐Ÿšš. This pass only moves the invariants that are hard to handle at the RTL level, like function calls or operations that expand into nontrivial sequences of insns ๐Ÿง . With -funswitch-loops, it also moves operands of conditions that are invariant out of the loop, so loop unswitching can get away with just trivial invariantness analysis ๐Ÿช„. The pass also includes store motion ๐Ÿ’พ.
  • -ftree-loop-ivcanon: creates a canonical counter for the number of iterations in loops where figuring out that number takes complicated analysis ๐Ÿ”ข. Later optimizations can then figure out the number easily ๐Ÿ˜Œ. It's especially useful alongside unrolling ๐ŸŒˆ.
  • -ftree-scev-cprop: performs final value replacement ๐ŸŽฏ. If a variable changes inside a loop in such a way that its value on exit can be worked out from only its initial value and the number of loop iterations, uses of the final value get replaced with that computation, as long as it's sufficiently cheap ๐Ÿ’ธ. This reduces data dependencies and may allow further simplifications โœจ. Enabled by default at -O and higher.
  • -fivopts: performs induction variable optimizations (strength reduction, induction variable merging and induction variable elimination) on trees ๐Ÿ”.
  • -ftree-parallelize-loops=n: parallelizes loops, which means splitting their iteration space to run in n threads ๐Ÿงต. This is only possible for loops whose iterations are independent and can be arbitrarily reordered ๐Ÿซถ. The optimization is only profitable on multiprocessor machines, and only for CPU-intensive loops rather than loops constrained by things like memory bandwidth ๐Ÿ–ฅ๏ธ. This option implies -pthread, so it's only supported on targets that have support for -pthread ๐Ÿ’….
  • -ftree-pta: performs function-local points-to analysis on trees ๐Ÿ•ต๏ธโ€โ™€๏ธ. Enabled by default at -O1 and higher, except for -Og ๐Ÿ’–.
  • -ftree-sra: performs scalar replacement of aggregates ๐Ÿงƒ. This pass swaps structure references for scalars so structures don't get committed to memory too early ๐Ÿง . Enabled by default at -O1 and higher, except for -Og โœจ.
  • -fstore-merging: merges narrow stores to consecutive memory addresses ๐Ÿ“ฆ. This pass combines contiguous stores of immediate values that are narrower than a word into fewer, wider stores, which cuts down on the number of instructions ๐Ÿ“. Enabled by default at -O2 and higher, as well as -Os ๐ŸŒธ.
  • -ftree-ter: performs temporary expression replacement during the SSA->normal phase ๐Ÿ”„. Single use/single def temporaries get replaced at their use location with their defining expression ๐Ÿงฉ. This results in non-GIMPLE code, but it gives the expanders much more complex trees to work on, which leads to better RTL generation ๐Ÿ’ซ. Enabled by default at -O and higher.
  • -ftree-slsr: performs straight-line strength reduction on trees ๐Ÿ“. It spots related expressions involving multiplications and swaps them for cheaper calculations when possible ๐Ÿ’ธ. Enabled by default at -O and higher ๐Ÿฆ‹.
  • -ftree-vectorize: performs vectorization on trees ๐Ÿš€. This flag enables -ftree-loop-vectorize and -ftree-slp-vectorize if they aren't explicitly specified ๐Ÿซถ.
  • -ftree-loop-vectorize: performs loop vectorization on trees ๐ŸŽ€. Enabled by default at -O3, and by -ftree-vectorize, -fprofile-use, and -fauto-profile ๐Ÿ‘‘.
  • -ftree-slp-vectorize: performs basic block vectorization on trees ๐Ÿง. Enabled by default at -O3, and by -ftree-vectorize, -fprofile-use, and -fauto-profile โœจ.

  • -fvect-cost-model=model: changes the cost model used for vectorization ๐Ÿ’ฐ. The model argument should be one of unlimited, dynamic or cheap. With the unlimited model, the vectorized code path is assumed to be profitable ๐Ÿค‘. With the dynamic model, a runtime check guards the vectorized code path so it only runs for iteration counts that will likely execute faster than the original scalar loop ๐Ÿƒโ€โ™€๏ธ. The cheap model turns off vectorization of loops where it would be cost prohibitive, for example because of required runtime checks for data dependence or alignment, but otherwise it's the same as the dynamic model ๐Ÿ™…โ€โ™€๏ธ. The default cost model depends on other optimization flags and is either dynamic or cheap ๐ŸŒˆ.
  • -fsimd-cost-model=model: changes the cost model used for vectorization of loops marked with the OpenMP simd directive ๐ŸŽถ. All values of model have the same meaning as described in -fvect-cost-model, and by default, a cost model defined with -fvect-cost-model is used ๐Ÿ’œ. The model argument should be one of unlimited, dynamic, cheap โœจ.
  • -ftree-vrp โ€” okay so this one runs Value Range Propagation on trees ๐ŸŒณ It's basically the cousin of constant propagation, except instead of tracking single values it tracks whole ranges of values โœจ That lets the optimizers ditch unnecessary range checks like array bound checks and null pointer checks ๐Ÿ’… It's on by default at -O2 and higher. Heads up though: null pointer check elimination only happens if -fdelete-null-pointer-checks is enabled ๐Ÿ™ˆ
  • -fsplit-paths โ€” splits paths that lead to loop backedges ๐Ÿ›ค๏ธ This can glow up dead code elimination and common subexpression elimination ๐Ÿ”ฅ It's enabled by default at -O3 and above.
  • -fsplit-ivs-in-unroller โ€” this lets the unroller express the values of induction variables in later iterations of the unrolled loop by using the value from the first iteration ๐Ÿฆ‹ It breaks up long dependency chains, which makes the scheduling passes way more efficient ๐Ÿซถ

A combo of -fweb and CSE is often enough to get the same effect ๐Ÿ’– But that's not reliable when the loop body is more complicated than a single basic block ๐Ÿ˜ญ It also doesn't work at all on some architectures because of restrictions in the CSE pass ๐Ÿ’€

This optimization is enabled by default โœจ

  • -fvariable-expansion-in-unroller โ€” when unrolling a loop, the compiler creates multiple copies of some local variables ๐ŸŽ€ which can result in superior code ๐Ÿ‘‘
  • -fpartial-inlining โ€” inlines parts of functions ๐Ÿงฉ This only has an effect when inlining itself is turned on by -finline-functions or -finline-small-functions ๐ŸŒธ

Enabled at levels -O2, -O3, -Os.

  • -fpredictive-commoning โ€” performs predictive commoning, aka reusing computations (especially memory loads and stores) from previous loop iterations ๐Ÿ”

This option is enabled at level -O3. It's also enabled by -fprofile-use and -fauto-profile ๐Ÿ’œ

  • -fprefetch-loop-arrays โ€” if the target machine supports it, this generates instructions to prefetch memory so loops that access large arrays run better ๐Ÿƒโ€โ™€๏ธ

This option may generate better or worse code ๐ŸŽฒ The results are highly dependent on the structure of the loops in your source code.

Disabled at level -Os.

  • -fno-printf-return-value โ€” do not substitute constants for the known return value of formatted output functions like "sprintf", "snprintf", "vsprintf", and "vsnprintf" (but not "printf" or "fprintf") ๐Ÿ™… This transformation lets GCC optimize or even eliminate branches based on the known return value of these functions, as long as the arguments are either constant or known to be in a range that makes the exact return value possible to figure out ๐Ÿง  For example, when -fprintf-return-value is in effect, both the branch and the body of the if statement (but not the call to snprint) can be optimized away when i is a 32-bit or smaller integer, because the return value is guaranteed to be at most 8 ๐Ÿ“
char buf[9];
if (snprintf (buf, "%08x", i) >= sizeof buf)
  ...

The -fprintf-return-value option relies on other optimizations and yields the best results with -O2 and above โœจ It works in tandem with the -Wformat-overflow and -Wformat-truncation options. The -fprintf-return-value option is enabled by default.

  • -fno-peephole, -fno-peephole2 โ€” disables any machine-specific peephole optimizations ๐Ÿงผ The difference between them is in how they're implemented in the compiler: some targets use one, some use the other, and a few use both ๐Ÿคท

-fpeephole is enabled by default. -fpeephole2 is enabled at levels -O2, -O3, -Os.

  • -fno-guess-branch-probability โ€” do not guess branch probabilities using heuristics ๐Ÿšซ๐ŸŽฒ

GCC uses heuristics to guess branch probabilities when they aren't provided by profiling feedback (-fprofile-arcs) ๐Ÿ“Š These heuristics are based on the control flow graph. If some branch probabilities are specified by "__builtin_expect", the heuristics guess the rest of the control flow graph while taking that "__builtin_expect" info into account. The interactions between the heuristics and "__builtin_expect" can get pretty complex, so sometimes it's useful to turn the heuristics off so the effects of "__builtin_expect" are easier to understand ๐Ÿง

You can also specify the expected probability of an expression with the "__builtin_expect_with_probability" built-in function ๐Ÿ’…

The default is -fguess-branch-probability at levels -O, -O2, -O3, -Os.

  • -freorder-blocks โ€” reorders basic blocks in the compiled function to reduce the number of taken branches and improve code locality ๐Ÿ“ฆ

Enabled at levels -O, -O2, -O3, -Os.

  • -freorder-blocks-algorithm=algorithm โ€” picks the algorithm used for basic block reordering ๐Ÿงญ The algorithm argument can be simple, which doesn't increase code size (except sometimes due to secondary effects like alignment), or stc, the "software trace cache" algorithm, which puts all the often-executed code together and minimizes the number of branches executed by making extra copies of code ๐Ÿง

The default is simple at levels -O, -Os, and stc at levels -O2, -O3.

  • -freorder-blocks-and-partition โ€” in addition to reordering basic blocks to reduce taken branches, this partitions hot and cold basic blocks into separate sections of the assembly and .o files, for better paging and cache locality performance ๐Ÿ”ฅ

This optimization is automatically turned off in the presence of exception handling or unwind tables (on targets using setjump/longjump or a target-specific scheme), for linkonce sections, for functions with a user-defined section attribute, and on any architecture that doesn't support named sections. When -fsplit-stack is used, this option is not enabled by default (to avoid linker errors), but it can be enabled explicitly (if you're using a working linker) ๐Ÿ˜ค

Enabled for x86 at levels -O2, -O3, -Os.

  • -freorder-functions โ€” reorders functions in the object file to improve code locality ๐Ÿ—บ๏ธ This is done using the special subsections ".text.hot" for most frequently executed functions and ".text.unlikely" for unlikely executed functions. The linker does the reordering, so the object file format has to support named sections and the linker has to place them in a reasonable way ๐Ÿ”—

This option isn't effective unless you either provide profile feedback (see -fprofile-arcs for details) or manually annotate functions with "hot" or "cold" attributes ๐Ÿ’ญ

Enabled at levels -O2, -O3, -Os.

  • -fstrict-aliasing โ€” allows the compiler to assume the strictest aliasing rules that apply to the language being compiled ๐Ÿงท For C (and C++), this activates optimizations based on the type of expressions. In particular, an object of one type is assumed never to reside at the same address as an object of a different type, unless the types are almost the same. For example, an "unsigned int" can alias an "int", but not a "void*" or a "double". A character type may alias any other type.

Pay special attention to code like this ๐Ÿ‘€

union a_union {
  int i;
  double d;
};

int f() {
  union a_union t;
  t.d = 3.0;
  return t.i;
}

Reading from a different union member than the one most recently written to (called "type-punning") is super common ๐Ÿฅด Even with -fstrict-aliasing, type-punning is allowed, provided the memory is accessed through the union type. So, the code above works as expected. However, this code might not:

int f() {
  union a_union t;
  int* ip;
  t.d = 3.0;
  ip = &t.i;
  return *ip;
}

Similarly, accessing by taking the address, casting the resulting pointer, and dereferencing the result has undefined behavior, even if the cast uses a union type, e.g.:

int f() {
  double d = 3.0;
  return ((union a_union *) &d)->i;
}
Bestie, that last one is undefined behavior ๐Ÿ’€ Even with a union type in the cast, it's not safe, so don't write it ๐Ÿ™…

The -fstrict-aliasing option is enabled at levels -O2, -O3, -Os.

  • -falign-functions, -falign-functions=n, -falign-functions=n:m, -falign-functions=n:m:n2, -falign-functions=n:m:n2:m2 โ€” aligns the start of functions to the next power-of-two greater than n, skipping up to m-1 bytes โœจ This makes sure at least the first m bytes of the function can be fetched by the CPU without crossing an n-byte alignment boundary ๐Ÿน

If m is not specified, it defaults to n.

Examples, because you know I love a good example ๐ŸŽ€

  • -falign-functions=32 aligns functions to the next 32-byte boundary
  • -falign-functions=24 aligns to the next 32-byte boundary only if this can be done by skipping 23 bytes or less
  • -falign-functions=32:7 aligns to the next 32-byte boundary only if this can be done by skipping 6 bytes or less

The second pair of n2:m2 values lets you set a secondary alignment ๐Ÿ’– For example, -falign-functions=64:7:32:3 aligns to the next 64-byte boundary if this can be done by skipping 6 bytes or less, otherwise it aligns to the next 32-byte boundary if this can be done by skipping 2 bytes or less. If m2 is not specified, it defaults to n2.

Some assemblers only support this flag when n is a power of two; in that case, it gets rounded up.

-fno-align-functions and -falign-functions=1 are equivalent and mean that functions are not aligned.

If n is not specified or is zero, a machine-dependent default is used. The maximum allowed n value is 65536.

Enabled at levels -O2, -O3.

  • -flimit-function-alignment โ€” if this is enabled, the compiler tries to avoid overaligning functions when it doesn't need to ๐Ÿ™… It attempts to tell the assembler to align by the amount specified by -falign-functions, but not to skip more bytes than the size of the function ๐Ÿ“
  • -falign-labels, -falign-labels=n, -falign-labels=n:m, -falign-labels=n:m:n2, -falign-labels=n:m:n2:m2 โ€” aligns all branch targets to a power-of-two boundary ๐ŸŽฏ

The parameters of this option work the same way as they do for -falign-functions. -fno-align-labels and -falign-labels=1 are equivalent and mean that labels are not aligned.

So if -falign-loops or -falign-jumps apply and their values are bigger than this one, their values win instead ๐Ÿ’…โœจ

If n isn't specified or is zero, GCC uses a machine-dependent default that's very likely to be 1, which means no alignment at all ๐Ÿ™ˆ. The biggest n you can pass is 65536 ๐Ÿ’–

Enabled at levels -O2, -O3 ๐ŸŽ€

  • -falign-loops, -falign-loops=n, -falign-loops=n:m, -falign-loops=n:m:n2, -falign-loops=n:m:n2:m2 โ€” bestie, this one lines your loops up on a power-of-two boundary ๐Ÿฆ‹ If the loops run a bajillion times, the padding ends up being worth it, because it makes up for the time spent running those dummy padding instructions ๐Ÿ˜ญ
    • The parameters work the same way as they do for -falign-functions. -fno-align-loops and -falign-loops=1 are equivalent, and both mean the loops are not aligned ๐Ÿซถ The max n is 65536.
    • If n isn't specified or is zero, you get a machine-dependent default.
    • Enabled at levels -O2, -O3 ๐ŸŒธ
  • -falign-jumps, -falign-jumps=n, -falign-jumps=n:m, -falign-jumps=n:m:n2, -falign-jumps=n:m:n2:m2 โ€” this one aligns branch targets to a power-of-two boundary ๐Ÿงš It's for targets that can only be reached by jumping, so no dummy operations need to run at all, which is iconic โœจ
    • The parameters are analogous to -falign-functions. -fno-align-jumps and -falign-jumps=1 are equivalent and mean that loops are not aligned ๐Ÿ™ƒ
    • If n isn't specified or is zero, you get a machine-dependent default. The max n is 65536.
    • Enabled at levels -O2, -O3 ๐Ÿ’œ
  • -funit-at-a-time โ€” this one's only hanging around for compatibility reasons ๐Ÿ’€ It has no effect on its own, but -fno-unit-at-a-time implies -fno-toplevel-reorder and -fno-section-anchors.
    • Enabled by default ๐ŸŒˆ
  • -fno-toplevel-reorder โ€” tells GCC to leave top-level functions, variables, and "asm" statements alone, outputting them in the exact same order they appear in your input file ๐Ÿ“œ With this on, unreferenced static variables are not removed. It's basically there for existing code that depends on a specific ordering. For new code, attributes are the better move when possible ๐Ÿ’…
    • -ftoplevel-reorder is the default at -O1 and higher, and also at -O0 if -fsection-anchors is explicitly requested.
    • -fno-toplevel-reorder implies -fno-section-anchors too ๐Ÿ”—
  • -fweb โ€” this builds webs, which are commonly used for register allocation, and gives each web its own pseudo register ๐Ÿง  The register allocation pass can now work on pseudos directly, and it also strengthens a bunch of other passes like CSE, the loop optimizer, and the trivial dead code remover. The catch? It can make debugging impossible, since variables no longer stay in a "home register" ๐Ÿ˜ฉ
    • Enabled by default with -funroll-loops ๐ŸŽ€
  • -fwhole-program โ€” this tells the compiler to treat the current compilation unit as the whole program being compiled ๐Ÿ‘‘ All public functions and variables, except main and anything merged by the attribute "externally_visible", become static functions. That means the interprocedural optimizers can go wild on them.
    • > Don't use this together with -flto. Relying on a linker plugin gives safer and more precise information, so that's the better vibe ๐Ÿซถ

โœจ -flto[=n] โœจ

This option runs the standard link-time optimizer, and it's literally the main character of this whole section ๐Ÿ”ฅ When you invoke it with source code, it generates GIMPLE (one of GCC's internal representations) and writes it into special ELF sections in the object file. When the object files get linked together, all the function bodies are read back out of those ELF sections and instantiated as if they were part of the same translation unit ๐Ÿงš

To use the link-time optimizer, -flto and your optimization options should be specified at compile time and during the final link. It's recommended that you compile all the files in the same link with the same options, and also specify those options at link time. For example:

gcc -c -O2 -flto foo.c
gcc -c -O2 -flto bar.c
gcc -o myprog -flto -O2 foo.o bar.o

The first two invocations save a bytecode representation of GIMPLE into special ELF sections inside foo.o and bar.o. The final invocation reads the GIMPLE bytecode from foo.o and bar.o, merges the two files into a single internal image, and compiles the result as usual ๐Ÿ’– Since both files get merged into one image, all the interprocedural analyses and optimizations work across the two files as if they were a single one. So, for example, the inliner can inline functions in bar.o into functions in foo.o and vice-versa. Iconic behaviour ๐Ÿ˜ญ

Another (simpler) way to turn on link-time optimization is:

gcc -o myprog -flto -O2 foo.c bar.c

That generates bytecode for foo.c and bar.c, merges them together into a single GIMPLE representation, and optimizes them as usual to produce myprog ๐ŸŒธ

The important thing to keep in mind is that, to enable link-time optimizations, you need to use the GCC driver to do the link step ๐Ÿšจ GCC automatically performs link-time optimization if any of the objects involved were compiled with the -flto command-line option. You can always override that automatic decision by passing -fno-lto to the link command ๐Ÿ™…โ€โ™€๏ธ

To make whole program optimization effective, you have to make certain whole program assumptions. The compiler needs to know what functions and variables can be accessed by libraries and runtime outside of the link-time optimized unit. When the linker supports it, the linker plugin (see -fuse-linker-plugin) passes that info to the compiler about used and externally visible symbols. When the linker plugin isn't available, use -fwhole-program so the compiler can make those assumptions, which leads to more aggressive optimization decisions โญ

When a file is compiled with -flto and without -fuse-linker-plugin, the generated object file is larger than a regular one, because it contains GIMPLE bytecodes and the usual final code (see -ffat-lto-objects). This means object files with LTO information can still be linked as normal object files. But if -fno-lto is passed to the linker, no interprocedural optimizations get applied ๐Ÿ˜ฌ Also, if you use -fno-fat-lto-objects, the compile stage is faster, but you can't perform a regular, non-LTO link on them.

When producing the final binary, GCC only applies link-time optimizations to the files that contain bytecode. That means you can mix and match object files and libraries with GIMPLE bytecodes and final object code ๐Ÿงฉ GCC automatically picks which files get optimized in LTO mode and which ones get linked without any further processing.

Generally, options specified at link time override the ones specified at compile time, although sometimes GCC tries to infer link-time options from the settings used to compile the input files ๐Ÿ”ฎ

If you don't specify an optimization level option -O at link time, GCC uses the highest optimization level that was used when compiling the object files. Also, it's generally ineffective to specify an optimization level only at link time and not at compile time, for two reasons ๐Ÿ™ˆ First, compiling without optimization suppresses the compiler passes that gather information needed for effective optimization at link time. Second, some early optimization passes can only be performed at compile time, not at link time.

There are some code generation flags that GCC preserves when generating bytecodes, since they need to be used during the final link. Right now, the following options and their settings are taken from the first object file that explicitly specifies them: -fPIC, -fpic, -fpie, -fcommon, -fexceptions, -fnon-call-exceptions, -fgnu-tm and all the -m target flags ๐ŸŽ€

Certain ABI-changing flags have to match across all compilation units. Trying to override them at link time with a conflicting value gets ignored ๐Ÿšซ This includes options like -freg-struct-return and -fpcc-struct-return.

Other options, such as -ffp-contract, -fno-strict-overflow, -fwrapv, -fno-trapv or -fno-strict-aliasing, are passed through to the link stage and merged conservatively for conflicting translation units. Specifically, -fno-strict-overflow, -fwrapv and -fno-trapv take precedence, and for example -ffp-contract=off takes precedence over -ffp-contract=fast. You can override them at link time ๐Ÿ’…

When you need to pass options to the assembler via -Wa or -Xassembler, make sure to either compile those translation units with -fno-lto, or consistently use the same assembler options on all translation units.

You can alternatively also specify assembler options at LTO link time, which is a nice escape hatch ๐Ÿซฃ

To enable debug info generation, you need to supply -g at compile time. If any of the input files at link time were built with debug info generation enabled, the link will enable debug info generation as well ๐Ÿž Any elaborate debug info settings, like the dwarf level -gdwarf-5, need to be explicitly repeated on the linker command line, and mixing different settings across translation units is discouraged ๐Ÿ™…โ€โ™€๏ธ

If LTO runs into objects with C linkage declared with incompatible types in separate translation units that get linked together (which is undefined behavior according to ISO C99 6.2.7), a non-fatal diagnostic may be issued. The behavior is still undefined at run time ๐Ÿ’€ Similar diagnostics may be raised for other languages too.

Another feature of LTO is that you can apply interprocedural optimizations to files written in different languages ๐ŸŒˆ

gcc -c -flto foo.c
g++ -c -flto bar.cc
gfortran -c -flto baz.f90
g++ -o myprog -flto -O3 foo.o bar.o baz.o -lgfortran

Notice that the final link is done with g++ to get the C++ runtime libraries, and -lgfortran is added to get the Fortran runtime libraries ๐Ÿงšโ€โ™€๏ธ In general, when mixing languages in LTO mode, you should use the same link command options as you would when mixing languages in a regular (non-LTO) compilation ๐Ÿ’–

Okay bestie, so say you've got GIMPLE bytecode object files stuck inside a library archive, like libfoo.a ๐Ÿ“ฆโœจ. You can totally pull them out for an LTO link, but only if your linker has plugin support ๐Ÿ”Œ. To make static libraries that vibe with LTO, use gcc-ar and gcc-ranlib instead of ar and ranlib ๐ŸŽ€. To peek at the symbols in object files that hold GIMPLE bytecode, use gcc-nm ๐Ÿ‘€. Heads up, those commands need ar, ranlib and nm to have been compiled with plugin support, no cap. At link time, add -fuse-linker-plugin so the library actually joins the LTO optimization party ๐Ÿฅณ:

gcc -o myprog -O2 -flto -fuse-linker-plugin a.o b.o -lfoo

With the plugin on, the linker pulls the needed GIMPLE files out of libfoo.a and hands them to the running GCC, so they become part of the big aggregated GIMPLE image that gets optimized ๐Ÿ’….

If you aren't using a linker with plugin support, and/or you don't turn the linker plugin on, the objects inside libfoo.a still get extracted and linked as usual, but they sit out the LTO optimization process ๐Ÿ˜ญ. If you want a static library that works for both LTO and normal linking, compile its object files with -flto -ffat-lto-objects ๐Ÿซถ.

Link-time optimizations don't need the whole program to be present to work โœจ. If the program doesn't need any symbols exported, you can combine -flto and -fwhole-program so the interprocedural optimizers can make more aggressive assumptions, which may lead to better optimization opportunities ๐Ÿš€. You don't need -fwhole-program when the linker plugin is active (see -fuse-linker-plugin).

The current LTO implementation makes no attempt to generate bytecode that is portable between different types of hosts ๐Ÿ’€. The bytecode files are versioned and there's a strict version check, so bytecode files generated by one version of GCC won't work with an older or newer version of GCC.
Link-time optimization doesn't work well with generating debugging information on systems other than those using a combination of ELF and DWARF ๐Ÿ™ˆ.

If you specify the optional n, the optimization and code generation done at link time runs in parallel using n parallel jobs, by utilizing an installed make program ๐Ÿƒโ€โ™€๏ธ. The environment variable MAKE can be used to override which program gets used.

You can also use -flto=jobserver to let GNU make's job server mode decide the number of parallel jobs ๐Ÿงš. This is super useful when the Makefile calling GCC is already running in parallel. You must prepend a + to the command recipe in the parent Makefile for this to work. This option likely only works if MAKE is GNU make.

Use -flto=auto to use GNU make's job server if it's available, or otherwise fall back to autodetecting the number of CPU threads on your system ๐Ÿง .

  • -flto-partition=alg โ€” picks the partitioning algorithm the link-time optimizer uses ๐Ÿฐ. The value is either 1to1, which partitions to mirror your original source files; balanced, which splits things into equally sized chunks (whenever possible); or max, which creates a new partition for every symbol where possible. Specifying none as the algorithm disables partitioning and streaming completely. The default is balanced. While 1to1 can be used as a workaround for various code ordering issues, max partitioning is intended for internal testing only โš ๏ธ. The value one means exactly one partition gets used, while none skips partitioning and runs the link-time optimization step directly from the WPA phase.
  • -flto-odr-type-merging โ€” turns on streaming of mangled type names of C++ types, plus their unification at link time ๐Ÿงฌ. It makes LTO object files bigger, but in return you get diagnostics about One Definition Rule violations ๐Ÿ”.
  • -flto-compression-level=n โ€” sets how hard the intermediate language written to LTO object files gets compressed ๐Ÿ—œ๏ธ. Valid values are 0 (no compression) through 9 (maximum compression). Values outside that range get clamped to either 0 or 9. If you don't give this option, a default balanced compression setting is used. It's only meaningful alongside LTO mode (-flto) ๐Ÿ’œ.
  • -fuse-linker-plugin โ€” enables the use of a linker plugin during link-time optimization ๐Ÿ”Œ. This relies on plugin support in the linker, which is available in gold or in GNU ld 2.21 or newer.

This option lets GCC extract object files with GIMPLE bytecode out of library archives ๐Ÿ“ค. That improves optimization quality by exposing more code to the link-time optimizer ๐Ÿ“ˆ. It also carries info about which symbols can be accessed externally (by a non-LTO object or during dynamic linking). The code quality improvements on binaries (and on shared libraries that use hidden visibility) are similar to -fwhole-program. See -flto for a description of what this flag does and how to use it.

This option is enabled by default when LTO support in GCC is enabled and GCC was configured for use with a linker that supports plugins (GNU ld 2.21 or newer, or gold) ๐Ÿฅฐ.

  • -ffat-lto-objects โ€” fat LTO objects are object files that contain both the intermediate language and the object code ๐Ÿฑ. That makes them usable for both LTO linking and normal linking. This option is only effective when compiling with -flto, and it's ignored at link time.

-fno-fat-lto-objects speeds up compilation compared to plain LTO ๐ŸŽ๏ธ, but it requires the complete toolchain to be aware of LTO. It needs a linker with linker plugin support for basic functionality. On top of that, nm, ar and ranlib need to support linker plugins to allow a full-featured build environment (one that can build static libraries and so on). GCC provides the gcc-ar, gcc-nm and gcc-ranlib wrappers to pass the right options to these tools. With non-fat LTO, makefiles need to be modified to use them ๐Ÿ› ๏ธ.

Note that modern binutils provide a plugin auto-load mechanism ๐Ÿช„. Installing the linker plugin into $libdir/bfd-plugins has the same effect as using the command wrappers (gcc-ar, gcc-nm and gcc-ranlib).

The default is -fno-fat-lto-objects on targets with linker plugin support ๐Ÿ’–.

  • -fcompare-elim โ€” after register allocation and post-register allocation instruction splitting, this identifies arithmetic instructions that compute processor flags similar to a comparison operation based on that arithmetic ๐Ÿงฎ. If possible, it eliminates the explicit comparison operation.

This pass only applies to certain targets that can't explicitly represent the comparison operation before register allocation is complete. Enabled at levels -O, -O2, -O3, -Os.

  • -fcprop-registers โ€” after register allocation and post-register allocation instruction splitting, this runs a copy-propagation pass to try to reduce scheduling dependencies and occasionally eliminate the copy ๐Ÿชž. Enabled at levels -O, -O2, -O3, -Os.
  • -fprofile-correction โ€” profiles collected using an instrumented binary for multi-threaded programs can be inconsistent because of missed counter updates ๐Ÿ˜ตโ€๐Ÿ’ซ. When you specify this option, GCC uses heuristics to correct or smooth out those inconsistencies. By default, GCC emits an error message when an inconsistent profile is detected. This option is enabled by -fauto-profile.
  • -fprofile-use, -fprofile-use=path โ€” enables profile feedback-directed optimizations, plus the following optimizations, many of which are generally only profitable when profile feedback is available ๐Ÿ”ฅ:
-fbranch-probabilities  -fprofile-values -funroll-loops
-fpeel-loops  -ftracer  -fvpt -finline-functions  -fipa-cp
-fipa-cp-clone  -fipa-bit-cp -fpredictive-commoning  -fsplit-loops
-funswitch-loops -fgcse-after-reload  -ftree-loop-vectorize
-ftree-slp-vectorize -fvect-cost-model=dynamic
-ftree-loop-distribute-patterns -fprofile-reorder-functions

Before you can use this option, you must first generate profiling information ๐Ÿ“Š.

By default, GCC emits an error message if the feedback profiles don't match the source code ๐Ÿšจ. You can turn that error into a warning by using -Wno-error=coverage-mismatch. Just know this may result in poorly optimized code. Also, by default, GCC emits a warning message if the feedback profiles don't exist (see -Wmissing-profile).

If path is specified, GCC looks at that path to find the profile feedback data files. See -fprofile-dir.

  • -fauto-profile, -fauto-profile=path โ€” enables sampling-based feedback-directed optimizations ๐ŸŽฏ, plus the following optimizations, many of which are generally only profitable with profile feedback available:
-fbranch-probabilities  -fprofile-values -funroll-loops
-fpeel-loops  -ftracer  -fvpt -finline-functions  -fipa-cp
-fipa-cp-clone  -fipa-bit-cp -fpredictive-commoning  -fsplit-loops
-funswitch-loops -fgcse-after-reload  -ftree-loop-vectorize
-ftree-slp-vectorize -fvect-cost-model=dynamic
-ftree-loop-distribute-patterns -fprofile-correction

path is the name of a file containing AutoFDO profile information. If you leave it out, it defaults to fbdata.afdo in the current directory ๐Ÿ“.

Producing an AutoFDO profile data file requires running your program with the perf utility on a supported GNU/Linux target system ๐Ÿง. For more information, see https://perf.wiki.kernel.org/.

E.g.

perf record -e br_inst_retired:near_taken -b -o perf.data \
    -- your_program

Then use the create_gcov tool to convert the raw profile data into a format GCC can use ๐Ÿ”„. You must also supply the unstripped binary for your program to this tool. See https://github.com/google/autofdo.

E.g.

create_gcov --binary=your_program.unstripped --profile=perf.data \
    --gcov=profile.afdo

The following options control compiler behavior regarding floating-point arithmetic ๐Ÿง. These options trade off between speed and correctness, so all of them must be specifically enabled โš–๏ธ.

  • -ffloat-store โ€” do not store floating-point variables in registers, and inhibit other options that might change whether a floating-point value is taken from a register or from memory ๐Ÿ™…โ€โ™€๏ธ.

Okay so the first thing to know about -ffloat-store ๐Ÿ’– is that it's all about stopping the excess precision drama on machines like the 68000, where the floating registers (of the 68881) keep more precision than a "double" is supposed to have. x86 has the same little problem too ๐Ÿ™ˆ For most programs the extra precision is only a good thing, but a few programs rely on the exact IEEE floating point definition. For those besties, use -ffloat-store after you've updated them to store all the pertinent intermediate computations into variables ๐Ÿซถ

๐ŸŒธ -fexcess-precision=style

Okay, this one gives you more control over excess precision on machines where floating-point operations happen in a format with more precision or range than the IEEE standard and interchange floating-point types. By default you get -fexcess-precision=fast, which means operations may run in a wider precision than the types in your source if that makes the code faster ๐Ÿ”ฅ It's unpredictable when the rounding to your source types actually happens, so it's giving chaos.

When you're compiling C and use -fexcess-precision=standard, the excess precision follows the rules in ISO C99. Casts and assignments both make values round to their semantic types, whereas -ffloat-store only affects assignments. This option is turned on by default for C if you use a strict conformance option like -std=c99 โœจ Also, -ffast-math turns on -fexcess-precision=fast by default no matter whether you're using a strict conformance option or not.

๐Ÿ’€ -fexcess-precision=standard is not implemented for languages other than C. On x86, it does nothing if you specify -mfpmath=sse or -mfpmath=sse+387. With -mfpmath=sse, IEEE semantics apply without excess precision. With -mfpmath=sse+387, the rounding is unpredictable.

๐Ÿฆ‹ -ffast-math

This one is a whole vibe ๐ŸŽ๏ธ It sets -fno-math-errno, -funsafe-math-optimizations, -ffinite-math-only, -fno-rounding-math, -fno-signaling-nans, -fcx-limited-range and -fexcess-precision=fast all at once. It also makes the preprocessor macro __FAST_MATH__ get defined ๐Ÿงš

Not every -O option turns this on. Only -Ofast does, because it can give you incorrect output for programs that depend on an exact implementation of IEEE or ISO rules and specifications for math functions. BUT it may yield faster code for programs that don't need the guarantees of those specifications, so it's a choice ๐Ÿ’…

๐ŸŽ€ -fno-math-errno

Do not set errno after calling math functions that run with a single instruction, for example sqrt. A program that relies on IEEE exceptions for math error handling might want this flag for the speed boost while still keeping IEEE arithmetic compatibility ๐ŸŒˆ

This is not turned on by any -O option, because it can give incorrect output for programs that depend on an exact implementation of IEEE or ISO rules and specifications for math functions. It may, however, be faster for programs that don't need those guarantees ๐Ÿ“

The default is -fmath-errno.

On Darwin systems, the math library never sets errno. So there's no reason for the compiler to consider that it might, and -fno-math-errno is the default there ๐ŸŽ

๐ŸŒท -funsafe-math-optimizations

This one lets the compiler use optimizations for floating-point arithmetic that (a) assume arguments and results are valid and (b) may break IEEE or ANSI standards. When it's used at link time, it may pull in libraries or startup files that change the default FPU control word or do other similar optimizations ๐Ÿ˜ญ

Also not turned on by any -O option, for the same reason: it can give incorrect output for programs that depend on an exact implementation of IEEE or ISO rules and specifications for math functions. It may still yield faster code for programs that don't need those guarantees. This enables -fno-signed-zeros, -fno-trapping-math, -fassociative-math and -freciprocal-math ๐Ÿ‘‘

The default is -fno-unsafe-math-optimizations.

๐Ÿ’œ -fassociative-math

This lets you re-associate operands in series of floating-point operations. It violates the ISO C and C++ language standard because it might change the computation result ๐Ÿ™ˆ Heads up, the re-ordering can change the sign of zero, ignore NaNs, and inhibit or create underflow or overflow. That means you can't use it on code that depends on rounding behavior like (x + 2**52) - 2**52.

It can also reorder floating-point comparisons, so don't use it when ordered comparisons are required. This option needs both -fno-signed-zeros and -fno-trapping-math to be in effect. Also, it doesn't make much sense with -frounding-math. For Fortran, the option gets turned on automatically when both -fno-signed-zeros and -fno-trapping-math are in effect โœจ

The default is -fno-associative-math.

๐Ÿงš -freciprocal-math

Allows the reciprocal of a value to be used instead of dividing by the value, if that makes things more optimized. For example, x / y can be replaced with x * (1/y), which is handy if (1/y) is subject to common subexpression elimination. Just know that this loses precision and increases the number of flops operating on the value ๐Ÿ“

The default is -fno-reciprocal-math.

๐Ÿซง -ffinite-math-only

This allows optimizations for floating-point arithmetic that assume arguments and results are not NaNs or +-Infs ๐ŸŒธ

Not turned on by any -O option, since it can give incorrect output for programs that depend on an exact implementation of IEEE or ISO rules and specifications for math functions. It may still yield faster code for programs that don't need those guarantees.

The default is -fno-finite-math-only.

๐ŸŒ™ -fno-signed-zeros

This allows optimizations for floating-point arithmetic that ignore the signedness of zero. IEEE arithmetic says distinct +0.0 and -0.0 values behave in specific ways, which stops you from simplifying expressions like x+0.0 or 0.0*x, even with -ffinite-math-only. This option means the sign of a zero result isn't significant ๐Ÿฆ‹

The default is -fsigned-zeros.

๐Ÿšซ -fno-trapping-math

This tells the compiler to assume floating-point operations cannot generate user-visible traps. Those traps include division by zero, overflow, underflow, inexact result and invalid operation ๐Ÿ˜ณ It requires -fno-signaling-nans to be in effect. Turning this on may give faster code if you rely on "non-stop" IEEE arithmetic, for example.

โš ๏ธ This option should never be turned on by any -O option, since it can give incorrect output for programs that depend on an exact implementation of IEEE or ISO rules and specifications for math functions.

The default is -ftrapping-math.

๐ŸŽˆ -frounding-math

This disables transformations and optimizations that assume the default floating-point rounding behavior. That's round-to-zero for all floating point to integer conversions, and round-to-nearest for all other arithmetic truncations. You should specify this for programs that change the FP rounding mode dynamically, or that might be executed with a non-default rounding mode ๐ŸŒˆ

It also disables constant folding of floating-point expressions at compile time (which can be affected by rounding mode), plus arithmetic transformations that are unsafe when sign-dependent rounding modes are involved.

The default is -fno-rounding-math.

๐Ÿงช This option is experimental and does not currently guarantee to disable all GCC optimizations that are affected by rounding mode. Future versions of GCC may provide finer control of this setting using C99's FENV_ACCESS pragma. This command-line option will be used to specify the default state for FENV_ACCESS.

๐ŸŒŸ -fsignaling-nans

This tells the compiler to assume IEEE signaling NaNs may generate user-visible traps during floating-point operations. Turning it on disables optimizations that might change the number of exceptions visible with signaling NaNs. It implies -ftrapping-math โœจ

This option makes the preprocessor macro __SUPPORT_SNAN__ get defined ๐Ÿ”ฅ

The default is -fno-signaling-nans.

๐Ÿงช This option is experimental and does not currently guarantee to disable all GCC optimizations that affect signaling NaN behavior.

๐Ÿญ -fno-fp-int-builtin-inexact

This stops the built-in functions ceil, floor, round and trunc (and their float and long double variants) from generating code that raises the inexact floating-point exception for noninteger arguments. ISO C99 and C11 let these functions raise the inexact exception, but ISO/IEC TS 18661-1:2014, the C bindings to IEEE 754-2008, does not ๐Ÿ™…โ€โ™€๏ธ

The default is -ffp-int-builtin-inexact, which allows the exception to be raised. This option does nothing unless -ftrapping-math is in effect.

๐Ÿ“š Even if you use -fno-fp-int-builtin-inexact, if the functions generate a call to a library function, then the inexact exception may still be raised if the library implementation doesn't follow TS 18661.

๐ŸŽ€ -fsingle-precision-constant

This treats floating-point constants as single precision, instead of implicitly converting them to double-precision constants ๐Ÿ’…

๐ŸŒบ -fcx-limited-range

When enabled, this says a range reduction step isn't needed when performing complex division. There's also no checking for whether the result of a complex multiplication or division is "NaN + I*NaN", with an attempt to rescue the situation in that case ๐Ÿซถ

The default is -fno-cx-limited-range, but it gets enabled by -ffast-math. This option controls the default setting of the ISO C99 CX_LIMITED_RANGE pragma. Even so, the option applies to all languages.

๐Ÿš -fcx-fortran-rules

Complex multiplication and division follow Fortran rules. Range reduction is done as part of complex division, but there's no checking for whether the result of a complex multiplication or division is "NaN + I*NaN", with an attempt to rescue the situation in that case ๐Ÿ‘‘

The default is -fno-cx-fortran-rules.


The following options control optimizations that may improve performance, but they are not enabled by any -O options. Heads up bestie: this section includes experimental options that may produce broken code ๐Ÿ’€

  • -fbranch-probabilities โ€” okay so, after you compile with -fprofile-arcs and run the program, you can compile it again with -fbranch-probabilities to get smarter optimizations based on how many times each branch actually got taken ๐Ÿง . When a -fprofile-arcs program exits, it saves arc execution counts to a file called sourcename.gcda for each source file. That data file is super dependent on the exact structure of the generated code, so you must use the same source code and the same optimization options for both compilations ๐Ÿ’….
    • With -fbranch-probabilities, GCC slaps a REG_BR_PROB note on each JUMP_INSN and CALL_INSN ๐ŸŽ€. These can be used to level up optimization. Right now they're only used in one place: in reorg.c. Instead of guessing which path a branch is most likely to take, the REG_BR_PROB values are used to exactly figure out which path gets taken more often โœจ.
    • Enabled by -fprofile-use and -fauto-profile.
  • -fprofile-values โ€” if you combine it with -fprofile-arcs, it adds code that gathers some data about the values of expressions in your program ๐Ÿ”.
    • With -fbranch-probabilities, it reads back the data gathered from profiling those expression values so it can be used in optimizations.
    • Enabled by -fprofile-generate, -fprofile-use, and -fauto-profile.
  • -fprofile-reorder-functions โ€” function reordering based on profile instrumentation records the first time each function runs, then puts the functions in ascending order by that time ๐ŸŒˆ.
    • Enabled with -fprofile-use.
  • -fvpt โ€” if combined with -fprofile-arcs, this tells the compiler to add code that gathers info about values of expressions ๐Ÿฆ‹.
    • With -fbranch-probabilities, it reads back that data and actually performs optimizations based on it. Right now those optimizations include specialization of division operations using what it knows about the value of the denominator ๐Ÿ”ฅ.
    • Enabled with -fprofile-use and -fauto-profile.
  • -frename-registers โ€” tries to avoid false dependencies in scheduled code by making use of registers left over after register allocation ๐ŸŒธ. This optimization benefits processors with lots of registers the most. BUT, depending on the debug information format the target uses, it can make debugging impossible, since variables no longer stay in a "home register" ๐Ÿ˜ญ.
    • Enabled by default with -funroll-loops.
  • -fschedule-fusion โ€” runs a target-dependent pass over the instruction stream to group instructions of the same type together ๐Ÿง. The target machine can run them more efficiently when they're adjacent in the instruction flow.
    • Enabled at levels -O2, -O3, -Os.
  • -ftracer โ€” performs tail duplication to enlarge superblock size ๐Ÿ“. This simplifies the function's control flow, so other optimizations can do a better job.
    • Enabled by -fprofile-use and -fauto-profile.
  • -funroll-loops โ€” unrolls loops whose number of iterations can be determined at compile time or upon entry to the loop ๐Ÿ”. -funroll-loops implies -frerun-cse-after-loop, -fweb and -frename-registers. It also turns on complete loop peeling (i.e. complete removal of loops with a small constant number of iterations). Heads up though: this makes code larger, and it may or may not make it run faster ๐Ÿคทโ€โ™€๏ธ.
    • Enabled by -fprofile-use and -fauto-profile.
  • -funroll-all-loops โ€” unrolls ALL the loops, even if their number of iterations is uncertain when the loop is entered ๐Ÿ’€. This usually makes programs run more slowly. -funroll-all-loops implies the same options as -funroll-loops.
  • -fpeel-loops โ€” peels loops that have enough information to show they don't roll much (from profile feedback or static analysis) ๐Ÿ‘. It also turns on complete loop peeling (i.e. complete removal of loops with small constant number of iterations).
    • Enabled by -O3, -fprofile-use, and -fauto-profile.
  • -fmove-loop-invariants โ€” turns on the loop invariant motion pass in the RTL loop optimizer ๐Ÿงš.
    • Enabled at level -O1 and higher, except for -Og.
  • -fsplit-loops โ€” splits a loop into two if it contains a condition that's always true for one side of the iteration space and false for the other โœ‚๏ธ.
    • Enabled by -fprofile-use and -fauto-profile.
  • -funswitch-loops โ€” moves branches with loop invariant conditions out of the loop, with duplicates of the loop on both branches (modified according to the result of the condition) ๐Ÿ‘‘.
    • Enabled by -fprofile-use and -fauto-profile.
  • -fversion-loops-for-strides โ€” if a loop iterates over an array with a variable stride, GCC creates another version of the loop that assumes the stride is always one ๐Ÿ’–. For example:
for (int i = 0; i < n; ++i)
  x[i * stride] = ...;

becomes:

if (stride == 1)
  for (int i = 0; i < n; ++i)
    x[i] = ...;
else
  for (int i = 0; i < n; ++i)
    x[i * stride] = ...;

This is particularly useful for assumed-shape arrays in Fortran, where (for example) it allows better vectorization assuming contiguous accesses ๐Ÿซถ. This flag is enabled by default at -O3. It is also enabled by -fprofile-use and -fauto-profile.

  • -ffunction-sections, -fdata-sections โ€” places each function or data item into its own section in the output file, if the target supports arbitrary sections ๐Ÿงฉ. The name of the function or the name of the data item determines the section's name in the output file.
    • Use these on systems where the linker can perform optimizations to improve locality of reference in the instruction space. Most systems using the ELF object format have linkers with such optimizations. On AIX, the linker rearranges sections (CSECTs) based on the call graph. The performance impact varies.
    • Together with a linker garbage collection (linker --gc-sections option), these options may lead to smaller statically-linked executables (after stripping) ๐ŸŒฟ.
    • On ELF/DWARF systems, these options do not degenerate the quality of the debug information. There could be issues with other object files/debug info formats.
    • Only use these options when there are significant benefits from doing so ๐Ÿ™…โ€โ™€๏ธ. When you specify them, the assembler and linker create larger object and executable files, and they are also slower. These options affect code generation. They prevent optimizations by the compiler and assembler from using relative locations inside a translation unit, since the locations are unknown until link time. An example of such an optimization is relaxing calls to short call instructions.
  • -fbranch-target-load-optimize โ€” performs branch target register load optimization before prologue / epilogue threading ๐ŸŽฏ. The use of target registers can typically be exposed only during reload, so hoisting loads out of loops and doing inter-block scheduling need a separate optimization pass.
  • -fbranch-target-load-optimize2 โ€” performs branch target register load optimization after prologue / epilogue threading ๐ŸŒท.
  • -fbtr-bb-exclusive โ€” when doing branch target register load optimization, don't reuse branch target registers within any basic block ๐Ÿšซ.
  • -fstdarg-opt โ€” optimizes the prologue of variadic argument functions with respect to how those arguments are used ๐Ÿงƒ.
NOTE: In Ubuntu 14.10 and later versions, -fstack-protector-strong is enabled by default for C, C++, ObjC, ObjC++, if none of -fno-stack-protector, -nostdlib, nor -ffreestanding are found. ๐Ÿ›ก๏ธ
  • -fsection-anchors โ€” tries to reduce the number of symbolic address calculations by using shared "anchor" symbols to address nearby objects ๐ŸŒŸ. This transformation can help reduce the number of GOT entries and GOT accesses on some targets.
    • Here's an example. Take this function "foo":
static int a, b, c;
int foo (void) { return a + b + c; }

Normally it calculates the addresses of all three variables. But if you compile it with -fsection-anchors, it accesses the variables from a common anchor point instead ๐Ÿช„. The effect is similar to the following pseudocode (which isn't valid C):

int foo (void)
{
  register int *xr = &x;
  return xr[&a - &x] + xr[&b - &x] + xr[&c - &x];
}
  • Not all targets support this option.
  • --param name=value โ€” in some places, GCC uses various constants to control how much optimization gets done ๐ŸŽ›๏ธ. For example, GCC does not inline functions that contain more than a certain number of instructions. You can control some of these constants on the command line using --param.
    • The names of specific parameters, and the meaning of the values, are tied to the internals of the compiler and are subject to change without notice in future releases โš ๏ธ.
    • To get the minimal, maximal, and default value of a parameter, you can use --help=param -Q options.
    • In each case, the value is an integer. The allowable choices for name are:
      • predictable-branch-outcome โ€” when a branch is predicted to be taken with a probability lower than this threshold (in percent), it is considered well predictable ๐Ÿ”ฎ.
      • max-rtl-if-conversion-insns โ€” RTL if-conversion tries to remove conditional branches around a block and replace them with conditionally executed instructions. This parameter gives the maximum number of instructions in a block that should be considered for if-conversion. The compiler will also use other heuristics to decide whether if-conversion is likely to be profitable.
      • max-rtl-if-conversion-predictable-cost, max-rtl-if-conversion-unpredictable-cost โ€” RTL if-conversion will try to remove conditional branches around a block and replace them with conditionally executed instructions. These parameters give the maximum permissible cost for the sequence that would be generated by if-conversion, depending on whether the branch is statically determined to be predictable or not. The units for this parameter are the same as those for the GCC internal seq_cost metric. The compiler will try to provide a reasonable default for this parameter using the BRANCH_COST target macro ๐Ÿ’œ.

โœจ OPTIONS โœจ (the --param goodies, continued) ๐Ÿ’…

  • max-crossjump-edges โ€” okay so this is the max number of incoming edges GCC will even look at for cross-jumping ๐Ÿฆ‹. -fcrossjumping runs in O(N^2) time based on the edges coming into each block, so cranking this up is more aggressive optimization, but compile time goes up for probably a small win in executable size ๐Ÿ™ˆ.
  • min-crossjump-insns โ€” the minimum number of instructions that have to match at the end of two blocks before cross-jumping happens on them ๐ŸŽ€. If every instruction in the block being cross-jumped from already matches, this value gets ignored, so don't stress ๐Ÿ’–.
  • max-grow-copy-bb-insns โ€” the max code size expansion factor when GCC copies basic blocks instead of jumping to them ๐ŸŒธ. The expansion is measured relative to a jump instruction โœจ.
  • max-goto-duplication-insns โ€” the max number of instructions that can be duplicated into a block that jumps to a computed goto ๐Ÿงš. GCC factors computed gotos early on to dodge O(N^2) behavior across a bunch of passes, then unfactors them as late as possible ๐Ÿซถ. Only computed jumps sitting at the end of a basic block with no more than max-goto-duplication-insns instructions get unfactored ๐Ÿ’œ.
  • max-delay-slot-insn-search โ€” how many instructions GCC will consider while hunting for something to fill a delay slot ๐Ÿ”. Past this arbitrary number, the time saved by filling the slot is basically nothing, so GCC just stops searching ๐Ÿ˜ญ. Cranking it up means more aggressive optimization and longer compile times, for probably a small boost in execution time ๐ŸŒˆ.
  • max-delay-slot-live-search โ€” when filling delay slots, the max number of instructions to check while looking for a block with valid live register information ๐Ÿ“. Bumping this arbitrary value is more aggressive optimization, which also means longer compile times โญ. This parameter should be removed once the delay slot code gets rewritten to maintain the control-flow graph ๐Ÿ’€.
  • max-gcse-memory โ€” the approximate max memory GCC can allocate for global common subexpression elimination ๐Ÿ‘‘. If the optimization needs more memory than this, it just doesn't happen ๐Ÿฅบ.
  • max-gcse-insertion-ratio โ€” if the ratio of expression insertions to deletions for any expression goes above this value, RTL PRE inserts or removes that expression ๐ŸŒธ. The result is that partially redundant computations get left behind in the instruction stream ๐Ÿ’….
  • max-pending-list-length โ€” the max number of pending dependencies the scheduler allows before it flushes the current state and starts over โœจ. Big functions with few branches or calls can build up huge lists that waste memory and resources for no reason, so this keeps things tidy ๐Ÿงน.
  • max-modulo-backtrack-attempts โ€” the max backtrack attempts the scheduler makes when modulo scheduling a loop ๐Ÿ”. Larger values can blow up compilation time exponentially, so be careful bestie โš ๏ธ.
  • max-inline-insns-single โ€” several params control the tree inliner, and this one sets the max number of instructions (counted in GCC's internal representation) that a single function can have and still be considered for inlining ๐Ÿ‘‘. It only affects functions declared inline and methods implemented in a class declaration (C++) ๐ŸŽ€.
  • max-inline-insns-auto โ€” iykyk: when you use -finline-functions (included in -O3), a whole bunch of functions that would normally never be considered for inlining get investigated ๐Ÿ”. Those functions get a different, more restrictive limit than functions declared inline ๐Ÿฆ‹.
  • max-inline-insns-small โ€” the bound applied to calls that count as relevant with -finline-small-functions ๐ŸŒท.
  • max-inline-insns-size โ€” the bound applied to calls that are optimized for size ๐Ÿ“. A small amount of growth can be worth it to set up optimization opportunities that inlining opens up ๐Ÿ’œ.
  • uninlined-function-insns โ€” the number of instructions the inliner counts as function overhead, like the function prologue and epilogue ๐Ÿงš.
  • uninlined-function-time โ€” the extra time the inliner counts as function overhead, like the time it takes to run the function prologue and epilogue โฑ๏ธ.
  • uninlined-thunk-insns, uninlined-thunk-time โ€” same deal as --param uninlined-function-insns and --param uninlined-function-time, but these apply to function thunks ๐Ÿซถ.
  • inline-min-speedup โ€” if the estimated performance improvement of caller plus callee runtime goes over this threshold (in percent), the function can be inlined no matter what the --param max-inline-insns-single and --param max-inline-insns-auto limits say ๐Ÿš€.
  • large-function-insns โ€” the limit that defines really large functions ๐Ÿ˜. For functions bigger than this after inlining, inlining gets constrained by --param large-function-growth ๐Ÿซง. This one is mostly there to avoid extreme compile times caused by non-linear back end algorithms ๐Ÿ˜ตโ€๐Ÿ’ซ.
  • large-function-growth โ€” the max growth of a large function caused by inlining, in percent ๐Ÿ“ˆ. For example, a value of 100 limits large function growth to 2.0 times the original size ๐Ÿ’–.
  • large-unit-insns โ€” the limit that defines a large translation unit ๐Ÿ—‚๏ธ. Growth from inlining into units bigger than this gets limited by --param inline-unit-growth, but for small units that might be too tight ๐Ÿฅน. Say a unit has function A (inline) and function B, which just calls A three times ๐Ÿค“. If B is small compared to A, the unit growth is 300% and yet that inlining is totally sane โœ…. For very large units full of small inlineable functions, though, the overall unit growth limit is needed to stop an exponential explosion of code size ๐Ÿ’ฅ. So for smaller units, the size gets bumped up to --param large-unit-insns before --param inline-unit-growth gets applied ๐ŸŒˆ.
  • inline-unit-growth โ€” the max overall growth of the compilation unit caused by inlining ๐Ÿ“ฆ. For example, a value of 20 limits unit growth to 1.2 times the original size ๐Ÿงฎ. Cold functions (marked cold with an attribute or by profile feedback) don't count toward the unit size ๐ŸงŠ.
  • ipcp-unit-growth โ€” the max overall growth of the compilation unit caused by interprocedural constant propagation ๐Ÿ”ข. For example, a value of 10 limits unit growth to 1.1 times the original size ๐Ÿฐ.
  • large-stack-frame โ€” the limit that defines large stack frames ๐Ÿฅž. While inlining, the algorithm tries not to grow past this limit too much ๐Ÿ™…โ€โ™€๏ธ.
  • large-stack-frame-growth โ€” the max growth of large stack frames caused by inlining, in percent ๐Ÿ“Š. For example, a value of 1000 limits large stack frame growth to 11 times the original size ๐Ÿซ .
  • max-inline-insns-recursive, max-inline-insns-recursive-auto โ€” the max number of instructions an out-of-line copy of a self-recursive inline function can grow into through recursive inlining ๐Ÿ”„. --param max-inline-insns-recursive applies to functions declared inline ๐ŸŽ€. For functions that aren't declared inline, recursive inlining only happens when -finline-functions (included in -O3) is enabled, and then --param max-inline-insns-recursive-auto applies instead ๐Ÿ’….
  • max-inline-recursive-depth, max-inline-recursive-depth-auto โ€” the max recursion depth used for recursive inlining ๐Ÿชž. --param max-inline-recursive-depth applies to functions declared inline ๐ŸŒธ. For functions that aren't declared inline, recursive inlining only happens when -finline-functions (included in -O3) is enabled, and then --param max-inline-recursive-depth-auto applies instead ๐Ÿซถ.
  • min-inline-recursive-probability โ€” recursive inlining only pays off for functions with deep recursion on average ๐ŸŒณ. For functions with little recursion depth, it can hurt by increasing the prologue size, or the complexity of the function body for other optimizers ๐Ÿ˜ฌ. When profile feedback is available (see -fprofile-generate), the actual recursion depth can be guessed from the probability that a function recurses via a given call expression ๐Ÿ”ฎ. This parameter limits inlining to only those call expressions whose probability goes over the threshold (in percent) ๐ŸŽฏ.
  • early-inlining-insns โ€” specifies how much growth the early inliner is allowed to make ๐ŸŒฑ. In effect, it bumps up the amount of inlining for code with a large abstraction penalty ๐Ÿ‹๏ธโ€โ™€๏ธ.
  • max-early-inliner-iterations โ€” the limit on early inliner iterations ๐Ÿ”. This basically bounds how many nested indirect calls the early inliner can resolve ๐Ÿ“ž. Deeper chains still get handled by late inlining ๐Ÿ•ฐ๏ธ.
  • comdat-sharing-probability โ€” the probability (in percent) that C++ inline functions with comdat visibility get shared across multiple compilation units ๐Ÿค.
  • profile-func-internal-id โ€” controls whether the function's internal id gets used in profile database lookups ๐Ÿ—ƒ๏ธ. If the value is 0, the compiler uses an id based on the function's assembler name and filename ๐Ÿท๏ธ, which makes old profile data more forgiving of source changes, like function reordering ๐Ÿฅฐ.
  • min-vect-loop-bound โ€” the min number of iterations below which loops don't get vectorized when -ftree-vectorize is used ๐ŸŽถ. The number of iterations after vectorization has to be greater than the value set here for vectorization to happen โœจ.
  • gcse-cost-distance-ratio โ€” okay so this one is the scaling factor for how far an expression can be moved by GCSE optimizations ๐Ÿฆ‹ Right now it only works in the code hoisting pass, and the bigger the ratio, the more aggressive the hoisting gets with simple expressions (the ones costing less than gcse-unrestricted-cost) ๐Ÿ”ฅ Setting it to 0 turns off hoisting of simple expressions completely ๐Ÿ™ˆ
  • gcse-unrestricted-cost โ€” this is the cost, roughly the price of one typical machine instruction โœจ Once an expression hits this cost, GCSE stops putting a leash on how far it can travel. It's also only a thing in the code hoisting pass. The lower the cost, the more aggressive the hoisting, and 0 lets every expression wander as far as it wants ๐ŸŒˆ
  • max-hoist-depth โ€” how deep the search goes up the dominator tree when looking for expressions to hoist ๐ŸŒธ It's there to keep the hoisting algorithm from going quadratic on us. A value of 0 means no limit on the search, but fair warning, it can slow down compilation of huge functions ๐Ÿข
  • max-tail-merge-comparisons โ€” the most similar bbs you're allowed to compare a bb against ๐Ÿ’… This keeps tree tail merging from going quadratic, so no spiraling.
  • max-tail-merge-iterations โ€” caps how many passes over the function the tree tail merging gets to make ๐Ÿงš It's basically a leash on compile time.
  • store-merging-allow-unaligned โ€” lets the store merging pass introduce unaligned stores, but only if that's legal to do ๐Ÿซถ Permission granted, with a big asterisk.
  • max-stores-to-merge โ€” the max number of stores the store merging pass will try to squish into wider stores ๐Ÿ’œ
  • max-unrolled-insns โ€” the most instructions a loop can have and still get unrolled โœจ If it does get unrolled, this same number also decides how many times the loop body gets copied ๐Ÿ‘‘
  • max-average-unrolled-insns โ€” same vibe as above, but it counts instructions biased by how likely they are to run ๐ŸŽ€ Loops that qualify get unrolled, and this value sets how many times too.
  • max-unroll-times โ€” the max number of unrollings for a single loop ๐Ÿ“
  • max-peeled-insns โ€” the most instructions a loop can have and still get peeled ๐Ÿฆ‹ If it gets peeled, this parameter also decides how many times the loop code gets peeled.
  • max-peel-times โ€” the max number of peelings for a single loop ๐ŸŒธ
  • max-peel-branches โ€” the max number of branches allowed on the hot path through the peeled sequence ๐Ÿ”ฅ
  • max-completely-peeled-insns โ€” the max number of insns a completely peeled loop can have ๐Ÿ’–
  • max-completely-peel-times โ€” the max number of iterations a loop can have and still be suitable for complete peeling ๐Ÿงš
  • max-completely-peel-loop-nest-depth โ€” the deepest a loop nest can be and still be suitable for complete peeling ๐ŸŒˆ
  • max-unswitch-insns โ€” the max number of insns an unswitched loop can have ๐Ÿ’…
  • max-unswitch-level โ€” the max number of branches that can get unswitched in a single loop ๐Ÿซถ
  • lim-expensive โ€” the minimum cost for something to count as an expensive expression in loop invariant motion ๐Ÿ’€ Anything cheaper than this isn't considered expensive, bestie.
  • iv-consider-all-candidates-bound โ€” this is the bound on how many candidates for induction variables there can be before the optimizer stops considering all of them for each use โœจ Go over it, and only the most relevant candidates get looked at, so the time complexity doesn't go quadratic on us ๐Ÿ™ˆ
  • iv-max-considered-uses โ€” the induction variable optimizations just give up on any loop with more induction variable uses than this ๐Ÿ˜ญ
  • iv-always-prune-cand-set-bound โ€” if the candidate set is smaller than this value, the optimizer will always try to remove unnecessary ivs from the set whenever it adds a new one ๐Ÿฆ‹
  • avg-loop-niter โ€” the average number of iterations a loop is expected to run ๐ŸŒธ
  • dse-max-object-size โ€” the max size, in bytes, of objects that dead store elimination tracks bytewise ๐Ÿ”ฅ Bigger values can mean longer compilation times, so keep that in mind, periodt.
  • dse-max-alias-queries-per-store โ€” the max number of queries into the alias oracle per store ๐Ÿ’– Crank this up and compilation takes longer, but you might get rid of more dead stores too.
  • scev-max-expr-size โ€” the bound on how big the expressions in the scalar evolutions analyzer can get ๐Ÿงš Huge expressions make the analyzer slow, so this keeps things snappy.
  • scev-max-expr-complexity โ€” the bound on how complex those scalar evolutions expressions can be ๐ŸŒˆ Complicated expressions slow the analyzer down too, so same energy.
  • max-tree-if-conversion-phi-args โ€” the max number of arguments a PHI can have and still be supported by TREE if conversion ๐Ÿ’… The exception is a loop marked with the simd pragma, which gets to ignore this limit ๐Ÿซถ
  • vect-max-version-for-alignment-checks โ€” when the vectorizer does loop versioning for alignment, this is the max number of run-time checks it can perform ๐Ÿ’œ
  • vect-max-version-for-alias-checks โ€” same deal, but for alias checks during loop versioning in the vectorizer ๐ŸŽ€
  • vect-max-peeling-for-alignment โ€” the max number of loop peels the vectorizer can do to get access alignment sorted ๐Ÿ“ Set it to -1 and there's no limit at all ๐Ÿ‘‘
  • max-iterations-to-track โ€” the max number of loop iterations that the brute-force algorithm will try to evaluate when it's figuring out how many iterations a loop runs ๐Ÿฆ‹
  • hot-bb-count-ws-permille โ€” a basic block profile count counts as hot if it contributes to the given permillage (so, 0...1000) of the entire profiled execution ๐Ÿ”ฅ
  • hot-bb-frequency-fraction โ€” picks the fraction of the entry block frequency that a basic block in a function needs to hit before it's considered hot ๐ŸŒธ
  • max-predicted-iterations โ€” the max number of loop iterations GCC will predict statically ๐Ÿ’– This matters when a function has one loop with a known bound and another with an unknown bound. The known count gets predicted correctly, but the unknown one averages out to roughly 10, which makes the unbounded loop look artificially cold compared to the other one ๐Ÿฅถ
  • builtin-expect-probability โ€” controls the probability that an expression has the specified value ๐Ÿงš It takes a percentage, so 0 ... 100 as input โœจ
  • builtin-string-cmp-inline-length โ€” the max length of a constant string for a builtin string cmp call to be eligible for inlining ๐ŸŒˆ
  • align-threshold โ€” picks the fraction of the maximal execution frequency of a basic block in a function that's needed before the basic block gets aligned ๐Ÿ’…
  • align-loop-iterations โ€” any loop that's expected to iterate at least this many times gets aligned ๐Ÿซถ
  • tracer-dynamic-coverage and tracer-dynamic-coverage-feedback โ€” these limit superblock formation once the given percentage of executed instructions is covered ๐Ÿ’œ That keeps the code from ballooning for no reason.

The tracer-dynamic-coverage-feedback parameter only gets used when profile feedback is available ๐ŸŽ€ Real profiles are way less balanced than statically estimated ones, so the threshold can be set to a bigger value ๐Ÿ“

  • tracer-max-code-growth โ€” stops tail duplication once code growth reaches the given percentage ๐Ÿ‘‘ Honestly this is a pretty artificial limit, since most of the duplicates get cleaned up later in cross jumping. So it can be set to way higher values than the code growth you actually want ๐Ÿฆ‹
  • tracer-min-branch-ratio โ€” stops reverse growth when the reverse probability of the best edge drops below this threshold (in percent) ๐Ÿ”ฅ
  • tracer-min-branch-probability and tracer-min-branch-probability-feedback โ€” stops forward growth if the best edge has a probability lower than this threshold ๐ŸŒธ

Same story as the dynamic coverage pair: there are two of these. tracer-min-branch-probability-feedback is for compilation with profile feedback, and tracer-min-branch-probability is for compilation without it. The feedback version needs to be more conservative (higher) to make the tracer effective ๐Ÿ’–

  • stack-clash-protection-guard-size โ€” specifies the size of the operating system provided stack guard as 2 raised to num bytes ๐Ÿงš Higher values can cut down on the number of explicit probes, but if the value is bigger than the operating system's guard, your code is left open to stack clash style attacks. Not it ๐Ÿ™…โ€โ™€๏ธ
  • stack-clash-protection-probe-interval โ€” stack clash protection means probing stack space as it gets allocated ๐ŸŒˆ This one controls the max distance between probes into the stack, as 2 raised to num bytes. Higher values can reduce explicit probes, but a value bigger than the OS-provided guard leaves the code vulnerable to stack clash style attacks ๐Ÿ’€
  • max-cse-path-length โ€” the max number of basic blocks on a path that CSE considers ๐Ÿ’…
  • max-cse-insns โ€” the max number of instructions CSE processes before it flushes ๐Ÿซถ
  • ggc-min-expand โ€” GCC uses a garbage collector to manage its own memory allocation โœจ This sets the minimum percentage that the garbage collector's heap is allowed to expand between collections ๐Ÿ’œ Tuning it might speed up compilation, but it has zero effect on code generation, so no vibe shift there ๐ŸŽ€

The default is 30% + 70% * (RAM/1GB) with an upper bound of 100% when RAM >= 1GB ๐Ÿ“ If getrlimit is available, "RAM" means the smallest of actual RAM and RLIMIT_DATA or RLIMIT_AS ๐Ÿ‘‘ If GCC can't work out RAM on a particular platform, the lower bound of 30% gets used ๐Ÿฆ‹ Setting this parameter and ggc-min-heapsize to zero forces a full collection at every opportunity ๐Ÿ”ฅ It's extremely slow, but it can be super useful for debugging ๐ŸŒธ

  • ggc-min-heapsize โ€” okay so this is the smallest the garbage collector's heap can get before it even starts bothering to clean up ๐Ÿงน The first collection happens once the heap grows by ggc-min-expand% past ggc-min-heapsize. Tuning this might speed up compilation โœจ, but it has zero effect on code generation ๐Ÿ’…
    • The default is the smaller of RAM/8, RLIMIT_RSS, or a limit that tries to make sure RLIMIT_DATA or RLIMIT_AS don't get exceeded ๐Ÿซถ But it's clamped to a floor of 4096 (four megabytes) and a ceiling of 131072 (128 megabytes).
    • If GCC can't figure out RAM on a particular platform, the lower bound gets used ๐Ÿคทโ€โ™€๏ธ
    • Setting this super large basically turns garbage collection off ๐Ÿ’€
    • Setting this and ggc-min-expand to zero makes a full collection happen at every single opportunity ๐Ÿ˜ญ
  • max-reload-search-insns โ€” the max number of instructions reload will look backward through to find an equivalent register ๐Ÿ” Bigger numbers mean more aggressive optimization, and compile time goes up for probably a slightly better performance glow-up ๐ŸŒธ
  • max-cselib-memory-locations โ€” how many memory locations cselib is allowed to take into account ๐Ÿง  Higher values mean more aggressive optimization, longer compile times, and probably slightly better performance โœจ
  • max-sched-ready-insns โ€” the max number of instructions that are ready to be issued that the scheduler will consider at any given moment during the first scheduling pass ๐Ÿ“‹ Higher values mean more thorough searches, so compile time climbs with probably not a ton of benefit ๐Ÿ™ƒ
  • max-sched-region-blocks โ€” the max number of blocks in a region that can be considered for interblock scheduling ๐Ÿงฑ
  • max-pipeline-region-blocks โ€” the max number of blocks in a region that can be considered for pipelining in the selective scheduler ๐ŸŽ€
  • max-sched-region-insns โ€” the max number of insns in a region that can be considered for interblock scheduling ๐Ÿฆ‹
  • max-pipeline-region-insns โ€” the max number of insns in a region that can be considered for pipelining in the selective scheduler ๐ŸŒˆ
  • min-spec-prob โ€” the minimum probability (in percents) of reaching a source block for interblock speculative scheduling ๐ŸŽฏ
  • max-sched-extend-regions-iters โ€” the max number of trips through the CFG when extending regions ๐Ÿ” Setting this to 0 turns region extensions off ๐Ÿšซ
  • max-sched-insn-conflict-delay โ€” the max conflict delay an insn can have and still be considered for speculative motion โณ
  • sched-spec-prob-cutoff โ€” the minimal probability of speculation success (in percents) needed before speculative insns actually get scheduled ๐Ÿ”ฎ
  • sched-state-edge-prob-cutoff โ€” the minimum probability an edge needs to have before the scheduler bothers saving its state across it ๐Ÿ’พ
  • sched-mem-true-dep-cost โ€” the minimal distance (in CPU cycles) between a store and a load that are targeting the same memory locations ๐ŸงŠ
  • selsched-max-lookahead โ€” the max size of the lookahead window for selective scheduling ๐Ÿ‘€ It's basically how deep the search goes for available instructions ๐Ÿ•ต๏ธโ€โ™€๏ธ
  • selsched-max-sched-times โ€” the max number of times an instruction can be scheduled during selective scheduling ๐Ÿ”„ This caps how many iterations the instruction is allowed to be pipelined through ๐Ÿšฆ
  • selsched-insns-to-rename โ€” the max number of best instructions in the ready list that get considered for renaming in the selective scheduler โœ๏ธ
  • sms-min-sc โ€” the minimum stage count value that the swing modulo scheduler generates ๐ŸŽข
  • max-last-value-rtl โ€” the max size, measured in RTLs, that can be recorded in a combiner expression for a pseudo register as its last known value ๐Ÿ“
  • max-combine-insns โ€” the max number of instructions the RTL combiner will try to combine together ๐Ÿงฉ
  • integer-share-limit โ€” small integer constants can use a shared data structure, which saves the compiler some memory and makes it faster ๐Ÿš€ This sets the max value that a shared integer constant can have ๐Ÿ”ข
  • ssp-buffer-size โ€” the minimum size of buffers (aka arrays) that get stack smashing protection when -fstack-protection is used ๐Ÿ›ก๏ธ
    • Before Ubuntu 10.10, this default was "8". Right now it's "4", so more functions get covered by the stack protector ๐Ÿ’–
  • min-size-for-stack-sharing โ€” the minimum size of variables that take part in stack slot sharing when you're not optimizing ๐Ÿงบ
  • max-jump-thread-duplication-stmts โ€” the max number of statements a block can have when it needs to be duplicated for jump threading ๐Ÿงต
  • max-fields-for-field-sensitive โ€” the max number of fields in a structure that gets treated in a field sensitive manner during pointer analysis ๐Ÿงฌ
  • prefetch-latency โ€” an estimate of the average number of instructions that run before a prefetch finishes โฑ๏ธ The distance prefetched ahead is proportional to this number ๐Ÿ“ Raising it might also mean fewer streams get prefetched (see simultaneous-prefetches) ๐ŸŒŠ
  • simultaneous-prefetches โ€” the max number of prefetches that can run at the same time ๐Ÿƒโ€โ™€๏ธ๐Ÿ’จ
  • l1-cache-line-size โ€” the size of a cache line in the L1 data cache, in bytes ๐Ÿ“ฆ
  • l1-cache-size โ€” the size of the L1 data cache, in kilobytes ๐Ÿ—‚๏ธ
  • l2-cache-size โ€” the size of the L2 data cache, in kilobytes ๐Ÿ—„๏ธ
  • prefetch-dynamic-strides โ€” whether the loop array prefetch pass should issue software prefetch hints for strides that are non-constant ๐ŸŽฒ Sometimes that's helpful, but a non-constant stride can make it really hard to tell when there's a clear benefit ๐Ÿค”
    • Set to 1 if prefetch hints should be issued for non-constant strides โœ…
    • Set to 0 if prefetch hints should only be issued for strides that are known to be constant and below prefetch-minimum-stride ๐Ÿšซ
  • prefetch-minimum-stride โ€” the minimum constant stride, in bytes, before prefetch hints start getting used ๐Ÿ›ฃ๏ธ If the stride is less than this threshold, no prefetch hints will be issued ๐Ÿ™…โ€โ™€๏ธ
    • This setting is super useful for processors with hardware prefetchers ๐Ÿ’œ In that case the hardware and software prefetchers can clash ๐Ÿ˜ฌ If the hardware prefetchers have a max stride they can handle, put that value here so the software prefetchers get used more effectively โœจ
    • A value of -1 means there's no threshold, so prefetch hints can be issued for any constant stride ๐ŸŒˆ
    • This setting only matters for strides that are known and constant ๐Ÿ“
  • loop-interchange-max-num-stmts โ€” the max number of stmts in a loop that can be interchanged ๐Ÿ”€
  • loop-interchange-stride-ratio โ€” the minimum ratio between the strides of two loops for interchange to be profitable ๐Ÿ’…
  • min-insn-to-prefetch-ratio โ€” the minimum ratio between the number of instructions and the number of prefetches needed to enable prefetching in a loop ๐Ÿ“Š
  • prefetch-min-insn-to-mem-ratio โ€” the minimum ratio between the number of instructions and the number of memory references needed to enable prefetching in a loop ๐Ÿงฎ
  • use-canonical-types โ€” whether the compiler should use the "canonical" type system ๐Ÿง‘โ€๐Ÿ”ฌ This should always be 1, since it uses a more efficient internal way to compare types in C++ and Objective-C++ ๐Ÿ”ฅ But if bugs in the canonical type system are causing compilation failures, set it to 0 to turn canonical types off ๐Ÿซ 
  • switch-conversion-max-branch-ratio โ€” switch initialization conversion refuses to create arrays that are bigger than switch-conversion-max-branch-ratio times the number of branches in the switch ๐Ÿšซ๐Ÿ“ฆ
  • max-partial-antic-length โ€” the max length of the partial antic set computed during tree partial redundancy elimination (-ftree-pre) when optimizing at -O3 and above โš ๏ธ For some source code, the enhanced PRE can run away and eat all the memory on the host machine ๐Ÿ˜ฑ This param caps the length of those sets so the runaway doesn't happen ๐Ÿ›‘
    • Setting this to 0 allows an unlimited set length, so be careful with that one ๐Ÿ™ˆ
  • rpo-vn-max-loop-depth โ€” the max loop depth that gets value-numbered optimistically ๐Ÿ”ข Once the limit is hit, the innermost rpo-vn-max-loop-depth loops and the outermost loop in the loop nest get value-numbered optimistically, and the remaining ones don't ๐Ÿง
  • sccvn-max-alias-queries-per-access โ€” the max number of alias-oracle queries we run when looking for redundancies in loads and stores ๐Ÿ”Ž If this limit is hit, the search is aborted and the load or store is not considered redundant ๐Ÿ™…โ€โ™€๏ธ The number of queries is algorithmically limited to the number of stores on all paths from the load to the function entry ๐Ÿ›ค๏ธ
  • ira-max-loops-num โ€” IRA uses regional register allocation by default ๐Ÿ—บ๏ธ If a function has more loops than this number, only at most this many of the most frequently executed loops form regions for regional register allocation ๐Ÿ”
  • ira-max-conflict-table-size โ€” IRA uses a fancy algorithm to compress the conflict table, but for huge functions the table can still eat an excessive amount of memory ๐Ÿฝ๏ธ If the conflict table for a function could be bigger than the size in MB given by this parameter, the register allocator switches to a faster, simpler, and lower-quality algorithm that doesn't build a pseudo-register conflict table at all ๐Ÿซถ
  • ira-loop-reserved-regs: okay so IRA can get a more accurate read on register pressure inside loops ๐Ÿ”, which helps it decide whether to pull out loop invariants (see -O3) โœจ. This parameter sets how many available registers get set aside for other purposes. The default is the best value found after numerous experiments ๐Ÿ’…
  • lra-inheritance-ebb-probability-cutoff: LRA likes to reuse values it already reloaded into registers for later insns, and that's called inheritance ๐Ÿฆ‹. EBB is the region used for this. This parameter is the minimal fall-through edge probability, in percent, needed to add a BB to the inheritance EBB in LRA ๐ŸŒธ. The default was chosen from loads of SPEC2000 runs on x86-64 ๐Ÿ’œ
  • loop-invariant-max-bbs-in-loop: loop invariant motion can get super expensive in both compilation time and compile-time memory when loops are huge ๐Ÿ™ˆ. Any loop with more basic blocks than this value just won't get loop invariant motion ๐Ÿšซ
  • loop-max-datarefs-for-datadeps: building data dependencies is costly for massive loops ๐Ÿ’€. This caps how many data references in a loop get considered for data dependence analysis. Loops that are too big aren't handled by the optimizations that use loop data dependencies ๐Ÿ™…
  • max-vartrack-size: this caps the number of hash table slots used during variable tracking dataflow analysis of any function ๐Ÿงฉ. If the limit is exceeded with variable tracking at assignments enabled, analysis for that function gets retried without it, after all debug insns are removed from the function. If it's still over the limit without debug insns, var tracking analysis is completely disabled for that function ๐Ÿ˜ญ. Setting it to 0 makes it unlimited ๐ŸŒˆ
  • max-vartrack-expr-depth: this is the max number of recursion levels when mapping variable names or debug temporaries to value expressions. It's a trade-off: more compile time for more complete debug information โณ. If it's set too low, value expressions that could be represented in debug info might never get used ๐Ÿฅฒ. Set it higher and the compiler can find fancier debug expressions, but compile time and memory use may grow ๐Ÿ“ˆ
  • max-debug-marker-count: this sets a threshold on debug markers (like begin stmt markers) so complexity doesn't explode at inlining or RTL expansion ๐ŸŽ€. If a function has more of these gimple stmts than the limit, they get dropped from the inlined copy of the function and from its RTL expansion โœ‚๏ธ
  • min-nondebug-insn-uid: this is the uid where nondebug insns start counting ๐Ÿ”ข. The range below it is reserved exclusively for debug insns created by -fvar-tracking-assignments. Debug insns can still get (non-overlapping) uids above it if that reserved range runs out ๐Ÿงš
  • ipa-sra-ptr-growth-factor: IPA-SRA only swaps a pointer to an aggregate for one or more new parameters when their cumulative size is less than or equal to ipa-sra-ptr-growth-factor times the size of the original pointer parameter ๐Ÿ“
  • sra-max-scalarization-size-Ospeed and sra-max-scalarization-size-Osize: the two Scalar Reduction of Aggregates passes (SRA and IPA-SRA) want to swap scalar parts of aggregates for independent scalar variables ๐Ÿช„. These control the max size, in storage units, of an aggregate that's considered for replacement when compiling for speed (sra-max-scalarization-size-Ospeed) or size (sra-max-scalarization-size-Osize) respectively ๐Ÿ’–
  • sra-max-propagations: this is the max number of artificial accesses that SRA will track per local variable, so copy propagation has something to work with ๐Ÿ”
  • tm-max-aggregate-size: when copying thread-local variables in a transaction, this is the size in bytes after which variables get saved with the logging functions instead of save/restore code sequence pairs ๐Ÿ“. This only applies when using -fgnu-tm ๐Ÿซถ
  • graphite-max-nb-scop-params: to avoid exponential effects in the Graphite loop transforms, the number of parameters in a Static Control Part (SCoP) is bounded ๐Ÿงฎ. A value of 0 lifts the bound. A variable whose value is unknown at compile time and defined outside a SCoP counts as a parameter of that SCoP ๐Ÿ‘‘
  • loop-block-tile-size: loop blocking or strip mining (enabled with -floop-block or -floop-strip-mine) strip mines each loop in the nest by a given number of iterations ๐Ÿงฑ. The strip length can be changed with this parameter ๐ŸŽฏ
  • ipa-cp-value-list-size: IPA-CP tries to track all possible values and types passed to a function's parameter so it can propagate them and perform devirtualization ๐Ÿ•ต๏ธ. This is the max number of values and types it stores per formal parameter of a function ๐Ÿ“š
  • ipa-cp-eval-threshold: IPA-CP calculates its own score for cloning profitability and goes ahead with cloning opportunities whose scores exceed ipa-cp-eval-threshold ๐Ÿ“Š
  • ipa-cp-recursion-penalty: this is the percentage penalty that recursive functions get when they're evaluated for cloning ๐Ÿ”„
  • ipa-cp-single-call-penalty: this is the percentage penalty that functions containing a single call to another function get when they're evaluated for cloning โ˜๏ธ
  • ipa-max-agg-items: IPA-CP can also propagate a number of scalar values passed in an aggregate ๐Ÿ“ฆ. This controls the max number of those values per parameter
  • ipa-cp-loop-hint-bonus: when IPA-CP figures out that a cloning candidate would make a loop's number of iterations known, it adds a bonus of ipa-cp-loop-hint-bonus to that candidate's profitability score ๐ŸŽ
  • ipa-cp-array-index-hint-bonus: same energy: when IPA-CP determines that a cloning candidate would make an array access's index known, it adds a bonus of ipa-cp-array-index-hint-bonus to the candidate's profitability score ๐ŸŽ
  • ipa-max-aa-steps: while analyzing function bodies, IPA-CP uses alias analysis to track values pointed to by function parameters ๐Ÿ”. So it doesn't spend forever on huge functions, it gives up and considers all memory clobbered after examining ipa-max-aa-steps statements that modify memory ๐Ÿณ๏ธ
  • lto-partitions: this is the desired number of partitions produced during WHOPR compilation ๐Ÿฐ. The number of partitions should exceed the number of CPUs used for compilation ๐Ÿ’ป
  • lto-min-partition: this is the size of the minimal partition for WHOPR (in estimated instructions) ๐Ÿง. It stops very small programs from being split into too many partitions ๐Ÿ™…
  • lto-max-partition: this is the size of the max partition for WHOPR (in estimated instructions) โฌ†๏ธ. It gives an upper bound on the size of each individual partition. It's only meant to be used with balanced partitioning โš–๏ธ
  • lto-max-streaming-parallelism: the max number of parallel processes used for LTO streaming ๐ŸŒŠ
  • cxx-max-namespaces-for-diagnostic-help: the max number of namespaces to consult for suggestions when C++ name lookup fails for an identifier ๐Ÿ”Ž
  • sink-frequency-threshold: this is the max relative execution frequency (in percents) of the target block compared to a statement's original block, which lets that statement get sunk ๐Ÿƒ. Bigger numbers mean more aggressive statement sinking. A small positive adjustment is applied to statements with memory operands, since those are even more profitable to sink ๐Ÿ’œ
  • max-stores-to-sink: this is the max number of conditional store pairs that can be sunk ๐Ÿ•ณ๏ธ. Set it to 0 if either vectorization (-ftree-vectorize) or if-conversion (-ftree-loop-if-convert) is disabled
  • allow-store-data-races: this lets optimizers introduce new data races on stores โš ๏ธ. Set it to 1 to allow that, otherwise set it to 0.
โš ๏ธ bestie, data races are NOT a vibe. Only flip this on if you know exactly what you're doing ๐Ÿ’€
  • case-values-threshold: this is the smallest number of different values for which a jump-table is better than a tree of conditional branches ๐ŸŒณ. If the value is 0, the default for the machine is used ๐Ÿ–ฅ๏ธ
  • tree-reassoc-width: this sets the max number of instructions executed in parallel in a reassociated tree ๐Ÿงต. A non-zero value overrides the target-dependent heuristics used by default ๐ŸŽฏ
  • sched-pressure-algorithm: this lets you choose between the two implementations of -fsched-pressure ๐Ÿง . Algorithm 1 is the original implementation and is the more likely one to prevent instructions from being reordered ๐Ÿ›‘. Algorithm 2 was designed as a compromise between the relatively conservative approach of algorithm 1 and the rather aggressive approach of the default scheduler โš–๏ธ. It relies more heavily on having a regular register file and accurate register pressure classes ๐Ÿ—‚๏ธ. See haifa-sched.c in the GCC sources for more details ๐Ÿ“–

The default choice depends on the target ๐ŸŽฏ

  • max-slsr-cand-scan: this sets the max number of existing candidates considered when seeking a basis for a new straight-line strength reduction candidate ๐Ÿ”ญ
  • asan-globals: this enables buffer overflow detection for global objects ๐Ÿ›ก๏ธ. This protection is enabled by default when you use the -fsanitize=address option. To disable global objects protection, use --param asan-globals=0 ๐Ÿ™…
  • asan-stack: this enables buffer overflow detection for stack objects ๐Ÿฅž. This protection is enabled by default when using -fsanitize=address. To disable stack protection, use --param asan-stack=0 option ๐Ÿ’…
  • asan-instrument-reads โ€” Turns on buffer overflow detection for memory reads ๐Ÿ›ก๏ธ It's already on by default with -fsanitize=address, but if you want it off, use --param asan-instrument-reads=0. ๐Ÿ’…
  • asan-instrument-writes โ€” Same energy, but for memory writes โœ๏ธ Also on by default with -fsanitize=address. To turn it off, use --param asan-instrument-writes=0 option.
  • asan-memintrin โ€” Enables detection for built-in functions ๐Ÿง  On by default with -fsanitize=address. To disable this protection, use --param asan-memintrin=0.
  • asan-use-after-return โ€” Enables detection of use-after-return ๐Ÿ” This is on by default when you use the -fsanitize=address option. To turn it off, use --param asan-use-after-return=0.
    • Note: this check is disabled at run time by default โš ๏ธ To enable it, add "detect_stack_use_after_return=1" to the environment variable ASAN_OPTIONS.
  • asan-instrumentation-with-call-threshold โ€” If the function being instrumented has a number of memory accesses that's greater than or equal to this number, GCC uses callbacks instead of inline checks ๐Ÿ“ž For example, to skip inline code entirely, use --param asan-instrumentation-with-call-threshold=0.
  • use-after-scope-direct-emission-threshold โ€” If a local variable is smaller than or equal to this many bytes, the shadow memory gets poisoned (or unpoisoned) directly ๐Ÿช„ instead of relying on run-time callbacks.
  • max-fsm-thread-path-insns โ€” The maximum number of instructions copied when duplicating blocks on a finite state automaton jump thread path ๐Ÿงต
  • max-fsm-thread-length โ€” The maximum number of basic blocks allowed on a finite state automaton jump thread path ๐Ÿ“
  • max-fsm-thread-paths โ€” The maximum number of new jump thread paths GCC will create for a finite state automaton ๐Ÿ›ค๏ธ
  • parloops-chunk-size โ€” The chunk size of the omp schedule for loops that get parallelized by parloops ๐Ÿงฉ
  • parloops-schedule โ€” The schedule type of the omp schedule for loops parallelized by parloops, which can be static, dynamic, guided, auto, or runtime ๐Ÿ—“๏ธ
  • parloops-min-per-thread โ€” The minimum number of iterations per thread in an innermost parallelized loop where the parallel version is preferred over the single-threaded one ๐Ÿงต Fair warning: for a parallelized loop nest, the minimum number of iterations of the outermost loop per thread is two.
  • max-ssa-name-query-depth โ€” The max recursion depth when querying properties of SSA names in things like fold routines ๐ŸŒ€ One level of recursion means following a use-def chain.
  • hsa-gen-debug-stores โ€” Enables emission of special debug stores inside HSA kernels, which the libgomp plugin then reads and reports ๐Ÿ“ These stores are not generated by default, so use --param hsa-gen-debug-stores=1 to turn them on.
  • max-speculative-devirt-maydefs โ€” The maximum number of may-defs GCC analyzes while hunting for a must-def that specifies the dynamic type of an object invoking a virtual call. If it finds one, it may be able to devirtualize speculatively ๐Ÿ”ฎ
  • max-vrp-switch-assertions โ€” The maximum number of assertions added along the default edge of a switch statement during VRP ๐Ÿ”€
  • unroll-jam-min-percent โ€” The minimum percentage of memory references that must get optimized away for the unroll-and-jam transformation to be considered worth it ๐Ÿ’ธ
  • unroll-jam-max-unroll โ€” The maximum number of times the outer loop can be unrolled by the unroll-and-jam transformation ๐Ÿ”
  • max-rtl-if-conversion-unpredictable-cost โ€” The maximum cost allowed for the sequence the RTL if-conversion pass would generate for a branch that's considered unpredictable ๐ŸŽฒ
  • max-variable-expansions-in-unroller โ€” If -fvariable-expansion-in-unroller is used, this is the maximum number of times a single variable gets expanded during loop unrolling ๐Ÿ“ˆ
  • tracer-min-branch-probability-feedback โ€” Stops forward growth if the probability of the best edge drops below this threshold (in percent). It's used when profile feedback is available ๐Ÿ“Š
  • partial-inlining-entry-probability โ€” The maximum probability of the entry BB of a split region (in percent, relative to the entry BB of the function) that still lets partial inlining happen ๐Ÿงฉ
  • max-tracked-strlens โ€” The maximum number of strings the strlen optimization pass will track lengths for ๐Ÿงถ
  • gcse-after-reload-partial-fraction โ€” The threshold ratio for performing partial redundancy elimination after reload โ™ป๏ธ
  • gcse-after-reload-critical-fraction โ€” The threshold ratio of critical edge execution counts that permits redundancy elimination after reload ๐Ÿงฎ
  • max-loop-header-insns โ€” The maximum number of insns in a loop header that gets duplicated by the copy loop headers pass ๐Ÿชž
  • vect-epilogues-nomask โ€” Enables loop epilogue vectorization using a smaller vector size ๐ŸŒธ
  • slp-max-insns-in-bb โ€” The maximum number of instructions in a basic block that can be considered for SLP vectorization ๐Ÿงบ
  • avoid-fma-max-bits โ€” The maximum number of bits for which GCC avoids creating FMAs โœ–๏ธ
  • sms-loop-average-count-threshold โ€” A threshold on the average loop count the swing modulo scheduler considers ๐ŸŒŠ
  • sms-dfa-history โ€” The number of cycles the swing modulo scheduler looks at when checking for conflicts using DFA ๐Ÿ•ฐ๏ธ
  • hot-bb-count-fraction โ€” The fraction of the maximal repetition count of a basic block in the program that a block needs to reach to be considered hot (used in non-LTO mode) ๐Ÿ”ฅ
  • max-inline-insns-recursive-auto โ€” The maximum number of instructions a non-inline function can grow to via recursive inlining ๐ŸŒฑ
  • graphite-allow-codegen-errors โ€” Whether codegen errors should be ICEs when -fchecking is on ๐Ÿ™ˆ
  • sms-max-ii-factor โ€” A factor for tuning the upper bound the swing modulo scheduler uses when scheduling a loop ๐ŸŽ›๏ธ
  • lra-max-considered-reload-pseudos โ€” The max number of reload pseudos considered while spilling a non-reload pseudo ๐Ÿฅž
  • max-pow-sqrt-depth โ€” The maximum depth of sqrt chains used when synthesizing exponentiation by a real constant ๐Ÿงฎ
  • max-dse-active-local-stores โ€” The maximum number of active local stores in RTL dead store elimination ๐Ÿ—‘๏ธ
  • asan-instrument-allocas โ€” Enables ASan protection for allocas and VLAs ๐Ÿ›ก๏ธ
  • max-iterations-computation-cost โ€” The bound on the cost of an expression used to compute the number of iterations ๐Ÿ’ญ
  • max-isl-operations โ€” The maximum number of isl operations. 0 means unlimited โ™พ๏ธ
  • graphite-max-arrays-per-scop โ€” The maximum number of arrays per scop ๐Ÿ“ฆ
  • max-vartrack-reverse-op-size โ€” The max size of a loc list for which reverse ops should be added ๐Ÿงญ
  • unlikely-bb-count-fraction โ€” The minimum fraction of profile runs a basic block's execution count must reach so it isn't considered unlikely ๐Ÿ™…โ€โ™€๏ธ
  • tracer-dynamic-coverage-feedback โ€” The percentage of a function, weighted by execution frequency, that trace formation must cover. It's used when profile feedback is available ๐ŸŽฏ
  • max-inline-recursive-depth-auto โ€” The maximum depth of recursive inlining for non-inline functions ๐Ÿช†
  • fsm-scale-path-stmts โ€” A scale factor applied to the number of statements in a threading path when comparing it to the number of (scaled) blocks ๐Ÿ“
  • fsm-maximum-phi-arguments โ€” The maximum number of arguments a PHI can have before the FSM threader stops trying to thread through its block ๐Ÿšซ
  • uninit-control-dep-attempts โ€” The maximum number of nested calls used to search for control dependencies during uninitialized variable analysis ๐Ÿ”Ž
  • indir-call-topn-profile โ€” Tracks the top N target addresses in the indirect-call profile ๐ŸŽฏ
  • max-once-peeled-insns โ€” The maximum number of insns in a peeled loop that only rolls once ๐ŸŽˆ
  • sra-max-scalarization-size-Osize โ€” The maximum size, in storage units, of an aggregate that should be considered for scalarization when compiling for size ๐Ÿ“
  • fsm-scale-path-blocks โ€” A scale factor applied to the number of blocks in a threading path when comparing it to the number of (scaled) statements ๐Ÿงฎ
  • sched-autopref-queue-depth โ€” A hardware autoprefetcher scheduler model control flag. It sets the number of lookahead cycles the model looks into. At ' ', only the instruction sorting heuristic is enabled ๐Ÿง 
  • loop-versioning-max-inner-insns โ€” The maximum number of instructions an inner loop can have before the loop versioning pass considers it too big to copy ๐Ÿช†
  • loop-versioning-max-outer-insns โ€” The maximum number of instructions an outer loop can have before the loop versioning pass considers it too big to copy. Instructions in inner loops that directly benefit from versioning don't count toward this total ๐Ÿช†
  • ssa-name-def-chain-limit โ€” The maximum number of SSA_NAME assignments to follow when figuring out a property of a variable, like its value. This caps how many iterations or recursive calls GCC makes when optimizing certain statements or checking whether they're valid before issuing diagnostics ๐Ÿ”—

โœจ Program Instrumentation Options โœจ

GCC supports a bunch of command-line options that tell it to add run-time instrumentation to the code it normally generates ๐ŸŽ€ Instrumentation can be used for profiling stats to find program hot spots, code coverage analysis, or profile-guided optimizations ๐Ÿ“Š Another kind is run-time checking, which catches programming errors like invalid pointer dereferences or out-of-bounds array accesses, plus sneaky attacks like stack smashing or C++ vtable hijacking ๐Ÿšจ There's also a general hook that can be used to implement other forms of tracing or function-level instrumentation for debug or program analysis purposes ๐Ÿฆ‹

  • -p, -pg โ€” okay bestie, these make your code spit out extra profiling info โœจ -p is for the prof analysis program and -pg is for gprof ๐Ÿ”ฅ. You HAVE to use this when compiling the source files you want data about, and you have to use it when linking too, no skipping ๐Ÿ™ˆ

You can also use the function attribute no_instrument_function to stop profiling individual functions when compiling with these options ๐Ÿ’…

  • -fprofile-arcs โ€” this one instruments the program flow arcs ๐Ÿฆ‹ While the program runs, it keeps count of how many times each branch and call gets executed, and how many times each one is taken or returns ๐ŸŒธ On targets that support constructors with priority support, profiling handles constructors, destructors, and C++ constructors (and destructors) of classes used as the type of a global variable properly ๐Ÿ’–

When your compiled program exits, it saves this data to a file called auxname.gcda for each source file ๐Ÿ’œ That data can be used for profile-directed optimizations (-fbranch-probabilities) or for test coverage analysis (-ftest-coverage) ๐ŸŽ€ Each object file's auxname comes from the name of the output file, but only if you explicitly specified one and it's not the final executable. Otherwise it's the basename of the source file. Either way, any suffix gets removed. So you get foo.gcda for input file dir/foo.c, or dir/foo.gcda for output file specified as -o dir/foo.o ๐Ÿงš

  • --coverage โ€” this one's the all-in-one for coverage-instrumented code, for both compiling and linking ๐Ÿ‘‘ It's a synonym for -fprofile-arcs -ftest-coverage (when compiling) and -lgcov (when linking). Check the docs for those options for more deets ๐Ÿซถ The whole workflow goes like this:
    • Compile the source files with -fprofile-arcs plus optimization and code generation options. For test coverage analysis, add the -ftest-coverage option too. You don't need to profile every source file in a program ๐Ÿ’…
    • Compile the source files additionally with -fprofile-abs-path to create absolute path names in the .gcno files. This lets gcov find the correct sources in projects where compilations happen with different working directories ๐Ÿ—บ๏ธ
    • Link your object files with -lgcov or -fprofile-arcs (the latter implies the former) ๐Ÿ”—
    • Run the program on a representative workload to generate the arc profile information. You can do this any number of times ๐Ÿ” You can run concurrent instances of your program, and as long as the file system supports locking, the data files will be correctly updated ๐Ÿ”’ Unless a strict ISO C dialect option is in effect, fork calls are detected and correctly handled without double counting ๐Ÿด
    • For profile-directed optimizations, compile the source files again with the same optimization and code generation options plus -fbranch-probabilities โœจ
    • For test coverage analysis, use gcov to produce human-readable info from the .gcno and .gcda files. Refer to the gcov docs for further info ๐Ÿค“

With -fprofile-arcs, for each function of your program GCC creates a program flow graph, then finds a spanning tree for that graph ๐ŸŒณ Only arcs that are not on the spanning tree have to be instrumented: the compiler adds code to count how many times those arcs are executed. When an arc is the only exit or only entrance to a block, the instrumentation code can go right into that block. Otherwise, a new basic block has to be created to hold it ๐Ÿง 

  • -ftest-coverage โ€” produces a notes file that the gcov code-coverage utility can use to show program coverage ๐Ÿ“ Each source file's note file is called auxname.gcno. Check out the -fprofile-arcs option up above for what auxname means and how to generate test coverage data ๐Ÿฆ‹ Coverage data matches your source files more closely if you don't optimize ๐Ÿ‘€
  • -fprofile-abs-path โ€” automatically converts relative source file names to absolute path names in the .gcno files ๐Ÿ—บ๏ธ This lets gcov find the correct sources in projects where compilations happen with different working directories ๐Ÿ’…
  • -fprofile-dir=path โ€” sets the directory where profile data files get searched for, to path ๐Ÿ“‚ This only affects profile data generated by -fprofile-generate, -ftest-coverage, and -fprofile-arcs, and the data used by -fprofile-use, -fbranch-probabilities, and their related options. Absolute and relative paths both work ๐Ÿ™Œ By default GCC uses the current directory, so the profile data file lives in the same directory as the object file. To prevent file name clashes, if the object file name isn't an absolute path, GCC mangles the absolute path of the sourcename.gcda file and uses that as the .gcda file name ๐ŸŒ€

When an executable runs in a massive parallel environment, it's recommended to save profiles to different folders. You can do that with variables in path that get exported at run-time ๐Ÿงš

  • %p โ€” process ID
  • %q{VAR} โ€” value of environment variable VAR
  • -fprofile-generate and -fprofile-generate=path โ€” these turn on the options usually used for instrumenting an app, so you get a profile you can use later for recompiling with profile feedbackโ€“based optimization ๐Ÿ”ฅ You must use -fprofile-generate both when compiling AND when linking your program ๐Ÿซต

The following options get enabled: -fprofile-arcs, -fprofile-values, -finline-functions, and -fipa-bit-cp ๐Ÿ’œ

If path is specified, GCC looks there to find the profile feedback data files. See -fprofile-dir ๐Ÿ“‚

To optimize the program based on the collected profile info, use -fprofile-use ๐Ÿ‘‘

  • -fprofile-update=method โ€” alters the update method for an app instrumented for profile feedbackโ€“based optimization ๐Ÿงต The method argument should be one of single, atomic or prefer-atomic. The first one is useful for single-threaded apps, while the second one prevents profile corruption by emitting thread-safe code ๐Ÿ›ก๏ธ
Warning: When an application doesn't properly join all of its threads (or creates a detached thread), a profile file can still get corrupted. ๐Ÿ’€

Using prefer-atomic gets transformed into either atomic (when a target supports it) or single otherwise. The GCC driver automatically selects prefer-atomic when -pthread is present in the command line โœจ

  • -fprofile-filter-files=regex โ€” instruments only functions from files whose names match any regular expression (separated by a semicolon) ๐Ÿ”

For example, -fprofile-filter-files=main.c;module.*.c will instrument only main.c and all C files starting with module ๐Ÿงš

  • -fprofile-exclude-files=regex โ€” instruments only functions from files whose names do not match all the regular expressions (separated by a semicolon) ๐Ÿ™…โ€โ™€๏ธ

For example, -fprofile-exclude-files=/usr/* will prevent instrumentation of all files located in the /usr/ folder ๐Ÿ™ˆ

  • -fsanitize=address โ€” enables AddressSanitizer, a fast memory error detector ๐Ÿ•ต๏ธ Memory access instructions get instrumented to catch out-of-bounds and use-after-free bugs ๐Ÿ’€ This option also enables -fsanitize-address-use-after-scope. For more details, see https://github.com/google/sanitizers/wiki/AddressSanitizer. The run-time behavior can be influenced with the ASAN_OPTIONS environment variable. When set to "help=1", the available options get shown at startup of the instrumented program. For a list of supported options, see https://github.com/google/sanitizers/wiki/AddressSanitizerFlags#run-time-flags. This option cannot be combined with -fsanitize=thread ๐Ÿšซ
  • -fsanitize=kernel-address โ€” enables AddressSanitizer for the Linux kernel ๐Ÿง For more details, see https://github.com/google/kasan/wiki.
  • -fsanitize=pointer-compare โ€” instruments comparison operations (<, <=, >, >=) with pointer operands ๐Ÿ‘€ This option must be combined with either -fsanitize=kernel-address or -fsanitize=address. It cannot be combined with -fsanitize=thread.

Note: By default the check is disabled at run time. To enable it, add "detect_invalid_pointer_pairs=2" to the ASAN_OPTIONS environment variable. Using "detect_invalid_pointer_pairs=1" detects invalid operations only when both pointers are non-null ๐Ÿซฃ

  • -fsanitize=pointer-subtract โ€” instruments subtraction with pointer operands ๐Ÿงฎ This option must be combined with either -fsanitize=kernel-address or -fsanitize=address. It cannot be combined with -fsanitize=thread.

Note: By default the check is disabled at run time. To enable it, add "detect_invalid_pointer_pairs=2" to the ASAN_OPTIONS environment variable. Using "detect_invalid_pointer_pairs=1" detects invalid operations only when both pointers are non-null ๐Ÿซฃ

Note that sanitized atomic builtins cannot throw exceptions when operating on invalid memory addresses with non-call exceptions (-fnon-call-exceptions) โš ๏ธ

  • -fsanitize=leak โ€” enables LeakSanitizer, a memory leak detector ๐Ÿ’ง This option only matters for linking executables, and only when the executable is linked against a library that overrides malloc and other allocator functions. For more details, see https://github.com/google/sanitizers/wiki/AddressSanitizerLeakSanitizer. The run-time behavior can be influenced with the LSAN_OPTIONS environment variable. This option cannot be combined with -fsanitize=thread.
  • -fsanitize=undefined โ€” enables UndefinedBehaviorSanitizer, a fast undefined behavior detector ๐Ÿค“ Various computations get instrumented to detect undefined behavior at runtime. For more details, see https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html. The run-time behavior can be influenced with the UBSAN_OPTIONS environment variable. Current suboptions are:
  • -fsanitize=shift โ€” okay bestie, this one checks that the result of a shift isn't undefined ๐ŸŒธ What counts as undefined is a little different in C vs C++, and between ISO C90 and C99, etc. ๐Ÿ’… It has two suboptions: -fsanitize=shift-base and -fsanitize=shift-exponent.
  • -fsanitize=shift-exponent โ€” checks that the second argument of a shift is not negative and is smaller than the precision of the promoted first argument ๐Ÿฆ‹
  • -fsanitize=shift-base โ€” if the second argument is in range, it checks that the shift result isn't undefined โœจ Same C vs C++ and C90 vs C99 caveat applies, so no cap, read the room ๐Ÿ‘‘
  • -fsanitize=integer-divide-by-zero โ€” catches integer division by zero, plus INT_MIN / -1 division ๐Ÿ’€
  • -fsanitize=unreachable โ€” the compiler swaps the __builtin_unreachable call for a diagnostics message call instead ๐Ÿงš
Reaching the __builtin_unreachable call is still undefined behavior. ๐Ÿ˜ญ
  • -fsanitize=vla-bound โ€” checks that the size of a variable length array is positive ๐Ÿ“
  • -fsanitize=null โ€” pointer checking, the main character of pointer safety ๐Ÿ‘‘ An app built with this will throw an error when it:
    • tries to dereference a NULL pointer,
    • binds a reference (possibly an rvalue reference) to a NULL pointer, or
    • invokes a method on an object pointed to by a NULL pointer.
  • -fsanitize=return โ€” return statement checking ๐ŸŽ€ Programs built with it error out when the end of a non-void function is reached without actually returning a value. This option works in C++ only.
  • -fsanitize=signed-integer-overflow โ€” checks that the results of +, *, and both unary and binary - don't overflow in signed arithmetic ๐Ÿ”ฅ Integer promotion rules totally count here, so this is not an overflow:
signed char a = SCHAR_MAX;
a++;
  • -fsanitize=bounds โ€” instruments array bounds, so various out of bounds accesses get caught ๐ŸŒˆ Flexible array members, flexible array member-like arrays, and initializers of variables with static storage are not instrumented, so those are skipped.
  • -fsanitize=bounds-strict โ€” the stricter version ๐Ÿ’ช Most out of bounds accesses are detected, including flexible array members and flexible array member-like arrays. Initializers of variables with static storage still aren't instrumented.
  • -fsanitize=alignment โ€” checks pointer alignment when pointers are dereferenced, when a reference is bound to an insufficiently aligned target, or when a method or constructor is invoked on an insufficiently aligned object ๐Ÿงธ
  • -fsanitize=object-size โ€” instruments memory references using the __builtin_object_size function ๐Ÿฆ‹ Various out of bounds pointer accesses get detected.
  • -fsanitize=float-divide-by-zero โ€” detects floating-point division by zero ๐ŸŒธ Unlike other similar options, this one is not enabled by -fsanitize=undefined, since float division by zero can be a totally legit way to get infinities and NaNs ๐Ÿ™ˆ
  • -fsanitize=float-cast-overflow โ€” checks floating-point to integer conversions and that the result doesn't overflow ๐Ÿ”ฅ Unlike other similar options, this is not enabled by -fsanitize=undefined. It also doesn't work well with FE_INVALID exceptions enabled. ๐Ÿ’€
  • -fsanitize=nonnull-attribute โ€” instruments calls to check that null values aren't passed to arguments marked as requiring a non-null value by the nonnull function attribute ๐Ÿซถ
  • -fsanitize=returns-nonnull-attribute โ€” instruments return statements in functions marked with the returns_nonnull function attribute, to catch null values being returned from those functions ๐ŸŒˆ
  • -fsanitize=bool โ€” instruments loads from bool ๐Ÿ“ If a value other than 0/1 gets loaded, a run-time error is issued.
  • -fsanitize=enum โ€” instruments loads from an enum type โœจ If a value outside the range of values for that enum type gets loaded, a run-time error is issued.
  • -fsanitize=vptr โ€” C++ vibes ๐Ÿงš Instruments C++ member function calls, member accesses, and some conversions between pointers to base and derived classes, to verify the referenced object has the correct dynamic type.
  • -fsanitize=pointer-overflow โ€” instruments pointer arithmetic ๐Ÿ’œ If pointer arithmetic overflows, a run-time error is issued.
  • -fsanitize=builtin โ€” instruments arguments to selected builtin functions ๐Ÿ”ฅ If an invalid value gets passed to one of those arguments, a run-time error is issued. E.g. passing 0 as the argument to __builtin_ctz or __builtin_clz invokes undefined behavior, and this option diagnoses it ๐Ÿ™ˆ

While -ftrapv causes traps for signed overflows to be emitted, -fsanitize=undefined gives a diagnostic message ๐Ÿ’… This currently works only for the C family of languages ๐ŸŒธ


  • -fno-sanitize=all โ€” disables all previously enabled sanitizers ๐Ÿงน
-fsanitize=all is not allowed, as some sanitizers cannot be used together. ๐Ÿ˜ญ
  • -fasan-shadow-offset=number โ€” forces GCC to use a custom shadow offset in AddressSanitizer checks ๐Ÿงช It's handy for experimenting with different shadow memory layouts in Kernel AddressSanitizer ๐Ÿฆ‹
  • -fsanitize-sections=s1,s2,... โ€” sanitizes global variables in selected user-defined sections ๐ŸŽ€ si may contain wildcards.
  • -fsanitize-recover[=opts] โ€” okay this one's a whole saga ๐ŸŒˆ -fsanitize-recover= controls the error recovery mode for the sanitizers in the comma-separated list of opts. Turn it on for a sanitizer and it tries to keep the program running as if no error happened. That means multiple runtime errors can get reported in one run, and the exit code can say success even when errors were reported. The -fno-sanitize-recover= option changes this: only the first detected error is reported, and then the program exits with a non-zero exit code ๐Ÿ’€

Right now this only works for -fsanitize=undefined (and its suboptions, except for -fsanitize=unreachable and -fsanitize=return), -fsanitize=float-cast-overflow, -fsanitize=float-divide-by-zero, -fsanitize=bounds-strict, -fsanitize=kernel-address and -fsanitize=address. For these sanitizers, error recovery is turned on by default, except for -fsanitize=address, where this feature is experimental โš ๏ธ -fsanitize-recover=all and -fno-sanitize-recover=all are also accepted: the former enables recovery for all sanitizers that support it, and the latter disables recovery for all sanitizers that support it ๐Ÿ‘‘

Even if a recovery mode is turned on compiler-side, it also needs to be enabled on the runtime library side, otherwise the failures are still fatal ๐Ÿ˜ญ The runtime library defaults to halt_on_error=0 for ThreadSanitizer and UndefinedBehaviorSanitizer, while the default value for AddressSanitizer is halt_on_error=1. You can override this by setting the halt_on_error flag in the corresponding environment variable ๐Ÿซถ

Syntax without an explicit opts parameter is deprecated ๐Ÿ™ˆ It's equivalent to specifying an opts list of:

undefined,float-cast-overflow,float-divide-by-zero,bounds-strict
  • -fsanitize-address-use-after-scope โ€” enables sanitization of local variables to catch use-after-scope bugs ๐Ÿ” This option sets -fstack-reuse to none.
  • -fsanitize-undefined-trap-on-error โ€” instructs the compiler to report undefined behavior using __builtin_trap rather than a libubsan library routine ๐ŸŒธ The advantage? The libubsan library isn't needed and doesn't get linked in, so this is usable even in freestanding environments ๐Ÿงš
  • -fsanitize-coverage=trace-pc โ€” enables coverage-guided fuzzing code instrumentation ๐ŸŽ€ It inserts a call to __sanitizer_cov_trace_pc into every basic block.
  • -fsanitize-coverage=trace-cmp โ€” enables dataflow-guided fuzzing code instrumentation ๐Ÿงช It inserts calls to:
    • __sanitizer_cov_trace_cmp1, __sanitizer_cov_trace_cmp2, __sanitizer_cov_trace_cmp4 or __sanitizer_cov_trace_cmp8 for integral comparisons where both operands are variable,
    • __sanitizer_cov_trace_const_cmp1, __sanitizer_cov_trace_const_cmp2, __sanitizer_cov_trace_const_cmp4 or __sanitizer_cov_trace_const_cmp8 for integral comparisons with one operand constant,
    • __sanitizer_cov_trace_cmpf or __sanitizer_cov_trace_cmpd for float or double comparisons, and
    • __sanitizer_cov_trace_switch for switch statements.
  • -fcf-protection=[full|branch|return|none|check] โ€” enables code instrumentation of control-flow transfers to boost program security ๐Ÿ›ก๏ธ It checks that the target addresses of control-flow transfer instructions (such as indirect function calls, function returns, and indirect jumps) are valid, which stops the flow of control from getting diverted to an unexpected target ๐Ÿ’– This is meant to protect against threats like Return-oriented Programming (ROP), and similarly call/jmp-oriented programming (COP/JOP) ๐Ÿ‘‘

Okay so branch tells the compiler to check that control-flow transfers are valid at indirect branch instructions, aka call/jmp instructions ๐Ÿฆ‹. return does that same check when a function returns ๐Ÿ”. And full is the bestie combo, an alias for asking for both branch and return ๐Ÿ‘‘. none just turns the instrumentation off ๐Ÿ’€.

check is for the final link with link-time optimization (LTO) โœจ. If LTO object files were compiled with different -fcf-protection values, you get an error, so double-check your builds ๐Ÿ™ˆ. check gets ignored at compile time, so it's not doing anything there ๐Ÿ’….

The macro __CET__ gets defined whenever you use -fcf-protection ๐Ÿ’œ. Its first bit is set to 1 for branch, and its second bit is set to 1 for return ๐ŸŒˆ.

You can also slap the nocf_check attribute on stuff to pick which functions and calls get skipped from instrumentation ๐ŸŽ€.

Right now the x86 GNU/Linux target has an implementation based on Intel Control-flow Enforcement Technology (CET), and it works on i686 processors or newer ๐Ÿ–ฅ๏ธ.

NOTE: In Ubuntu 19.10 and later versions, -fcf-protection is enabled by default for C, C++, ObjC, ObjC++, if none of -fno-cf-protection nor -fcf-protection=* are found. ๐Ÿซถ
  • -fstack-protector โ€” Emit extra code to check for buffer overflows, like stack smashing attacks ๐Ÿ›ก๏ธ. It adds a guard variable to functions with vulnerable objects, which includes functions that call alloca and functions with buffers larger than 8 bytes. The guards get set up when a function is entered and checked when it exits. If a guard check fails, an error message is printed and the program exits ๐Ÿ’€.
  • -fstack-protector-all โ€” Same energy as -fstack-protector, except now all functions are protected ๐Ÿ‘‘.
  • -fstack-protector-strong โ€” Like -fstack-protector, but it adds more functions to the protected list: the ones with local array definitions, or ones that have references to local frame addresses ๐Ÿ’–.
  • -fstack-protector-explicit โ€” Like -fstack-protector, but it only protects the functions that have the stack_protect attribute ๐ŸŽฏ.
  • -fstack-check โ€” Generates code to verify that you don't go beyond the boundary of the stack ๐Ÿงš. You should use this if you're running in an environment with multiple threads. In a single-threaded environment you rarely need it, since stack overflow is automatically detected on nearly all systems when there's only one stack ๐Ÿ™„.
    • Heads up: this switch doesn't actually do the checking. The operating system or the language runtime has to do that. The switch just generates code so they can see the stack being extended ๐Ÿ”.
    • You can add a string parameter too: no means no checking, generic forces the old-style checking, and specific uses the best checking method and is equivalent to bare -fstack-check โœจ.
    • Old-style checking is a generic mechanism. It needs no specific target support in the compiler, but it comes with these drawbacks:
      1. Modified allocation strategy for large objects: they're always allocated dynamically if their size goes over a fixed threshold. This may change the semantics of some code ๐Ÿ˜ฌ.
      2. Fixed limit on the size of the static frame of functions: when it's topped by a particular function, stack checking isn't reliable and the compiler issues a warning ๐Ÿšจ.
      3. Inefficiency: the modified allocation strategy plus the generic implementation means code performance takes a hit ๐ŸŒ.
    • Old-style stack checking is also the fallback method for specific if no target support has been added in the compiler ๐Ÿ”„.
    • -fstack-check= was made for Ada's needs, to detect infinite recursion and stack overflows. specific is an excellent choice when compiling Ada code ๐Ÿ‘ธ. It's not generally enough to protect against stack-clash attacks, though. For that, you want -fstack-clash-protection ๐Ÿ›ก๏ธ.
  • -fstack-clash-protection โ€” Generates code to prevent stack clash style attacks. With this enabled, the compiler only allocates one page of stack space at a time, and each page is accessed right after allocation. That way, allocations can't jump over any stack guard page the operating system provides ๐Ÿงฑ.
    • Most targets don't fully support stack clash protection. On the ones that do, -fstack-clash-protection protects dynamic stack allocations ๐Ÿ’…. It may also give limited protection for static stack allocations if the target supports -fstack-check=specific ๐ŸŒธ.
    • NOTE: In Ubuntu 19.10 and later versions, -fstack-clash-protection is enabled by default for C, C++, ObjC, ObjC++, unless -fno-stack-clash-protection is found ๐ŸŒˆ.
  • -fstack-limit-register=reg, -fstack-limit-symbol=sym, -fno-stack-limit โ€” Generates code to make sure the stack doesn't grow beyond a certain value, either the value of a register or the address of a symbol ๐Ÿšง. If a bigger stack is needed, a signal gets raised at run time. On most targets the signal goes off before the stack overruns the boundary, so you can catch it without taking special precautions ๐Ÿฆ‹.
    • For example, say the stack starts at absolute address 0x80000000 and grows downwards. You can use the flags -fstack-limit-symbol=__stack_limit and -Wl,--defsym,__stack_limit=0x7ffe0000 to enforce a stack limit of 128KB ๐Ÿ“. Just know this may only work with the GNU linker โš ๏ธ.
    • You can locally override stack limit checking with the no_stack_limit function attribute ๐Ÿ™…โ€โ™€๏ธ.
  • -fsplit-stack โ€” Generates code that automatically splits the stack before it overflows ๐Ÿช„. The result is a discontiguous stack that can only overflow if the program can't allocate any more memory. This is most useful with threaded programs, because you no longer have to calculate a good stack size for each thread ๐Ÿงต. It's currently only implemented for x86 targets running GNU/Linux ๐Ÿ–ฅ๏ธ.
    • When code compiled with -fsplit-stack calls code compiled without -fsplit-stack, there may not be much stack space left for the latter code to run in ๐Ÿ˜ฐ. If compiling all code, library code included, with -fsplit-stack isn't an option, the linker can fix up these calls so that code compiled without -fsplit-stack always gets a large stack. This is implemented in the gold linker in GNU binutils release 2.21 and later ๐Ÿ”ง.
  • -fvtable-verify=[std|preinit|none] โ€” This one is C++ only ๐Ÿ’œ. It turns on (or off, if you use -fvtable-verify=none) the security feature that checks at run time, for every virtual call, that the vtable pointer used for the call is valid for the type of the object and hasn't been corrupted or overwritten ๐Ÿ”. If an invalid vtable pointer gets detected at run time, an error is reported and execution of the program halts right away ๐Ÿ›‘.
    • This option builds run-time data structures at program startup, and those are used to verify the vtable pointers โฐ. The std and preinit values control when those data structures get built. In both cases, they're built before execution reaches main ๐Ÿ. -fvtable-verify=std builds them after shared libraries have been loaded and initialized. -fvtable-verify=preinit builds them before shared libraries have been loaded and initialized ๐Ÿ“š.
    • If this option shows up more than once on the command line with different values, none takes the highest priority over both std and preinit, and preinit takes priority over std ๐Ÿ‘‘.
  • -fvtv-debug โ€” Used together with -fvtable-verify=std or -fvtable-verify=preinit, this makes the debug versions of the runtime functions for vtable verification get called ๐Ÿ›. It also makes the compiler log which vtable pointers it finds for each class ๐Ÿ“. That info gets written to a file named vtv_set_ptr_data.log in the directory named by the environment variable VTV_LOGS_DIR if it's defined, or in the current working directory otherwise ๐Ÿ“.
    • Note: this feature appends data to the log file. If you want a fresh log file, delete any existing one first ๐Ÿงน.
  • -fvtv-counts โ€” A debugging flag ๐Ÿ”. Used together with -fvtable-verify=std or -fvtable-verify=preinit, it makes the compiler keep track of the total number of virtual calls it encounters and the number of verifications it inserts ๐Ÿ”ข. It also counts how many calls to certain run-time library functions it inserts, and logs that info for each compilation unit ๐Ÿ“Š. The compiler writes this to a file named vtv_count_data.log in the directory named by VTV_LOGS_DIR if that's defined, or the current working directory otherwise. It also counts the size of the vtable pointer sets for each class and writes that to vtv_class_set_sizes.log in the same directory ๐Ÿ“‚.
    • Note: this feature appends data to the log files. To get fresh log files, delete any existing ones ๐Ÿ—‘๏ธ.
  • -finstrument-functions โ€” Generates instrumentation calls for function entry and exit ๐Ÿ”ฌ. Just after a function is entered, and just before it exits, the following profiling functions get called with the address of the current function and its call site ๐Ÿ“ก. (On some platforms, __builtin_return_address doesn't work beyond the current function, so the call site info may not be available to the profiling functions otherwise ๐Ÿ™ˆ.)
void __cyg_profile_func_enter (void *this_fn,
                               void *call_site);
void __cyg_profile_func_exit  (void *this_fn,
                               void *call_site);

The first argument is the address of the start of the current function, which can be looked up exactly in the symbol table ๐Ÿ—บ๏ธโœจ.

Okay so this instrumentation also happens for functions that get expanded inline into other functions ๐Ÿ‘€โœจ The profiling calls basically mark where the inline function is conceptually entered and exited. That means addressable versions of those functions still have to exist, bestie ๐Ÿซถ If every single use of a function gets expanded inline, that can mean extra code size ๐Ÿ’€ And if you use extern inline in your C code, you have to provide an addressable version of those functions. (This is normally the case anyway, but if you get lucky and the optimizer always inlines them, you might have gotten away without providing static copies ๐Ÿ™ˆ)

A function can be given the attribute no_instrument_function, and then this instrumentation just isn't done for it ๐Ÿ’… This is useful for things like the profiling functions above, high-priority interrupt routines, and any functions the profiling functions can't safely be called from. Think signal handlers, if the profiling routines generate output or allocate memory ๐Ÿšจ

  • -finstrument-functions-exclude-file-list=file,file,... โ€” Okay, this one lets you make a list of files whose functions get skipped by -finstrument-functions ๐Ÿฆ‹ If the file with a function's definition matches one of the entries, that function isn't instrumented. The matching is done on substrings, so if your file value is a substring of the file name, it counts as a match.

For example:

-finstrument-functions-exclude-file-list=/bits/stl,include/sys

That excludes any inline function defined in files whose pathnames contain /bits/stl or include/sys ๐ŸŒธ

If, for some reason, you want to include a comma inside one of the sym values, write two commas in a row (,,). For example, -finstrument-functions-exclude-file-list=',,tmp' (note the single quotes around the option, so your shell doesn't mess it up ๐Ÿ™ˆ).

  • -finstrument-functions-exclude-function-list=sym,sym,... โ€” This is basically the same vibe as the file list, except this one excludes by function name instead ๐Ÿงš The name it matches is the user-visible one, like vector<int> blah(const vector<int> &), not the internal mangled name (like _Z4blahRSt6vectorIiSaIiEE). Matching is also substring-based: if your sym is a substring of the function name, it's a match. For C99 and C++ extended identifiers, the function name has to be written in UTF-8, not with universal character names ๐Ÿ’œ
  • -fpatchable-function-entry=N[,M] โ€” This one generates N NOPs right at the start of each function, with the function entry point sitting before the Mth NOP โœจ If M is left out, it defaults to 0, so the entry point is the address right at the first NOP. Those NOPs reserve extra space that you can patch instrumentation into at run time, as long as the code segment is writable ๐Ÿ”ฅ You control the amount of space indirectly through the number of NOPs. The NOP instruction used matches the one emitted by the internal GCC back-end interface gen_nop. This behavior is target-specific and may also depend on the architecture variant and/or other compilation options ๐ŸŒˆ

For run-time identification, the starting addresses of these areas (which correspond to their function entries minus M) are also collected in the __patchable_function_entries section of the resulting binary ๐ŸŽ€

Note that the value of __attribute__ ((patchable_function_entry (N,M))) takes precedence over the command-line option -fpatchable-function-entry=N,M ๐Ÿ‘‘ This is handy for making the area bigger, or removing it completely, on a single function. If N=0, no pad location is recorded.

The NOP instructions are inserted at (and maybe before, depending on M) the function entry address, even before the prologue ๐Ÿซถ


โœจ Options Controlling the Preprocessor โœจ

These options control the C preprocessor, which runs on each C source file before the actual compilation ๐Ÿ’–

If you use the -E option, nothing is done except preprocessing. Some of these options only make sense together with -E, because they make the preprocessor output unsuitable for actual compilation ๐Ÿ™ˆ

In addition to the options listed here, there are a bunch of options that control search paths for include files, documented in Directory Options. Options to control preprocessor diagnostics are listed in Warning Options ๐Ÿฆ‹

  • -D name โ€” Predefine name as a macro, with the definition 1 ๐Ÿ“
  • -D name=definition โ€” The contents of definition get tokenized and processed as if they showed up during translation phase three in a #define directive. Heads up: the definition gets cut off at any embedded newline characters ๐Ÿ˜ญ

If you're calling the preprocessor from a shell (or something shell-like), you might need the shell's quoting syntax to protect characters like spaces that mean something to the shell ๐Ÿ’…

Wanna define a function-like macro on the command line? Write its argument list in surrounding parentheses before the equals sign (if there is one). Parentheses mean stuff to most shells, so you should quote the option. With sh and csh, -D'name(args...)=definition' works ๐ŸŒธ

-D and -U options get processed in the order they show up on the command line. All -imacros file and -include file options get processed after all the -D and -U options ๐Ÿงš

  • -U name โ€” Cancel any previous definition of name, whether it was built in or provided with a -D option ๐Ÿ’œ
  • -include file โ€” Processes file as if #include "file" appeared as the very first line of the primary source file ๐ŸŽ€ The difference is that the first directory searched for file is the preprocessor's working directory, not the directory containing the main source file. If it's not found there, it's searched for in the rest of the #include "..." search chain as normal.

If you give multiple -include options, the files get included in the order they appear on the command line โœจ

  • -imacros file โ€” Exactly like -include, except any output produced by scanning file gets thrown away. The macros it defines stay defined. This lets you grab all the macros from a header without also processing its declarations ๐Ÿ“

All files specified by -imacros are processed before all files specified by -include โญ

  • -undef โ€” Don't predefine any system-specific or GCC-specific macros. The standard predefined macros stay defined ๐Ÿ™…โ€โ™€๏ธ
  • -pthread โ€” Defines additional macros required for using the POSIX threads library ๐Ÿงต You should use this option consistently for both compilation and linking. It's supported on GNU/Linux targets, most other Unix derivatives, and also on x86 Cygwin and MinGW targets ๐Ÿ‘‘
  • -M โ€” Instead of outputting the preprocessed result, this outputs a rule suitable for make describing the dependencies of the main source file ๐Ÿ”ฅ The preprocessor outputs one make rule containing the object file name for that source file, a colon, and the names of all the included files. That includes ones coming from -include or -imacros command-line options.

Unless you specify it explicitly (with -MT or -MQ), the object file name is the source file name with any suffix swapped for the object file suffix, and with any leading directory parts removed ๐Ÿฆ‹ If there are lots of included files, the rule gets split into several lines using \-newline. The rule has no commands.

This option does not suppress the preprocessor's debug output, like -dM. To avoid mixing that debug output with your dependency rules, specify the dependency output file explicitly with -MF, or use an environment variable like DEPENDENCIES_OUTPUT ๐Ÿ˜ญ Debug output still goes to the regular output stream as normal.

Passing -M to the driver implies -E, and suppresses warnings with an implicit -w ๐Ÿ’€

  • -MM โ€” Like -M, but don't mention header files found in system header directories, or header files included (directly or indirectly) from such a header ๐Ÿ™ˆ

This means the choice of angle brackets or double quotes in an #include directive doesn't, on its own, decide whether that header shows up in -MM dependency output โœจ

  • -MF file โ€” When used with -M or -MM, this specifies a file to write the dependencies to ๐ŸŒˆ If you don't give a -MF switch, the preprocessor sends the rules to the same place it would send preprocessed output.

When used with the driver options -MD or -MMD, -MF overrides the default dependency output file ๐Ÿ’–

If file is -, the dependencies get written to stdout ๐Ÿซถ

  • -MG โ€” In conjunction with an option like -M that requests dependency generation, -MG assumes missing header files are generated files. It adds them to the dependency list without raising an error ๐Ÿ› ๏ธ The dependency filename is taken directly from the #include directive, without prepending any path. -MG also suppresses preprocessed output, since a missing header file makes that useless ๐Ÿ™…โ€โ™€๏ธ

This feature is used in automatic updating of makefiles ๐Ÿงš

  • -MP โ€” This option tells CPP to add a phony target for each dependency other than the main file, so each one depends on nothing ๐ŸŒธ These dummy rules work around errors make gives if you remove header files without updating the Makefile to match ๐Ÿ˜ญ

This is typical output:

test.o: test.c test.h

test.h:
  • -MT target โ€” Changes the target of the rule emitted by dependency generation ๐Ÿ’… By default, CPP takes the name of the main input file, deletes any directory components and any file suffix such as .c, and appends the platform's usual object suffix. That result is the target.

An -MT option sets the target to be exactly the string you specify. If you want multiple targets, you can specify them as a single argument to -MT, or use multiple -MT options ๐Ÿฆ‹

For example, -MT '$(objpfx)foo.o' might give:

$(objpfx)foo.o: foo.c
  • -MQ target โ€” Same as -MT, but it quotes any characters that are special to Make ๐Ÿ”ฅ -MQ '$(objpfx)foo.o' gives:
$$(objpfx)foo.o: foo.c

The default target is automatically quoted, as if it were given with -MQ ๐Ÿ’œ

  • -MD โ€” okay bestie, this is -M -MF file but without the implied -E ๐Ÿ’… The driver picks the output name like this: if you gave it an -o, it uses your argument with a .d suffix. If not, it grabs the input file name, strips any directory parts and the suffix, and slaps a .d on the end โœจ
    • If you use -MD together with -E, any -o switch is understood to name the dependency output file. Without -E, each -o names a target object file instead ๐Ÿงš
    • Since -E isn't implied, -MD can make a dependency output file as a side effect of compiling. No extra steps needed, it's giving efficiency ๐Ÿฆ‹
  • -MMD โ€” like -MD, but it only mentions user header files and skips system header files ๐ŸŒธ
  • -fpreprocessed โ€” tells the preprocessor "hey, this is already preprocessed, don't redo it" ๐Ÿ™ˆ It skips macro expansion, trigraph conversion, escaped newline splicing, and most directives. Comments still get recognized and removed, so you can feed it a file preprocessed with -C no problem. In this mode the integrated preprocessor is basically just a tokenizer for the front ends ๐Ÿ’œ
    • -fpreprocessed is implicit if the input file has one of the extensions .i, .ii or .mi. Those are the ones GCC uses for preprocessed files made by -save-temps.
  • -fdirectives-only โ€” when preprocessing, handle directives but do not expand macros. How it behaves depends on -E and -fpreprocessed:
    • With -E, preprocessing is limited to directives like "#define", "#ifdef", and "#error". Macro expansion and trigraph conversion aren't happening. The -dD option also gets implicitly enabled ๐ŸŽ€
    • With -fpreprocessed, predefinition of the command line and most builtin macros is disabled. Contextual macros like "__LINE__" are handled normally. This lets you compile files previously preprocessed with "-E -fdirectives-only" ๐Ÿ‘‘
    • With both -E and -fpreprocessed, the -fpreprocessed rules take precedence. This enables full preprocessing of files previously preprocessed with "-E -fdirectives-only" โœจ
  • -fdollars-in-identifiers โ€” accept $ in identifiers ๐Ÿ’–
  • -fextended-identifiers โ€” accept universal character names in identifiers. This is enabled by default for C99 (and later C standards) and C++ ๐ŸŒˆ
  • -fno-canonical-system-headers โ€” when preprocessing, don't shorten system header paths with canonicalization ๐Ÿงผ
  • -ftabstop=width โ€” sets the distance between tab stops ๐Ÿ“ This helps the preprocessor report correct column numbers in warnings or errors, even if tabs show up on the line. If the value is less than 1 or greater than 100, the option is ignored. The default is 8.
  • -ftrack-macro-expansion[=level] โ€” tracks token locations across macro expansions, so the compiler can show the current macro expansion stack when an error happens inside a macro ๐Ÿ” Heads up: it makes the preprocessor and compiler eat more memory. The level parameter lets you pick how precisely tokens are tracked, so you can dial memory use down if needed.
    • Level 0 deactivates this option.
    • Level 1 tracks token locations in a degraded mode for minimal memory overhead. In this mode, all tokens from expanding an argument of a function-like macro share the same location.
    • Level 2 tracks token locations completely. It's the most memory hungry ๐Ÿฝ๏ธ
    • When given no argument, the default parameter value is 2.
    • Note that "-ftrack-macro-expansion=2" is activated by default.
  • -fmacro-prefix-map=old=new โ€” when preprocessing files in directory old, expands the "__FILE__" and "__BASE_FILE__" macros as if the files lived in directory new instead ๐Ÿ—บ๏ธ Use . for new to turn an absolute path into a relative one, which can give more reproducible, location-independent builds. This also affects "__builtin_FILE()" during compilation. See also -ffile-prefix-map.
  • -fexec-charset=charset โ€” sets the execution character set, used for string and character constants ๐Ÿ”ค The default is UTF-8. charset can be any encoding the system's iconv library routine supports.
  • -fwide-exec-charset=charset โ€” sets the wide execution character set, used for wide string and character constants ๐Ÿช„ The default is UTF-32 or UTF-16, whichever matches the width of "wchar_t". Just like -fexec-charset, charset can be any iconv encoding, but you'll have problems with encodings that don't fit exactly in "wchar_t" โš ๏ธ
  • -finput-charset=charset โ€” sets the input character set, for translating from the input file's character set to the source character set GCC uses ๐ŸŒ If the locale doesn't specify it, or GCC can't get it from the locale, the default is UTF-8. The locale or this command-line option can override that, but right now the command-line option wins if there's a conflict. charset can be any encoding the system's iconv routine supports.
  • -fpch-deps โ€” when using precompiled headers, this makes the dependency-output flags also list files from the precompiled header's dependencies ๐Ÿ“ฆ Without it, only the precompiled header gets listed, not the files used to create it, since those aren't consulted when a PCH is used.
  • -fpch-preprocess โ€” lets you use a precompiled header together with -E ๐Ÿงฉ It inserts a special #pragma, #pragma GCC pch_preprocess "filename", into the output to mark where the precompiled header was found, plus its filename. When -fpreprocessed is in use, GCC recognizes this #pragma and loads the PCH.
    • This option is off by default, because the resulting preprocessed output is only really suitable as input to GCC. It gets switched on by -save-temps.
    • You should not write this #pragma in your own code ๐Ÿ™…โ€โ™€๏ธ But it's safe to edit the filename if the PCH file is available in a different location. The filename can be absolute or relative to GCC's current directory.
  • -fworking-directory โ€” enables linemarkers in the preprocessor output that tell the compiler the working directory at preprocessing time ๐Ÿ—‚๏ธ When it's on, after the initial linemarker the preprocessor emits a second linemarker with the current working directory followed by two slashes. GCC uses that directory, when it's present in the preprocessed input, as the working directory in some debugging information formats. This is implicitly enabled if debugging information is enabled, but you can inhibit it with the negated form -fno-working-directory. If the -P flag is in the command line, this option has no effect, since no "#line" directives are emitted whatsoever.
  • -A predicate=answer โ€” makes an assertion with the predicate predicate and the answer answer ๐Ÿš This form is preferred to the older -A predicate(answer) form, which is still supported, because it doesn't use shell special characters.
  • -A -predicate=answer โ€” cancels an assertion with the predicate predicate and the answer answer ๐Ÿšซ
  • -C โ€” don't discard comments ๐Ÿ’ฌ All comments are passed through to the output file, except comments in processed directives, which get deleted along with the directive.
    • Be prepared for side effects with -C, since it makes the preprocessor treat comments as tokens in their own right. For example, comments at the start of what would be a directive line turn that line into an ordinary source line, since the first token on the line is no longer a #.
  • -CC โ€” don't discard comments, including during macro expansion ๐Ÿง  This is like -C, except comments contained within macros also get passed through to the output file where the macro is expanded.
    • On top of the -C side effects, -CC converts all C++-style comments inside a macro into C-style comments. This stops a later use of that macro from accidentally commenting out the rest of the source line.
    • -CC is generally used to support lint comments.
  • -P โ€” inhibits linemarkers in the output from the preprocessor ๐Ÿ™ƒ This might be useful when running the preprocessor on something that isn't C code and will be sent to a program that could get confused by the linemarkers.
  • -traditional, -traditional-cpp โ€” try to imitate pre-standard C preprocessors, as opposed to ISO C preprocessors ๐Ÿ•ฐ๏ธ See the GNU CPP manual for details.
    • GCC doesn't otherwise try to emulate a pre-standard C compiler, and these options only work with the -E switch, or when invoking CPP explicitly.
  • -trigraphs โ€” support ISO C trigraphs ๐Ÿ”บ These are three-character sequences, all starting with ??, that ISO C defines to stand for single characters. For example, ??/ stands for \, so '??/n' is a character constant for a newline.

The nine trigraphs and their replacements are:

Trigraph:       ??(  ??)  ??<  ??>  ??=  ??/  ??'  ??!  ??-
Replacement:      [    ]    {    }    #    \    ^    |    ~

By default GCC ignores trigraphs, but in standard-conforming modes it converts them. See the -std and -ansi options.

  • -remap โ€” enables special code to work around file systems that only permit very short file names, like MS-DOS ๐Ÿ“
  • -H โ€” prints the name of each header file used, in addition to the other normal stuff ๐Ÿช† Each name is indented to show how deep it sits in the #include stack. Precompiled header files get printed too, even if they turn out to be invalid: an invalid one is printed with ...x, and a valid one with ...!.
  • -dletters โ€” okay so this one tells GCC to make debugging dumps during compilation, based on whatever letters you hand it ๐Ÿ” The ones here are for the preprocessor. Other letters are handled by the compiler proper or saved for future GCC versions, so they get quietly ignored ๐Ÿซถ If you mix letters whose behavior clashes, the result is undefined ๐Ÿ’€
    • -dM โ€” skip the normal output and get a list of #define directives for every macro the preprocessor defined, predefined ones included ๐Ÿงš It's the best way to peek at what your preprocessor already has baked in. Assuming you don't have a file foo.h, run this:
touch foo.h; cpp -dM foo.h

and boom, all the predefined macros show up โœจ If you use -dM without the -E option, it's treated as a synonym for -fdump-rtl-mach ๐Ÿค“

  • -dD โ€” same energy as -dM, but with two twists: it leaves out the predefined macros, and it outputs both the #define directives and the result of preprocessing ๐ŸŽ€ Both kinds of output go to the standard output file.
  • -dN โ€” like -dD, but only the macro names come through, not their expansions ๐Ÿฆ‹
  • -dI โ€” outputs #include directives on top of the result of preprocessing ๐ŸŒธ
  • -dU โ€” like -dD, except only macros that get expanded, or whose definedness gets tested in preprocessor directives, make the cut ๐Ÿ‘‘ The output is delayed until that macro is used or tested, and #undef directives also show up for macros that were tested but undefined at that point ๐Ÿ’…
  • -fdebug-cpp โ€” this one is only useful if you're debugging GCC itself ๐Ÿ˜ญ When it's used from CPP or with -E, it dumps debugging info about location maps, and every token in the output gets preceded by the dump of the map its location belongs to ๐Ÿ”ฅ When used from GCC without -E, it does absolutely nothing ๐Ÿ™ˆ
  • -Wp,option โ€” lets you skip the compiler driver and pass option straight through to the preprocessor ๐Ÿš€ If option has commas, it gets split into multiple options at the commas. Here's the tea though: lots of options get modified, translated, or interpreted by the driver before they reach the preprocessor, and -Wp totally bypasses that step.
The preprocessor's direct interface is undocumented and subject to change, so whenever possible, avoid -Wp and let the driver handle the options instead ๐Ÿซ 
  • -Xpreprocessor option โ€” passes option along to the preprocessor ๐Ÿ’– Use it for system-specific preprocessor options that GCC doesn't recognize.
    • If you want to pass an option that takes an argument, you have to use -Xpreprocessor twice, once for the option and once for the argument ๐Ÿ“
  • -no-integrated-cpp โ€” runs preprocessing as a separate pass before compilation ๐Ÿงฉ By default GCC preprocesses as an integrated part of input tokenization and parsing, but with this option, the right language front end (cc1, cc1plus, or cc1obj for C, C++, and Objective-C, respectively) gets invoked twice: once for preprocessing only, and once for actual compilation of the preprocessed input. This may be useful alongside the -B or -wrapper options to specify an alternate preprocessor, or to do extra processing on the program source between normal preprocessing and compilation ๐ŸŒˆ

โœจ Passing Options to the Assembler โœจ

You can pass options to the assembler ๐ŸŽ€

  • -Wa,option โ€” passes option to the assembler ๐Ÿ’œ If option has commas, it gets split into multiple options at the commas.
  • -Xassembler option โ€” also passes option to the assembler ๐Ÿฆ‹ Use it for system-specific assembler options that GCC doesn't recognize.
    • If you want to pass an option that takes an argument, you must use -Xassembler twice, once for the option and once for the argument ๐Ÿ’…

โœจ Options for Linking โœจ

These options come into play when the compiler links object files into an executable output file ๐Ÿ”— They're meaningless if the compiler isn't doing a link step, so don't expect them to do anything otherwise ๐Ÿ™ƒ

  • object-file-name โ€” a file name that doesn't end in a special recognized suffix is considered to name an object file or library ๐Ÿ—‚๏ธ (The linker tells object files and libraries apart by checking the file contents.) If linking happens, these object files get used as input to the linker.
  • -c, -S, -E โ€” if any of these is used, the linker doesn't run, and object file names shouldn't be used as arguments ๐Ÿšซ
  • -flinker-output=type โ€” this one controls the code generation of the link time optimizer โš™๏ธ By default the linker output gets determined by the linker plugin automatically. For debugging the compiler, or when you want incremental linking to non-LTO object files, it may be useful to control the type manually ๐Ÿง 
    • exec โ€” code generation is set up to produce a static binary, and then -fpic and -fpie are both disabled ๐Ÿชจ
    • dyn โ€” code generation is set up to produce a shared library. -fpic or -fPIC is preserved, but not enabled automatically ๐ŸŒŠ This makes it possible to build shared libraries without position independent code on architectures where that's possible, i.e. on x86.
    • pie โ€” code generation is set up to produce a -fpie executable ๐ŸŽฏ This gives similar optimizations as exec, except -fpie is not disabled if it was specified at compilation time.
    • rel โ€” the compiler assumes incremental linking is happening ๐Ÿงš The sections containing intermediate code for link-time optimization are merged, pre-optimized, and output to the resulting object file. Also, if -ffat-lto-objects is specified, binary code is produced for future non-LTO linking. The object file from incremental linking is smaller than a static library made from the same object files, and at link time, the result of incremental linking also loads faster to the compiler than a static library, assuming most objects in the library are used โœจ
    • nolto-rel โ€” configures the compiler for incremental linking where code generation is forced, the final binary is produced, and the intermediate code for later link-time optimization is stripped ๐Ÿ’€ When multiple object files get linked together, the resulting code is optimized better than with link time optimizations disabled (for example, cross-module inlining will happen), but most of the benefits of whole program optimizations are however lost.

During the incremental link (by -r), the linker plugin defaults to rel ๐Ÿ” With current interfaces to GNU Binutils, it isn't possible to link incrementally LTO objects and non-LTO objects into a single mixed object file. If any object files in an incremental link can't be used for link-time optimization, the linker plugin outputs a warning and uses nolto-rel โš ๏ธ To maintain whole program optimization, it's recommended to link such objects into a static library instead. Alternatively, it's possible to use H.J. Lu's binutils with support for mixed objects ๐Ÿซถ

  • -fuse-ld=bfd โ€” uses the bfd linker instead of the default linker ๐Ÿ› ๏ธ
  • -fuse-ld=gold โ€” uses the gold linker instead of the default linker ๐Ÿฅ‡
  • -fuse-ld=lld โ€” uses the LLVM lld linker instead of the default linker ๐Ÿ’œ
  • -llibrary, -l library โ€” searches the library named library when linking ๐Ÿ“š The second alternative, with the library as a separate argument, is only there for POSIX compliance and isn't recommended ๐Ÿ™ˆ

The -l option gets passed directly to the linker by GCC, so check your linker documentation for the exact details ๐Ÿ” The general description below applies to the GNU linker.

The linker searches a standard list of directories for the library ๐Ÿ—บ๏ธ The directories it searches include several standard system directories, plus any you specify with -L.

Static libraries are archives of object files, and they have file names like liblibrary.a. Some targets also support shared libraries, which typically have names like liblibrary.so. If both static and shared libraries are found, the linker gives preference to the shared library, unless the -static option is used ๐ŸŒธ

It makes a difference where in the command you write this option ๐Ÿ“ The linker searches and processes libraries and object files in the order they're specified. So foo.o -lz bar.o searches library z after file foo.o but before bar.o. If bar.o refers to functions in z, those functions may not be loaded ๐Ÿ˜ญ

  • -lobjc โ€” you need this special case of the -l option to link an Objective-C or Objective-C++ program ๐ŸŒˆ
  • -nostartfiles โ€” don't use the standard system startup files when linking ๐Ÿšช The standard system libraries are still used normally, unless -nostdlib, -nolibc, or -nodefaultlibs is used.
  • -nodefaultlibs โ€” don't use the standard system libraries when linking ๐Ÿ™… Only the libraries you specify get passed to the linker, and options specifying linkage of the system libraries, such as -static-libgcc or -shared-libgcc, are ignored ๐ŸงŠ The standard startup files are still used normally, unless -nostartfiles is used.
The compiler may generate calls to "memcmp", "memset", "memcpy" and "memmove". These entries are usually resolved by entries in libc. When this option is specified, these entry points should be supplied through some other mechanism ๐Ÿšจ
  • -nolibc โ€” don't use the C library, or the system libraries tightly coupled with it, when linking ๐Ÿงผ It still links with the startup files, libgcc, or toolchain-provided language support libraries such as libgnat, libgfortran, or libstdc++, unless options preventing their inclusion are used as well. This typically removes -lc from the link command line, along with system libraries that normally go with it and become meaningless when a C library is assumed to be absent, for example -lpthread or -lm in some configurations. This is intended for bare-board targets when there is indeed no C library available ๐Ÿค–
  • -nostdlib โ€” don't use the standard system startup files or libraries when linking ๐Ÿซฅ No startup files get used, and only the libraries you specify are passed to the linker. Options specifying linkage of the system libraries, such as -static-libgcc or -shared-libgcc, are ignored too ๐Ÿ’ซ

Okay so the compiler might generate calls to memcmp, memset, memcpy and memmove all on its own ๐Ÿซถ Usually libc is the one that resolves those for you, but when this option is on, those entry points have to be supplied some other way, bestie ๐Ÿ’…

Plot twist: one of the standard libraries that -nostdlib and -nodefaultlibs skip is libgcc.a ๐Ÿงš It's a library of internal subroutines GCC uses to work around shortcomings of particular machines, or to cover special needs for some languages.

Here's the thing though: you usually still need libgcc.a even when you're ditching the other standard libraries ๐Ÿ˜ญ So when you specify -nostdlib or -nodefaultlibs, you should usually specify -lgcc as well. That way you don't end up with unresolved references to internal GCC library subroutines. (An example of one of those is __main, which makes sure C++ constructors get called ๐ŸŒธ)

  • -e entry, --entry=entry โ€” Sets the program entry point to entry. The linker is the one who interprets this, and the GNU linker will take either a symbol name or an address ๐Ÿฆ‹
  • -pie โ€” Makes a dynamically linked position independent executable on targets that support it โœจ For predictable results, you also have to use the same options you used for compilation (-fpie, -fPIE, or model suboptions) when you pass this linker option.
  • -no-pie โ€” Nope, don't make a dynamically linked position independent executable ๐Ÿ™…
  • -static-pie โ€” Makes a static position independent executable on targets that support it. It's giving static executable energy, but it can be loaded at any address without a dynamic linker ๐Ÿ’œ For predictable results, use the same options used for compilation (-fpie, -fPIE, or model suboptions) here too.
  • -pthread โ€” Links with the POSIX threads library ๐Ÿงต This works on GNU/Linux, most other Unix derivatives, and also x86 Cygwin and MinGW targets. On some targets it also sets flags for the preprocessor, so use it consistently for both compiling and linking.
  • -r โ€” Produces a relocatable object as output. This is also known as partial linking ๐ŸŒˆ
  • -rdynamic โ€” Passes -export-dynamic to the ELF linker, on targets that support it. This tells the linker to add all symbols to the dynamic symbol table, not only the used ones. It's needed for some uses of dlopen, or to get backtraces from inside a program ๐Ÿ”
  • -s โ€” Removes all symbol table and relocation information from the executable ๐Ÿงน
  • -static โ€” On systems that support dynamic linking, this overrides -pie and stops linking with the shared libraries. On other systems it has no effect ๐Ÿ’€
  • -shared โ€” Produces a shared object that can then be linked with other objects to form an executable. Not every system supports this one. For predictable results, use the same options used for compilation (-fpic, -fPIC, or model suboptions) when you pass this linker option.[1]
  • -shared-libgcc, -static-libgcc โ€” On systems that provide libgcc as a shared library, these force the use of the shared or static version, respectively ๐Ÿ’– If no shared version of libgcc was built when the compiler was configured, these do nothing.

There are a few situations where an app should use the shared libgcc instead of the static one ๐Ÿ‘‘ The most common is when the app wants to throw and catch exceptions across different shared libraries. In that case, each of the libraries as well as the application itself should use the shared libgcc.

So the G++ driver automatically adds -shared-libgcc whenever you build a shared library or a main executable, because C++ programs typically use exceptions. That's the right thing to do, periodt โœจ

If you use the GCC driver to create shared libraries instead, they might not always get linked with the shared libgcc ๐Ÿค” If GCC finds at configuration time that you have a non-GNU linker, or a GNU linker that doesn't support the option --eh-frame-hdr, it links the shared version of libgcc into shared libraries by default. Otherwise, it takes advantage of the linker and optimizes away the linking with the shared version, so it links with the static version of libgcc by default. This lets exceptions propagate through those shared libraries without incurring relocation costs at library load time.

However, if a library or main executable is supposed to throw or catch exceptions, you must link it using the G++ driver, or using the option -shared-libgcc, so it gets linked with the shared libgcc. Don't skip this one, bestie ๐Ÿ˜ญ
  • -static-libasan โ€” When the -fsanitize=address option is used to link a program, the GCC driver automatically links against libasan ๐Ÿ›ก๏ธ If libasan is available as a shared library and -static isn't used, it links against the shared version of libasan. The -static-libasan option tells the GCC driver to link libasan statically, without necessarily linking other libraries statically.
  • -static-libtsan โ€” When the -fsanitize=thread option is used to link a program, the GCC driver automatically links against libtsan ๐Ÿงต If libtsan is available as a shared library and -static isn't used, it links against the shared version of libtsan. The -static-libtsan option tells the GCC driver to link libtsan statically, without necessarily linking other libraries statically.
  • -static-liblsan โ€” When the -fsanitize=leak option is used to link a program, the GCC driver automatically links against liblsan ๐Ÿ’ง If liblsan is available as a shared library and -static isn't used, it links against the shared version of liblsan. The -static-liblsan option tells the GCC driver to link liblsan statically, without necessarily linking other libraries statically.
  • -static-libubsan โ€” When the -fsanitize=undefined option is used to link a program, the GCC driver automatically links against libubsan ๐ŸŒ€ If libubsan is available as a shared library and -static isn't used, it links against the shared version of libubsan. The -static-libubsan option tells the GCC driver to link libubsan statically, without necessarily linking other libraries statically.
  • -static-libstdc++ โ€” When the g++ program links a C++ program, it normally links against libstdc++ automatically ๐Ÿ“š If libstdc++ is available as a shared library and -static isn't used, it links against the shared version, and that's normally fine. Sometimes, though, it's useful to freeze the version of libstdc++ your program uses without going all the way to a fully static link. The -static-libstdc++ option tells the g++ driver to link libstdc++ statically, without necessarily linking other libraries statically.
  • -symbolic โ€” Binds references to global symbols when building a shared object. It warns about any unresolved references, unless you override that with the link editor option -Xlinker -z -Xlinker defs. Only a few systems support this option ๐Ÿ™ˆ
  • -T script โ€” Uses script as the linker script. This option is supported by most systems using the GNU linker. On some targets, like bare-board targets without an operating system, -T may be required when linking to avoid references to undefined symbols.
  • -Xlinker option โ€” Passes option along to the linker as an option. This is your go-to for system-specific linker options that GCC doesn't recognize ๐Ÿ”ง

If you want to pass an option that takes a separate argument, you have to use -Xlinker twice: once for the option and once for the argument. For example, to pass -assert definitions, you write -Xlinker -assert -Xlinker definitions. Writing -Xlinker "-assert definitions" does not work, because it passes the entire string as one single argument, and that's not what the linker expects ๐Ÿ˜ค

When you're using the GNU linker, it's usually more convenient to pass arguments to linker options with the option=value syntax instead of as separate arguments. For example, you can write -Xlinker -Map=output.map rather than -Xlinker -Map -Xlinker output.map. Other linkers may not support this syntax for command-line options.

  • -Wl,option โ€” Passes option along to the linker as an option. If option contains commas, it gets split into multiple options at those commas. You can use this syntax to pass an argument to the option. For example, -Wl,-Map,output.map passes -Map output.map to the linker. With the GNU linker, you can also get the same effect with -Wl,-Map=output.map โœจ
NOTE: In Ubuntu 8.10 and later versions, for LDFLAGS, the option -Wl,-z,relro is used. To disable it, use -Wl,-z,norelro.
  • -u symbol โ€” Pretends the symbol symbol is undefined, which forces linking of the library modules that define it ๐ŸŽฏ You can use -u multiple times with different symbols to force loading of additional library modules.
  • -z keyword โ€” -z gets passed straight to the linker along with the keyword. Check the section in your linker's documentation for the permitted values and what they mean ๐Ÿ“–

These options specify directories to search for header files, for libraries and for parts of the compiler:

  • -I dir, -iquote dir, -isystem dir, -idirafter dir โ€” Adds the directory dir to the list of directories searched for header files during preprocessing ๐Ÿงญ If dir begins with = or $SYSROOT, then that = or $SYSROOT gets replaced by the sysroot prefix. See --sysroot and -isysroot for more.

Directories specified with -iquote only apply to the quote form of the directive, #include "file". Directories specified with -I, -isystem, or -idirafter apply to the lookup for both #include "file" and #include <file> directives ๐ŸŒธ

You can specify any number or combination of these options on the command line to search for header files in several directories ๐Ÿ’… The lookup order goes like this:

  1. For the quote form of the include directive, the directory of the current file is searched first.
  2. okay bestie, for the quote form of the include directive, the -iquote dirs get searched left-to-right, in whatever order they show up on the command line ๐ŸŽ€
  3. next up, -I dirs get scanned left-to-right ๐Ÿฆ‹
  4. then the -isystem dirs get scanned left-to-right too ๐Ÿ’…
  5. standard system dirs get scanned ๐ŸŒธ
  6. last but not least, -idirafter dirs get scanned left-to-right ๐Ÿซถ

Ngl, this order is iconic. You can use -I to override a system header file and swap in your own version, because these dirs get searched before the standard system header file dirs โœจ But please don't use this to add dirs full of vendor-supplied system header files. Use -isystem for that ๐Ÿ™ˆ

The -isystem and -idirafter options also mark the directory as a system directory, so it gets the same special treatment as the standard system directories ๐Ÿ’œ

If a standard system include directory, or a directory given with -isystem, also shows up with -I, then the -I option gets ignored ๐Ÿ’€ The directory still gets searched, just as a system directory at its normal spot in the system include chain. This keeps GCC's procedure for fixing buggy system headers and the ordering for the #include_next directive from getting accidentally messed up ๐Ÿงš If you really, truly need to change the search order for system directories, use the -nostdinc and/or -isystem options.

  • -I- โ€” Split the include path. This option has been deprecated, so please use -iquote instead for -I directories before the -I-, and remove the -I- option ๐Ÿฅ€

Any directories given with -I options before -I- only get searched for headers requested with #include "file". They're not searched for #include <file>. If additional directories are given with -I options after the -I-, those directories get searched for all #include directives โœจ

Also, -I- stops the directory of the current file from being used as the first search directory for #include "file". There's no way to override this effect of -I- ๐Ÿ™…โ€โ™€๏ธ

  • -iprefix prefix โ€” Set prefix as the prefix for subsequent -iwithprefix options. If the prefix represents a directory, you should include the final / ๐Ÿ“
  • -iwithprefix dir, -iwithprefixbefore dir โ€” Tack dir onto the prefix you set earlier with -iprefix, and add the resulting directory to the include search path. -iwithprefixbefore puts it in the same place -I would, while -iwithprefix puts it where -idirafter would ๐ŸŒˆ
  • -isysroot dir โ€” This one's like the --sysroot option, but it only applies to header files. The exception is Darwin targets, where it applies to both header files and libraries. Check out the --sysroot option for more info ๐Ÿ’–
  • -imultilib dir โ€” Use dir as a subdirectory of the directory that holds the target-specific C++ headers ๐ŸŒธ
  • -nostdinc โ€” Do not search the standard system directories for header files. Only the directories you explicitly give with -I, -iquote, -isystem, and/or -idirafter options get searched, plus the directory of the current file if it's appropriate ๐ŸŽ€
  • -nostdinc++ โ€” Don't search for header files in the C++-specific standard directories, but do still search the other standard directories. This option is used when building the C++ library ๐Ÿงš
  • -iplugindir=dir โ€” Set the directory to search for plugins that get passed by -fplugin=name instead of -fplugin=path/name.so. This one isn't really meant for users. Only the driver passes it along ๐Ÿค–
  • -Ldir โ€” Add directory dir to the list of directories to be searched for -l ๐Ÿฆ‹
  • -Bprefix โ€” This option tells the compiler where to find its own executables, libraries, include files, and data files ๐Ÿซถ

The compiler driver program runs one or more of the subprograms cpp, cc1, as and ld. It tries prefix as a prefix for each program it tries to run, both with and without machine/version/ for the corresponding target machine and compiler version ๐Ÿ’…

For each subprogram, the compiler driver first tries the -B prefix, if there is one. If that name isn't found, or if -B isn't specified at all, the driver tries two standard prefixes, /usr/lib/gcc/ and /usr/local/lib/gcc/. If neither of those turns up a file that exists, the unmodified program name gets searched for in the directories listed in your PATH environment variable ๐Ÿ”ฅ

The compiler checks whether the path given by -B refers to a directory. If it's necessary, it adds a directory separator character to the end of the path ๐ŸŒธ

-B prefixes that effectively specify directory names also apply to libraries in the linker, because the compiler translates these options into -L options for the linker. They also apply to include files in the preprocessor, because the compiler translates these options into -isystem options for the preprocessor. In this case, the compiler appends include to the prefix ๐Ÿงš

The runtime support file libgcc.a can also be searched for using the -B prefix, if needed. If it isn't found there, the two standard prefixes above get tried, and that's all. If those means don't find it either, the file gets left out of the link ๐Ÿ’œ

Another way to specify a prefix that's a lot like the -B prefix is the environment variable GCC_EXEC_PREFIX ๐ŸŒˆ

As a special kludge, if the path given by -B is [dir/]stageN/, where N is a number in the range 0 to 9, then it gets replaced by [dir/]include. This is there to help with boot-strapping the compiler ๐Ÿ› ๏ธ

  • -no-canonical-prefixes โ€” Do not expand any symbolic links, resolve references to /../ or /./, or make the path absolute when generating a relative prefix ๐Ÿฆ‹
  • --sysroot=dir โ€” Use dir as the logical root directory for headers and libraries. For example, if the compiler normally searches for headers in /usr/include and libraries in /usr/lib, it instead searches dir/usr/include and dir/usr/lib ๐Ÿ‘‘

If you use both this option and the -isysroot option, then --sysroot applies to libraries, but -isysroot applies to header files ๐Ÿ’…

The GNU linker (beginning with version 2.16) has the necessary support for this option. If your linker doesn't support it, the header file side of --sysroot still works, but the library side doesn't ๐Ÿ˜ญ

  • --no-sysroot-suffix โ€” For some targets, a suffix gets added to the root directory specified with --sysroot, depending on the other options you used. That means headers might be found in dir/suffix/usr/include instead of dir/usr/include. This option turns off the addition of that suffix ๐Ÿ™ˆ

โœจ Options for Code Generation Conventions โœจ

These machine-independent options control the interface conventions used in code generation ๐Ÿงš

Most of them have both positive and negative forms, and the negative form of -ffoo is -fno-foo. In the list below, only one of the forms is listed, the one that is not the default. You can figure out the other form by either removing no- or adding it ๐Ÿ’–

โœจ -fstack-reuse=reuse-level โœจ

This option controls stack space reuse for user declared local/auto variables and compiler generated temporaries ๐ŸŒธ reuse_level can be all, named_vars, or none. all enables stack reuse for all local variables and temporaries, named_vars enables reuse only for user defined local variables with names, and none disables stack reuse completely. The default value is all ๐ŸŽ€

The option is needed when the program extends the lifetime of a scoped local variable or a compiler generated temporary beyond the end point defined by the language. When a lifetime of a variable ends, and if the variable lives in memory, the optimizing compiler has the freedom to reuse its stack space with other temporaries or scoped local variables whose live range does not overlap with it. Legacy code extending local lifetime is likely to break with the stack reuse optimization ๐Ÿ’€

For example,

int *p;
{
  int local1;

  p = &local1;
  local1 = 10;
  ....
}
{
   int local2;
   local2 = 20;
   ...
}

if (*p == 10)  // out of scope use of local1
  {

  }

Another example:

struct A
{
    A(int k) : i(k), j(k) { }
    int i;
    int j;
};

A *ap;

void foo(const A& ar)
{
   ap = &ar;
}

void bar()
{
   foo(A(10)); // temp object's lifetime ends when foo returns

   {
     A a(20);
     ....
   }
   ap->i+= 10;  // ap references out of scope temp whose space
                // is reused with a. What is the value of ap->i?
}

The lifetime of a compiler generated temporary is well defined by the C++ standard. When a lifetime of a temporary ends, and if the temporary lives in memory, the optimizing compiler has the freedom to reuse its stack space with other temporaries or scoped local variables whose live range does not overlap with it. However, some of the legacy code relies on the behavior of older compilers, where temporaries' stack space is not reused. Aggressive stack reuse can lead to runtime errors. This option is used to control the temporary stack reuse optimization ๐Ÿ˜ญ

  • -ftrapv โ€” This option generates traps for signed overflow on addition, subtraction, and multiplication operations. The options -ftrapv and -fwrapv override each other, so using -ftrapv -fwrapv on the command-line results in -fwrapv being effective. Note that only active options override, so using -ftrapv -fwrapv -fno-wrapv on the command-line results in -ftrapv being effective ๐Ÿ‘‘
  • -fwrapv โ€” okay bestie, this one tells the compiler to assume that signed arithmetic overflow from addition, subtraction and multiplication just wraps around, using twos-complement representation ๐Ÿ”„โœจ. It turns some optimizations on and others off. -ftrapv and -fwrapv cancel each other out, so -ftrapv -fwrapv on the command line results in -fwrapv being effective ๐Ÿ’…. Only active options override, though, so -ftrapv -fwrapv -fno-wrapv on the command line results in -ftrapv being effective ๐Ÿ‘‘.
  • -fwrapv-pointer โ€” same energy, but for pointers ๐ŸŒธ. It tells the compiler to assume pointer arithmetic overflow on addition and subtraction wraps around using twos-complement representation. It also disables some optimizations that would otherwise assume pointer overflow is invalid ๐Ÿ™ˆ.
  • -fstrict-overflow โ€” this one implies -fno-wrapv -fno-wrapv-pointer ๐Ÿ“. When it's negated, it implies -fwrapv -fwrapv-pointer ๐Ÿฆ‹.
  • -fexceptions โ€” enables exception handling โœจ and generates the extra code needed to propagate exceptions ๐Ÿงš. For some targets, this implies GCC generates frame unwind information for all functions. That can add a pretty big data size overhead ๐Ÿ˜ญ, although it doesn't affect execution ๐Ÿ’–.

If you don't specify this option, GCC turns it on by default for languages like C++ that normally require exception handling, and turns it off for languages like C that don't ๐ŸŽ€. You might still need to enable it when compiling C code that has to interoperate properly with exception handlers written in C++ ๐Ÿซถ. You might also want to disable it if you're compiling older C++ programs that don't use exception handling ๐Ÿ’€.

  • -fnon-call-exceptions โ€” makes trapping instructions able to throw exceptions ๐Ÿ’ฅ. Heads up: this needs platform-specific runtime support, and that support doesn't exist everywhere โš ๏ธ. It only lets trapping instructions throw exceptions, meaning memory references or floating-point instructions ๐Ÿง . It does not let exceptions get thrown from arbitrary signal handlers, like "SIGALRM" ๐Ÿ™….
  • -fdelete-dead-exceptions โ€” instructions that may throw exceptions but don't otherwise contribute to the program's execution can be optimized away ๐Ÿ—‘๏ธ. This is enabled by default for the Ada front end, which the Ada language specification permits ๐Ÿ‘‘. Optimization passes that remove dead exceptions are enabled independently at different optimization levels ๐Ÿ”ฅ.
  • -funwind-tables โ€” kinda like -fexceptions, except it only generates any needed static data and doesn't affect the generated code in any other way ๐Ÿฆ‹. You normally don't need to enable it yourself, since a language processor that needs this handling turns it on for you ๐Ÿซถ.
  • -fasynchronous-unwind-tables โ€” generates an unwind table in DWARF format, if the target machine supports it ๐ŸŒˆ. The table is exact at each instruction boundary, so it can be used for stack unwinding from asynchronous events, like a debugger or garbage collector ๐Ÿ”.
  • -fno-gnu-unique โ€” on systems with a recent GNU assembler and C library, the C++ compiler uses the STB_GNU_UNIQUE binding. This keeps definitions of template static data members and static local variables in inline functions unique, even with RTLD_LOCAL โœจ. That's needed so a library used by two different RTLD_LOCAL plugins doesn't end up depending on a definition in one and disagreeing with the other about the symbol's binding ๐Ÿ˜ต. The catch is that dlclose gets ignored for affected DSOs ๐Ÿ™ƒ. If your program relies on reinitializing a DSO through dlclose and dlopen, you can use -fno-gnu-unique ๐Ÿงน.
  • -fpcc-struct-return โ€” returns short struct and union values in memory, like the longer ones, instead of in registers ๐Ÿงบ. It's less efficient ๐Ÿ˜ฌ, but it lets GCC-compiled files play nicely with files compiled by other compilers, especially the Portable C Compiler (pcc) ๐Ÿค.

The precise convention for returning structures in memory depends on the target configuration macros ๐Ÿ› ๏ธ.

Short structures and unions are the ones whose size and alignment match that of some integer type ๐Ÿ“.

Warning: code compiled with -fpcc-struct-return is not binary compatible with code compiled with -freg-struct-return. Only use it to conform to a non-default application binary interface ๐Ÿšจ.
  • -freg-struct-return โ€” returns struct and union values in registers when possible ๐Ÿš€. This is more efficient for small structures than -fpcc-struct-return ๐Ÿ’ช.

If you specify neither -fpcc-struct-return nor -freg-struct-return, GCC defaults to whichever convention is standard for the target ๐ŸŽฏ. If there's no standard convention, GCC defaults to -fpcc-struct-return, except on targets where GCC is the principal compiler ๐Ÿ‘‘. In those cases, GCC can choose the standard itself, and it chose the more efficient register return alternative ๐Ÿ’….

Warning: code compiled with -freg-struct-return is not binary compatible with code compiled with -fpcc-struct-return. Only use it to conform to a non-default application binary interface ๐Ÿšจ.
  • -fshort-enums โ€” allocates an enum type only as many bytes as it needs for the declared range of possible values ๐Ÿ”ข. Specifically, the enum type is equivalent to the smallest integer type that has enough room ๐Ÿงธ.
Warning: the -fshort-enums switch causes GCC to generate code that is not binary compatible with code generated without that switch. Use it to conform to a non-default application binary interface โš ๏ธ.
  • -fshort-wchar โ€” overrides the underlying type for wchar_t to be short unsigned int instead of the target's default ๐Ÿช„. This is useful for building programs to run under WINE ๐Ÿท.
Warning: the -fshort-wchar switch causes GCC to generate code that is not binary compatible with code generated without that switch. Use it to conform to a non-default application binary interface โš ๏ธ.
  • -fno-common โ€” in C code, this controls where global variables defined without an initializer get placed. These are known as tentative definitions in the C standard ๐Ÿ“ฆ. Tentative definitions are different from declarations of a variable with the extern keyword, which don't allocate storage ๐Ÿ™….

Unix C compilers have traditionally put storage for uninitialized global variables in a common block ๐Ÿงฑ. That lets the linker resolve all tentative definitions of the same variable in different compilation units to the same object, or to a non-tentative definition ๐Ÿ”—. This is the behaviour -fcommon specifies, and it's the default for GCC on most targets ๐Ÿ†. But ISO C doesn't require it, and on some targets it may carry a speed or code size penalty on variable references ๐Ÿ˜ค.

-fno-common tells the compiler to place uninitialized global variables in the BSS section of the object file instead ๐ŸŽฏ. This stops the linker from merging tentative definitions, so you get a multiple-definition error if the same variable is defined in more than one compilation unit ๐Ÿ’ฅ. It's useful on targets where it performs better, or if you want to verify that your program works on other systems that always treat uninitialized variable definitions this way ๐Ÿ”.

  • -fno-ident โ€” ignores the #ident directive ๐Ÿ™ˆ.
  • -finhibit-size-directive โ€” doesn't output a .size assembler directive, or anything else that would cause trouble if the function gets split in the middle and the two halves end up far apart in memory ๐Ÿงฉ. This option is used when compiling crtstuff.c. You shouldn't need it for anything else ๐Ÿšซ.
  • -fverbose-asm โ€” adds extra commentary to the generated assembly code to make it way more readable ๐Ÿ“–. This is really only useful for people who actually need to read the generated assembly, like when debugging the compiler itself ๐Ÿค“.

-fno-verbose-asm, the default, leaves the extra information out, which is handy when comparing two assembler files ๐Ÿ”€.

The added comments include:

  • information on the compiler version and command-line options,
  • the source code lines associated with the assembly instructions, in the form FILENAME:LINENUMBER:CONTENT OF LINE,
  • hints on which high-level expressions correspond to the various assembly instruction operands.

For example, given this C source file:

int test (int n)
{
  int i;
  int total = 0;

  for (i = 0; i < n; i++)
    total += i * i;

  return total;
}

Compiling to (x86_64) assembly via -S and emitting the result direct to stdout via -o -:

gcc -S test.c -fverbose-asm -Os -o -

gives output similar to this:

     .file   "test.c"
# GNU C11 (GCC) version 7.0.0 20160809 (experimental) (x86_64-pc-linux-gnu)
  [...snip...]
# options passed:
  [...snip...]

Okay bestie, the assembly listing is the output you get from -fverbose-asm, and it's giving "here's what the compiler actually spat out" ๐Ÿงš Look at all those little # comments tying each instruction back to test.c ๐Ÿ’…

        .text
        .globl  test
        .type   test, @function
test:
.LFB0:
        .cfi_startproc
# test.c:4:   int total = 0;
        xorl    %eax, %eax      # <retval>
# test.c:6:   for (i = 0; i < n; i++)
        xorl    %edx, %edx      # i
.L2:
# test.c:6:   for (i = 0; i < n; i++)
        cmpl    %edi, %edx      # n, i
        jge     .L5     #,
# test.c:7:     total += i * i;
        movl    %edx, %ecx      # i, tmp92
        imull   %edx, %ecx      # i, tmp92
# test.c:6:   for (i = 0; i < n; i++)
        incl    %edx    # i
# test.c:7:     total += i * i;
        addl    %ecx, %eax      # tmp92, <retval>
        jmp     .L2     #
.L5:
# test.c:10: }
        ret
        .cfi_endproc
.LFE0:
        .size   test, .-test
        .ident  "GCC: (GNU) 7.0.0 20160809 (experimental)"
        .section        .note.GNU-stack,"",@progbits

The comments are for humans, not machines, so the exact format of them can change whenever. Don't build anything that depends on it ๐Ÿ™ˆ

  • -frecord-gcc-switches โ€” this one tells the compiler to stash the exact command line you used into the object file it's making ๐ŸŽ€

This only works on some targets, and the format depends on both the target and the binary file format. Usually it's a section full of ASCII text. It's related to -fverbose-asm, but that one only writes info into the assembler output as comments, so it never makes it into the object file. For another way to store compiler options in the object file, check out -grecord-gcc-switches โœจ

  • -fpic โ€” generate position-independent code (PIC) that's good for shared libraries, if the target machine supports it ๐Ÿฆ‹

This code reaches every constant address through a global offset table (GOT). The dynamic loader fills in the GOT entries when the program starts up. (The dynamic loader isn't part of GCC, it's part of the operating system, so no it's not GCC's fault ๐Ÿ’€)

If the GOT for your linked executable goes over a machine-specific max size, the linker throws an error saying -fpic doesn't work. In that case, recompile with -fPIC instead. (The maximums are 8k on the SPARC, 28k on AArch64, and 32k on the m68k and RS/6000. The x86 has no such limit, so it's living its best life ๐Ÿ‘‘)

PIC needs special support, so it only works on certain machines. On x86, GCC does PIC for System V but not for the Sun 386i. Code for the IBM RS/6000 is always position-independent ๐ŸŒˆ

When this flag is set, the macros __pic__ and __PIC__ get defined to 1 โœจ

  • -fPIC โ€” if the target machine supports it, this emits position-independent code that works for dynamic linking and has no size limit on the global offset table ๐Ÿ’– It makes a real difference on AArch64, m68k, PowerPC, and SPARC ๐Ÿ”ฅ

PIC needs special support, so again, only certain machines can do it ๐Ÿ™ˆ

When this flag is set, __pic__ and __PIC__ get defined to 2 ๐Ÿ’œ

  • -fpie, -fPIE โ€” these are like -fpic and -fPIC, but the position-independent code they make can only be linked into executables ๐Ÿงš You'll usually use them for code that's going to be linked with the -pie GCC option.

Both -fpie and -fPIE define the macros __pie__ and __PIE__. They're 1 for -fpie and 2 for -fPIE ๐ŸŽ€

  • -fno-plt โ€” skip the PLT for external function calls in position-independent code. Instead, load the callee address from the GOT at each call site and branch to it ๐Ÿฆ‹

This gets you more efficient code, because it kills the PLT stubs and lets the GOT loads get optimized. On architectures like 32-bit x86, where PLT stubs expect the GOT pointer in one specific register, it gives the compiler more freedom with register allocation ๐Ÿ’… Lazy binding needs the PLT, so with -fno-plt, every external symbol gets resolved at load time instead.

Alternatively, you can use the function attribute noplt to avoid calls through the PLT for specific external functions โœจ

In position-dependent code, a few targets will also switch calls to functions marked to skip the PLT over to use the GOT instead ๐ŸŒธ

  • -fno-jump-tables โ€” don't use jump tables for switch statements, even when they'd be more efficient than other codegen strategies ๐Ÿ™ˆ

This is handy alongside -fpic or -fPIC when you're building code that's part of a dynamic linker and can't reference the address of a jump table. On some targets, jump tables don't need a GOT, so you don't need this option there ๐Ÿซถ

  • -ffixed-reg โ€” treat the register named reg as fixed, so generated code should never touch it (unless it's being used as the stack pointer, frame pointer, or some other fixed role) ๐Ÿ“

reg has to be an actual register name. The accepted names are machine-specific and get defined in the REGISTER_NAMES macro in the machine description macro file ๐Ÿงš

This flag has no negative form, since it's a three-way choice ๐Ÿ’œ

  • -fcall-used-reg โ€” treat the register named reg as an allocable register that function calls clobber. It can get used for temporaries or variables that don't live across a call. Functions compiled this way don't save and restore reg ๐ŸŒˆ

Using this flag with the frame pointer or stack pointer is an error ๐Ÿšซ Using it on other registers that have fixed, pervasive roles in the machine's execution model gives disastrous results ๐Ÿ’€

This flag has no negative form, since it's a three-way choice โœจ

  • -fcall-saved-reg โ€” treat the register named reg as an allocable register that functions save. It can be allocated even for temporaries or variables that live across a call. Functions compiled this way save and restore reg if they use it ๐Ÿฆ‹

Using this flag with the frame pointer or stack pointer is an error ๐Ÿšซ Using it on other registers with fixed, pervasive roles in the machine's execution model gives disastrous results ๐Ÿ’€

A different kind of disaster happens if you use it on a register where function values get returned ๐Ÿ˜ญ

This flag has no negative form, since it's a three-way choice ๐Ÿ’…

  • -fpack-struct[=n] โ€” without a value, this packs all structure members together with no holes ๐Ÿงฉ If you give it a value, which has to be a small power of two, it packs the structure members according to that value, treating it as the maximum alignment. (That means objects with default alignment requirements bigger than this get output potentially unaligned at the next fitting location.) ๐ŸŽ€
Warning: -fpack-struct makes GCC generate code that is NOT binary compatible with code made without it. It also makes the code suboptimal. Only use it when you need to conform to a non-default application binary interface ๐Ÿ’€
  • -fleading-underscore โ€” this one, along with its counterpart -fno-leading-underscore, forcibly changes how C symbols get represented in the object file ๐Ÿงš One reason to use it is to link with legacy assembly code ๐Ÿซถ
Warning: -fleading-underscore makes GCC generate code that is NOT binary compatible with code made without it. Only use it to conform to a non-default application binary interface. Not every target fully supports this switch, so double-check before you rely on it ๐Ÿ˜ญ
  • -ftls-model=model โ€” change the thread-local storage model. model should be one of global-dynamic, local-dynamic, initial-exec, or local-exec ๐ŸŒธ

The choice is subject to optimization. The compiler might use a more efficient model for symbols that aren't visible outside the translation unit, or if -fpic isn't given on the command line. (That's the "it's giving smart compiler" energy ๐Ÿง )

The default without -fpic is initial-exec. With -fpic, the default is global-dynamic ๐Ÿ’–

  • -ftrampolines โ€” for targets that normally need trampolines for nested functions, this always generates them instead of using descriptors. For targets that don't need them, like HP-PA or IA-64, it does nothing ๐Ÿฆ‹

A trampoline is a tiny bit of code created at run time on the stack when the address of a nested function is taken. It's used to call the nested function indirectly. That means the stack has to be made executable for the program to work properly ๐Ÿ˜ญ

-fno-trampolines is enabled by default on a language-by-language basis. That lets the compiler skip making trampolines when it works out that's safe, and swap in descriptors instead. Descriptors are made of data only, but the generated code has to be ready to deal with them ๐ŸŒˆ As of this writing, -fno-trampolines is enabled by default only for Ada ๐Ÿ‘‘

Code compiled with -ftrampolines and code compiled with -fno-trampolines are not binary compatible if nested functions are present. So this option has to be used program-wide, and you need to handle it with extreme care ๐Ÿ™ˆ

  • -fvisibility=[default|internal|hidden|protected] โ€” this sets the default ELF image symbol visibility to whatever option you pick. Every symbol gets marked with it unless the code overrides it ๐Ÿ’…

This can seriously speed up linking and load times for shared object libraries, make the code more optimized, give you near-perfect API export, and stop symbol clashes. It's strongly recommended for any shared objects you distribute ๐Ÿซถ

Despite the name, default actually means public, i.e., it can be linked against from outside the shared object ๐ŸŒธ protected and internal are pretty useless in real-world use, so the only other one you'll commonly see is hidden ๐Ÿ™ˆ If you don't specify -fvisibility, the default is default, which means every symbol is public โœจ

Okay so if you want the full tea on why ELF symbol visibility matters, read "How To Write Shared Libraries" by Ulrich Drepper, found at https://www.akkadia.org/drepper/ ๐Ÿ“š๐Ÿค“ But the lowkey iconic move this option unlocks is making the default hidden and only marking the stuff you actually want public โœจ Instead of marking everything hidden when the default is public (so much typing ๐Ÿ™„), you flip it. That's the norm with DLLs on Windows. With -fvisibility=hidden plus __attribute__ ((visibility("default"))) instead of __declspec(dllexport), you get almost identical semantics with identical syntax ๐Ÿซถ Cross-platform projects, this is your moment ๐ŸŒˆ

For people adding visibility to existing code, #pragma GCC visibility is giving ๐Ÿ’– You wrap the declarations you care about in #pragma GCC visibility push(hidden) and close it with #pragma GCC visibility pop ๐ŸŽ€ Real talk though: symbol visibility is part of your API interface contract, so all new code should always specify visibility whenever it isn't the default. Declarations that only get used inside the local DSO should always be marked explicitly as hidden, so you dodge PLT indirection overheads ๐Ÿ™…โ€โ™€๏ธ Being this clear also makes the code way more readable and self-documenting, no cap ๐Ÿ“– Also, because of ISO C++ specification requirements, operator new and operator delete must always be default visibility ๐Ÿ’€

Heads up, bestie: headers from outside your project, like system headers and headers from any other library you use, might not be expecting anything other than default visibility ๐Ÿ˜ฌ You may need to say #pragma GCC visibility push(default) before including any of those ๐Ÿ›ก๏ธ

extern declarations aren't affected by -fvisibility, so a lot of code can be recompiled with -fvisibility=hidden with zero modifications โœจ BUT (plot twist ๐Ÿ˜ญ) calls to extern functions with no explicit visibility go through the PLT. So it's way more effective to use __attribute ((visibility)) and/or #pragma GCC visibility to tell the compiler which extern declarations should be treated as hidden ๐Ÿงš

Also, -fvisibility does affect C++ vague linkage entities ๐Ÿ‘€ So an exception class that gets thrown between DSOs must be explicitly marked with default visibility, so the type_info nodes get unified between the DSOs. Don't skip this one, it's a whole bug just waiting to happen ๐Ÿ’€

An overview of all these techniques, their benefits, and how to use them lives at http://gcc.gnu.org/wiki/Visibility ๐Ÿฆ‹

๐ŸŒธ -fstrict-volatile-bitfields

Use this when you want accesses to volatile bit-fields (or other structure fields, although the compiler usually honors those types anyway) to be a single access at the width of the field's type, aligned to a natural alignment if possible. Like, targets with memory-mapped peripheral registers might need every access to be 16 bits wide. With this flag, you can declare all the peripheral bit-fields as unsigned short (assuming short is 16 bits on those targets) to force GCC into 16-bit accesses, instead of a maybe-more-efficient 32-bit access ๐Ÿ”ง

If this option is disabled, the compiler goes for the most efficient instruction ๐ŸŽ๏ธ In the example above, that might be a 32-bit load, even though it touches bytes that have no part of the bit-field in them, or memory-mapped registers unrelated to the one being updated ๐Ÿ˜ฌ

In some cases, like when the packed attribute is applied to a structure field, it might not be possible to access the field with one read or write that's correctly aligned for the target machine. In that situation GCC falls back to generating multiple accesses, rather than code that will fault or truncate the result at run time ๐Ÿ™

Note: due to restrictions of the C/C++11 memory model, write accesses are not allowed to touch non bit-field members. So it's recommended to define all bits of the field's type as bit-field members ๐Ÿ’…

The default value of this option is determined by the application binary interface for the target processor ๐Ÿงพ

๐Ÿงš -fsync-libcalls

This option controls whether any out-of-line instance of the __sync family of functions may be used to implement the C++11 __atomic family of functions ๐Ÿงต The default is enabled, so the only useful form of the option is -fno-sync-libcalls ๐Ÿ™ƒ This option is used in the implementation of the libatomic runtime library ๐Ÿ“š


โœจ GCC Developer Options โœจ

This section covers command-line options that are mainly for GCC developers ๐Ÿง‘โ€๐Ÿ’ป Think compiler testing, investigating compiler bugs, and compile-time performance problems. That includes options that produce debug dumps at various points, options that print statistics like memory use and execution time, and options that print info about GCC's configuration, like where it searches for libraries ๐Ÿ” Honestly, you should rarely need any of these for ordinary compiling and linking, so don't go wild ๐Ÿ™ˆ

Many developer options that make GCC dump output to a file take an optional =filename suffix. You can use stdout or - to dump to standard output, and stderr for standard error ๐Ÿ“ค

If you leave out =filename, GCC builds a default dump file name by sticking together the base dump file name, a pass number, a phase letter, and the pass name ๐Ÿงฉ The base dump file name is the name of the output file if you explicitly specified one and it isn't an executable. Otherwise it's the source file name. The pass number comes from the order passes are registered with the compiler's pass manager. That's usually the same as execution order, BUT passes registered by plugins, target-specific passes, or passes that are otherwise registered late get numbered higher than the pass named final, even if they actually run earlier ๐Ÿ˜ญ The phase letter is one of i (inter-procedural analysis), l (language-specific), r (RTL), or t (tree). The files get created in the directory of the output file ๐Ÿ“

๐Ÿ”ฅ -dletters, -fdump-rtl-pass, -fdump-rtl-pass=filename

These make debugging dumps during compilation at the times specified by the letters. This is the move for debugging the RTL-based passes of the compiler ๐Ÿ› ๏ธ

Heads up: some -dletters switches mean something different when you use -E for preprocessing ๐Ÿ‘€

You can enable debug dumps with a -fdump-rtl switch or with some -d option letters. Here are the possible values for pass and the letters, and what each one means ๐Ÿ’–

  • -fdump-rtl-alignments โ€” dumps right after branch alignments have been computed ๐Ÿ“
  • -fdump-rtl-asmcons โ€” dumps after fixing rtl statements that have unsatisfied in/out constraints ๐Ÿงฉ
  • -fdump-rtl-auto_inc_dec โ€” dumps after auto-inc-dec discovery. This pass only runs on architectures that have auto inc or auto dec instructions ๐Ÿค–
  • -fdump-rtl-barriers โ€” dumps after cleaning up the barrier instructions ๐Ÿงน
  • -fdump-rtl-bbpart โ€” dumps after partitioning hot and cold basic blocks ๐Ÿ”ฅ๐ŸงŠ
  • -fdump-rtl-bbro โ€” dumps after block reordering ๐Ÿ”€
  • -fdump-rtl-btl1, -fdump-rtl-btl2 โ€” turn on dumping after the two branch target load optimization passes ๐ŸŽฏ
  • -fdump-rtl-bypass โ€” dumps after jump bypassing and control flow optimizations ๐Ÿฆ˜
  • -fdump-rtl-combine โ€” dumps after the RTL instruction combination pass ๐Ÿงƒ
  • -fdump-rtl-compgotos โ€” dumps after duplicating the computed gotos ๐Ÿ‘ฏ
  • -fdump-rtl-ce1, -fdump-rtl-ce2, -fdump-rtl-ce3 โ€” turn on dumping after the three if conversion passes ๐Ÿ”
  • -fdump-rtl-cprop_hardreg โ€” dumps after hard register copy propagation ๐Ÿ“‹
  • -fdump-rtl-csa โ€” dumps after combining stack adjustments ๐Ÿฅž
  • -fdump-rtl-cse1, -fdump-rtl-cse2 โ€” turn on dumping after the two common subexpression elimination passes ๐Ÿ”
  • -fdump-rtl-dce โ€” dumps after the standalone dead code elimination passes ๐Ÿ—‘๏ธ
  • -fdump-rtl-dbr โ€” dumps after delayed branch scheduling โณ
  • -fdump-rtl-dce1, -fdump-rtl-dce2 โ€” turn on dumping after the two dead store elimination passes ๐Ÿ‘ป
  • -fdump-rtl-eh โ€” dumps after the finalization of EH handling code ๐Ÿšจ
  • -fdump-rtl-eh_ranges โ€” dumps after conversion of EH handling range regions ๐Ÿ“
  • -fdump-rtl-expand โ€” dumps after RTL generation ๐ŸŒฑ
  • -fdump-rtl-fwprop1, -fdump-rtl-fwprop2 โ€” turn on dumping after the two forward propagation passes โžก๏ธ
  • -fdump-rtl-gcse1, -fdump-rtl-gcse2 โ€” turn on dumping after global common subexpression elimination ๐ŸŒ
  • -fdump-rtl-init-regs โ€” dumps after the initialization of the registers ๐Ÿ
  • -fdump-rtl-initvals โ€” dumps after the computation of the initial value sets ๐ŸŽฌ
  • -fdump-rtl-into_cfglayout โ€” dumps after converting to cfglayout mode ๐Ÿ—‚๏ธ
  • -fdump-rtl-ira โ€” dumps after iterated register allocation ๐Ÿง 
  • -fdump-rtl-jump โ€” dumps after the second jump optimization ๐Ÿธ
  • -fdump-rtl-loop2 โ€” turns on dumping after the rtl loop optimization passes ๐Ÿ”
  • -fdump-rtl-mach โ€” dumps after the machine dependent reorganization pass, if that pass exists ๐Ÿ—๏ธ
  • -fdump-rtl-mode_sw โ€” dumps after removing redundant mode switches โœ‚๏ธ
  • -fdump-rtl-rnreg โ€” dumps after register renumbering ๐Ÿ”ข
  • -fdump-rtl-outof_cfglayout โ€” dumps after converting from cfglayout mode ๐Ÿ”™
  • -fdump-rtl-peephole2 โ€” dumps after the peephole pass ๐Ÿ”Ž
  • -fdump-rtl-postreload โ€” dumps after post-reload optimizations ๐Ÿ”ง
  • -fdump-rtl-pro_and_epilogue โ€” dumps after generating the function prologues and epilogues ๐ŸŽญ
  • -fdump-rtl-sched1, -fdump-rtl-sched2 โ€” turn on dumping after the basic block scheduling passes ๐Ÿ—“๏ธ
  • -fdump-rtl-ree โ€” dumps after sign/zero extension elimination โž•
  • -fdump-rtl-seqabstr โ€” dumps after common sequence discovery ๐Ÿช„
  • -fdump-rtl-shorten โ€” okay bestie, this one drops a dump right after branch shortening โœจ
  • -fdump-rtl-sibling โ€” dumps after the sibling call optimizations, so you can peek at all the tail-call magic ๐Ÿฆ‹
  • -fdump-rtl-split1, -fdump-rtl-split2, -fdump-rtl-split3, -fdump-rtl-split4, -fdump-rtl-split5 โ€” the splitting squad ๐ŸŽ€ these enable dumping after each of the five rounds of instruction splitting
  • -fdump-rtl-sms โ€” dumps after modulo scheduling ๐ŸŒธ but ngl, this pass only runs on some architectures
  • -fdump-rtl-stack โ€” dumps after GCC converts its "flat register file" registers into the x87's stack-like registers ๐Ÿ”ฅ this pass only runs on x86 variants
  • -fdump-rtl-subreg1, -fdump-rtl-subreg2 โ€” the two subreg expansion passes get their own dumps ๐Ÿงš both of these enable dumping after each pass
  • -fdump-rtl-unshare โ€” dumps after all the rtl has been unshared ๐Ÿ“
  • -fdump-rtl-vartrack โ€” dumps after variable tracking ๐Ÿ‘‘
  • -fdump-rtl-vregs โ€” dumps after virtual registers get converted to hard registers ๐Ÿ’œ
  • -fdump-rtl-web โ€” dumps after live range splitting ๐ŸŒˆ
  • -fdump-rtl-regclass, -fdump-rtl-subregs_of_mode_init, -fdump-rtl-subregs_of_mode_finish, -fdump-rtl-dfinit, -fdump-rtl-dfinish โ€” these ones are kinda ghosts ๐Ÿ‘ป they're defined, but they always produce empty files, so don't waste your time staring at them
  • -da, -fdump-rtl-all โ€” produces all the dumps listed above ๐Ÿ’– the full buffet ๐Ÿฐ
  • -dA โ€” annotates the assembler output with miscellaneous debugging information ๐Ÿ™ˆ
  • -dD โ€” dumps all macro definitions at the end of preprocessing, on top of the normal output ๐Ÿงš
  • -dH โ€” produces a core dump whenever an error occurs ๐Ÿ’€
  • -dp โ€” annotates the assembler output with a comment showing which pattern and alternative is used ๐Ÿ”ฅ the length and cost of each instruction get printed too
  • -dP โ€” dumps the RTL in the assembler output as a comment before each instruction ๐Ÿซถ this also turns on -dp annotation
  • -dx โ€” just generates RTL for a function instead of compiling it ๐Ÿฆ‹ usually used with -fdump-rtl-expand
  • -fdump-debug โ€” dumps the debugging info generated during the debug generation phase ๐ŸŒธ
  • -fdump-earlydebug โ€” dumps the debugging info generated during the early debug generation phase ๐ŸŒธ
  • -fdump-noaddr โ€” when doing debugging dumps, suppresses address output ๐Ÿ” this makes it way more feasible to use diff on debugging dumps for compiler invocations with different compiler binaries and/or different text / bss / data / heap / stack / dso start locations
  • -freport-bug โ€” if an internal compiler error (ICE) happens, collects and dumps debug information into a temporary file ๐Ÿ˜ญ
  • -fdump-unnumbered โ€” when doing debugging dumps, suppresses instruction numbers and address output โœจ this makes diff way easier for compiler invocations with different options, in particular with and without -g
  • -fdump-unnumbered-links โ€” when doing debugging dumps (see -d option above), suppresses instruction numbers for the links to the previous and next instructions in a sequence ๐Ÿงš
  • -fdump-ipa-switch, -fdump-ipa-switch-options โ€” controls dumping at various stages of inter-procedural analysis, language tree to a file ๐ŸŒˆ the file name is your source file name with a switch-specific suffix appended, and it gets created in the same directory as the output file. The possible dumps are:
    • all โ€” enables all inter-procedural analysis dumps
    • cgraph โ€” dumps information about call-graph optimization, unused function removal, and inlining decisions
    • inline โ€” dumps after function inlining

Additionally, the options -optimized, -missed, -note, and -all can be provided, with the same meaning as for -fopt-info, defaulting to -optimized. For example, -fdump-ipa-inline-optimized-missed will emit information on callsites that were inlined, along with callsites that were not inlined. By default, the dump will contain messages about successful optimizations (equivalent to -optimized) together with low-level details about the analysis.

  • -fdump-lang-all, -fdump-lang-switch, -fdump-lang-switch-options, -fdump-lang-switch-options=filename โ€” controls the dumping of language-specific information ๐Ÿ’… the options and filename bits work exactly like in the -fdump-tree option. The switch values accepted are:
    • all โ€” enables all language-specific dumps
    • class โ€” dumps class hierarchy information ๐Ÿ‘‘ virtual table information is emitted unless slim is specified. This is C++ only.
    • raw โ€” dumps the raw internal tree data ๐Ÿ“ this is C++ only too
  • -fdump-passes โ€” prints on stderr the list of optimization passes that are turned on and off by the current command-line options ๐Ÿฆ‹
  • -fdump-statistics-option โ€” enables and controls dumping of pass statistics in a separate file ๐Ÿ“Š the file name is your source file name with a suffix ending in .statistics, and it's created in the same directory as the output file. With the -option form, -stats sums counters over the whole compilation unit, while -details dumps every event as the passes generate them. With no option, the default is to sum counters for each function compiled.
  • -fdump-tree-all, -fdump-tree-switch, -fdump-tree-switch-options, -fdump-tree-switch-options=filename โ€” controls dumping at various stages of processing the intermediate language tree to a file ๐ŸŒธ if the -options form is used, options is a list of - separated options that control the details of the dump. Not every option works with every dump, and the ones that aren't meaningful get ignored. The available options are:
    • address โ€” prints the address of each node ๐Ÿ™ˆ this is usually not meaningful, since it changes according to the environment and source file. Its main use is tying a dump file to a debug environment.
    • asmname โ€” if DECL_ASSEMBLER_NAME has been set for a given decl, uses that in the dump instead of DECL_NAME ๐Ÿ”ฅ its main use is making it easier to work backward from mangled names in the assembly file.
    • slim โ€” when dumping front-end intermediate representations, inhibits dumping members of a scope or body of a function just because that scope has been reached. Only dumps those items when they're directly reachable by some other path. When dumping pretty-printed trees, this inhibits dumping the bodies of control structures. When dumping RTL, prints it in slim (condensed) form instead of the default LISP-like representation.
    • raw โ€” prints a raw representation of the tree. By default, trees are pretty-printed into a C-like representation.
    • details โ€” enables more detailed dumps (not honored by every dump option) ๐Ÿ’– also includes information from the optimization passes.
    • stats โ€” enables dumping various statistics about the pass (not honored by every dump option).
    • blocks โ€” enables showing basic block boundaries (disabled in raw dumps).
    • graph โ€” for each of the other indicated dump files (-fdump-rtl-pass), dumps a representation of the control flow graph suitable for viewing with GraphViz to file.passid.pass.dot ๐Ÿ•ธ๏ธ each function in the file is pretty-printed as a subgraph, so GraphViz can render them all in a single plot. This option currently only works for RTL dumps, and the RTL is always dumped in slim form.
    • vops โ€” enables showing virtual operands for every statement.
    • lineno โ€” enables showing line numbers for statements.
    • uid โ€” enables showing the unique ID (DECL_UID) for each variable.
    • verbose โ€” enables showing the tree dump for each statement.
    • eh โ€” enables showing the EH region number holding each statement.
    • scev โ€” enables showing scalar evolution analysis details.
    • optimized โ€” enables showing optimization information (only available in certain passes).
    • missed โ€” enables showing missed optimization information (only available in certain passes).
    • note โ€” enables other detailed optimization information (only available in certain passes).
    • all โ€” turns on all options, except raw, slim, verbose and lineno.
    • optall โ€” turns on all optimization options, i.e., optimized, missed, and note.

To figure out what tree dumps are available or find the dump for a pass you're interested in, follow these steps:

  1. Invoke GCC with -fdump-passes and look in the stderr output for a code that matches the pass you're after. For example, the codes tree-evrp, tree-vrp1, and tree-vrp2 correspond to the three Value Range Propagation passes. The number at the end tells the distinct invocations of the same pass apart.
  2. To enable creation of the dump file, append the pass code to the -fdump- option prefix and invoke GCC with it. For example, to enable the dump from the Early Value Range Propagation pass, invoke GCC with the -fdump-tree-evrp option. Optionally, you may specify the name of the dump file. If you don't specify one, GCC creates one as described below.
  3. Find the pass dump in a file whose name is made of three components separated by a period: the name of the source file GCC was invoked to compile, a numeric suffix indicating the pass number followed by the letter t for tree passes (and the letter r for RTL passes), and finally the pass code. For example, the Early VRP pass dump might be in a file named myfile.c.038t.evrp in the current working directory. Note that the numeric codes are not stable and may change from one version of GCC to another โš ๏ธ
  • -fopt-info, -fopt-info-options, -fopt-info-options=filename โ€” controls optimization dumps from various optimization passes ๐Ÿ”ฅ if the -options form is used, options is a list of - separated option keywords that select the dump details and optimizations.

The options can be divided into three groups:

  1. ๐Ÿ’Œ options that decide what kinds of messages get printed,
  2. ๐Ÿ” options that set how verbose the dump is, and
  3. โšก options that decide which optimizations get included.

Mix and match from each group all you want, because they don't overlap at all ๐Ÿ’…. If there's ever a clash on the command line, the later option wins, so the last one you type is the one that slays ๐Ÿ‘‘.


๐Ÿ’Œ Message kinds

  • optimized โ€” Prints info whenever an optimization successfully lands โœจ. Each pass decides what's relevant, so the vectorizer passes will tell you the source location of loops they successfully vectorize ๐Ÿฆ‹.
  • missed โ€” Prints info about optimizations that got missed ๐Ÿฅฒ. Individual passes control what goes into the output.
  • note โ€” Verbose info about optimizations, like certain transformations and more detailed messages about decisions ๐Ÿง.
  • all โ€” Full detail, no skipping! This includes optimized, missed, and note ๐Ÿ”ฅ.

๐Ÿ” Dump verbosity

  • internals โ€” By default you only get the "high-level" messages ๐Ÿ’. Turn this on to unlock extra, more detailed messages, which are mostly of interest to GCC developers ๐Ÿค“.

๐ŸŽฏ Optimization groups

One or more of these keywords can be used to describe a whole group of optimizations:

  • ipa โ€” Enables dumps from all interprocedural optimizations ๐ŸŒ.
  • loop โ€” Enables dumps from all loop optimizations ๐Ÿ”.
  • inline โ€” Enables dumps from all inlining optimizations ๐Ÿ“ฆ.
  • omp โ€” Enables dumps from all OMP (Offloading and Multi Processing) optimizations ๐Ÿš€.
  • vec โ€” Enables dumps from all vectorization optimizations ๐ŸŽ€.
  • optall โ€” Enables dumps from all optimizations, and it's a superset of the groups above ๐Ÿ‘‘.

If you leave options out, it defaults to optimized-optall. That means you get messages about successful optimizations from all the passes, minus anything tagged as "internals" ๐Ÿ’–.

If you give a filename, the dumps from all the applicable optimizations get concatenated into it. Otherwise the dump goes to stderr ๐Ÿ“œ. You can type as many -fopt-info options as you want, but only one of them can include a filename ๐Ÿ™…. If other filenames sneak in, every option after the first one gets ignored ๐Ÿซ .

Heads up, bestie: the output filename gets overwritten when there are multiple translation units. If you want a combined output from several translation units, use stderr instead โš ๏ธ.

Let's look at some examples ๐Ÿง. This one sends the optimization info to stderr:

gcc -O3 -fopt-info

This one outputs the missed optimization report from all the passes into missed.all:

gcc -O3 -fopt-info-missed=missed.all

And this one prints info about missed optimization opportunities from the vectorization passes to stderr:

gcc -O2 -ftree-vectorize -fopt-info-vec-missed

Note that -fopt-info-vec-missed is equivalent to -fopt-info-missed-vec. The order of the optimization group names and message types listed after -fopt-info doesn't matter ๐Ÿ™Œ.

As another example:

gcc -O3 -fopt-info-inline-optimized-missed=inline.txt

This outputs info about missed optimizations, as well as optimized locations, from all the inlining passes into inline.txt ๐Ÿช„.

Finally, consider:

gcc -fopt-info-vec-missed=vec.miss -fopt-info-loop-optimized=loop.opt

Here the two output filenames vec.miss and loop.opt are in conflict, since only one output file is allowed ๐ŸฅŠ. In this case, only the first option takes effect and the subsequent options are ignored. Thus only vec.miss is produced, and it contains dumps from the vectorizer about missed opportunities.


๐Ÿ’พ -fsave-optimization-record

Writes a SRCFILE.opt-record.json.gz file detailing what optimizations were performed, for those optimizations that support -fopt-info ๐Ÿ“.

This option is experimental, and the format of the data inside the compressed JSON file is subject to change ๐Ÿงช.

It's roughly a machine-readable version of -fopt-info-all, as a collection of messages with source file, line number and column number. Each message also gets these extras:

  • the execution count of the code being optimized, plus metadata about whether it came from actual profile data or just an estimate, so consumers can prioritize messages by code hotness ๐Ÿ”ฅ
  • the function name of the code being optimized, where applicable
  • the "inlining chain" for the code being optimized, so when a function is inlined into several different places (which might themselves be inlined), the reader can tell the copies apart ๐Ÿช†
  • objects identifying the parts of the message that refer to expressions, statements or symbol-table nodes, which of these categories they are, and, when available, their source code location
  • the GCC pass that emitted the message, and
  • the location in GCC's own code from which the message was emitted

Also, some messages are logically nested within other messages, reflecting implementation details of the optimization passes ๐Ÿชบ.


๐Ÿง  -fsched-verbose=n

On targets that use instruction scheduling, this option controls how much debugging output the scheduler prints to the dump files ๐Ÿ”ง.

For n greater than zero, -fsched-verbose outputs the same information as -fdump-rtl-sched1 and -fdump-rtl-sched2. For n greater than one, it also outputs basic block probabilities, detailed ready list information and unit/insn info. For n greater than two, it includes RTL at abort point, control-flow and regions info. And for n over four, -fsched-verbose also includes dependence info ๐Ÿงฉ.


๐ŸŽ›๏ธ -fenable-kind-pass, -fdisable-kind-pass=range-list

These are a set of options used to explicitly disable or enable optimization passes ๐Ÿ•น๏ธ. They're intended for debugging GCC.

Compiler users should use the regular options for enabling and disabling passes instead โš ๏ธ.
  • -fdisable-ipa-pass โ€” Disables the IPA pass pass, where pass is the pass name ๐Ÿšซ. If the same pass is statically invoked in the compiler multiple times, append a sequential number starting from 1 to the pass name.
  • -fdisable-rtl-pass, -fdisable-rtl-pass=range-list โ€” Disables the RTL pass pass ๐Ÿ›‘. The same numbering rule applies: if the pass is statically invoked more than once, append a sequential number starting from 1. range-list is a comma-separated list of function ranges or assembler names. Each range is a number pair separated by a colon, and it's inclusive at both ends. If the range is trivial, the number pair can be simplified to a single number. If the function's call graph node's uid falls within one of the specified ranges, the pass is disabled for that function ๐ŸŽฏ. The uid is shown in the function header of a dump file, and you can dump the pass names by using -fdump-passes ๐Ÿ”Ž.
  • -fdisable-tree-pass, -fdisable-tree-pass=range-list โ€” Disables the tree pass pass. See -fdisable-rtl for the description of option arguments.
  • -fenable-ipa-pass โ€” Enables the IPA pass pass, where pass is the pass name โœ…. If the same pass is statically invoked in the compiler multiple times, append a sequential number starting from 1 to the pass name.
  • -fenable-rtl-pass, -fenable-rtl-pass=range-list โ€” Enables the RTL pass pass. See -fdisable-rtl for option argument description and examples.
  • -fenable-tree-pass, -fenable-tree-pass=range-list โ€” Enables the tree pass pass. See -fdisable-rtl for the description of option arguments.

Here are some examples showing these options in action ๐Ÿงช:

# disable ccp1 for all functions
   -fdisable-tree-ccp1
# disable complete unroll for function whose cgraph node uid is 1
   -fenable-tree-cunroll=1
# disable gcse2 for functions at the following ranges [1,1],
# [300,400], and [400,1000]
# disable gcse2 for functions foo and foo2
   -fdisable-rtl-gcse2=foo,foo2
# disable early inlining
   -fdisable-tree-einline
# disable ipa inlining
   -fdisable-ipa-inline
# enable tree full unroll
   -fenable-tree-unroll

๐Ÿชž -fchecking, -fchecking=n

Enables internal consistency checking ๐Ÿ”. The default depends on the compiler configuration. -fchecking=2 enables further internal consistency checking that might affect code generation โš ๏ธ.


๐ŸŽฒ -frandom-seed=string

This option provides a seed that GCC uses in place of random numbers when generating certain symbol names that have to be different in every compiled file ๐ŸŒˆ. It's also used to place unique stamps in coverage data files and the object files that produce them. You can use the -frandom-seed option to produce reproducibly identical object files ๐Ÿ’œ.

The string can either be a number (decimal, octal or hex) or an arbitrary string. An arbitrary string gets converted to a number by computing CRC32 ๐Ÿ”ข.

The string should be different for every file you compile ๐Ÿซถ.


๐Ÿ“‚ -save-temps, -save-temps=cwd

Stores the usual "temporary" intermediate files permanently ๐Ÿ—‚๏ธ. They get placed in the current directory and named based on the source file. So compiling foo.c with -c -save-temps produces foo.i and foo.s, as well as foo.o ๐Ÿฆ‹. This creates a preprocessed foo.i output file even though the compiler now normally uses an integrated preprocessor ๐Ÿงš.

When you use -save-temps together with the -x command-line option, it's smart enough to avoid overwriting an input source file that has the same extension as an intermediate file ๐Ÿ™Œ. If you want the corresponding intermediate file, just rename the source file before using -save-temps ๐Ÿ”.

If you run GCC in parallel ๐Ÿ˜ญ on files that share a base name, like foo.c, in different subdirectories, or the same file compiled for several output destinations, the compilers can totally step on each other and overwrite each other's temp files ๐Ÿ’€. Check this out:

gcc -save-temps -o outdir1/foo.o indir1/foo.c&
gcc -save-temps -o outdir2/foo.o indir2/foo.c&
Heads up, bestie ๐Ÿšจ: this can end with foo.i and foo.o being written to at the same time by both compilers. Not a vibe.
  • -save-temps=obj โ€” Keeps the usual "temporary" intermediate files forever ๐Ÿ’พโœจ. If you use -o, the temp files get named after the object file. If you don't use -o, -save-temps=obj acts exactly like -save-temps ๐Ÿซถ.

For example, these commands:

gcc -save-temps=obj -c foo.c
gcc -save-temps=obj -c bar.c -o dir/xbar.o
gcc -save-temps=obj foobar.c -o dir2/yfoobar

create foo.i, foo.s, dir/xbar.i, dir/xbar.s, dir2/yfoobar.i, dir2/yfoobar.s, and dir2/yfoobar.o. Iconic organization ๐Ÿ“๐Ÿ‘‘.

  • -time[=file] โ€” Reports the CPU time each subprocess in the compilation sequence takes โฑ๏ธ. For C source files, that's the compiler proper and the assembler, plus the linker if you're linking ๐Ÿ”—.

If you don't give an output file, the output looks like this:

# cc1 0.12 0.01
# as 0.00 0.01

The first number on each line is the "user time", which is the time spent running the program itself ๐Ÿง . The second number is the "system time", which is the time spent in operating system routines on the program's behalf ๐Ÿ’ป. Both numbers are in seconds โญ.

If you do give an output file, the output gets appended to that file, and it looks like this:

0.12 0.01 cc1 <options>
0.00 0.01 as <options>

Here the "user time" and "system time" get moved in front of the program name, and the options passed to the program are shown too. That way you can later figure out which file was being compiled and with which options ๐Ÿ•ต๏ธโ€โ™€๏ธ๐ŸŽ€.

  • -fdump-final-insns[=*file*] โ€” Dumps the final internal representation (RTL) into file ๐Ÿ—‚๏ธ. If you leave off the optional argument (or file is .), the dump file's name comes from adding .gkd to the compilation output file name.
  • -fcompare-debug[=*opts*] โ€” If compilation doesn't hit any errors, GCC runs the compiler a second time ๐Ÿ”. This second run gets opts and -fcompare-debug-second added to its arguments. It dumps the final internal representation in both compilations and prints an error if they differ ๐Ÿฅบ.

If you leave out the equal sign, the default -gtoggle is used.

The environment variable GCC_COMPARE_DEBUG ๐ŸŒธ, if it's defined, non-empty, and nonzero, implicitly enables -fcompare-debug. If GCC_COMPARE_DEBUG is defined to a string starting with a dash, that string is used for opts. Otherwise, the default -gtoggle is used.

-fcompare-debug=, with the equal sign but without opts, is the same as -fno-compare-debug ๐Ÿšซ. That one turns off the dumping of the final representation and the second compilation, and it even stops GCC_COMPARE_DEBUG from taking effect. Hard stop ๐Ÿ›‘.

To check for full coverage during -fcompare-debug testing, set GCC_COMPARE_DEBUG to -fcompare-debug-not-overridden. GCC rejects that as an invalid option in any real compilation (as opposed to preprocessing, assembly, or linking) ๐Ÿ™…โ€โ™€๏ธ. If you just want a warning instead, setting GCC_COMPARE_DEBUG to -w%n-fcompare-debug not overridden will do the trick โœจ.

  • -fcompare-debug-second โ€” This is passed to the compiler implicitly for the second compilation requested by -fcompare-debug ๐Ÿชž. It comes along with options that silence warnings, and it leaves out any other options that would make the compiler write output to files or to standard output as a side effect ๐Ÿ™ˆ. During that second compilation, dump files and preserved temporary files get the extra .gk extension, so they don't overwrite the ones from the first run ๐Ÿ’….

When you pass this option to the compiler driver, the first compilation gets skipped. That makes it pretty much only useful for debugging the compiler itself ๐Ÿงš.

  • -gtoggle โ€” Turns off debug info generation if leaving this option out would generate it. Otherwise, it turns debug info on at level 2 ๐Ÿ”„. Where you put it on the command line doesn't matter. It takes effect after all the other options are processed, and it only does its thing once, no matter how many times you pass it ๐ŸŽฏ. It's mainly meant to be used with -fcompare-debug.
  • -fvar-tracking-assignments-toggle โ€” Toggles -fvar-tracking-assignments, the same way -gtoggle toggles -g ๐Ÿฆ‹.
  • -Q โ€” Makes the compiler print out each function name as it gets compiled, and print some statistics about each pass when it finishes ๐Ÿ“Š.
  • -ftime-report โ€” Makes the compiler print some statistics about the time each pass consumed when it finishes โฐ.
  • -ftime-report-details โ€” Records the time consumed by infrastructure parts separately for each pass ๐Ÿงฉ.
  • -fira-verbose=n โ€” Controls how verbose the dump file for the integrated register allocator is. The default value is 5. If the value n is greater than or equal to 10, the dump output goes to stderr in the same format as n minus 10 ๐ŸŒˆ.
  • -flto-report โ€” Prints a report with internal details on how the link-time optimizer works ๐Ÿ”. What's in this report changes from version to version. It's meant for GCC developers, for when they're processing object files in LTO mode (via -flto) ๐Ÿ› ๏ธ.

Disabled by default.

  • -flto-report-wpa โ€” Like -flto-report, but it only prints for the WPA phase of Link Time Optimization ๐ŸŽฏ.
  • -fmem-report โ€” Makes the compiler print some statistics about permanent memory allocation when it finishes ๐Ÿง .
  • -fmem-report-wpa โ€” Makes the compiler print some statistics about permanent memory allocation for the WPA phase only ๐Ÿง .
  • -fpre-ipa-mem-report, -fpost-ipa-mem-report โ€” Makes the compiler print some statistics about permanent memory allocation before or after interprocedural optimization ๐Ÿ’–.
  • -fprofile-report โ€” Makes the compiler print some statistics about the consistency of the (estimated) profile and the effect of individual passes ๐Ÿ“ˆ.
  • -fstack-usage โ€” Makes the compiler output stack usage info for your program, broken down per function ๐Ÿฅž. The dump filename is made by appending .su to the auxname. The auxname comes from the output file name if you explicitly specified one and it's not an executable. Otherwise, it's the basename of the source file ๐Ÿ“. Each entry has three fields:
    • The name of the function.
    • A number of bytes.
    • One or more qualifiers: "static", "dynamic", "bounded".

The "static" qualifier means the function manages the stack statically ๐Ÿงฑ. A fixed number of bytes gets allocated for the frame on function entry and released on function exit, and no other stack adjustments get made in the function. The second field is this fixed number of bytes.

The "dynamic" qualifier means the function manages the stack dynamically ๐ŸŒ€. On top of the static allocation above, stack adjustments happen in the body of the function, like pushing and popping arguments around function calls. If the "bounded" qualifier is also there, the amount of these adjustments is bounded at compile time, and the second field is an upper bound on the total stack used by the function โœ…. If it's not present, the amount of these adjustments isn't bounded at compile time, and the second field only represents the bounded part ๐Ÿ™ƒ.

  • -fstats โ€” Emits statistics about front-end processing at the end of compilation ๐Ÿ“‰. This option is only supported by the C++ front end, and the info is generally only useful to the G++ development team ๐Ÿง‘โ€๐Ÿ’ป.
  • -fdbg-cnt-list โ€” Prints the name and the counter upper bound for all debug counters ๐Ÿ“‹.
  • -fdbg-cnt=*counter-value-list* โ€” Sets the internal debug counter lower and upper bounds ๐ŸŽš๏ธ. counter-value-list is a comma-separated list of name:lower_bound:upper_bound tuples, which set the lower and upper bound of each debug counter name. The lower_bound is optional and is zero-initialized if it isn't set. All debug counters start with an upper bound of "UINT_MAX", so dbg_cnt always returns true unless this option sets the upper bound ๐Ÿ˜Œ. For example, with -fdbg-cnt=dce:2:4,tail_call:10, dbg_cnt(dce) only returns true for the third and fourth invocations. For dbg_cnt(tail_call), true is returned for the first 10 invocations ๐Ÿ”ข.
  • -print-file-name=*library* โ€” Prints the full absolute name of the library file library that would be used when linking, and then stops there ๐Ÿ—บ๏ธ. With this option, GCC doesn't compile or link anything. It just prints the file name ๐Ÿ–จ๏ธ.
  • -print-multi-directory โ€” Prints the directory name for the multilib selected by any other switches on the command line ๐Ÿ“‚. This directory is supposed to exist in GCC_EXEC_PREFIX ๐ŸŒท.
  • -print-multi-lib โ€” Prints the mapping from multilib directory names to the compiler switches that enable them ๐Ÿ—‚๏ธ. The directory name is separated from the switches by ;. Each switch starts with an @ instead of a -, and there are no spaces between multiple switches. This is supposed to make shell processing easier ๐Ÿš.
  • -print-multi-os-directory โ€” Prints the path to the OS libraries for the selected multilib, relative to some lib subdirectory ๐ŸŒˆ. If the OS libraries live in the lib subdirectory and no multilibs are used, this is usually just .. If the OS libraries live in libsuffix sibling directories, it prints things like ../lib64, ../lib, or ../lib32. If they live in lib/subdir subdirectories, it prints things like amd64, sparcv9, or ev6 ๐Ÿงฉ.
  • -print-multiarch โ€” Prints the path to the OS libraries for the selected multiarch, relative to some lib subdirectory ๐Ÿฆ„.
  • -print-prog-name=*program* โ€” Works like -print-file-name, but searches for a program such as cpp ๐Ÿ”Ž.
  • -print-libgcc-file-name โ€” Same as -print-file-name=libgcc.a ๐Ÿ’œ.

This is useful when you use -nostdlib or -nodefaultlibs but you still want to link with libgcc.a ๐Ÿซถ. You can do:

gcc -nostdlib <files>... `gcc -print-libgcc-file-name`
  • -print-search-dirs โ€” okay so this one is a lifesaver ๐Ÿงš It prints the name of the configured installation directory AND the list of program and library directories gcc searches, and then it just stops. Nothing else gets done. Literally that's it ๐Ÿ’…

This one is super handy when gcc throws installation problem, cannot exec cpp0: No such file or directory. ๐Ÿ˜ญ To fix that, you either need to put cpp0 and the other compiler components where gcc expects to find them, or you can set the environment variable GCC_EXEC_PREFIX to the directory where you installed them. Don't forget the trailing / ๐Ÿซถ

  • -print-sysroot โ€” this prints the target sysroot directory used during compilation ๐ŸŒธ It's the one set either at configure time or with the --sysroot option, and it might come with an extra suffix depending on your compilation options. If no target sysroot is set, this option prints nothing at all. Silent queen behavior ๐Ÿ‘‘
  • -print-sysroot-headers-suffix โ€” prints the suffix that gets added to the target sysroot when gcc goes searching for headers ๐Ÿ” If the compiler wasn't configured with a suffix, you'll get an error instead. And again, it won't do anything else โœจ
  • -dumpmachine โ€” prints the compiler's target machine, like i686-pc-linux-gnu ๐Ÿฆ‹ Then it stops. No extra steps, no drama ๐Ÿ’–
  • -dumpversion โ€” prints the compiler version, like 3.0, 6.3.0 or 7 ๐ŸŽ€ Then it stops too. This is the version used in filesystem paths and specs, and depending on how the compiler was configured, it can be one number (the major version), two numbers separated by a dot (major and minor), or three numbers separated by dots (major, minor and patchlevel) ๐ŸŒˆ
  • -dumpfullversion โ€” prints the full compiler version and then stops ๐Ÿ’… The output is always three numbers separated by dots: major, minor and patchlevel. Always. No exceptions bestie ๐Ÿ’œ
  • -dumpspecs โ€” prints the compiler's built-in specs and then stops ๐Ÿ“ This one is used when GCC itself is being built, so it's kind of an insider thing ๐Ÿ™ˆ

๐ŸŒˆ Machine-Dependent Options ๐ŸŒˆ

Every target machine GCC supports can have its own options ๐Ÿงš For example, you can compile for a particular processor variant or ABI, or control optimizations that are specific to that machine. By convention, the names of machine-specific options start with -m ๐Ÿ’–

Some configurations of the compiler also support extra target-specific options, usually so they can stay compatible with other compilers on the same platform ๐Ÿซถ

๐Ÿฆ‹ AArch64 Options ๐Ÿฆ‹

These options are defined for AArch64 implementations โœจ

  • -mabi=name โ€” generates code for the specified data model ๐Ÿ’… The allowed values are ilp32, which is a SysV-like data model where int, long int and pointers are 32 bits, and lp64, which is also SysV-like but where int is 32 bits while long int and pointers are 64 bits ๐ŸŒธ

The default depends on the specific target configuration.

๐Ÿ˜ญ Heads up: the LP64 and ILP32 ABIs are NOT link-compatible. You must compile your entire program with the same ABI, and link it with a compatible set of libraries.
  • -mbig-endian โ€” generates big-endian code ๐ŸŒˆ This is the default when GCC is configured for an aarch64_be-*-* target.
  • -mgeneral-regs-only โ€” generates code that only uses the general-purpose registers ๐ŸŽ€ This stops the compiler from using floating-point and Advanced SIMD registers, but it doesn't put any restrictions on the assembler.
  • -mlittle-endian โ€” generates little-endian code ๐Ÿ’œ This is the default when GCC is configured for an aarch64-*-* target but NOT an aarch64_be-*-* target.
  • -mcmodel=tiny โ€” generates code for the tiny code model ๐Ÿฃ The program and its statically defined symbols have to be within 1MB of each other. Programs can be statically or dynamically linked.
  • -mcmodel=small โ€” generates code for the small code model ๐ŸŒท The program and its statically defined symbols have to be within 4GB of each other. Programs can be statically or dynamically linked. This is the default code model, so you get it automatically โœจ
  • -mcmodel=large โ€” generates code for the large code model ๐ŸŒŒ It makes no assumptions about the addresses and sizes of sections, which is very chill but also very limited: programs can be statically linked only ๐Ÿ™ˆ
  • -mstrict-align, -mno-strict-align โ€” these let you avoid (-mstrict-align) or allow (-mno-strict-align) generating memory accesses that might not be aligned on a natural object boundary, as described in the architecture specification ๐Ÿงฑ
  • -momit-leaf-frame-pointer, -mno-omit-leaf-frame-pointer โ€” these omit (-momit-leaf-frame-pointer) or keep (-mno-omit-leaf-frame-pointer) the frame pointer in leaf functions ๐Ÿƒ The omit behavior is the default.
  • -mstack-protector-guard=guard, -mstack-protector-guard-reg=reg, -mstack-protector-guard-offset=offset โ€” this generates stack protection code using a canary at guard ๐Ÿ›ก๏ธ The supported locations are global (for a global canary) or sysreg (for a canary in an appropriate system register).

With the sysreg choice, the options -mstack-protector-guard-reg=reg and -mstack-protector-guard-offset=offset also tell it which system register to use as the base register for reading the canary, and what offset from that base register to use ๐Ÿ”

๐Ÿ˜ญ There's no default register or offset for this. It's entirely for use within the Linux kernel, so don't go sprinkling it everywhere.
  • -mstack-protector-guard=guard, -mstack-protector-guard-reg=reg, -mstack-protector-guard-offset=offset โ€” this is the exact same entry again, so the same deal applies ๐Ÿ” It generates stack protection code using a canary at guard. The supported locations are global for a global canary or sysreg for a canary in an appropriate system register.

With the sysreg choice, -mstack-protector-guard-reg=reg and -mstack-protector-guard-offset=offset furthermore specify which system register to use as the base register for reading the canary, and from what offset from that base register.

๐Ÿ˜ญ There is no default register or offset as this is entirely for use within the Linux kernel.
  • -mtls-dialect=desc โ€” uses TLS descriptors as the thread-local storage mechanism for dynamic accesses of TLS variables ๐Ÿงต This is the default, so it's the one you get if you don't pick anything ๐Ÿ’…
  • -mtls-dialect=traditional โ€” uses traditional TLS as the thread-local storage mechanism for dynamic accesses of TLS variables ๐Ÿ•ฐ๏ธ
  • -mtls-size=size โ€” specifies the bit size of immediate TLS offsets ๐Ÿ“ The valid values are 12, 24, 32 and 48. Heads up: this option needs binutils 2.26 or newer โš ๏ธ
  • -mfix-cortex-a53-835769, -mno-fix-cortex-a53-835769 โ€” enables (-mfix-cortex-a53-835769) or disables (-mno-fix-cortex-a53-835769) the workaround for ARM Cortex-A53 erratum number 835769 ๐Ÿ› ๏ธ The workaround involves inserting a NOP instruction between memory instructions and 64-bit integer multiply-accumulate instructions.
  • -mfix-cortex-a53-843419, -mno-fix-cortex-a53-843419 โ€” enables or disables the workaround for ARM Cortex-A53 erratum number 843419 ๐Ÿ”ง This erratum workaround is made at link time, so this option only passes the corresponding flag to the linker ๐Ÿ”—
  • -mlow-precision-recip-sqrt, -mno-low-precision-recip-sqrt โ€” enables or disables the reciprocal square root approximation ๐Ÿงฎ This only does anything if -ffast-math or -funsafe-math-optimizations is also used. When it's on, reciprocal square root results lose precision, down to about 16 bits for single precision and 32 bits for double precision ๐ŸŒ€
  • -mlow-precision-sqrt, -mno-low-precision-sqrt โ€” enables or disables the square root approximation ๐Ÿ“ This only has an effect if -ffast-math or -funsafe-math-optimizations is also used. When enabled, square root results drop to about 16 bits for single precision and 32 bits for double precision. If you enable it, it implies -mlow-precision-recip-sqrt too ๐Ÿช„
  • -mlow-precision-div, -mno-low-precision-div โ€” enables or disables the division approximation โž— This only has an effect if -ffast-math or -funsafe-math-optimizations is also used. When enabled, division results drop to about 16 bits for single precision and 32 bits for double precision ๐ŸŽฒ
  • -mtrack-speculation, -mno-track-speculation โ€” enables or disables generating additional code that tracks speculative execution through conditional branches ๐Ÿ•ต๏ธ The tracking state can then be used by the compiler when expanding calls to __builtin_speculation_safe_copy, so it can generate a more efficient code sequence ๐Ÿง 
  • -moutline-atomics, -mno-outline-atomics โ€” enables or disables calls to out-of-line helpers that implement atomic operations โšก At runtime, these helpers figure out whether the LSE instructions from ARMv8.1-A can be used. If they can't, they fall back to the load/store-exclusive instructions that are present in the base ARMv8.0 ISA ๐Ÿงฉ

This option only applies when compiling for the base ARMv8.0 instruction set. If you're using a later revision, like -march=armv8.1-a or -march=armv8-a+lse, the ARMv8.1-Atomics instructions get used directly. The same goes for -mcpu= when the selected CPU supports the lse feature ๐Ÿ’ซ

  • -march=name โ€” specifies the name of the target architecture and, optionally, one or more feature modifiers ๐Ÿ—๏ธ This option has the form -march=arch{+[no]feature}*.

The permissible values for arch are armv8-a, armv8.1-a, armv8.2-a, armv8.3-a, armv8.4-a, armv8.5-a or native ๐ŸŒŸ

The value armv8.5-a implies armv8.4-a and enables compiler support for the ARMv8.5-A architecture extensions ๐Ÿš€

The value armv8.4-a implies armv8.3-a and enables compiler support for the ARMv8.4-A architecture extensions ๐Ÿš€

The value armv8.3-a implies armv8.2-a and enables compiler support for the ARMv8.3-A architecture extensions ๐Ÿš€

The value armv8.2-a implies armv8.1-a and enables compiler support for the ARMv8.2-A architecture extensions ๐Ÿš€

The value armv8.1-a implies armv8-a and enables compiler support for the ARMv8.1-A architecture extension. In particular, it enables the +crc, +lse, and +rdma features ๐Ÿ’–

The value native is available on native AArch64 GNU/Linux and makes the compiler pick the architecture of the host system. This option has no effect if the compiler is unable to recognize the architecture of the host system, ๐Ÿซ 

The permissible values for feature are listed in the sub-section on aarch64-feature-modifiers,,-march and -mcpu Feature Modifiers. Where conflicting feature modifiers are specified, the right-most feature is used ๐ŸŽ€

GCC uses name to determine what kind of instructions it can emit when generating assembly code. If -march is specified without either -mtune or -mcpu also being specified, the code is tuned to perform well across a range of target processors implementing the target architecture ๐ŸŒธ

โœจ OPTIONS โœจ

  • -mtune=name โ€” okay bestie, this one tells GCC which target processor to tune the performance of your code for ๐Ÿ’… The valid values are generic, cortex-a35, cortex-a53, cortex-a55, cortex-a57, cortex-a72, cortex-a73, cortex-a75, cortex-a76, ares, exynos-m1, emag, falkor, neoverse-e1, neoverse-n1, neoverse-n2, neoverse-v1, neoverse-512tvb, qdf24xx, saphira, phecda, xgene1, vulcan, octeontx, octeontx81, octeontx83, a64fx, thunderx, thunderxt88, thunderxt88p1, thunderxt81, tsv110, thunderxt83, thunderx2t99, zeus, cortex-a57.cortex-a53, cortex-a72.cortex-a53, cortex-a73.cortex-a35, cortex-a73.cortex-a53, cortex-a75.cortex-a55, cortex-a76.cortex-a55, and native ๐Ÿฆ‹

The dotted pairs cortex-a57.cortex-a53, cortex-a72.cortex-a53, cortex-a73.cortex-a35, cortex-a73.cortex-a53, cortex-a75.cortex-a55, and cortex-a76.cortex-a55 are the big.LITTLE combos ๐Ÿงš They tell GCC to tune for a big.LITTLE system, so yeah, iykyk.

neoverse-512tvb is giving very specific energy โœจ It means GCC tunes for Neoverse cores that (a) implement SVE and (b) have a total vector bandwidth of 512 bits per cycle. Translation: those cores can run 4 128-bit Advanced SIMD arithmetic instructions a cycle, plus an equivalent number of SVE arithmetic instructions a cycle (2 for 256-bit SVE, 4 for 128-bit SVE). It's more general than tuning for one specific core like Neoverse V1, but more specific than the default tuning down below ๐ŸŒธ

On native AArch64 GNU/Linux systems, the value native tunes performance to whatever host system you're on ๐Ÿ”ฅ If the compiler can't recognize the processor of the host system, this option just has no effect. No drama.

If none of -mtune=, -mcpu=, or -march= are specified, the code gets tuned to perform well across a range of target processors ๐Ÿ’œ

This option cannot be suffixed by feature modifiers ๐Ÿ™ˆ

  • -mcpu=name โ€” this is the target processor name, and it can be suffixed by one or more feature modifiers ๐Ÿ’– The form is -mcpu=cpu{+[no]feature}*, and the permissible values for cpu are the same ones you get for -mtune. For the permissible feature values, check out the sub-section on aarch64-feature-modifiers,,-march and -mcpu Feature Modifiers. If you specify conflicting feature modifiers, the right-most one wins, periodt ๐Ÿ‘‘

GCC uses name to figure out what kind of instructions it's allowed to emit when generating assembly code (same as -march), and to pick the target processor it tunes performance for (same as -mtune). If you use this option together with -march or -mtune, those options take precedence over the matching part of this option ๐Ÿซถ

-mcpu=neoverse-512tvb is special because it doesn't refer to one specific core. It refers to all Neoverse cores that (a) implement SVE and (b) have a total vector bandwidth of 512 bits a cycle โœจ Unless you override it with -march, -mcpu=neoverse-512tvb generates code that can run on a Neoverse V1 core, since Neoverse V1 is the first Neoverse core with these properties. Unless you override it with -mtune, -mcpu=neoverse-512tvb tunes code the same way as -mtune=neoverse-512tvb does.

  • -moverride=string โ€” overrides the tuning decisions the back-end makes in response to a -mtune= switch ๐Ÿงช The syntax, semantics, and accepted values for string are not guaranteed to stay consistent across releases.
โš ๏ธ This option is only intended to be useful when developing GCC. Don't go poking at it in your everyday builds, bestie ๐Ÿ˜ญ
  • -mverbose-cost-dump โ€” turns on verbose cost model dumping in the debug dump files ๐Ÿ” It's provided for debugging the compiler, so it's really for compiler nerds.
  • -mpc-relative-literal-loads, -mno-pc-relative-literal-loads โ€” these enable or disable PC-relative literal loads ๐ŸŒˆ With this on, literal pools get accessed with a single instruction and emitted after each function. The catch is that it limits the maximum size of functions to 1MB. It's enabled by default for -mcmodel=tiny.
  • -msign-return-address=scope โ€” picks which functions get return address signing ๐Ÿ” The permissible values are none, which turns return address signing off; non-leaf, which enables pointer signing for functions that aren't leaf functions; and all, which enables pointer signing for all functions. The default is none.
๐Ÿ’€ This option has been deprecated by -mbranch-protection. Switch over when you can!
  • -mbranch-protection=none|standard|pac-ret[+leaf]|bti โ€” picks the branch protection features to use ๐Ÿ›ก๏ธ none is the default and turns off all types of branch protection. standard turns on all types of branch protection features, and if a feature has extra tuning options, standard sets it to its standard level. pac-ret[+leaf] turns on return address signing to its standard level, which means signing functions that save the return address to memory (non-leaf functions practically always do this) using the a-key. The optional leaf argument extends the signing to include leaf functions. bti turns on the branch target identification mechanism.
  • -mharden-sls=opts โ€” enables compiler hardening against straight line speculation (SLS) ๐Ÿงฑ opts is a comma-separated list of the following options:
    • retbr
    • blr

On top of that, -mharden-sls=all enables all SLS hardening, and -mharden-sls=none disables all of it.

  • -msve-vector-bits=bits โ€” sets the number of bits in an SVE vector register ๐Ÿ“ This option only has an effect when SVE is enabled.

GCC supports two forms of SVE code generation. There's "vector-length agnostic" output that works with any size of vector register, and "vector-length specific" output that lets GCC make assumptions about the vector length when that helps optimization ๐Ÿง  The possible values of bits are scalable, 128, 256, 512, 1024, and 2048. Specifying scalable selects vector-length agnostic output. Right now, -msve-vector-bits=128 also generates vector-length agnostic output. All other values generate vector-length specific code. These values might change in future releases, so the only value you should rely on for code that's portable across different hardware SVE vector lengths is scalable.

The default is -msve-vector-bits=scalable, which produces vector-length agnostic code โœจ

-march and -mcpu Feature Modifiers

Feature modifiers used with -march and -mcpu can be any of the following, and each one also has an inverse, nofeature ๐ŸŽ€

  • crc โ€” enables the CRC extension. This is on by default for -march=armv8.1-a.
  • crypto โ€” enables the Crypto extension. This also enables Advanced SIMD and floating-point instructions.
  • fp โ€” enables floating-point instructions. This is on by default for all possible values for options -march and -mcpu.
  • simd โ€” enables Advanced SIMD instructions. This also enables floating-point instructions. This is on by default for all possible values for options -march and -mcpu.
  • sve โ€” enables Scalable Vector Extension instructions. This also enables Advanced SIMD and floating-point instructions.
  • lse โ€” enables Large System Extension instructions. This is on by default for -march=armv8.1-a.
  • rdma โ€” enables Round Double Multiply Accumulate instructions. This is on by default for -march=armv8.1-a.
  • fp16 โ€” enables the FP16 extension. This also enables floating-point instructions.
  • fp16fml โ€” enables the FP16 fmla extension. This also enables FP16 extensions and floating-point instructions. It's enabled by default for -march=armv8.4-a. Using this option with architectures prior to Armv8.2-A is not supported ๐Ÿšซ
  • rcpc โ€” enables the RcPc extension. This doesn't change code generation from GCC, but it gets passed on to the assembler, so inline asm statements can use instructions from the RcPc extension.
  • dotprod โ€” enables the Dot Product extension. This also enables Advanced SIMD instructions.
  • aes โ€” enables the Armv8-a aes and pmull crypto extension. This also enables Advanced SIMD instructions.
  • sha2 โ€” enables the Armv8-a sha2 crypto extension. This also enables Advanced SIMD instructions.
  • sha3 โ€” enables the sha512 and sha3 crypto extension. This also enables Advanced SIMD instructions. Using this option with architectures prior to Armv8.2-A is not supported ๐Ÿšซ
  • sm4 โ€” enables the sm3 and sm4 crypto extension. This also enables Advanced SIMD instructions. Using this option with architectures prior to Armv8.2-A is not supported ๐Ÿšซ
  • profile โ€” enables the Statistical Profiling extension. This option only enables the extension at the assembler level and doesn't affect code generation.
  • rng โ€” enables the Armv8.5-a Random Number instructions. This option only enables the extension at the assembler level and doesn't affect code generation.
  • memtag โ€” enables the Armv8.5-a Memory Tagging Extensions. This option only enables the extension at the assembler level and doesn't affect code generation.
  • sb โ€” enables the Armv8-a Speculation Barrier instruction. This option only enables the extension at the assembler level and doesn't affect code generation. It's enabled by default for -march=armv8.5-a.
  • ssbs โ€” enables the Armv8-a Speculative Store Bypass Safe instruction. This option only enables the extension at the assembler level and doesn't affect code generation. It's enabled by default for -march=armv8.5-a.
  • predres โ€” enables the Armv8-a Execution and Data Prediction Restriction instructions. This option only enables the extension at the assembler level and doesn't affect code generation. It's enabled by default for -march=armv8.5-a.

Heads up on the chain reactions ๐Ÿ”— Enabling crypto implies aes, sha2, and simd, which in turn implies fp. Going the other way, nofp implies nosimd, which implies nocrypto, noaes, and nosha2.

Adapteva Epiphany Options

These -m options are defined for Adapteva Epiphany ๐Ÿ

  • -mhalf-reg-file โ€” don't allocate any register in the range "r32"..."r63". That lets your code run on hardware variants that lack these registers ๐Ÿงš
  • -mprefer-short-insn-regs โ€” preferentially allocates registers that allow short instruction generation. This can increase the instruction count, so it may either reduce or increase overall code size.
  • -mbranch-cost=num โ€” okay so this sets the cost of branches to roughly num "simple" instructions ๐ŸŒธ. It's only a heuristic, though, so don't expect the same results across releases ๐Ÿ’€.
  • -mcmove โ€” turns on the generation of conditional moves โœจ.
  • -mnops=num โ€” emits num NOPs before every other instruction that gets generated ๐Ÿงš.
  • -mno-soft-cmpsf โ€” for single-precision floating-point comparisons, this emits an fsub instruction and tests the flags. It's faster than a software comparison, but it can give incorrect results when NaNs are involved, or when two different small numbers get compared and their difference is calculated as zero ๐Ÿ˜ญ. The default is -msoft-cmpsf, which uses software comparisons that are slower but IEEE-compliant ๐Ÿ’–.
  • -mstack-offset=num โ€” sets the offset between the top of the stack and the stack pointer. E.g., a value of 8 means the eight bytes in the range "sp+0...sp+7" can be used by leaf functions without stack allocation ๐Ÿฆ‹. Values other than 8 or 16 are untested and unlikely to work ๐Ÿ™ˆ. Also, this option changes the ABI, so compiling a program with a different stack offset than the libraries were built with generally does not work ๐Ÿšซ.
Heads up bestie: this option changes the ABI! If you want to test whether a different stack offset gives you better code, this is a fine place to poke around. But if you want to build programs that actually work with a different stack offset, the recommended move is to configure the toolchain with the appropriate --with-stack-offset=num option ๐Ÿ”ฅ.
  • -mno-round-nearest โ€” makes the scheduler assume the rounding mode has been set to truncating ๐ŸŒˆ. The default is -mround-nearest.
  • -mlong-calls โ€” if an attribute doesn't say otherwise, this assumes all calls might be beyond the offset range of the "b" / "bl" instructions. So it loads the function address into a register before doing a (otherwise direct) call ๐ŸŽ€. This is the default.
  • -mshort-calls โ€” if an attribute doesn't say otherwise, this assumes all direct calls are in range of the "b" / "bl" instructions, so those instructions get used for direct calls ๐Ÿ“. The default is -mlong-calls.
  • -msmall16 โ€” assumes addresses can be loaded as 16-bit unsigned values ๐Ÿ’œ. This doesn't apply to function addresses that have -mlong-calls semantics in effect.
  • -mfp-mode=mode โ€” sets the prevailing mode of the floating-point unit โœจ. This decides which floating-point mode gets provided and expected at function call and return time. Matching this to the mode you mostly need at function start can make your programs smaller and faster by avoiding unnecessary mode switches ๐Ÿ‘‘.

mode can be set to one of the following values:

  • caller โ€” any mode at function entry is valid, and it gets retained or restored when the function returns and when it calls other functions ๐Ÿซถ. This one is great for libraries or other compilation units you want to drop into programs with different prevailing FPU modes. Being able to use a single object file is worth the extra size and speed overhead of any mode switching, compared with a more specific choice of prevailing FPU mode ๐Ÿ’….
  • truncate โ€” the mode used for floating-point calculations with truncating (i.e. round towards zero) rounding mode. That includes conversion from floating point to integer ๐Ÿฆ‹.
  • round-nearest โ€” the mode used for floating-point calculations with round-to-nearest-or-even rounding mode ๐ŸŒธ.
  • int โ€” the mode used to perform integer calculations in the FPU, e.g. integer multiply, or integer multiply-and-accumulate ๐Ÿงฎ.

The default is -mfp-mode=caller ๐ŸŽ€.

  • -mno-split-lohi, -mno-postinc, -mno-postmodify โ€” code generation tweaks that disable, respectively, splitting of 32-bit loads, generation of post-increment addresses, and generation of post-modify addresses ๐Ÿ™ˆ. The defaults are msplit-lohi, -mpost-inc, and -mpost-modify.
  • -mnovect-double โ€” changes the preferred SIMD mode to SImode ๐Ÿ’€. The default is -mvect-double, which uses DImode as the preferred SIMD mode.
  • -max-vect-align=num โ€” the maximum alignment for SIMD vector mode types ๐Ÿ“. num may be 4 or 8, and the default is 8. Heads up: this is an ABI change, even though lots of library function interfaces are unaffected as long as they don't use SIMD vector modes in places that affect the size and/or alignment of relevant types ๐Ÿ”ฅ.
  • -msplit-vecmove-early โ€” splits vector moves into single word moves before reload ๐Ÿงš. In theory this can give better register allocation, but so far the reverse seems to be the usual outcome ๐Ÿ˜ญ.
  • -m1reg-reg โ€” specifies a register to hold the constant -1, which makes loading small negative constants and certain bitmasks faster โญ. Allowable values for reg are r43 and r63, which specify using that register as a fixed register, and none, which means no register is used for this purpose ๐Ÿ’–. The default is -m1reg-none.

โœจ AMD GCN Options โœจ

These options are defined specifically for the AMD GCN port ๐Ÿ‘‘.

  • -march=gpu, -mtune=gpu โ€” sets the architecture type or tuning for gpu ๐Ÿ”ฅ. Supported values for gpu are:
    • fiji โ€” compiles for GCN3 Fiji devices (gfx803) ๐ŸŒˆ.
    • gfx900 โ€” compiles for GCN5 Vega 10 devices (gfx900) ๐Ÿ’….
  • -mstack-size=bytes โ€” specifies how many bytes of stack space get requested for each GPU thread (wave-front) ๐Ÿซถ. Beware that there may be many threads and limited memory available ๐Ÿ’€. The size of the stack allocation may also have an impact on run-time performance. The default is 32KB when using OpenACC or OpenMP, and 1MB otherwise โœจ.

๐ŸŒธ ARC Options ๐ŸŒธ

The following options control the architecture variant that code is being compiled for ๐Ÿฆ‹.

  • -mbarrel-shifter โ€” generates instructions supported by the barrel shifter ๐ŸŽ€. This is the default unless -mcpu=ARC601 or -mcpu=ARCEM is in effect.
  • -mjli-always โ€” forces a function to be called using the jli_s instruction ๐Ÿงš. This option is valid only for the ARCv2 architecture.
  • -mcpu=cpu โ€” sets the architecture type, register usage, and instruction scheduling parameters for cpu ๐Ÿ’œ. There are also shortcut alias options for backward compatibility and convenience. Supported values for cpu are:
    • arc600 โ€” compiles for ARC600. Aliases: -mA6, -mARC600.
    • arc601 โ€” compiles for ARC601. Alias: -mARC601.
    • arc700 โ€” compiles for ARC700. Aliases: -mA7, -mARC700. This is the default when configured with --with-cpu=arc700 ๐Ÿ‘‘.
    • arcem โ€” compiles for ARC EM ๐Ÿ“.
    • archs โ€” compiles for ARC HS ๐ŸŒˆ.
    • em โ€” compiles for ARC EM CPU with no hardware extensions ๐Ÿ™ˆ.
    • em4 โ€” compiles for ARC EM4 CPU ๐Ÿงฎ.
    • em4_dmips โ€” compiles for ARC EM4 DMIPS CPU ๐Ÿซถ.
    • em4_fpus โ€” compiles for ARC EM4 DMIPS CPU with the single-precision floating-point extension โœจ.
    • em4_fpuda โ€” compiles for ARC EM4 DMIPS CPU with single-precision floating-point and double assist instructions ๐Ÿ”ฅ.
    • hs โ€” compiles for ARC HS CPU with no hardware extensions except the atomic instructions ๐Ÿ’….
    • hs34 โ€” compiles for ARC HS34 CPU โญ.
    • hs38 โ€” compiles for ARC HS38 CPU ๐Ÿฆ‹.
    • hs38_linux โ€” compiles for ARC HS38 CPU with all hardware extensions on ๐ŸŒธ.
    • arc600_norm โ€” compiles for ARC 600 CPU with "norm" instructions enabled ๐Ÿ’–.
    • arc600_mul32x16 โ€” compiles for ARC 600 CPU with "norm" and 32x16-bit multiply instructions enabled ๐ŸŽ€.
    • arc600_mul64 โ€” compiles for ARC 600 CPU with "norm" and "mul64"-family instructions enabled ๐Ÿงš.
    • arc601_norm โ€” compiles for ARC 601 CPU with "norm" instructions enabled ๐Ÿ’œ.
    • arc601_mul32x16 โ€” compiles for ARC 601 CPU with "norm" and 32x16-bit multiply instructions enabled ๐Ÿ‘‘.
    • arc601_mul64 โ€” compiles for ARC 601 CPU with "norm" and "mul64"-family instructions enabled ๐Ÿ“.
    • nps400 โ€” compiles for ARC 700 on NPS400 chip ๐ŸŒˆ.
    • em_mini โ€” compiles for the ARC EM minimalist configuration, which features a reduced register set ๐Ÿ™ˆ.
  • -mdpfp, -mdpfp-compact โ€” generates double-precision FPX instructions, tuned for the compact implementation ๐Ÿงฎ.
  • -mdpfp-fast โ€” generates double-precision FPX instructions, tuned for the fast implementation ๐Ÿซถ.
  • -mno-dpfp-lrsr โ€” disables "lr" and "sr" instructions from using FPX extension aux registers โœจ.
  • -mea โ€” generates extended arithmetic instructions ๐Ÿ”ฅ. Currently only "divaw", "adds", "subs", and "sat16" are supported. This is always enabled for -mcpu=ARC700 ๐Ÿ’….
  • -mno-mpy โ€” does not generate "mpy"-family instructions for ARC700 โญ. Deprecated bestie, so maybe don't reach for it ๐Ÿ’€.
  • -mmul32x16 โ€” generates 32x16-bit multiply and multiply-accumulate instructions ๐Ÿฆ‹.
  • -mmul64 โ€” generates "mul64" and "mulu64" instructions ๐ŸŒธ. Only valid for -mcpu=ARC600.
  • -mnorm โ€” generates "norm" instructions ๐Ÿ’–. This is the default if -mcpu=ARC700 is in effect.
  • -mspfp, -mspfp-compact โ€” generates single-precision FPX instructions, tuned for the compact implementation ๐ŸŽ€.
  • -mspfp-fast โ€” generates single-precision FPX instructions, tuned for the fast implementation ๐Ÿงš.
  • -msimd โ€” enables generation of ARC SIMD instructions via target-specific builtins ๐Ÿ’œ. Only valid for -mcpu=ARC700.
  • -msoft-float โ€” this option is ignored ๐Ÿ™ˆ; it's only provided for compatibility purposes. Software floating-point code is emitted by default, and this default can be overridden by FPX options: -mspfp, -mspfp-compact, or -mspfp-fast for single precision, and -mdpfp, -mdpfp-compact, or -mdpfp-fast for double precision ๐Ÿ‘‘.
  • -mswap โ€” generates "swap" instructions ๐Ÿ“.
  • -matomic โ€” enables use of the locked load/store conditional extension to implement atomic memory built-in functions ๐ŸŒˆ. Not available for ARC 6xx or ARC EM cores.
  • -mdiv-rem โ€” enables "div" and "rem" instructions for ARCv2 cores ๐Ÿ™ˆ.
  • -mcode-density โ€” enables code density instructions for ARC EM ๐Ÿงฎ. This option is on by default for ARC HS.
  • -mll64 โ€” enables double load/store operations for ARC HS cores ๐Ÿซถ.
  • -mtp-regno=regno โ€” specifies the thread pointer register number โœจ.
  • -mmpy-option=multo โ€” Okay so this one picks your multiplier design for ARCv2 code ๐Ÿงฎโœจ You can pass multo as either a string or a number, and wlh1 is the default. Here's the full menu:
    • 0 or none โ€” No multiplier available, bestie ๐Ÿ’€
    • 1 or w โ€” 16x16 multiplier, fully pipelined. You get mpyw and mpyuw ๐Ÿ”ฅ
    • 2 or wlh1 โ€” 32x32 multiplier, fully pipelined (1 stage). This one also unlocks mpy, mpyu, mpym, mpymu, and mpy_s ๐Ÿ’…
    • 3 or wlh2 โ€” 32x32 multiplier, fully pipelined (2 stages). Same extras as above: mpy, mpyu, mpym, mpymu, and mpy_s ๐Ÿฆ‹
    • 4 or wlh3 โ€” Two 16x16 multipliers, blocking and sequential. Also unlocks mpy, mpyu, mpym, mpymu, and mpy_s ๐ŸŒธ
    • 5 or wlh4 โ€” One 16x16 multiplier, blocking and sequential. Same bonus list: mpy, mpyu, mpym, mpymu, and mpy_s โœจ
    • 6 or wlh5 โ€” One 32x4 multiplier, blocking and sequential. Also gives you mpy, mpyu, mpym, mpymu, and mpy_s ๐ŸŽ€
    • 7 or plus_dmpy โ€” ARC HS SIMD support ๐Ÿ‘‘
    • 8 or plus_macd โ€” ARC HS SIMD support ๐ŸŒˆ
    • 9 or plus_qmacw โ€” ARC HS SIMD support โญ
This option is only available for ARCv2 cores, so don't try it on the others ๐Ÿ™…โ€โ™€๏ธ
  • -mfpu=fpu โ€” This one turns on specific floating-point hardware extensions for ARCv2 cores ๐Ÿฆ‹ Here are the fpu values you can use:
    • fpus โ€” Single-precision floating-point hardware extensions, enabled ๐Ÿ’–
    • fpud โ€” Double-precision floating-point hardware extensions. The single-precision extension comes along for the ride too. Not available for ARC EM ๐Ÿ™ˆ
    • fpuda โ€” Double-precision floating-point using double-precision assist instructions. The single-precision extension is also enabled. This one is only for ARC EM ๐Ÿ’…
    • fpuda_div โ€” Double-precision floating-point using double-precision assist instructions. The single-precision, square-root, and divide extensions are also enabled. ARC EM only ๐Ÿ”ฅ
    • fpuda_fma โ€” Double-precision floating-point using double-precision assist instructions. The single-precision and fused multiply and add extensions are also enabled. ARC EM only โœจ
    • fpuda_all โ€” Double-precision floating-point using double-precision assist instructions. Every single-precision floating-point extension is also enabled. ARC EM only ๐Ÿ‘‘
    • fpus_div โ€” Single-precision floating-point, plus the square-root and divide extensions ๐ŸŒธ
    • fpud_div โ€” Double-precision floating-point, plus the square-root and divide extensions. This one includes fpus_div. Not available for ARC EM ๐Ÿ’œ
    • fpus_fma โ€” Single-precision floating-point, plus the fused multiply and add extensions ๐Ÿงš
    • fpud_fma โ€” Double-precision floating-point, plus the fused multiply and add extensions. This one includes fpus_fma. Not available for ARC EM ๐Ÿ“
    • fpus_all โ€” Every single-precision floating-point hardware extension ๐ŸŒˆ
    • fpud_all โ€” Every single- and double-precision floating-point hardware extension. Not available for ARC EM ๐Ÿซถ
  • -mirq-ctrl-saved=register-range, blink, lp_count โ€” This tells the processor which general-purpose registers to automatically save and restore on interrupt entry and exit. The register-range is two registers separated by a dash. The range always starts with r0, and the upper limit is the fp register. blink and lp_count are optional. This option is only valid for ARC EM and ARC HS cores ๐Ÿงก
  • -mrgf-banked-regs=number โ€” This sets how many registers get replicated in the second register bank when you enter a fast interrupt. Fast interrupts are the ones with the highest priority level, P0. They only save PC and STATUS32 to skip memory transactions during entry and exit, so use this when you're doing fast interrupts on an ARC V2 family processor. Permitted values are 4, 8, 16, and 32 ๐Ÿฆ‹
  • -mlpc-width=width โ€” Sets the width of the lp_count register. Valid widths are 8, 16, 20, 24, 28, and 32 bits, and the default is fixed at 32 bits. If the width is less than 32, the compiler won't try to turn your loops into the zero-delay loop mechanism unless it knows lp_count can actually hold the loop-counter value. Depending on the width, the compiler and run-time library might still use the loop mechanism for various needs. This option defines the macro __ARC_LPC_WIDTH__ with the value of width ๐Ÿงฎ
  • -mrf16 โ€” Tells the compiler to generate code for a 16-entry register file. This option defines the __ARC_RF16__ preprocessor macro ๐Ÿ’…
  • -mbranch-index โ€” Enables the use of bi or bih instructions to implement jump tables โœจ

These next options are passed through to the assembler, and they also define preprocessor macro symbols ๐ŸŽ€

  • -mdsp-packa โ€” Passed down to the assembler to enable the DSP Pack A extensions. It also sets the preprocessor symbol __Xdsp_packa. This option is deprecated ๐Ÿ’€
  • -mdvbf โ€” Passed down to the assembler to enable the dual Viterbi butterfly extension. It also sets the preprocessor symbol __Xdvbf. This option is deprecated ๐Ÿ’€
  • -mlock โ€” Passed down to the assembler to enable the locked load/store conditional extension. It also sets the preprocessor symbol __Xlock ๐Ÿ”’
  • -mmac-d16 โ€” Passed down to the assembler. It also sets the preprocessor symbol __Xxmac_d16. This option is deprecated ๐Ÿ’€
  • -mmac-24 โ€” Passed down to the assembler. It also sets the preprocessor symbol __Xxmac_24. This option is deprecated ๐Ÿ’€
  • -mrtsc โ€” Passed down to the assembler to enable the 64-bit time-stamp counter extension instruction. It also sets the preprocessor symbol __Xrtsc. This option is deprecated ๐Ÿ’€
  • -mswape โ€” Passed down to the assembler to enable the swap byte ordering extension instruction. It also sets the preprocessor symbol __Xswape ๐Ÿ”
  • -mtelephony โ€” Passed down to the assembler to enable dual- and single-operand instructions for telephony. It also sets the preprocessor symbol __Xtelephony. This option is deprecated ๐Ÿ’€
  • -mxy โ€” Passed down to the assembler to enable the XY memory extension. It also sets the preprocessor symbol __Xxy ๐Ÿงš

These options control how the assembly code gets annotated ๐Ÿ“

  • -misize โ€” Annotates assembler instructions with estimated addresses ๐Ÿ“
  • -mannotate-align โ€” Explains which alignment considerations led to the decision to make an instruction short or long ๐Ÿค“

These options are passed through to the linker ๐Ÿ”—

  • -marclinux โ€” Passed through to the linker to specify the arclinux emulation. This one is on by default in tool chains built for arc-linux-uclibc and arceb-linux-uclibc targets when profiling is not requested ๐ŸŒˆ
  • -marclinux_prof โ€” Passed through to the linker to specify the arclinux_prof emulation. This one is on by default in tool chains built for arc-linux-uclibc and arceb-linux-uclibc targets when profiling is requested ๐ŸŒธ

These options control the semantics of the generated code ๐Ÿง 

  • -mlong-calls โ€” Generates calls as register indirect calls, so you get access to the full 32-bit address range ๐Ÿ“ž
  • -mmedium-calls โ€” Doesn't use less than a 25-bit addressing range for calls, which is the offset available for an unconditional branch-and-link instruction. Conditional execution of function calls is suppressed so the 25-bit range can be used, instead of the 21-bit range you'd get with conditional branch-and-link. This is the default for tool chains built for arc-linux-uclibc and arceb-linux-uclibc targets ๐Ÿฆ‹
  • -G num โ€” Puts definitions of externally-visible data in a small data section if that data is no bigger than num bytes. The default value of num is 4 for any ARC configuration, or 8 when you have double load/store operations ๐Ÿ“ฆ
  • -mno-sdata โ€” Don't generate sdata references. This is the default for tool chains built for arc-linux-uclibc and arceb-linux-uclibc targets ๐Ÿšซ
  • -mvolatile-cache โ€” Uses ordinarily cached memory accesses for volatile references. This is the default ๐Ÿ’œ
  • -mno-volatile-cache โ€” Enables cache bypass for volatile references ๐Ÿƒโ€โ™€๏ธ

These options fine-tune code generation ๐ŸŽ€

  • -malign-call โ€” Does alignment optimizations for call instructions โœจ
  • -mauto-modify-reg โ€” Enables the use of pre/post modify with register displacement ๐Ÿ”ง
  • -mbbit-peephole โ€” Enables bbit peephole2 ๐Ÿงฉ
  • -mno-brcc โ€” This disables a target-specific pass in arc_reorg that generates compare-and-branch (brcc) instructions. It has no effect on the generation of these instructions when they're driven by the combiner pass ๐Ÿ™…โ€โ™€๏ธ
  • -mcase-vector-pcrel โ€” Uses PC-relative switch case tables to enable case table shortening. This is the default for -Os ๐ŸŒท
  • -mcompact-casesi โ€” Enables the compact casesi pattern. This is the default for -Os, and it's only available for ARCv1 cores. This option is deprecated ๐Ÿ’€
  • -mno-cond-exec โ€” Disables the ARCompact-specific pass that generates conditional execution instructions ๐Ÿ›‘

Okay so the ARC port has its own special pass, and bestie, it's giving main character energy ๐Ÿ’…. The target-independent conditional execution pass is kinda lacking because of delay slot scheduling and how operand numbers, literal sizes, instruction lengths, and conditional execution support all interact ๐Ÿ˜ญ. So ARC runs an extra pass that hunts for more conditional execution chances after register allocation, branch shortening, and delay slot scheduling are done โœจ. It usually (not always!) makes performance and code size better, but it costs extra compile time, which is why there's an option to switch it off ๐Ÿซถ. If your call instructions are going out of their allowed offset range because they got conditionalized, try -mmedium-calls instead ๐Ÿฆ‹.

  • -mearly-cbranchsi โ€” Turns on pre-reload use of the cbranchsi pattern ๐ŸŒธ.
  • -mexpand-adddi โ€” Expands adddi3 and subdi3 at RTL generation time into add.f, adc etc. โš ๏ธ This one is deprecated, so it's on its way out ๐Ÿ’€.
  • -mindexed-loads โ€” Turns on indexed loads ๐Ÿ“. Heads up, this can be problematic, because some optimizers then assume indexed stores exist, and they don't on this target ๐Ÿ™ˆ.
  • -mlra โ€” Turns on Local Register Allocation. It's still experimental for ARC, so by default the compiler uses standard reload, which is the same as -mno-lra ๐Ÿงช.
  • -mlra-priority-none โ€” Doesn't indicate any priority for target registers ๐ŸŒˆ.
  • -mlra-priority-compact โ€” Indicates target register priority for r0..r3 / r12..r15 ๐Ÿ’œ.
  • -mlra-priority-noncompact โ€” Reduces target register priority for r0..r3 / r12..r15 ๐ŸŽ€.
  • -mmillicode โ€” When you're optimizing for size (with -Os), prologues and epilogues that have to save or restore a lot of registers often get shortened by calling a special function in libgcc. That's called a millicode call ๐Ÿงš. These calls can cause performance issues, and/or linking issues if you link in a nonstandard way, so this option lets you turn millicode call generation on or off ๐Ÿ‘‘.
  • -mcode-density-frame โ€” Lets the compiler emit enter and leave instructions ๐Ÿฆ‹. These are only valid for CPUs with the code-density feature, so don't use them on anything else ๐Ÿ™….
  • -mmixed-code โ€” Tweaks register allocation to help 16-bit instruction generation โœจ. Generally it makes the average instruction size smaller, but the instruction count goes up ๐Ÿ“ˆ.
  • -mq-class โ€” Enables q instruction alternatives. This is the default for -Os ๐Ÿ“.
  • -mRcq โ€” Enables Rcq constraint handling. Most short code generation depends on this, and it's the default ๐Ÿ’–.
  • -mRcw โ€” Enables Rcw constraint handling. Most ccfsm condexec depends on this, and it's the default too ๐ŸŒธ.
  • -msize-level=level โ€” Fine-tunes size optimization with regards to instruction lengths and alignment ๐Ÿ’…. The recognized values for level are:
    • 0 โ€” No size optimization. This level is deprecated and treated like 1 ๐Ÿ’€.
    • 1 โ€” Short instructions are used opportunistically ๐Ÿฆ‹.
    • 2 โ€” On top of that, alignment of loops and of code after barriers gets dropped ๐Ÿ™ˆ.
    • 3 โ€” On top of that, optional data alignment gets dropped, and the option -Os is enabled ๐Ÿ‘‘.

It defaults to 3 when -Os is in effect ๐Ÿ”ฅ. Otherwise, if you don't set it, it works the same as level 1 ๐Ÿซถ.

  • -mtune=cpu โ€” Sets instruction scheduling parameters for cpu, overriding whatever -mcpu= implied ๐ŸŽ€. The supported values for cpu are:
    • ARC600 โ€” Tunes for ARC600 CPU ๐Ÿงš.
    • ARC601 โ€” Tunes for ARC601 CPU ๐ŸŒˆ.
    • ARC700 โ€” Tunes for ARC700 CPU with standard multiplier block โœจ.
    • ARC700-xmac โ€” Tunes for ARC700 CPU with XMAC block ๐Ÿ’œ.
    • ARC725D โ€” Tunes for ARC725D CPU ๐Ÿฆ‹.
    • ARC750D โ€” Tunes for ARC750D CPU ๐ŸŒธ.
  • -mmultcost=num โ€” Sets the cost to assume for a multiply instruction, with 4 being equal to a normal instruction ๐Ÿ”ฅ.
  • -munalign-prob-threshold=probability โ€” Sets the probability threshold for unaligning branches ๐Ÿง . When you're tuning for ARC700 and optimizing for speed, branches without a filled delay slot are usually emitted unaligned and long, unless profiling shows the probability of the branch being taken is below probability ๐Ÿ“. The default is (REG_BR_PROB_BASE/2), which is 5000 ๐Ÿ’–.

The following options are kept around for backward compatibility, but they're now deprecated and will be removed in a future release ๐Ÿ˜ญ. Please migrate off them ๐Ÿซถ.

  • -margonaut โ€” Obsolete FPX ๐Ÿ’€.
  • -mbig-endian, -EB โ€” Compiles code for big-endian targets. Using these is deprecated now ๐Ÿ™ˆ. Big-endian code is supported by configuring GCC to build arceb-elf32 and arceb-linux-uclibc targets, where big endian is already the default ๐ŸŒˆ.
  • -mlittle-endian, -EL โ€” Compiles code for little-endian targets. Using these is deprecated now ๐Ÿ™ˆ. Little-endian code is supported by configuring GCC to build arc-elf32 and arc-linux-uclibc targets, where little endian is already the default ๐ŸŒˆ.
  • -mbarrel_shifter โ€” Replaced by -mbarrel-shifter ๐Ÿ”.
  • -mdpfp_compact โ€” Replaced by -mdpfp-compact ๐Ÿ”.
  • -mdpfp_fast โ€” Replaced by -mdpfp-fast ๐Ÿ”.
  • -mdsp_packa โ€” Replaced by -mdsp-packa ๐Ÿ”.
  • -mEA โ€” Replaced by -mea ๐Ÿ”.
  • -mmac_24 โ€” Replaced by -mmac-24 ๐Ÿ”.
  • -mmac_d16 โ€” Replaced by -mmac-d16 ๐Ÿ”.
  • -mspfp_compact โ€” Replaced by -mspfp-compact ๐Ÿ”.
  • -mspfp_fast โ€” Replaced by -mspfp-fast ๐Ÿ”.
  • -mtune=cpu โ€” The values arc600, arc601, arc700 and arc700-xmac for cpu are replaced by ARC600, ARC601, ARC700 and ARC700-xmac respectively ๐Ÿ”.
  • -multcost=num โ€” Replaced by -mmultcost ๐Ÿ”.

โœจ ARM Options โœจ

okay bestie, these -m options are defined for the ARM port ๐ŸŽ€:

  • -mabi=name โ€” Generates code for the specified ABI ๐Ÿงš. The permissible values are apcs-gnu, atpcs, aapcs, aapcs-linux and iwmmxt ๐ŸŒˆ.
  • -mapcs-frame โ€” Generates a stack frame that follows the ARM Procedure Call Standard for all functions, even when it's not strictly needed for the code to run correctly ๐Ÿ“œ. Specifying -fomit-frame-pointer with this option means stack frames won't be generated for leaf functions ๐Ÿƒ. The default is -mno-apcs-frame ๐Ÿ’…. This option is deprecated ๐Ÿ’€.
  • -mapcs โ€” A synonym for -mapcs-frame, and it's deprecated too ๐Ÿ™ˆ.
  • -mthumb-interwork โ€” Generates code that supports calling between the ARM and Thumb instruction sets ๐Ÿ”ฅ. Without this option, on pre-v5 architectures, the two instruction sets can't be reliably used inside one program ๐Ÿ˜ฌ. The default is -mno-thumb-interwork, since slightly larger code gets generated when -mthumb-interwork is specified ๐Ÿซถ. In AAPCS configurations this option is meaningless ๐Ÿคท.
  • -mno-sched-prolog โ€” Stops the reordering of instructions in the function prologue, and stops those instructions from being merged with the instructions in the function's body ๐Ÿ”’. That means every function starts with a recognizable set of instructions (or one from a small set of different prologues), so you can use that to find where functions start inside an executable piece of code ๐Ÿ”. The default is -msched-prolog โœจ.
  • -mfloat-abi=name โ€” Specifies which floating-point ABI to use ๐Ÿงฎ. The permissible values are soft, softfp and hard ๐Ÿ’œ.
    • soft makes GCC generate output with library calls for floating-point operations ๐Ÿ“š.
    • softfp lets you generate code using hardware floating-point instructions, but it still uses the soft-float calling conventions ๐ŸŒธ.
    • hard allows floating-point instructions and uses FPU-specific calling conventions โšก.

The default depends on your specific target configuration ๐ŸŽฏ. Heads up: the hard-float and soft-float ABIs are not link-compatible, so you have to compile your whole program with the same ABI, and link with a compatible set of libraries ๐Ÿšจ.

  • -mgeneral-regs-only โ€” Generates code that only uses the general-purpose registers ๐Ÿงบ. This stops the compiler from using floating-point and Advanced SIMD registers, but it won't put any restrictions on the assembler ๐Ÿซถ.
  • -mlittle-endian โ€” Generates code for a processor running in little-endian mode ๐Ÿ’–. This is the default for all standard configurations ๐ŸŒˆ.
  • -mbig-endian โ€” Generates code for a processor running in big-endian mode ๐Ÿ“. The default is to compile for a little-endian processor ๐Ÿ’….
  • -mbe8, -mbe32 โ€” When linking a big-endian image, these select between the BE8 and BE32 formats ๐Ÿงฉ. They have no effect on little-endian images and get ignored there ๐Ÿ™ƒ. The default depends on the selected target architecture: for ARMv6 and later it's BE8, and for older architectures it's BE32 ๐ŸŽ€. BE32 format has been deprecated by ARM ๐Ÿ’€.
  • -march=name[+extension...] โ€” Specifies the name of the target ARM architecture ๐Ÿ›๏ธ. GCC uses this name to figure out what kind of instructions it can emit when generating assembly code ๐Ÿง . You can use this option together with -mcpu=, or instead of it ๐Ÿ”.

The permissible names are: armv4t, armv5t, armv5te, armv6, armv6j, armv6k, armv6kz, armv6t2, armv6z, armv6zk, armv7, armv7-a, armv7ve, armv8-a, armv8.1-a, armv8.2-a, armv8.3-a, armv8.4-a, armv8.5-a, armv7-r, armv8-r, armv6-m, armv6s-m, armv7-m, armv7e-m, armv8-m.base, armv8-m.main, iwmmxt and iwmmxt2 ๐Ÿ“.

On top of that, these architectures lack support for the Thumb execution state, so they're recognized but support is deprecated: armv4 ๐Ÿ˜ญ.

Lots of these architectures support extensions ๐Ÿงฉ. You can add them by appending +extension to the architecture name โž•. Extension options are processed in order, and capabilities accumulate ๐Ÿ“ˆ. An extension also turns on any base extensions it depends on, so for example the +crypto extension will always enable the +simd extension ๐Ÿ”. The exception to the additive rule is extensions prefixed with +no...: those disable the specified option, along with any other extensions that depend on it ๐Ÿšซ.

For example, -march=armv7-a+simd+nofp+vfpv4 is equivalent to writing -march=armv7-a+vfpv4, since the +simd option gets entirely disabled by the +nofp option that follows it ๐Ÿ™ˆโœจ.

Okay so bestie, most extension names are super generic ๐Ÿ’… but what they actually do depends on which architecture you slap them onto โœจ Like +simd works on both armv7-a and armv8-a, but on armv7-a it turns on the original ARMv7-A Advanced SIMD (Neon) stuff, and on armv8-a it gives you the ARMv8-A version ๐Ÿ”ฅ The table below is the full tea on what each architecture supports. Anything not mentioned? Sorry bestie, no extensions for it ๐Ÿ™ˆ


โœจ armv5te, armv6, armv6j, armv6k, armv6kz, armv6t2, armv6z, armv6zk โœจ

All of these architectures share the same two extensions ๐Ÿฆ‹

  • +fp โ€” the VFPv2 floating-point instructions. +vfpv2 works as an alias for this one ๐Ÿ’–
  • +nofp โ€” turns the floating-point instructions off ๐Ÿ™…

๐ŸŒธ armv7 ๐ŸŒธ

This is the common subset of the ARMv7-A, ARMv7-R, and ARMv7-M architectures ๐Ÿ’œ

  • +fp โ€” the VFPv3 floating-point instructions, with 16 double-precision registers. +vfpv3-d16 is an alias for this one. Heads up: floating-point isn't supported by the base ARMv7-M architecture, but it's compatible with both ARMv7-A and ARMv7-R ๐Ÿซถ
  • +nofp โ€” turns the floating-point instructions off

๐Ÿฆ‹ armv7-a ๐Ÿฆ‹

  • +mp โ€” the multiprocessing extension ๐Ÿงš
  • +sec โ€” the security extension ๐Ÿ”’
  • +fp โ€” the VFPv3 floating-point instructions, with 16 double-precision registers. +vfpv3-d16 is an alias ๐Ÿ’…
  • +simd โ€” the Advanced SIMD (Neon) v1 plus the VFPv3 floating-point instructions. +neon and +neon-vfpv3 are both aliases for this one ๐Ÿ”ฅ
  • +vfpv3 โ€” the VFPv3 floating-point instructions, but with 32 double-precision registers ๐Ÿ‘‘
  • +vfpv3-d16-fp16 โ€” the VFPv3 floating-point instructions with 16 double-precision registers and the half-precision floating-point conversion operations ๐Ÿ“
  • +vfpv3-fp16 โ€” the VFPv3 floating-point instructions with 32 double-precision registers and the half-precision conversion operations ๐Ÿ“
  • +vfpv4-d16 โ€” the VFPv4 floating-point instructions, with 16 double-precision registers ๐ŸŒˆ
  • +vfpv4 โ€” the VFPv4 floating-point instructions, with 32 double-precision registers ๐ŸŒˆ
  • +neon-fp16 โ€” the Advanced SIMD (Neon) v1 plus the VFPv3 floating-point instructions, with the half-precision conversion operations โœจ
  • +neon-vfpv4 โ€” the Advanced SIMD (Neon) v2 plus the VFPv4 floating-point instructions ๐ŸŒŸ
  • +nosimd โ€” disables the Advanced SIMD instructions (floating-point stays on, though) ๐Ÿ™ƒ
  • +nofp โ€” disables the floating-point and Advanced SIMD instructions ๐Ÿ’€

๐Ÿ’œ armv7ve ๐Ÿ’œ

This is the extended version of the ARMv7-A architecture, with support for virtualization ๐Ÿงš

  • +fp โ€” the VFPv4 floating-point instructions, with 16 double-precision registers. +vfpv4-d16 is an alias for this one ๐Ÿ’–
  • +simd โ€” the Advanced SIMD (Neon) v2 plus the VFPv4 floating-point instructions. +neon-vfpv4 is an alias for this one ๐Ÿ”ฅ
  • +vfpv3-d16 โ€” the VFPv3 floating-point instructions, with 16 double-precision registers ๐ŸŽ€
  • +vfpv3 โ€” the VFPv3 floating-point instructions, with 32 double-precision registers ๐ŸŽ€
  • +vfpv3-d16-fp16 โ€” the VFPv3 floating-point instructions with 16 double-precision registers and the half-precision conversion operations ๐Ÿ“
  • +vfpv3-fp16 โ€” the VFPv3 floating-point instructions with 32 double-precision registers and the half-precision conversion operations ๐Ÿ“
  • +vfpv4-d16 โ€” the VFPv4 floating-point instructions, with 16 double-precision registers ๐ŸŒˆ
  • +vfpv4 โ€” the VFPv4 floating-point instructions, with 32 double-precision registers ๐ŸŒˆ
  • +neon โ€” the Advanced SIMD (Neon) v1 plus the VFPv3 floating-point instructions. +neon-vfpv3 is an alias for this one โœจ
  • +neon-fp16 โ€” the Advanced SIMD (Neon) v1 plus the VFPv3 floating-point instructions, with the half-precision conversion operations ๐ŸŒŸ
  • +nosimd โ€” disables the Advanced SIMD instructions (floating-point stays on) ๐Ÿ™ƒ
  • +nofp โ€” disables the floating-point and Advanced SIMD instructions ๐Ÿ’€

๐ŸŒˆ armv8-a ๐ŸŒˆ

  • +crc โ€” the Cyclic Redundancy Check (CRC) instructions ๐Ÿงฎ
  • +simd โ€” the ARMv8-A Advanced SIMD and floating-point instructions ๐Ÿ”ฅ
  • +crypto โ€” the cryptographic instructions ๐Ÿ”
  • +nocrypto โ€” disables the cryptographic instructions ๐Ÿ™…
  • +nofp โ€” disables the floating-point, Advanced SIMD, and cryptographic instructions ๐Ÿ’€
  • +sb โ€” the Speculation Barrier Instruction ๐Ÿ›ก๏ธ
  • +predres โ€” the Execution and Data Prediction Restriction Instructions ๐Ÿ›ก๏ธ

โญ armv8.1-a โญ

  • +simd โ€” the ARMv8.1-A Advanced SIMD and floating-point instructions ๐Ÿ”ฅ
  • +crypto โ€” the cryptographic instructions. This also turns on the Advanced SIMD and floating-point instructions ๐Ÿ”
  • +nocrypto โ€” disables the cryptographic instructions ๐Ÿ™…
  • +nofp โ€” disables the floating-point, Advanced SIMD, and cryptographic instructions ๐Ÿ’€
  • +sb โ€” the Speculation Barrier Instruction ๐Ÿ›ก๏ธ
  • +predres โ€” the Execution and Data Prediction Restriction Instructions ๐Ÿ›ก๏ธ

๐Ÿ‘‘ armv8.2-a, armv8.3-a ๐Ÿ‘‘

Both of these architectures share the same extensions ๐Ÿ’…

  • +fp16 โ€” the half-precision floating-point data processing instructions. This also enables the Advanced SIMD and floating-point instructions ๐Ÿ“
  • +fp16fml โ€” the half-precision floating-point fmla extension. This also enables the half-precision floating-point extension, plus the Advanced SIMD and floating-point instructions ๐Ÿ“
  • +simd โ€” the ARMv8.1-A Advanced SIMD and floating-point instructions ๐Ÿ”ฅ
  • +crypto โ€” the cryptographic instructions. This also enables the Advanced SIMD and floating-point instructions ๐Ÿ”
  • +dotprod โ€” enables the Dot Product extension. This also enables Advanced SIMD instructions ๐Ÿฆ‹
  • +nocrypto โ€” disables the cryptographic extension ๐Ÿ™…
  • +nofp โ€” disables the floating-point, Advanced SIMD, and cryptographic instructions ๐Ÿ’€
  • +sb โ€” the Speculation Barrier Instruction ๐Ÿ›ก๏ธ
  • +predres โ€” the Execution and Data Prediction Restriction Instructions ๐Ÿ›ก๏ธ

๐Ÿงš armv8.4-a ๐Ÿงš

  • +fp16 โ€” the half-precision floating-point data processing instructions. This also enables the Advanced SIMD and floating-point instructions, as well as the Dot Product extension and the half-precision floating-point fmla extension ๐Ÿ“
  • +simd โ€” the ARMv8.3-A Advanced SIMD and floating-point instructions, as well as the Dot Product extension ๐Ÿ”ฅ
  • +crypto โ€” the cryptographic instructions. This also enables the Advanced SIMD and floating-point instructions, as well as the Dot Product extension ๐Ÿ”
  • +nocrypto โ€” disables the cryptographic extension ๐Ÿ™…
  • +nofp โ€” disables the floating-point, Advanced SIMD, and cryptographic instructions ๐Ÿ’€
  • +sb โ€” the Speculation Barrier Instruction ๐Ÿ›ก๏ธ
  • +predres โ€” the Execution and Data Prediction Restriction Instructions ๐Ÿ›ก๏ธ

๐ŸŽ€ armv8.5-a ๐ŸŽ€

  • +fp16 โ€” the half-precision floating-point data processing instructions. This also enables the Advanced SIMD and floating-point instructions, as well as the Dot Product extension and the half-precision floating-point fmla extension ๐Ÿ“
  • +simd โ€” the ARMv8.3-A Advanced SIMD and floating-point instructions, as well as the Dot Product extension ๐Ÿ”ฅ
  • +crypto โ€” the cryptographic instructions. This also enables the Advanced SIMD and floating-point instructions, as well as the Dot Product extension ๐Ÿ”
  • +nocrypto โ€” disables the cryptographic extension ๐Ÿ™…
  • +nofp โ€” disables the floating-point, Advanced SIMD, and cryptographic instructions ๐Ÿ’€

๐Ÿฆ„ armv7-r ๐Ÿฆ„

  • +fp.sp โ€” the single-precision VFPv3 floating-point instructions. +vfpv3xd is an alias for this one ๐Ÿ’–
  • +fp โ€” the VFPv3 floating-point instructions with 16 double-precision registers. +vfpv3-d16 is an alias for this one ๐Ÿ’…
  • +vfpv3xd-d16-fp16 โ€” the single-precision VFPv3 floating-point instructions with 16 double-precision registers and the half-precision conversion operations ๐Ÿ“
  • +vfpv3-d16-fp16 โ€” the VFPv3 floating-point instructions with 16 double-precision registers and the half-precision conversion operations ๐Ÿ“
  • +nofp โ€” disables the floating-point extension ๐Ÿ™…
  • +idiv โ€” the ARM-state integer division instructions โž—
  • +noidiv โ€” disables the ARM-state integer division extension ๐Ÿ™…

๐ŸŒŸ armv7e-m ๐ŸŒŸ

  • +fp โ€” the single-precision VFPv4 floating-point instructions ๐Ÿ”ฅ
  • +fpv5 โ€” the single-precision FPv5 floating-point instructions ๐Ÿ”ฅ
  • +fp.dp โ€” the single- and double-precision FPv5 floating-point instructions ๐Ÿ‘‘
  • +nofp โ€” disables the floating-point extensions ๐Ÿ’€

Okay so the ARMv8 squad gets their own little lists ๐Ÿ’…

  • armv8-m.main
    • +dsp โ€” the DSP instructions ๐Ÿ’–
    • +nodsp โ€” disables the DSP extension ๐Ÿ™…
    • +fp โ€” the single-precision floating-point instructions โœจ
    • +fp.dp โ€” the single- and double-precision floating-point instructions ๐Ÿ”ฅ
    • +nofp โ€” disables the floating-point extension ๐Ÿ’€
  • armv8-r
    • +crc โ€” the Cyclic Redundancy Check (CRC) instructions ๐Ÿฆ‹
    • +fp.sp โ€” the single-precision FPv5 floating-point instructions ๐ŸŒธ
    • +simd โ€” the ARMv8-A Advanced SIMD and floating-point instructions ๐Ÿ’œ
    • +crypto โ€” the cryptographic instructions ๐Ÿ”
    • +nocrypto โ€” disables the cryptographic instructions ๐Ÿ™ˆ
    • +nofp โ€” disables the floating-point, Advanced SIMD and cryptographic instructions. Big vibe check, bestie ๐Ÿ˜ญ

-march=native makes the compiler auto-detect the architecture of the build computer. Right now this only works on GNU/Linux, and not every architecture gets recognized. If the auto-detect doesn't work out, the option has no effect at all ๐Ÿซ 

๐ŸŽ€ -mtune=name

This one tells GCC which target ARM processor to tune the performance of the code for. Some ARM chips run noticeably better when you use it ๐Ÿš€ Here are the names you can pick from:

arm7tdmi, arm7tdmi-s, arm710t,
arm720t, arm740t, strongarm, strongarm110, strongarm1100,
0strongarm1110, arm8, arm810, arm9, arm9e, arm920, arm920t, arm922t,
arm946e-s, arm966e-s, arm968e-s, arm926ej-s, arm940t, arm9tdmi,
arm10tdmi, arm1020t, arm1026ej-s, arm10e, arm1020e, arm1022e,
arm1136j-s, arm1136jf-s, mpcore, mpcorenovfp, arm1156t2-s,
arm1156t2f-s, arm1176jz-s, arm1176jzf-s, generic-armv7-a, cortex-a5,
cortex-a7, cortex-a8, cortex-a9, cortex-a12, cortex-a15, cortex-a17,
cortex-a32, cortex-a35, cortex-a53, cortex-a55, cortex-a57,
cortex-a72, cortex-a73, cortex-a75, cortex-a76, ares, cortex-r4,
cortex-r4f, cortex-r5, cortex-r7, cortex-r8, cortex-r52, cortex-m0,
cortex-m0plus, cortex-m1, cortex-m3, cortex-m4, cortex-m7,
cortex-m23, cortex-m33, cortex-m1.small-multiply,
cortex-m0.small-multiply, cortex-m0plus.small-multiply, exynos-m1,
marvell-pj4, neoverse-n1, neoverse-n2, neoverse-v1, xscale, iwmmxt,
iwmmxt2, ep9312, fa526, fa626, fa606te, fa626te, fmp626, fa726te,
xgene1.

Also, this option can tune for a big.LITTLE system, which is a whole mood ๐ŸŒˆ The names for that are:

cortex-a15.cortex-a7, cortex-a17.cortex-a7,
cortex-a57.cortex-a53, cortex-a72.cortex-a53, cortex-a72.cortex-a35,
cortex-a73.cortex-a53, cortex-a75.cortex-a55, cortex-a76.cortex-a55.

-mtune=generic-arch tells GCC to tune for a blend of processors within architecture arch ๐Ÿงš The goal is code that runs well on the most popular chips right now, balancing the optimizations that help some CPUs in that range while avoiding the performance potholes of others. The effects of this option may shift in future GCC versions as CPU models come and go, so don't be shocked if it changes ๐Ÿ“

-mtune takes the same extension options as -mcpu, but the extension options don't affect how the generated code gets tuned ๐Ÿ’…

-mtune=native makes the compiler auto-detect the CPU of the build computer. Right now this only works on GNU/Linux, and not every architecture is recognized. If the auto-detect is unsuccessful, the option has no effect ๐Ÿ™ƒ

๐Ÿ’– -mcpu=name[+extension...]

This one names the target ARM processor. GCC uses that name to figure out the target ARM architecture (as if you'd used -march) and the processor type to tune performance for (as if you'd used -mtune). If you use this option together with -march or -mtune, those options take precedence over the matching part of this one ๐Ÿ‘‘

Lots of the supported CPUs come with optional architectural extensions, and those are usually enabled by default. If some versions of a CPU are missing an extension, you can use the extension syntax to turn off the ones that got left out. For floating-point and Advanced SIMD (Neon) instructions, you also have to think about -mfloat-abi and -mfpu. Floating-point and Advanced SIMD instructions only get used if -mfloat-abi isn't set to soft, and any -mfpu setting other than auto overrides the available floating-point and SIMD extension instructions ๐Ÿซถ

For example, cortex-a9 shows up in three main flavours: integer only, with just a floating-point unit, or with floating-point and Advanced SIMD. By default it enables all the instructions, but +nosimd and +nofp can switch off just the SIMD, or both SIMD and floating-point, respectively ๐Ÿ”ฅ

Permissible names for this option are the same as the ones for -mtune.

The following extension options are shared by the listed CPUs:

  • +nodsp โ€” disables the DSP instructions on cortex-m33.
  • +nofp โ€” disables the floating-point instructions on arm9e, arm946e-s, arm966e-s, arm968e-s, arm10e, arm1020e, arm1022e, arm926ej-s, arm1026ej-s, cortex-r5, cortex-r7, cortex-r8, cortex-m4, cortex-m7 and cortex-m33. On generic-armv7-a, cortex-a5, cortex-a7, cortex-a8, cortex-a9, cortex-a12, cortex-a15, cortex-a17, cortex-a15.cortex-a7, cortex-a17.cortex-a7, cortex-a32, cortex-a35, cortex-a53 and cortex-a55, it disables the floating-point and SIMD instructions instead ๐Ÿ˜ญ
  • +nofp.dp โ€” disables the double-precision part of the floating-point instructions on cortex-r5, cortex-r7, cortex-r8, cortex-r52 and cortex-m7.
  • +nosimd โ€” disables the SIMD instructions (but keeps floating-point) on generic-armv7-a, cortex-a5, cortex-a7 and cortex-a9.
  • +crypto โ€” enables the cryptographic instructions on cortex-a32, cortex-a35, cortex-a53, cortex-a55, cortex-a57, cortex-a72, cortex-a73, cortex-a75, exynos-m1, xgene1, cortex-a57.cortex-a53, cortex-a72.cortex-a53, cortex-a73.cortex-a35, cortex-a73.cortex-a53 and cortex-a75.cortex-a55. ๐Ÿ”

Also, the generic-armv7-a pseudo target defaults to VFPv3 with 16 double-precision registers. It supports these extension options: mp, sec, vfpv3-d16, vfpv3, vfpv3-d16-fp16, vfpv3-fp16, vfpv4-d16, vfpv4, neon, neon-vfpv3, neon-fp16 and neon-vfpv4. They mean the same thing as the extensions to -march=armv7-a โœจ

-mcpu=generic-arch is also allowed, and it's the same as -march=arch -mtune=generic-arch. Check out -mtune for more deets ๐ŸŒธ

-mcpu=native makes the compiler auto-detect the CPU of the build computer. Right now this only works on GNU/Linux, and not every architecture is recognized. If the auto-detect is unsuccessful, the option has no effect ๐Ÿ™ˆ

๐Ÿฆ‹ -mfpu=name

This one says what floating-point hardware (or hardware emulation) the target has. Permissible names are:

auto, vfpv2, vfpv3, vfpv3-fp16, vfpv3-d16, vfpv3-d16-fp16, vfpv3xd, vfpv3xd-fp16,
neon-vfpv3, neon-fp16, vfpv4, vfpv4-d16, fpv4-sp-d16, neon-vfpv4,
fpv5-d16, fpv5-sp-d16, fp-armv8, neon-fp-armv8, crypto-neon-fp-armv8

neon is an alias for neon-vfpv3, and vfp is an alias for vfpv2 ๐Ÿ’•

The setting auto is the default and it's special. It makes the compiler pick the floating-point and Advanced SIMD instructions based on the settings of -mcpu and -march ๐Ÿง 

Heads up, bestie ๐Ÿšจ If the selected floating-point hardware includes the NEON extension (e.g. -mfpu=neon), GCC's auto-vectorization pass won't generate floating-point operations unless -funsafe-math-optimizations is also specified. That's because NEON hardware doesn't fully implement the IEEE 754 standard for floating-point arithmetic (in particular, denormal values are treated as zero), so using NEON instructions may lead to a loss of precision.

You can also set the fpu name at function level using the target("fpu=") function attributes or pragmas ๐Ÿช„

๐ŸŒˆ -mfp16-format=name

This specifies the format of the "__fp16" half-precision floating-point type. Permissible names are none, ieee and alternative. The default is none, which means the "__fp16" type isn't defined at all ๐Ÿซฅ

๐Ÿ“ -mstructure-size-boundary=n

The sizes of all structures and unions get rounded up to a multiple of the number of bits set by this option. Permissible values are 8, 32 and 64. The default value varies between toolchains, and for the COFF targeted toolchain the default is 8. A value of 64 is only allowed if the underlying ABI supports it ๐Ÿงฉ

Going bigger can produce faster, more efficient code, but it can also make your program bigger. Different values are potentially incompatible, too. Code compiled with one value can't necessarily be expected to work with code or libraries compiled with another value, if they pass information around using structures or unions ๐Ÿ™…โ€โ™€๏ธ

This option is deprecated, so please don't build new stuff around it ๐Ÿฅ€

๐Ÿงš -mabort-on-noreturn

This generates a call to the function "abort" at the end of a "noreturn" function. It runs if the function tries to return ๐Ÿ’€

๐ŸŒธ -mlong-calls, -mno-long-calls

These tell the compiler to make function calls by first loading the address of the function into a register, and then doing a subroutine call on that register. You need this switch if the target function lives outside the 64-megabyte addressing range of the offset-based version of the subroutine call instruction ๐Ÿฆ‹

Even with this switch on, not every function call becomes a long call. The heuristic is that these are not turned into long calls: static functions, functions with the "short_call" attribute, functions inside the scope of a #pragma no_long_calls directive, and functions whose definitions have already been compiled within the current compilation unit. The exceptions are that weak function definitions, functions with the "long_call" attribute or the "section" attribute, and functions inside the scope of a #pragma long_calls directive are always turned into long calls ๐Ÿ’œ

This one's off by default, bestie ๐Ÿ™ˆ Use -mno-long-calls to get back to normal, or wrap the calls in a #pragma long_calls_off directive ๐ŸŽ€. Just know these switches don't change how calls through function pointers get generated ๐Ÿ’€.

  • -msingle-pic-base โ€” treats the register used for PIC addressing as read-only ๐Ÿ”’ instead of loading it in the prologue for every function. The runtime system has to set that register to an appropriate value before execution begins ๐Ÿงš
  • -mpic-register=reg โ€” picks the register used for PIC addressing ๐Ÿ’…. For the standard PIC base case, the default is any suitable register the compiler chooses ๐Ÿค–. For the single PIC base case, the default is R9 if the target is EABI based or stack-checking is enabled, otherwise it's R10 ๐Ÿ’œ
  • -mpic-data-is-text-relative โ€” assumes the gap between the text and data segments is locked in at static link time ๐Ÿ”—. That means you can use PC-relative addressing to reach data you know lives in the data segment โœจ. For non-VxWorks RTP targets this is on by default ๐Ÿ‘‘. If you turn it off on those targets, -msingle-pic-base gets switched on by default instead ๐Ÿฆ‹
  • -mpoke-function-name โ€” writes the name of each function into the text section, right before the function prologue ๐Ÿช„. The generated code is basically this:
t0
    .ascii "arm_poke_function_name", 0
    .align
t1
    .word 0xff000000 + (t1 - t0)
arm_poke_function_name
    mov     ip, sp
    stmfd   sp!, {fp, ip, lr, pc}
    sub     fp, ip, #4

When you're doing a stack backtrace, code can check the pc stored at fp + 0 ๐Ÿ”. If the trace function then looks at location pc - 12 and the top 8 bits are set, we know there's a function name embedded right before that spot, and it has length ((pc[-3]) & 0xff000000) ๐Ÿซถ

  • -mthumb, -marm โ€” choose whether the code runs in ARM state or Thumb state ๐ŸŒ—. Most configurations default to ARM state, but you can change that default by configuring GCC with the --with-mode=state configure option โš™๏ธ

You can also override ARM and Thumb mode for each function using the target("thumb") and target("arm") function attributes or pragmas ๐Ÿ’ซ

  • -mflip-thumb โ€” switches ARM and Thumb modes on alternating functions ๐Ÿ”„. This is only here for regression testing of mixed Thumb/ARM code generation ๐Ÿงช, so please don't use it for normal compiling ๐Ÿ™…โ€โ™€๏ธ
  • -mtpcs-frame โ€” generates a stack frame that's compliant with the Thumb Procedure Call Standard for all non-leaf functions ๐Ÿ“š. (A leaf function is one that doesn't call any other functions ๐Ÿƒ.) The default is -mno-tpcs-frame โœจ
  • -mtpcs-leaf-frame โ€” generates a stack frame that's compliant with the Thumb Procedure Call Standard for all leaf functions ๐Ÿƒ. (A leaf function is one that does not call any other functions.) The default is -mno-apcs-leaf-frame ๐Ÿ’–
  • -mcallee-super-interworking โ€” gives all externally visible functions in the file being compiled an ARM instruction set header ๐Ÿ“œ. That header switches to Thumb mode before the rest of the function runs ๐Ÿ”€, so these functions can be called from non-interworking code ๐Ÿซถ. This option is not valid in AAPCS configurations, because interworking is already enabled by default ๐Ÿ™…
  • -mcaller-super-interworking โ€” lets calls via function pointers (including virtual functions) run correctly whether or not the target code was compiled for interworking ๐Ÿช„. Heads up: there's a small overhead in the cost of executing a function pointer when this is enabled ๐Ÿข. This option is not valid in AAPCS configurations either, since interworking is enabled by default
  • -mtp=name โ€” sets the access model for the thread local storage pointer ๐Ÿงต. The valid models are soft, which generates calls to __aeabi_read_tp ๐Ÿ“ž; cp15, which fetches the thread pointer straight from cp15 (supported in the arm6k architecture) ๐Ÿ’Ž; and auto, which uses the best available method for the selected processor ๐Ÿค–. The default setting is auto
  • -mtls-dialect=dialect โ€” picks the dialect used for accessing thread local storage ๐Ÿงต. Two dialects are supported: gnu and gnu2 ๐Ÿ‘ฏ. The gnu dialect is the original GNU scheme for supporting local and global dynamic TLS models ๐Ÿ•ฐ๏ธ. The gnu2 dialect is the GNU descriptor scheme, which gives better performance for shared libraries ๐Ÿš€. It's compatible with the original scheme, but it does require new assembler, linker and library support ๐Ÿ› ๏ธ. Initial and local exec TLS models aren't affected by this option and always use the original scheme ๐Ÿ™ˆ
  • -mword-relocations โ€” only generates absolute relocations on word-sized values (i.e. R_ARM_ABS32) ๐ŸŽฏ. This is enabled by default on targets (uClinux, SymbianOS) where the runtime loader imposes this restriction, and whenever -fpic or -fPIC is specified ๐Ÿ’–. This option conflicts with -mslow-flash-data โš ๏ธ
  • -mfix-cortex-m3-ldrd โ€” some Cortex-M3 cores can cause data corruption when ldrd instructions with overlapping destination and base registers are used ๐Ÿ˜ฑ. This option avoids generating those instructions ๐Ÿ›ก๏ธ. It's enabled by default when -mcpu=cortex-m3 is specified
  • -munaligned-access, -mno-unaligned-access โ€” enables (or disables) reading and writing of 16- and 32-bit values from addresses that aren't 16- or 32-bit aligned ๐ŸŒ€. By default, unaligned access is disabled for all pre-ARMv6, all ARMv6-M and for ARMv8-M Baseline architectures, and enabled for all other architectures. If unaligned access isn't enabled, words in packed data structures get accessed one byte at a time ๐ŸŒ

The ARM attribute Tag_CPU_unaligned_access is set in the generated object file to either true or false, depending on the setting of this option ๐Ÿ“ฆ. If unaligned access is enabled, the preprocessor symbol __ARM_FEATURE_UNALIGNED is also defined โœจ

  • -mneon-for-64bits โ€” enables using Neon to handle scalar 64-bit operations ๐ŸŽถ. It's disabled by default, since the cost of moving data from core registers to Neon is high ๐Ÿ’ธ
  • -mslow-flash-data โ€” assumes loading data from flash is slower than fetching instructions ๐Ÿข. Literal loads get minimized for better performance โšก. This option is only supported when compiling for ARMv7 M-profile and is off by default ๐Ÿ™…. It conflicts with -mword-relocations โš ๏ธ
  • -masm-syntax-unified โ€” assumes inline assembler is using unified asm syntax ๐Ÿ“. The default is currently off, which implies divided syntax. This option has no impact on Thumb2 ๐Ÿคท, though that may change in future releases of GCC. Divided syntax should be considered deprecated ๐Ÿ’€
  • -mrestrict-it โ€” restricts generation of IT blocks so they conform to the rules of ARMv8-A ๐Ÿ“. IT blocks can only contain a single 16-bit instruction from a select set of instructions ๐ŸŽฏ. This option is on by default for ARMv8-A Thumb mode ๐ŸŒˆ
  • -mprint-tune-info โ€” prints CPU tuning information as a comment in the assembler file ๐Ÿ“. This is an option used only for regression testing of the compiler, and it's not intended for ordinary use in compiling code ๐Ÿงช. It's disabled by default
  • -mverbose-cost-dump โ€” enables verbose cost model dumping in the debug dump files ๐Ÿ”. This option is provided for debugging the compiler ๐Ÿ› ๏ธ
  • -mpure-code โ€” does not allow constant data to be placed in code sections ๐Ÿšซ. Additionally, when compiling for ELF object format, it gives all text sections the ELF processor-specific section attribute SHF_ARM_PURECODE ๐Ÿท๏ธ. This option is only available when generating non-pic code for M-profile targets ๐Ÿ’œ
  • -mcmse โ€” generates secure code as per the "ARMv8-M Security Extensions: Requirements on Development Tools Engineering Specification" ๐Ÿ”. You can find that spec at https://developer.arm.com/documentation/ecm0359818/latest/ ๐Ÿ”—

โœจ AVR Options โœจ

These options are defined for AVR implementations, so if you're working with those chips, this part's for you ๐Ÿ

  • -mmcu=mcu โ€” picks the Atmel AVR instruction set architecture (ISA) or MCU type ๐Ÿ’…. The default for this option is avr2 ๐Ÿ’œ

GCC supports the following AVR devices and ISAs:

  • avr2 โ€” "Classic" devices with up to 8 KiB of program memory ๐Ÿ•ฐ๏ธ. mcu values: attiny22, attiny26, at90s2313, at90s2323, at90s2333, at90s2343, at90s4414, at90s4433, at90s4434, at90c8534, at90s8515, at90s8535
  • avr25 โ€” "Classic" devices with up to 8 KiB of program memory and with the MOVW instruction ๐ŸŽ€. mcu values: attiny13, attiny13a, attiny24, attiny24a, attiny25, attiny261, attiny261a, attiny2313, attiny2313a, attiny43u, attiny44, attiny44a, attiny45, attiny48, attiny441, attiny461, attiny461a, attiny4313, attiny84, attiny84a, attiny85, attiny87, attiny88, attiny828, attiny841, attiny861, attiny861a, ata5272, ata6616c, at86rf401
  • avr3 โ€” "Classic" devices with 16 KiB up to 64 KiB of program memory ๐Ÿงฉ. mcu values: at76c711, at43usb355
  • avr31 โ€” "Classic" devices with 128 KiB of program memory ๐ŸŒŸ. mcu values: atmega103, at43usb320
  • avr35 โ€” "Classic" devices with 16 KiB up to 64 KiB of program memory and with the MOVW instruction ๐Ÿฆ‹. mcu values: attiny167, attiny1634, atmega8u2, atmega16u2, atmega32u2, ata5505, ata6617c, ata664251, at90usb82, at90usb162
  • avr4 โ€” "Enhanced" devices with up to 8 KiB of program memory ๐ŸŒธ. mcu values: atmega48, atmega48a, atmega48p, atmega48pa, atmega48pb, atmega8, atmega8a, atmega8hva, atmega88, atmega88a, atmega88p, atmega88pa, atmega88pb, atmega8515, atmega8535, ata6285, ata6286, ata6289, ata6612c, at90pwm1, at90pwm2, at90pwm2b, at90pwm3, at90pwm3b, at90pwm81
  • avr5 โ€” โœจ "Enhanced" devices with 16 KiB up to 64 KiB of program memory ๐Ÿ’–
    • MCUs: atmega16, atmega16a, atmega16hva, atmega16hva2, atmega16hvb, atmega16hvbrevb, atmega16m1, atmega16u4, atmega161, atmega162, atmega163, atmega164a, atmega164p, atmega164pa, atmega165, atmega165a, atmega165p, atmega165pa, atmega168, atmega168a, atmega168p, atmega168pa, atmega168pb, atmega169, atmega169a, atmega169p, atmega169pa, atmega32, atmega32a, atmega32c1, atmega32hvb, atmega32hvbrevb, atmega32m1, atmega32u4, atmega32u6, atmega323, atmega324a, atmega324p, atmega324pa, atmega325, atmega325a, atmega325p, atmega325pa, atmega328, atmega328p, atmega328pb, atmega329, atmega329a, atmega329p, atmega329pa, atmega3250, atmega3250a, atmega3250p, atmega3250pa, atmega3290, atmega3290a, atmega3290p, atmega3290pa, atmega406, atmega64, atmega64a, atmega64c1, atmega64hve, atmega64hve2, atmega64m1, atmega64rfr2, atmega640, atmega644, atmega644a, atmega644p, atmega644pa, atmega644rfr2, atmega645, atmega645a, atmega645p, atmega649, atmega649a, atmega649p, atmega6450, atmega6450a, atmega6450p, atmega6490, atmega6490a, atmega6490p, ata5795, ata5790, ata5790n, ata5791, ata6613c, ata6614q, ata5782, ata5831, ata8210, ata8510, ata5702m322, at90pwm161, at90pwm216, at90pwm316, at90can32, at90can64, at90scr100, at90usb646, at90usb647, at94k, m3000
  • avr51 โ€” โœจ "Enhanced" devices with 128 KiB of program memory ๐ŸŽ€
    • MCUs: atmega128, atmega128a, atmega128rfa1, atmega128rfr2, atmega1280, atmega1281, atmega1284, atmega1284p, atmega1284rfr2, at90can128, at90usb1286, at90usb1287
  • avr6 โ€” โœจ "Enhanced" devices with a 3-byte PC, i.e. with more than 128 KiB of program memory ๐Ÿฆ‹
    • MCUs: atmega256rfr2, atmega2560, atmega2561, atmega2564rfr2
  • avrxmega2 โ€” ๐ŸŒธ "XMEGA" devices with more than 8 KiB and up to 64 KiB of program memory
    • MCUs: atxmega8e5, atxmega16a4, atxmega16a4u, atxmega16c4, atxmega16d4, atxmega16e5, atxmega32a4, atxmega32a4u, atxmega32c3, atxmega32c4, atxmega32d3, atxmega32d4, atxmega32e5
  • avrxmega3 โ€” ๐Ÿงš "XMEGA" devices with up to 64 KiB of combined program memory and RAM, where the program memory is visible in the RAM address space ๐Ÿ‘‘
    • MCUs: attiny202, attiny204, attiny212, attiny214, attiny402, attiny404, attiny406, attiny412, attiny414, attiny416, attiny417, attiny804, attiny806, attiny807, attiny814, attiny816, attiny817, attiny1604, attiny1606, attiny1607, attiny1614, attiny1616, attiny1617, attiny3214, attiny3216, attiny3217, atmega808, atmega809, atmega1608, atmega1609, atmega3208, atmega3209, atmega4808, atmega4809
  • avrxmega4 โ€” ๐Ÿ“ "XMEGA" devices with more than 64 KiB and up to 128 KiB of program memory
    • MCUs: atxmega64a3, atxmega64a3u, atxmega64a4u, atxmega64b1, atxmega64b3, atxmega64c3, atxmega64d3, atxmega64d4
  • avrxmega5 โ€” ๐Ÿ’œ "XMEGA" devices with more than 64 KiB and up to 128 KiB of program memory, plus more than 64 KiB of RAM
    • MCUs: atxmega64a1, atxmega64a1u
  • avrxmega6 โ€” ๐Ÿ”ฅ "XMEGA" devices with more than 128 KiB of program memory
    • MCUs: atxmega128a3, atxmega128a3u, atxmega128b1, atxmega128b3, atxmega128c3, atxmega128d3, atxmega128d4, atxmega192a3, atxmega192a3u, atxmega192c3, atxmega192d3, atxmega256a3, atxmega256a3b, atxmega256a3bu, atxmega256a3u, atxmega256c3, atxmega256d3, atxmega384c3, atxmega384d3
  • avrxmega7 โ€” ๐ŸŒˆ "XMEGA" devices with more than 128 KiB of program memory and more than 64 KiB of RAM
    • MCUs: atxmega128a1, atxmega128a1u, atxmega128a4u
  • avrtiny โ€” โญ "TINY" Tiny core devices with 512 B up to 4 KiB of program memory ๐Ÿซถ
    • MCUs: attiny4, attiny5, attiny9, attiny10, attiny20, attiny40
  • avr1 โ€” ๐Ÿ™ˆ This ISA is baked into the minimal AVR core and is supported for the assembler only, so no C compiling here, bestie ๐Ÿ’€
    • MCUs: attiny11, attiny12, attiny15, attiny28, at90s1200
  • -mabsdata โ€” ๐Ÿงš Assumes all data in static storage can be reached with LDS / STS instructions. This only does anything on reduced Tiny devices like ATtiny40. See also the absdata AVR Variable Attributes, variable attribute.
  • -maccumulate-args โ€” ๐Ÿ’… Piles up outgoing function arguments and grabs/releases the stack space for them once, in the function prologue/epilogue. Without this, outgoing arguments get pushed before each call and popped afterwards.

Popping arguments after a call can be pricey on AVR, so accumulating the stack space can give you smaller executables, since arguments don't need removing after each call. This can shrink code for functions that make several calls to functions taking their arguments on the stack, like printf-style functions. โœจ

  • -mbranch-cost=cost โ€” ๐ŸŽ€ Sets the branch costs for conditional branch instructions to cost. Reasonable values for cost are small, non-negative integers. The default branch cost is 0.
  • -mcall-prologues โ€” ๐Ÿฆ‹ Function prologues/epilogues get expanded as calls to appropriate subroutines. The code size comes out smaller.
  • -mgas-isr-prologues โ€” ๐Ÿ”ฅ Interrupt service routines (ISRs) may use the __gcc_isr pseudo instruction supported by GNU Binutils. If this option is on, you can still turn the feature off for individual ISRs with the no_gccisr function attribute (see AVR Function Attributes). This feature is on by default if optimization is on (but not with -Og, see Optimize Options), and if GNU Binutils supports PR21683 at https://sourceware.org/PR21683. ๐ŸŒธ
  • -mint8 โ€” ๐Ÿ’€ Assumes int is an 8-bit integer. This changes the sizes of all the types: a char is 1 byte, an int is 1 byte, a long is 2 bytes, and a long long is 4 bytes. Heads up that this does not conform to the C standards, but the code comes out smaller. ๐Ÿ™ˆ
  • -mmain-is-OS_task โ€” ๐Ÿ‘‘ Don't save registers in main. The effect is the same as attaching the OS_task function attribute to main (see AVR Function Attributes). This is on by default if optimization is on. โœจ
  • -mn-flash=num โ€” ๐Ÿ“ Assumes the flash memory is num times 64 KiB in size.
  • -mno-interrupts โ€” ๐ŸŒˆ The generated code is not compatible with hardware interrupts. The code size is smaller, but interrupts are a no-go ๐Ÿ˜ญ
  • -mrelax โ€” ๐Ÿซถ Tries to swap a CALL or JMP instruction for the shorter RCALL or RJMP instruction where that applies. Setting -mrelax only adds the --mlink-relax option to the assembler's command line and the --relax option to the linker's command line.

Jump relaxing is done by the linker, because jump offsets aren't known until the code is located. So the assembler code the compiler generates is the same, but the instructions in the executable might look different from the assembler code. ๐Ÿงš

Relaxing must be turned on if linker stubs are needed, see the section on "EIND" and linker stubs below. ๐Ÿ’–

  • -mrmw โ€” ๐Ÿ’œ Assumes the device supports the Read-Modify-Write instructions XCH, LAC, LAS and LAT. ๐Ÿ”ฅ
  • -mshort-calls โ€” ๐Ÿฆ‹ Assumes RJMP and RCALL can target the whole program memory.

This one is used internally for multilib selection. It's not an optimization option, so you don't need to set it by hand. ๐Ÿ™…โ€โ™€๏ธ

  • -msp8 โ€” ๐ŸŒธ Treats the stack pointer register as an 8-bit register, i.e. assumes the high byte of the stack pointer is zero. Generally, you don't need to set this one by hand. ๐Ÿ’…

The compiler uses this internally to select and build multilibs for the avr2 and avr25 architectures. These architectures mix devices with and without SPH. For any setting other than -mmcu=avr2 or -mmcu=avr25, the compiler driver adds or removes this option from the compiler proper's command line, because the compiler then knows whether the device or architecture has an 8-bit stack pointer and therefore no SPH register. โœจ

  • -mstrict-X โ€” ๐ŸŽ€ Uses the address register X the way the hardware intends. That means X is only used in indirect, post-increment or pre-decrement addressing.

Without this option, the X register can be used the same way as Y or Z, which then gets emulated with extra instructions. For example, loading a value with X+const addressing, where const is a small non-negative number (const < 64), into a register Rn is done like this:

        adiw r26, const   ; X += const
        ld   <Rn>, X        ; <Rn> = *X
        sbiw r26, const   ; X -= const
  • -mtiny-stack โ€” ๐Ÿ’– Only changes the lower 8 bits of the stack pointer. โญ
  • -mfract-convert-truncate โ€” ๐Ÿฆ‹ Allows truncation instead of rounding toward zero for fractional fixed-point types. ๐ŸŒˆ
  • -nodevicelib โ€” ๐Ÿ™ˆ Don't link against AVR-LibC's device-specific library lib<mcu>.a. ๐Ÿซถ
  • -nodevicespecs โ€” ๐Ÿงš Don't add -specs=device-specs/specs-<mcu> to the compiler driver's command line. You're on the hook for giving the subprocesses (compiler proper, assembler and linker) the right command line options yourself. ๐Ÿ’…
  • -Waddr-space-convert โ€” ๐Ÿ‘‘ Warns about conversions between address spaces where the resulting address space isn't contained in the incoming address space. โš ๏ธ
  • -Wmisspelled-isr โ€” ๐Ÿ’€ Warns if the ISR is misspelled, i.e. without the __vector prefix. This one is enabled by default. ๐Ÿ”ฅ

โœจ "EIND" and Devices with More Than 128 Ki Bytes of Flash โœจ

Pointers in the implementation are 16 bits wide ๐Ÿ’– The address of a function or label is represented as a word address, so indirect jumps and calls can target any code address in the range of 64 Ki words ๐Ÿฆ‹

Okay bestie, so on devices with more than 128 Ki bytes of program memory there's this super special function register called EIND ๐Ÿ’–. It's the most significant part of the target address whenever EICALL or EIJMP instructions get used. Iconic, right? ๐ŸŽ€

Indirect jumps and calls on these devices are handled by the compiler in the following way, and they come with some limitations, so read this part carefully ๐Ÿ‘€

  • The compiler never sets EIND. ๐Ÿ™…โ€โ™€๏ธ
  • The compiler uses EIND implicitly in EICALL/EIJMP instructions, or it might read EIND directly so it can fake an indirect call/jump with a RET instruction. ๐Ÿง 
  • The compiler assumes that EIND never changes during the startup code or during the application. In particular, EIND is not saved/restored in function or interrupt service routine prologue/epilogue, so please don't mess with it ๐Ÿ™ˆ
  • For indirect calls to functions and computed goto, the linker generates stubs. Stubs are jump pads, sometimes also called trampolines ๐Ÿงš. So the indirect call/jump lands on a stub, and the stub contains a direct jump to the address you actually wanted. โœจ
  • Linker relaxation must be turned on so the linker generates the stubs correctly in all situations. See the compiler option -mrelax and the linker option --relax.
โš ๏ธ Bestie, watch out: there are corner cases where the linker is supposed to generate stubs but aborts without relaxation and without a helpful error message. Not it. ๐Ÿ’€
  • The default linker script is arranged for code with EIND = 0. If your code is supposed to work for a setup with EIND != 0, you need a custom linker script ๐Ÿ› ๏ธ to place the sections whose name start with .trampolines into the segment where EIND points to.
  • The startup code from libgcc never sets EIND. Notice that startup code is a blend of code from libgcc and AVR-LibC. For the impact of AVR-LibC on EIND, check out the AVR-LibC user manual ("http://nongnu.org/avr-libc/user-manual/") ๐Ÿ“–
  • It is totally legit for user-specific startup code to set up EIND early, for example by means of initialization code located in section .init3 ๐Ÿ’…. That code runs prior to the general startup code that initializes RAM and calls constructors, but after the bit of AVR-LibC startup code that sets EIND to the segment where the vector table is located.
#include <avr/io.h>

static void
__attribute__((section(".init3"),naked,used,no_instrument_function))
init3_set_eind (void)
{
  __asm volatile ("ldi r24,pm_hh8(__trampolines_start)\n\t"
                  "out %i0,r24" :: "n" (&EIND) : "r24","memory");
}

The __trampolines_start symbol is defined in the linker script. ๐Ÿซถ

  • Stubs are generated automatically by the linker if the following two conditions are met:
    • The address of a label is taken by means of the gs modifier (short for generate stubs), like so:
LDI r24, lo8(gs(<func>))
LDI r25, hi8(gs(<func>))
  • The final location of that label is in a code segment outside the segment where the stubs are located.
  • The compiler emits such gs modifiers for code labels in the following situations:
    • Taking address of a function or code label.
    • Computed goto.
    • If prologue-save function is used, see -mcall-prologues command-line option.
    • Switch/case dispatch tables. If you do not want such dispatch tables you can specify the -fno-jump-tables command-line option.
    • C and C++ constructors/destructors called during startup/shutdown.
    • If the tools hit a gs() modifier explained above.
  • Jumping to non-symbolic addresses like this is not supported ๐Ÿšซ
int main (void)
{
    /* Call function at word address 0x2 */
    return ((int(*)(void)) 0x2)();
}

Instead, a stub has to be set up, i.e., the function has to be called through a symbol (func_4 in the example) ๐Ÿฆ‹

int main (void)
{
    extern int func_4 (void);

    /* Call function at byte address 0x4 */
    return func_4();
}

and the application be linked with -Wl,--defsym,func_4=0x4. Alternatively, func_4 can be defined in the linker script.


๐ŸŒธ Handling of the "RAMPD", "RAMPX", "RAMPY" and "RAMPZ" Special Function Registers ๐ŸŒธ

Some AVR devices support memories larger than the 64 KiB range that can be accessed with 16-bit pointers. To reach memory locations outside that 64 KiB range, the content of a RAMP register is used as the high part of the address. The X, Y, Z address register gets concatenated with the RAMPX, RAMPY, RAMPZ special function register, respectively, to make a wide address. Similarly, RAMPD is used together with direct addressing. ๐Ÿ’œ

  • The startup code initializes the RAMP special function registers with zero. ๐ŸŒฑ
  • If a named address space (see AVR Named Address Spaces) other than generic or __flash is used, then RAMPZ is set as needed before the operation. โœจ
  • If the device supports RAM larger than 64 KiB and the compiler needs to change RAMPZ to accomplish an operation, RAMPZ is reset to zero after the operation. ๐Ÿ”„
  • If the device comes with a specific RAMP register, the ISR prologue/epilogue saves/restores that SFR and initializes it with zero, in case the ISR code might (implicitly) use it. ๐Ÿ›ก๏ธ
  • RAM larger than 64 KiB is not supported by GCC for AVR targets. If you use inline assembler to read from locations outside the 16-bit address range and change one of the RAMP registers, you must reset it to zero after the access. ๐Ÿ˜ญ

๐ŸŽ€ AVR Built-in Macros ๐ŸŽ€

GCC defines several built-in macros so user code can test for the presence or absence of features. Almost any of the following built-in macros are deduced from device capabilities, and are therefore triggered by the -mmcu= command-line option. ๐Ÿงš

For even more AVR-specific built-in macros, see AVR Named Address Spaces and AVR Built-in Functions. ๐Ÿ’–

๐ŸŒˆ "__AVR_ARCH__"

This built-in macro resolves to a decimal number that identifies the architecture, and it depends on the -mmcu=mcu option. Possible values are:

2, 25, 3, 31, 35, 4, 5, 51, 6

for mcu="avr2", "avr25", "avr3", "avr31", "avr35", "avr4", "avr5", "avr51", "avr6",

respectively, and

100, 102, 103, 104, 105, 106, 107

for mcu="avrtiny", "avrxmega2", "avrxmega3", "avrxmega4", "avrxmega5", "avrxmega6", "avrxmega7", respectively. If mcu specifies a device, this built-in macro is set accordingly. For example, with -mmcu=atmega8 the macro is defined to 4. ๐Ÿ“

๐Ÿฆ‹ "__AVR_Device__"

Setting -mmcu=device defines this built-in macro, which reflects the device's name. For example, -mmcu=atmega8 defines the built-in macro "__AVR_ATmega8__", and -mmcu=attiny261a defines "__AVR_ATtiny261A__", etc. ๐ŸŒธ

The built-in macro names follow the scheme "__AVR_Device__", where Device is the device name as it appears in the AVR user manual. The difference between Device in the built-in macro and device in -mmcu=device is that the latter is always lowercase. ๐Ÿ™ˆ

If device is not a device but only a core architecture like avr51, this macro is not defined. ๐Ÿ’€

๐Ÿ’… "__AVR_DEVICE_NAME__"

Setting -mmcu=device defines this built-in macro to the device's name. For example, with -mmcu=atmega8 the macro is defined to "atmega8". โญ

If device is not a device but only a core architecture like avr51, this macro is not defined. ๐Ÿ’€

๐Ÿ‘‘ "__AVR_XMEGA__"

The device or architecture belongs to the XMEGA family of devices. ๐Ÿ”ฅ

๐Ÿซถ "__AVR_HAVE_ELPM__"

The device has the ELPM instruction. ๐Ÿ’œ

๐Ÿซถ "__AVR_HAVE_ELPMX__"

The device has the ELPM Rn,Z and ELPM Rn,Z+ instructions. ๐Ÿฆ‹

๐Ÿซถ "__AVR_HAVE_MOVW__"

The device has the MOVW instruction, which performs 16-bit register-register moves. โœจ

๐Ÿซถ "__AVR_HAVE_LPMX__"

The device has the LPM Rn,Z and LPM Rn,Z+ instructions. ๐ŸŒˆ

๐Ÿซถ "__AVR_HAVE_MUL__"

The device has a hardware multiplier. ๐Ÿ’ช

๐Ÿซถ "__AVR_HAVE_JMP_CALL__"

The device has the JMP and CALL instructions. This is the case for devices with more than 8 KiB of program memory. ๐ŸŒธ

๐Ÿซถ "__AVR_HAVE_EIJMP_EICALL__" and "__AVR_3_BYTE_PC__"

The device has the EIJMP and EICALL instructions. This is the case for devices with more than 128 KiB of program memory. This also means that the program counter (PC) is 3 bytes wide. ๐Ÿง 

๐Ÿซถ "__AVR_2_BYTE_PC__"

The program counter (PC) is 2 bytes wide. This is the case for devices with up to 128 KiB of program memory. ๐Ÿ“

๐Ÿซถ "__AVR_HAVE_8BIT_SP__" and "__AVR_HAVE_16BIT_SP__"

The stack pointer (SP) register is treated by the compiler as an 8-bit register or a 16-bit register, respectively. The definition of these macros is affected by -mtiny-stack. ๐ŸŽ€

๐Ÿซถ "__AVR_HAVE_SPH__" and "__AVR_SP8__"

The device has the SPH (high part of stack pointer) special function register, or has an 8-bit stack pointer, respectively. The definition of these macros is affected by -mmcu= and, in the cases of -mmcu=avr2 and -mmcu=avr25, also by -msp8. ๐ŸŒท

๐Ÿซถ "__AVR_HAVE_RAMPD__", "__AVR_HAVE_RAMPX__", "__AVR_HAVE_RAMPY__" and "__AVR_HAVE_RAMPZ__"

The device has the RAMPD, RAMPX, RAMPY, RAMPZ special function register, respectively. ๐Ÿงš

๐Ÿซถ "__NO_INTERRUPTS__"

This macro reflects the -mno-interrupts command-line option. ๐Ÿšซ

๐Ÿซถ "__AVR_ERRATA_SKIP__" and "__AVR_ERRATA_SKIP_JMP_CALL__"

Some AVR devices (AT90S8515, ATmega103) must not skip 32-bit instructions because of a hardware erratum. The skip instructions are SBRS, SBRC, SBIS, SBIC and CPSE. The second macro is only defined if "__AVR_HAVE_JMP_CALL__" is also set. โš ๏ธ

๐Ÿซถ "__AVR_ISA_RMW__"

The device has Read-Modify-Write instructions (XCH, LAC, LAS and LAT). ๐Ÿ”ฅ

๐Ÿซถ "__AVR_SFR_OFFSET__=offset"

Instructions that can address I/O special function registers directly, like IN, OUT, SBI, etc., may use a different address than an instruction that accesses RAM, like LD or STS. This offset depends on the device architecture and has to be subtracted from the RAM address in order to get the respective I/O address. ๐ŸŒˆ

๐Ÿซถ "__AVR_SHORT_CALLS__"

The -mshort-calls command-line option is set. ๐Ÿ’–

โœจ AVR Options (continued) โœจ

  • __AVR_PM_BASE_ADDRESS__=addr โ€” okay so some devices can read from flash memory using LD* instructions ๐Ÿงš The flash shows up in the data address space at an offset of __AVR_PM_BASE_ADDRESS__. If this macro isn't defined, the feature just isn't available ๐Ÿ˜ญ If it is defined, the address space is linear, so there's no need to shove .rodata into RAM. The default linker description file handles that, and it's currently available for avrtiny and avrxmega3. Even more convenient, you don't need address spaces like __flash or features like the attribute progmem and pgm_read_* ๐Ÿ’…
  • __WITH_AVRLIBC__ โ€” the compiler is configured to work together with AVR-Libc ๐ŸŽ€ See the --with-avrlibc configure option.

๐ŸŒธ Blackfin Options ๐ŸŒธ

  • -mcpu=cpu[-sirevision] โ€” choose your target Blackfin processor! cpu can be one of bf512, bf514, bf516, bf518, bf522, bf523, bf524, bf525, bf526, bf527, bf531, bf532, bf533, bf534, bf536, bf537, bf538, bf539, bf542, bf544, bf547, bf548, bf549, bf542m, bf544m, bf547m, bf548m, bf549m, bf561, or bf592 ๐Ÿ’–
    • The optional sirevision picks the silicon revision of the target Blackfin processor, and any workarounds for that revision get enabled โœจ
    • If sirevision is none, no workarounds are enabled. If it's any, all workarounds for the targeted processor are enabled ๐Ÿ”ง
    • The __SILICON_REVISION__ macro gets defined to two hexadecimal digits, representing the major and minor numbers of the silicon revision. If sirevision is none, __SILICON_REVISION__ is not defined at all. If it's any, it's defined to be 0xffff.
    • If you skip the optional sirevision, GCC assumes the latest known silicon revision of the targeted Blackfin processor ๐Ÿง 
    • GCC defines a preprocessor macro for the specified cpu. For the bfin-elf toolchain, this option causes the hardware BSP provided by libgloss to get linked in, as long as -msim isn't given.
    • Without this option, bf532 is used as the processor by default ๐ŸŒˆ
    • > Heads up bestie: support for bf561 is incomplete. For bf561, only the preprocessor macro is defined ๐Ÿ™ˆ
  • -msim โ€” the program will run on the simulator ๐Ÿ–ฅ๏ธ This links in the simulator BSP provided by libgloss. It only has an effect for the bfin-elf toolchain. Certain other options, like -mid-shared-library and -mfdpic, imply -msim.
  • -momit-leaf-frame-pointer โ€” don't keep the frame pointer in a register for leaf functions ๐Ÿ“ This skips the instructions that save, set up, and restore frame pointers, and frees up an extra register in leaf functions.
  • -mspecld-anomaly โ€” when enabled, the compiler makes sure the generated code doesn't contain speculative loads after jump instructions ๐Ÿ›ก๏ธ If this option is used, __WORKAROUND_SPECULATIVE_LOADS is defined.
  • -mno-specld-anomaly โ€” don't generate extra code to stop speculative loads from happening ๐Ÿ™…โ€โ™€๏ธ
  • -mcsync-anomaly โ€” when enabled, the compiler makes sure the generated code doesn't contain CSYNC or SSYNC instructions too soon after conditional branches ๐Ÿ’… If this option is used, __WORKAROUND_SPECULATIVE_SYNCS is defined.
  • -mno-csync-anomaly โ€” don't generate extra code to stop CSYNC or SSYNC instructions from popping up too soon after a conditional branch ๐Ÿ™…โ€โ™€๏ธ
  • -mlow64k โ€” when enabled, the compiler is free to take advantage of the knowledge that the entire program fits into the low 64k of memory ๐Ÿฆ‹
  • -mno-low64k โ€” assume the program is arbitrarily large. This is the default ๐ŸŒธ
  • -mstack-check-l1 โ€” do stack checking using information placed into L1 scratchpad memory by the uClinux kernel ๐Ÿงš
  • -mid-shared-library โ€” generate code that supports shared libraries via the library ID method ๐Ÿ“š This lets you do execute in place and use shared libraries in an environment without virtual memory management. This option implies -fPIC. With a bfin-elf target, it also implies -msim.
  • -mno-id-shared-library โ€” generate code that doesn't assume ID-based shared libraries are being used. This is the default ๐ŸŒท
  • -mleaf-id-shared-library โ€” generate code that supports shared libraries via the library ID method, but assumes this library or executable won't link against any other ID shared libraries ๐Ÿƒโ€โ™€๏ธ That lets the compiler use faster code for jumps and calls.
  • -mno-leaf-id-shared-library โ€” don't assume the code being compiled won't link against any ID shared libraries. Slower code is generated for jump and call instructions ๐Ÿข
  • -mshared-library-id=n โ€” specifies the identification number of the ID-based shared library being compiled ๐Ÿ”ข A value of 0 generates more compact code. Other values force that number to be allocated to the current library, but it's no more space- or time-efficient than leaving this option out.
  • -msep-data โ€” generate code that lets the data segment live in a different area of memory from the text segment ๐Ÿ’œ This allows execute in place in an environment without virtual memory management, by getting rid of relocations against the text section.
  • -mno-sep-data โ€” generate code that assumes the data segment follows the text segment. This is the default ๐ŸŽ€
  • -mlong-calls, -mno-long-calls โ€” tells the compiler to do function calls by first loading the function's address into a register, then making a subroutine call on that register ๐Ÿ“ž You need this switch if the target function lives outside the 24-bit addressing range of the offset-based version of the subroutine call instruction.
    • This feature is not enabled by default. Specifying -mno-long-calls restores the default behavior ๐Ÿ™Œ
    • These switches have no effect on how the compiler handles function calls made through function pointers ๐Ÿคทโ€โ™€๏ธ
  • -mfast-fp โ€” link with the fast floating-point library โšก It relaxes some of the IEEE floating-point standard's rules for checking inputs against Not-a-Number (NAN), in the name of performance.
  • -minline-plt โ€” enable inlining of PLT entries in function calls to functions that aren't known to bind locally ๐Ÿงฉ It has no effect without -mfdpic.
  • -mmulticore โ€” build a standalone application for multicore Blackfin processors ๐ŸŒ This option makes sure the proper start files and link scripts supporting multicore get used, and it defines the macro __BFIN_MULTICORE. It can only be used with -mcpu=bf561[-sirevision].
    • This option can be used with -mcorea or -mcoreb, which select the one-application-per-core programming model ๐Ÿ‘ฏ
    • Without -mcorea or -mcoreb, the single-application/dual-core programming model is used. In this model, the main function of Core B should be named coreb_main ๐Ÿ‘‘
    • If this option isn't used, the single-core application programming model is used ๐ŸŒ™
  • -mcorea โ€” build a standalone application for Core A of BF561 when using the one-application-per-core programming model ๐Ÿ…ฐ๏ธ Proper start files and link scripts are used to support Core A, and the macro __BFIN_COREA is defined. This option can only be used together with -mmulticore.
  • -mcoreb โ€” build a standalone application for Core B of BF561 when using the one-application-per-core programming model ๐Ÿ…ฑ๏ธ Proper start files and link scripts are used to support Core B, and the macro __BFIN_COREB is defined. When this option is used, coreb_main should be used instead of main. This option can only be used together with -mmulticore.
  • -msdram โ€” build a standalone application for SDRAM ๐Ÿง  Proper start files and link scripts are used to put the application into SDRAM, and the macro __BFIN_SDRAM is defined. The loader should initialize SDRAM before loading the application.
  • -micplb โ€” assume ICPLBs are enabled at run time ๐Ÿ” This has an effect on certain anomaly workarounds. For Linux targets, the default is to assume ICPLBs are enabled. For standalone applications, the default is off.

๐Ÿฆ‹ C6X Options ๐Ÿฆ‹

  • -march=name โ€” specifies the name of the target architecture ๐Ÿ—๏ธ GCC uses this name to figure out what kind of instructions it can emit when generating assembly code. Permissible names are: c62x, c64x, c64x+, c67x, c67x+, and c674x.
  • -mbig-endian โ€” generate code for a big-endian target ๐ŸŒ…
  • -mlittle-endian โ€” generate code for a little-endian target. This is the default ๐Ÿ’–
  • -msim โ€” choose startup files and a linker script that suit the simulator ๐Ÿ–ฅ๏ธ
  • -msdata=default โ€” put small global and static data in the .neardata section, which is pointed to by register B14 ๐Ÿ“ Small uninitialized global and static data goes in the .bss section, which is adjacent to .neardata. Small read-only data goes into the .rodata section. The sections used for large pieces of data are .fardata, .far, and .const.
  • -msdata=all โ€” put all data, not just small objects, into the sections reserved for small data, and use addressing relative to the B14 register to access them ๐ŸŒˆ
  • -msdata=none โ€” make no use of the sections reserved for small data, and use absolute addresses to access all data ๐Ÿงญ All initialized global and static data goes in the .fardata section, all uninitialized data goes in the .far section, and all constant data goes in the .const section.

๐ŸŒท CRIS Options ๐ŸŒท

These options are defined specifically for the CRIS ports ๐Ÿ’…

  • -march=architecture-type, -mcpu=architecture-type โ€” generate code for the specified architecture ๐Ÿ› ๏ธ The choices for architecture-type are v3, v8, and v10, for ETRAX 4, ETRAX 100, and ETRAX 100 LX respectively. The default is v0, except for cris-axis-linux-gnu, where the default is v10.
  • -mtune=architecture-type โ€” tune everything applicable about the generated code to architecture-type, except for the ABI and the set of available instructions ๐ŸŽถ The choices for architecture-type are the same as for -march=architecture-type.
  • -mmax-stack-frame=n โ€” warn when the stack frame of a function goes over n bytes ๐Ÿšจ
  • -metrax4, -metrax100 โ€” these are synonyms for -march=v3 and -march=v8, respectively ๐Ÿ”

okay bestie, we're still in the CRIS vibes so let's keep going ๐Ÿฆ‹

  • -mmul-bug-workaround, -mno-mul-bug-workaround โ€” ๐Ÿ› Patches up a bug in the muls and mulu instructions on CPU models where it actually shows up. This one's on by default, so you get the fix for free โœจ
  • -mpdebug โ€” ๐Ÿ” Turns on CRIS-specific verbose debug info in the assembly output. Heads up: it also switches off the #NO_APP marker that normally gets dropped at the top of the assembly file for the assembler ๐Ÿ’…
  • -mcc-init โ€” ๐Ÿง  Stops GCC from trusting condition-code results left over from the previous instruction. Instead, it always puts in compare and test instructions before any condition codes get used. Extra safe, extra instructions, no cap ๐Ÿ’€
  • -mno-side-effects โ€” ๐Ÿšซ No instructions with side effects in addressing modes, except post-increment. Post-increment is still allowed, bestie ๐Ÿ’–
  • -mstack-align, -mno-stack-align, -mdata-align, -mno-data-align, -mconst-align, -mno-const-align โ€” ๐Ÿ“ Okay so the plain versions make the stack frame, individual data, and constants line up to the biggest single data access size for your chosen CPU model. The no- versions cancel that alignment out. By default you get 32-bit alignment, and ABI stuff like structure layout doesn't get touched by any of these โœจ

  • -m32-bit, -m16-bit, -m8-bit โ€” ๐ŸŽ€ Same vibe as the stack, data, and const align options above, but these make the stack frame, writable data, and constants 32-bit, 16-bit, or 8-bit aligned. The default is 32-bit ๐ŸŒธ
  • -mno-prologue-epilogue, -mprologue-epilogue โ€” โš ๏ธ With -mno-prologue-epilogue, the usual function prologue and epilogue that set up the stack frame get skipped, and no return instructions or return sequences show up in the code. Only use this if you're going to eyeball the compiled code yourself ๐Ÿ‘€ GCC won't warn or error when call-saved registers need saving or local variable storage needs allocating. Be careful out there ๐Ÿ˜ญ
  • -mno-gotplt, -mgotplt โ€” ๐Ÿฆ‹ With -fpic and -fPIC, -mno-gotplt means no instruction sequences that load function addresses from the PLT part of the GOT. The alternative, which is how other architectures usually do it, is calls to the PLT. The default is -mgotplt, so that's what you get unless you say otherwise ๐Ÿ’œ
  • -melf โ€” ๐Ÿชฆ A legacy no-op. It's only recognized with the cris-axis-elf and cris-axis-linux-gnu targets, so it's basically just vibing there doing nothing ๐Ÿ™ˆ
  • -mlinux โ€” ๐Ÿชฆ Another legacy no-op, only recognized with the cris-axis-linux-gnu target ๐ŸŒˆ
  • -sim โ€” ๐Ÿงš Recognized for the cris-axis-elf target. It links in input-output functions from a simulator library. Code, initialized data, and zero-initialized data all get allocated right next to each other, one after the other โœจ
  • -sim2 โ€” ๐Ÿ‘‘ Same as -sim, but it also passes linker options so initialized data lands at 0x40000000 and zero-initialized data lands at 0x80000000 ๐Ÿ”ฅ

โœจ CR16 Options โœจ

okay so these options are made specifically for the CR16 ports, so if that's your world, this section is for you ๐Ÿซถ

  • -mmac โ€” ๐Ÿงฎ Turns on the multiply-accumulate instructions. It's disabled by default, so you have to ask for it ๐Ÿ’…
  • -mcr16cplus, -mcr16c โ€” ๐ŸŽฏ Generates code for the CR16C or CR16C+ architecture. CR16C+ is the default, so -mcr16c is how you opt into the older one ๐Ÿ“
  • -msim โ€” ๐Ÿ”— Links in the library libsim.a, which works with the simulator. This one only applies to the ELF compiler, so keep that in mind ๐ŸŒธ
  • -mint32 โ€” ๐Ÿ”ข Makes the integer type 32-bit wide ๐Ÿ’–
  • -mbit-ops โ€” โšก Generates "sbit"/"cbit" instructions for bit manipulation. Bit-twiddling, but make it efficient ๐Ÿ’…
  • -mdata-model=model โ€” ๐Ÿ—‚๏ธ Picks a data model. Your choices are near, far, or medium, and medium is the default. Watch out though: far isn't valid with -mcr16c, because the CR16C architecture doesn't support the far data model at all ๐Ÿ˜ญ

โœจ C-SKY Options โœจ

GCC supports these options when you're compiling for C-SKY V2 processors, so if that's your chip, you're in the right place ๐Ÿงš

  • -march=arch โ€” ๐Ÿ—๏ธ Specifies the C-SKY target architecture. Valid values for arch are ck801, ck802, ck803, ck807, and ck810. The default is ck810 ๐Ÿ’œ
  • -mcpu=cpu โ€” ๐ŸŽ›๏ธ Specifies the C-SKY target processor. Valid values for cpu are ck801, ck801t, ck802, ck802t, ck802j, ck803, ck803h, ck803t, ck803ht, ck803f, ck803fh, ck803e, ck803eh, ck803et, ck803eht, ck803ef, ck803efh, ck803ft, ck803eft, ck803efht, ck803r1, ck803hr1, ck803tr1, ck803htr1, ck803fr1, ck803fhr1, ck803er1, ck803ehr1, ck803etr1, ck803ehtr1, ck803efr1, ck803efhr1, ck803ftr1, ck803eftr1, ck803efhtr1, ck803s, ck803st, ck803se, ck803sf, ck803sef, ck803seft, ck807e, ck807ef, ck807, ck807f, ck810e, ck810et, ck810ef, ck810eft, ck810, ck810v, ck810f, ck810t, ck810fv, ck810tv, ck810ft, and ck810ftv. That's a whole roster, bestie ๐Ÿ˜ญ๐Ÿซถ

  • -mbig-endian, -EB, -mlittle-endian, -EL โ€” ๐ŸŒŠ Picks big-endian or little-endian code. Little-endian is the default ๐Ÿ’–
  • -mhard-float, -msoft-float โ€” ๐Ÿ”ง Picks hardware or software floating-point. The default is soft float, so you need -mhard-float if you want the hardware version โœจ
  • -mdouble-float, -mno-double-float โ€” ๐ŸŽฏ When -mhard-float is in effect, -mdouble-float turns on double-precision float instructions. This is the default unless you're compiling for CK803 ๐ŸŒธ
  • -mfdivdu, -mno-fdivdu โ€” โž— When -mhard-float is in effect, -mfdivdu turns on the "frecipd", "fsqrtd", and "fdivd" instructions. Also the default unless you're compiling for CK803 ๐Ÿ’…
  • -mfpu=fpu โ€” ๐Ÿงฉ Selects the floating-point processor. This only works together with -mhard-float. The values for fpu are fpv2_sf (which is the same as -mno-double-float -mno-fdivdu), fpv2 (-mdouble-float -mno-divdu), and fpv2_divd (-mdouble-float -mdivdu) ๐Ÿ”ฅ
  • -melrw, -mno-elrw โ€” ๐Ÿช„ Turns on the extended "lrw" instruction. It defaults to on for CK801 and off for everything else ๐Ÿ’œ
  • -mistack, -mno-istack โ€” ๐Ÿ“š Turns on interrupt stack instructions. The default is off ๐Ÿ™ˆ
โš ๏ธ You need -mistack to handle the "interrupt" and "isr" function attributes. No -mistack, no interrupt handling, periodt ๐Ÿ˜ญ
  • -mmp โ€” ๐Ÿงต Turns on multiprocessor instructions. Default is off ๐ŸŒˆ
  • -mcp โ€” ๐Ÿค Turns on coprocessor instructions. Default is off ๐Ÿฆ‹
  • -mcache โ€” ๐Ÿ—„๏ธ Turns on coprocessor instructions. Default is off. Yes, the original says the same thing as -mcp, so both of these are doing the coprocessor thing ๐Ÿ’€
  • -msecurity โ€” ๐Ÿ” Turns on C-SKY security instructions. Default is off โœจ
  • -mtrust โ€” ๐Ÿซก Turns on C-SKY trust instructions. Default is off ๐Ÿ’–
  • -mdsp, -medsp, -mvdsp โ€” ๐ŸŽถ Turn on C-SKY DSP, Enhanced DSP, or Vector DSP instructions, respectively. They all default to off ๐Ÿ‘‘
  • -mdiv, -mno-div โ€” โž— Generates divide instructions. Default is off ๐Ÿ“
  • -msmart, -mno-smart โ€” ๐Ÿง  Generates code for Smart Mode, which only uses registers numbered 0-7 so you can use 16-bit instructions. This is ignored for CK801, where that's already the required behavior, and it defaults to on for CK802. For other targets, the default is off ๐ŸŒธ
  • -mhigh-registers, -mno-high-registers โ€” ๐Ÿš€ Generates code using the high registers numbered 16-31. This isn't supported on CK801, CK802, or CK803, but it's enabled by default for other processors ๐Ÿ’…
  • -manchor, -mno-anchor โ€” โš“ Generates code using global anchor symbol addresses ๐ŸŒŠ
  • -mpushpop, -mno-pushpop โ€” ๐Ÿ“ฅ Generates code using "push" and "pop" instructions. This option defaults to on ๐Ÿ’–
  • -mmultiple-stld, -mstm, -mno-multiple-stld, -mno-stm โ€” ๐Ÿงบ Generates code using "stm" and "ldm" instructions. This one isn't supported on CK801, but it's enabled by default on other processors ๐ŸŽ€
  • -mconstpool, -mno-constpool โ€” ๐ŸŠ Creates constant pools in the compiler, instead of leaving it to the assembler. This is the default and it's required for correct code generation on CK801 and CK802. It's optional on other processors ๐Ÿ’œ
  • -mstack-size, -mno-stack-size โ€” ๐Ÿ“ Emits ".stack_size" directives for each function in the assembly output. Defaults to off ๐ŸŒˆ
  • -mccrt, -mno-ccrt โ€” ๐Ÿ› ๏ธ Generates code for the C-SKY compiler runtime instead of libgcc. Defaults to off โœจ
  • -mbranch-cost=n โ€” ๐Ÿ›ค๏ธ Sets the branch costs to roughly "n" instructions. The default is 1 ๐Ÿฆ‹
  • -msched-prolog, -mno-sched-prolog โ€” โฐ Permits scheduling of function prologue and epilogue sequences. Heads up, this can give you code that doesn't follow the C-SKY V2 ABI prologue requirements, and that code can't be debugged or backtraced. It's disabled by default, so only turn it on if you know what you're doing ๐Ÿ˜ญ

โœจ Darwin Options โœจ

These options are defined for all architectures running the Darwin operating system ๐ŸŽ

Okay so FSF GCC on Darwin does not make "fat" object files. It makes an object file for the single architecture GCC was built to target. Apple's GCC, though, does make "fat" files if you use multiple -arch options. It does that by running the compiler or linker multiple times and then joining the results together with lipo ๐Ÿซถ

The subtype of the file (like ppc7400, ppc970, or i686) gets decided by the flags that specify the ISA GCC is targeting, like -mcpu or -march. The -force_cpusubtype_ALL option can override that if you need it to ๐Ÿ‘‘

The Darwin tools act differently when they hit an ISA mismatch, so pay attention ๐Ÿ” The assembler, as, only lets instructions be used if they're valid for the subtype of the file it's generating. So no 64-bit instructions in a ppc750 object file, sorry bestie ๐Ÿ’€ The linker for shared libraries, /usr/bin/libtool, fails and prints an error if you ask it to make a shared library with a less restrictive subtype than its input files. For example, putting a ppc970 object file in a ppc7400 library is a no-go ๐Ÿ™…โ€โ™€๏ธ The linker for executables, ld, quietly gives the executable the most restrictive subtype of any of its input files ๐Ÿคซ

  • -Fdir โ€” ๐Ÿ“‚ Adds the framework directory dir to the front of the list of directories searched for header files. These directories get mixed in with the ones from -I options, and they're scanned left-to-right ๐ŸŒธ

A framework directory ๐Ÿ—‚๏ธ is just a folder full of frameworks, and a framework is a directory with a Headers and/or PrivateHeaders folder sitting directly inside it and a name ending in .framework ๐ŸŽ€. The framework's name is that folder name minus the .framework part. Its headers live in one of those two folders, and Headers gets searched first ๐Ÿ‘‘. A subframework is a framework tucked inside another framework's Frameworks directory. Subframework headers can only be included from a header of the framework that contains them, or from a sibling subframework's header ๐Ÿซถ. Two subframeworks are siblings if they live in the same framework. A subframework shouldn't share a name with a framework, and the compiler warns you if it does ๐Ÿ’€. Right now subframeworks can't have subframeworks of their own, but that might change later ๐Ÿ‘€. The standard frameworks live in /System/Library/Frameworks and /Library/Frameworks. An include looks like #include <Framework/header.h>, where Framework is the framework's name and header.h is found in the PrivateHeaders or Headers folder โœจ.

  • -iframeworkdir โ€” This is like -F, except the directory gets treated as a system directory ๐Ÿงš. The big difference is that with -iframework the compiler won't warn about constructs inside header files it finds through that directory. This only works for the C family of languages.
  • -gused โ€” Emits debugging info for symbols that are actually used ๐Ÿ”. For the stabs debugging format, this turns on -feliminate-unused-debug-symbols. It's ON by default, so you're already getting it ๐Ÿ’….
  • -gfull โ€” Emits debugging info for every symbol and type, no exceptions ๐ŸŒˆ.
  • -mmacosx-version-min=version โ€” The earliest version of MacOS X this executable will run on is version ๐ŸŽ. Typical values include 10.1, 10.2, and 10.3.9. If the compiler was built to use the system's headers by default, the default for this option is the system version the compiler is running on. Otherwise, it picks choices that are compatible with as many systems and code bases as possible ๐Ÿซง.
  • -mkernel โ€” Turns on kernel development mode ๐Ÿ”ฅ. This sets -static, -fno-common, -fno-use-cxa-atexit, -fno-exceptions, -fno-non-call-exceptions, -fapple-kext, -fno-weak and -fno-rtti, where applicable. For PowerPC targets, it also sets -mno-altivec, -msoft-float, -fno-builtin and -mlong-branch ๐Ÿ‘‘.
  • -mone-byte-bool โ€” Overrides the defaults for bool so that sizeof(bool)==1 ๐Ÿซ . By default, sizeof(bool) is 4 when compiling for Darwin/PowerPC and 1 when compiling for Darwin/x86, so this option does nothing on x86.
โš ๏ธ Warning: The -mone-byte-bool switch causes GCC to generate code that is not binary compatible with code generated without that switch. Using this switch may require recompiling all other modules in a program, including system libraries. Use this switch to conform to a non-default data model. ๐Ÿ’€
  • -mfix-and-continue, -ffix-and-continue, -findirect-data โ€” These generate code built for fast turnaround development โšก, like letting GDB dynamically load .o files into programs that are already running ๐Ÿƒโ€โ™€๏ธ. -findirect-data and -ffix-and-continue are only here for backwards compatibility ๐Ÿ•ฐ๏ธ.
  • -all_load โ€” Loads all members of static archive libraries ๐Ÿ“ฆ. See man ld(1) for more information.
  • -arch_errors_fatal โ€” Makes errors about files with the wrong architecture fatal ๐Ÿ›‘.
  • -bind_at_load โ€” Marks the output file so the dynamic linker binds all undefined references when the file is loaded or launched ๐Ÿ”—.
  • -bundle โ€” Produces a Mach-o bundle format file ๐Ÿงณ. See man ld(1) for more information.
  • -bundle_loader executable โ€” Specifies the executable that will load the build output file being linked ๐ŸŽฏ. See man ld(1) for more information.
  • -dynamiclib โ€” When you pass this, GCC produces a dynamic library instead of an executable when linking, using the Darwin libtool command ๐ŸŒธ.
  • -force_cpusubtype_ALL โ€” Gives GCC's output file the ALL subtype, instead of one controlled by the -mcpu or -march option ๐Ÿฆ‹.
  • Darwin linker passthroughs โ€” Everything below is passed to the Darwin linker. The Darwin linker man page explains them in detail, so go there for the full tea โ˜•:
    • -allowable_client client_name
    • -client_name
    • -compatibility_version
    • -current_version
    • -dead_strip
    • -dependency-file
    • -dylib_file
    • -dylinker_install_name
    • -dynamic
    • -exported_symbols_list
    • -filelist
    • -flat_namespace
    • -force_flat_namespace
    • -headerpad_max_install_names
    • -image_base
    • -init
    • -install_name
    • -keep_private_externs
    • -multi_module
    • -multiply_defined
    • -multiply_defined_unused
    • -noall_load
    • -no_dead_strip_inits_and_terms
    • -nofixprebinding
    • -nomultidefs
    • -noprebind
    • -noseglinkedit
    • -pagezero_size
    • -prebind
    • -prebind_all_twolevel_modules
    • -private_bundle
    • -read_only_relocs
    • -sectalign
    • -sectobjectsymbols
    • -whyload
    • -seg1addr
    • -sectcreate
    • -sectobjectsymbols
    • -sectorder
    • -segaddr
    • -segs_read_only_addr
    • -segs_read_write_addr
    • -seg_addr_table
    • -seg_addr_table_filename
    • -seglinkedit
    • -segprot
    • -segs_read_only_addr
    • -segs_read_write_addr
    • -single_module
    • -static
    • -sub_library
    • -sub_umbrella
    • -twolevel_namespace
    • -umbrella
    • -undefined
    • -unexported_symbols_list
    • -weak_reference_mismatches
    • -whatsloaded

๐Ÿฆ‹ DEC Alpha Options ๐Ÿฆ‹

These -m options are defined for the DEC Alpha implementations ๐Ÿ’œ.

  • -mno-soft-float, -msoft-float โ€” Uses (or doesn't use) the hardware floating-point instructions for floating-point operations ๐Ÿ”ข. When -msoft-float is specified, functions in libgcc.a are used to do the floating-point work. Unless those get replaced by routines that emulate the floating-point operations, or get compiled to call such emulation routines, these routines will issue floating-point operations ๐Ÿ˜ฌ. If you're compiling for an Alpha without floating-point operations, you have to make sure the library is built so it doesn't call them.

Note that Alpha implementations without floating-point operations are still required to have floating-point registers ๐Ÿง .

  • -mfp-reg, -mno-fp-regs โ€” Generates code that uses (or doesn't use) the floating-point register set ๐ŸŽ€. -mno-fp-regs implies -msoft-float. If the floating-point register set isn't used, floating-point operands get passed in integer registers as if they were integers, and floating-point results get passed in $0 instead of $f0. This is a non-standard calling sequence, so any function with a floating-point argument or return value that's called by code compiled with -mno-fp-regs must also be compiled with that option ๐Ÿšจ.

A typical use of this option is building a kernel that doesn't use, and so doesn't need to save and restore, any floating-point registers ๐Ÿง‘โ€๐Ÿ’ป.

  • -mieee โ€” The Alpha architecture has floating-point hardware that's optimized for max performance โšก. It's mostly compliant with the IEEE floating-point standard, but full compliance needs some software help. This option generates fully IEEE-compliant code, except that the inexact-flag isn't maintained (see below). When you turn this on, the preprocessor macro "_IEEE_FP" gets defined during compilation. The resulting code is less efficient, but it can correctly support denormalized numbers and exceptional IEEE values like not-a-number and plus/minus infinity ๐ŸŒŸ. Other Alpha compilers call this option -ieee_with_no_inexact.
  • -mieee-with-inexact โ€” This is like -mieee, except the generated code also maintains the IEEE inexact-flag ๐Ÿซง. Turning this on makes the generated code implement fully-compliant IEEE math. On top of "_IEEE_FP", the preprocessor macro "_IEEE_FP_EXACT" also gets defined. On some Alpha implementations, the resulting code may run significantly slower than the default code ๐Ÿข. Since there's very little code that depends on the inexact-flag, you should normally not specify this option ๐Ÿ™…โ€โ™€๏ธ. Other Alpha compilers call this option -ieee_with_inexact.
  • -mfp-trap-mode=trap-mode โ€” Controls which floating-point related traps are enabled ๐Ÿชค. Other Alpha compilers call this option -fptm trap-mode. The trap mode can be set to one of four values:
    • n โ€” This is the default (normal) setting. The only traps enabled are the ones that can't be disabled in software (for example, the division by zero trap) ๐Ÿงฑ.
    • u โ€” On top of the traps enabled by n, underflow traps are enabled too ๐Ÿ“‰.
    • su โ€” Like u, but the instructions are marked as safe for software completion (see the Alpha architecture manual for details) โœ….
    • sui โ€” Like su, but inexact traps are enabled as well ๐Ÿ””.
  • -mfp-rounding-mode=rounding-mode โ€” Selects the IEEE rounding mode ๐ŸŽฏ. Other Alpha compilers call this option -fprm rounding-mode. The rounding-mode can be one of:
    • n โ€” Normal IEEE rounding mode. Floating-point numbers are rounded towards the nearest machine number, or towards the even machine number in case of a tie ๐ŸŽฒ.
    • m โ€” Rounds towards minus infinity โฌ‡๏ธ.
    • c โ€” Chopped rounding mode. Floating-point numbers are rounded towards zero โœ‚๏ธ.
    • d โ€” Dynamic rounding mode. A field in the floating-point control register (fpcr, see the Alpha architecture reference manual) controls the rounding mode in effect ๐ŸŽ›๏ธ. The C library initializes this register for rounding towards plus infinity, so unless your program modifies the fpcr, d corresponds to rounding towards plus infinity โฌ†๏ธ.
  • -mtrap-precision=trap-precision โ€” In the Alpha architecture, floating-point traps are imprecise ๐Ÿ˜ตโ€๐Ÿ’ซ. That means without software assistance it's impossible to recover from a floating trap, and program execution normally has to be terminated. GCC can generate code that helps operating system trap handlers figure out the exact location that caused a floating-point trap ๐Ÿ•ต๏ธโ€โ™€๏ธ. Depending on what your application needs, you can select different levels of precision:

Okay bestie, the -mtrap-precision values are where we pick up ๐Ÿซถ

  • p ๐Ÿ’… Program precision. This one's the default, and it means a trap handler can only tell which program caused a floating-point exception.
  • f ๐ŸŽ€ Function precision. The trap handler can figure out which function caused a floating-point exception.
  • i ๐Ÿฆ‹ Instruction precision. The trap handler can pinpoint the exact instruction that caused a floating-point exception.

Other Alpha compilers have equivalent options called -scope_safe and -resumption_safe. iykyk ๐Ÿ’œ


  • -mieee-conformant โœจ marks the generated code as IEEE conformant. โš ๏ธ You must not use this unless you also specify -mtrap-precision=i and either -mfp-trap-mode=su or -mfp-trap-mode=sui. That's the whole rule, no cap. All it actually does is emit the line .eflag 48 in the function prologue of the generated assembly file.
  • -mbuild-constants ๐Ÿงš Normally GCC looks at a 32- or 64-bit integer constant and checks whether it can build it from smaller constants in two or three instructions. If it can't, it outputs the constant as a literal and generates code that loads it from the data segment at run time. With this option, GCC is forced to build every integer constant with code, even if that takes more instructions (the maximum is six). Main character energy, but you asked for it ๐Ÿ’…

You typically use this when building a shared library dynamic loader ๐ŸŒธ. It's a shared library itself, so it has to relocate itself in memory before it can find the variables and constants in its own data segment.

  • -mbwx, -mno-bwx, -mcix, -mno-cix, -mfix, -mno-fix, -mmax, -mno-max ๐Ÿ“ decide whether GCC is allowed to generate code using the optional BWX, CIX, FIX and MAX instruction sets. By default, it uses whatever instruction sets the CPU type from -mcpu= supports, or the CPU the compiler was built on if you don't set one.
  • -mfloat-vax, -mfloat-ieee ๐ŸŒˆ switch between generating code that uses VAX F and G floating-point arithmetic (-mfloat-vax) and code that doesn't use it, sticking with IEEE single and double precision (-mfloat-ieee).
  • -mexplicit-relocs, -mno-explicit-relocs ๐Ÿ”ฅ Okay, the history is kinda wild. Older Alpha assemblers had no way to generate symbol relocations except through assembler macros, and those macros don't allow optimal instruction scheduling. GNU binutils as of version 2.12 added a new syntax that lets the compiler explicitly mark which relocations apply to which instructions. This option is mostly useful for debugging, since GCC detects the assembler's capabilities when it's built and sets the default accordingly.
  • -msmall-data, -mlarge-data ๐Ÿ’œ When -mexplicit-relocs is in effect, static data is accessed through gp-relative relocations. With -msmall-data, objects 8 bytes long or smaller get placed in a small data area (the ".sdata" and ".sbss" sections) and accessed through 16-bit relocations off the $gp register. This caps the small data area at 64KB, but the variables can be accessed directly with a single instruction, which is so efficient ๐Ÿ˜ญ

The default is -mlarge-data. With this option, the data area is limited to just below 2GB. Programs needing more than 2GB of data have to use "malloc" or "mmap" to allocate it on the heap instead of in the program's data segment.

When generating code for shared libraries, -fpic implies -msmall-data, and -fPIC implies -mlarge-data.

  • -msmall-text, -mlarge-text ๐Ÿฆ‹ With -msmall-text, the compiler assumes the code for the entire program (or shared library) fits in 4MB, so it's reachable with a branch instruction. When -msmall-data is also used, the compiler can assume all local symbols share the same $gp value, which cuts the instructions needed for a function call from 4 down to 1. The default is -mlarge-text.
  • -mcpu=cpu_type ๐Ÿ‘‘ sets the instruction set and instruction scheduling parameters for the machine type cpu_type. You can pass either the EV style name or the matching chip number. GCC has scheduling parameters for the EV4, EV5 and EV6 families, and picks the default instruction set from the processor you name. If you don't name one, GCC defaults to the processor the compiler was built on.

Supported values for cpu_type are:

  • ev4, ev45, 21064: schedules as an EV4 and has no instruction set extensions.
  • ev5, 21164: schedules as an EV5 and has no instruction set extensions.
  • ev56, 21164a: schedules as an EV5 and supports the BWX extension.
  • pca56, 21164pc, 21164PC: schedules as an EV5 and supports the BWX and MAX extensions.
  • ev6, 21264: schedules as an EV6 and supports the BWX, FIX, and MAX extensions.
  • ev67, 21264a: schedules as an EV6 and supports the BWX, CIX, FIX, and MAX extensions.

Native toolchains also accept native, which picks the best architecture option for the host processor. -mcpu=native does nothing if GCC doesn't recognize the processor.

  • -mtune=cpu_type ๐Ÿง sets only the instruction scheduling parameters for cpu_type. The instruction set stays exactly the same.

Native toolchains also accept native, which picks the best architecture option for the host processor. -mtune=native does nothing if GCC doesn't recognize the processor.

  • -mmemory-latency=time โฑ๏ธ sets the latency the scheduler should assume for typical memory references, as the application sees them. This number depends a lot on the application's memory access patterns and on the size of the external cache on the machine.

Valid values for time are:

  • number: a decimal number of clock cycles.
  • L1, L2, L3, main: GCC has estimates of clock cycles for "typical" EV4 & EV5 hardware at the Level 1, 2 and 3 caches (also called Dcache, Scache, and Bcache), plus main memory. Heads up: L3 is only valid for EV5.

๐Ÿงš FR30 Options

These options are defined specifically for the FR30 port.

  • -msmall-model ๐ŸŒธ uses the small address space model. This can produce smaller code, but it does assume that all symbolic values and addresses fit into a 20-bit range.
  • -mno-lsim ๐ŸŽ€ assumes runtime support has already been provided, so there's no need to include the simulator library (libsim.a) on the linker command line.

๐ŸŒˆ FT32 Options

These options are defined specifically for the FT32 port.

  • -msim ๐Ÿค– says the program will run on the simulator. This links in an alternate runtime startup and library. โš ๏ธ Do not use this option when generating programs for real hardware. You have to provide your own runtime library for whatever I/O functions you need.
  • -mlra ๐Ÿงช enables Local Register Allocation. It's still experimental for FT32, so by default the compiler uses standard reload.
  • -mnodiv ๐Ÿšซ stops the compiler from using div and mod instructions.
  • -mft32b ๐Ÿฆ‹ enables the extended instructions of the FT32B processor.
  • -mcompress ๐Ÿ—œ๏ธ compresses all code using the Ft32B code compression scheme.
  • -mnopm ๐Ÿ™… stops the compiler from generating code that reads program memory.

๐Ÿ’– FRV Options

  • -mgpr-32 only uses the first 32 general-purpose registers.
  • -mgpr-64 uses all 64 general-purpose registers.
  • -mfpr-32 only uses the first 32 floating-point registers.
  • -mfpr-64 uses all 64 floating-point registers.
  • -mhard-float uses hardware instructions for floating-point operations.
  • -msoft-float uses library routines for floating-point operations.
  • -malloc-cc dynamically allocates condition code registers.
  • -mfixed-cc does not try to dynamically allocate condition code registers. It only uses "icc0" and "fcc0". ๐Ÿซ 
  • -mdword changes the ABI to use double word insns.
  • -mno-dword doesn't use double word instructions.
  • -mdouble uses floating-point double instructions.
  • -mno-double doesn't use floating-point double instructions.
  • -mmedia uses media instructions.
  • -mno-media doesn't use media instructions.
  • -mmuladd uses multiply and add/subtract instructions.
  • -mno-muladd doesn't use multiply and add/subtract instructions.
  • -mfdpic ๐ŸŒท selects the FDPIC ABI, which uses function descriptors to represent pointers to functions. Without any PIC/PIE-related options, it implies -fPIE. With -fpic or -fpie, it assumes GOT entries and small data are within a 12-bit range from the GOT base address. With -fPIC or -fPIE, GOT offsets are computed with 32 bits. With a bfin-elf target, this option implies -msim.
  • -minline-plt ๐Ÿงต enables inlining of PLT entries in function calls to functions that aren't known to bind locally. It has no effect without -mfdpic. It's enabled by default when optimizing for speed and compiling shared libraries (i.e., -fPIC or -fpic), or when an optimization option such as -O3 or above is on the command line.
  • -mTLS ๐Ÿ“ฆ assumes a large TLS segment when generating thread-local code.
  • -mtls ๐Ÿชถ does not assume a large TLS segment when generating thread-local code.
  • -mgprel-ro ๐ŸŒ™ enables the use of "GPREL" relocations in the FDPIC ABI for data known to be in read-only sections. It's enabled by default, except for -fpic or -fpie. Even though it may help make the global offset table smaller, it trades 1 instruction for 4 there. With -fPIC or -fPIE, it trades 3 instructions for 4, one of which may be shared by multiple symbols, and it avoids needing a GOT entry for the referenced symbol, so it's more likely to be a win. If it isn't, -mno-gprel-ro can turn it off.
  • -multilib-library-pic ๐Ÿ“š links with the (library, not FD) pic libraries. It's implied by -mlibrary-pic, and by -fPIC and -fpic without -mfdpic. You should never have to use it explicitly.
  • -mlinked-fp ๐Ÿ–ผ๏ธ follows the EABI requirement of always creating a frame pointer whenever a stack frame is allocated. This option is enabled by default and can be disabled with -mno-linked-fp.
  • -mlong-calls โ€” okay so this one uses indirect addressing to call functions sitting outside the current compilation unit ๐Ÿฆ‹. The functions can be placed anywhere within the 32-bit address space โœจ.
  • -malign-labels โ€” this tries to align labels to an 8-byte boundary by slipping NOPs into the previous packet ๐Ÿซถ. It only has an effect when VLIW packing is enabled, and it never creates new packets. It just adds NOPs to packets that already exist ๐Ÿ’….
  • -mlibrary-pic โ€” generates position-independent EABI code ๐ŸŒธ.
  • -macc-4 โ€” uses only the first four media accumulator registers ๐ŸŽ€.
  • -macc-8 โ€” uses all eight media accumulator registers ๐Ÿ‘‘.
  • -mpack โ€” packs VLIW instructions ๐Ÿงš.
  • -mno-pack โ€” does not pack VLIW instructions ๐Ÿ™ˆ.
  • -mno-eflags โ€” does not mark ABI switches in e_flags ๐Ÿ’€.
  • -mcond-move โ€” enables conditional-move instructions, and this is the default ๐Ÿ’–. Mainly for debugging the compiler, and it'll likely be removed in a future version.
  • -mno-cond-move โ€” disables conditional-move instructions ๐Ÿ™…โ€โ™€๏ธ. Mainly for debugging the compiler, and it'll likely be removed in a future version.
  • -mscc โ€” enables conditional set instructions, and this is the default โœจ. Mainly for debugging the compiler, and it'll likely be removed in a future version.
  • -mno-scc โ€” disables conditional set instructions ๐Ÿฅ€. Mainly for debugging the compiler, and it'll likely be removed in a future version.
  • -mcond-exec โ€” enables conditional execution, and this is the default ๐Ÿฆ„. Mainly for debugging the compiler, and it'll likely be removed in a future version.
  • -mno-cond-exec โ€” disables conditional execution ๐Ÿšซ. Mainly for debugging the compiler, and it'll likely be removed in a future version.
  • -mvliw-branch โ€” runs a pass that packs branches into VLIW instructions, and this is the default ๐ŸŒˆ. Mainly for debugging the compiler, and it'll likely be removed in a future version.
  • -mno-vliw-branch โ€” does not run the pass that packs branches into VLIW instructions ๐Ÿซ . Mainly for debugging the compiler, and it'll likely be removed in a future version.
  • -mmulti-cond-exec โ€” enables optimization of "&&" and "||" in conditional execution, and this is the default ๐Ÿ”ฅ. Mainly for debugging the compiler, and it'll likely be removed in a future version.
  • -mno-multi-cond-exec โ€” disables optimization of "&&" and "||" in conditional execution ๐Ÿ˜ค. Mainly for debugging the compiler, and it'll likely be removed in a future version.
  • -mnested-cond-exec โ€” enables nested conditional execution optimizations, and this is the default ๐Ÿ“. Mainly for debugging the compiler, and it'll likely be removed in a future version.
  • -mno-nested-cond-exec โ€” disables nested conditional execution optimizations ๐Ÿ™ƒ. Mainly for debugging the compiler, and it'll likely be removed in a future version.
  • -moptimize-membar โ€” removes redundant "membar" instructions from the compiler-generated code, and it's enabled by default ๐Ÿงน.
  • -mno-optimize-membar โ€” disables the automatic removal of redundant "membar" instructions from the generated code ๐Ÿ›‘.
  • -mtomcat-stats โ€” makes gas print out tomcat statistics ๐Ÿ“Š.
  • -mcpu=cpu โ€” picks the processor type to generate code for ๐Ÿ–ฅ๏ธ. The possible values are frv, fr550, tomcat, fr500, fr450, fr405, fr400, fr300 and simple ๐Ÿ’….

โœจ GNU/Linux Options โœจ

These -m options are defined for GNU/Linux targets ๐Ÿง:

  • -mglibc โ€” uses the GNU C library ๐Ÿ’œ. This is the default except on *-*-linux-*uclibc*, *-*-linux-*musl* and *-*-linux-*android* targets.
  • -muclibc โ€” uses the uClibc C library ๐ŸŒท. This is the default on *-*-linux-*uclibc* targets.
  • -mmusl โ€” uses the musl C library ๐ŸŽ‹. This is the default on *-*-linux-*musl* targets.
  • -mbionic โ€” uses the Bionic C library ๐Ÿค–. This is the default on *-*-linux-*android* targets.
  • -mandroid โ€” compiles code that's compatible with the Android platform ๐Ÿ“ฑ. This is the default on *-*-linux-*android* targets. When compiling, this option enables -mbionic, -fPIC, -fno-exceptions and -fno-rtti by default. When linking, it makes the GCC driver pass Android-specific options to the linker. It also causes the preprocessor macro "__ANDROID__" to be defined ๐Ÿซถ.
  • -tno-android-cc โ€” turns off the compilation effects of -mandroid, i.e., doesn't enable -mbionic, -fPIC, -fno-exceptions and -fno-rtti by default ๐Ÿ™…โ€โ™€๏ธ.
  • -tno-android-ld โ€” turns off the linking effects of -mandroid, i.e., passes standard Linux linking options to the linker ๐Ÿ”—.

โœจ H8/300 Options โœจ

These -m options are defined for the H8/300 implementations ๐Ÿฆ‹:

  • -mrelax โ€” shortens some address references at link time, when possible ๐Ÿช„. It uses the linker option -relax.
  • -mh โ€” generates code for the H8/300H ๐ŸŒธ.
  • -ms โ€” generates code for the H8S ๐Ÿ’Ž.
  • -mn โ€” generates code for the H8S and H8/300H in the normal mode ๐Ÿฐ. This switch must be used either with -mh or -ms.
  • -ms2600 โ€” generates code for the H8S/2600 ๐ŸŽ€. This switch must be used with -ms.
  • -mexr โ€” extended registers get stored on the stack before a function with the monitor attribute runs ๐Ÿ“š. The default option is -mexr. This option is only valid for H8S targets.
  • -mno-exr โ€” extended registers do not get stored on the stack before a function with the monitor attribute runs ๐Ÿ™ˆ. The default option is -mno-exr. This option is only valid for H8S targets.
  • -mint32 โ€” makes "int" data 32 bits by default ๐Ÿ”ข.
  • -malign-300 โ€” on the H8/300H and H8S, uses the same alignment rules as the H8/300 ๐Ÿ“. The default for the H8/300H and H8S is to align longs and floats on 4-byte boundaries, but -malign-300 makes them align on 2-byte boundaries instead. This option has no effect on the H8/300 ๐Ÿซ .

โœจ HPPA Options โœจ

These -m options are defined for the HPPA family of computers ๐Ÿ–จ๏ธ:

  • -march=architecture-type โ€” generates code for the specified architecture ๐Ÿ—๏ธ. The choices for architecture-type are 1.0 for PA 1.0, 1.1 for PA 1.1, and 2.0 for PA 2.0 processors. Refer to /usr/lib/sched.models on an HP-UX system to figure out the proper architecture option for your machine ๐Ÿง. Code compiled for lower numbered architectures runs on higher numbered architectures, but not the other way around ๐Ÿšซ.
  • -mpa-risc-1-0 โ€” a synonym for -march=1.0 ๐Ÿ”.
  • -mpa-risc-1-1 โ€” a synonym for -march=1.1 ๐Ÿ”.
  • -mpa-risc-2-0 โ€” a synonym for -march=2.0 ๐Ÿ”.
  • -mcaller-copies โ€” the caller copies function arguments that get passed by hidden reference ๐Ÿงณ. This option should be used with care, because it isn't compatible with the default 32-bit runtime ๐Ÿ˜ฌ. That said, only aggregates larger than eight bytes are passed by hidden reference, and this option gives better compatibility with OpenMP ๐Ÿซถ.
  • -mjump-in-delay โ€” this option is ignored and only exists for compatibility purposes ๐Ÿ™ƒ.
  • -mdisable-fpregs โ€” stops floating-point registers from being used in any manner ๐Ÿšท. This is necessary for compiling kernels that do lazy context switching of floating-point registers ๐Ÿง . If you use this option and then try to do floating-point operations, the compiler aborts ๐Ÿ’€.
  • -mdisable-indexing โ€” stops the compiler from using indexing address modes ๐Ÿ™…โ€โ™€๏ธ. This avoids some rather obscure problems when compiling MIG generated code under MACH ๐Ÿ•ต๏ธโ€โ™€๏ธ.
  • -mno-space-regs โ€” generates code that assumes the target has no space registers ๐ŸŒŠ. This lets GCC generate faster indirect calls and use unscaled index address modes โšก. Such code is suitable for level 0 PA systems and kernels ๐Ÿงš.
  • -mfast-indirect-calls โ€” generates code that assumes calls never cross space boundaries ๐Ÿƒโ€โ™€๏ธ. This lets GCC emit code that performs faster indirect calls. This option does not work in the presence of shared libraries or nested functions ๐Ÿ˜ญ.
  • -mfixed-range=register-range โ€” generates code that treats the given register range as fixed registers ๐Ÿ“Œ. A fixed register is one the register allocator can't use. This is super useful when compiling kernel code ๐Ÿง‘โ€๐Ÿ’ป. A register range is specified as two registers separated by a dash, and multiple register ranges can be specified separated by a comma ๐ŸŽ€.
  • -mlong-load-store โ€” generates 3-instruction load and store sequences, which are sometimes required by the HP-UX 10 linker ๐Ÿ”ง. This is equivalent to the +k option to the HP compilers ๐Ÿ’….
  • -mportable-runtime โ€” uses the portable calling conventions HP proposed for ELF systems ๐Ÿงณ.
  • -mgas โ€” enables the use of assembler directives that only GAS understands ๐Ÿง .
  • -mschedule=cpu-type โ€” schedules code according to the constraints for the machine type cpu-type ๐Ÿ—“๏ธ. The choices for cpu-type are 700 7100, 7100LC, 7200, 7300 and 8000. Refer to /usr/lib/sched.models on an HP-UX system to determine the proper scheduling option for your machine ๐Ÿ”. The default scheduling is 8000 โœจ.
  • -mlinker-opt โ€” enables the optimization pass in the HP-UX linker ๐Ÿ› ๏ธ. Heads up, this makes symbolic debugging impossible ๐Ÿ™ˆ. It also triggers a bug in the HP-UX 8 and HP-UX 9 linkers, where they give bogus error messages when linking some programs ๐Ÿ’€.
  • -msoft-float โ€” generates output that contains library calls for floating point ๐Ÿงฎ.
Warning: the requisite libraries are not available for all HPPA targets ๐Ÿšจ. Normally the facilities of the machine's usual C compiler are used, but this can't be done directly in cross-compilation. You must make your own arrangements to provide suitable library functions for cross-compilation ๐Ÿซ .

-msoft-float changes the calling convention in the output file, so it's only useful if you compile all of a program with this option ๐Ÿงฉ. In particular, you need to compile libgcc.a, the library that comes with GCC, with -msoft-float in order for this to work ๐Ÿซถ.

  • -msio โ€” generates the predefine "_SIO" for server IO ๐Ÿ–ง. The default is -mwsio. That one generates the predefines "__hp9000s700", "__hp9000s700__" and "_WSIO" for workstation IO ๐Ÿ–ฅ๏ธ. These options are available under HP-UX and HI-UX ๐ŸŒˆ.
  • -mgnu-ld โ€” okay, this one tells GCC to use the GNU ld options ๐Ÿ”—. It passes -shared to ld when you're building a shared library, and it's the default if GCC was configured with the GNU linker, explicitly or implicitly. It only changes which parameters get passed, not which ld gets called. That's decided by the --with-ld configure option, GCC's program search path, and then your PATH. To see the linker GCC is using, run which `gcc -print-prog-name=ld` ๐Ÿงš. Only available on the 64-bit HP-UX GCC (hppa*64*-*-hpux*) ๐Ÿ’œ.
  • -mhp-ld โ€” same vibe, but for the HP linker ๐Ÿ’…. It passes -b to ld when building a shared library and passes +Accept TypeMismatch to ld on all links. It's the default if GCC was configured with the HP linker, explicitly or implicitly. Like -mgnu-ld, it doesn't change which ld is called, just the parameters sent to it. The ld is picked by --with-ld, GCC's program search path, and then PATH. Check the linker with which `gcc -print-prog-name=ld` โœจ. Only available on the 64-bit HP-UX GCC (hppa*64*-*-hpux*) ๐ŸŒธ.
  • -mlong-calls โ€” generates long call sequences ๐Ÿฆ‹. This makes sure a call can always reach linker-generated stubs. By default, long calls only kick in when the distance from the call site to the start of the function or translation unit (depending on the case) goes over a limit set by the branch type. Those limits are 7,600,000 bytes for normal calls on PA 2.0 and 240,000 bytes on PA 1.X. Sibcalls are always capped at 240,000 bytes ๐Ÿ’–.

Distances are measured from the start of functions when you use -ffunction-sections, or when you use -mgas and -mno-portable-runtime together under HP-UX with the SOM linker.

Heads up: this usually isn't what you want, because it degrades performance ๐Ÿ˜ญ. It might still be useful in big applications, especially when partial linking is used to build the app.

The kind of long calls used depends on what the assembler and linker can do, plus the type of code being generated. The hit on systems that support long absolute calls, and long PIC symbol-difference or pc-relative calls, should be pretty small. An indirect call is used on 32-bit ELF systems in PIC code, though, and it's quite long ๐Ÿ™ˆ.

  • -munix=unix-std โ€” generates compiler predefines and picks a startfile for the UNIX standard you specify ๐Ÿ‘‘. The choices are 93, 95, and 98. 93 works on all HP-UX versions. 95 is available on HP-UX 10.10 and later. 98 is available on HP-UX 11.11 and later. The defaults are 93 for HP-UX 10.00, 95 for HP-UX 10.10 through 11.00, and 98 for HP-UX 11.11 and later ๐ŸŽ€.

-munix=93 gives the same predefines as GCC 3.3 and 3.4. -munix=95 adds predefines for "XOPEN_UNIX" and "_XOPEN_SOURCE_EXTENDED", plus the startfile unix95.o. -munix=98 adds predefines for "_XOPEN_UNIX", "_XOPEN_SOURCE_EXTENDED", "_INCLUDE__STDC_A1_SOURCE" and "_INCLUDE_XOPEN_SOURCE_500", plus the startfile unix98.o ๐Ÿ“.

Warning, bestie ๐Ÿšจ: this option changes the interfaces of various library routines and also affects how the C library behaves at runtime. Be extremely careful using it ๐Ÿ˜ฌ.

Library code meant to work with more than one UNIX standard has to test, set, and restore the variable "__xpg4_extended_mask" as needed. Most GNU software doesn't offer this capability ๐Ÿฅบ.

  • -nolibdld โ€” stops GCC from adding link options that search libdld.sl when -static is used on HP-UX 10 and later ๐Ÿ›‘.
  • -static โ€” okay, so the HP-UX version of setlocale in libc depends on libdld.sl, and there's no archive version of it ๐Ÿ’€. That means when you use -static, you need special link options to resolve the dependency โœจ.

On HP-UX 10 and later, the GCC driver adds those options to link with libdld.sl when -static is specified. This makes the resulting binary dynamic, which is kind of ironic ๐Ÿ™ƒ. On the 64-bit port, the linkers make dynamic binaries by default anyway. If you don't want the driver adding these link options, use -nolibdld ๐Ÿฆ‹.

  • -threads โ€” adds multithreading support with the dce thread library under HP-UX ๐Ÿงต. It sets flags for both the preprocessor and the linker ๐Ÿ’œ.

โœจ IA-64 Options โœจ

These are the -m options defined for the Intel IA-64 architecture ๐ŸŒˆ.

  • -mbig-endian โ€” generates code for a big-endian target. This is the default for HP-UX ๐Ÿ“.
  • -mlittle-endian โ€” generates code for a little-endian target. This is the default for AIX5 and GNU/Linux ๐ŸŒธ.
  • -mgnu-as / -mno-gnu-as โ€” generates (or doesn't) code for the GNU assembler. The default is -mgnu-as ๐Ÿ’–.
  • -mgnu-ld / -mno-gnu-ld โ€” generates (or doesn't) code for the GNU linker. The default is -mgnu-ld โœจ.
  • -mno-pic โ€” generates code that doesn't use a global pointer register ๐Ÿ™…. The result isn't position independent code, and it violates the IA-64 ABI ๐Ÿ’€.
  • -mvolatile-asm-stop / -mno-volatile-asm-stop โ€” generates (or doesn't) a stop bit immediately before and after volatile asm statements ๐Ÿ”ฅ.
  • -mregister-names / -mno-register-names โ€” generates (or doesn't) in, loc, and out register names for the stacked registers. This may make assembler output more readable ๐Ÿ‘‘.
  • -mno-sdata / -msdata โ€” disables (or enables) optimizations that use the small data section ๐Ÿงš. This may be useful for working around optimizer bugs ๐Ÿ™ˆ.
  • -mconstant-gp โ€” generates code that uses a single constant global pointer value. This is useful when compiling kernel code ๐Ÿซถ.
  • -mauto-pic โ€” generates code that is self-relocatable. This implies -mconstant-gp. It's useful when compiling firmware code ๐Ÿฆ‹.
  • -minline-float-divide-min-latency โ€” generates code for inline divides of floating-point values using the minimum latency algorithm โญ.
  • -minline-float-divide-max-throughput โ€” generates code for inline divides of floating-point values using the maximum throughput algorithm ๐ŸŒˆ.
  • -mno-inline-float-divide โ€” doesn't generate inline code for divides of floating-point values ๐Ÿ™….
  • -minline-int-divide-min-latency โ€” generates code for inline divides of integer values using the minimum latency algorithm ๐Ÿ’œ.
  • -minline-int-divide-max-throughput โ€” generates code for inline divides of integer values using the maximum throughput algorithm ๐ŸŽ€.
  • -mno-inline-int-divide โ€” doesn't generate inline code for divides of integer values ๐Ÿฅบ.
  • -minline-sqrt-min-latency โ€” generates code for inline square roots using the minimum latency algorithm ๐ŸŒธ.
  • -minline-sqrt-max-throughput โ€” generates code for inline square roots using the maximum throughput algorithm ๐Ÿ“.
  • -mno-inline-sqrt โ€” doesn't generate inline code for "sqrt" ๐Ÿ™ƒ.
  • -mfused-madd / -mno-fused-madd โ€” does (or doesn't) generate code that uses the fused multiply/add or multiply/subtract instructions. The default is to use these instructions โœจ.
  • -mno-dwarf2-asm / -mdwarf2-asm โ€” doesn't (or does) generate assembler code for the DWARF line number debugging info. This may be useful when you're not using the GNU assembler ๐Ÿ”ง.
  • -mearly-stop-bits / -mno-early-stop-bits โ€” allows stop bits to be placed earlier than immediately preceding the instruction that triggered the stop bit. This can improve instruction scheduling, but it doesn't always do so ๐Ÿฆ‹.
  • -mfixed-range=register-range โ€” generates code treating the given register range as fixed registers ๐Ÿ”’. A fixed register is one the register allocator can't use. This is useful when compiling kernel code ๐Ÿซถ. A register range is two registers separated by a dash, and you can specify multiple ranges separated by a comma ๐Ÿ’….
  • -mtls-size=tls-size โ€” specifies the bit size of immediate TLS offsets. Valid values are 14, 22, and 64 ๐Ÿ“.
  • -mtune=cpu-type โ€” tunes the instruction scheduling for a particular CPU. Valid values are itanium, itanium1, merced, itanium2, and mckinley ๐ŸŽ€.
  • -milp32 / -mlp64 โ€” generates code for a 32-bit or 64-bit environment. The 32-bit environment sets int, long, and pointer to 32 bits. The 64-bit environment sets int to 32 bits and long and pointer to 64 bits. These are HP-UX specific flags ๐Ÿ‘‘.
  • -mno-sched-br-data-spec / -msched-br-data-spec โ€” (dis/en)ables data speculative scheduling before reload. This results in generation of "ld.a" instructions and the corresponding check instructions ("ld.c" / "chk.a") ๐Ÿง . The default setting is disabled ๐Ÿ™ˆ.
  • -msched-ar-data-spec / -mno-sched-ar-data-spec โ€” (en/dis)ables data speculative scheduling after reload. This results in generation of "ld.a" instructions and the corresponding check instructions ("ld.c" / "chk.a") โญ. The default setting is enabled โœจ.
  • -mno-sched-control-spec / -msched-control-spec โ€” (dis/en)ables control speculative scheduling. This feature is only available during region scheduling (i.e. before reload) ๐ŸŒŠ. It results in generation of the "ld.s" instructions and the corresponding check instructions "chk.s" ๐Ÿ’œ. The default setting is disabled ๐Ÿ™….
  • -msched-br-in-data-spec / -mno-sched-br-in-data-spec โ€” (en/dis)ables speculative scheduling of instructions that depend on data speculative loads before reload ๐Ÿฆ‹. This is only effective with -msched-br-data-spec enabled. The default setting is enabled ๐ŸŒธ.
  • -msched-ar-in-data-spec / -mno-sched-ar-in-data-spec โ€” (en/dis)ables speculative scheduling of instructions that depend on data speculative loads after reload ๐Ÿ“. This is only effective with -msched-ar-data-spec enabled. The default setting is enabled ๐Ÿ’–.
  • -msched-in-control-spec / -mno-sched-in-control-spec โ€” (en/dis)ables speculative scheduling of instructions that depend on control speculative loads ๐Ÿซถ. This is only effective with -msched-control-spec enabled. The default setting is enabled ๐ŸŽ€.
  • -mno-sched-prefer-non-data-spec-insns, -msched-prefer-non-data-spec-insns โ€” okay so when this is turned on, data-speculative instructions only get picked for scheduling if there are literally no other choices ๐Ÿ’… It makes data speculation way more conservative ๐Ÿซถ The default is disabled ๐ŸŒธ
  • -mno-sched-prefer-non-control-spec-insns, -msched-prefer-non-control-spec-insns โ€” same energy, but for control-speculative instructions โœจ When this is enabled they only get scheduled if nothing else is available, which makes control speculation super cautious ๐Ÿฆ‹ Default is disabled ๐Ÿ’œ
  • -mno-sched-count-spec-in-critical-path, -msched-count-spec-in-critical-path โ€” when enabled, speculative dependencies get counted while the scheduler figures out instruction priorities ๐Ÿงš That makes speculation a bit more conservative too ๐ŸŽ€ The default is disabled ๐ŸŒˆ
  • -msched-spec-ldc โ€” uses a simple data speculation check ๐Ÿ’– This one is on by default, so you get it without asking ๐Ÿ‘‘
  • -msched-control-spec-ldc โ€” uses a simple check for control speculation ๐Ÿซถ Also on by default ๐ŸŒธ
  • -msched-stop-bits-after-every-cycle โ€” places a stop bit after every cycle while scheduling โญ On by default, no notes ๐Ÿ’…
  • -msched-fp-mem-deps-zero-cost โ€” assumes floating-point stores and loads won't likely cause a conflict when they land in the same instruction group ๐Ÿฆ‹ This one is disabled by default, so you have to opt in ๐Ÿ™ˆ
  • -msel-sched-dont-check-control-spec โ€” this one is kind of backwards in name vibes ๐Ÿ˜ญ It generates checks for control speculation in selective scheduling, and it's disabled by default ๐Ÿ”ฅ
  • -msched-max-memory-insns=max-insns โ€” puts a limit on how many memory insns go into one instruction group ๐Ÿ“ Memory insns that try to schedule after the limit get lower priority, which is frequently useful for avoiding cache bank conflicts ๐Ÿ’œ The default value is 1 โœจ
  • -msched-max-memory-insns-hard-limit โ€” turns the -msched-max-memory-insns limit into a hard limit, so no more than that number is allowed in one instruction group ๐Ÿ’€ Without it, the limit is "soft": non-memory operations get preferred once the limit is hit, but memory operations can still sneak in ๐Ÿฅน

๐ŸŒˆ LM32 Options ๐ŸŒˆ

These -m options are defined for the LatticeMico32 architecture ๐Ÿงš

  • -mbarrel-shift-enabled โ€” enables barrel-shift instructions ๐ŸŒธ
  • -mdivide-enabled โ€” enables divide and modulus instructions ๐Ÿ’–
  • -mmultiply-enabled โ€” enables multiply instructions โœจ
  • -msign-extend-enabled โ€” enables sign extend instructions ๐ŸŽ€
  • -muser-enabled โ€” enables user-defined instructions ๐Ÿ‘‘

๐Ÿ’… M32C Options ๐Ÿ’…

  • -mcpu=name โ€” picks the CPU you want code generated for ๐Ÿฆ‹ The name can be r8c for the R8C/Tiny series, m16c for the M16C (up to /60) series, m32cm for the M16C/80 series, or m32c for the M32C/80 series ๐Ÿซถ
  • -msim โ€” tells the compiler the program will run on the simulator ๐Ÿงš This links in an alternate runtime library that supports things like file I/O ๐Ÿ’œ Do not use this when making programs for real hardware ๐Ÿ˜ญ You'd need to supply your own runtime library for whatever I/O functions you need ๐Ÿ”ฅ
  • -memregs=number โ€” sets how many memory-based pseudo-registers GCC uses during code generation ๐ŸŒˆ These act like real registers, so it's a tradeoff between fitting code into the available registers and the performance hit of using memory instead ๐Ÿ“ Every module in a program has to be compiled with the same value for this option ๐Ÿ™ˆ Because of that, don't use this option with GCC's default runtime libraries โš ๏ธ

๐Ÿฆ‹ M32R/D Options ๐Ÿฆ‹

These -m options are defined for Renesas M32R/D architectures ๐ŸŒธ

  • -m32r2 โ€” generates code for the M32R/2 ๐Ÿ’–
  • -m32rx โ€” generates code for the M32R/X โœจ
  • -m32r โ€” generates code for the M32R ๐ŸŽ€ This is the default ๐Ÿ‘‘
  • -mmodel=small โ€” assumes all objects live in the lower 16MB of memory, so their addresses can be loaded with the ld24 instruction ๐Ÿงš It also assumes all subroutines are reachable with the bl instruction ๐Ÿซถ This is the default ๐Ÿ’…

The addressability of a particular object can be set with the "model" attribute ๐ŸŒธ

  • -mmodel=medium โ€” assumes objects may be anywhere in the 32-bit address space, so the compiler generates seth/add3 instructions to load their addresses ๐Ÿฆ‹ It still assumes all subroutines are reachable with the bl instruction ๐Ÿ’œ
  • -mmodel=large โ€” assumes objects may be anywhere in the 32-bit address space, using seth/add3 instructions to load their addresses ๐ŸŒˆ This time subroutines may not be reachable with the bl instruction, so the compiler generates the much slower seth/add3/jl instruction sequence ๐Ÿ˜ญ
  • -msdata=none โ€” disables use of the small data area ๐Ÿ™ˆ Variables get put into one of .data, .bss, or .rodata (unless the "section" attribute has been specified) ๐Ÿ“ This is the default ๐Ÿ’…

The small data area consists of the sections .sdata and .sbss โœจ Objects can be explicitly put in the small data area with the "section" attribute using one of these sections ๐ŸŽ€

  • -msdata=sdata โ€” puts small global and static data in the small data area, but doesn't generate special code to reference them ๐Ÿฆ‹
  • -msdata=use โ€” puts small global and static data in the small data area and generates special instructions to reference them ๐Ÿ”ฅ
  • -G num โ€” puts global and static objects less than or equal to num bytes into the small data or BSS sections instead of the normal data or BSS sections ๐Ÿงš The default value of num is 8 ๐Ÿ’– The -msdata option has to be set to either sdata or use for this option to do anything ๐ŸŒธ

All modules should be compiled with the same -G num value ๐Ÿซถ Compiling with different values of num may or may not work ๐Ÿคทโ€โ™€๏ธ If it doesn't, the linker gives an error message, so incorrect code is not generated ๐Ÿ›ก๏ธ

  • -mdebug โ€” makes the M32R-specific code in the compiler display some statistics that might help you debug programs ๐Ÿ”
  • -malign-loops โ€” aligns all loops to a 32-byte boundary ๐ŸŒˆ
  • -mno-align-loops โ€” doesn't enforce a 32-byte alignment for loops ๐Ÿ’… This is the default ๐Ÿ™ˆ
  • -missue-rate=number โ€” issues number instructions per cycle ๐Ÿงš The number can only be 1 or 2 ๐Ÿซถ
  • -mbranch-cost=number โ€” number can only be 1 or 2 ๐Ÿฆ‹ If it's 1, branches are preferred over conditional code ๐Ÿ’œ If it's 2, the opposite applies โœจ
  • -mflush-trap=number โ€” specifies the trap number to use to flush the cache ๐ŸŽ€ The default is 12 ๐ŸŒธ Valid numbers are between 0 and 15 inclusive ๐Ÿ’–
  • -mno-flush-trap โ€” specifies that the cache can't be flushed by using a trap ๐Ÿ˜ญ
  • -mflush-func=name โ€” specifies the name of the operating system function to call to flush the cache ๐Ÿงš The default is _flush_cache, but a function call is only used if a trap isn't available ๐Ÿ’…
  • -mno-flush-func โ€” indicates there's no OS function for flushing the cache ๐Ÿ™ˆ

๐Ÿ‘‘ M680x0 Options ๐Ÿ‘‘

These are the -m options defined for M680x0 and ColdFire processors โœจ The default settings depend on which architecture was selected when the compiler was configured ๐ŸŒˆ The defaults for the most common choices are given below ๐Ÿซถ

  • -march=arch โ€” generates code for a specific M680x0 or ColdFire instruction set architecture ๐Ÿฆ‹ For M680x0 architectures, the permissible values of arch are: 68000, 68010, 68020, 68030, 68040, 68060 and cpu32 ๐Ÿ’– ColdFire architectures are selected according to Freescale's ISA classification, and the permissible values are: isaa, isaaplus, isab and isac ๐ŸŽ€

GCC defines a macro __mcfarch__ whenever it's generating code for a ColdFire target ๐Ÿงš The arch in this macro is one of the -march arguments given above ๐Ÿ’œ

When used together, -march and -mtune select code that runs on a family of similar processors, but that is optimized for a particular microarchitecture ๐ŸŒธ

  • -mcpu=cpu โ€” generates code for a specific M680x0 or ColdFire processor ๐Ÿ”ฅ The M680x0 cpus are: 68000, 68010, 68020, 68030, 68040, 68060, 68302, 68332 and cpu32 ๐Ÿ’… The ColdFire cpus are given in the table below, which also sorts the CPUs into families ๐Ÿงš
Family : -mcpu arguments
51 : 51 51ac 51ag 51cn 51em 51je 51jf 51jg 51jm 51mm 51qe 51qm
5206 : 5202 5204 5206
5206e : 5206e
5208 : 5207 5208
5211a : 5210a 5211a
5213 : 5211 5212 5213
5216 : 5214 5216
52235 : 52230 52231 52232 52233 52234 52235
5225 : 5224 5225
52259 : 52252 52254 52255 52256 52258 52259
5235 : 5232 5233 5234 5235 523x
5249 : 5249
5250 : 5250
5271 : 5270 5271
5272 : 5272
5275 : 5274 5275
5282 : 5280 5281 5282 528x
53017 : 53011 53012 53013 53014 53015 53016 53017
5307 : 5307
5329 : 5327 5328 5329 532x
5373 : 5372 5373 537x
5407 : 5407
5475 : 5470 5471 5472 5473 5474 5475 547x 5480 5481 5482 5483 5484
5485
-mcpu=cpu overrides -march=arch if arch is compatible with cpu. Other combinations of -mcpu and -march are rejected!

GCC defines the macro __mcf_cpu_cpu when a ColdFire target cpu is selected ๐ŸŒˆ It also defines __mcf_family_family, where the value of family is given by the table above ๐Ÿซถ

  • -mtune=tune โ€” tunes the code for a particular microarchitecture within the constraints set by -march and -mcpu ๐Ÿฆ‹ The M680x0 microarchitectures are: 68000, 68010, 68020, 68030, 68040, 68060 and cpu32 ๐Ÿ’œ The ColdFire microarchitectures are: cfv1, cfv2, cfv3, cfv4 and cfv4e โœจ

You can also use -mtune=68020-40 for code that needs to run relatively well on 68020, 68030 and 68040 targets ๐ŸŽ€ -mtune=68020-60 is similar, but it includes 68060 targets as well ๐Ÿงš These two options select the same tuning decisions as -m68020-40 and -m68020-60 respectively ๐Ÿ’…

GCC defines the macros __mcarch and __mcarch__ when tuning for 680x0 architecture arch ๐ŸŒธ It also defines mcarch unless either -ansi or a non-GNU -std option is used ๐Ÿ”ฅ If GCC is tuning for a range of architectures, as selected by -mtune=68020-40 or -mtune=68020-60, it defines the macros for every architecture in the range ๐Ÿ’–

GCC also defines the macro __muarch__ when tuning for ColdFire microarchitecture uarch, where uarch is one of the arguments given above ๐Ÿ‘‘

OKAY bestie, the M680x0 family is next and it's giving retro computer chaos ๐Ÿ•น๏ธ๐Ÿ’–

  • -m68000, -mc68000 โ€” ๐ŸŒธ Generates output for a 68000. This is the default when the compiler is configured for 68000-based systems, and it's the same as -march=68000. Use it for microcontrollers with a 68000 or EC000 core, like the 68008, 68302, 68306, 68307, 68322, 68328, and 68356. ๐Ÿ’…
  • -m68010 โ€” ๐Ÿฆ‹ Generates output for a 68010. This is the default when the compiler is configured for 68010-based systems. It's equivalent to -march=68010. โœจ
  • -m68020, -mc68020 โ€” ๐Ÿงš Generates output for a 68020. This is the default when the compiler is configured for 68020-based systems. It's equivalent to -march=68020. ๐Ÿ’œ
  • -m68030 โ€” ๐Ÿ“ Generates output for a 68030. This is the default when the compiler is configured for 68030-based systems. It's equivalent to -march=68030. ๐ŸŽ€
  • -m68040 โ€” ๐Ÿ”ฅ Generates output for a 68040. This is the default when the compiler is configured for 68040-based systems, and it's equivalent to -march=68040. This one inhibits the use of 68881/68882 instructions that have to be emulated in software on the 68040, so use it if your 68040 doesn't have code to emulate those instructions. ๐Ÿ™ˆ
  • -m68060 โ€” ๐Ÿ‘‘ Generates output for a 68060. This is the default when the compiler is configured for 68060-based systems, and it's equivalent to -march=68060. It inhibits the use of 68020 and 68881/68882 instructions that have to be emulated in software on the 68060, so only use it if your 68060 lacks code to emulate them. ๐Ÿ’€
  • -mcpu32 โ€” ๐ŸŒˆ Generates output for a CPU32. This is the default when the compiler is configured for CPU32-based systems, and it's the same as -march=cpu32. Use it for microcontrollers with a CPU32 or CPU32+ core, including the 68330, 68331, 68332, 68333, 68334, 68336, 68340, 68341, 68349, and 68360. ๐Ÿซถ
  • -m5200 โ€” ๐ŸŒธ Generates output for a 520X ColdFire CPU. This is the default when the compiler is configured for 520X-based systems. It's equivalent to -mcpu=5206, but it's now deprecated in favor of that option. Use it for microcontrollers with a 5200 core, like the MCF5202, MCF5203, MCF5204, and MCF5206. ๐Ÿ˜ญ
  • -m5206e โ€” ๐Ÿฆ‹ Generates output for a 5206e ColdFire CPU. This option is now deprecated in favor of the equivalent -mcpu=5206e. โญ
  • -m528x โ€” ๐Ÿงš Generates output for a member of the ColdFire 528X family. This option is now deprecated in favor of the equivalent -mcpu=528x. ๐Ÿ’…
  • -m5307 โ€” ๐Ÿ“ Generates output for a ColdFire 5307 CPU. This option is now deprecated in favor of the equivalent -mcpu=5307. โœจ
  • -m5407 โ€” ๐ŸŽ€ Generates output for a ColdFire 5407 CPU. This option is now deprecated in favor of the equivalent -mcpu=5407. ๐Ÿ’œ
  • -mcfv4e โ€” ๐Ÿ”ฅ Generates output for a ColdFire V4e family CPU (e.g. 547x/548x). This includes the use of hardware floating-point instructions. It's equivalent to -mcpu=547x, and it's now deprecated in favor of that option. ๐Ÿ‘‘
  • -m68020-40 โ€” ๐ŸŒˆ Generates output for a 68040, without using any of the new instructions. The result is code that can run relatively efficiently on a 68020/68881, a 68030, or a 68040. The generated code does use the 68881 instructions that are emulated on the 68040. It's equivalent to -march=68020 -mtune=68020-40. ๐Ÿซถ
  • -m68020-60 โ€” ๐ŸŒธ Generates output for a 68060, without using any of the new instructions. The result is code that can run relatively efficiently on a 68020/68881, a 68030, or a 68040. The generated code does use the 68881 instructions that are emulated on the 68060. It's equivalent to -march=68020 -mtune=68020-60. ๐Ÿ’–
  • -mhard-float, -m68881 โ€” ๐Ÿฆ‹ Generates floating-point instructions. This is the default for the 68020 and above, and for ColdFire devices that have an FPU. It defines the macro "__HAVE_68881__" on M680x0 targets and "__mcffpu__" on ColdFire targets. ๐Ÿ”ฅ
  • -msoft-float โ€” ๐Ÿ™ˆ Does not generate floating-point instructions. Library calls are used instead. This is the default for 68000, 68010, and 68832 targets, and it's also the default for ColdFire devices that have no FPU. ๐Ÿ“
  • -mdiv, -mno-div โ€” ๐Ÿงš Generates (or doesn't generate) ColdFire hardware divide and remainder instructions. If -march is used without -mcpu, the default is "on" for ColdFire architectures and "off" for M680x0 architectures. Otherwise, the default comes from the target CPU, which is either the default CPU or the one specified by -mcpu. For example, the default is "off" for -mcpu=5206 and "on" for -mcpu=5206e. GCC defines the macro "__mcfhwdiv__" when this option is enabled. โœจ
  • -mshort โ€” ๐Ÿ’œ Treats type "int" as 16 bits wide, just like "short int". Parameters passed on the stack are also aligned to a 16-bit boundary, even on targets that mandate promotion to 32-bit. ๐ŸŽ€
  • -mno-short โ€” ๐Ÿ‘‘ Does not treat type "int" as 16 bits wide. This is the default. ๐ŸŒˆ
  • -mnobitfield, -mno-bitfield โ€” ๐Ÿ’… Doesn't use the bit-field instructions. The -m68000, -mcpu32, and -m5200 options imply -mnobitfield. ๐Ÿ˜ญ
  • -mbitfield โ€” ๐Ÿซถ Does use the bit-field instructions. The -m68020 option implies -mbitfield, and this is the default if you use a configuration designed for a 68020. ๐ŸŒธ
  • -mrtd โ€” ๐Ÿ’€ Uses a different function-calling convention, where functions that take a fixed number of arguments return with the "rtd" instruction. That instruction pops their arguments while returning, which saves one instruction in the caller since there's no need to pop the arguments there.

This calling convention is incompatible with the one normally used on Unix, so you can't use it if you need to call libraries compiled with the Unix compiler. You also must provide function prototypes for all functions that take variable numbers of arguments (including printf), or incorrect code gets generated for calls to those functions. And seriously incorrect code results if you call a function with too many arguments. (Normally, extra arguments are harmlessly ignored, so this one is a big deal!) ๐Ÿ™ˆ

The "rtd" instruction is supported by the 68010, 68020, 68030, 68040, 68060, and CPU32 processors, but not by the 68000 or 5200. The default is -mno-rtd. ๐Ÿ”ฅ

  • -malign-int, -mno-align-int โ€” ๐Ÿฆ‹ Controls whether GCC aligns "int", "long", "long long", "float", "double", and "long double" variables on a 32-bit boundary (-malign-int) or a 16-bit boundary (-mno-align-int). Aligning on 32-bit boundaries makes code run somewhat faster on processors with 32-bit busses, but it costs more memory. ๐Ÿงš
โš ๏ธ Warning: if you use the -malign-int switch, GCC aligns structures containing the above types differently than most published application binary interface specifications for the m68k. ๐Ÿ’€
  • -mpcrel โ€” ๐ŸŒˆ Uses the pc-relative addressing mode of the 68000 directly, instead of using a global offset table. Right now this option implies -fpic, which allows at most a 16-bit offset for pc-relative addressing. -fPIC isn't presently supported with -mpcrel, though it could be supported for the 68020 and higher processors. ๐Ÿซถ
  • -mno-strict-align, -mstrict-align โ€” ๐Ÿ“ Does not (or does) assume that unaligned memory references are handled by the system. ๐Ÿ’–
  • -msep-data โ€” ๐ŸŽ€ Generates code that lets the data segment live in a different area of memory from the text segment. This allows for execute-in-place in an environment without virtual memory management. This option implies -fPIC. โœจ
  • -mno-sep-data โ€” ๐Ÿ’œ Generates code that assumes the data segment follows the text segment. This is the default. ๐ŸŒธ
  • -mid-shared-library โ€” ๐Ÿฆ‹ Generates code that supports shared libraries via the library ID method. This allows for execute-in-place and shared libraries in an environment without virtual memory management. This option implies -fPIC. ๐Ÿงš
  • -mno-id-shared-library โ€” ๐Ÿ™ˆ Generates code that doesn't assume ID-based shared libraries are being used. This is the default. ๐Ÿ‘‘
  • -mshared-library-id=n โ€” ๐Ÿ”ฅ Specifies the identification number of the ID-based shared library being compiled. Specifying a value of 0 generates more compact code. Specifying other values forces the allocation of that number to the current library, but it's no more space- or time-efficient than leaving this option out. ๐Ÿ’…
  • -mxgot, -mno-xgot โ€” ๐Ÿ˜ญ When generating position-independent code for ColdFire, this generates code that works if the GOT has more than 8192 entries. That code is larger and slower than code generated without this option. On M680x0 processors this option isn't needed, since -fPIC is enough. ๐ŸŒˆ

GCC normally uses a single instruction to load values from the GOT. That's pretty efficient, but it only works if the GOT is smaller than about 64k. Anything larger makes the linker report an error like this:

relocation truncated to fit: R_68K_GOT16O foobar

If that happens, recompile your code with -mxgot, and it should work with very large GOTs. Just know that code generated with -mxgot is less efficient, since it takes 4 instructions to fetch the value of a global symbol. ๐Ÿซถ

Some linkers, including newer versions of the GNU linker, can create multiple GOTs and sort GOT entries. If you have one of those, you should only need -mxgot when compiling a single object file that accesses more than 8192 GOT entries. Very few do. ๐ŸŽ€

These options have no effect unless GCC is generating position-independent code. ๐Ÿ“

  • -mlong-jump-table-offsets โ€” ๐Ÿงš Uses 32-bit offsets in "switch" tables. The default is to use 16-bit offsets. ๐Ÿ’œ

๐ŸŒˆ MCore Options ๐ŸŒˆ

These are the -m options defined for the Motorola M*Core processors. ๐Ÿซถ

  • -mhardlit, -mno-hardlit โ€” ๐Ÿ”ฅ Inlines constants into the code stream if it can be done in two instructions or less. ๐Ÿ’–
  • -mdiv, -mno-div โ€” ๐Ÿฆ‹ Uses the divide instruction. (Enabled by default.) โœจ
  • -mrelax-immediate, -mno-relax-immediate โ€” ๐ŸŒธ Allows arbitrary-sized immediates in bit operations. ๐Ÿงš
  • -mwide-bitfields, -mno-wide-bitfields โ€” ๐Ÿ’… Always treats bit-fields as "int"-sized. ๐Ÿ‘‘
  • -m4byte-functions, -mno-4byte-functions โ€” ๐ŸŽ€ Forces all functions to be aligned to a 4-byte boundary. ๐Ÿ™ˆ
  • -mcallgraph-data, -mno-callgraph-data โ€” ๐Ÿ’œ Emits callgraph information. ๐Ÿ“
  • -mslow-bytes, -mno-slow-bytes โ€” ๐Ÿ˜ญ Prefers word access when reading byte quantities. ๐ŸŒˆ

โœจ Machine-Dependent Options (continued) โœจ

  • -mlittle-endian, -mbig-endian โ€” generate code for a little-endian target ๐ŸŒธ
  • -m210, -m340 โ€” generate code for the 210 processor ๐Ÿ’–
  • -mno-lsim โ€” okay so this one assumes runtime support is already handled, so the simulator library (libsim.a) gets left off the linker command line ๐Ÿงš
  • -mstack-increment=size โ€” sets the max amount for a single stack increment operation ๐ŸŽ€ Big values can speed things up for programs with functions that need a huge chunk of stack, but they can also cause a segmentation fault if the stack gets extended too much ๐Ÿ˜ญ The default is 0x1000 ๐Ÿ’…

๐Ÿฆ‹ MeP Options ๐Ÿฆ‹

  • -mabsdiff โ€” enables the abs instruction, which gives you the absolute difference between two registers โœจ
  • -mall-opts โ€” enables ALL the optional instructions ๐Ÿ”ฅ: average, multiply, divide, bit operations, leading zero, absolute difference, min/max, clip, and saturation
  • -maverage โ€” enables the ave instruction, which computes the average of two registers ๐Ÿซถ
  • -mbased=n โ€” variables of size n bytes or smaller get placed in the ".based" section by default. Based variables use $tp as their base register, and the ".based" section has a 128-byte limit ๐Ÿ’€
  • -mbitops โ€” enables the bit operation instructions: bit test (btstm), set (bsetm), clear (bclrm), invert (bnotm), and test-and-set (tas) ๐Ÿ’œ
  • -mc=name โ€” picks which section constant data gets placed in. name can be tiny, near, or far ๐ŸŒˆ
  • -mclip โ€” enables the clip instruction. Heads up, bestie: -mclip isn't useful unless you also provide -mminmax โš ๏ธ
  • -mconfig=name โ€” selects one of the built-in core configurations ๐Ÿ‘‘ Each MeP chip has one or more modules, and each module has a core CPU plus a bunch of coprocessors, optional instructions, and peripherals. The "MeP-Integrator" tool (not part of GCC!) provides these configurations through this option. Using this option is the same as using all the matching command-line options. The default configuration is default.
  • -mcop โ€” enables the coprocessor instructions. By default this is a 32-bit coprocessor. The coprocessor is normally enabled through the -mconfig= option ๐Ÿฆ‹
  • -mcop32 โ€” enables the 32-bit coprocessor's instructions
  • -mcop64 โ€” enables the 64-bit coprocessor's instructions
  • -mivc2 โ€” enables IVC2 scheduling. IVC2 is a 64-bit VLIW coprocessor ๐Ÿ”ฅ
  • -mdc โ€” causes constant variables to get placed in the ".near" section
  • -mdiv โ€” enables the div and divu instructions
  • -meb โ€” generate big-endian code
  • -mel โ€” generate little-endian code
  • -mio-volatile โ€” tells the compiler that any variable marked with the io attribute is considered volatile ๐Ÿ™ˆ
  • -ml โ€” causes variables to be assigned to the ".far" section by default
  • -mleadz โ€” enables the leadz (leading zero) instruction
  • -mm โ€” causes variables to be assigned to the ".near" section by default
  • -mminmax โ€” enables the min and max instructions
  • -mmult โ€” enables the multiplication and multiply-accumulate instructions โœจ
  • -mno-opts โ€” disables all the optional instructions that -mall-opts enabled
  • -mrepeat โ€” enables the repeat and erepeat instructions, used for low-overhead looping ๐Ÿ“
  • -ms โ€” causes all variables to default to the ".tiny" section. There's a 65536-byte limit on this section, and accesses to these variables use the %gp base register ๐Ÿ’…
  • -msatur โ€” enables the saturation instructions. Note that the compiler doesn't currently generate these itself, but this option is here for compatibility with other tools, like as ๐Ÿงš
  • -msdram โ€” links the SDRAM-based runtime instead of the default ROM-based runtime
  • -msim โ€” links the simulator run-time libraries
  • -msimnovec โ€” links the simulator runtime libraries, but leaves out built-in support for reset and exception vectors and tables
  • -mtf โ€” causes all functions to default to the ".far" section. Without this option, functions default to the ".near" section ๐ŸŒธ
  • -mtiny=n โ€” variables that are n bytes or smaller get allocated to the ".tiny" section, and they use the $gp base register. The default for this option is 4, but there's a 65536-byte limit on the ".tiny" section ๐ŸŽ€

๐ŸŒˆ MicroBlaze Options ๐ŸŒˆ

  • -msoft-float โ€” uses software emulation for floating point (this is the default) ๐Ÿซถ
  • -mhard-float โ€” uses hardware floating-point instructions โญ
  • -mmemcpy โ€” doesn't optimize block moves, uses memcpy instead ๐Ÿฆ‹
  • -mno-clearbss โ€” ๐Ÿ’€ deprecated. Use -fno-zero-initialized-in-bss instead.
โš ๏ธ -mno-clearbss is deprecated, so switch over to -fno-zero-initialized-in-bss.
  • -mcpu=cpu-type โ€” uses features of, and schedules code for, the given CPU. Supported values are in the format vX.YY.Z, where X is a major version, YY is the minor version, and Z is compatibility code. Example values are v3.00.a, v4.00.b, v5.00.a, v5.00.b, v6.00.a โœจ
  • -mxl-soft-mul โ€” uses software multiply emulation (default) ๐Ÿ’–
  • -mxl-soft-div โ€” uses software emulation for divides (default) ๐ŸŒธ
  • -mxl-barrel-shift โ€” uses the hardware barrel shifter ๐Ÿ”ฅ
  • -mxl-pattern-compare โ€” uses pattern compare instructions ๐Ÿงš
  • -msmall-divides โ€” uses table lookup optimization for small signed integer divisions ๐Ÿ‘‘
  • -mxl-stack-check โ€” ๐Ÿ’€ deprecated. Use -fstack-check instead.
โš ๏ธ -mxl-stack-check is deprecated, so use -fstack-check instead.
  • -mxl-gp-opt โ€” uses GP-relative ".sdata"/".sbss" sections ๐Ÿ“
  • -mxl-multiply-high โ€” uses multiply high instructions for the high part of a 32x32 multiply ๐Ÿ’œ
  • -mxl-float-convert โ€” uses hardware floating-point conversion instructions ๐ŸŒˆ
  • -mxl-float-sqrt โ€” uses the hardware floating-point square root instruction ๐Ÿฆ‹
  • -mbig-endian โ€” generate code for a big-endian target ๐ŸŽ€
  • -mlittle-endian โ€” generate code for a little-endian target ๐Ÿซถ
  • -mxl-reorder โ€” uses reorder instructions (swap and byte reversed load/store) โœจ
  • -mxl-mode-app-model โ€” selects the application model app-model. Valid models are:
    • executable โ€” normal executable (default), uses startup code crt0.o ๐ŸŒธ
    • -mpic-data-is-text-relative โ€” assumes the displacement between the text and data segments is fixed at static link time. This lets data get referenced by offset from the start of the text address instead of the GOT, since PC-relative addressing isn't supported ๐Ÿงš
    • xmdstub โ€” for use with the Xilinx Microprocessor Debugger (XMD) based software intrusive debug agent called xmdstub. This uses startup file crt1.o and sets the program's start address to 0x800 ๐Ÿ”ฅ
    • bootstrap โ€” for applications that get loaded using a bootloader. This model uses startup file crt2.o, which does NOT contain a processor reset vector handler. It's suitable for handing control back to the bootloader on a processor reset instead of the application ๐Ÿ‘‘
    • novectors โ€” for applications that don't need any of the MicroBlaze vectors. This can be useful for apps running inside a monitoring application. This model uses crt3.o as its startup file ๐Ÿ’…

Option -xl-mode-app-model is a deprecated alias for -mxl-mode-app-model ๐Ÿ’€


๐Ÿ“ MIPS Options ๐Ÿ“

  • -EB โ€” generate big-endian code ๐Ÿ’–
  • -EL โ€” generate little-endian code. This is the default for mips*el-*-* configurations ๐ŸŒธ
  • -march=arch โ€” generates code that runs on arch, which can be the name of a generic MIPS ISA or the name of a particular processor ๐Ÿ‘‘ The ISA names are:
    • mips1, mips2, mips3, mips4, mips32, mips32r2, mips32r3, mips32r5, mips32r6, mips64, mips64r2, mips64r3, mips64r5 and mips64r6

The processor names are:

  • 4kc, 4km, 4kp, 4ksc, 4kec, 4kem, 4kep, 4ksd, 5kc, 5kf, 20kc, 24kc, 24kf2_1, 24kf1_1, 24kec, 24kef2_1, 24kef1_1, 34kc, 34kf2_1, 34kf1_1, 34kn, 74kc, 74kf2_1, 74kf1_1, 74kf3_2, 1004kc, 1004kf2_1, 1004kf1_1, i6400, i6500, interaptiv, loongson2e, loongson2f, loongson3a, gs464, gs464e, gs264e, m4k, m14k, m14kc, m14ke, m14kec, m5100, m5101, octeon, octeon+, octeon2, octeon3, orion, p5600, p6600, r2000, r3000, r3900, r4000, r4400, r4600, r4650, r4700, r5900, r6000, r8000, rm7000, rm9000, r10000, r12000, r14000, r16000, sb1, sr71000, vr4100, vr4111, vr4120, vr4130, vr4300, vr5000, vr5400, vr5500, xlr and xlp.

The special value from-abi selects the most compatible architecture for the selected ABI. That means mips1 for 32-bit ABIs and mips3 for 64-bit ABIs ๐Ÿงš

The native Linux/GNU toolchain also supports the value native, which selects the best architecture option for the host processor. -march=native has no effect if GCC doesn't recognize the processor ๐Ÿ”ฅ

In processor names, a final 000 can be abbreviated as k (for example, -march=r2k). Prefixes are optional, and vr may be written r ๐Ÿ’…

Names of the form nf2_1 refer to processors with FPUs clocked at half the rate of the core. Names of the form nf1_1 refer to processors with FPUs clocked at the same rate as the core. Names of the form nf3_2 refer to processors with FPUs clocked at a 3:2 ratio with respect to the core. For compatibility reasons, nf is accepted as a synonym for nf2_1, while nx and bfx are accepted as synonyms for nf1_1 ๐Ÿฆ‹

GCC defines two macros based on the value of this option. The first is "_MIPS_ARCH", which gives the name of the target architecture as a string. The second has the form "_MIPS_ARCH_foo", where foo is the capitalized value of "_MIPS_ARCH". For example, -march=r2000 sets "_MIPS_ARCH" to "r2000" and defines the macro "_MIPS_ARCH_R2000" โœจ

Note that the "_MIPS_ARCH" macro uses the processor names given above. In other words, it has the full prefix and doesn't abbreviate 000 as k. In the case of from-abi, the macro names the resolved architecture (either "mips1" or "mips3"). It names the default architecture when no -march option is given ๐ŸŒธ

  • -mtune=arch โ€” optimizes for arch ๐ŸŽ€ Among other things, this option controls the way instructions are scheduled, and the perceived cost of arithmetic operations. The list of arch values is the same as for -march.

When this option isn't used, GCC optimizes for the processor specified by -march. By using -march and -mtune together, it's possible to generate code that runs on a family of processors but optimizes the code for one particular member of that family ๐Ÿ’–

-mtune also defines the macros _MIPS_TUNE and _MIPS_TUNE_foo, which work exactly like the -march ones I just covered ๐Ÿ’…โœจ

  • -mips1 โ€” same as -march=mips1 ๐ŸŽ€
  • -mips2 โ€” same as -march=mips2 ๐ŸŽ€
  • -mips3 โ€” same as -march=mips3 ๐ŸŽ€
  • -mips4 โ€” same as -march=mips4 ๐ŸŽ€
  • -mips32 โ€” same as -march=mips32 ๐ŸŽ€
  • -mips32r3 โ€” same as -march=mips32r3 ๐ŸŽ€
  • -mips32r5 โ€” same as -march=mips32r5 ๐ŸŽ€
  • -mips32r6 โ€” same as -march=mips32r6 ๐ŸŽ€
  • -mips64 โ€” same as -march=mips64 ๐ŸŽ€
  • -mips64r2 โ€” same as -march=mips64r2 ๐ŸŽ€
  • -mips64r3 โ€” same as -march=mips64r3 ๐ŸŽ€
  • -mips64r5 โ€” same as -march=mips64r5 ๐ŸŽ€
  • -mips64r6 โ€” same as -march=mips64r6 ๐ŸŽ€

  • -mips16, -mno-mips16 โ€” okay so these tell GCC to generate (or not generate) MIPS16 code ๐Ÿฆ‹ If you're targeting a MIPS32 or MIPS64 architecture, it uses the MIPS16e ASE, which is lowkey iconic.

You can also control MIPS16 on a per-function basis with the mips16 and nomips16 attributes ๐Ÿ’œ

  • -mflip-mips16 โ€” generates MIPS16 code on every other function ๐Ÿงš This one exists for regression testing of mixed MIPS16/non-MIPS16 code generation.
Not for ordinary use! Please don't use this when compiling your own code ๐Ÿ™ˆ
  • -minterlink-compressed, -mno-interlink-compressed โ€” these require (or don't require) that code using the standard, uncompressed MIPS ISA be link-compatible with MIPS16 and microMIPS code, and vice versa ๐Ÿ”ฅ

Here's the tea: code using the standard ISA encoding can't jump directly to MIPS16 or microMIPS code. It has to use a call or an indirect jump instead. So -minterlink-compressed turns off direct jumps unless GCC knows the jump's target isn't compressed ๐Ÿ’€

  • -minterlink-mips16, -mno-interlink-mips16 โ€” these are just aliases for -minterlink-compressed and -mno-interlink-compressed โœจ They predate the microMIPS ASE and are kept around for backwards compatibility ๐ŸŒธ

  • -mabi=32, -mabi=o64, -mabi=n32, -mabi=64, -mabi=eabi โ€” generates code for the ABI you pick ๐Ÿ‘‘

The EABI comes in a 32-bit and a 64-bit flavour. GCC normally makes 64-bit code when you pick a 64-bit architecture, but if you want 32-bit code instead, use -mgp32 ๐Ÿซถ

For info about the O64 ABI, check out http://gcc.gnu.org/projects/mipso64-abi.html ๐ŸŒˆ

GCC also supports a version of the o32 ABI where the floating-point registers are 64 bits wide instead of 32. You can select that combo with -mabi=32 -mfp64 ๐Ÿ’– This one leans on the "mthc1" and "mfhc1" instructions, so it's only supported on MIPS32R2, MIPS32R3 and MIPS32R5 processors.

The argument and return value register assignments stay the same, but each scalar value gets passed in one 64-bit register instead of a pair of 32-bit ones. For example, scalar floating-point values are returned in $f0 only, not a $f0/$f1 pair. The set of call-saved registers is also unchanged, so the even-numbered double-precision registers still get saved โœจ

Two more o32 variants exist to help you transition from 32-bit to 64-bit registers: FPXX (-mfpxx) and FP64A (-mfp64 -mno-odd-spreg) ๐Ÿฆ‹ FPXX says all code has to run correctly with either 32-bit or 64-bit registers. It can interlink with FP32 or FP64, but not both at once. FP64A is a lot like FP64 except it forbids odd-numbered single-precision registers. It can be paired with the "FRE" mode of FPUs in MIPS32R5 processors, so FP32 and FP64A code can interlink and run in the same process without switching FPU modes. Main character energy ๐Ÿ‘‘

  • -mabicalls, -mno-abicalls โ€” generates (or doesn't generate) code that works with SVR4-style dynamic objects ๐ŸŒธ -mabicalls is the default on SVR4-based systems.
  • -mshared, -mno-shared โ€” generates (or doesn't generate) code that's fully position-independent, so it can be linked into shared libraries ๐Ÿ’œ This only affects -mabicalls.

All -mabicalls code has traditionally been position-independent, no matter what -fPIC and -fpic say ๐Ÿ™ˆ BUT, as an extension, the GNU toolchain lets executables use absolute accesses for locally-binding symbols. It can also use shorter GP initialization sequences and make direct calls to locally-defined functions. That mode is what you get with -mno-shared ๐Ÿ”ฅ

-mno-shared needs binutils 2.16 or higher, and the objects it makes can only be linked by the GNU linker. The good news is it doesn't change the ABI of the final executable, only the ABI of relocatable objects. Using -mno-shared usually makes executables both smaller and quicker ๐ŸŽ€

-mshared is the default โœจ

  • -mplt, -mno-plt โ€” assumes (or doesn't assume) that the static and dynamic linkers support PLTs and copy relocations ๐Ÿงš This only affects -mno-shared -mabicalls. For the n64 ABI, this option does nothing without -msym32.

You can make -mplt the default by configuring GCC with --with-mips-plt. Otherwise the default is -mno-plt ๐Ÿ“

  • -mxgot, -mno-xgot โ€” lifts (or doesn't lift) the usual size limits on the global offset table ๐ŸŒˆ

Normally GCC uses a single instruction to load values from the GOT. That's pretty efficient, but it only works if the GOT is smaller than about 64k. Anything bigger makes the linker throw an error that looks like this:

relocation truncated to fit: R_MIPS_GOT16 foobar

If that happens, recompile your code with -mxgot ๐Ÿ˜ญ It works with very large GOTs, but the code is less efficient, because it takes three instructions to fetch the value of a global symbol.

Some linkers can create multiple GOTs. If you've got one of those, you should only need -mxgot when a single object file accesses more than 64k's worth of GOT entries. Very few do ๐Ÿ’…

These options do nothing unless GCC is generating position-independent code ๐Ÿซถ

  • -mgp32 โ€” assumes general-purpose registers are 32 bits wide ๐ŸŒธ
  • -mgp64 โ€” assumes general-purpose registers are 64 bits wide ๐Ÿ’œ
  • -mfp32 โ€” assumes floating-point registers are 32 bits wide ๐Ÿฆ‹
  • -mfp64 โ€” assumes floating-point registers are 64 bits wide ๐Ÿ”ฅ
  • -mfpxx โ€” doesn't assume anything about how wide the floating-point registers are ๐Ÿงš
  • -mhard-float โ€” uses floating-point coprocessor instructions ๐Ÿ’–
  • -msoft-float โ€” doesn't use floating-point coprocessor instructions. Instead, floating-point math is done with library calls ๐ŸŽ€
  • -mno-float โ€” same as -msoft-float, but it also asserts that your program doesn't do any floating-point operations ๐Ÿ’€ Right now this is only supported by some bare-metal MIPS configurations, which may pick a special set of libraries that don't have any floating-point support at all, including the floating-point "printf" formats.
If code compiled with -mno-float accidentally has floating-point operations in it, it'll probably fail at link time or at run time. Be careful, bestie ๐Ÿ˜ญ
  • -msingle-float โ€” assumes the floating-point coprocessor only supports single-precision operations ๐ŸŒธ
  • -mdouble-float โ€” assumes the floating-point coprocessor supports double-precision operations. This is the default ๐Ÿ‘‘
  • -modd-spreg, -mno-odd-spreg โ€” enables (or disables) the use of odd-numbered single-precision floating-point registers for the o32 ABI โœจ This is the default for processors that are known to support these registers. When you're using the o32 FPXX ABI, -mno-odd-spreg gets set by default.

  • -mabs=2008, -mabs=legacy โ€” these control how the special not-a-number (NaN) IEEE 754 floating-point data gets handled by the abs.fmt and neg.fmt machine instructions ๐Ÿ”ฅ

By default, or when you use -mabs=legacy, the legacy treatment is selected. Here, these instructions count as arithmetic and get avoided wherever correct operation is needed and the input might be a NaN. A longer sequence that manipulates the sign bit of the floating-point datum by hand gets used instead, unless -ffinite-math-only has also been specified ๐Ÿ’…

-mabs=2008 selects the IEEE 754-2008 treatment. In this case the instructions count as non-arithmetic, so they work correctly in every case, including when the input operand is a NaN. They're always used for the respective operations ๐ŸŒˆ

  • -mnan=2008, -mnan=legacy โ€” these control how the special not-a-number (NaN) IEEE 754 floating-point data is encoded ๐Ÿงš

-mnan=legacy selects the legacy encoding. Quiet NaNs (qNaNs) are marked by the first bit of their trailing significand field being 0, while signaling NaNs (sNaNs) are marked by that first bit being 1 ๐Ÿฆ‹

-mnan=2008 selects the IEEE 754-2008 encoding. Here qNaNs are marked by the first bit of their trailing significand field being 1, and sNaNs by that first bit being 0 ๐Ÿ’œ

The default is -mnan=legacy, unless GCC was configured with --with-nan=2008 ๐ŸŽ€

  • -mllsc, -mno-llsc โ€” uses (or doesn't use) the ll, sc and sync instructions to implement the atomic memory built-in functions ๐Ÿซถ When you specify neither, GCC uses those instructions if the target architecture supports them.

-mllsc is handy if your runtime environment can emulate the instructions. -mno-llsc can be useful when you're compiling for nonstandard ISAs ๐Ÿ“ You can make either one the default by configuring GCC with --with-llsc and --without-llsc respectively. --with-llsc is the default for some configurations, so check the installation documentation for the details โœจ

  • -mdsp, -mno-dsp โ€” uses (or doesn't use) revision 1 of the MIPS DSP ASE ๐ŸŒธ This option defines the preprocessor macro __mips_dsp. It also defines __mips_dsp_rev to 1 ๐Ÿ’–
  • -mdspr2, -mno-dspr2 โ€” uses (or doesn't use) revision 2 of the MIPS DSP ASE ๐Ÿ’… This option defines the preprocessor macros __mips_dsp and __mips_dspr2. It also defines __mips_dsp_rev to 2 ๐ŸŒˆ
  • -msmartmips, -mno-smartmips โ€” Turn it on or keep it off โœจ This flips the MIPS SmartMIPS ASE on or off ๐Ÿ’–
  • -mpaired-single, -mno-paired-single โ€” Turn on or skip the paired-single floating-point instructions ๐ŸŒธ Heads up, this one needs hardware floating-point support enabled first ๐Ÿซถ
  • -mdmx, -mno-mdmx โ€” Use or skip the MIPS Digital Media Extension instructions ๐Ÿ’… These only work when you're generating 64-bit code, and they also need hardware floating-point support turned on ๐Ÿ”ฅ
  • -mips3d, -mno-mips3d โ€” Turn the MIPS-3D ASE on or off ๐Ÿฆ‹ Using -mips3d automatically implies -mpaired-single โœจ
  • -mmicromips, -mno-micromips โ€” Generate or don't generate microMIPS code ๐Ÿงš You can also control microMIPS on a per-function basis with the "micromips" and "nomicromips" attributes ๐Ÿ’œ
  • -mmt, -mno-mt โ€” Use or skip the MT Multithreading instructions ๐ŸŽ€
  • -mmcu, -mno-mcu โ€” Use or skip the MIPS MCU ASE instructions ๐Ÿ“
  • -meva, -mno-eva โ€” Use or skip the MIPS Enhanced Virtual Addressing instructions ๐ŸŒˆ
  • -mvirt, -mno-virt โ€” Use or skip the MIPS Virtualization (VZ) instructions ๐Ÿ‘‘
  • -mxpa, -mno-xpa โ€” Use or skip the MIPS eXtended Physical Address (XPA) instructions ๐ŸŒธ
  • -mcrc, -mno-crc โ€” Use or skip the MIPS Cyclic Redundancy Check (CRC) instructions โญ
  • -mginv, -mno-ginv โ€” Use or skip the MIPS Global INValidate (GINV) instructions ๐Ÿซถ
  • -mloongson-mmi, -mno-loongson-mmi โ€” Use or skip the MIPS Loongson MultiMedia extensions Instructions (MMI) ๐Ÿ’–
  • -mloongson-ext, -mno-loongson-ext โ€” Use or skip the MIPS Loongson EXTensions (EXT) instructions ๐Ÿฆ‹
  • -mloongson-ext2, -mno-loongson-ext2 โ€” Use or skip the MIPS Loongson EXTensions r2 (EXT2) instructions ๐Ÿ”ฅ
  • -mlong64 โ€” Forces "long" types to be 64 bits wide ๐ŸŒˆ Check out -mlong32 for the full scoop on the default and how the pointer size gets decided ๐Ÿงš
  • -mlong32 โ€” Forces "long", "int", and pointer types to be 32 bits wide ๐Ÿ‘‘
    • The default size of "int"s, "long"s, and pointers depends on the ABI ๐Ÿ’…
    • Every supported ABI uses 32-bit "int"s โœจ
    • The n64 ABI uses 64-bit "long"s, and so does the 64-bit EABI. Everything else uses 32-bit "long"s ๐ŸŒธ
    • Pointers are the same size as "long"s, or the same size as integer registers, whichever is smaller ๐Ÿซถ
  • -msym32, -mno-sym32 โ€” Assume (or don't assume) that all symbols have 32-bit values, no matter which ABI you picked ๐Ÿฆ‹ This is super handy with -mabi=64 and -mno-abicalls because it lets GCC generate shorter and faster references to symbolic addresses ๐Ÿ”ฅ
  • -G num โ€” Puts definitions of externally-visible data into a small data section, as long as that data is no bigger than num bytes ๐ŸŒˆ GCC can then access the data more efficiently. Check out -mgpopt for the details ๐Ÿงš
    • The default -G value depends on the configuration โœจ
  • -mlocal-sdata, -mno-local-sdata โ€” Extend (or don't extend) the -G behavior to local data too, like static variables in C ๐Ÿ’œ -mlocal-sdata is the default for all configurations ๐Ÿ’–
    • If the linker complains that your app is using too much small data, try rebuilding the less performance-critical parts with -mno-local-sdata ๐Ÿ™ˆ
    • You might also want to build large libraries with -mno-local-sdata, so the libraries leave more room for the main program ๐Ÿซถ
  • -mextern-sdata, -mno-extern-sdata โ€” Assume (or don't assume) that externally-defined data is in a small data section, as long as its size is within the -G limit ๐ŸŒธ -mextern-sdata is the default for all configurations โญ
    • Okay, this part is important ๐Ÿ˜ญ If you compile a module Mod with -mextern-sdata -G num -mgpopt, and Mod references a variable Var that is no bigger than num bytes, you have to make sure Var ends up in a small data section ๐Ÿ”ฅ
    • If Var is defined by another module, you either need to compile that module with a high-enough -G setting, or attach a "section" attribute to Var's definition ๐Ÿ’…
    • If Var is common, you need to link the application with a high-enough -G setting ๐Ÿ‘‘
    • The easiest way to keep all of this from getting messy is to compile and link every module with the same -G option โœจ
    • If you want a library that supports several different small data limits, compile it with the highest supported -G setting and also use -mno-extern-sdata. That stops the library from making assumptions about externally-defined data ๐Ÿงš
  • -mgpopt, -mno-gpopt โ€” Use (or don't use) GP-relative accesses for symbols that are known to be in a small data section ๐Ÿ’œ See -G, -mlocal-sdata, and -mextern-sdata ๐ŸŒˆ -mgpopt is the default for all configurations ๐Ÿฆ‹
    • -mno-gpopt is useful when the $gp register might not hold the value of "_gp" ๐Ÿ™ˆ For example, if your code is part of a library that might be used in a boot monitor, programs that call boot monitor routines pass an unknown value in $gp ๐Ÿ˜ญ
    • The boot monitor itself is usually compiled with -G0 in those situations ๐Ÿซถ
    • -mno-gpopt implies -mno-local-sdata and -mno-extern-sdata ๐Ÿ”ฅ
  • -membedded-data, -mno-embedded-data โ€” Allocates variables to the read-only data section first if possible, then to the small data section if possible, and otherwise to data ๐Ÿ“ This gives slightly slower code than the default, but it reduces the amount of RAM needed while executing, so it might be the move for some embedded systems ๐Ÿ’–
  • -muninit-const-in-rodata, -mno-uninit-const-in-rodata โ€” Puts uninitialized "const" variables in the read-only data section ๐ŸŒธ This only means something when you're also using -membedded-data ๐Ÿงš
  • -mcode-readable=setting โ€” Tells GCC whether it may generate code that reads from executable sections ๐Ÿฆ‹ There are three possible settings, bestie ๐Ÿ’…
    • -mcode-readable=yes โ€” Instructions can freely access executable sections. This is the default setting โœจ
    • -mcode-readable=pcrel โ€” MIPS16 PC-relative load instructions can access executable sections, but other instructions must not ๐ŸŒˆ This is useful on 4KSc and 4KSd processors when the code TLBs have the Read Inhibit bit set. It's also useful on processors that can be configured to have a dual instruction/data SRAM interface and that, like the M4K, automatically redirect PC-relative loads to the instruction RAM ๐Ÿ’œ
    • -mcode-readable=no โ€” Instructions must not access executable sections ๐Ÿ™ˆ This can be useful on targets configured with a dual instruction/data SRAM interface that (unlike the M4K) do not automatically redirect PC-relative loads to the instruction RAM ๐Ÿ”ฅ
  • -msplit-addresses, -mno-split-addresses โ€” Enable (or disable) the use of the %hi() and %lo() assembler relocation operators ๐Ÿซถ This one has been superseded by -mexplicit-relocs, but it's kept around for backwards compatibility ๐Ÿฅบ
  • -mexplicit-relocs, -mno-explicit-relocs โ€” Use (or don't use) assembler relocation operators when dealing with symbolic addresses ๐Ÿ’– The alternative, selected by -mno-explicit-relocs, is to use assembler macros instead ๐Ÿฆ‹ -mexplicit-relocs is the default if GCC was configured to use an assembler that supports relocation operators ๐Ÿ’…
  • -mcheck-zero-division, -mno-check-zero-division โ€” Trap (or don't trap) on integer division by zero ๐Ÿ’€ The default is -mcheck-zero-division โœจ
  • -mdivide-traps, -mdivide-breaks โ€” MIPS systems check for division by zero by generating either a conditional trap or a break instruction ๐Ÿ‘‘ Traps give you smaller code, but they're only supported on MIPS II and later ๐ŸŒธ Also, some versions of the Linux kernel have a bug that stops trap from generating the proper signal ("SIGFPE") ๐Ÿ˜ญ Use -mdivide-traps to allow conditional traps on architectures that support them, and -mdivide-breaks to force the use of breaks ๐Ÿงš
    • The default is usually -mdivide-traps, but you can override it at configure time using --with-divide=breaks ๐ŸŒˆ
    • Divide-by-zero checks can be completely disabled with -mno-check-zero-division ๐Ÿ™ˆ
  • -mload-store-pairs, -mno-load-store-pairs โ€” Enable (or disable) an optimization that pairs consecutive load or store instructions to enable load/store bonding ๐Ÿ”ฅ It's enabled by default, but it only takes effect when the selected architecture is known to support bonding ๐Ÿ’œ
  • -mmemcpy, -mno-memcpy โ€” Force (or don't force) the use of "memcpy" for non-trivial block moves ๐Ÿ“ The default is -mno-memcpy, which lets GCC inline most constant-sized copies ๐Ÿฆ‹
  • -mlong-calls, -mno-long-calls โ€” Disable (or don't disable) the use of the "jal" instruction ๐ŸŒธ Calling functions with "jal" is more efficient, but it requires the caller and callee to be in the same 256 megabyte segment ๐Ÿซถ This option has no effect on abicalls code, and the default is -mno-long-calls โœจ
  • -mmad, -mno-mad โ€” Enable (or disable) the use of the "mad", "madu", and "mul" instructions, as provided by the R4650 ISA ๐Ÿ’…
  • -mimadd, -mno-imadd โ€” Enable (or disable) the use of the "madd" and "msub" integer instructions ๐Ÿ’– The default is -mimadd on architectures that support "madd" and "msub", except for the 74k architecture, where it was found to generate slower code ๐Ÿ™ˆ
  • -mfused-madd, -mno-fused-madd โ€” Enable (or disable) the use of the floating-point multiply-accumulate instructions, when they're available ๐ŸŒˆ The default is -mfused-madd โœจ
    • On the R8000 CPU, when multiply-accumulate instructions are used, the intermediate product is calculated to infinite precision and is not subject to the FCSR Flush to Zero bit ๐Ÿ˜ญ That may be undesirable in some circumstances ๐Ÿ’€
    • On other processors, the result is numerically identical to the equivalent computation using separate multiply, add, subtract, and negate instructions ๐Ÿงš
  • -nocpp โ€” Tells the MIPS assembler to not run its preprocessor over user assembler files (with a .s suffix) when assembling them ๐Ÿฆ‹
  • -mfix-24k, -mno-fix-24k โ€” Works around the 24K E48 (lost data on stores during refill) errata ๐Ÿ”ฅ The workarounds are implemented by the assembler rather than by GCC ๐Ÿ’…
  • -mfix-r4000, -mno-fix-r4000 โ€” Works around certain R4000 CPU errata ๐Ÿซถ
    • A double-word or a variable shift may give an incorrect result if it's executed immediately after starting an integer division ๐Ÿ™ˆ
  • bestie, a double-word or a variable shift can give you a wrong answer if it runs while an integer multiplication is still going ๐Ÿ’€
    • An integer division may give an incorrect result if it's started in a delay slot of a taken branch or a jump. ๐Ÿ™ˆ
  • -mfix-r4400, -mno-fix-r4400 โ€” okay so this one patches some R4400 CPU errata ๐ŸŽ€ that are lowkey chaotic:
    • A double-word or a variable shift may give an incorrect result if executed immediately after starting an integer division. ๐Ÿ˜ญ
  • -mfix-r10000, -mno-fix-r10000 โ€” this one fixes some R10000 errata ๐Ÿ’œ
    • "ll"/"sc" sequences may not behave atomically on revisions prior to 3.0. They may deadlock on revisions 2.6 and earlier. ๐Ÿ’€

This option can only be used if the target architecture supports branch-likely instructions. -mfix-r10000 is the default when -march=r10000 is used, and -mno-fix-r10000 is the default otherwise. โœจ

  • -mfix-r5900, -mno-fix-r5900 โ€” ngl this one is a whole mood ๐Ÿฆ‹ It tells GCC not to try scheduling the preceding instruction into the delay slot of a branch placed at the end of a short loop of six instructions or fewer. Instead, it always puts a nop there. The short loop bug can make loops run only once or twice under certain conditions, because of a hardware bug in the R5900 chip. The workaround is handled by the assembler rather than by GCC. ๐Ÿ”ฅ
  • -mfix-rm7000, -mno-fix-rm7000 โ€” works around the RM7000 dmult/dmultu errata. The workarounds are done by the assembler, not GCC. ๐Ÿงš
  • -mfix-vr4120, -mno-fix-vr4120 โ€” fixes some VR4120 errata ๐ŸŒธ
    • dmultu does not always produce the correct result.
    • div and ddiv do not always produce the correct result if one of the operands is negative.

The workarounds for the division errata rely on special functions in libgcc.a. At the moment, these functions are only provided by the mips64vr*-elf configurations, so keep that in mind, bestie. ๐Ÿ‘€

Other VR4120 errata need a nop inserted between certain pairs of instructions. The assembler handles those, not GCC itself. ๐Ÿ’…

  • -mfix-vr4130 โ€” works around the VR4130 mflo/mfhi errata. The workarounds are implemented by the assembler rather than GCC, though GCC avoids using mflo and mfhi if the VR4130 macc, macchi, dmacc and dmacchi instructions are available instead. ๐Ÿ“
  • -mfix-sb1, -mno-fix-sb1 โ€” works around certain SB-1 CPU core errata. (This flag currently works around the SB-1 revision 2 "F1" and "F2" floating-point errata.) ๐ŸŒˆ
  • -mr10k-cache-barrier=setting โ€” this one is a whole saga, so grab a snack ๐Ÿฟ It specifies whether GCC should insert cache barriers to avoid the side effects of speculation on R10K processors.

Like lots of processors, the R10K tries to guess the outcome of a conditional branch and speculatively runs instructions from the "taken" branch. It later aborts them if the guess was wrong. The catch is that on the R10K, even aborted instructions can have side effects. ๐Ÿ˜ญ

This problem only affects kernel stores and, depending on the system, kernel loads. For example, a speculatively executed store may load the target memory into cache and mark the cache line as dirty, even if the store itself is later aborted. If a DMA operation writes to the same area of memory before that "dirty" line is flushed, the cached data overwrites the DMA-ed data. Check the R10K processor manual for a full description, including other potential problems. ๐Ÿ“–

One workaround is to insert cache barrier instructions before every memory access that might be speculatively executed and might have side effects even if aborted. -mr10k-cache-barrier=setting controls GCC's version of this workaround. It assumes that aborted accesses to any byte in the following regions do not have side effects:

  1. the memory occupied by the current function's stack frame;
  2. the memory occupied by an incoming stack argument;
  3. the memory occupied by an object with a link-time-constant address.

It is the kernel's job to make sure speculative accesses to these regions are actually safe. ๐Ÿซถ

If your input program has a function declaration like this:

void foo (void);

then the implementation of foo must allow j foo and jal foo to be executed speculatively. GCC honors this for functions it compiles itself, and it expects non-GCC functions (like hand-written assembly) to do the same. ๐ŸŽ€

The option has three forms:

  • -mr10k-cache-barrier=load-store โ€” inserts a cache barrier before a load or store that might be speculatively executed and might have side effects even if aborted.
  • -mr10k-cache-barrier=store โ€” inserts a cache barrier before a store that might be speculatively executed and might have side effects even if aborted.
  • -mr10k-cache-barrier=none โ€” turns off cache barrier insertion. This is the default setting. โœจ
  • -mflush-func=func, -mno-flush-func โ€” picks the function to call to flush the I and D caches, or tells GCC not to call any such function. If one is called, it must take the same arguments as the common _flush_func: the address of the memory range being flushed, the size of that range, and the number 3 (to flush both caches). The default depends on the target GCC was configured for, but it's commonly either _flush_func or __cpu_flush. ๐Ÿงš
  • mbranch-cost=num โ€” sets the cost of branches to roughly num "simple" instructions. This cost is only a heuristic, so it's not guaranteed to give consistent results across releases. A zero cost redundantly selects the default, which is based on the -mtune setting. ๐Ÿ’–
  • -mbranch-likely, -mno-branch-likely โ€” turns Branch Likely instructions on or off, no matter what the selected architecture defaults to. By default, Branch Likely instructions may be generated if the selected architecture supports them. The exception is the MIPS32 and MIPS64 architectures, and processors that implement them. For those, Branch Likely instructions are not generated by default, because MIPS32 and MIPS64 specifically deprecate their use. ๐Ÿ™ˆ
  • -mcompact-branches=never, -mcompact-branches=optimal, -mcompact-branches=always โ€” these control which form of branches gets generated. The default is -mcompact-branches=optimal. ๐Ÿ‘‘

-mcompact-branches=never makes sure compact branch instructions are never generated.

-mcompact-branches=always makes sure a compact branch instruction is generated if one is available. If it isn't, a delay slot form of the branch gets used instead.

-mcompact-branches=optimal uses a delay slot branch if one is available in the current ISA and the delay slot is successfully filled. If the delay slot isn't filled, a compact branch gets chosen when one is available.

These options are supported from MIPS Release 6 onwards. ๐ŸŒธ

  • -mfp-exceptions, -mno-fp-exceptions โ€” specifies whether FP exceptions are enabled. This affects how FP instructions get scheduled for some processors. The default is that FP exceptions are enabled. ๐Ÿ”ฅ

For instance, on the SB-1, if FP exceptions are disabled and we're emitting 64-bit code, then we can use both FP pipes. Otherwise, we can only use one FP pipe. ๐Ÿฆ‹

  • -mvr4130-align, -mno-vr4130-align โ€” the VR4130 pipeline is two-way superscalar, but it can only issue two instructions together if the first one is 8-byte aligned. When this option is enabled, GCC aligns pairs of instructions that it thinks should execute in parallel. โœจ

This option only has an effect when optimizing for the VR4130. It usually makes code faster, but at the expense of making it bigger. It is enabled by default at optimization level -O3. ๐Ÿ“

  • -msynci, -mno-synci โ€” enables (or disables) generation of synci instructions on architectures that support them. The synci instructions, if enabled, are generated when __builtin___clear_cache is compiled.

This option defaults to -mno-synci, but you can override the default by configuring GCC with --with-synci.

When compiling code for single processor systems, it's generally safe to use synci. But on many multi-core (SMP) systems, it doesn't invalidate the instruction caches on all cores and may lead to undefined behavior. Be careful out there, bestie. โš ๏ธ
  • -mrelax-pic-calls, -mno-relax-pic-calls โ€” tries to turn PIC calls that are normally dispatched via register $25 into direct calls. This only works if the linker can resolve the destination at link time, and the destination is within range for a direct call. ๐Ÿงš

-mrelax-pic-calls is the default if GCC was configured to use an assembler and a linker that support the .reloc assembly directive, and -mexplicit-relocs is in effect. With -mno-explicit-relocs, this optimization can be done by the assembler and the linker alone, without help from the compiler. ๐Ÿ’…

  • -mmcount-ra-address, -mno-mcount-ra-address โ€” emits (or doesn't emit) code that lets _mcount modify the calling function's return address. When enabled, this option extends the usual _mcount interface with a new ra-address parameter. It has type intptr_t * and is passed in register $12. _mcount can then modify the return address by doing both of the following:
    • Returning the new address in register $31.
    • Storing the new address in *ra-address, if ra-address is nonnull.

The default is -mno-mcount-ra-address. ๐Ÿซถ

  • -mframe-header-opt, -mno-frame-header-opt โ€” enables (or disables) frame header optimization in the o32 ABI. When you use the o32 ABI, calling functions allocate 16 bytes on the stack for the called function to write out register arguments. When this optimization is enabled, it suppresses that frame header allocation if it can be determined to be unused. ๐ŸŽ€

This optimization is off by default at all optimization levels. ๐Ÿ™ˆ

  • -mlxc1-sxc1, -mno-lxc1-sxc1 โ€” when applicable, enables (or disables) generation of lwxc1, swxc1, ldxc1 and sdxc1 instructions. It's enabled by default. ๐Ÿ’–
  • -mmadd4, -mno-madd4 โ€” okay so this one is a switch for the 4-operand madd.s, madd.d and friends. Where it applies, you can turn generation on or off. It's already on by default, so you don't have to lift a finger ๐Ÿ’…

โœจ MMIX Options โœจ

These options are defined for the MMIX ๐Ÿงš

  • -mlibfuncs, -mno-libfuncs โ€” this tells GCC you're compiling intrinsic library functions, so every value gets passed in registers, no matter how big it is ๐Ÿ”ฅ
  • -mepsilon, -mno-epsilon โ€” turn this on and you get floating-point comparison instructions that compare against the rE epsilon register ๐Ÿฆ‹
  • -mabi=mmixware, -mabi=gnu โ€” -mabi=mmixware makes function parameters and return values show up as registers $0 and up inside the called function. -mabi=gnu is the other vibe, where it uses global registers $231 and up instead ๐Ÿ‘‘
  • -mzero-extend, -mno-zero-extend โ€” when you read data from memory in chunks shorter than 64 bits, -mzero-extend makes zero-extending loads the default, while -mno-zero-extend keeps sign-extending ones ๐Ÿ“
  • -mknuthdiv, -mno-knuthdiv โ€” -mknuthdiv makes the remainder of a division take the same sign as the divisor. The default, -mno-knuthdiv, has the remainder follow the sign of the dividend instead. Both are arithmetically valid, but the second one is the one basically everybody uses ๐Ÿ’œ
  • -mtoplevel-symbols, -mno-toplevel-symbols โ€” -mtoplevel-symbols slaps a : in front of every global symbol, so your assembly code works with the "PREFIX" assembly directive. -mno-toplevel-symbols skips the prefix ๐ŸŒธ
  • -melf โ€” makes an executable in ELF format instead of the default mmo format that the mmix simulator uses ๐ŸŽ€
  • -mbranch-predict, -mno-branch-predict โ€” -mbranch-predict lets the compiler use the probable-branch instructions whenever static branch prediction says a branch is likely. -mno-branch-predict says nope to that โœจ
  • -mbase-addresses, -mno-base-addresses โ€” -mbase-addresses has the compiler generate code that uses base addresses. Using one automatically makes a request, which the assembler and linker take care of, for a constant that gets set up in a global register. That register then serves one or more base address requests within 0 to 255 from the value it holds. The upside is that the code comes out short and fast, but there's a limit on how many different data items you can address. So if your program has lots of static data, you might need -mno-base-addresses ๐Ÿ™ˆ
  • -msingle-exit, -mno-single-exit โ€” -msingle-exit forces the generated code to have one single exit point in each function. -mno-single-exit doesn't force that ๐Ÿฆ‹

๐Ÿ’– MN10300 Options ๐Ÿ’–

These -m options are defined for Matsushita MN10300 architectures ๐ŸŒˆ

  • -mmult-bug โ€” generates code that avoids bugs in the multiply instructions for MN10300 processors. This is the default โœจ
  • -mno-mult-bug โ€” does not generate code to avoid those multiply bugs for MN10300 processors ๐Ÿ™ˆ
  • -mam33 โ€” generates code using features specific to the AM33 processor ๐Ÿ”ฅ
  • -mno-am33 โ€” no AM33-specific features in the generated code. This is the default ๐Ÿ’…
  • -mam33-2 โ€” generates code using features specific to the AM33/2.0 processor ๐Ÿ‘‘
  • -mam34 โ€” generates code using features specific to the AM34 processor ๐Ÿฆ‹
  • -mtune=cpu-type โ€” schedules instructions using the timing characteristics of the CPU type you name. This doesn't change the processor type you're targeting. The CPU type has to be one of mn10300, am33, am33-2 or am34 ๐ŸŽ€
  • -mreturn-pointer-on-d0 โ€” when generating a function that returns a pointer, the pointer gets returned in both "a0" and "d0". Otherwise it only comes back in "a0", and trying to call those functions without a prototype throws errors. This one is on by default, but you can flip it off with -mno-return-pointer-on-d0 ๐Ÿซถ
  • -mno-crt0 โ€” doesn't link in the C run-time initialization object file ๐ŸŒธ
  • -mrelax โ€” tells the linker to run a relaxation pass that shortens branches, calls and absolute memory addresses. It only does anything when you use it on the command line for the final link step ๐Ÿงš
This option makes symbolic debugging impossible. Be careful with -mrelax if you're debugging ๐Ÿ’€
  • -mliw โ€” lets the compiler generate Long Instruction Word instructions if the target is AM33 or later. This is the default. It also defines the preprocessor macro "__LIW__" ๐Ÿ’œ
  • -mno-liw โ€” no Long Instruction Word instructions for you. It defines the preprocessor macro "__NO_LIW__" ๐Ÿ“
  • -msetlb โ€” lets the compiler generate SETLB and Lcc instructions if the target is AM33 or later. This is the default. It defines the preprocessor macro "__SETLB__" โœจ
  • -mno-setlb โ€” no SETLB or Lcc instructions. It defines the preprocessor macro "__NO_SETLB__" ๐Ÿ™ˆ

๐ŸŒธ Moxie Options ๐ŸŒธ

  • -meb โ€” generates big-endian code. This is the default for moxie-*-* configurations ๐Ÿฆ‹
  • -mel โ€” generates little-endian code ๐ŸŽ€
  • -mmul.x โ€” generates mul.x and umul.x instructions. This is the default for moxiebox-*-* configurations ๐Ÿ”ฅ
  • -mno-crt0 โ€” doesn't link in the C run-time initialization object file ๐Ÿ’…

๐Ÿ‘‘ MSP430 Options ๐Ÿ‘‘

These options are defined for the MSP430 ๐Ÿงš

  • -masm-hex โ€” forces assembly output to always use hex constants. Normally these are signed decimals, but this option is there for testsuite and/or aesthetic purposes ๐ŸŒˆ
  • -mmcu= โ€” picks the MCU you're targeting. GCC uses that MCU name, converts it to upper case, and wraps it with __ on both sides to make a C preprocessor symbol. The msp430.h header then uses that symbol to pick an MCU-specific supplementary header file ๐Ÿ’–

This option also sets the ISA. If the MCU name is one that only supports the 430 ISA, that's the one selected. Otherwise you get the 430X ISA. The generic MCU name msp430 selects the 430 ISA, and the generic msp430x MCU name selects the 430X ISA ๐Ÿฆ‹

An MCU-specific linker script also gets added to the linker command line. The script's name is the MCU name with .ld appended. So -mmcu=xxx defines the C preprocessor symbol "__XXX__" and makes the linker look for a script called xxx.ld ๐Ÿ”ฅ

This option is also passed on to the assembler โœจ

  • -mwarn-mcu, -mno-warn-mcu โ€” these turn warnings on or off about conflicts between the MCU name from -mmcu and the ISA set by -mcpu, and/or the hardware multiply support set by -mhwmult. They also toggle warnings about unrecognized MCU names. This one is on by default ๐Ÿซถ
  • -mcpu= โ€” specifies the ISA to use. The accepted values are msp430, msp430x and msp430xv2. This option is deprecated, so use -mmcu= to select the ISA instead ๐Ÿ’€
  • -msim โ€” links to the simulator runtime libraries and linker script. It overrides any scripts that -mmcu= would have picked ๐ŸŽ€
  • -mlarge โ€” uses large-model addressing, with 20-bit pointers and a 32-bit "size_t" ๐Ÿ“
  • -msmall โ€” uses small-model addressing, with 16-bit pointers and a 16-bit "size_t" ๐ŸŒธ
  • -mrelax โ€” gets passed to the assembler and linker, so the linker can do certain optimizations that can't happen until the final link ๐Ÿงš
  • mhwmult= โ€” describes the type of hardware multiply your target supports. The accepted values are none for no hardware multiply, 16bit for the original 16-bit-only multiply in early MCUs, 32bit for the 16/32-bit multiply in later MCUs, and f5series for the 16/32-bit multiply in F5-series MCUs. You can also give it auto, which tells GCC to figure out the hardware multiply support from the MCU name given by -mmcu. If there's no -mmcu option or the MCU name isn't recognized, GCC assumes no hardware multiply support. "auto" is the default setting ๐Ÿ’œ

Hardware multiplies are normally done by calling a library routine, which saves space in the generated code. When you compile at -O3 or higher, though, the hardware multiplier gets invoked inline. That makes the code bigger, but faster ๐Ÿ”ฅ

The hardware multiply routines turn off interrupts while they run and restore the previous interrupt state when they finish. So they're safe to use inside interrupt handlers as well as in normal code ๐Ÿซถ

  • -minrt โ€” enables a minimum runtime environment, meaning no static initializers or constructors. This is meant for memory-constrained devices. The compiler includes special symbols in some objects that tell the linker and runtime which code fragments are required ๐ŸŒˆ
  • -mcode-region=, -mdata-region= โ€” these tell the compiler where to place functions and data that don't have a lower, upper, either or section attribute. The possible values are lower, upper, either or any. The first three behave like the matching attribute. any is the default, and it leaves placement entirely up to the linker script and how it assigns the standard sections (.text, .data, etc) to the memory regions ๐Ÿฆ‹
  • -msilicon-errata= โ€” passes a request to the assembler to enable the fixes for the named silicon errata โœจ
  • -msilicon-errata-warn= โ€” passes a request to the assembler to turn on warning messages for when a silicon errata might need to be applied ๐Ÿ™ˆ

๐Ÿ“ NDS32 Options ๐Ÿ“

These options are defined for NDS32 implementations ๐Ÿงš

  • -mbig-endian โ€” generates code in big-endian mode ๐ŸŒธ
  • -mlittle-endian โ€” generates code in little-endian mode ๐Ÿ’–
  • -mreduced-regs โ€” uses the reduced-set registers for register allocation ๐Ÿฆ‹
  • -mfull-regs โ€” uses the full-set registers for register allocation ๐Ÿ‘‘
  • -mcmov โ€” generates conditional move instructions ๐Ÿ”ฅ
  • -mno-cmov โ€” does not generate conditional move instructions ๐Ÿ’…
  • -mext-perf โ€” generates performance extension instructions ๐ŸŽ€
  • -mno-ext-perf โ€” does not generate performance extension instructions ๐Ÿ™ˆ
  • -mext-perf2 โ€” generates performance extension 2 instructions โœจ
  • -mno-ext-perf2 โ€” does not generate performance extension 2 instructions ๐Ÿ’€
  • -mext-string โ€” generates string extension instructions ๐ŸŒˆ
  • -mno-ext-string โ€” does not generate string extension instructions ๐Ÿซถ
  • -mv3push โ€” generates v3 push25/pop25 instructions ๐Ÿ’œ
  • -mno-v3push: bestie, this one tells the compiler to skip the v3 push25 and pop25 instructions ๐Ÿ™…โ€โ™€๏ธ
  • -m16-bit: turns on 16-bit instructions ๐ŸŽ€
  • -mno-16-bit: nope, no 16-bit instructions allowed ๐Ÿ’…
  • -misr-vector-size=num: picks the size of each interrupt vector. It has to be either 4 or 16 ๐Ÿ”ฅ
  • -mcache-block-size=num: sets the size of each cache block. It must be a power of 2 between 4 and 512 ๐Ÿ“ฆ
  • -march=arch: names the target architecture ๐Ÿ—๏ธ
  • -mcmodel=code-model: sets the code model to one of these:
    • small: All the data and read-only data segments must be within 512KB addressing space. The text segment must be within 16MB addressing space. ๐Ÿฃ
    • medium: The data segment must be within 512KB, while the read-only data segment can be within 4GB addressing space. The text segment should still be within 16MB addressing space. ๐ŸŒ™
    • large: All the text and data segments can be within 4GB addressing space. ๐ŸŒŒ
  • -mctor-dtor: enables the constructor/destructor feature โœจ
  • -mrelax: guides the linker to relax instructions ๐Ÿฆ‹

๐ŸŒธ Nios II Options ๐ŸŒธ

These are the options defined for the Altera Nios II processor. ๐Ÿงš

  • -G num: puts global and static objects that are less than or equal to num bytes into the small data or BSS sections, instead of the normal data or BSS sections. The default value of num is 8 ๐Ÿ“
  • -mgpopt=option, -mgpopt, -mno-gpopt: turns GP-relative accesses on or off. Use the first form to pick one of the option names below, or stick with the plain flags ๐ŸŒˆ
    • none: Do not generate GP-relative accesses. ๐Ÿ™…โ€โ™€๏ธ
    • local: Generate GP-relative accesses for small data objects that are not external, weak, or uninitialized common symbols. GP-relative addressing is also used for objects that have been explicitly placed in a small data section via a "section" attribute. ๐ŸŽฏ
    • global: Same as local, but also generates GP-relative accesses for small data objects that are external, weak, or common. If you use this option, you must make sure that all parts of your program (including libraries) are compiled with the same -G setting. ๐Ÿค
    • data: Generates GP-relative accesses for all data objects in the program. If you use this option, the entire data and BSS segments of your program must fit in 64K of memory, and you must use an appropriate linker script to allocate them within the addressable range of the global pointer. ๐Ÿ’พ
    • all: Generates GP-relative addresses for function pointers as well as data pointers. If you use this option, the entire text, data, and BSS segments of your program must fit in 64K of memory, and you must use an appropriate linker script to allocate them within the addressable range of the global pointer. ๐Ÿ‘‘

-mgpopt is equivalent to -mgpopt=local, and -mno-gpopt is equivalent to -mgpopt=none.

The default is -mgpopt, except when -fpic or -fPIC is specified to generate position-independent code.

Heads up: the Nios II ABI does not permit GP-relative accesses from shared libraries. ๐Ÿšซ

You may need to specify -mno-gpopt explicitly when building programs that include large amounts of small data, including large GOT data sections. In this case, the 16-bit offset for GP-relative addressing may not be large enough to allow access to the entire small data section. ๐Ÿฅบ

  • -mgprel-sec=regexp: adds extra section names that can be accessed via GP-relative addressing. This one is most useful together with "section" attributes on variable declarations and a custom linker script. The regexp is a POSIX Extended Regular Expression ๐Ÿ”

This option does not affect how -G behaves. The sections you list are in addition to the standard ".sdata" and ".sbss" small-data sections that -mgpopt recognizes.

  • -mr0rel-sec=regexp: specifies names of sections that can be accessed via a 16-bit offset from "r0". That means they live in the low 32K or high 32K of the 32-bit address space. This is most useful together with "section" attributes on variable declarations and a custom linker script. The regexp is a POSIX Extended Regular Expression ๐Ÿ—บ๏ธ

Unlike GP-relative addressing for small data, zero-based addressing is never generated by default. There are also no conventional section names used in standard linker scripts for sections in the low or high areas of memory. ๐Ÿคทโ€โ™€๏ธ

  • -mel, -meb: generate little-endian (the default) or big-endian (experimental) code, respectively ๐Ÿ”„
  • -march=arch: specifies the name of the target Nios II architecture. GCC uses this name to figure out what kind of instructions it can emit when generating assembly code. Permissible names are: r1, r2 ๐Ÿ›๏ธ

The preprocessor macro __nios2_arch__ is available to programs. Its value is 1 or 2, which tells you the targeted ISA level ๐Ÿ“š

  • -mbypass-cache, -mno-bypass-cache: forces all load and store instructions to always bypass the cache by using I/O variants of the instructions. The default is not to bypass the cache ๐Ÿƒโ€โ™€๏ธ
  • -mno-cache-volatile, -mcache-volatile: volatile memory accesses bypass the cache by using the I/O variants of the load and store instructions. The default is not to bypass the cache ๐Ÿ™ˆ
  • -mno-fast-sw-div, -mfast-sw-div: stops the use of table-based fast divide for small numbers. The default is to use the fast divide at -O3 and above โšก
  • -mno-hw-mul, -mhw-mul, -mno-hw-mulx, -mhw-mulx, -mno-hw-div, -mhw-div: enables or disables the compiler emitting the mul, mulx, and div family of instructions. The default is to emit mul, and not to emit div or mulx ๐Ÿงฎ
  • -mbmx, -mno-bmx, -mcdx, -mno-cdx: enables or disables generation of Nios II R2 BMX (bit manipulation) and CDX (code density) instructions. Turning these on also requires -march=r2. Since they're optional extensions to the R2 architecture, the default is not to emit them ๐Ÿงฉ
  • -mcustom-insn=N, -mno-custom-insn: each -mcustom-insn=N option enables use of a custom instruction with encoding N when generating code that uses insn. For example, -mcustom-fadds=253 generates custom instruction 253 for single-precision floating-point add operations, instead of the default behavior of using a library call ๐Ÿ› ๏ธ

The following values of insn are supported. Unless noted otherwise, floating-point operations are expected to use normal IEEE 754 semantics and to correspond directly to the C operators or the equivalent GCC built-in functions. ๐Ÿง 

๐Ÿ’– Single-precision floating point ๐Ÿ’–

  • fadds, fsubs, fdivs, fmuls: binary arithmetic operations
  • fnegs: unary negation
  • fabss: unary absolute value
  • fcmpeqs, fcmpges, fcmpgts, fcmples, fcmplts, fcmpnes: comparison operations
  • fmins, fmaxs: floating-point minimum and maximum. These are only generated if -ffinite-math-only is specified
  • fsqrts: unary square root operation
  • fcoss, fsins, ftans, fatans, fexps, flogs: floating-point trigonometric and exponential functions. These are only generated if -funsafe-math-optimizations is also specified

๐Ÿฆ‹ Double-precision floating point ๐Ÿฆ‹

  • faddd, fsubd, fdivd, fmuld: binary arithmetic operations
  • fnegd: unary negation
  • fabsd: unary absolute value
  • fcmpeqd, fcmpged, fcmpgtd, fcmpled, fcmpltd, fcmpned: comparison operations
  • fmind, fmaxd: double-precision minimum and maximum. These are only generated if -ffinite-math-only is specified
  • fsqrtd: unary square root operation
  • fcosd, fsind, ftand, fatand, fexpd, flogd: double-precision trigonometric and exponential functions. These are only generated if -funsafe-math-optimizations is also specified

๐Ÿ” Conversions ๐Ÿ”

  • fextsd: conversion from single precision to double precision
  • ftruncds: conversion from double precision to single precision
  • fixsi, fixsu, fixdi, fixdu: conversion from floating point to signed or unsigned integer types, with truncation towards zero
  • round: conversion from single-precision floating point to signed integer, rounding to the nearest integer and ties away from zero. This corresponds to the __builtin_lroundf function when -fno-math-errno is used
  • floatis, floatus, floatid, floatud: conversion from signed or unsigned integer types to floating-point types

In addition, all of the following transfer instructions for internal registers X and Y must be provided before you can use any of the double-precision floating-point instructions. ๐Ÿšจ

Custom instructions that take two double-precision source operands expect the first operand in the 64-bit register X. The other operand (or the only operand of a unary operation) is given to the custom arithmetic instruction, with the least significant half in source register src1 and the most significant half in src2. A custom instruction that returns a double-precision result returns the most significant 32 bits in the destination register, and the other half in 32-bit register Y. GCC automatically generates the necessary code sequences to write register X and/or read register Y when double-precision floating-point instructions are used. ๐Ÿง

  • fwrx: writes src1 into the least significant half of X, and src2 into the most significant half of X
  • fwry: writes src1 into Y
  • frdxhi, frdxlo: read the most or least (respectively) significant half of X and store it in dest
  • frdy: reads the value of Y and stores it into dest

Want more local control over Nios II custom instruction generation? You can use the target("custom-insn=N") and target("no-custom-insn") function attributes or pragmas. ๐ŸŽ€

  • -mcustom-fpu-cfg=name: enables a predefined, named set of custom instruction encodings (see -mcustom-insn above). Currently, the following sets are defined:

Okay so the -mcustom-fpu-cfg presets are literally just bundles of -mcustom- flags in a trench coat ๐Ÿงš Here's what each one expands to:

           -mcustom-fpu-cfg=60-1 is equivalent to: -mcustom-fmuls=252
           -mcustom-fadds=253 -mcustom-fsubs=254 -fsingle-precision-constant

           -mcustom-fpu-cfg=60-2 is equivalent to: -mcustom-fmuls=252
           -mcustom-fadds=253 -mcustom-fsubs=254 -mcustom-fdivs=255
           -fsingle-precision-constant

           -mcustom-fpu-cfg=72-3 is equivalent to: -mcustom-floatus=243
           -mcustom-fixsi=244 -mcustom-floatis=245 -mcustom-fcmpgts=246
           -mcustom-fcmples=249 -mcustom-fcmpeqs=250 -mcustom-fcmpnes=251
           -mcustom-fmuls=252 -mcustom-fadds=253 -mcustom-fsubs=254
           -mcustom-fdivs=255 -fsingle-precision-constant

Here's the tea: if you set an individual -mcustom-insn= option, it wins over whatever -mcustom-fpu-cfg= gave you, no matter which one shows up first on the command line ๐Ÿ’…

Also, if you want local control over which FPU config a specific function uses, you can do that with the target("custom-fpu-cfg=name") function attribute or pragma ๐ŸŽ€

These extra -m options are available for the Altera Nios II ELF (bare-metal) target โœจ

  • -mhal โ€” Links with the HAL BSP ๐Ÿ› ๏ธ This skips the GCC-provided C runtime startup and termination code, and it's usually paired with -msys-crt0= so you can point at the alternate startup code that the HAL BSP brings along.
  • -msmallc โ€” Links with a limited version of the C library, -lsmallc, instead of Newlib. Small and mighty ๐Ÿฆ‹
  • -msys-crt0=startfile โ€” startfile is the file name of the startfile (crt0) you want to use while linking. This one only does anything when you're also using -mhal ๐Ÿงš
  • -msys-lib=systemlib โ€” systemlib is the library name of the library that handles the low-level system calls the C library needs, like "read" and "write". This is usually how you link against a library that comes from a HAL BSP ๐Ÿซถ

๐Ÿ’– Nvidia PTX Options ๐Ÿ’–

These options are defined for Nvidia PTX, bestie ๐Ÿ“

  • -m32, -m64 โ€” Generate code for the 32-bit or 64-bit ABI. Pick your fighter ๐Ÿ‘‘
  • -misa=ISA-string โ€” Generate code for the PTX ISA you specify, like sm_35. ISA strings have to be lower-case (no caps lock allowed here ๐Ÿ’€). Valid ISA strings include sm_30 and sm_35. The default ISA is sm_30.
  • -mmainkernel โ€” Links in code for a __main kernel. This is for stand-alone execution instead of offloading ๐Ÿ”ฅ
  • -moptimize โ€” Applies partitioned execution optimizations. This is the default whenever any level of optimization is selected, so you're probably already getting it โœจ
  • -msoft-stack โ€” Generates code that doesn't use ".local" memory directly for stack storage. Instead, a per-warp stack pointer gets maintained explicitly. This lets you do variable-length stack allocation (with variable-length arrays or "alloca"). When global memory is the underlying storage, it also makes it possible to access automatic variables from other threads, or with atomic instructions ๐ŸŒธ This code generation variant is used for OpenMP offloading, but the option is exposed on its own just so the compiler can be tested. If you want code that links into programs using OpenMP offloading, use -mgomp instead.
  • -muniform-simt โ€” Switches to a code generation variant that lets all threads in each warp execute, while keeping memory state and side effects the same as if only one thread in each warp was active outside of OpenMP SIMD regions. All atomic operations and calls to the runtime (malloc, free, vprintf) are conditionally executed (iff the current lane index equals the master lane index), and the register being assigned gets copied via a shuffle instruction from the master lane. Outside of SIMD regions, lane 0 is the master. Inside, each thread sees itself as the master ๐Ÿง  The shared memory array int __nvptx_uni[] stores all-zeros or all-ones bitmasks for each warp, which indicates the current mode (0 outside of SIMD regions). Each thread can bitwise-and the bitmask at position tid.y with the current lane index to compute the master lane index. Lowkey a lot, but it's giving genius ๐Ÿ’…
  • -mgomp โ€” Generates code for OpenMP offloading. This enables -msoft-stack and -muniform-simt, and selects the corresponding multilib variant ๐Ÿฆ‹

๐ŸŒˆ OpenRISC Options ๐ŸŒˆ

These options are defined for OpenRISC:

  • -mboard=name โ€” Configures a board-specific runtime. This gets passed to the linker for newlib board library linking. The default is or1ksim ๐Ÿงš
  • -mnewlib โ€” For compatibility, it's always newlib for ELF now ๐ŸŽ€
  • -mhard-div โ€” Generates code for hardware that supports divide instructions. This is the default โœจ
  • -mhard-mul โ€” Generates code for hardware that supports multiply instructions. This is the default too ๐Ÿ’–
  • -mcmov โ€” Generates code for hardware that supports the conditional move (l.cmov) instruction.
  • -mror โ€” Generates code for hardware that supports rotate right instructions.
  • -msext โ€” Generates code for hardware that supports sign-extension instructions.
  • -msfimm โ€” Generates code for hardware that supports set flag immediate (l.sf*i) instructions.
  • -mshftimm โ€” Generates code for hardware that supports shift-immediate related instructions (i.e. l.srai, l.srli, l.slli, 1.rori). Note, to enable generation of the l.rori instruction, the -mror flag must also be specified โš ๏ธ
  • -msoft-div โ€” Generates code for hardware that needs divide instruction emulation.
  • -msoft-mul โ€” Generates code for hardware that needs multiply instruction emulation.

๐Ÿฆ‹ PDP-11 Options ๐Ÿฆ‹

These options are defined for the PDP-11:

  • -mfpu โ€” Uses hardware FPP floating point. This is the default. (FIS floating point on the PDP-11/40 is not supported, sorry bestie ๐Ÿฅบ) Implies -m45.
  • -msoft-float โ€” Does not use hardware floating point.
  • -mac0 โ€” Returns floating-point results in ac0 (fr0 in Unix assembler syntax).
  • -mno-ac0 โ€” Returns floating-point results in memory. This is the default.
  • -m40 โ€” Generates code for a PDP-11/40. Implies -msoft-float -mno-split.
  • -m45 โ€” Generates code for a PDP-11/45. This is the default ๐Ÿ‘‘
  • -m10 โ€” Generates code for a PDP-11/10. Implies -msoft-float -mno-split.
  • -mint16, -mno-int32 โ€” Uses 16-bit "int". This is the default.
  • -mint32, -mno-int16 โ€” Uses 32-bit "int".
  • -msplit โ€” The target has split instruction and data space. Implies -m45.
  • -munix-asm โ€” Uses Unix assembler syntax.
  • -mdec-asm โ€” Uses DEC assembler syntax.
  • -mgnu-asm โ€” Uses GNU assembler syntax. This is the default ๐ŸŒˆ
  • -mlra โ€” Uses the new LRA register allocator. By default, the old "reload" allocator is used ๐Ÿง 

๐Ÿงš picoChip Options ๐Ÿงš

These -m options are defined for picoChip implementations:

  • -mae=ae_type โ€” Sets the instruction set, register set, and instruction scheduling parameters for array element type ae_type. Supported values for ae_type are ANY, MUL, and MAC.
    • -mae=ANY selects a completely generic AE type. Code generated with this option runs on any of the other AE types. It's not as efficient as code compiled for a specific AE type, and some types of operation (e.g., multiplication) don't work properly on all types of AE ๐Ÿ’€
    • -mae=MUL selects a MUL AE type. This is the most useful AE type for compiled code, and it's the default ๐Ÿ’–
    • -mae=MAC selects a DSP-style MAC AE. Code compiled with this option may suffer from poor performance of byte (char) manipulation, since the DSP AE doesn't provide hardware support for byte load/stores ๐Ÿ™ˆ
  • -msymbol-as-address โ€” Lets the compiler use a symbol name directly as an address in a load/store instruction, without loading it into a register first. Usually this makes larger programs that run faster than without the option. The results vary from program to program, though, so it's left as a user option instead of being permanently enabled ๐Ÿฆ‹
  • -mno-inefficient-warnings โ€” Disables warnings about the generation of inefficient code. These warnings can show up, for example, when compiling code that does byte-level memory operations on the MAC AE type. The MAC AE has no hardware support for byte-level memory operations, so every byte load/store has to be synthesized from word load/store operations. That's inefficient, so a warning tells you to rewrite the code to avoid byte operations, or to target an AE type with the necessary hardware support. This option turns those warnings off ๐Ÿ™ˆ

๐ŸŒธ PowerPC Options ๐ŸŒธ

These are listed under

Okay bestie, the text just trails off right there, so that's all the PowerPC tea I've got ๐Ÿ˜ญ

๐ŸŒŠ RISC-V Options ๐ŸŒŠ

These command-line options are defined for RISC-V targets:

  • -mbranch-cost=n โ€” Sets the cost of branches to roughly n instructions.
  • -mplt, -mno-plt โ€” When generating PIC code, do or don't allow the use of PLTs. This is ignored for non-PIC. The default is -mplt.
  • -mabi=ABI-string โ€” Specifies the integer and floating-point calling convention. The ABI string has two parts: the size of integer types, and the registers used for floating-point types. For example, -march=rv64ifd -mabi=lp64d means that long and pointers are 64-bit (implicitly making int 32-bit), and that floating-point values up to 64 bits wide get passed in F registers. Compare that with -march=rv64ifd -mabi=lp64f, which still lets the compiler generate code that uses the F and D extensions, but only allows floating-point values up to 32 bits long to be passed in registers. Or there's -march=rv64ifd -mabi=lp64, where no floating-point arguments get passed in registers at all ๐Ÿ’…

The default for this argument is system dependent, so bestie, if you want a specific calling convention, specify one explicitly ๐Ÿซถ The valid calling conventions are: ilp32, ilp32f, ilp32d, lp64, lp64f, and lp64d. Some calling conventions are impossible to implement on some ISAs. For example, -march=rv32if -mabi=ilp32d is invalid, because the ABI requires 64-bit values to be passed in F registers, but F registers are only 32 bits wide ๐Ÿ’€ There's also the ilp32e ABI, which can only be used with the rv32e architecture. This ABI isn't well specified at present, and it's subject to change โš ๏ธ

  • -mfdiv, -mno-fdiv โ€” Do or don't use hardware floating-point divide and square root instructions. This requires the F or D extensions for floating-point registers. The default is to use them if the specified architecture has these instructions โœจ
  • -mdiv, -mno-div โ€” okay so these let you choose whether to use hardware instructions for integer division ๐Ÿงฎ -mdiv turns them on and -mno-div turns them off. You'll need the M extension for this to work ๐Ÿซถ. By default they're used if the architecture you picked actually has those instructions โœจ
  • -march=ISA-string โ€” tell GCC which RISC-V ISA to generate code for, like rv64im ๐Ÿฆ‹ ISA strings have to be lower-case, no exceptions. Some vibes to try: rv64i, rv32g, rv32e, and rv32imaf.
  • -mtune=processor-string โ€” optimize the output for a specific processor, named by its microarchitecture ๐Ÿ”ฅ The valid picks are rocket, sifive-3-series, sifive-5-series, sifive-7-series, and size.

When you skip -mtune= entirely, the default is rocket ๐Ÿ’œ

The size option isn't really meant for end-users ๐Ÿ™ˆ It gets used when -Os is specified. It overrides the instruction cost info that -mtune= provides, but it does not override the pipeline info. Basically it helps shrink code size while still keeping good performance ๐ŸŒธ

  • -mpreferred-stack-boundary=num โ€” this tries to keep the stack boundary aligned to a 2 raised to num byte boundary ๐Ÿ“ If you don't set it, the default is 4 (16 bytes or 128-bits).
๐Ÿ’€ Warning: if you use this switch, you have to build all modules with the same value, and that includes any libraries. System libraries and startup modules count too, so don't skip them!
  • -msmall-data-limit=n โ€” global and static data smaller than n bytes gets tucked into a special section ๐Ÿงš (this only happens on some targets, so don't count on it everywhere).
  • -msave-restore, -mno-save-restore โ€” these let you pick between smaller-but-slower prologue and epilogue code that uses library function calls (-msave-restore) or not (-mno-save-restore) ๐Ÿข The default is fast inline prologues and epilogues, so you get speed out of the box โšก
  • -mstrict-align, -mno-strict-align โ€” these control whether unaligned memory accesses get generated ๐Ÿ™ƒ The first one says do not, the second one says do. The default depends on whether the processor you're optimizing for supports fast unaligned access or not.
  • -mcmodel=medlow โ€” generates code for the medium-low code model ๐ŸŒ™ The program and its statically defined symbols have to live inside one single 2 GiB address range, sitting between absolute addresses -2 GiB and +2 GiB. Programs can be statically or dynamically linked. This is the default code model, so you're already using it if you don't pick anything else ๐Ÿ’…
  • -mcmodel=medany โ€” generates code for the medium-any code model ๐ŸŒˆ Here the program and its statically defined symbols just need to be within any single 2 GiB address range. Programs can be statically or dynamically linked.
  • -mexplicit-relocs, -mno-exlicit-relocs โ€” use or skip assembler relocation operators when dealing with symbolic addresses โœจ The other route is assembler macros, which may limit optimization ๐Ÿฅฒ (heads up, the negative flag is spelled -mno-exlicit-relocs in the official page, so copy it exactly ๐Ÿ™ˆ)
  • -mrelax, -mno-relax โ€” take advantage of linker relaxations to cut down on the number of instructions needed to materialize symbol addresses ๐Ÿฆ‹ The default is to take advantage of them.
  • -memit-attribute, -mno-emit-attribute โ€” these emit (or don't emit) a RISC-V attribute that records extra info into ELF objects ๐Ÿงพ This feature needs at least binutils 2.32 ๐Ÿ’œ

๐ŸŒˆ RL78 Options ๐ŸŒˆ

  • -msim โ€” links in extra target libraries so your stuff can run inside a simulator ๐Ÿ–ฅ๏ธ
  • -mmul=none, -mmul=g10, -mmul=g13, -mmul=g14, -mmul=rl78 โ€” this is where you pick which hardware multiplication and division support to use ๐Ÿงฎ The simplest choice is "none", which uses software for both multiplication and division, and it's the default. "g13" is for the hardware multiply/divide peripheral on the RL78/G13 (S2 core) targets. "g14" selects the multiplication and division instructions that the RL78/G14 (S3 core) parts support. "rl78" is just an alias for "g14", and "mg10" is an alias for "none".

Setting this option also defines a C preprocessor macro based on what you picked ๐Ÿงš The possible values are __RL78_MUL_NONE__, __RL78_MUL_G13__, or __RL78_MUL_G14__.

  • -mcpu=g10, -mcpu=g13, -mcpu=g14, -mcpu=rl78 โ€” pick which RL78 core you're targeting ๐Ÿ‘‘ The default is the G14 core, also called an S3 core or just RL78. The G13 (or S2) core doesn't have multiply or divide instructions, so it uses a hardware peripheral for those jobs instead. The G10 (or S1) core doesn't have register banks, so it uses a different calling convention ๐Ÿซ 

If you set this option, it also picks the type of hardware multiply support, unless you override it with an explicit -mmul=none on the command line ๐Ÿ’… So -mcpu=g13 turns on the G13 hardware multiply peripheral, and -mcpu=g10 turns off hardware multiplications altogether.

Heads up, though: even though the RL78/G14 core is the default target, typing -mcpu=g14 or -mcpu=rl78 on the command line does change how the toolchain behaves, because it turns on G14 hardware multiply support ๐Ÿ‘€ If you don't specify these on the command line, software multiplication routines get used even though the code targets the RL78 core. This is only there for backwards compatibility with older toolchains that didn't have hardware multiply and divide support ๐Ÿฅน

Same deal with the macros here: based on the setting, you get __RL78_G10__, __RL78_G13__, or __RL78_G14__ defined โœจ

  • -mg10, -mg13, -mg14, -mrl78 โ€” these are aliases for the matching -mcpu= option ๐Ÿ“ They're only around for backwards compatibility.
  • -mallregs โ€” lets the compiler use every available register ๐ŸŒธ By default, r24..r31 are reserved for interrupt handlers. With this option turned on, those registers can also be used in ordinary functions.
  • -m64bit-doubles, -m32bit-doubles โ€” make the double data type 64 bits (-m64bit-doubles) or 32 bits (-m32bit-doubles) ๐Ÿ’– The default is -m32bit-doubles.
  • -msave-mduc-in-interrupts, -mno-save-mduc-in-interrupts โ€” these tell interrupt handler functions whether they should preserve the MDUC registers ๐Ÿ›ก๏ธ You only really need this if normal code might touch the MDUC registers, for example because it does multiplication and division. The default is to ignore the MDUC registers, since that keeps the interrupt handlers faster โšก You need to pass the target option -mg13 for this to work, because this feature is only available on the G13 target (S2 core). The MDUC registers only get saved if the interrupt handler performs a multiplication or division operation, or if it calls another function.

๐ŸŒธ IBM RS/6000 and PowerPC Options ๐ŸŒธ

These -m options are defined for the IBM RS/6000 and PowerPC ๐Ÿฆš

Here's the whole squad of flags ๐Ÿ‘‘

-mpowerpc-gpopt
-mno-powerpc-gpopt
-mpowerpc-gfxopt
-mno-powerpc-gfxopt
-mpowerpc64
-mno-powerpc64
-mmfcrf
-mno-mfcrf
-mpopcntb
-mno-popcntb
-mpopcntd
-mno-popcntd
-mfprnd
-mno-fprnd
-mcmpb
-mno-cmpb
-mmfpgpr
-mno-mfpgpr
-mhard-dfp
-mno-hard-dfp

You use these to specify which instructions are available on the processor you're using ๐Ÿง  The default value of these options is determined when you configure GCC. Specifying -mcpu=cpu_type overrides whatever you set here. The devs recommend using the -mcpu=cpu_type option instead of the ones listed above, so that's the move ๐Ÿซถ

Specifying -mpowerpc-gpopt lets GCC use the optional PowerPC architecture instructions in the General Purpose group, including floating-point square root โœจ Specifying -mpowerpc-gfxopt lets GCC use the optional PowerPC architecture instructions in the Graphics group, including floating-point select ๐ŸŽจ

The -mmfcrf option lets GCC generate the move from condition register field instruction, which is implemented on the POWER4 processor and other processors that support the PowerPC V2.01 architecture ๐Ÿ’œ The -mpopcntb option lets GCC generate the popcount and double-precision FP reciprocal estimate instruction, implemented on the POWER5 processor and other processors that support the PowerPC V2.02 architecture ๐ŸŒŸ The -mpopcntd option lets GCC generate the popcount instruction implemented on the POWER7 processor and other processors that support the PowerPC V2.06 architecture ๐Ÿ”ฅ The -mfprnd option lets GCC generate the FP round to integer instructions implemented on the POWER5+ processor and other processors that support the PowerPC V2.03 architecture ๐Ÿง The -mcmpb option lets GCC generate the compare bytes instruction implemented on the POWER6 processor and other processors that support the PowerPC V2.05 architecture ๐Ÿ“ The -mmfpgpr option lets GCC generate the FP move to/from general-purpose register instructions implemented on the POWER6X processor and other processors that support the extended PowerPC V2.05 architecture ๐Ÿฆ‹ The -mhard-dfp option lets GCC generate the decimal floating-point instructions implemented on some POWER processors ๐Ÿ’…

The -mpowerpc64 option lets GCC generate the additional 64-bit instructions found in the full PowerPC64 architecture, and it treats GPRs as 64-bit, doubleword quantities ๐ŸŒˆ GCC defaults to -mno-powerpc64.

  • -mcpu=cpu_type โ€” sets the architecture type, register usage, and instruction scheduling parameters for the machine type cpu_type ๐Ÿ–ฅ๏ธ These are the supported values: 401, 403, 405, 405fp, 440, 440fp, 464, 464fp, 476, 476fp, 505, 601, 602, 603, 603e, 604, 604e, 620, 630, 740, 7400, 7450, 750, 801, 821, 823, 860, 970, 8540, a2, e300c2, e300c3, e500mc, e500mc64, e5500, e6500, ec603e, G3, G4, G5, titan, power3, power4, power5, power5+, power6, power6x, power7, power8, power9, powerpc, powerpc64, powerpc64le, rs64, and native.

-mcpu=powerpc, -mcpu=powerpc64, and -mcpu=powerpc64le specify pure 32-bit PowerPC (either endian), 64-bit big endian PowerPC, and 64-bit little endian PowerPC architecture machine types ๐Ÿงš An appropriate, generic processor model gets assumed for scheduling purposes.

Specifying native as the cpu type detects and selects the architecture option that matches the host processor doing the compilation ๐Ÿซถ -mcpu=native has no effect if GCC doesn't recognize the processor ๐Ÿคทโ€โ™€๏ธ

The other options specify a specific processor ๐Ÿ’–

โš ๏ธ Code generated under those options runs best on that processor, and it may not run at all on others. Be careful, bestie!

The -mcpu options automatically enable or disable the following options:

-maltivec  -mfprnd  -mhard-float  -mmfcrf  -mmultiple -mpopcntb
-mpopcntd  -mpowerpc64 -mpowerpc-gpopt  -mpowerpc-gfxopt -mmulhw
-mdlmzb  -mmfpgpr  -mvsx -mcrypto  -mhtm  -mpower8-fusion
-mpower8-vector -mquad-memory  -mquad-memory-atomic  -mfloat128
-mfloat128-hardware

ngl the exact set of flags that gets picked for a CPU changes between compiler versions ๐Ÿ’… GCC goes with whatever seems to make the best code for that chip, so it doesn't necessarily match what the hardware can actually do ๐Ÿ’€. Want one specific flag set differently? Put it after -mcpu like -mcpu=970 -mno-altivec โœจ

On AIX, -maltivec and -mpowerpc64 don't get turned on or off by -mcpu right now, because AIX doesn't have full support for them yet ๐Ÿ™ˆ. You can still toggle them yourself if you're sure it'll work in your setup.

๐ŸŽ€ -mtune=cpu_type

Okay this one is so useful ๐Ÿงš It sets the instruction scheduling parameters for the machine type cpu_type, but it does not touch the architecture or register usage the way -mcpu=cpu_type does. You use the same values for cpu_type as you would with -mcpu. If you pass both, the code uses the architecture and registers from -mcpu, but the scheduling comes from -mtune ๐Ÿฆ‹

๐ŸŒธ -mcmodel=small

Generates PowerPC64 code for the small model. The TOC is limited to 64k ๐Ÿ“

๐ŸŒธ -mcmodel=medium

Generates PowerPC64 code for the medium model. The TOC and other static data can be up to a total of 4G in size. This is the default for 64-bit Linux ๐Ÿ‘‘

๐ŸŒธ -mcmodel=large

Generates PowerPC64 code for the large model. The TOC can be up to 4G in size, and other data and code is only limited by the 64-bit address space ๐ŸŒˆ

โœจ -maltivec / -mno-altivec

These generate code that uses (or doesn't use) AltiVec instructions, and they also unlock built-in functions that give you more direct access to the AltiVec instruction set ๐Ÿ”ฅ You might also need -mabi=altivec to tweak the current ABI with the AltiVec ABI enhancements.

When -maltivec is on, the element order for AltiVec intrinsics like "vec_splat", "vec_extract", and "vec_insert" matches the array element order for the target's endianness. So element zero is the leftmost element of a vector register on a big-endian target, and the rightmost one on a little-endian target ๐Ÿซถ

๐Ÿฆ‹ -mvrsave / -mno-vrsave

Generates VRSAVE instructions when you're generating AltiVec code ๐Ÿ’œ

๐Ÿฆ‹ -msecure-plt

Generates code that lets ld and ld.so build executables and shared libraries with non-executable ".plt" and ".got" sections. This is a PowerPC 32-bit SYSV ABI option ๐Ÿงš

๐Ÿฆ‹ -mbss-plt

Generates code that uses a BSS ".plt" section, which ld.so fills in. It needs ".plt" and ".got" sections that are both writable and executable ๐Ÿ˜ญ This is also a PowerPC 32-bit SYSV ABI option.

Heads up bestie: -mbss-plt requires ".plt" and ".got" to be both writable and executable, so make sure that's okay for your situation before you reach for it ๐Ÿ’€

๐Ÿฆ‹ -misel / -mno-isel

This switch enables or disables the generation of ISEL instructions ๐ŸŒธ

โœจ -mvsx / -mno-vsx

These generate code that uses (or doesn't use) vector/scalar (VSX) instructions. They also turn on built-in functions for more direct access to the VSX instruction set ๐Ÿ”ฅ

โœจ -mcrypto / -mno-crypto

Enables (or disables) the built-in functions that give direct access to the cryptographic instructions added in version 2.07 of the PowerPC ISA ๐Ÿ”

โœจ -mhtm / -mno-htm

Enables (or disables) the built-in functions for direct access to the Hardware Transactional Memory (HTM) instructions, which were added in version 2.07 of the PowerPC ISA ๐Ÿ’…

โœจ -mpower8-fusion / -mno-power8-fusion

The -mpower8-fusion form generates code that keeps some integer operations next to each other, so the instructions can be fused together on POWER8 and later processors โœจ The -mno-power8-fusion form does not keep them adjacent like that (the original text says "does not keeps", but the meaning is clear ๐Ÿ™ˆ).

โœจ -mpower8-vector / -mno-power8-vector

These generate code that uses (or doesn't use) the vector and scalar instructions added in version 2.07 of the PowerPC ISA. -mpower8-vector also enables built-in functions for more direct access to the vector instructions ๐Ÿฆ‹

โœจ -mquad-memory / -mno-quad-memory

These generate code that uses (or doesn't use) the non-atomic quad word memory instructions. -mquad-memory needs 64-bit mode, so no skipping that part ๐Ÿ“

โœจ -mquad-memory-atomic / -mno-quad-memory-atomic

These generate code that uses (or doesn't use) the atomic quad word memory instructions. -mquad-memory-atomic also needs 64-bit mode ๐ŸŒˆ

๐ŸŒˆ -mfloat128 / -mno-float128

These enable (or disable) the __float128 keyword for IEEE 128-bit floating point, and pick between software emulation or hardware instructions for it ๐Ÿ”ฅ

The VSX instruction set (-mvsx, -mcpu=power7, -mcpu=power8) or -mcpu=power9 must be enabled to use IEEE 128-bit floating point support. Also, this support only works on PowerPC Linux systems, so it's not a vibe anywhere else ๐Ÿ’€

-mfloat128 is enabled by default on PowerPC Linux systems using the VSX instruction set, and disabled on other systems ๐Ÿ‘‘

If you use the ISA 3.0 instruction set (-mpower9-vector or -mcpu=power9) on a 64-bit system, IEEE 128-bit floating point support also enables generation of ISA 3.0 IEEE 128-bit floating point instructions. Otherwise, if you don't ask for ISA 3.0 instructions, or you're targeting a 32-bit big endian system, IEEE 128-bit floating point gets handled by software emulation ๐Ÿซถ

๐ŸŒˆ -mfloat128-hardware / -mno-float128-hardware

These enable (or disable) using ISA 3.0 hardware instructions to support the __float128 data type โœจ

-mfloat128-hardware is enabled by default on PowerPC Linux systems using the ISA 3.0 instruction set, and disabled on other systems ๐Ÿ’–

๐Ÿงš -m32 / -m64

These generate code for 32-bit or 64-bit environments on Darwin and SVR4 targets, including GNU/Linux ๐ŸŒธ

The 32-bit environment sets int, long and pointer to 32 bits, and generates code that runs on any PowerPC variant.

The 64-bit environment sets int to 32 bits and long and pointer to 64 bits, and generates code for PowerPC64, same as -mpowerpc64 ๐Ÿ‘‘

๐Ÿงš -mfull-toc / -mno-fp-in-toc / -mno-sum-in-toc / -mminimal-toc

These modify how the TOC (Table Of Contents) gets generated, and every executable file gets one ๐Ÿ“–

-mfull-toc is the default. In that case GCC allocates at least one TOC entry for each unique non-automatic variable reference in your program, and it also puts floating-point constants in the TOC. The catch is that only 16,384 entries are available in the TOC ๐Ÿ’€

If the linker yells that you've overflowed the available TOC space, you can shrink TOC usage with -mno-fp-in-toc and -mno-sum-in-toc:

  • -mno-fp-in-toc โ€” stops GCC from putting floating-point constants in the TOC
  • -mno-sum-in-toc โ€” forces GCC to calculate the sum of an address and a constant at run time, instead of stuffing that sum into the TOC

You can use one or both of these. Each one makes the code very slightly slower and larger, but it saves TOC space ๐Ÿฆ‹

If you still run out of space even with both of those, try -mminimal-toc. It makes only one TOC entry per file. The code is slower and larger, but it uses extremely little TOC space. Maybe only use it on files with less frequently-executed code ๐Ÿ™ˆ

๐Ÿ‘‘ -maix64 / -maix32

-maix64 enables the 64-bit AIX ABI and calling convention: 64-bit pointers, a 64-bit "long" type, and the infrastructure needed to support them. It implies -mpowerpc64.

-maix32 disables the 64-bit ABI and implies -mno-powerpc64.

GCC defaults to -maix32 ๐Ÿ“

๐Ÿ’… -mxl-compat / -mno-xl-compat

-mxl-compat produces code that matches IBM XL compiler semantics more closely when you're using the AIX-compatible ABI. Specifically:

  • Floating-point arguments to prototyped functions beyond the register save area (RSA) go on the stack, in addition to argument FPRs.
  • It doesn't assume the most significant double in a 128-bit long double value is properly rounded when comparing values and converting to double.
  • It uses XL symbol names for long double support routines.

The AIX calling convention got extended without being documented at first, to handle an obscure K&R C case: calling a function that takes the address of its arguments with fewer arguments than declared. IBM XL compilers read floating-point arguments that don't fit in the RSA from the stack when a subroutine is compiled without optimization. Always storing floating-point arguments on the stack is inefficient and rarely needed, so this option isn't on by default. You only really need it when calling subroutines compiled by IBM XL compilers without optimization ๐Ÿง 

๐Ÿ’– -mpe

This supports the IBM RS/6000 SP Parallel Environment (PE) ๐ŸŒŠ It links an application that uses message passing with special startup code so it can run.

The system needs PE installed in the standard location (/usr/lpp/ppe.poe/), or you have to override the specs file with -specs= to point at the right directory.

Heads up: the Parallel Environment doesn't support threads, so -mpe and -pthread are incompatible ๐Ÿ’€

๐ŸŒธ -malign-natural / -malign-power

On AIX, 32-bit Darwin, and 64-bit PowerPC GNU/Linux, -malign-natural overrides the ABI-defined alignment of larger types (like floating-point doubles) and puts them on their natural size-based boundary โœจ

-malign-power tells GCC to follow the ABI-specified alignment rules instead.

GCC defaults to the standard alignment defined in the ABI.

On 64-bit Darwin, natural alignment is the default, and -malign-power is not supported ๐Ÿ™…

๐ŸŒŠ -msoft-float / -mhard-float

These generate code that doesn't use (or does use) the floating-point register set ๐Ÿฆ‹

If you use -msoft-float, software floating-point emulation is provided, but you have to pass the option to GCC when linking too ๐Ÿ’œ

  • -mmultiple, -mno-multiple โ€” okay so these tell GCC whether to use (or skip) the load multiple word and store multiple word instructions ๐Ÿงš. They're on by default on POWER systems, but not on PowerPC systems. > ๐Ÿ’€ Do not use -mmultiple on little-endian PowerPC systems, since those instructions don't work when the processor is in little-endian mode. The only exceptions are PPC740 and PPC750, which let these instructions run in little-endian mode ๐Ÿ‘‘.
  • -mupdate, -mno-update โ€” makes GCC use (or not use) the load or store instructions that update the base register to the address of the calculated memory location ๐Ÿ’…. These are generated by default. > ๐Ÿ˜ญ If you go with -mno-update, there's a small window between the time the stack pointer is updated and the address of the previous frame is stored. That means code that walks the stack frame across interrupts or signals may get corrupted data.
  • -mavoid-indexed-addresses, -mno-avoid-indexed-addresses โ€” tries to avoid (or not avoid) the use of indexed load or store instructions ๐ŸŒธ. These can cost you a performance penalty on Power6 processors in certain situations, like stepping through large arrays that cross a 16M boundary. It's enabled by default when targeting Power6 and disabled otherwise.
  • -mfused-madd, -mno-fused-madd โ€” uses (or doesn't use) the floating-point multiply and accumulate instructions ๐Ÿ”ฅ. They're generated by default if hardware floating point is used. The machine-dependent -mfused-madd is now mapped to the machine-independent -ffp-contract=fast option, and -mno-fused-madd is mapped to -ffp-contract=off ๐Ÿ’–.
  • -mmulhw, -mno-mulhw โ€” uses (or doesn't use) the half-word multiply and multiply-accumulate instructions on the IBM 405, 440, 464 and 476 processors โœจ. These are generated by default when targeting those processors.
  • -mdlmzb, -mno-dlmzb โ€” uses (or doesn't use) the string-search dlmzb instruction on the IBM 405, 440, 464 and 476 processors ๐Ÿฆ‹. It's generated by default when targeting those processors.
  • -mno-bit-align, -mbit-align โ€” on System V.4 and embedded PowerPC systems, do not (or do) force structures and unions that contain bit-fields to be aligned to the base type of the bit-field ๐ŸŽ€.

Example time ๐Ÿ“: by default, a structure containing nothing but 8 "unsigned" bit-fields of length 1 is aligned to a 4-byte boundary and has a size of 4 bytes. With -mno-bit-align, that same structure is aligned to a 1-byte boundary and is 1 byte in size.

  • -mno-strict-align, -mstrict-align โ€” on System V.4 and embedded PowerPC systems, do not (or do) assume that unaligned memory references are handled by the system ๐Ÿซถ.
  • -mrelocatable, -mno-relocatable โ€” allows (or doesn't allow) a static executable to be relocated to a different address at run time ๐Ÿ’œ. A simple embedded PowerPC system loader should relocate the entire contents of .got2 and the 4-byte locations listed in the .fixup section, which is a table of 32-bit addresses generated by this option. For this to work, all objects linked together must be compiled with -mrelocatable or -mrelocatable-lib. Also, -mrelocatable code aligns the stack to an 8-byte boundary.
  • -mrelocatable-lib, -mno-relocatable-lib โ€” just like -mrelocatable, this generates a .fixup section so static executables can be relocated at run time ๐ŸŒˆ. The difference is that -mrelocatable-lib doesn't use the smaller stack alignment that -mrelocatable does. Objects compiled with -mrelocatable-lib can be linked with objects compiled with any combination of the -mrelocatable options.
  • -mno-toc, -mtoc โ€” on System V.4 and embedded PowerPC systems, do not (or do) assume that register 2 contains a pointer to a global area pointing to the addresses used in the program ๐Ÿงš.
  • -mlittle, -mlittle-endian โ€” on System V.4 and embedded PowerPC systems, compiles code for the processor in little-endian mode ๐ŸŒธ. The -mlittle-endian option is the same as -mlittle.
  • -mbig, -mbig-endian โ€” on System V.4 and embedded PowerPC systems, compiles code for the processor in big-endian mode ๐Ÿ“. The -mbig-endian option is the same as -mbig.
  • -mdynamic-no-pic โ€” on Darwin and Mac OS X systems, compiles code so it isn't relocatable itself, but its external references are relocatable ๐Ÿ‘‘. The result is suitable for applications, but not shared libraries.
  • -msingle-pic-base โ€” treats the register used for PIC addressing as read-only, instead of loading it in the prologue for each function ๐Ÿ’…. The runtime system is responsible for initializing this register with an appropriate value before execution begins.
  • -mprioritize-restricted-insns=priority โ€” controls the priority given to dispatch-slot restricted instructions during the second scheduling pass โญ. The priority argument takes 0, 1, or 2: 0 gives no priority, 1 gives the highest priority, and 2 gives the second-highest priority.
  • -msched-costly-dep=dependence_type โ€” controls which dependences the target considers costly during instruction scheduling ๐Ÿ”ฅ. The dependence_type argument takes one of these values:
    • no โ€” no dependence is costly.
    • all โ€” all dependences are costly.
    • true_store_to_load โ€” a true dependence from store to load is costly.
    • store_to_load โ€” any dependence from store to load is costly.
    • number โ€” any dependence whose latency is greater than or equal to number is costly.
  • -minsert-sched-nops=scheme โ€” controls which NOP insertion scheme gets used during the second scheduling pass ๐Ÿฆ‹. The scheme argument takes one of these values:
    • no โ€” don't insert NOPs.
    • pad โ€” pad with NOPs any dispatch group that has vacant issue slots, according to the scheduler's grouping.
    • regroup_exact โ€” insert NOPs to force costly dependent insns into separate groups. Insert exactly as many NOPs as needed to force an insn to a new group, according to the estimated processor grouping.
    • number โ€” insert NOPs to force costly dependent insns into separate groups. Insert number NOPs to force an insn to a new group.
  • -mcall-sysv โ€” on System V.4 and embedded PowerPC systems, compiles code using calling conventions that follow the March 1995 draft of the System V Application Binary Interface, PowerPC processor supplement ๐Ÿ’œ. This is the default unless you configured GCC using powerpc-*-eabiaix.
  • -mcall-sysv-eabi, -mcall-eabi โ€” specifies both -mcall-sysv and -meabi ๐ŸŽ€.
  • -mcall-sysv-noeabi โ€” specifies both -mcall-sysv and -mno-eabi ๐ŸŒˆ.
  • -mcall-aixdesc โ€” on System V.4 and embedded PowerPC systems, compiles code for the AIX operating system ๐Ÿงš.
  • -mcall-linux โ€” on System V.4 and embedded PowerPC systems, compiles code for the Linux-based GNU system ๐Ÿซถ.
  • -mcall-freebsd โ€” on System V.4 and embedded PowerPC systems, compiles code for the FreeBSD operating system ๐ŸŒธ.
  • -mcall-netbsd โ€” on System V.4 and embedded PowerPC systems, compiles code for the NetBSD operating system ๐Ÿ“.
  • -mcall-openbsd โ€” on System V.4 and embedded PowerPC systems, compiles code for the OpenBSD operating system โœจ.
  • -mtraceback=traceback_type โ€” selects the type of traceback table ๐Ÿ’–. Valid values for traceback_type are full, part, and no.
  • -maix-struct-return โ€” returns all structures in memory, as specified by the AIX ABI ๐Ÿ‘‘.
  • -msvr4-struct-return โ€” returns structures smaller than 8 bytes in registers, as specified by the SVR4 ABI ๐Ÿ”ฅ.
  • -mabi=abi-type โ€” extends the current ABI with a particular extension, or removes one ๐Ÿ’…. Valid values are altivec, no-altivec, ibmlongdouble, ieeelongdouble, elfv1, and elfv2.
  • -mabi=ibmlongdouble โ€” changes the current ABI to use IBM extended-precision long double ๐ŸŽ€. > โš ๏ธ This is not likely to work if your system defaults to using IEEE extended-precision long double. If you change the long double type from IEEE extended-precision, the compiler will issue a warning unless you use -Wno-psabi. It requires -mlong-double-128 to be enabled.
  • -mabi=ieeelongdouble โ€” changes the current ABI to use IEEE extended-precision long double ๐ŸŒˆ. > โš ๏ธ This is not likely to work if your system defaults to using IBM extended-precision long double. If you change the long double type from IBM extended-precision, the compiler will issue a warning unless you use -Wno-psabi. It requires -mlong-double-128 to be enabled.
  • -mabi=elfv1 โ€” changes the current ABI to use the ELFv1 ABI ๐Ÿงš. This is the default ABI for big-endian PowerPC 64-bit Linux. > ๐Ÿ’€ Overriding the default ABI requires special system support and is likely to fail in spectacular ways.
  • -mabi=elfv2 โ€” changes the current ABI to use the ELFv2 ABI ๐Ÿซถ. This is the default ABI for little-endian PowerPC 64-bit Linux. > ๐Ÿ’€ Overriding the default ABI requires special system support and is likely to fail in spectacular ways.
  • -mgnu-attribute, -mno-gnu-attribute โ€” emits .gnu_attribute assembly directives to set tag/value pairs in a .gnu.attributes section โœจ. Those pairs specify ABI variations in function parameters or return values.
  • -mprototype, -mno-prototype โ€” on System V.4 and embedded PowerPC systems, assumes that all calls to variable argument functions are properly prototyped ๐Ÿฆ‹. Otherwise, the compiler has to insert an instruction before every non-prototyped call to set or clear bit 6 of the condition code register ("CR"), so it can indicate whether floating-point values are passed in the floating-point registers in case the function takes variable arguments. With -mprototype, only calls to prototyped variable argument functions set or clear that bit.
  • -msim โ€” on embedded PowerPC systems, assumes that the startup module is called sim-crt0.o and that the standard C libraries are libsim.a and libc.a ๐Ÿ’œ. This is the default for powerpc-*-eabisim configurations.
  • -mmvme โ€” on embedded PowerPC systems, assumes that the startup module is called crt0.o and that the standard C libraries are libmvme.a and libc.a ๐ŸŽ€.
  • -mads โ€” ๐Ÿ’– okay so on embedded PowerPC systems, this one assumes the startup module is called crt0.o and the standard C libraries are libads.a and libc.a. Iconic setup ๐Ÿงš
  • -myellowknife โ€” ๐Ÿ“ on embedded PowerPC systems, this one assumes the startup module is called crt0.o and the standard C libraries are libyk.a and libc.a. Same energy, different libs ๐Ÿ’…
  • -mvxworks โ€” ๐ŸŒˆ on System V.4 and embedded PowerPC systems, this tells the compiler you're building for a VxWorks system. Main character energy ๐Ÿ‘‘
  • -memb โ€” โœจ on embedded PowerPC systems, this sets the "PPC_EMB" bit in the ELF flags header to signal that eabi extended relocations are being used ๐Ÿฆ‹
  • -meabi, -mno-eabi โ€” ๐ŸŒธ on System V.4 and embedded PowerPC systems, you either do (-meabi) or do not (-mno-eabi) follow the Embedded Applications Binary Interface (EABI), which is basically a set of tweaks on top of the System V.4 specifications. ๐Ÿซถ

With -meabi, the stack is aligned to an 8-byte boundary, a function "__eabi" gets called from main to set up the EABI environment, and the -msdata option can use both r2 and r13 to point to two separate small data areas.

With -mno-eabi, the stack is aligned to a 16-byte boundary, no EABI initialization function is called from main, and the -msdata option only uses r13 to point to a single small data area.

The -meabi option is on by default if you configured GCC using one of the powerpc*-*-eabi* options. โœจ

  • -msdata=eabi โ€” ๐Ÿ’… on System V.4 and embedded PowerPC systems, small initialized "const" global and static data goes in the .sdata2 section, which is pointed to by register r2. Small initialized non-"const" global and static data goes in the .sdata section, pointed to by register r13. Small uninitialized global and static data goes in the .sbss section, which sits right next to .sdata.

Heads up: -msdata=eabi is incompatible with -mrelocatable. It also sets -memb for you ๐Ÿ™ˆ

  • -msdata=sysv โ€” ๐ŸŽ€ on System V.4 and embedded PowerPC systems, small global and static data goes in the .sdata section, pointed to by register r13. Small uninitialized global and static data goes in the .sbss section, which is adjacent to .sdata.

This one is incompatible with -mrelocatable too, so pick your side ๐Ÿ”ฅ

  • -msdata=default, -msdata โ€” ๐ŸŒท on System V.4 and embedded PowerPC systems, if -meabi is used, the code gets compiled the same as -msdata=eabi. Otherwise, it gets compiled the same as -msdata=sysv.
  • -msdata=data โ€” ๐Ÿ‘ on System V.4 and embedded PowerPC systems, small global data goes in the .sdata section, and small uninitialized global data goes in the .sbss section. The catch is that register r13 is not used to address small data. This is the default behaviour unless other -msdata options are used.
  • -msdata=none, -mno-sdata โ€” ๐ŸงŠ on embedded PowerPC systems, all initialized global and static data goes in the .data section, and all uninitialized data goes in the .bss section. No small data shenanigans here ๐Ÿฅฒ
  • -mreadonly-in-sdata โ€” ๐Ÿ“– read-only objects get put in the .sdata section as well. This is the default, so you're already getting it ๐Ÿ’œ
  • -mblock-move-inline-limit=num โ€” ๐Ÿš€ inlines all block moves (like calls to "memcpy" or structure copies) that are less than or equal to num bytes. The minimum value for num is 32 bytes on 32-bit targets and 64 bytes on 64-bit targets. The default value is target-specific, so it depends on your setup ๐Ÿง 
  • -mblock-compare-inline-limit=num โ€” ๐Ÿ” generates non-looping inline code for all block compares (like calls to "memcmp" or structure compares) that are less than or equal to num bytes. If num is 0, all inline expansion (both non-loop and loop) of block compare is disabled. The default value is target-specific ๐Ÿ™ƒ
  • -mblock-compare-inline-loop-limit=num โ€” ๐Ÿ” generates an inline expansion using loop code for all block compares that are less than or equal to num bytes, but greater than the limit for non-loop inline block compare expansion. If the block length isn't constant, at most num bytes get compared before "memcmp" is called to compare the rest of the block. The default value is target-specific ๐ŸŒธ
  • -mstring-compare-inline-limit=num โ€” ๐Ÿงต compares at most num string bytes with inline code. If the difference or end of string isn't found at the end of the inline compare, a call to "strcmp" or "strncmp" takes care of the rest. The default is 64 bytes ๐Ÿฆ‹
  • -G num โ€” ๐Ÿ“ฆ on embedded PowerPC systems, global and static items less than or equal to num bytes go into the small data or BSS sections instead of the normal data or BSS section. By default, num is 8. The -G num switch is also passed to the linker. Every module should be compiled with the same -G num value, bestie, or things get messy ๐Ÿซ 
  • -mregnames, -mno-regnames โ€” ๐Ÿท๏ธ on System V.4 and embedded PowerPC systems, you do (-mregnames) or do not (-mno-regnames) emit register names in the assembly language output using symbolic forms.
  • -mlongcall, -mno-longcall โ€” ๐Ÿ“ž by default, the compiler assumes that all calls are far away, so a longer and more expensive calling sequence is required. This is needed for calls farther than 32 megabytes (33,554,432 bytes) from the current location. A short call only gets generated if the compiler knows the call cannot be that far away.

This setting can be overridden by the shortcall function attribute, or by #pragma longcall(0). โœจ

Some linkers are capable of detecting out-of-range calls and generating glue code on the fly. On these systems, long calls are unnecessary and generate slower code. As of this writing, the AIX linker can do this, as can the GNU linker for PowerPC/64. It is planned to add this feature to the GNU linker for 32-bit PowerPC systems as well.

On PowerPC64 ELFv2 and 32-bit PowerPC systems with newer GNU linkers, GCC can generate long calls using an inline PLT call sequence (see -mpltseq). PowerPC with -mbss-plt and PowerPC64 ELFv1 (big-endian) do not support inline PLT calls. ๐Ÿ’€

On Darwin/PPC systems, #pragma longcall generates jbsr callee, L42, plus a branch island (glue code). The two target addresses represent the callee and the branch island. The Darwin/PPC linker prefers the first address and generates a bl callee if the PPC bl instruction reaches the callee directly. Otherwise, the linker generates bl L42 to call the branch island. The branch island is appended to the body of the calling function, and it computes the full 32-bit address of the callee and jumps to it. ๐Ÿงฉ

On Mach-O (Darwin) systems, this option directs the compiler to emit the glue for every direct call, and the Darwin linker decides whether to use or discard it.

In the future, GCC may ignore all longcall specifications when the linker is known to generate glue. ๐Ÿ”ฎ

  • -mpltseq, -mno-pltseq โ€” ๐Ÿช„ implements (-mpltseq) or does not implement (-mno-pltseq) -fno-plt and long calls using an inline PLT call sequence. This supports lazy linking and long calls to functions in dlopen'd shared libraries.

Inline PLT calls are only supported on PowerPC64 ELFv2 and 32-bit PowerPC systems with newer GNU linkers. They are enabled by default if the support is detected when configuring GCC. In the case of 32-bit PowerPC, they're also enabled if GCC is configured with --enable-secureplt.

Heads up: -mpltseq code and -mbss-plt 32-bit PowerPC relocatable objects may not be linked together. ๐Ÿšซ

  • -mtls-markers, -mno-tls-markers โ€” ๐Ÿณ๏ธโ€๐ŸŒˆ marks (-mtls-markers) or does not mark (-mno-tls-markers) calls to "__tls_get_addr" with a relocation specifying the function argument. The relocation lets the linker reliably associate the function call with the argument setup instructions for TLS optimization, which in turn lets GCC schedule the sequence better ๐Ÿง 
  • -mrecip, -mno-recip โ€” โšก this enables use of the reciprocal estimate and reciprocal square root estimate instructions, with additional Newton-Raphson steps to increase precision. These are used instead of doing a divide, or a square root and divide, for floating-point arguments.

You should use -ffast-math when using -mrecip, or at least -funsafe-math-optimizations, -ffinite-math-only, -freciprocal-math and -fno-trapping-math. ๐Ÿซถ

The throughput of the sequence is generally higher than the throughput of the non-reciprocal instruction. But the precision of the sequence can be decreased by up to 2 ulp (i.e. the inverse of 1.0 equals 0.99999994) for reciprocal square roots. Keep that in mind, bestie ๐Ÿ‘€

  • -mrecip=opt โ€” ๐ŸŽ›๏ธ this controls which reciprocal estimate instructions may be used. opt is a comma-separated list of options, and any of them can be preceded by a ! to invert the option:
    • all โ€” enables all estimate instructions ๐ŸŒŸ
    • default โ€” enables the default instructions, which is equivalent to -mrecip ๐Ÿง
    • none โ€” disables all estimate instructions, which is equivalent to -mno-recip ๐Ÿ™…โ€โ™€๏ธ
    • div โ€” enables the reciprocal approximation instructions for both single and double precision โž—
    • divf โ€” enables the single-precision reciprocal approximation instructions ๐Ÿ”น
    • divd โ€” enables the double-precision reciprocal approximation instructions ๐Ÿ”ท
    • rsqrt โ€” enables the reciprocal square root approximation instructions for both single and double precision ๐ŸŒ™
    • rsqrtf โ€” enables the single-precision reciprocal square root approximation instructions ๐ŸŒ›
    • rsqrtd โ€” enables the double-precision reciprocal square root approximation instructions ๐ŸŒœ

So, for example, -mrecip=all,!rsqrtd enables all of the reciprocal estimate instructions, except for the FRSQRTE, XSRSQRTEDP, and XVRSQRTEDP instructions, which handle the double-precision reciprocal square root calculations. Iykyk ๐Ÿ’…

  • -mrecip-precision, -mno-recip-precision โ€” ๐ŸŽฏ assumes (-mrecip-precision) or does not assume (-mno-recip-precision) that the reciprocal estimate instructions provide higher-precision estimates than the PowerPC ABI mandates. Selecting -mcpu=power6, -mcpu=power7 or -mcpu=power8 automatically selects -mrecip-precision.

The double-precision square root estimate instructions aren't generated by default on low-precision machines, since they don't provide an estimate that converges after three steps. Not me being picky, it's just the math ๐Ÿค“

  • -mveclibabi=type โ€” okay bestie, this one picks the ABI type for vectorizing intrinsics with an external library ๐ŸŽ€ The only type supported right now is mass, which means IBM's Mathematical Acceleration Subsystem (MASS) libraries ๐Ÿ’… When you're generating code for power7, GCC emits calls to these functions:
acosd2, acosf4, acoshd2, acoshf4, asind2, asinf4, asinhd2, asinhf4,
atan2d2, atan2f4, atand2, atanf4, atanhd2, atanhf4, cbrtd2, cbrtf4,
cosd2, cosf4, coshd2, coshf4, erfcd2, erfcf4, erfd2, erff4, exp2d2,
exp2f4, expd2, expf4, expm1d2, expm1f4, hypotd2, hypotf4, lgammad2,
lgammaf4, log10d2, log10f4, log1pd2, log1pf4, log2d2, log2f4, logd2,
logf4, powd2, powf4, sind2, sinf4, sinhd2, sinhf4, sqrtd2, sqrtf4,
tand2, tanf4, tanhd2, tanhf4

But wait, bestie, both -ftree-vectorize and -funsafe-math-optimizations have to be enabled too ๐Ÿ”ฅ And the MASS libraries must be specified at link time ๐Ÿ”—

  • -mfriz, -mno-friz โ€” you can make GCC generate (or not generate) the friz instruction ๐ŸŒธ It's used when -funsafe-math-optimizations is on, to optimize rounding floating-point values to 64-bit integers and back to floats.
โš ๏ธ Heads up: friz does not return the same value if the floating-point number is too large to fit in an integer ๐Ÿ’€
  • -mpointers-to-nested-functions, -mno-pointers-to-nested-functions โ€” this decides whether GCC generates code to load the static chain register (r11) when calling through a pointer on AIX and 64-bit Linux systems โœจ On those systems a function pointer points to a 3-word descriptor that holds the function address, the TOC value to load into register r2, and the static chain value to load into register r11. -mpointers-to-nested-functions is on by default.
๐Ÿšจ Danger zone: if you use -mno-pointers-to-nested-functions, you cannot call through pointers to nested functions, or through pointers to functions compiled in other languages that use the static chain.
  • -msave-toc-indirect, -mno-save-toc-indirect โ€” generate (or don't generate) code that saves the TOC value in the reserved stack location in the function prologue, if the function calls through a pointer on AIX and 64-bit Linux systems ๐Ÿงš If the TOC value isn't saved in the prologue, it gets saved just before the call through the pointer. -mno-save-toc-indirect is the default.
  • -mcompat-align-parm, -mno-compat-align-parm โ€” generate (or don't generate) code that passes structure parameters with a maximum alignment of 64 bits, so it stays compatible with older versions of GCC ๐Ÿ“ Older versions (before 4.9.0) incorrectly didn't align a structure parameter on a 128-bit boundary when that structure had a member needing 128-bit alignment. Newer versions fixed this, but this option lets you make code that works with functions built by the older GCC. -mno-compat-align-parm is the default.
  • -mstack-protector-guard=guard, -mstack-protector-guard-reg=reg, -mstack-protector-guard-offset=offset, -mstack-protector-guard-symbol=symbol โ€” generate stack protection code that uses a canary at guard ๐Ÿ›ก๏ธ The supported locations are global for a global canary, or tls for a per-thread canary in the TLS block (the default with GNU libc version 2.4 or later). With tls, the options -mstack-protector-guard-reg=reg and -mstack-protector-guard-offset=offset tell GCC which register to use as the base register for reading the canary, and what offset from that base to use. The defaults for those come from the relevant ABI. -mstack-protector-guard-symbol=symbol overrides the offset with a symbol reference to a canary in the TLS block.

โœจ RX Options โœจ

These command-line options are defined for RX targets ๐Ÿฆ‹

  • -m64bit-doubles, -m32bit-doubles โ€” makes the double data type 64 bits (-m64bit-doubles) or 32 bits (-m32bit-doubles) in size ๐ŸŒˆ The default is -m32bit-doubles, and that's because RX floating-point hardware only works on 32-bit values.
  • -fpu, -nofpu โ€” enables (-fpu) or disables (-nofpu) the use of RX floating-point hardware ๐Ÿ’– It's enabled by default for the RX600 series and disabled for the RX200 series. Floating-point instructions are only generated for 32-bit floating-point values, though, so the FPU hardware isn't used for doubles if -m64bit-doubles is used.
Note: if -fpu is enabled, then -funsafe-math-optimizations is also enabled automatically ๐Ÿซถ That's because the RX FPU instructions are themselves unsafe.
  • -mcpu=name โ€” selects the type of RX CPU to target ๐Ÿ‘‘ Three types are supported: the generic RX600 and RX200 series hardware, and the specific RX610 CPU. The default is RX600. The only difference between RX600 and RX610 is that the RX610 doesn't support the MVTIPL instruction. The RX200 series doesn't have a hardware floating-point unit, so -nofpu is enabled by default when this type is selected.
  • -mbig-endian-data, -mlittle-endian-data โ€” stores data (but not code) in the big-endian format ๐Ÿฌ The default is -mlittle-endian-data, meaning data is stored in the little-endian format.
  • -msmall-data-limit=N โ€” specifies the maximum size in bytes of global and static variables that can be placed into the small data area ๐Ÿ”ฅ Using the small data area can lead to smaller and faster code, but the area is limited in size, and it's up to you to make sure it doesn't overflow ๐Ÿ˜ฌ Also, when the small data area is used, one of the RX's registers (usually r13) is reserved to point to this area, so the compiler can't use it anymore. This could make code slower and/or larger if variables get pushed onto the stack instead of living in that register.
Common variables (variables that haven't been initialized) and constants are NOT placed into the small data area, because they get assigned to other sections in the output executable.

The default value is zero, which disables this feature ๐Ÿ™ˆ It's not enabled by default with higher optimization levels (-O2 etc.) because of the potentially detrimental effects of reserving a register. It's up to you to experiment and see whether it benefits your program. See the description of the -mpid option for how the actual register holding the small data area pointer gets chosen.

  • -msim, -mno-sim โ€” uses the simulator runtime ๐Ÿงช The default is to use the libgloss board-specific runtime.
  • -mas100-syntax, -mno-as100-syntax โ€” when generating assembler output, uses a syntax that's compatible with Renesas's AS100 assembler ๐Ÿ’… This syntax can also be handled by the GAS assembler, but it has some restrictions, so it isn't generated by default.
  • -mmax-constant-size=N โ€” specifies the maximum size, in bytes, of a constant that can be used as an operand in an RX instruction ๐Ÿฆ‹ The RX instruction set does allow constants up to 4 bytes long, but a longer value means a longer instruction. So sometimes it's beneficial to restrict the size of constants used in instructions. Constants that are too big get placed into a constant pool instead and are referenced via register indirection. The value N can be between 0 and 4. A value of 0 (the default) or 4 means constants of any size are allowed.
  • -mrelax โ€” enables linker relaxation ๐Ÿงš This is a process where the linker tries to shrink your program by finding shorter versions of various instructions. It's disabled by default.
  • -mint-register=N โ€” specifies the number of registers to reserve for fast interrupt handler functions โšก The value N can be between 0 and 4. A value of 1 means register r13 is reserved for the exclusive use of fast interrupt handlers. A value of 2 reserves r13 and r12. A value of 3 reserves r13, r12 and r11, and a value of 4 reserves r13 through r10. A value of 0, the default, doesn't reserve any registers.
  • -msave-acc-in-interrupts โ€” specifies that interrupt handler functions should preserve the accumulator register ๐ŸŒธ This is only necessary if normal code might use the accumulator register, for example because it does 64-bit multiplications. The default is to ignore the accumulator, since that makes the interrupt handlers faster.
  • -mpid, -mno-pid โ€” enables the generation of position independent data ๐Ÿ’œ When enabled, any access to constant data is done via an offset from a base address held in a register. This lets the location of constant data be determined at run time without the executable having to be relocated, which is a big win for embedded apps with tight memory constraints. Data that can be modified isn't affected by this option.
Heads up: using this feature reserves a register, usually r13, for the constant data base address ๐Ÿ˜ญ That can result in slower and/or larger code, especially in complicated functions.

The actual register chosen to hold the constant data base address depends on whether the -msmall-data-limit and/or the -mint-register command-line options are enabled. Starting with register r13 and proceeding downwards, registers are allocated first to satisfy the requirements of -mint-register, then -mpid, and finally -msmall-data-limit. So it's possible for the small data area register to be r8 if both -mint-register=4 and -mpid are specified on the command line.

By default this feature is not enabled, and the default can be restored via the -mno-pid command-line option.

  • -mno-warn-multiple-fast-interrupts, -mwarn-multiple-fast-interrupts โ€” prevents GCC from issuing a warning message if it finds more than one fast interrupt handler while compiling a file ๐ŸŽ€ The default is to issue a warning for each extra fast interrupt handler found, because the RX only supports one such interrupt.
  • -mallow-string-insns, -mno-allow-string-insns โ€” okay so this pair switches the string manipulation instructions on or off: SMOVF, SCMPU, SMOVB, SMOVU, SUNTIL, SWHILE, and also the RMPA instruction ๐Ÿงš. These can prefetch data, which is not safe if you're touching an I/O register ๐Ÿ’€ (see section 12.2.7 of the RX62N Group User's Manual for more info).
    • The default is to allow these instructions. GCC can't reliably catch every case where a string instruction might hit an I/O register, so turning them off automatically isn't possible ๐Ÿ˜ญ Instead, it's on the programmer to use -mno-allow-string-insns if the program accesses I/O space.
    • When the instructions are enabled, GCC defines the C preprocessor symbol __RX_ALLOW_STRING_INSNS__. Otherwise it defines __RX_DISALLOW_STRING_INSNS__ ๐ŸŒธ.
  • -mjsr, -mno-jsr โ€” use only (or not only) JSR instructions to access functions ๐Ÿฆ‹. This is handy when your code size goes past the range of BSR instructions. Note that -mno-jsr doesn't mean "don't use JSR" โ€” it just means any type of branch can be used.

Note: the generic GCC command-line option -ffixed-reg has special vibes for the RX port when it's paired with the interrupt function attribute ๐Ÿ‘‘. That attribute marks a function meant to handle fast interrupts. GCC makes sure it only uses the registers r10, r11, r12 and/or r13, and only if the normal use of those registers has been restricted via the -ffixed-reg or -mint-register command-line options.


โœจ S/390 and zSeries Options โœจ

These are the -m options defined for the S/390 and zSeries architecture ๐Ÿ’œ.

  • -mhard-float, -msoft-float โ€” use (or don't use) the hardware floating-point instructions and registers for floating-point operations. With -msoft-float, functions in libgcc.a do the floating-point work. With -mhard-float, the compiler generates IEEE floating-point instructions. This is the default ๐Ÿ’–.
  • -mhard-dfp, -mno-hard-dfp โ€” use (or don't use) the hardware decimal-floating-point instructions for decimal-floating-point operations. With -mno-hard-dfp, functions in libgcc.a handle the decimal-floating-point operations. With -mhard-dfp, the compiler generates decimal-floating-point hardware instructions. This is the default for -march=z9-ec or higher โœจ.
  • -mlong-double-64, -mlong-double-128 โ€” these control the size of the long double type. A size of 64 bits makes long double equivalent to double. This is the default ๐Ÿ“.
  • -mbackchain, -mno-backchain โ€” store (or don't store) the address of the caller's frame as the backchain pointer in the callee's stack frame. A backchain may be needed for debugging with tools that don't understand DWARF call frame information ๐Ÿ”.
    • When -mno-packed-stack is in effect, the backchain pointer is stored at the bottom of the stack frame. When -mpacked-stack is in effect, the backchain goes into the topmost word of the 96/160 byte register save area.
    • In general, code compiled with -mbackchain is call-compatible with code compiled with -mmo-backchain. However, using the backchain for debugging usually means the whole binary has to be built with -mbackchain.
    • The default is to not maintain the backchain.
Heads up bestie ๐Ÿšจ: the combination of -mbackchain, -mpacked-stack and -mhard-float is not supported. If you're building a Linux kernel, use -msoft-float.
  • -mpacked-stack, -mno-packed-stack โ€” use (or don't use) the packed stack layout ๐Ÿงš.
    • With -mno-packed-stack, the compiler uses all fields of the 96/160 byte register save area only for their default purpose. Unused fields still take up stack space.
    • With -mpacked-stack, register save slots are densely packed at the top of the register save area, and unused space gets reused for other purposes. That means more efficient use of the available stack space. However, when -mbackchain is also in effect, the topmost word of the save area is always used to store the backchain, and the return address register is always saved two words below the backchain.
    • As long as the stack frame backchain isn't used, code generated with -mpacked-stack is call-compatible with code generated with -mno-packed-stack. Some non-FSF releases of GCC 2.95 for S/390 or zSeries generated code that uses the stack frame backchain at run time, not just for debugging. That code is not call-compatible with code compiled with -mpacked-stack.
    • The default is to not use the packed stack layout.
Same energy here ๐Ÿšจ: the combination of -mbackchain, -mpacked-stack and -mhard-float is not supported. To build a Linux kernel, use -msoft-float.
  • -msmall-exec, -mno-small-exec โ€” generate (or don't generate) code using the bras instruction for subroutine calls. This only works reliably if the total executable size doesn't go over 64k ๐Ÿ™ˆ. The default is to use the basr instruction instead, which doesn't have this limitation.
  • -m64, -m31 โ€” with -m31, generate code compliant with the GNU/Linux for S/390 ABI. With -m64, generate code compliant with the GNU/Linux for zSeries ABI. This lets GCC generate 64-bit instructions in particular ๐ŸŒˆ. For the s390 targets, the default is -m31, while the s390x targets default to -m64.
  • -mzarch, -mesa โ€” with -mzarch, generate code using the instructions available on z/Architecture. With -mesa, generate code using the instructions available on ESA/390. Note that -mesa is not possible with -m64. When generating code compliant with the GNU/Linux for S/390 ABI, the default is -mesa. When generating code compliant with the GNU/Linux for zSeries ABI, the default is -mzarch ๐Ÿ’….
  • -mhtm, -mno-htm โ€” the -mhtm option enables a set of builtins that make use of instructions from the transactional execution facility, introduced with the IBM zEnterprise EC12 machine generation S/390 System z Built-in Functions. -mhtm is enabled by default when using -march=zEC12 ๐Ÿฆ‹.
  • -mvx, -mno-vx โ€” with -mvx, generate code using the instructions from the vector extension facility introduced with the IBM z13 machine generation. This option changes the ABI for some vector type values when it comes to alignment and calling conventions. If vector type values are used in an ABI-relevant context, a GAS .gnu_attribute command gets added to mark the resulting binary with the ABI used. -mvx is enabled by default when using -march=z13 โœจ.
  • -mzvector, -mno-zvector โ€” -mzvector enables vector language extensions and builtins using instructions from the vector extension facility introduced with the IBM z13 machine generation ๐Ÿ”ฅ. It adds support for vector as a keyword to define vector type variables and arguments. vector is only available when GNU extensions are enabled. It won't be expanded when requesting strict standard compliance, e.g. with -std=c99. On top of the GCC low-level builtins, -mzvector enables a set of builtins added for compatibility with AltiVec-style implementations like Power and Cell. To use these builtins, the header file vecintrin.h needs to be included. -mzvector is disabled by default.
  • -mmvcle, -mno-mvcle โ€” generate (or don't generate) code using the mvcle instruction to perform block moves. With -mno-mvcle, a mvc loop is used instead. This is the default unless optimizing for size ๐ŸŽ€.
  • -mdebug, -mno-debug โ€” print (or don't print) additional debug information when compiling. The default is to not print debug information ๐Ÿ™ˆ.
  • -march=cpu-type โ€” generate code that runs on cpu-type, which is the name of a system representing a certain processor type. Possible values for cpu-type are z900/arch5, z990/arch6, z9-109, z9-ec/arch7, z10/arch8, z196/arch9, zEC12, z13/arch11, z14/arch12, and native ๐Ÿงš.
    • The default is -march=z900.
    • Specifying native as the cpu type can be used to select the best architecture option for the host processor. -march=native has no effect if GCC doesn't recognize the processor.
  • -mtune=cpu-type โ€” tune everything applicable about the generated code to cpu-type, except for the ABI and the set of available instructions ๐Ÿ’œ. The list of cpu-type values is the same as for -march. The default is the value used for -march.
  • -mtpf-trace, -mno-tpf-trace โ€” generate code that adds (or doesn't add) TPF OS-specific branches to trace routines in the operating system. This option is off by default, even when compiling for the TPF OS ๐Ÿ‘‘.
  • -mfused-madd, -mno-fused-madd โ€” generate code that uses (or doesn't use) the floating-point multiply and accumulate instructions. These instructions are generated by default if hardware floating point is used โญ.
  • -mwarn-framesize=framesize โ€” emit a warning if the current function exceeds the given frame size. Because this is a compile-time check, it doesn't need to be a real problem when the program runs. It's meant to flag functions that most probably cause a stack overflow ๐Ÿ˜ญ. It's useful in an environment with a limited stack size, e.g. the Linux kernel.
  • -mwarn-dynamicstack โ€” emit a warning if the function calls alloca or uses dynamically-sized arrays. This is generally a bad idea with a limited stack size ๐Ÿ’€.
  • -mstack-guard=stack-guard, -mstack-size=stack-size โ€” okay so these make the S/390 backend sneak extra instructions into the function prologue ๐Ÿงš Once they're on, a trap fires when the stack gets stack-guard bytes above stack-size. (Remember the S/390 stack grows downward, so the math is flipped ๐Ÿ™ˆ) If you skip stack-guard, GCC picks the smallest power of 2 that's bigger than the compiled function's frame size. These are meant for chasing down stack overflow bugs ๐Ÿ› The extra code adds only a little overhead, so you can even use it on production-like systems without a big performance hit ๐Ÿ’… The values have to be exact powers of 2, stack-size has to be bigger than stack-guard, and it can't go past 64k. To be efficient, the extra code assumes the stack starts at an address aligned to the stack-size value. And stack-guard only works if you're also using stack-size โœจ
  • -mhotpatch=pre-halfwords,post-halfwords โ€” if this is enabled, a "hot-patching" function prologue gets generated for every function in the compilation unit ๐Ÿ”ฅ The function label gets prepended with the given number of two-byte NOP instructions (pre-halfwords, max 1000000). After the label, 2 * post-halfwords bytes get tacked on, using the biggest NOP-like instructions the architecture allows (max 1000000).

If both arguments are zero, hotpatching is disabled ๐Ÿ™…โ€โ™€๏ธ

This option can be overridden for individual functions with the hotpatch attribute ๐ŸŽ€


๐Ÿ’– Score Options

These options are defined for Score implementations ๐ŸŒธ

  • -meb โ€” compile code for big-endian mode. This is the default ๐Ÿ’œ
  • -mel โ€” compile code for little-endian mode ๐Ÿฆ‹
  • -mnhwloop โ€” disable generation of bcnz instructions ๐Ÿ™ˆ
  • -muls โ€” enable generation of unaligned load and store instructions โœจ
  • -mmac โ€” enable the use of multiply-accumulate instructions. Disabled by default ๐Ÿ’…
  • -mscore5 โ€” target the SCORE5 architecture ๐ŸŒˆ
  • -mscore5u โ€” target the SCORE5U architecture ๐ŸŒˆ
  • -mscore7 โ€” target the SCORE7 architecture. This is the default ๐Ÿ‘‘
  • -mscore7d โ€” target the SCORE7D architecture ๐Ÿงš

๐Ÿฆ‹ SH Options

These -m options are defined for the SH implementations ๐Ÿซถ

  • -m1 โ€” generate code for the SH1 ๐Ÿ“
  • -m2 โ€” generate code for the SH2 ๐Ÿ“
  • -m2e โ€” generate code for the SH2e ๐Ÿ“
  • -m2a-nofpu โ€” generate code for the SH2a without an FPU, or for an SH2a-FPU in a way that the floating-point unit isn't used ๐Ÿ’€
  • -m2a-single-only โ€” generate code for the SH2a-FPU, in a way that no double-precision floating-point operations get used ๐ŸŒธ
  • -m2a-single โ€” generate code for the SH2a-FPU, assuming the floating-point unit is in single-precision mode by default ๐ŸŒธ
  • -m2a โ€” generate code for the SH2a-FPU, assuming the floating-point unit is in double-precision mode by default ๐ŸŒธ
  • -m3 โ€” generate code for the SH3 ๐Ÿ“
  • -m3e โ€” generate code for the SH3e ๐Ÿ“
  • -m4-nofpu โ€” generate code for the SH4 without a floating-point unit ๐Ÿ’€
  • -m4-single-only โ€” generate code for the SH4 with a floating-point unit that only supports single-precision arithmetic ๐ŸŒธ
  • -m4-single โ€” generate code for the SH4, assuming the floating-point unit is in single-precision mode by default ๐ŸŒธ
  • -m4 โ€” generate code for the SH4 ๐Ÿ“
  • -m4-100 โ€” generate code for SH4-100 ๐Ÿฆ‹
  • -m4-100-nofpu โ€” generate code for SH4-100 in a way that the floating-point unit isn't used ๐Ÿ’€
  • -m4-100-single โ€” generate code for SH4-100, assuming the floating-point unit is in single-precision mode by default ๐ŸŒธ
  • -m4-100-single-only โ€” generate code for SH4-100 in a way that no double-precision floating-point operations get used ๐ŸŒธ
  • -m4-200 โ€” generate code for SH4-200 ๐Ÿฆ‹
  • -m4-200-nofpu โ€” generate code for SH4-200, in a way that the floating-point unit isn't used ๐Ÿ’€
  • -m4-200-single โ€” generate code for SH4-200, assuming the floating-point unit is in single-precision mode by default ๐ŸŒธ
  • -m4-200-single-only โ€” generate code for SH4-200 in a way that no double-precision floating-point operations get used ๐ŸŒธ
  • -m4-300 โ€” generate code for SH4-300 ๐Ÿฆ‹
  • -m4-300-nofpu โ€” generate code for SH4-300, in a way that the floating-point unit isn't used ๐Ÿ’€
  • -m4-300-single โ€” generate code for SH4-300 in a way that no double-precision floating-point operations get used ๐ŸŒธ
  • -m4-300-single-only โ€” generate code for SH4-300 in a way that no double-precision floating-point operations get used ๐ŸŒธ
  • -m4-340 โ€” generate code for SH4-340 (no MMU, no FPU) ๐Ÿฆ‹
  • -m4-500 โ€” generate code for SH4-500 (no FPU). It passes -isa=sh4-nofpu to the assembler ๐Ÿงš
  • -m4a-nofpu โ€” generate code for the SH4al-dsp, or for an SH4a in a way that the floating-point unit isn't used ๐Ÿ’€
  • -m4a-single-only โ€” generate code for the SH4a in a way that no double-precision floating-point operations get used ๐ŸŒธ
  • -m4a-single โ€” generate code for the SH4a, assuming the floating-point unit is in single-precision mode by default ๐ŸŒธ
  • -m4a โ€” generate code for the SH4a ๐Ÿ“
  • -m4al โ€” same as -m4a-nofpu, except it implicitly passes -dsp to the assembler. GCC doesn't generate any DSP instructions at the moment ๐Ÿคทโ€โ™€๏ธ
  • -mb โ€” compile code for the processor in big-endian mode ๐Ÿ’œ
  • -ml โ€” compile code for the processor in little-endian mode ๐Ÿฆ‹
  • -mdalign โ€” align doubles at 64-bit boundaries. Heads up, this changes the calling conventions, so some functions from the standard C library won't work unless you recompile them first with -mdalign ๐Ÿ˜ญ
  • -mrelax โ€” shorten some address references at link time, when possible. This uses the linker option -relax โœจ
  • -mbigtable โ€” use 32-bit offsets in switch tables. The default is 16-bit offsets ๐Ÿงš
  • -mbitops โ€” enable the use of bit manipulation instructions on SH2A ๐Ÿ’…
  • -mfmovd โ€” enable the use of the fmovd instruction. Check -mdalign for alignment constraints ๐Ÿซถ
  • -mrenesas โ€” comply with the calling conventions defined by Renesas ๐Ÿ‘‘
  • -mno-renesas โ€” comply with the calling conventions GCC used before the Renesas conventions existed. This is the default for all targets of the SH toolchain ๐Ÿ‘‘
  • -mnomacsave โ€” mark the MAC register as call-clobbered, even if -mrenesas is given ๐Ÿ™ˆ
  • -mieee, -mno-ieee โ€” control the IEEE compliance of floating-point comparisons, which affects how unordered comparison results get handled ๐Ÿง By default -mieee is implicitly enabled. If -ffinite-math-only is enabled, -mno-ieee gets implicitly set, which makes floating-point greater-equal and less-equal comparisons faster. You can override the implicit settings by specifying either -mieee or -mno-ieee ๐Ÿ”ฅ
  • -minline-ic_invalidate โ€” inline code that invalidates instruction cache entries after setting up nested function trampolines. This has no effect if -musermode is in effect and the selected code generation option (e.g. -m4) doesn't allow the use of the icbi instruction ๐Ÿ™ƒ If the selected code generation option doesn't allow icbi and -musermode isn't in effect, the inlined code manipulates the instruction cache address array directly with an associative write.
โš ๏ธ That last bit is a big deal: it requires privileged mode at run time, and it fails if the cache line had been mapped via the TLB and has since become unmapped. Proceed with caution, bestie ๐Ÿ˜ญ
  • -misize โ€” dump instruction size and location in the assembly code ๐Ÿ“
  • -mpadstruct โ€” this option is deprecated ๐Ÿšซ It pads structures to a multiple of 4 bytes, which is incompatible with the SH ABI.
  • -matomic-model=model โ€” sets the model of atomic operations, plus additional parameters, as a comma separated list ๐Ÿ’œ For details on the atomic built-in functions, see __atomic Builtins. These models and parameters are supported:
    • none โ€” disable compiler-generated atomic sequences and emit library calls for atomic operations. This is the default if the target isn't sh*-*-linux* ๐Ÿ™…โ€โ™€๏ธ
    • soft-gusa โ€” generate GNU/Linux compatible gUSA software atomic sequences for the atomic built-in functions ๐Ÿงš These sequences need extra support from the system's interrupt/exception handling code, and they're only suitable for SH3* and SH4* single-core systems. This option is enabled by default when the target is sh*-*-linux* and SH3* or SH4*. When the target is SH4A, this option also partially uses the hardware atomic instructions movli.l and movco.l to make more efficient code, unless strict is specified ๐Ÿ”ฅ
    • soft-tcb โ€” generate software atomic sequences that use a variable in the thread control block ๐Ÿฆ‹ This is a variation of the gUSA sequences that can also be used on SH1* and SH2* targets. These sequences need extra support from the system's interrupt/exception handling code and are only suitable for single-core systems. When using this model, the gbr-offset= parameter has to be specified as well ๐Ÿ’…
    • soft-imask โ€” generate software atomic sequences that temporarily disable interrupts by setting SR.IMASK = 1111 ๐ŸŒˆ This model only works when the program runs in privileged mode, and it's only suitable for single-core systems. You don't need extra support from the system's interrupt/exception handling code for it. This model is enabled by default when the target is sh*-*-linux* and SH1* or SH2* ๐Ÿ‘‘
    • hard-llcs โ€” generate hardware atomic sequences using only the movli.l and movco.l instructions ๐Ÿ’œ This is only available on SH4A and is suitable for multi-core systems. Since the hardware instructions only support 32-bit atomic variable access, 8- and 16-bit variable access is emulated with 32-bit accesses. Code compiled with this option is also compatible with other software atomic model interrupt/exception handling systems if it runs on an SH4A system. You don't need extra support from the system's interrupt/exception handling code for this model ๐Ÿซถ
  • gbr-offset= โ€” okay so this one sets the byte offset of the variable inside the thread control block structure that the generated atomic sequences use, but only when you've picked the soft-tcb model ๐Ÿงš. For every other model it gets ignored completely ๐Ÿซ . The value has to be an integer multiple of 4 and sit somewhere in the range 0-1020 ๐Ÿ’….
  • strict โ€” this one stops you from mixing multiple atomic models, even when they'd be compatible ๐Ÿ™…โ€โ™€๏ธ. It makes the compiler generate atomic sequences of just the model you asked for ๐Ÿ’–.
  • -mtas โ€” generates the tas.b opcode for __atomic_test_and_set ๐Ÿ”ฅ. Heads up, bestie: depending on your hardware and software setup, this can actually drag down overall performance because of the operand cache line flushes that tas.b implies ๐Ÿ˜ญ. On multi-core SH4A processors you have to be extra careful with tas.b, since it can cause data corruption with certain cache configurations ๐Ÿ’€.
  • -mprefergot โ€” when you're generating position-independent code, function calls go through the Global Offset Table instead of the Procedure Linkage Table ๐ŸŒธ.
  • -musermode, -mno-usermode โ€” -musermode means the compiler won't generate privileged mode code, and -mno-usermode means it's allowed ๐Ÿ”. Using -musermode also implies -mno-inline-ic_invalidate if the inlined code wouldn't work in user mode ๐Ÿ™ˆ. -musermode is the default when the target is sh*-*-linux* โœจ. If the target is SH1* or SH2*, -musermode does nothing, since there's no user mode on those ๐Ÿคทโ€โ™€๏ธ.
  • -multcost=number โ€” sets the cost the compiler should assume for a multiply insn ๐Ÿงฎ.
  • -mdiv=strategy โ€” picks the division strategy for integer division operations ๐Ÿ‘‘. strategy can be one of:
    • call-div1 โ€” calls a library function that uses the single-step division instruction div1 to do the job. Division by zero gives an unspecified result and doesn't trap. This is the default except for SH4, SH2A, and SHcompact ๐Ÿง.
    • call-fp โ€” calls a library function that does the operation in double precision floating point. Division by zero causes a floating-point exception ๐Ÿ’ฅ. This is the default for SHcompact with FPU. Specifying it for targets without a double precision FPU defaults to call-div1 ๐Ÿซถ.
    • call-table โ€” calls a library function that uses a lookup table for small divisors and the div1 instruction with case distinction for larger divisors ๐Ÿ“–. Division by zero gives an unspecified result and doesn't trap. This is the default for SH4. Specifying it for targets without dynamic shift instructions defaults to call-div1 ๐ŸŒˆ.

If you don't specify a division strategy, the compiler picks the default based on your current target ๐ŸŽฏ. For SH2A, the default is to use the divs and divu instructions instead of library function calls โšก.

  • -maccumulate-outgoing-args โ€” reserves space once for outgoing arguments in the function prologue, rather than around each call ๐Ÿง . It's generally great for performance and size ๐Ÿ’ช. It's also needed for unwinding, so the stack frame doesn't get changed around conditional code ๐Ÿฆ‹.
  • -mdivsi3_libfunc=name โ€” sets the name of the library function used for 32-bit signed division to name ๐ŸŽ€. This only changes the name used in the call division strategies. The compiler still expects the same sets of input, output, and clobbered registers as if this option weren't there ๐Ÿ’œ.
  • -mfixed-range=register-range โ€” generates code that treats the given register range as fixed registers ๐Ÿ”’. A fixed register is one the register allocator isn't allowed to use, which makes this super useful when compiling kernel code ๐Ÿ› ๏ธ. A register range is written as two registers separated by a dash, and you can separate multiple ranges with a comma ๐Ÿงฉ.
  • -mbranch-cost=num โ€” tells the compiler to assume num is the cost of a branch instruction ๐ŸŒฟ. Higher numbers make the compiler try to generate more branch-free code when it can ๐Ÿ™Œ. If you don't specify it, the value is picked based on the processor type you're compiling for ๐Ÿ–ฅ๏ธ.
  • -mzdcbranch, -mno-zdcbranch โ€” assumes (or doesn't assume) that the zero displacement conditional branch instructions bt and bf are fast ๐ŸŽ๏ธ. With -mzdcbranch, the compiler prefers zero displacement branch code sequences. This is enabled by default for SH4 and SH4A, and you can explicitly turn it off with -mno-zdcbranch ๐Ÿšซ.
  • -mcbranch-force-delay-slot โ€” forces the use of delay slots for conditional branches, stuffing the delay slot with a nop if no suitable instruction can be found ๐Ÿ˜ค. It's disabled by default. You can turn it on to work around hardware bugs found in the original SH7055 ๐Ÿ›.
  • -mfused-madd, -mno-fused-madd โ€” generates code that does (or doesn't) use the floating-point multiply and accumulate instructions ๐Ÿงฎ. These get generated by default if hardware floating point is in use. The machine-dependent -mfused-madd is now mapped to the machine-independent -ffp-contract=fast, and -mno-fused-madd is mapped to -ffp-contract=off ๐Ÿ”„.
  • -mfsca, -mno-fsca โ€” allows (or disallows) the compiler to emit the fsca instruction for sine and cosine approximations ๐Ÿ“. The option -mfsca must be used together with -funsafe-math-optimizations. It's enabled by default for SH4A. Using -mno-fsca disables sine and cosine approximations, even if -funsafe-math-optimizations is in effect ๐Ÿ™…โ€โ™€๏ธ.
  • -mfsrra, -mno-fsrra โ€” allows (or disallows) the compiler to emit the fsrra instruction for reciprocal square root approximations ๐ŸŒŸ. The option -mfsrra must be used together with -funsafe-math-optimizations and -ffinite-math-only. It's enabled by default for SH4A. Using -mno-fsrra disables reciprocal square root approximations, even if -funsafe-math-optimizations and -ffinite-math-only are in effect ๐Ÿšซ.
  • -mpretend-cmove โ€” prefers zero-displacement conditional branches for conditional move instruction patterns ๐Ÿ“. This can result in faster code on the SH4 processor ๐Ÿš€.
  • -mfdpic โ€” generates code using the FDPIC ABI ๐ŸŒท.

Solaris 2 Options

These -m options are supported on Solaris 2 ๐ŸŒž:

  • -mclear-hwcap โ€” tells the compiler to remove the hardware capabilities generated by the Solaris assembler ๐Ÿงน. This is only necessary when object files use ISA extensions that the current machine doesn't support, but still check at runtime whether or not to use them ๐Ÿ”.
  • -mimpure-text โ€” used in addition to -shared, this tells the compiler not to pass -z text to the linker when linking a shared object ๐Ÿฆ„. With it, you can link position-dependent code into a shared object ๐Ÿ’….
Heads up: -mimpure-text suppresses the "relocations remain against allocatable but non-writable sections" linker error message. However, the necessary relocations trigger copy-on-write, so the shared object is not actually shared across processes ๐Ÿ˜ฌ. Instead of using -mimpure-text, you should compile all source code with -fpic or -fPIC ๐Ÿซถ.

These switches are supported in addition to the above on Solaris 2 โœจ:

  • -pthreads โ€” this is a synonym for -pthread ๐Ÿงต.

SPARC Options

These -m options are supported on the SPARC ๐Ÿฆ‹:

  • -mno-app-regs, -mapp-regs โ€” -mapp-regs generates output using the global registers 2 through 4, which the SPARC SVR4 ABI reserves for applications ๐ŸŽ€. Just like global register 1, each of global registers 2 through 4 is then treated as an allocable register that gets clobbered by function calls. This is the default ๐Ÿ’œ.

To be fully SVR4 ABI-compliant (with some performance loss), use -mno-app-regs. You should compile libraries and system software with this option ๐Ÿ› ๏ธ.

  • -mflat, -mno-flat โ€” with -mflat, the compiler doesn't generate save/restore instructions and uses a "flat" or single register window model ๐ŸชŸ. This model is compatible with the regular register window model. The local registers and the input registers (0--5) are still treated as "call-saved" registers and get saved on the stack as needed ๐Ÿ“š.

With -mno-flat (the default), the compiler generates save/restore instructions, except for leaf functions. This is the normal operating mode ๐ŸŒธ.

  • -mfpu, -mhard-float โ€” generates output containing floating-point instructions โšก. This is the default ๐Ÿ’–.
  • -mno-fpu, -msoft-float โ€” generates output containing library calls for floating point ๐Ÿ“ž.
Warning: the requisite libraries are not available for all SPARC targets ๐Ÿšจ. Normally the facilities of the machine's usual C compiler are used, but this can't be done directly in cross-compilation. You must make your own arrangements to provide suitable library functions for cross-compilation ๐Ÿ™ƒ. The embedded targets sparc-*-aout and sparclite-*-* do provide software floating-point support ๐Ÿงก.

-msoft-float changes the calling convention in the output file, so it's only useful if you compile all of a program with this option ๐Ÿ”. In particular, you need to compile libgcc.a, the library that comes with GCC, with -msoft-float for this to work ๐Ÿงฉ.

  • -mhard-quad-float โ€” generates output containing quad-word (long double) floating-point instructions ๐Ÿ’Ž.
  • -msoft-quad-float โ€” generates output containing library calls for quad-word (long double) floating-point instructions ๐Ÿ“ฆ. The functions called are the ones specified in the SPARC ABI. This is the default ๐Ÿซก.

As of this writing, there are no SPARC implementations with hardware support for the quad-word floating-point instructions ๐Ÿ˜ญ. They all invoke a trap handler for one of these instructions, and then the trap handler emulates the effect of the instruction. Because of that trap handler overhead, this is much slower than calling the ABI library routines ๐Ÿข. So the -msoft-quad-float option is the default ๐ŸŒˆ.

  • -mno-unaligned-doubles, -munaligned-doubles โ€” -mno-unaligned-doubles assumes that doubles have 8-byte alignment, and that's the default ๐Ÿ“.

So with -munaligned-doubles, GCC only assumes doubles have 8-byte alignment if they're tucked inside another type or have an absolute address. Otherwise it assumes 4-byte alignment ๐Ÿ“. Turning it on dodges some rare compatibility drama with code from other compilers, but it's not the default because it costs performance, especially for floating-point code ๐Ÿ˜ญ.

  • -muser-mode, -mno-user-mode โ€” Stops GCC from generating code that can only run in supervisor mode ๐Ÿ”’. This only matters for the casa instruction emitted for the LEON3 processor. This is the default, so you're already set ๐Ÿ’–.
  • -mfaster-structs, -mno-faster-structs โ€” With -mfaster-structs, the compiler assumes structures should have 8-byte alignment โšก. That unlocks pairs of ldd and std instructions for copies in structure assignment, instead of twice as many ld and st pairs. Ngl, it's a speed glow-up, but the changed alignment directly violates the SPARC ABI ๐Ÿ’€.
Only use this on targets where the developer acknowledges that the resulting code isn't directly in line with the rules of the ABI. It's a "know what you're doing" option, bestie ๐Ÿ™ˆ.
  • -mstd-struct-return, -mno-std-struct-return โ€” With -mstd-struct-return, the compiler adds checking code to functions that return structures or unions ๐Ÿง. That code catches size mismatches between the two sides of a function call, as per the 32-bit ABI. The default is -mno-std-struct-return. This option has no effect in 64-bit mode.
  • -mlra, -mno-lra โ€” Turns on Local Register Allocation ๐Ÿง . This has been the default for SPARC since GCC 7, so if you want the old Reload vibes back, you have to pass -mno-lra ๐Ÿ•ฐ๏ธ.
  • -mcpu=cpu_type โ€” Sets the instruction set, register set, and instruction scheduling parameters for the machine type cpu_type ๐ŸŽ€. The supported values are v7, cypress, v8, supersparc, hypersparc, leon, leon3, leon3v7, sparclite, f930, f934, sparclite86x, sparclet, tsc701, v9, ultrasparc, ultrasparc3, niagara, niagara2, niagara3, niagara4, niagara7 and m8.

Native Solaris and GNU/Linux toolchains also accept native, which picks the best architecture option for your host processor โœจ. -mcpu=native does nothing if GCC doesn't recognize the processor ๐Ÿคทโ€โ™€๏ธ.

Default instruction scheduling parameters get used for values that pick an architecture rather than a specific implementation. Those are v7, v8, sparclite, sparclet and v9.

Here's the lowdown on each architecture and the implementations that live under it ๐Ÿ“‹:

  • v7 โ€” cypress, leon3v7
  • v8 โ€” supersparc, hypersparc, leon, leon3
  • sparclite โ€” f930, f934, sparclite86x
  • sparclet โ€” tsc701
  • v9 โ€” ultrasparc, ultrasparc3, niagara, niagara2, niagara3, niagara4, niagara7, m8

By default (unless configured otherwise), GCC generates code for the V7 variant of the SPARC architecture ๐ŸŒธ. With -mcpu=cypress, the compiler also optimizes for the Cypress CY7C602 chip, as used in the SPARCStation/SPARCServer 3xx series. This is also a good fit for the older SPARCStation 1, 2, IPX etc. ๐Ÿฆ–

With -mcpu=v8, GCC generates code for the V8 variant of the SPARC architecture ๐Ÿ’œ. The only difference from V7 code is that the compiler emits the integer multiply and integer divide instructions that exist in SPARC-V8 but not in SPARC-V7. With -mcpu=supersparc, the compiler also optimizes for the SuperSPARC chip, as used in the SPARCStation 10, 1000 and 2000 series.

With -mcpu=sparclite, GCC generates code for the SPARClite variant of the SPARC architecture ๐Ÿฆ‹. This adds the integer multiply, integer divide step and scan ("ffs") instructions that exist in SPARClite but not in SPARC-V7. With -mcpu=f930, the compiler also optimizes for the Fujitsu MB86930 chip, which is the original SPARClite, with no FPU. With -mcpu=f934, it optimizes for the Fujitsu MB86934 chip, which is the more recent SPARClite with FPU.

With -mcpu=sparclet, GCC generates code for the SPARClet variant of the SPARC architecture ๐Ÿงš. This adds the integer multiply, multiply/accumulate, integer divide step and scan ("ffs") instructions that exist in SPARClet but not in SPARC-V7. With -mcpu=tsc701, the compiler also optimizes for the TEMIC SPARClet chip.

With -mcpu=v9, GCC generates code for the V9 variant of the SPARC architecture ๐Ÿ‘‘. This adds 64-bit integer and floating-point move instructions, 3 additional floating-point condition code registers and conditional move instructions. With -mcpu=ultrasparc, the compiler also optimizes for the Sun UltraSPARC I/II/IIi chips. With -mcpu=ultrasparc3, it optimizes for the Sun UltraSPARC III/III+/IIIi/IIIi+/IV/IV+ chips. With -mcpu=niagara, it optimizes for Sun UltraSPARC T1 chips. With -mcpu=niagara2, it optimizes for Sun UltraSPARC T2 chips. With -mcpu=niagara3, it optimizes for Sun UltraSPARC T3 chips. With -mcpu=niagara4, it optimizes for Sun UltraSPARC T4 chips. With -mcpu=niagara7, it optimizes for Oracle SPARC M7 chips. With -mcpu=m8, it optimizes for Oracle M8 chips ๐Ÿ”ฅ.

  • -mtune=cpu_type โ€” Sets the instruction scheduling parameters for the machine type cpu_type, but leaves the instruction set and register set alone ๐ŸŽฏ. That's the difference from -mcpu=cpu_type.

The same values work for -mtune=cpu_type, but the only useful ones are those that pick a specific CPU implementation ๐Ÿ’…. Those are cypress, supersparc, hypersparc, leon, leon3, leon3v7, f930, f934, sparclite86x, tsc701, ultrasparc, ultrasparc3, niagara, niagara2, niagara3, niagara4, niagara7 and m8. With native Solaris and GNU/Linux toolchains, native can also be used.


  • -mv8plus, -mno-v8plus โ€” With -mv8plus, GCC generates code for the SPARC-V8+ ABI ๐Ÿซถ. The difference from the V8 ABI is that the global and out registers are treated as 64 bits wide. This is on by default on Solaris in 32-bit mode for all SPARC-V9 processors.
  • -mvis, -mno-vis โ€” With -mvis, GCC generates code that takes advantage of the UltraSPARC Visual Instruction Set extensions ๐ŸŽจ. The default is -mno-vis.
  • -mvis2, -mno-vis2 โ€” With -mvis2, GCC generates code that takes advantage of version 2.0 of the UltraSPARC Visual Instruction Set extensions ๐ŸŒˆ. The default is -mvis2 when targeting a CPU that supports such instructions, such as UltraSPARC-III and later. Setting -mvis2 also sets -mvis.
  • -mvis3, -mno-vis3 โ€” With -mvis3, GCC generates code that takes advantage of version 3.0 of the UltraSPARC Visual Instruction Set extensions ๐Ÿฆ„. The default is -mvis3 when targeting a CPU that supports such instructions, such as niagara-3 and later. Setting -mvis3 also sets -mvis2 and -mvis.
  • -mvis4, -mno-vis4 โ€” With -mvis4, GCC generates code that takes advantage of version 4.0 of the UltraSPARC Visual Instruction Set extensions ๐Ÿ“. The default is -mvis4 when targeting a CPU that supports such instructions, such as niagara-7 and later. Setting -mvis4 also sets -mvis3, -mvis2 and -mvis.
  • -mvis4b, -mno-vis4b โ€” With -mvis4b, GCC generates code that takes advantage of version 4.0 of the UltraSPARC Visual Instruction Set extensions, plus the extra VIS instructions introduced in the Oracle SPARC Architecture 2017 ๐Ÿ’ซ. The default is -mvis4b when targeting a CPU that supports such instructions, such as m8 and later. Setting -mvis4b also sets -mvis4, -mvis3, -mvis2 and -mvis.
  • -mcbcond, -mno-cbcond โ€” With -mcbcond, GCC generates code that takes advantage of the UltraSPARC Compare-and-Branch-on-Condition instructions ๐Ÿ”€. The default is -mcbcond when targeting a CPU that supports such instructions, such as Niagara-4 and later.
  • -mfmaf, -mno-fmaf โ€” With -mfmaf, GCC generates code that takes advantage of the UltraSPARC Fused Multiply-Add Floating-point instructions ๐Ÿงฎ. The default is -mfmaf when targeting a CPU that supports such instructions, such as Niagara-3 and later.
  • -mfsmuld, -mno-fsmuld โ€” With -mfsmuld, GCC generates code that takes advantage of the Floating-point Multiply Single to Double (FsMULd) instruction โœ–๏ธ. The default is -mfsmuld when targeting a CPU supporting the architecture versions V8 or V9 with FPU, except -mcpu=leon.
  • -mpopc, -mno-popc โ€” With -mpopc, GCC generates code that takes advantage of the UltraSPARC Population Count instruction ๐Ÿ”ข. The default is -mpopc when targeting a CPU that supports such an instruction, such as Niagara-2 and later.
  • -msubxc, -mno-subxc โ€” With -msubxc, GCC generates code that takes advantage of the UltraSPARC Subtract-Extended-with-Carry instruction โž–. The default is -msubxc when targeting a CPU that supports such an instruction, such as Niagara-7 and later.
  • -mfix-at697f โ€” Enables the documented workaround for the single erratum of the Atmel AT697F processor (which corresponds to erratum #13 of the AT697E processor) ๐Ÿฉน.
  • -mfix-ut699 โ€” Enables the documented workarounds for the floating-point errata and the data cache nullify errata of the UT699 processor ๐Ÿ› ๏ธ.
  • -mfix-ut700 โ€” Enables the documented workaround for the back-to-back store errata of the UT699E/UT700 processor ๐Ÿ”ง.
  • -mfix-gr712rc โ€” Enables the documented workaround for the back-to-back store errata of the GR712RC processor ๐Ÿงฐ.

These -m options are supported in addition to the above on SPARC-V9 processors in 64-bit environments ๐ŸŒŸ:

  • -m32, -m64 โ€” Generates code for a 32-bit or 64-bit environment ๐Ÿ’–. The 32-bit environment sets int, long and pointer to 32 bits. The 64-bit environment sets int to 32 bits and long and pointer to 64 bits.
  • -mcmodel=which โ€” Sets the code model to one of the following ๐Ÿงฉ:
    • medlow โ€” The Medium/Low code model: 64-bit addresses, programs must be linked in the low 32 bits of memory. Programs can be statically or dynamically linked.
    • medmid โ€” The Medium/Middle code model: 64-bit addresses, programs must be linked in the low 44 bits of memory, the text and data segments must be less than 2GB in size and the data segment must be located within 2GB of the text segment.
  • medany โ€” okay so this is the Medium/Anywhere code model ๐Ÿ’– You get 64-bit addresses and programs can be linked anywhere in memory. The text and data segments each have to be under 2GB, and the data segment has to sit within 2GB of the text segment ๐Ÿฆ‹
  • embmedany โ€” the embedded-systems version of Medium/Anywhere ๐Ÿงš You still get 64-bit addresses, and the text and data segments must be under 2GB each, but they can both start anywhere in memory (that gets decided at link time). The global register %g4 points to the base of the data segment. Programs are statically linked and PIC is not supported, so no PIC for you ๐Ÿ™ˆ

๐ŸŒˆ -mmemory-model=mem-model ๐ŸŒˆ

This sets the memory model the processor runs with, and you pick one of these:

  • default โ€” the default memory model for the processor and operating system โœจ
  • rmo โ€” Relaxed Memory Order
  • pso โ€” Partial Store Order
  • tso โ€” Total Store Order
  • sc โ€” Sequential Consistency

These are formally defined in Appendix D of the SPARC-V9 architecture manual, and they get set in the processor's PSTATE.MM field ๐Ÿ’…

๐Ÿฆ‹ -mstack-bias / -mno-stack-bias ๐Ÿฆ‹

  • -mstack-bias โ€” with this one, GCC assumes the stack pointer (and the frame pointer, if there is one) is offset by -2047, and that offset has to be added back whenever it makes stack frame references. This is the default in 64-bit mode ๐Ÿ”ฅ
  • -mno-stack-bias โ€” no offset is assumed to be there at all

๐ŸŒธ SPU Options ๐ŸŒธ

These -m options are supported on the SPU ๐Ÿงš

  • -mwarn-reloc, -merror-reloc โ€” the SPU loader doesn't handle dynamic relocations, so by default GCC throws an error when it generates code that needs one ๐Ÿ˜ญ -mno-error-reloc turns that error off, and -mwarn-reloc gives you a warning instead
  • -msafe-dma, -munsafe-dma โ€” instructions that start DMA or check whether it's finished can't get reordered with loads and stores of the memory being accessed ๐Ÿซถ With -munsafe-dma you have to use the "volatile" keyword to protect those memory accesses, but that can make the code inefficient in places where the memory is known not to change. Instead of marking everything volatile, you can use -msafe-dma to tell the compiler to treat the DMA instructions as potentially affecting all memory
  • -mbranch-hints โ€” by default GCC makes a branch hint instruction so you don't get pipeline stalls on always-taken or probably-taken branches โœจ A hint never gets generated closer than 8 instructions away from its branch. There's not much reason to turn these off, except for debugging or to make an object a little smaller
  • -msmall-mem, -mlarge-mem โ€” by default GCC assumes addresses are never bigger than 18 bits. With -mlarge-mem, the code is generated to assume a full 32-bit address ๐Ÿ“
  • -mstdmain โ€” by default you link against startup code that assumes the SPU-style main function interface, which has a pretty unconventional parameter list ๐Ÿ’€ With -mstdmain, your program links against startup code that assumes a C99-style interface to main, including a local copy of "argv" strings
  • -mfixed-range=register-range โ€” generates code that treats the given register range as fixed registers ๐Ÿ‘‘ A fixed register is one the register allocator isn't allowed to use, which is super useful when you're compiling kernel code. A register range is written as two registers separated by a dash, and you can put multiple ranges in separated by a comma
  • -mea32, -mea64 โ€” compiles code assuming that pointers to the PPU address space, accessed through the "__ea" named address space qualifier, are either 32 or 64 bits wide. The default is 32 bits. This is an ABI-changing option, so all object code in an executable has to be compiled with the same setting โš ๏ธ
  • -maddress-space-conversion, -mno-address-space-conversion โ€” allows or disallows treating the "__ea" address space as a superset of the generic address space ๐Ÿ’… Allowing it enables explicit type casts between "__ea" and generic pointers, as well as implicit conversions of generic pointers to "__ea" pointers. The default is to allow address space pointer conversions
  • -mcache-size=cache-size โ€” this one controls which version of libgcc the compiler links into an executable, and it selects a software-managed cache for accessing variables in the "__ea" address space with a particular cache size ๐ŸŽ€ The possible values for cache-size are 8, 16, 32, 64 and 128, and the default cache size is 64KB
  • -matomic-updates, -mno-atomic-updates โ€” also controls the libgcc version, and picks whether atomic updates to the software-managed cache of PPU-side variables are used ๐Ÿฆ‹ If you use atomic updates, changes to a PPU variable from SPU code using the "__ea" named address space qualifier won't interfere with changes to other PPU variables sitting in the same cache line from PPU code. If you don't use them, that interference may happen, but writing back cache lines is more efficient. The default is to use atomic updates
  • -mdual-nops, -mdual-nops=n โ€” by default GCC inserts NOPs to boost dual issue when it expects that to improve performance ๐Ÿš€ n can be anything from 0 to 10, and a smaller n inserts fewer NOPs. 10 is the default, and 0 is the same as -mno-dual-nops. This gets disabled with -Os
  • -mhint-max-nops=n โ€” the maximum number of NOPs to insert for a branch hint ๐Ÿงš A branch hint has to be at least 8 instructions away from the branch it's affecting. GCC inserts up to n NOPs to enforce this, and otherwise it just doesn't generate the branch hint
  • -mhint-max-distance=n โ€” the encoding of the branch hint instruction limits the hint to within 256 instructions of the branch it's affecting โœจ By default, GCC makes sure it's within 125
  • -msafe-hints โ€” works around a hardware bug that can make the SPU stall indefinitely ๐Ÿ˜ญ By default, GCC inserts the "hbrp" instruction to make sure that stall won't happen

๐ŸŽ€ Options for System V ๐ŸŽ€

These extra options are available on System V Release 4, for compatibility with other compilers on those systems ๐ŸŒˆ

  • -G โ€” creates a shared object ๐Ÿ’– It's recommended to use -symbolic or -shared instead
  • -Qy โ€” identifies the versions of each tool the compiler used, and puts them in a ".ident" assembler directive in the output
  • -Qn โ€” refrains from adding ".ident" directives to the output file, which is the default ๐Ÿซถ
  • -YP,dirs โ€” searches the directories dirs, and no others, for libraries specified with -l
  • -Ym,dir โ€” looks in the directory dir to find the M4 preprocessor ๐Ÿ”ฅ The assembler uses this option

๐Ÿฆ‹ TILE-Gx Options ๐Ÿฆ‹

These -m options are supported on the TILE-Gx ๐Ÿ’…

  • -mcmodel=small โ€” generates code for the small model ๐Ÿ“ The distance for direct calls is limited to 500M in either direction, PC-relative addresses are 32 bits, and absolute addresses support the full address range
  • -mcmodel=large โ€” generates code for the large model ๐Ÿ‘‘ There's no limitation on call distance, PC-relative addresses, or absolute addresses
  • -mcpu=name โ€” selects the type of CPU to target. Right now the only supported type is tilegx โœจ
  • -m32, -m64 โ€” generates code for a 32-bit or 64-bit environment ๐Ÿงš The 32-bit environment sets int, long, and pointer to 32 bits. The 64-bit environment sets int to 32 bits, and long and pointer to 64 bits
  • -mbig-endian, -mlittle-endian โ€” generates code in big or little endian mode, respectively ๐Ÿ’œ

๐ŸŒท TILEPro Options ๐ŸŒท

These -m options are supported on the TILEPro ๐ŸŒธ

  • -mcpu=name โ€” selects the type of CPU to target. Right now the only supported type is tilepro โœจ
  • -m32 โ€” generates code for a 32-bit environment, which sets int, long, and pointer to 32 bits ๐Ÿ’… This is the only supported behavior, so the flag is basically ignored ๐Ÿ™ˆ

๐ŸŒˆ V850 Options ๐ŸŒˆ

These -m options are defined for V850 implementations ๐Ÿซถ

  • -mlong-calls, -mno-long-calls โ€” treats all calls as being far away (near) ๐Ÿ”ฅ If calls are assumed to be far away, the compiler always loads the function's address into a register, and calls indirect through the pointer
  • -mno-ep, -mep โ€” -mno-ep means don't optimize basic blocks that use the same index pointer 4 or more times to copy the pointer into the "ep" register, and use the shorter "sld" and "sst" instructions. -mep means do optimize them. The -mep option is on by default if you optimize โœจ
  • -mno-prolog-function, -mprolog-function โ€” -mno-prolog-function means don't use external functions to save and restore registers at the prologue and epilogue of a function, and -mprolog-function means do use them. The external functions are slower, but they use less code space if more than one function saves the same number of registers. The -mprolog-function option is on by default if you optimize ๐Ÿ’–
  • -mspace โ€” tries to make the code as small as possible ๐Ÿงš At present, this just turns on the -mep and -mprolog-function options
  • -mtda=n โ€” puts static or global variables whose size is n bytes or less into the tiny data area that the "ep" register points to ๐Ÿฆ‹ The tiny data area can hold up to 256 bytes in total, or 128 bytes for byte references
  • -msda=n โ€” puts static or global variables whose size is n bytes or less into the small data area that the "gp" register points to ๐Ÿ“ The small data area can hold up to 64 kilobytes
  • -mzda=n โ€” puts static or global variables whose size is n bytes or less into the first 32 kilobytes of memory ๐ŸŒธ
  • -mv850 โ€” specifies that the target processor is the V850 ๐Ÿ’œ
  • -mv850e3v5 โ€” specifies that the target processor is the V850E3V5 ๐ŸŒˆ The preprocessor constant "__v850e3v5__" is defined if this option is used
  • -mv850e2v4 โ€” specifies that the target processor is the V850E3V5 ๐Ÿซถ This is an alias for the -mv850e3v5 option
  • -mv850e2v3 โ€” specifies that the target processor is the V850E2V3 โœจ The preprocessor constant "__v850e2v3__" is defined if this option is used
  • -mv850e2 โ€” specifies that the target processor is the V850E2 ๐Ÿ’… The preprocessor constant "__v850e2__" is defined if this option is used
  • -mv850e1 โ€” specifies that the target processor is the V850E1 ๐Ÿ”ฅ The preprocessor constants "__v850e1__" and "__v850e__" are defined if this option is used
  • -mv850es โ€” specifies that the target processor is the V850ES ๐Ÿ‘‘ This is an alias for the -mv850e1 option
  • -mv850e โ€” okay so this one tells GCC the target is the V850E ๐Ÿ’– and defines the preprocessor constant __v850e__ when you use it โœจ

If none of -mv850, -mv850e, -mv850e1, -mv850e2, -mv850e2v3, or -mv850e3v5 are defined, GCC picks a default target processor for you and defines the matching __v850*__ preprocessor constant ๐Ÿซถ

The preprocessor constants __v850 and __v851__ are always defined, no matter which processor variant is the target ๐Ÿ’…

  • -mdisable-callt, -mno-disable-callt โ€” these suppress generation of the CALLT instruction for the v850e, v850e1, v850e2, v850e2v3, and v850e3v5 flavors of V850 ๐ŸŒธ

-mdisable-callt is turned on by default when the RH850 ABI is in use (see -mrh850-abi), and off by default when the GCC ABI is in use. If CALLT instructions are being generated, the C preprocessor symbol __V850_CALLT__ gets defined ๐Ÿฆ‹

  • -mrelax, -mno-relax โ€” passes (or doesn't pass) the -mrelax command-line option along to the assembler ๐Ÿงš
  • -mlong-jumps, -mno-long-jumps โ€” -mlong-jumps turns off generation of PC-relative jump instructions, and -mno-long-jumps turns them back on ๐Ÿ“
  • -msoft-float, -mhard-float โ€” -msoft-float turns off hardware floating point instructions, and -mhard-float turns them back on. This only matters when the target architecture is V850E2V3 or higher ๐ŸŒˆ If hardware floating point instructions are being generated, the __FPU_OK__ symbol is defined. Otherwise, __NO_FPU__ is defined โœจ
  • -mloop โ€” enables the e3v5 LOOP instruction ๐Ÿ”ฅ It's not on by default when the e3v5 architecture is selected, because its use is still experimental ๐Ÿ™ˆ
  • -mrh850-abi, -mghs โ€” enables support for the RH850 version of the V850 ABI. This is the default, and it's giving main character energy ๐Ÿ‘‘ With this version of the ABI, these rules apply:
    • Integer sized structures and unions are returned via a memory pointer instead of a register.
    • Large structures and unions (more than 8 bytes in size) are passed by value.
    • Functions are aligned to 16-bit boundaries.
    • The -m8byte-align command-line option is supported.
    • The -mdisable-callt command-line option is enabled by default. The -mno-disable-callt command-line option is not supported.

When this version of the ABI is enabled, the C preprocessor symbol __V850_RH850_ABI__ is defined ๐Ÿ’–

  • -mgcc-abi โ€” enables support for the old GCC version of the V850 ABI ๐Ÿ•ฐ๏ธ With this version, these rules apply:
    • Integer sized structures and unions are returned in register r10.
    • Large structures and unions (more than 8 bytes in size) are passed by reference.
    • Functions are aligned to 32-bit boundaries, unless optimizing for size.
    • The -m8byte-align command-line option is not supported.
    • The -mdisable-callt command-line option is supported but not enabled by default.

When this version of the ABI is enabled, the C preprocessor symbol __V850_GCC_ABI__ is defined ๐ŸŽ€

  • -m8byte-align, -mno-8byte-align โ€” enables double and long long types being aligned on 8-byte boundaries. By default, the alignment of all objects is restricted to at most 4 bytes ๐Ÿฆ‹ When -m8byte-align is in effect, the C preprocessor symbol __V850_8BYTE_ALIGN__ is defined โœจ
  • -mbig-switch โ€” generates code suitable for big switch tables. Only use this one if the assembler or linker complains about out of range branches within a switch table ๐Ÿ˜ญ
  • -mapp-regs โ€” makes r2 and r5 get used in the code the compiler generates. This is the default vibe ๐Ÿ’…
  • -mno-app-regs โ€” makes r2 and r5 get treated as fixed registers ๐Ÿซถ

๐Ÿฆ‹ VAX Options ๐Ÿฆ‹

These -m options are defined for the VAX ๐ŸŒธ

  • -munix โ€” doesn't output certain jump instructions (like aobleq and so on) that the Unix assembler for the VAX can't handle across long ranges ๐Ÿ™ˆ
  • -mgnu โ€” does output those jump instructions, assuming you're using the GNU assembler ๐Ÿงš
  • -mg โ€” outputs code for G-format floating-point numbers instead of D-format ๐Ÿ”ฅ

๐ŸŒธ Visium Options ๐ŸŒธ

  • -mdebug โ€” a program that does file I/O and is destined to run on an MCM target should be linked with this option โœจ It causes the libraries libc.a and libdebug.a to be linked. The program should be run on the target under the control of the GDB remote debugging stub ๐Ÿ“
  • -msim โ€” a program that does file I/O and is destined to run on the simulator should be linked with this option ๐Ÿ’– It causes the libraries libc.a and libsim.a to be linked ๐ŸŒˆ
  • -mfpu, -mhard-float โ€” generates code containing floating-point instructions. This is the default ๐Ÿ‘‘
  • -mno-fpu, -msoft-float โ€” generates code containing library calls for floating-point ๐Ÿซถ
โš ๏ธ -msoft-float changes the calling convention in the output file, so it's only useful if you compile all of a program with this option. In particular, you need to compile libgcc.a, the library that comes with GCC, with -msoft-float in order for this to work ๐Ÿ’€
  • -mcpu=cpu_type โ€” sets the instruction set, register set, and instruction scheduling parameters for machine type cpu_type ๐Ÿฆ‹ Supported values for cpu_type are mcm, gr5, and gr6 ๐Ÿ’…
    • mcm is a synonym of gr5, kept around for backward compatibility.
    • By default (unless configured otherwise), GCC generates code for the GR5 variant of the Visium architecture.
    • With -mcpu=gr6, GCC generates code for the GR6 variant. The only difference from GR5 code is that the compiler will generate block move instructions ๐Ÿ”ฅ
  • -mtune=cpu_type โ€” sets the instruction scheduling parameters for machine type cpu_type, but doesn't set the instruction set or register set that -mcpu=cpu_type would ๐Ÿงš
  • -msv-mode โ€” generates code for supervisor mode, where there are no restrictions on access to general registers. This is the default ๐Ÿ‘‘
  • -muser-mode โ€” generates code for user mode, where access to some general registers is forbidden ๐Ÿ™ˆ On the GR5, registers r24 to r31 can't be accessed in this mode. On the GR6, only registers r29 to r31 are affected ๐Ÿ’€

๐Ÿ’– VMS Options ๐Ÿ’–

These -m options are defined for the VMS implementations โœจ

  • -mvms-return-codes โ€” returns VMS condition codes from main. The default is to return POSIX-style condition (e.g. error) codes ๐ŸŒธ
  • -mdebug-main=prefix โ€” flags the first routine whose name starts with prefix as the main routine for the debugger ๐ŸŽ€
  • -mmalloc64 โ€” defaults to 64-bit memory allocation routines ๐ŸŒˆ
  • -mpointer-size=size โ€” sets the default size of pointers ๐Ÿ”ฅ Possible options for size are 32 or short for 32-bit pointers, 64 or long for 64-bit pointers, and no for supporting only 32-bit pointers. The latter option disables pragma pointer_size ๐Ÿ˜ญ

โญ VxWorks Options โญ

The options in this section are defined for all VxWorks targets. Options specific to the target hardware are listed with the other options for that target ๐Ÿงš

  • -mrtp โ€” GCC can generate code for both VxWorks kernels and real time processes (RTPs) ๐Ÿฆ‹ This option switches from the former to the latter. It also defines the preprocessor macro __RTP__ โœจ
  • -non-static โ€” links an RTP executable against shared libraries rather than static libraries ๐Ÿซถ The options -static and -shared can also be used for RTPs, and -static is the default ๐Ÿ’…
  • -Bstatic, -Bdynamic โ€” these options are passed down to the linker. They're defined for compatibility with Diab ๐Ÿ“
  • -Xbind-lazy โ€” enables lazy binding of function calls ๐ŸŒˆ This option is equivalent to -Wl,-z,now and is defined for compatibility with Diab ๐Ÿ™ˆ
  • -Xbind-now โ€” disables lazy binding of function calls ๐Ÿ‘‘ This option is the default and is defined for compatibility with Diab ๐Ÿ’…

๐Ÿ‘‘ x86 Options ๐Ÿ‘‘

These -m options are defined for the x86 family of computers ๐Ÿ’–

  • -march=cpu-type โ€” generates instructions for the machine type cpu-type ๐Ÿ”ฅ In contrast to -mtune=cpu-type, which merely tunes the generated code for the specified cpu-type, -march=cpu-type allows GCC to generate code that may not run at all on processors other than the one indicated ๐Ÿ˜ญ Specifying -march=cpu-type implies -mtune=cpu-type ๐Ÿซถ

The choices for cpu-type are:

  • native โ€” selects the CPU to generate code for at compilation time by determining the processor type of the compiling machine ๐Ÿฆ‹ Using -march=native enables all instruction subsets supported by the local machine (so the result might not run on different machines) ๐Ÿ’€ Using -mtune=native produces code optimized for the local machine under the constraints of the selected instruction set ๐Ÿงš
  • x86-64 โ€” a generic CPU with 64-bit extensions ๐ŸŒˆ
  • i386 โ€” original Intel i386 CPU ๐Ÿ•ฐ๏ธ
  • i486 โ€” Intel i486 CPU. (No scheduling is implemented for this chip.) ๐ŸŒธ
  • i586, pentium โ€” Intel Pentium CPU with no MMX support ๐ŸŽ€
  • lakemont โ€” Intel Lakemont MCU, based on Intel Pentium CPU โœจ
  • pentium-mmx โ€” Intel Pentium MMX CPU, based on Pentium core with MMX instruction set support ๐Ÿ’…
  • pentiumpro โ€” Intel Pentium Pro CPU ๐Ÿ”ฅ
  • i686 โ€” when used with -march, the Pentium Pro instruction set is used, so the code runs on all i686 family chips. When used with -mtune, it has the same meaning as generic ๐Ÿ‘‘
  • pentium2 โ€” Intel Pentium II CPU, based on Pentium Pro core with MMX instruction set support ๐Ÿ“
  • pentium3, pentium3m โ€” Intel Pentium III CPU, based on Pentium Pro core with MMX and SSE instruction set support ๐ŸŒˆ
  • pentium-m โ€” Intel Pentium M, a low-power version of the Intel Pentium III CPU with MMX, SSE, and SSE2 instruction set support. Used by Centrino notebooks ๐Ÿ’ปโœจ
  • pentium4, pentium4m โ€” Intel Pentium 4 CPU with MMX, SSE, and SSE2 instruction set support ๐Ÿ™ˆ
  • prescott โ€” improved version of the Intel Pentium 4 CPU with MMX, SSE, SSE2, and SSE3 instruction set support ๐Ÿซถ
  • nocona โ€” improved version of the Intel Pentium 4 CPU with 64-bit extensions, MMX, SSE, SSE2, and SSE3 instruction set support ๐Ÿงš
  • core2 โ€” ๐Ÿ’– Intel Core 2 CPU with 64-bit extensions plus MMX, SSE, SSE2, SSE3 and SSSE3 support. Iconic. ๐Ÿ‘‘
  • nehalem โ€” โœจ Intel Nehalem CPU with 64-bit extensions and MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2 and POPCNT. The vibe is very structured.
  • westmere โ€” ๐Ÿฆ‹ Intel Westmere CPU with 64-bit extensions and everything from nehalem, plus AES and PCLMUL.
  • sandybridge โ€” ๐ŸŒธ Intel Sandy Bridge CPU with 64-bit extensions, MMX, SSE through SSE4.2, POPCNT, AVX, AES and PCLMUL.
  • ivybridge โ€” ๐Ÿงš Intel Ivy Bridge CPU with 64-bit extensions, MMX, SSE through SSE4.2, POPCNT, AVX, AES, PCLMUL, FSGSBASE, RDRND and F16C.
  • haswell โ€” ๐Ÿ”ฅ Intel Haswell CPU with 64-bit extensions, MOVBE, MMX, SSE through SSE4.2, POPCNT, AVX, AVX2, AES, PCLMUL, FSGSBASE, RDRND, FMA, BMI, BMI2 and F16C.
  • broadwell โ€” ๐Ÿ’… Intel Broadwell CPU with 64-bit extensions, MOVBE, MMX, SSE through SSE4.2, POPCNT, AVX, AVX2, AES, PCLMUL, FSGSBASE, RDRND, FMA, BMI, BMI2, F16C, RDSEED, ADCX and PREFETCHW.
  • skylake โ€” ๐ŸŒˆ Intel Skylake CPU with everything from broadwell, plus CLFLUSHOPT, XSAVEC and XSAVES.
  • bonnell โ€” ๐Ÿ“ Intel Bonnell CPU with 64-bit extensions, MOVBE, MMX, SSE, SSE2, SSE3 and SSSE3. Lowkey a chill little starter set.
  • silvermont โ€” ๐ŸŽ€ Intel Silvermont CPU with 64-bit extensions, MOVBE, MMX, SSE through SSE4.2, POPCNT, AES, PREFETCHW, PCLMUL and RDRND.
  • goldmont โ€” ๐Ÿ’œ Intel Goldmont CPU with 64-bit extensions, MOVBE, MMX, SSE through SSE4.2, POPCNT, AES, PREFETCHW, PCLMUL, RDRND, XSAVE, XSAVEC, XSAVES, XSAVEOPT and FSGSBASE.
  • goldmont-plus โ€” ๐ŸŒธ Intel Goldmont Plus CPU with 64-bit extensions, MOVBE, MMX, SSE through SSE4.2, POPCNT, AES, PREFETCHW, PCLMUL, RDRND, XSAVE, XSAVEC, XSAVES, XSAVEOPT, FSGSBASE, PTWRITE, RDPID, SGX and UMIP.
  • tremont โ€” ๐Ÿฆ‹ Intel Tremont CPU with 64-bit extensions, MOVBE, MMX, SSE through SSE4.2, POPCNT, AES, PREFETCHW, PCLMUL, RDRND, XSAVE, XSAVEC, XSAVES, XSAVEOPT, FSGSBASE, PTWRITE, RDPID, SGX, UMIP, GFNI-SSE, CLWB, MOVDIRI, MOVDIR64B, CLDEMOTE and WAITPKG support. That is a LOT of extensions, bestie. ๐Ÿ˜ญ
  • knl โ€” ๐Ÿ‘‘ Intel Knight's Landing CPU with 64-bit extensions, MOVBE, MMX, SSE through SSE4.2, POPCNT, AVX, AVX2, AES, PCLMUL, FSGSBASE, RDRND, FMA, BMI, BMI2, F16C, RDSEED, ADCX, PREFETCHW, PREFETCHWT1, AVX512F, AVX512PF, AVX512ER and AVX512CD.
  • knm โ€” โญ Intel Knights Mill CPU with 64-bit extensions, MOVBE, MMX, SSE through SSE4.2, POPCNT, AVX, AVX2, AES, PCLMUL, FSGSBASE, RDRND, FMA, BMI, BMI2, F16C, RDSEED, ADCX, PREFETCHW, PREFETCHWT1, AVX512F, AVX512PF, AVX512ER, AVX512CD, AVX5124VNNIW, AVX5124FMAPS and AVX512VPOPCNTDQ.
  • skylake-avx512 โ€” ๐Ÿ”ฅ Intel Skylake Server CPU with 64-bit extensions, MOVBE, MMX, SSE through SSE4.2, POPCNT, PKU, AVX, AVX2, AES, PCLMUL, FSGSBASE, RDRND, FMA, BMI, BMI2, F16C, RDSEED, ADCX, PREFETCHW, CLFLUSHOPT, XSAVEC, XSAVES, AVX512F, CLWB, AVX512VL, AVX512BW, AVX512DQ and AVX512CD.
  • cannonlake โ€” ๐Ÿ’€ Intel Cannonlake Server CPU with 64-bit extensions, MOVBE, MMX, SSE through SSE4.2, POPCNT, PKU, AVX, AVX2, AES, PCLMUL, FSGSBASE, RDRND, FMA, BMI, BMI2, F16C, RDSEED, ADCX, PREFETCHW, CLFLUSHOPT, XSAVEC, XSAVES, AVX512F, AVX512VL, AVX512BW, AVX512DQ, AVX512CD, AVX512VBMI, AVX512IFMA, SHA and UMIP.
  • icelake-client โ€” ๐Ÿซถ Intel Icelake Client CPU with 64-bit extensions, MOVBE, MMX, SSE through SSE4.2, POPCNT, PKU, AVX, AVX2, AES, PCLMUL, FSGSBASE, RDRND, FMA, BMI, BMI2, F16C, RDSEED, ADCX, PREFETCHW, CLFLUSHOPT, XSAVEC, XSAVES, AVX512F, AVX512VL, AVX512BW, AVX512DQ, AVX512CD, AVX512VBMI, AVX512IFMA, SHA, CLWB, UMIP, RDPID, GFNI, AVX512VBMI2, AVX512VPOPCNTDQ, AVX512BITALG, AVX512VNNI, VPCLMULQDQ and VAES support.
  • icelake-server โ€” ๐Ÿงš Intel Icelake Server CPU with everything icelake-client has, plus PCONFIG and WBNOINVD. Same glow-up, server edition. โœจ
  • cascadelake โ€” ๐ŸŽ€ Intel Cascadelake CPU with 64-bit extensions, MOVBE, MMX, SSE through SSE4.2, POPCNT, PKU, AVX, AVX2, AES, PCLMUL, FSGSBASE, RDRND, FMA, BMI, BMI2, F16C, RDSEED, ADCX, PREFETCHW, CLFLUSHOPT, XSAVEC, XSAVES, AVX512F, CLWB, AVX512VL, AVX512BW, AVX512DQ, AVX512CD and AVX512VNNI.
  • tigerlake โ€” ๐Ÿ‘‘ Intel Tigerlake CPU with 64-bit extensions, MOVBE, MMX, SSE through SSE4.2, POPCNT, PKU, AVX, AVX2, AES, PCLMUL, FSGSBASE, RDRND, FMA, BMI, BMI2, F16C, RDSEED, ADCX, PREFETCHW, CLFLUSHOPT, XSAVEC, XSAVES, AVX512F, AVX512VL, AVX512BW, AVX512DQ, AVX512CD, AVX512VBMI, AVX512IFMA, SHA, CLWB, UMIP, RDPID, GFNI, AVX512VBMI2, AVX512VPOPCNTDQ, AVX512BITALG, AVX512VNNI, VPCLMULQDQ, VAES, PCONFIG, WBNOINVD, MOVDIRI, MOVDIR64B and CLWB support. Note that CLWB is listed twice in the original, and we're keeping it exactly like that. ๐Ÿ™ˆ
  • k6 โ€” ๐Ÿ“ AMD K6 CPU with MMX instruction set support. A classic, honestly.
  • k6-2, k6-3 โ€” ๐ŸŒˆ Improved versions of the AMD K6 CPU with MMX and 3DNow! instruction set support.
  • athlon, athlon-tbird โ€” ๐Ÿ’œ AMD Athlon CPU with MMX, 3dNOW!, enhanced 3DNow! and SSE prefetch instructions support.
  • athlon-4, athlon-xp, athlon-mp โ€” โœจ Improved AMD Athlon CPU with MMX, 3DNow!, enhanced 3DNow! and full SSE instruction set support. Level up!
  • k8, opteron, athlon64, athlon-fx โ€” ๐Ÿฆ‹ Processors based on the AMD K8 core with x86-64 instruction set support, including the AMD Opteron, Athlon 64 and Athlon 64 FX processors. (This one supersets MMX, SSE, SSE2, 3DNow!, enhanced 3DNow! and 64-bit instruction set extensions.)
  • k8-sse3, opteron-sse3, athlon64-sse3 โ€” ๐ŸŒธ Improved versions of the AMD K8 cores with SSE3 instruction set support.
  • amdfam10, barcelona โ€” ๐Ÿ”ฅ CPUs based on AMD Family 10h cores with x86-64 instruction set support. (This supersets MMX, SSE, SSE2, SSE3, SSE4A, 3DNow!, enhanced 3DNow!, ABM and 64-bit instruction set extensions.)
  • bdver1 โ€” ๐ŸŽ€ CPUs based on AMD Family 15h cores with x86-64 instruction set support. (This supersets FMA4, AVX, XOP, LWP, AES, PCL_MUL, CX16, MMX, SSE, SSE2, SSE3, SSE4A, SSSE3, SSE4.1, SSE4.2, ABM and 64-bit instruction set extensions.)
  • bdver2 โ€” ๐Ÿ’… AMD Family 15h core based CPUs with x86-64 instruction set support. (This supersets BMI, TBM, F16C, FMA, FMA4, AVX, XOP, LWP, AES, PCL_MUL, CX16, MMX, SSE, SSE2, SSE3, SSE4A, SSSE3, SSE4.1, SSE4.2, ABM and 64-bit instruction set extensions.)
  • bdver3 โ€” ๐Ÿงš AMD Family 15h core based CPUs with x86-64 instruction set support. (This supersets BMI, TBM, F16C, FMA, FMA4, FSGSBASE, AVX, XOP, LWP, AES, PCL_MUL, CX16, MMX, SSE, SSE2, SSE3, SSE4A, SSSE3, SSE4.1, SSE4.2, ABM and 64-bit instruction set extensions.)
  • bdver4 โ€” ๐ŸŒˆ AMD Family 15h core based CPUs with x86-64 instruction set support. (This supersets BMI, BMI2, TBM, F16C, FMA, FMA4, FSGSBASE, AVX, AVX2, XOP, LWP, AES, PCL_MUL, CX16, MOVBE, MMX, SSE, SSE2, SSE3, SSE4A, SSSE3, SSE4.1, SSE4.2, ABM and 64-bit instruction set extensions.)
  • znver1 โ€” ๐Ÿ‘‘ AMD Family 17h core based CPUs with x86-64 instruction set support. (This supersets BMI, BMI2, F16C, FMA, FSGSBASE, AVX, AVX2, ADCX, RDSEED, MWAITX, SHA, CLZERO, AES, PCL_MUL, CX16, MOVBE, MMX, SSE, SSE2, SSE3, SSE4A, SSSE3, SSE4.1, SSE4.2, ABM, XSAVEC, XSAVES, CLFLUSHOPT, POPCNT, and 64-bit instruction set extensions.)
  • znver2 โ€” ๐Ÿ’– AMD Family 17h core based CPUs with x86-64 instruction set support. (This supersets BMI, BMI2, CLWB, F16C, FMA, FSGSBASE, AVX, AVX2, ADCX, RDSEED, MWAITX, SHA, CLZERO, AES, PCL_MUL, CX16, MOVBE, MMX, SSE, SSE2, SSE3, SSE4A, SSSE3, SSE4.1, SSE4.2, ABM, XSAVEC, XSAVES, CLFLUSHOPT, POPCNT and 64-bit instruction set extensions.)
  • btver1 โ€” ๐Ÿ“ CPUs based on AMD Family 14h cores with x86-64 instruction set support. (This supersets MMX, SSE, SSE2, SSE3, SSSE3, SSE4A, CX16, ABM and 64-bit instruction set extensions.)
  • btver2 โ€” ๐Ÿฆ‹ CPUs based on AMD Family 16h cores with x86-64 instruction set support. This includes MOVBE, F16C, BMI, AVX, PCL_MUL, AES, SSE4.2, SSE4.1, CX16, ABM, SSE4A, SSSE3, SSE3, SSE2, SSE, MMX and 64-bit instruction set extensions.
  • winchip-c6 โ€” ๐ŸŽ€ IDT WinChip C6 CPU, treated the same way as i486, with additional MMX instruction set support.
  • winchip2 โ€” ๐ŸŒธ IDT WinChip 2 CPU, treated the same way as i486, with additional MMX and 3DNow! instruction set support.
  • c3 โ€” ๐Ÿงš VIA C3 CPU with MMX and 3DNow! instruction set support. (No scheduling is implemented for this chip.)
  • c3-2 โ€” ๐Ÿ’œ VIA C3-2 (Nehemiah/C5XL) CPU with MMX and SSE instruction set support. (No scheduling is implemented for this chip.)
  • c7 โ€” โญ VIA C7 (Esther) CPU with MMX, SSE, SSE2 and SSE3 instruction set support. (No scheduling is implemented for this chip.) ๐Ÿซถ
  • samuel-2 โ€” the VIA Eden Samuel 2 CPU ๐ŸŒธ, slaying with MMX and 3DNow! instruction set support. (ngl, no scheduling is implemented for this chip.)
  • nehemiah โ€” the VIA Eden Nehemiah CPU ๐Ÿฆ‹, with MMX and SSE instruction set support. (No scheduling is implemented for this chip.)
  • esther โ€” the VIA Eden Esther CPU ๐Ÿงš, with MMX, SSE, SSE2 and SSE3 instruction set support. (No scheduling is implemented for this chip.)
  • eden-x2 โ€” the VIA Eden X2 CPU ๐Ÿ’–, with x86-64, MMX, SSE, SSE2 and SSE3 instruction set support. (No scheduling is implemented for this chip.)
  • eden-x4 โ€” the VIA Eden X4 CPU ๐Ÿ‘‘, with x86-64, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, AVX and AVX2 instruction set support. (No scheduling is implemented for this chip.)
  • nano โ€” the generic VIA Nano CPU โœจ, with x86-64, MMX, SSE, SSE2, SSE3 and SSSE3 instruction set support. (No scheduling is implemented for this chip.)
  • nano-1000 โ€” the VIA Nano 1xxx CPU ๐Ÿ“, with x86-64, MMX, SSE, SSE2, SSE3 and SSSE3 instruction set support. (No scheduling is implemented for this chip.)
  • nano-2000 โ€” the VIA Nano 2xxx CPU ๐ŸŒˆ, with x86-64, MMX, SSE, SSE2, SSE3 and SSSE3 instruction set support. (No scheduling is implemented for this chip.)
  • nano-3000 โ€” the VIA Nano 3xxx CPU ๐Ÿ’œ, with x86-64, MMX, SSE, SSE2, SSE3, SSSE3 and SSE4.1 instruction set support. (No scheduling is implemented for this chip.)
  • nano-x2 โ€” the VIA Nano Dual Core CPU ๐Ÿซถ, with x86-64, MMX, SSE, SSE2, SSE3, SSSE3 and SSE4.1 instruction set support. (No scheduling is implemented for this chip.)
  • nano-x4 โ€” the VIA Nano Quad Core CPU ๐Ÿ”ฅ, with x86-64, MMX, SSE, SSE2, SSE3, SSSE3 and SSE4.1 instruction set support. (No scheduling is implemented for this chip.)
  • geode โ€” the AMD Geode embedded processor ๐Ÿ’…, with MMX and 3DNow! instruction set support.

-mtune=cpu-type ๐ŸŽ€

Okay so -mtune is the move when you want the generated code tuned for a specific chip, except for the ABI and the set of available instructions. Picking a specific cpu-type schedules things appropriately for that particular chip, but the compiler won't generate code that can't run on the default machine type unless you also use a -march=cpu-type option. For example, if GCC is configured for i686-pc-linux-gnu, then -mtune=pentium4 generates code tuned for Pentium 4 that still runs on i686 machines. Main character energy ๐Ÿ‘‘.

The choices for cpu-type are the same as for -march. On top of that, -mtune supports 2 extra choices for cpu-type:

  • generic โ€” produces code optimized for the most common IA32/AMD64/EM64T processors ๐ŸŒธ. If you already know the CPU your code will run on, use the matching -mtune or -march option instead of -mtune=generic. But if you have no idea what CPU your users will have, this is the one to pick.

As new processors hit the market, the behavior of this option will change. So if you upgrade to a newer version of GCC, the code generation controlled by this option will shift to reflect whichever processors are most common when that version of GCC is released.

There is no -march=generic option, because -march indicates the instruction set the compiler can use, and there's no generic instruction set that applies to all processors. -mtune, on the other hand, indicates the processor (or, in this case, collection of processors) the code is optimized for. ๐Ÿงš

  • intel โ€” produces code optimized for the most current Intel processors, which for this version of GCC are Haswell and Silvermont ๐Ÿ’™. If you know the CPU your code will run on, use the matching -mtune or -march option instead of -mtune=intel. But if you want your application to perform better on both Haswell and Silvermont, this is the one.

As new Intel processors get deployed, the behavior of this option will change. So if you upgrade to a newer version of GCC, the code generation controlled by this option will reflect the most current Intel processors at the time that version of GCC is released.

There is no -march=intel option, because -march indicates the instruction set the compiler can use, and there's no common instruction set that applies to all processors. -mtune, in contrast, indicates the processor (or, in this case, collection of processors) the code is optimized for. โœจ

-mcpu=cpu-type ๐Ÿ™ˆ

This is a deprecated synonym for -mtune. Still works, but it's on its way out, so switch to -mtune ๐Ÿซถ.

-mfpmath=unit ๐Ÿฆ‹

Generate floating-point arithmetic for the selected unit. The choices for unit are:

  • 387 โ€” uses the standard 387 floating-point coprocessor that's on the majority of chips, and emulates it otherwise ๐Ÿ’–. Code compiled with this option runs almost everywhere. The temporary results are computed in 80-bit precision instead of the precision specified by the type, so the results can come out slightly different from most other chips. See -ffloat-store for a more detailed description.

This is the default choice for non-Darwin x86-32 targets.

  • sse โ€” uses the scalar floating-point instructions from the SSE instruction set. This set is supported by Pentium III and newer chips, and on the AMD side by Athlon-4, Athlon XP and Athlon MP chips ๐ŸŒˆ. The earlier version of the SSE instruction set only supports single-precision arithmetic, so double and extended-precision arithmetic still go through 387. A later version, present only in Pentium 4 and AMD x86-64 chips, supports double-precision arithmetic too.

For the x86-32 compiler, you must use -march=cpu-type, -msse or -msse2 switches to enable the SSE extensions and make this option work. For the x86-64 compiler, these extensions are enabled by default.

The resulting code should be considerably faster in most cases and avoids the numerical instability problems of 387 code. But it may break some existing code that expects temporaries to be 80 bits ๐Ÿ™ˆ.

This is the default choice for the x86-64 compiler, Darwin x86-32 targets, and the default choice for x86-32 targets with the SSE2 instruction set when -ffast-math is enabled.

  • sse,387, sse+387, both โ€” attempts to use both instruction sets at once ๐Ÿ”ฅ. This effectively doubles the number of available registers, and on chips with separate execution units for 387 and SSE, it doubles the execution resources too. Use this option with care, because it is still experimental: the GCC register allocator doesn't model separate functional units well, which can make performance unstable.

-masm=dialect ๐Ÿ’…

Outputs assembly instructions using the selected dialect. This also affects which dialect is used for basic asm and extended asm. The supported choices (in dialect order) are att or intel. The default is att. Darwin does not support intel ๐Ÿ™ˆ.

-mieee-fp, -mno-ieee-fp ๐ŸŒธ

These control whether or not the compiler uses IEEE floating-point comparisons. These correctly handle the case where the result of a comparison is unordered ๐Ÿงš.

-m80387, -mhard-float โœจ

Generates output containing 80387 instructions for floating point ๐Ÿ’œ.

-mno-80387, -msoft-float ๐ŸŒˆ

Generates output containing library calls for floating point instead ๐Ÿซถ.

Warning: the requisite libraries are NOT part of GCC ๐Ÿ˜ญ. Normally the facilities of the machine's usual C compiler are used, but this can't be done directly in cross-compilation. You must make your own arrangements to provide suitable library functions for cross-compilation.

On machines where a function returns floating-point results in the 80387 register stack, some floating-point opcodes may still be emitted even if -msoft-float is used ๐Ÿ’€.

-mno-fp-ret-in-387 ๐Ÿฆ‹

Do not use the FPU registers for return values of functions.

The usual calling convention has functions return values of types float and double in an FPU register, even if there's no FPU. The idea is that the operating system should emulate an FPU.

-mno-fp-ret-in-387 causes such values to be returned in ordinary CPU registers instead ๐Ÿ“.

-mno-fancy-math-387 ๐Ÿงš

Some 387 emulators don't support the sin, cos and sqrt instructions for the 387. Specify this option to avoid generating those instructions. This option is overridden when -march indicates that the target CPU always has an FPU, so the instruction doesn't need emulation. These instructions are not generated unless you also use the -funsafe-math-optimizations switch ๐Ÿ™ˆ.

-malign-double, -mno-align-double ๐Ÿ’–

These control whether GCC aligns double, long double, and long long variables on a two-word boundary or a one-word boundary. Aligning double variables on a two-word boundary produces code that runs somewhat faster on a Pentium, at the expense of more memory ๐Ÿ”ฅ.

On x86-64, -malign-double is enabled by default.

Warning: if you use the -malign-double switch, structures containing the above types are aligned differently than the published application binary interface specifications for x86-32, and they are not binary compatible with structures in code compiled without that switch ๐Ÿ˜ญ.

-m96bit-long-double, -m128bit-long-double ๐Ÿ‘‘

These switches control the size of the long double type ๐Ÿ’…. The x86-32 application binary interface specifies the size as 96 bits, so -m96bit-long-double is the default in 32-bit mode.

Modern architectures (Pentium and newer) prefer long double to be aligned to an 8- or 16-byte boundary. In arrays or structures that conform to the ABI, that isn't possible. So specifying -m128bit-long-double aligns long double to a 16-byte boundary by padding it with an additional 32-bit zero ๐ŸŒธ.

On the x86-64 compiler, -m128bit-long-double is the default choice, since its ABI specifies that long double is aligned on a 16-byte boundary ๐Ÿซถ.

Notice that neither of these options enables any extra precision over the x87 standard of 80 bits for a long double ๐Ÿ™ˆ.

Okay so this next batch is all about stack alignment and instruction sets ๐Ÿ’…โœจ

๐Ÿšจ Warning: if you override the default value for your target ABI, this changes the size of structures and arrays containing long double variables, as well as modifying the function calling convention for functions taking long double. Hence they are not binary-compatible with code compiled without that switch. ๐Ÿ’€
  • -mlong-double-64, -mlong-double-80, -mlong-double-128 โ€” ๐ŸŽ€ these control the size of the long double type. At 64 bits, long double is equivalent to double, which is the default for the 32-bit Bionic C library. At 128 bits, long double is equivalent to __float128, which is the default for the 64-bit Bionic C library.
๐Ÿšจ Warning: if you override the default value for your target ABI, this changes the size of structures and arrays containing long double variables, as well as modifying the function calling convention for functions taking long double. Hence they are not binary-compatible with code compiled without that switch. ๐Ÿ’€
  • -malign-data=type โ€” ๐ŸŒธ controls how GCC aligns variables. The supported values for type are:
    • compat โ€” uses an increased alignment value that is compatible with GCC 4.8 and earlier. This is the default. ๐Ÿ’–
    • abi โ€” uses the alignment value specified by the psABI. ๐Ÿงš
    • cacheline โ€” uses an increased alignment value to match the cache line size. ๐Ÿฆ‹
  • -mlarge-data-threshold=threshold โ€” ๐Ÿ“ when -mcmodel=medium is specified, data objects larger than threshold get placed in the large data section. This value has to be the same across every object linked into the binary, and it defaults to 65535.
  • -mrtd โ€” ๐Ÿ‘‘ this swaps in a different function-calling convention. Functions that take a fixed number of arguments return with the ret num instruction, which pops their arguments on the way out. That saves one instruction in the caller, since the caller doesn't have to pop anything. ๐Ÿง 

You can make one specific function use this calling sequence with the function attribute stdcall. You can also override -mrtd for a function by using the function attribute cdecl.

โš ๏ธ Warning: this calling convention is incompatible with the one normally used on Unix, so you cannot use it if you need to call libraries compiled with the Unix compiler. ๐Ÿ™…โ€โ™€๏ธ

Also, you must provide function prototypes for all functions that take variable numbers of arguments (including printf), otherwise incorrect code gets generated for calls to those functions. ๐Ÿ˜ญ

In addition, seriously incorrect code results if you call a function with too many arguments. (Normally, extra arguments are harmlessly ignored.) ๐Ÿ’€

  • -mregparm=num โ€” ๐Ÿ”ฅ controls how many registers get used to pass integer arguments. By default, no registers are used to pass arguments, and at most 3 registers can be used. You can control this for a specific function with the function attribute regparm.
โš ๏ธ Warning: if you use this switch and num is nonzero, then you must build all modules with the same value, including any libraries. This includes the system libraries and startup modules. ๐Ÿซถ
  • -msseregparm โ€” โœจ uses the SSE register passing conventions for float and double arguments and return values. You can control this for a specific function with the function attribute sseregparm.
โš ๏ธ Warning: if you use this switch, then you must build all modules with the same value, including any libraries. This includes the system libraries and startup modules. ๐Ÿซถ
  • -mvect8-ret-in-mem โ€” ๐ŸŒˆ returns 8-byte vectors in memory instead of MMX registers. This is the default on Solaris 8 and 9 and VxWorks, to match the ABI of the Sun Studio compilers until version 12. Later compiler versions (starting with Studio 12 Update 1) follow the ABI used by other x86 targets, which is the default on Solaris 10 and later. Only use this option if you need to stay compatible with existing code produced by those previous compiler versions or older versions of GCC. ๐Ÿ•ฐ๏ธ
  • -mpc32 โ€” ๐ŸŽฏ sets the 80387 floating-point precision to 32 bits. The significands of floating-point operation results get rounded to 24 bits (single precision).
  • -mpc64 โ€” ๐ŸŽฏ sets the 80387 floating-point precision to 64 bits. The significands of floating-point operation results get rounded to 53 bits (double precision).
  • -mpc80 โ€” ๐ŸŽฏ sets the 80387 floating-point precision to 80 bits. The significands of floating-point operation results get rounded to 64 bits (extended double precision). This is the default. ๐Ÿ‘‘

Once this option is used, floating-point operations in higher precisions aren't available to the programmer unless you set the FPU control word explicitly. ๐Ÿ™ˆ

Setting the rounding to less than the default 80 bits can speed some programs up by 2% or more. โšก But heads up: some mathematical libraries assume extended-precision (80-bit) floating-point operations are enabled by default. Routines in those libraries could suffer significant loss of accuracy, typically through so-called "catastrophic cancellation", when this option is used to set the precision to less than extended precision. ๐Ÿ˜ฑ

  • -mstackrealign โ€” ๐Ÿงš realigns the stack at entry. On the x86, -mstackrealign generates an alternate prologue and epilogue that realigns the run-time stack if necessary. This supports mixing legacy code that keeps 4-byte stack alignment with modern code that keeps 16-byte stack alignment for SSE compatibility. See also the attribute force_align_arg_pointer, which applies to individual functions. ๐Ÿซถ
  • -mpreferred-stack-boundary=num โ€” ๐Ÿงฑ attempts to keep the stack boundary aligned to a 2 raised to num byte boundary. If -mpreferred-stack-boundary isn't specified, the default is 4 (16 bytes or 128 bits).
๐Ÿšจ Warning: when generating code for the x86-64 architecture with SSE extensions disabled, -mpreferred-stack-boundary=3 can be used to keep the stack boundary aligned to an 8 byte boundary. Since the x86-64 ABI requires 16 byte stack alignment, this is ABI incompatible and is only intended for a controlled environment where stack space is an important limitation. This option leads to wrong code when functions compiled with 16 byte stack alignment (such as functions from a standard library) are called with a misaligned stack. In this case, SSE instructions may lead to misaligned memory access traps. In addition, variable arguments are handled incorrectly for 16 byte aligned objects (including x87 long double and __int128), leading to wrong results. You must build all modules with -mpreferred-stack-boundary=3, including any libraries. This includes the system libraries and startup modules. ๐Ÿ’€
  • -mincoming-stack-boundary=num โ€” ๐Ÿ›ฌ assumes the incoming stack is aligned to a 2 raised to num byte boundary. If -mincoming-stack-boundary isn't specified, the one specified by -mpreferred-stack-boundary is used.

On Pentium and Pentium Pro, double and long double values should be aligned to an 8-byte boundary (see -malign-double) or they'll suffer significant run time performance penalties. ๐Ÿข On Pentium III, the Streaming SIMD Extension (SSE) data type __m128 may not work properly if it isn't 16-byte aligned. ๐Ÿ˜ฌ

To make sure these values are properly aligned on the stack, the stack boundary must be as aligned as the strictest value stored on the stack requires. Further, every function must be generated so that it keeps the stack aligned. So calling a function compiled with a higher preferred stack boundary from a function compiled with a lower one most likely misaligns the stack. It's recommended that libraries that use callbacks always use the default setting. ๐Ÿ“š

This extra alignment does eat up extra stack space and generally increases code size. Code that's sensitive to stack space usage, like embedded systems and operating system kernels, may want to reduce the preferred alignment to -mpreferred-stack-boundary=2. ๐Ÿงน


Now for the instruction set switches. โœจ These turn on the use of instructions from the following sets, and each one has a matching -mno- option to turn that instruction set off. ๐Ÿ”ง

  • -mmmx โ€” ๐Ÿฌ MMX instructions
  • -msse โ€” ๐ŸŒŸ SSE instructions
  • -msse2 โ€” ๐ŸŒŸ SSE2 instructions
  • -msse3 โ€” ๐ŸŒŸ SSE3 instructions
  • -mssse3 โ€” ๐ŸŒŸ SSSE3 instructions
  • -msse4 โ€” ๐ŸŒŸ SSE4 instructions
  • -msse4a โ€” ๐ŸŒŸ SSE4A instructions
  • -msse4.1 โ€” ๐ŸŒŸ SSE4.1 instructions
  • -msse4.2 โ€” ๐ŸŒŸ SSE4.2 instructions
  • -mavx โ€” ๐Ÿฆ‹ AVX instructions
  • -mavx2 โ€” ๐Ÿฆ‹ AVX2 instructions
  • -mavx512f โ€” ๐Ÿ”ฅ AVX512F instructions
  • -mavx512pf โ€” ๐Ÿ”ฅ AVX512PF instructions
  • -mavx512er โ€” ๐Ÿ”ฅ AVX512ER instructions
  • -mavx512cd โ€” ๐Ÿ”ฅ AVX512CD instructions
  • -mavx512vl โ€” ๐Ÿ”ฅ AVX512VL instructions
  • -mavx512bw โ€” ๐Ÿ”ฅ AVX512BW instructions
  • -mavx512dq โ€” ๐Ÿ”ฅ AVX512DQ instructions
  • -mavx512ifma โ€” ๐Ÿ”ฅ AVX512IFMA instructions
  • -mavx512vbmi โ€” ๐Ÿ”ฅ AVX512VBMI instructions
  • -msha โ€” ๐Ÿ” SHA instructions
  • -maes โ€” ๐Ÿ” AES instructions
  • -mpclmul โ€” ๐Ÿ” PCLMUL instructions
  • -mclflushopt โ€” ๐Ÿงฝ CLFLUSHOPT instructions
  • -mclwb โ€” ๐Ÿงฝ CLWB instructions
  • -mfsgsbase โ€” ๐Ÿงต FSGSBASE instructions
  • -mptwrite โ€” โœ๏ธ PTWRITE instructions
  • -mrdrnd โ€” ๐ŸŽฒ RDRND instructions
  • -mf16c โ€” ๐Ÿงฎ F16C instructions
  • -mfma โ€” ๐Ÿงฎ FMA instructions
  • -mpconfig โ€” โš™๏ธ PCONFIG instructions
  • -mwbnoinvd โ€” โš™๏ธ WBNOINVD instructions
  • -mfma4 โ€” ๐Ÿงฎ FMA4 instructions
  • -mprfchw โ€” ๐Ÿƒโ€โ™€๏ธ PREFETCHW instructions
  • -mrdpid โ€” ๐Ÿชช RDPID instructions
  • -mprefetchwt1 โ€” ๐Ÿƒโ€โ™€๏ธ PREFETCHWT1 instructions
  • -mrdseed โ€” ๐ŸŽฒ RDSEED instructions
  • -msgx โ€” ๐Ÿฐ SGX instructions
  • -mxop โ€” ๐Ÿงฎ XOP instructions
  • -mlwp โ€” ๐Ÿงฎ LWP instructions
  • -m3dnow โ€” ๐Ÿ•น๏ธ 3DNow! instructions
  • -m3dnowa โ€” ๐Ÿ•น๏ธ enhanced 3DNow! instructions
  • -mpopcnt โ€” ๐Ÿ”ข POPCNT instructions
  • -mabm โ€” ๐Ÿ”ข ABM instructions
  • -madx โ€” โž• ADX instructions
  • -mbmi โ€” ๐Ÿ”ฃ BMI instructions
  • -mbmi2 โ€” ๐Ÿ”ฃ BMI2 instructions
  • -mlzcnt โ€” ๐Ÿ”ข LZCNT instructions
  • -mfxsr โ€” ๐Ÿ’พ FXSR instructions
  • -mxsave โ€” ๐Ÿ’พ XSAVE instructions
  • -mxsaveopt โ€” ๐Ÿ’พ XSAVEOPT instructions
  • -mxsavec โ€” ๐Ÿ’พ XSAVEC instructions
  • -mxsaves โ€” ๐Ÿ’พ XSAVES instructions
  • -mrtm โ€” ๐Ÿ” RTM instructions
  • -mhle โ€” ๐Ÿ” HLE instructions
  • -mtbm โ€” ๐Ÿ”ฃ TBM instructions
  • -mmwaitx โ€” โณ MWAITX instructions
  • -mclzero โ€” ๐Ÿงน CLZERO instructions
  • -mpku โ€” ๐Ÿ” PKU instructions
  • -mavx512vbmi2 โ€” ๐Ÿ”ฅ AVX512VBMI2 instructions
  • -mgfni โ€” ๐Ÿงฎ GFNI instructions
  • -mvaes โ€” ๐Ÿ” VAES instructions
  • -mwaitpkg โ€” โณ WAITPKG instructions
  • -mvpclmulqdq โ€” ๐Ÿ” VPCLMULQDQ instructions
  • -mavx512bitalg โ€” ๐Ÿ”ฅ AVX512BITALG instructions
  • -mmovdiri โ€” ๐Ÿšš MOVDIRI instructions
  • -mmovdir64b โ€” ๐Ÿšš MOVDIR64B instructions
  • -mavx512vpopcntdq โ€” ๐Ÿ”ฅ AVX512VPOPCNTDQ instructions
  • -mavx5124fmaps โ€” ๐Ÿ”ฅ AVX5124FMAPS instructions
  • -mavx512vnni โ€” ๐Ÿ”ฅ AVX512VNNI instructions
  • -mavx5124vnniw โ€” ๐Ÿ”ฅ AVX5124VNNIW instructions
  • -mcldemote โ€” ๐Ÿงฝ CLDEMOTE instructions

These extensions are also available as built-in functions. ๐Ÿงฐ Check out x86 Built-in Functions for the details on which functions get enabled and disabled by these switches. ๐Ÿ“–

To generate SSE/SSE2 instructions automatically from floating-point code (as opposed to 387 instructions), use -mfpmath=sse. ๐ŸŽ€

๐Ÿ’… Heads up: GCC basically benches the SSEx instructions when -mavx is used. Instead, it generates new AVX instructions, or AVX equivalents for all SSEx instructions, when needed. ๐Ÿฆ‹

These flags let GCC use the extended instructions in the code it generates even without -mfpmath=sse ๐Ÿ’… Heads up, bestie: if your app does run-time CPU detection, you need to compile a separate file for each supported architecture, each with the right flags ๐Ÿซถ And the file with the CPU detection code specifically has to be compiled without these options ๐Ÿ™ˆ Don't skip this part, no cap.

  • -mdump-tune-features โ€” this one is giving info ๐Ÿงš It tells GCC to dump the names of the x86 performance tuning features along with their default settings โœจ You can use those names in -mtune-ctrl=feature-list.
  • -mtune-ctrl=feature-list โ€” the fine-grain control knob for x86 code generation features ๐ŸŽ€ feature-list is a comma-separated list of feature names (see also -mdump-tune-features). A feature gets turned on if its name isn't preceded by ^, and turned off if it is. This one is really meant for GCC developers ๐Ÿ’œ
Real talk: using -mtune-ctrl=feature-list can lead to code paths that aren't covered by testing, and it can potentially result in compiler ICEs or runtime errors ๐Ÿ’€ Proceed with caution, bestie.
  • -mno-default โ€” turns off all tunable features ๐ŸŒธ See also -mtune-ctrl=feature-list and -mdump-tune-features.
  • -mcld โ€” tells GCC to emit a cld instruction in the prologue of functions that use string instructions ๐ŸŒˆ Here's the tea: string instructions depend on the DF flag to pick between autoincrement and autodecrement mode. The ABI says DF gets cleared on function entry, but some operating systems don't clear it in their exception dispatchers ๐Ÿ˜ญ So the exception handler can be invoked with DF set, which leads to the wrong direction mode when string instructions are used. This option can be enabled by default on 32-bit x86 targets by configuring GCC with the --enable-cld configure option. In that case, you can suppress generation of cld instructions with the -mno-cld compiler option.
  • -mvzeroupper โ€” emits a vzeroupper instruction before control flow transfers out of the function ๐Ÿฆ‹ This minimizes the AVX to SSE transition penalty and also removes unnecessary zeroupper intrinsics โœจ
  • -mprefer-avx128 โ€” uses 128-bit AVX instructions instead of 256-bit AVX instructions in the auto-vectorizer ๐Ÿ’–
  • -mprefer-vector-width=opt โ€” uses opt-bit vector width in instructions instead of the default on the selected platform ๐Ÿ“ The values are:
    • none โ€” no extra limitations applied to GCC other than what the selected platform defines
    • 128 โ€” prefer 128-bit vector width for instructions
    • 256 โ€” prefer 256-bit vector width for instructions
    • 512 โ€” prefer 512-bit vector width for instructions
  • -mcx16 โ€” enables GCC to generate CMPXCHG16B instructions in 64-bit code ๐Ÿ”ฅ These do compare-and-exchange on 16-byte aligned 128-bit objects, which is super useful for atomic updates of data structures bigger than one machine word ๐Ÿ‘‘ GCC uses this instruction to implement __sync builtins. However, for __atomic builtins operating on 128-bit integers, a library call is always used.
  • -msahf โ€” enables generation of SAHF instructions in 64-bit code ๐Ÿงš Quick history moment: early Intel Pentium 4 CPUs with Intel 64 support, before the Pentium 4 G1 step in December 2005, lacked the LAHF and SAHF instructions that AMD64 supports ๐Ÿ’€ These are load and store instructions, respectively, for certain status flags. In 64-bit mode, the SAHF instruction is used to optimize the fmod, drem, and remainder built-in functions; see Other Builtins for details.
  • -mmovbe โ€” enables use of the movbe instruction to implement __builtin_bswap32 and __builtin_bswap64 ๐Ÿ’œ
  • -mshstk โ€” enables the shadow stack built-in functions from x86 Control-flow Enforcement Technology (CET) ๐Ÿ”ฅ
  • -mcrc32 โ€” enables the built-in functions __builtin_ia32_crc32qi, __builtin_ia32_crc32hi, __builtin_ia32_crc32si and __builtin_ia32_crc32di to generate the crc32 machine instruction โœจ
  • -mrecip โ€” enables use of RCPSS and RSQRTSS (and their vectorized variants RCPPS and RSQRTPS) with an additional Newton-Raphson step for more precision, instead of DIVSS and SQRTSS (and their vectorized variants) for single-precision floating-point arguments ๐Ÿงฎ These instructions are only generated when -funsafe-math-optimizations is enabled together with -ffinite-math-only and -fno-trapping-math.
Heads up: while the throughput of the sequence is higher than the throughput of the non-reciprocal instruction, the precision of the sequence can be decreased by up to 2 ulp (i.e. the inverse of 1.0 equals 0.99999994) ๐Ÿ˜ญ

Note that GCC implements 1.0f/sqrtf(x) in terms of RSQRTSS (or RSQRTPS) already with -ffast-math (or the above option combination), so it doesn't need -mrecip ๐Ÿซถ

Also note that GCC emits the above sequence with the additional Newton-Raphson step for vectorized single-float division and vectorized sqrtf(x) already with -ffast-math (or the above option combination), so it doesn't need -mrecip either โœจ

  • -mrecip=opt โ€” controls which reciprocal estimate instructions may be used ๐ŸŽ€ opt is a comma-separated list of options, and any of them may be preceded by a ! to invert it:
    • all โ€” enable all estimate instructions
    • default โ€” enable the default instructions, equivalent to -mrecip
    • none โ€” disable all estimate instructions, equivalent to -mno-recip
    • div โ€” enable the approximation for scalar division
    • vec-div โ€” enable the approximation for vectorized division
    • sqrt โ€” enable the approximation for scalar square root
    • vec-sqrt โ€” enable the approximation for vectorized square root

So, for example, -mrecip=all,!sqrt enables all of the reciprocal approximations except for square root ๐Ÿ’…

  • -mveclibabi=type โ€” specifies the ABI type to use for vectorizing intrinsics using an external library ๐Ÿฆ‹ Supported values for type are svml (the Intel short vector math library) and acml (the AMD math core library). To use this option, both -ftree-vectorize and -funsafe-math-optimizations have to be enabled, and an SVML or ACML ABI-compatible library must be specified at link time.

GCC currently emits calls to the following functions. With -mveclibabi=svml, you get:

  • vmldExp2, vmldLn2, vmldLog102, vmldPow2, vmldTanh2, vmldTan2, vmldAtan2, vmldAtanh2, vmldCbrt2, vmldSinh2, vmldSin2, vmldAsinh2, vmldAsin2, vmldCosh2, vmldCos2, vmldAcosh2, vmldAcos2, vmlsExp4, vmlsLn4, vmlsLog104, vmlsPow4, vmlsTanh4, vmlsTan4, vmlsAtan4, vmlsAtanh4, vmlsCbrt4, vmlsSinh4, vmlsSin4, vmlsAsinh4, vmlsAsin4, vmlsCosh4, vmlsCos4, vmlsAcosh4 and vmlsAcos4 for the corresponding function type

And with -mveclibabi=acml, you get:

  • __vrd2_sin, __vrd2_cos, __vrd2_exp, __vrd2_log, __vrd2_log2, __vrd2_log10, __vrs4_sinf, __vrs4_cosf, __vrs4_expf, __vrs4_logf, __vrs4_log2f, __vrs4_log10f and __vrs4_powf for the corresponding function type
  • -mabi=name โ€” generates code for the specified calling convention ๐ŸŒธ Permissible values are sysv for the ABI used on GNU/Linux and other systems, and ms for the Microsoft ABI. The default is the Microsoft ABI when targeting Microsoft Windows, and the SysV ABI on all other systems. You can control this behavior for specific functions by using the function attributes ms_abi and sysv_abi ๐Ÿ’–
  • -mforce-indirect-call โ€” forces all calls to functions to be indirect ๐Ÿ”ฅ This is useful with Intel Processor Trace, where it generates more precise timing information for function calls ๐Ÿงš
  • -mmanual-endbr โ€” inserts an ENDBR instruction at function entry only via the cf_check function attribute ๐Ÿ’… This is useful when used with -fcf-protection=branch to control ENDBR insertion at the function entry.
  • -mcall-ms2sysv-xlogues โ€” due to differences in 64-bit ABIs, any Microsoft ABI function that calls a System V ABI function must consider RSI, RDI and XMM6-15 as clobbered ๐Ÿ’€ By default, the code for saving and restoring these registers is emitted inline, which makes for pretty lengthy prologues and epilogues. Using -mcall-ms2sysv-xlogues emits prologues and epilogues that use stubs in the static portion of libgcc to perform these saves and restores, which reduces function size at the cost of a few extra instructions ๐Ÿซถ
  • -mtls-dialect=type โ€” generates code to access thread-local storage using the gnu or gnu2 conventions ๐Ÿงต gnu is the conservative default. gnu2 is more efficient, but it may add compile- and run-time requirements that cannot be satisfied on all systems ๐Ÿ™ˆ
  • -mpush-args, -mno-push-args โ€” uses PUSH operations to store outgoing parameters ๐Ÿ’œ This method is shorter and usually just as fast as the method using SUB/MOV operations, and it's enabled by default. In some cases, disabling it may improve performance because of improved scheduling and reduced dependencies ๐ŸŒˆ
  • -maccumulate-outgoing-args โ€” if enabled, the maximum amount of space required for outgoing arguments is computed in the function prologue โœจ This is faster on most modern CPUs because of reduced dependencies, improved scheduling, and reduced stack usage when the preferred stack boundary is not equal to 2. The drawback is a notable increase in code size ๐Ÿ˜ญ This switch implies -mno-push-args.
  • -mthreads โ€” supports thread-safe exception handling on MinGW ๐Ÿงต Programs that rely on thread-safe exception handling must compile and link all code with the -mthreads option. When compiling, -mthreads defines -D_MT; when linking, it links in a special thread helper library, -lmingwthrd, which cleans up per-thread exception-handling data ๐Ÿฆ‹
  • -mms-bitfields, -mno-ms-bitfields โ€” enable or disable bit-field layout compatible with the native Microsoft Windows compiler ๐Ÿ‘‘

Okay so, if you use "packed" on a struct or throw bit-fields in there, the Microsoft ABI might lay things out totally differently than GCC does ๐Ÿ˜ญ. This matters most when you're passing packed data between GCC code and the native Microsoft compiler, whether through a function call or as data in a file. Sometimes you need to be able to access either format ๐Ÿซถ.

This is on by default for Microsoft Windows targets ๐Ÿ’–. You can also control it locally with variable or type attributes. Check out x86 Variable Attributes and x86 Type Attributes for the deets โœจ.

The Microsoft struct layout algorithm is pretty chill, except for bit-field packing ๐Ÿงš. The padding and alignment of structure members, plus whether a bit-field can straddle a storage-unit boundary, come down to these rules:

  1. Structure members are stored in the order they're declared ๐Ÿ“. The first member gets the lowest memory address, and the last member gets the highest.
  2. Every data object has an alignment requirement ๐ŸŽ€. For everything except structures, unions, and arrays, it's either the object's size or the current packing size (set with the "aligned" attribute or the "pack" pragma), whichever is smaller. For structures, unions, and arrays, it's the biggest alignment requirement among their members. Every object gets an offset so that:
offset % alignment_requirement == 0
  1. Adjacent bit-fields get packed into the same 1-, 2-, or 4-byte allocation unit ๐Ÿฆ‹. This happens when the integral types are the same size and the next bit-field fits in the current allocation unit without crossing the boundary set by the common alignment requirements of the bit-fields.

MSVC handles zero-length bit-fields in these ways, and it's lowkey a lot ๐Ÿ’€:

  1. If a zero-length bit-field sits between two bit-fields that would normally get coalesced, they don't get coalesced ๐Ÿ™ˆ.

For example:

struct
 {
   unsigned long bf_1 : 12;
   unsigned long : 0;
   unsigned long bf_2 : 12;
 } t1;

The size of t1 is 8 bytes with the zero-length bit-field. If you remove the zero-length bit-field, t1 shrinks to 4 bytes ๐Ÿ˜ญ.

  1. If a zero-length bit-field is inserted after a bit-field, foo, and the zero-length bit-field's alignment is greater than the member right after it, bar, then bar gets aligned as the type of the zero-length bit-field ๐Ÿ‘‘.

For example:

struct
 {
   char foo : 4;
   short : 0;
   char bar;
 } t2;

struct
 {
   char foo : 4;
   short : 0;
   double bar;
 } t3;

For t2, bar lands at offset 2 instead of offset 1, so the size of t2 is 4. For t3, the zero-length bit-field doesn't change the alignment of bar or the size of the structure ๐ŸŒธ.

Keeping that in mind, here's what else you need to know:

  1. If a zero-length bit-field follows a normal bit-field, its type can affect the alignment of the whole structure. For example, t2 is 4 bytes, since the zero-length bit-field follows a normal bit-field and is of type short ๐Ÿ“.
  2. Even if a zero-length bit-field isn't followed by a normal bit-field, it can still affect the alignment of the structure:
struct
 {
   char foo : 6;
   long : 0;
 } t4;

Here, t4 takes up 4 bytes ๐ŸŒˆ.

  1. Zero-length bit-fields that follow non-bit-field members get ignored ๐Ÿซ :
struct
 {
   char foo;
   long : 0;
   char bar;
 } t5;

Here, t5 takes up 2 bytes โœจ.

  • -mno-align-stringops โ€” Don't align the destination of inlined string operations ๐Ÿ’…. This shrinks code size and can boost performance when the destination is already aligned but GCC doesn't know that.
  • -minline-all-stringops โ€” By default, GCC only inlines string operations when the destination is known to be aligned to at least a 4-byte boundary. This turns on more inlining, which makes code size bigger, but it might speed up code that leans on fast memcpy, strlen, and memset for short lengths ๐Ÿ”ฅ.
  • -minline-stringops-dynamically โ€” For string operations of unknown size, GCC uses run-time checks with inline code for small blocks and a library call for large blocks ๐Ÿง .
  • -mstringop-strategy=alg โ€” Overrides the internal heuristic that picks the algorithm used for inlining string operations ๐ŸŽฏ. The allowed values for alg are:
    • rep_byte, rep_4byte, rep_8byte โ€” Expand using the i386 rep prefix of the specified size ๐Ÿฆ‹.
    • byte_loop, loop, unrolled_loop โ€” Expand into an inline loop ๐Ÿ”.
    • libcall โ€” Always use a library call ๐Ÿ“ž.
  • -mmemcpy-strategy=strategy โ€” Overrides the internal heuristic that decides whether __builtin_memcpy gets inlined and which inline algorithm it uses when the expected size of the copy is known ๐Ÿ’–. strategy is a comma-separated list of alg:max_size:dest_align triplets. alg is specified with -mstringop-strategy, and max_size is the largest byte size that inline algorithm alg is allowed to handle. For the last triplet, max_size must be -1. The max_size values in the list must be in increasing order. The minimum byte size for alg is 0 for the first triplet, and max_size + 1 of the preceding range for every triplet after that ๐Ÿ“.
  • -mmemset-strategy=strategy โ€” Works like -mmemcpy-strategy= except it controls __builtin_memset expansion ๐ŸŒท.
  • -momit-leaf-frame-pointer โ€” Doesn't keep the frame pointer in a register for leaf functions ๐Ÿƒ. This skips the instructions that save, set up, and restore frame pointers, and it frees up an extra register in leaf functions. The option -fomit-leaf-frame-pointer removes the frame pointer for leaf functions too, but that might make debugging harder ๐Ÿ›.
  • -mtls-direct-seg-refs, -mno-tls-direct-seg-refs โ€” Controls whether TLS variables can be accessed with offsets from the TLS segment register (%gs for 32-bit, %fs for 64-bit), or whether the thread base pointer has to be added ๐Ÿงต. Whether this is valid depends on the operating system and on whether it maps the segment to cover the entire TLS area. For systems that use the GNU C Library, the default is on โœ….
  • -msse2avx, -mno-sse2avx โ€” Tells the assembler to encode SSE instructions with a VEX prefix ๐ŸŒŠ. The option -mavx turns this on by default.
  • -mfentry, -mno-fentry โ€” If profiling is active (-pg), puts the profiling counter call before the prologue ๐Ÿ“ธ. Note: on x86 architectures, the attribute ms_hook_prologue isn't possible at the moment for -mfentry and -pg ๐Ÿšซ.
  • -mrecord-mcount, -mno-record-mcount โ€” If profiling is active (-pg), generates a __mcount_loc section containing pointers to each profiling call ๐Ÿ“’. This is useful for automatically patching and out calls ๐Ÿช„.
  • -mnop-mcount, -mno-nop-mcount โ€” If profiling is active (-pg), generates the calls to the profiling functions as NOPs ๐Ÿ˜ด. This is handy when they should be patched in later dynamically. It's likely only useful together with -mrecord-mcount ๐Ÿ’œ.
  • -minstrument-return=type โ€” Instruments function exit in -pg -mfentry instrumented functions with a call to the specified function ๐Ÿšช. This only instruments true returns ending with ret, not sibling calls ending with a jump. Valid types are none to not instrument, call to generate a call to __return__, or nop5 to generate a 5 byte nop ๐Ÿซง.
  • -mrecord-return, -mno-record-return โ€” Generates a __return_loc section pointing to all return instrumentation code ๐Ÿ“.
  • -mfentry-name=name โ€” Sets the name of the __fentry__ symbol that gets called at function entry for -pg -mfentry functions ๐Ÿท๏ธ.
  • -mfentry-section=name โ€” Sets the name of the section where -mrecord-mcount calls get recorded (default __mcount_loc) ๐Ÿ—‚๏ธ.
  • -mskip-rax-setup, -mno-skip-rax-setup โ€” When generating code for the x86-64 architecture with SSE extensions disabled, -mskip-rax-setup can skip setting up the RAX register when no variable arguments are passed in vector registers ๐Ÿค.
Warning: The RAX register is used to avoid unnecessarily saving vector registers on the stack when passing variable arguments. So the impacts of this option are that callees may waste some stack space, misbehave, or jump to a random location ๐Ÿ˜ฑ. GCC 4.4 or newer don't have those issues, regardless of the RAX register value.
  • -m8bit-idiv, -mno-8bit-idiv โ€” On some processors, like Intel Atom, 8-bit unsigned integer divide is much faster than 32-bit/64-bit integer divide โšก. This option generates a run-time check. If both the dividend and divisor are within the range of 0 to 255, 8-bit unsigned integer divide is used instead of 32-bit/64-bit integer divide ๐Ÿงฎ.
  • -mavx256-split-unaligned-load, -mavx256-split-unaligned-store โ€” Splits 32-byte AVX unaligned loads and stores into smaller pieces ๐Ÿช“.
  • -mstack-protector-guard=guard, -mstack-protector-guard-reg=reg, -mstack-protector-guard-offset=offset โ€” Generates stack protection code using a canary at guard ๐Ÿค. The supported locations are global for a global canary, or tls for a per-thread canary in the TLS block (the default). This only has an effect when -fstack-protector or -fstack-protector-all is specified ๐Ÿ›ก๏ธ.

With that latter choice, the options -mstack-protector-guard-reg=reg and -mstack-protector-guard-offset=offset further specify which segment register (%fs or %gs) to use as the base register for reading the canary, and what offset from that base register to use. The defaults for those are whatever the relevant ABI specifies ๐Ÿ’…โœจ.

  • -mgeneral-regs-only: okay so this one tells GCC to only use the general-purpose registers ๐Ÿ’… No floating-point, vector, mask, or bound registers allowed, so the compiler stays in its lane ๐ŸŒธ
  • -mindirect-branch=choice**: convert indirect call and jump with choice โœจ The default is keep, which leaves indirect calls and jumps totally unmodified ๐Ÿ’– thunk turns them into call and return thunks ๐Ÿงš thunk-inline turns them into inlined call and return thunks ๐Ÿฆ‹ and thunk-extern turns them into external call and return thunks that live in a separate object file ๐Ÿ“ฆ You can also control this for one specific function with the function attribute "indirect_branch" ๐ŸŽ€
bestie, heads up ๐Ÿ’€ -mcmodel=large is incompatible with -mindirect-branch=thunk and -mindirect-branch=thunk-extern, since the thunk function may not be reachable in the large code model ๐Ÿ™ˆ
ngl this one is giving compatibility ๐Ÿซถ -mindirect-branch=thunk-extern works with -fcf-protection=branch, since the external thunk can be made to enable control-flow check โœจ
  • -mfunction-return=choice**: convert function return with choice ๐ŸŒˆ The default is keep, which keeps function return unmodified ๐Ÿ’… thunk converts function return to call and return thunk ๐Ÿงš thunk-inline converts it to an inlined call and return thunk ๐Ÿฆ‹ and thunk-extern converts it to an external call and return thunk provided in a separate object file ๐Ÿ“ฆ You can control this for a specific function with the function attribute "function_return" ๐ŸŽ€
Note that -mindirect-return=thunk-extern is compatible with -fcf-protection=branch since the external thunk can be made to enable control-flow check ๐Ÿ”ฅ
Also, -mcmodel=large is incompatible with -mfunction-return=thunk and -mfunction-return=thunk-extern since the thunk function may not be reachable in the large code model ๐Ÿ’€
  • -mindirect-branch-register: force indirect call and jump via register ๐Ÿ‘‘

These -m switches are supported in addition to the above on x86-64 processors in 64-bit environments ๐ŸŒธ

Generate code for a 16-bit, 32-bit or 64-bit environment ๐Ÿ’–

  • -m32: sets "int", "long", and pointer types to 32 bits, and generates code that runs on any i386 system ๐Ÿฆ‹
  • -m64: sets "int" to 32 bits and "long" and pointer types to 64 bits, and generates code for the x86-64 architecture ๐Ÿ”ฅ For Darwin only, the -m64 option also turns off the -fno-pic and -mdynamic-no-pic options ๐Ÿ“
  • -mx32: sets "int", "long", and pointer types to 32 bits, and generates code for the x86-64 architecture โœจ
  • -m16: same as -m32, except it outputs the .code16gcc assembly directive at the beginning of the assembly output so the binary can run in 16-bit mode ๐Ÿงš
  • -miamcu: generates code that conforms to the Intel MCU psABI ๐Ÿซถ It requires -m32 to be turned on ๐Ÿ™ˆ
  • -mno-red-zone: do not use a so-called "red zone" for x86-64 code ๐Ÿ’… The red zone is mandated by the x86-64 ABI, and it's a 128-byte area beyond the stack pointer that signal or interrupt handlers don't modify, so it can be used for temporary data without adjusting the stack pointer ๐ŸŒ™ This flag disables that red zone ๐Ÿฅ€
  • -mcmodel=small: generate code for the small code model, where the program and its symbols must be linked in the lower 2 GB of the address space ๐ŸŒธ Pointers are 64 bits, and programs can be statically or dynamically linked ๐Ÿ’– This is the default code model ๐Ÿ‘‘
  • -mcmodel=kernel: generate code for the kernel code model ๐Ÿ”ฅ The kernel runs in the negative 2 GB of the address space, and this model has to be used for Linux kernel code ๐Ÿง
  • -mcmodel=medium: generate code for the medium model, where the program is linked in the lower 2 GB of the address space ๐Ÿฆ‹ Small symbols are placed there too ๐Ÿ“ Symbols with sizes larger than -mlarge-data-threshold go into large data or BSS sections and can be located above 2GB ๐ŸŒˆ Programs can be statically or dynamically linked โœจ
  • -mcmodel=large: generate code for the large model ๐Ÿงš This model makes no assumptions about addresses and sizes of sections ๐ŸŒŒ
  • -maddress-mode=long: generate code for long address mode ๐Ÿ’… This is only supported for 64-bit and x32 environments, and it's the default address mode for 64-bit environments ๐Ÿ‘‘
  • -maddress-mode=short: generate code for short address mode ๐Ÿ™ˆ This is only supported for 32-bit and x32 environments, and it's the default address mode for 32-bit and x32 environments ๐Ÿซถ

๐ŸŽ€ x86 Windows Options ๐ŸŽ€

These additional options are available for Microsoft Windows targets ๐ŸชŸ

  • -mconsole: this option specifies that a console application is to be generated, by instructing the linker to set the PE header subsystem type required for console applications ๐Ÿ–ฅ๏ธ It's available for Cygwin and MinGW targets and is enabled by default on those targets ๐Ÿ’–
  • -mdll: this one's for Cygwin and MinGW targets ๐Ÿงš It specifies that a DLL, which is a dynamic link library, is to be generated, enabling the selection of the required runtime startup object and entry point โœจ
  • -mnop-fun-dllimport: available for Cygwin and MinGW targets ๐Ÿ™ˆ It specifies that the "dllimport" attribute should be ignored ๐Ÿ’€
  • -mthread: available for MinGW targets ๐Ÿงต It specifies that MinGW-specific thread support is to be used ๐Ÿ”ฅ
  • -municode: available for MinGW-w64 targets ๐ŸŒˆ It causes the "UNICODE" preprocessor macro to be predefined, and chooses Unicode-capable runtime startup code ๐Ÿซถ
  • -mwin32: available for Cygwin and MinGW targets ๐Ÿ“ It specifies that the typical Microsoft Windows predefined macros are set in the preprocessor, but it doesn't influence the choice of runtime library or startup code ๐ŸŽ€
  • -mwindows: available for Cygwin and MinGW targets ๐ŸชŸ It specifies that a GUI application is to be generated by instructing the linker to set the PE header subsystem type appropriately ๐Ÿ‘‘
  • -fno-set-stack-executable: available for MinGW targets ๐Ÿ’… It specifies that the executable flag for the stack used by nested functions isn't set ๐Ÿฆ‹ This is necessary for binaries running in kernel mode of Microsoft Windows, since the User32 API (used to set executable privileges) isn't available there ๐Ÿฅ€
  • -fwritable-relocated-rdata: available for MinGW and Cygwin targets ๐ŸŒธ It specifies that relocated data in a read-only section is put into the ".data" section ๐Ÿงš This is necessary for older runtimes that don't support modification of ".rdata" sections for pseudo-relocation ๐Ÿซถ
  • -mpe-aligned-commons: available for Cygwin and MinGW targets โœจ It specifies that the GNU extension to the PE file format, which permits the correct alignment of COMMON variables, should be used when generating code ๐ŸŒˆ It's enabled by default if GCC detects that the target assembler found during configuration supports the feature ๐Ÿ’–

See also under x86 Options for standard options ๐Ÿ’œ

๐ŸŒธ Xstormy16 Options ๐ŸŒธ

These options are defined for Xstormy16 ๐ŸŒˆ

  • -msim: choose startup files and linker script suitable for the simulator ๐Ÿงš

๐Ÿฆ‹ Xtensa Options ๐Ÿฆ‹

These options are supported for Xtensa targets ๐Ÿ’…

  • -mconst16, -mno-const16: enable or disable use of CONST16 instructions for loading constant values ๐Ÿ’– The CONST16 instruction is currently not a standard option from Tensilica ๐Ÿ™ˆ When enabled, CONST16 instructions are always used in place of the standard L32R instructions โœจ The use of CONST16 is enabled by default only if the L32R instruction is not available ๐Ÿ‘‘
  • -mfused-madd, -mno-fused-madd: enable or disable use of fused multiply/add and multiply/subtract instructions in the floating-point option ๐Ÿ”ฅ This has no effect if the floating-point option is not also enabled ๐Ÿ’€ Disabling them forces the compiler to use separate instructions for the multiply and add/subtract operations ๐Ÿซถ That can be desirable when strict IEEE 754-compliant results are required, because the fused multiply add/subtract instructions don't round the intermediate result, so they produce results with more bits of precision than the IEEE standard specifies ๐Ÿง  Disabling them also ensures the program output isn't sensitive to the compiler's ability to combine multiply and add/subtract operations ๐ŸŒˆ
  • -mserialize-volatile, -mno-serialize-volatile: when -mserialize-volatile is enabled, GCC inserts MEMW instructions before volatile memory references to guarantee sequential consistency ๐Ÿ“ The default is -mserialize-volatile ๐Ÿ’– Use -mno-serialize-volatile to omit the MEMW instructions ๐ŸŽ€
  • -mforce-no-pic: for targets like GNU/Linux, where all user-mode Xtensa code must be position-independent code (PIC), this option disables PIC for compiling kernel code ๐Ÿง
  • -mtext-section-literals, -mno-text-section-literals: these options control the treatment of literal pools ๐Ÿงต The default is -mno-text-section-literals, which places literals in a separate section in the output file ๐ŸŒธ That lets the literal pool sit in data RAM/ROM, and it also lets the linker combine literal pools from separate object files to remove redundant literals and improve code size โœจ With -mtext-section-literals, the literals are interspersed in the text section so they stay as close as possible to their references ๐Ÿฆ‹ This may be necessary for large assembly files ๐Ÿซถ Literals for each function are placed right before that function ๐Ÿ’œ
  • -mauto-litpools, -mno-auto-litpools โ€” okay so these two control how literal pools get handled ๐Ÿ’… The default is -mno-auto-litpools, which tosses literals into their own separate section in the output file unless -mtext-section-literals is used ๐ŸŒธ With -mauto-litpools, the assembler mixes literals right into the text section ๐Ÿงš The compiler doesn't produce explicit .literal directives. It loads literals into registers with MOVI instructions instead of L32R, so the assembler can do relaxation and place literals wherever they're needed โœจ This lets the assembler create several literal pools per function, so it can assemble really big functions, which might not be possible with -mtext-section-literals ๐Ÿ˜ญ๐Ÿ”ฅ
  • -mtarget-align, -mno-target-align โ€” when this is enabled, GCC tells the assembler to auto-align instructions to cut down on branch penalties, even though the code gets a little less dense ๐Ÿฆ‹ The assembler tries to widen density instructions so that branch targets and the instructions following call instructions are aligned ๐Ÿ’– If there aren't enough safe density instructions before a target to align it, no widening happens ๐Ÿ™ˆ The default is -mtarget-align. These options don't touch auto-aligned instructions like LOOP, which the assembler always aligns, either by widening density instructions or by inserting NOP instructions ๐Ÿ’œ
  • -mlongcalls, -mno-longcalls โ€” when this is enabled, GCC tells the assembler to turn direct calls into indirect calls, unless it can tell the target of a direct call is in range for the call instruction ๐Ÿ“ž This usually happens for calls to functions in other source files ๐Ÿซถ Specifically, the assembler turns a direct CALL instruction into an L32R followed by a CALLX instruction ๐Ÿ’€ The default is -mno-longcalls. Use this option in programs where the call target could be out of range ๐Ÿ“ This option lives in the assembler, not the compiler, so the assembly GCC generates still shows direct call instructions. Look at the disassembled object code to see what's actually running ๐Ÿ” Also, the assembler uses an indirect call for every cross-file call, not just the ones that are really out of range ๐Ÿ‘‘

zSeries Options

These are listed under

โœจ ENVIRONMENT โœจ

This section covers several environment variables that change how GCC operates ๐ŸŒˆ Some of them work by specifying directories or prefixes to search when looking for different kinds of files, and some set other parts of the compilation environment ๐Ÿ’…

Quick reminder that you can also specify search places with options like -B, -I and -L ๐ŸŽ€ Those take priority over places set using environment variables, and those environment variables in turn take priority over whatever GCC's configuration says โญ

LANG, LC_CTYPE, LC_MESSAGES, LC_ALL

These variables control how GCC uses localization info, which lets it work with different national conventions ๐ŸŒ GCC checks the locale categories LC_CTYPE and LC_MESSAGES if it's been configured to do so. These categories can be set to any value your installation supports. A typical value is en_GB.UTF-8, which means English in the United Kingdom encoded in UTF-8 ๐Ÿ‡ฌ๐Ÿ‡ง

The LC_CTYPE variable specifies character classification ๐Ÿ”ค GCC uses it to figure out character boundaries in a string. This matters for some multibyte encodings that contain quote and escape characters, which would otherwise get read as the end of a string or as an escape ๐Ÿ˜ญ

The LC_MESSAGES variable specifies which language to use in diagnostic messages ๐Ÿ’ฌ

If LC_ALL is set, it overrides LC_CTYPE and LC_MESSAGES. Otherwise, LC_CTYPE and LC_MESSAGES default to whatever LANG is set to ๐Ÿซถ If none of these variables are set, GCC defaults to traditional C English behaviour ๐Ÿงธ

TMPDIR

If TMPDIR is set, it specifies the directory for temporary files ๐Ÿ—‚๏ธ GCC uses temporary files to hold the output of one stage of compilation that gets used as input for the next stage. For example, the output of the preprocessor is the input to the compiler proper ๐Ÿงš

GCC_COMPARE_DEBUG

Setting GCC_COMPARE_DEBUG is nearly the same as passing -fcompare-debug to the compiler driver. Check out the docs for that option for more details ๐Ÿ”Ž

GCC_EXEC_PREFIX

If GCC_EXEC_PREFIX is set, it specifies a prefix to use in the names of the subprograms the compiler runs. No slash gets added when this prefix is combined with a subprogram name, but you can add a trailing slash to your prefix if you want one ๐Ÿฆ‹

If GCC_EXEC_PREFIX isn't set, GCC tries to figure out a good prefix based on the pathname it was invoked with ๐Ÿงญ

If GCC can't find the subprogram using the specified prefix, it looks in the usual places for it ๐Ÿ”

The default value of GCC_EXEC_PREFIX is prefix/lib/gcc/, where prefix is the prefix of the installed compiler. In lots of cases, prefix is the value of prefix you gave when you ran the configure script ๐ŸŒท

Other prefixes set with -B take priority over this one ๐Ÿ‘‘

This prefix is also used to find files like crt0.o that get used for linking ๐Ÿ”—

The prefix is also used in a kinda unusual way when finding the directories to search for header files ๐Ÿ™ˆ For each standard directory whose name normally begins with /usr/local/lib/gcc (or more precisely, with the value of GCC_INCLUDE_DIR), GCC tries swapping that beginning out for the specified prefix to make an alternate directory name. So with -Bfoo/, GCC searches foo/bar just before it searches the standard directory /usr/local/lib/bar. If a standard directory starts with the configured prefix, then the value of prefix gets replaced by GCC_EXEC_PREFIX when GCC looks for header files ๐Ÿ’–

COMPILER_PATH

The value of COMPILER_PATH is a colon-separated list of directories, a lot like PATH ๐Ÿ›ฃ๏ธ GCC tries these directories when searching for subprograms, if it can't find them using GCC_EXEC_PREFIX ๐Ÿ’…

LIBRARY_PATH

The value of LIBRARY_PATH is also a colon-separated list of directories, just like PATH ๐Ÿ“š When GCC is configured as a native compiler, it tries these directories when searching for special linker files, if it can't find them using GCC_EXEC_PREFIX. Linking with GCC also uses these directories to look for ordinary libraries for the -l option. Directories specified with -L come first though ๐Ÿฅ‡

LANG

This variable passes locale info to the compiler ๐ŸŒ One thing this info is used for is figuring out which character set to use when parsing character literals, string literals and comments in C and C++. When the compiler is configured to allow multibyte characters, these values for LANG are recognised:

  • C-JIS โ€” recognises JIS characters ๐ŸŽŒ
  • C-SJIS โ€” recognises SJIS characters ๐Ÿฃ
  • C-EUCJP โ€” recognises EUCJP characters ๐Ÿ™

If LANG isn't defined, or has some other value, then the compiler uses mblen and mbtowc as defined by the default locale to recognise and translate multibyte characters ๐Ÿค“

Some additional environment variables affect the behaviour of the preprocessor ๐Ÿงผ

CPATH, C_INCLUDE_PATH, CPLUS_INCLUDE_PATH, OBJC_INCLUDE_PATH

Each variable's value is a list of directories separated by a special character, a lot like PATH, and they're used to look for header files ๐Ÿ“‚ That special character, PATH_SEPARATOR, depends on the target and gets set when GCC is built. For Microsoft Windows-based targets it's a semicolon, and for almost every other target it's a colon ๐Ÿ’ป

CPATH specifies a list of directories to search as if they were given with -I, but after any paths given with -I options on the command line. This variable is used no matter which language is being preprocessed ๐Ÿ’œ

The remaining variables only apply when preprocessing the particular language they name. Each one specifies a list of directories to search as if they were given with -isystem, but after any paths given with -isystem options on the command line ๐ŸŒท

In all of these variables, an empty element tells the compiler to search its current working directory. Empty elements can show up at the beginning or end of a path. For instance, if the value of CPATH is ":/special/include", that's the same as -I. -I/special/include ๐Ÿซง

DEPENDENCIES_OUTPUT

If this variable is set, its value specifies how to output dependencies for Make, based on the non-system header files the compiler processes. System header files get ignored in the dependency output ๐Ÿ™…โ€โ™€๏ธ

The value of DEPENDENCIES_OUTPUT can be just a file name. In that case the Make rules get written to that file, and the target name gets guessed from the source file name. Or the value can take the form file target, where the rules are written to file using target as the target name ๐ŸŽฏ

In other words, this environment variable is the same as combining the options -MM and -MF, with an optional -MT switch too ๐Ÿง

SUNPRO_DEPENDENCIES

This variable is the same as DEPENDENCIES_OUTPUT (see above), except system header files are not ignored, so it implies -M rather than -MM ๐ŸŒˆ However, the dependence on the main input file is omitted ๐Ÿ™ƒ

SOURCE_DATE_EPOCH

If this variable is set, its value specifies a UNIX timestamp to use instead of the current date and time in the __DATE__ and __TIME__ macros. That way the embedded timestamps are reproducible โฐ

The value of SOURCE_DATE_EPOCH must be a UNIX timestamp, which is the number of seconds (excluding leap seconds) since 01 Jan 1970 00:00:00, written in ASCII. It's identical to the output of date +%s on GNU/Linux and other systems that support the %s extension in the date command ๐Ÿง

The value should be a known timestamp, like the last modification time of the source or package, and the build process should set it ๐Ÿ› ๏ธ

๐Ÿ› BUGS ๐Ÿ›

For instructions on reporting bugs, see <file:///usr/share/doc/gcc-9/README.Bugs> ๐Ÿž๐Ÿ’–

โœจ FOOTNOTES โœจ

okay bestie, there's one footnote and it's a big deal ๐Ÿซถ

  1. ngl, this one is a whole vibe ๐Ÿ’… On some systems, gcc -shared needs to build supplementary stub code for constructors to work. On multi-libbed systems, gcc -shared has to pick the correct support libraries to link against. If you don't supply the correct flags, you can get subtle defects ๐Ÿ˜ญ But supplying them when they aren't needed is totally innocuous, so when in doubt, add them ๐Ÿฆ‹

๐Ÿฆ‹ SEE ALSO ๐Ÿฆ‹

the vibe check of related reads, all the way from the GNU side of things ๐ŸŒˆ

๐Ÿ‘‘ AUTHOR ๐Ÿ‘‘

the people who built GCC are literally iconic ๐Ÿ”ฅ For the full list of contributors, check the Info entry for gcc, or head to <http://gcc.gnu.org/onlinedocs/gcc/Contributors.html> ๐ŸŒธ

okay legal stuff but make it cute ๐ŸŽ€ Copyright (c) 1988-2019 Free Software Foundation, Inc.

This document is free for you to copy, distribute, and/or modify under the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation ๐Ÿ’œ The Invariant Sections are "GNU General Public License" and "Funding Free Software". The Front-Cover texts are the one in (a) below, and the Back-Cover Texts are the one in (b) below. A copy of the license is included in the gfdl(7) man page ๐Ÿงš

(a) The FSF's Front-Cover Text is:

A GNU Manual

(b) The FSF's Back-Cover Text is:

You have freedom to copy and modify this GNU Manual, like GNU
software.  Copies published by the Free Software Foundation raise
funds for GNU development.

and that's a wrap on the GCC(1) page, bestie ๐ŸŽ€ It's the GCC 9 era, last updated 2022-05-27, and honestly the whole thing is giving main character energy ๐Ÿ’…โœจ mwah ๐Ÿซถ๐ŸŒˆ

๐Ÿ“ฆ where this page comes from