GCC(1)

๐Ÿ“ฆ
version 11.5.0 ยท 5 versions
, in ubuntu questing, ubuntu resolute, ubuntu stonking

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

Okay bestie, this is the GCC(1) page from the GNU manual, and it is giving everything for anyone who compiles C and C++ ๐Ÿ”ฅ

โœจ 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 waiting for you further down. And g++ accepts mostly the same options as gcc, so you're not learning a whole new vibe ๐Ÿฆ‹

โœจ DESCRIPTION โœจ

When you invoke GCC, it normally does preprocessing, compilation, assembly, and linking, all in one go ๐Ÿงš The "overall options" let you stop this process at an intermediate stage. For example, -c says not to run the linker, so the output is the object files the assembler spits out ๐Ÿ’œ

Other options get passed on to one or more stages of processing. Some control the preprocessor, some control the compiler itself, and some control the assembler and linker. Most of those last ones aren't documented here, because you rarely need to touch them, so no stress ๐Ÿซถ

Most of the command-line options you can use with GCC are useful for C programs. When an option is only useful with another language (usually C++), the explanation says so explicitly. If an option's description doesn't mention a source language, then you can use it with all supported languages โœจ

The usual way to run GCC is to run the executable called gcc, or machine-gcc when cross-compiling, or machine-gcc-version if you want a 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 cannot be grouped together. -dv is very different from -d -v, so don't try to be clever ๐Ÿ’€

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

Lots of options have long names that start with -f or with -W, like -fmove-loop-invariants or -Wformat. Most of these have both positive and negative forms, 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, typically separated from the option name either by a space or by the equals sign (=). Unless documented otherwise, an argument can be either numeric or a string. Numeric arguments must typically be small unsigned decimal or hexadecimal integers. Hexadecimal arguments must begin with the 0x prefix ๐Ÿ“

Arguments to options that specify a size threshold of some sort can be arbitrarily large decimal or hexadecimal integers, followed by a byte size suffix that designates a multiple of bytes. So you've got kB and KiB for kilobyte and kibibyte, MB and MiB for megabyte and mebibyte, GB and GiB for gigabyte and gigibyte, and so on. These arguments are called byte-size in the rest of the text. For the full listing and explanation 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. The explanations live in the following sections, so keep scrolling ๐Ÿ“–

Overall Options

-c  -S  -E  -o file -dumpbase dumpbase  -dumpbase-ext auxdropsuf
-dumpdir dumppfx  -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-cache-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
-fmodule-header[=kind] -fmodule-only -fmodules-ts
-fmodule-implicit-inline -fno-module-lazy
-fmodule-mapper=specification -fmodule-version-ignore
-fms-extensions -fnew-inheriting-ctors -fnew-ttp-matching
-fno-nonansi-builtins  -fnothrow-opt  -fno-operator-names
-fno-optional-diags  -fpermissive -fno-pretty-templates -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 -flang-info-include-translate[=header]
-flang-info-include-translate-not -flang-info-module-cmi[=module]
-stdlib=libstdc++,libc++ -Wabi-tag  -Wcatch-value  -Wcatch-value=n
-Wno-class-conversion  -Wclass-memaccess -Wcomma-subscript
-Wconditionally-supported -Wno-conversion-null
-Wctad-maybe-unsupported -Wctor-dtor-privacy  -Wno-delete-incomplete
-Wdelete-non-virtual-dtor  -Wdeprecated-copy -Wdeprecated-copy-dtor
-Wno-deprecated-enum-enum-conversion
-Wno-deprecated-enum-float-conversion -Weffc++  -Wno-exceptions
-Wextra-semi  -Wno-inaccessible-base -Wno-inherited-variadic-ctor
-Wno-init-list-lifetime -Winvalid-imported-macros
-Wno-invalid-offsetof  -Wno-literal-suffix
-Wno-mismatched-new-delete -Wmismatched-tags -Wmultiple-inheritance
-Wnamespaces  -Wnarrowing -Wnoexcept  -Wnoexcept-type
-Wnon-virtual-dtor -Wpessimizing-move  -Wno-placement-new
-Wplacement-new=n -Wrange-loop-construct -Wredundant-move
-Wredundant-tags -Wreorder  -Wregister -Wstrict-null-sentinel
-Wno-subobject-linkage  -Wtemplates -Wno-non-template-friend
-Wold-style-cast -Woverloaded-virtual  -Wno-pmf-conversions
-Wsign-promo -Wsized-deallocation  -Wsuggest-final-methods
-Wsuggest-final-types  -Wsuggest-override -Wno-terminate
-Wuseless-cast  -Wno-vexing-parse -Wvirtual-inheritance
-Wno-virtual-move-assign  -Wvolatile
-Wzero-as-null-pointer-constant

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-property-assign-default -Wno-protocol -Wobjc-root-class
-Wselector -Wstrict-selector-match -Wundeclared-selector

Diagnostic Message Formatting Options

-fmessage-length=n -fdiagnostics-plain-output
-fdiagnostics-show-location=[once|every-line]
-fdiagnostics-color=[auto|never|always]
-fdiagnostics-urls=[auto|never|always]
-fdiagnostics-format=[text|json] -fno-diagnostics-show-option
-fno-diagnostics-show-caret -fno-diagnostics-show-labels
-fno-diagnostics-show-line-numbers -fno-diagnostics-show-cwe
-fdiagnostics-minimum-margin-width=width
-fdiagnostics-parseable-fixits  -fdiagnostics-generate-patch
-fdiagnostics-show-template-tree  -fno-elide-type
-fdiagnostics-path-format=[none|separate-events|inline-events]
-fdiagnostics-show-path-depths -fno-show-column
-fdiagnostics-column-unit=[display|byte]
-fdiagnostics-column-origin=origin

โœจ Warning Options โœจ

okay bestie, this list is absolutely unhinged in length ๐Ÿ’€ but I promise I'm lining up every single flag so nothing gets dropped ๐Ÿซถ

-fsyntax-only -fmax-errors=n -Wpedantic -pedantic-errors -w
-Wextra -Wall -Wabi=n -Waddress -Wno-address-of-packed-member
-Waggregate-return -Walloc-size-larger-than=byte-size -Walloc-zero
-Walloca -Walloca-larger-than=byte-size
-Wno-aggressive-loop-optimizations -Warith-conversion -Warray-bounds
-Warray-bounds=n -Wno-attributes -Wattribute-alias=n
-Wno-attribute-alias -Wno-attribute-warning -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 -Wc++20-compat -Wcast-align -Wcast-align=strict
-Wcast-function-type -Wcast-qual -Wchar-subscripts -Wclobbered
-Wcomment -Wconversion -Wno-coverage-mismatch -Wno-cpp
-Wdangling-else -Wdate-time -Wno-deprecated
-Wno-deprecated-declarations -Wno-designated-init
-Wdisabled-optimization -Wno-discarded-array-qualifiers
-Wno-discarded-qualifiers -Wno-div-by-zero -Wdouble-promotion
-Wduplicated-branches -Wduplicated-cond -Wempty-body
-Wno-endif-labels -Wenum-compare -Wenum-conversion -Werror
-Werror=* -Wexpansion-to-defined -Wfatal-errors -Wfloat-conversion
-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 -Wno-if-not-aligned
-Wno-ignored-attributes -Wignored-qualifiers
-Wno-incompatible-pointer-types -Wimplicit -Wimplicit-fallthrough
-Wimplicit-fallthrough=n -Wno-implicit-function-declaration
-Wno-implicit-int -Winit-self -Winline -Wno-int-conversion
-Wint-in-bool-context -Wno-int-to-pointer-cast
-Wno-invalid-memory-model -Winvalid-pch -Wjump-misses-init
-Wlarger-than=byte-size -Wlogical-not-parentheses -Wlogical-op
-Wlong-long -Wno-lto-type-mismatch -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 -Wno-missing-profile -Wno-multichar
-Wmultistatement-macros -Wnonnull -Wnonnull-compare
-Wnormalized=[none|id|nfc|nfkc] -Wnull-dereference -Wno-odr
-Wopenmp-simd -Wno-overflow -Woverlength-strings
-Wno-override-init-side-effects -Wpacked
-Wno-packed-bitfield-compat -Wpacked-not-aligned -Wpadded
-Wparentheses -Wno-pedantic-ms-format -Wpointer-arith
-Wno-pointer-compare -Wno-pointer-to-int-cast -Wno-pragmas
-Wno-prio-ctor-dtor -Wredundant-decls -Wrestrict
-Wno-return-local-addr -Wreturn-type -Wno-scalar-storage-order
-Wsequence-point -Wshadow -Wshadow=global -Wshadow=local
-Wshadow=compatible-local -Wno-shadow-ivar -Wno-shift-count-negative
-Wno-shift-count-overflow -Wshift-negative-value
-Wno-shift-overflow -Wshift-overflow=n -Wsign-compare
-Wsign-conversion -Wno-sizeof-array-argument -Wsizeof-array-div
-Wsizeof-pointer-div -Wsizeof-pointer-memaccess -Wstack-protector
-Wstack-usage=byte-size -Wstrict-aliasing -Wstrict-aliasing=n
-Wstrict-overflow -Wstrict-overflow=n -Wstring-compare
-Wno-stringop-overflow -Wno-stringop-overread
-Wno-stringop-truncation
-Wsuggest-attribute=[pure|const|noreturn|format|malloc] -Wswitch
-Wno-switch-bool -Wswitch-default -Wswitch-enum
-Wno-switch-outside-range -Wno-switch-unreachable -Wsync-nand
-Wsystem-headers -Wtautological-compare -Wtrampolines -Wtrigraphs
-Wtsan -Wtype-limits -Wundef -Wuninitialized -Wunknown-pragmas
-Wunsuffixed-float-constants -Wunused -Wunused-but-set-parameter
-Wunused-but-set-variable -Wunused-const-variable
-Wunused-const-variable=n -Wunused-function -Wunused-label
-Wunused-local-typedefs -Wunused-macros -Wunused-parameter
-Wno-unused-result -Wunused-value -Wunused-variable -Wno-varargs
-Wvariadic-macros -Wvector-operation-performance -Wvla
-Wvla-larger-than=byte-size -Wno-vla-larger-than
-Wvolatile-register-var -Wwrite-strings -Wzero-length-bounds

โœจ Static Analyzer Options โœจ

the analyzer crew ๐Ÿ” is up next, and these flags are giving main character energy ๐Ÿ‘‘

-fanalyzer -fanalyzer-call-summaries -fanalyzer-checker=name
-fno-analyzer-feasibility -fanalyzer-fine-grained
-fanalyzer-state-merge -fanalyzer-state-purge
-fanalyzer-transitivity -fanalyzer-verbose-edges
-fanalyzer-verbose-state-changes -fanalyzer-verbosity=level
-fdump-analyzer -fdump-analyzer-stderr -fdump-analyzer-callgraph
-fdump-analyzer-exploded-graph -fdump-analyzer-exploded-nodes
-fdump-analyzer-exploded-nodes-2 -fdump-analyzer-exploded-nodes-3
-fdump-analyzer-feasibility -fdump-analyzer-json
-fdump-analyzer-state-purge -fdump-analyzer-supergraph
-Wno-analyzer-double-fclose -Wno-analyzer-double-free
-Wno-analyzer-exposure-through-output-file -Wno-analyzer-file-leak
-Wno-analyzer-free-of-non-heap -Wno-analyzer-malloc-leak
-Wno-analyzer-mismatching-deallocation -Wno-analyzer-null-argument
-Wno-analyzer-null-dereference -Wno-analyzer-possible-null-argument
-Wno-analyzer-possible-null-dereference
-Wno-analyzer-shift-count-negative
-Wno-analyzer-shift-count-overflow -Wno-analyzer-stale-setjmp-buffer
-Wno-analyzer-tainted-array-index -Wanalyzer-too-complex
-Wno-analyzer-unsafe-call-within-signal-handler
-Wno-analyzer-use-after-free
-Wno-analyzer-use-of-pointer-in-stale-stack-frame
-Wno-analyzer-use-of-uninitialized-value
-Wno-analyzer-write-to-const -Wno-analyzer-write-to-string-literal

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

these ones are only for C and Objective-C ๐ŸŒธ so if you're not writing those, you can just vibe past them ๐Ÿซถ

-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 โœจ

ok and last but not least, the debugging squad ๐Ÿ› these are all the -g and -f flags that handle debug info, and they are a whole mood ๐Ÿฆ‹

-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 -gdwarf32 -gdwarf64 -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]
-fno-eliminate-unused-debug-symbols -femit-class-debug-always
-fno-merge-debug-strings -fno-dwarf2-cfi-asm -fvar-tracking
-fvar-tracking-assignments

โœจ Optimization Options โœจ

okay bestie, this is the BIG tuning list ๐Ÿ’… every single flag, zero cap

  • -faggressive-loop-optimizations โ€” loops get a glow-up ๐Ÿ”ฅ
  • -falign-functions[=n[:m:[n2[:m2]]]] โ€” function alignment, very precise ๐Ÿ“
  • -falign-jumps[=n[:m:[n2[:m2]]]] โ€” jump target alignment ๐Ÿฆ‹
  • -falign-labels[=n[:m:[n2[:m2]]]] โ€” label alignment ๐Ÿท๏ธ
  • -falign-loops[=n[:m:[n2[:m2]]]] โ€” loop alignment ๐Ÿ”
  • -fno-allocation-dce โ€” the no-thanks version of allocation cleanup ๐Ÿ™…โ€โ™€๏ธ
  • -fallow-store-data-races โ€” allowing store data races, โš ๏ธ spicy
  • -fassociative-math โ€” math reshuffling vibes ๐Ÿงฎ
  • -fauto-profile โ€” auto profile, hands-off ๐Ÿช„
  • -fauto-profile[=path] โ€” same, but you pick the path ๐Ÿ“‚
  • -fauto-inc-dec โ€” auto increment and decrement ๐ŸŒธ
  • -fbranch-probabilities โ€” branch odds, bestie ๐ŸŽฒ
  • -fcaller-saves โ€” caller saves, very responsible ๐Ÿ’œ
  • -fcombine-stack-adjustments โ€” stack adjustments, combined ๐Ÿงฉ
  • -fconserve-stack โ€” stack-saving mode ๐ŸŒฟ
  • -fcompare-elim โ€” comparison elimination โœ‚๏ธ
  • -fcprop-registers โ€” register propagation ๐ŸŽ€
  • -fcrossjumping โ€” crossjumping, iconic ๐Ÿฆ˜
  • -fcse-follow-jumps โ€” CSE that follows the jumps ๐Ÿ‘ฃ
  • -fcse-skip-blocks โ€” CSE that skips blocks โญ๏ธ
  • -fcx-fortran-rules โ€” Fortran complex rules ๐Ÿ“œ
  • -fcx-limited-range โ€” limited range for complex math ๐ŸŒˆ
  • -fdata-sections โ€” data gets its own sections ๐Ÿ—‚๏ธ
  • -fdce โ€” dead code elimination, bye bye ๐Ÿ’€
  • -fdelayed-branch โ€” delayed branches ๐Ÿ•ฐ๏ธ
  • -fdelete-null-pointer-checks โ€” null pointer checks get deleted ๐Ÿ™ˆ
  • -fdevirtualize โ€” devirtualization โœจ
  • -fdevirtualize-speculatively โ€” speculative devirtualization ๐Ÿ”ฎ
  • -fdevirtualize-at-ltrans โ€” devirtualize at LTRANS time ๐Ÿ•
  • -fdse โ€” dead store elimination ๐Ÿงน
  • -fearly-inlining โ€” inlining, early edition ๐Ÿ“
  • -fipa-sra โ€” interprocedural SRA ๐Ÿง 
  • -fexpensive-optimizations โ€” the pricey-but-worth-it ones ๐Ÿ’Ž
  • -ffat-lto-objects โ€” fat LTO objects ๐Ÿ˜
  • -ffast-math โ€” fast math, โš ๏ธ not for the faint-hearted
  • -ffinite-math-only โ€” finite math only, no infinities ๐ŸงŠ
  • -ffloat-store โ€” float storage rules ๐Ÿ’พ
  • -fexcess-precision=style โ€” excess precision, your call ๐ŸŽš๏ธ
  • -ffinite-loops โ€” loops that are finite ๐Ÿ”‚
  • -fforward-propagate โ€” forward propagation โžก๏ธ
  • -ffp-contract=style โ€” floating-point contraction, pick a style ๐Ÿชก
  • -ffunction-sections โ€” functions get their own sections ๐Ÿงบ
  • -fgcse โ€” global CSE ๐ŸŒ
  • -fgcse-after-reload โ€” global CSE after reload ๐Ÿ”„
  • -fgcse-las โ€” GCSE load after store ๐Ÿ—ƒ๏ธ
  • -fgcse-lm โ€” GCSE load motion ๐Ÿšš
  • -fgraphite-identity โ€” Graphite identity transform ๐Ÿชช
  • -fgcse-sm โ€” GCSE store motion ๐Ÿ“ฆ
  • -fhoist-adjacent-loads โ€” hoisting adjacent loads ๐Ÿ—๏ธ
  • -fif-conversion โ€” if-conversion ๐Ÿ”€
  • -fif-conversion2 โ€” if-conversion, round two ๐Ÿ”€โœจ
  • -findirect-inlining โ€” inlining the indirect calls ๐ŸŽฏ
  • -finline-functions โ€” inline all the functions ๐Ÿ’…
  • -finline-functions-called-once โ€” inline the once-only functions 1๏ธโƒฃ
  • -finline-limit=n โ€” set the inline limit to n ๐Ÿšง
  • -finline-small-functions โ€” inline the small ones ๐Ÿฃ
  • -fipa-modref โ€” mod/ref analysis across functions ๐Ÿชž
  • -fipa-cp โ€” interprocedural constant propagation ๐Ÿ’ฌ
  • -fipa-cp-clone โ€” constant propagation with clones ๐Ÿ‘ฏ
  • -fipa-bit-cp โ€” bit-level constant propagation ๐Ÿ”ข
  • -fipa-vrp โ€” interprocedural value range propagation ๐Ÿ“ˆ
  • -fipa-pta โ€” interprocedural pointer analysis ๐Ÿงญ
  • -fipa-profile โ€” interprocedural profile use ๐Ÿ“Š
  • -fipa-pure-const โ€” pure and const function detection ๐Ÿง˜
  • -fipa-reference โ€” reference analysis ๐Ÿ”—
  • -fipa-reference-addressable โ€” reference analysis for addressable stuff ๐Ÿ“ฌ
  • -fipa-stack-alignment โ€” stack alignment, interprocedural ๐Ÿ“
  • -fipa-icf โ€” identical code folding ๐Ÿ‘ญ
  • -fira-algorithm=algorithm โ€” pick the IRA algorithm ๐Ÿง‘โ€๐Ÿ”ฌ
  • -flive-patching=level โ€” live patching level ๐Ÿฉน
  • -fira-region=region โ€” IRA region choice ๐Ÿ—บ๏ธ
  • -fira-hoist-pressure โ€” hoist pressure, IRA style โ›ฐ๏ธ
  • -fira-loop-pressure โ€” loop pressure, IRA style ๐ŸŒ€
  • -fno-ira-share-save-slots โ€” don't share save slots ๐Ÿ™…
  • -fno-ira-share-spill-slots โ€” don't share spill slots ๐Ÿ™…โ€โ™€๏ธ
  • -fisolate-erroneous-paths-dereference โ€” isolate erroneous dereference paths ๐Ÿšง
  • -fisolate-erroneous-paths-attribute โ€” isolate erroneous paths by attribute ๐Ÿท๏ธ
  • -fivopts โ€” induction variable optimizations ๐Ÿ”โœจ
  • -fkeep-inline-functions โ€” keep the inline functions around ๐Ÿงธ
  • -fkeep-static-functions โ€” keep the static functions ๐Ÿงธ
  • -fkeep-static-consts โ€” keep the static consts ๐Ÿ’Ž
  • -flimit-function-alignment โ€” limit function alignment ๐Ÿ“
  • -flive-range-shrinkage โ€” live range shrinkage ๐Ÿค
  • -floop-block โ€” loop blocking ๐Ÿงฑ
  • -floop-interchange โ€” loop interchange ๐Ÿ”
  • -floop-strip-mine โ€” loop strip mining ๐Ÿชš
  • -floop-unroll-and-jam โ€” unroll and jam loops ๐Ÿฏ
  • -floop-nest-optimize โ€” loop nest optimization ๐Ÿช†
  • -floop-parallelize-all โ€” parallelize all the loops ๐Ÿงต
  • -flra-remat โ€” LRA rematerialization ๐Ÿ”
  • -flto โ€” link-time optimization ๐Ÿš€
  • -flto-compression-level โ€” LTO compression level ๐Ÿ—œ๏ธ
  • -flto-partition=alg โ€” LTO partitioning algorithm ๐Ÿฐ
  • -fmerge-all-constants โ€” merge all the constants ๐Ÿค
  • -fmerge-constants โ€” merge constants ๐Ÿค
  • -fmodulo-sched โ€” modulo scheduling ๐ŸŽถ
  • -fmodulo-sched-allow-regmoves โ€” modulo scheduling with register moves ๐Ÿšš
  • -fmove-loop-invariants โ€” move loop invariants out ๐Ÿƒ
  • -fno-branch-count-reg โ€” no branch count register ๐Ÿ™…
  • -fno-defer-pop โ€” don't defer pops ๐Ÿ™…โ€โ™€๏ธ
  • -fno-fp-int-builtin-inexact โ€” no inexact floating-point to integer builtins ๐Ÿ™…
  • -fno-function-cse โ€” no CSE on function addresses ๐Ÿ™…
  • -fno-guess-branch-probability โ€” don't guess branch probabilities ๐Ÿ™…โ€โ™€๏ธ
  • -fno-inline โ€” no inlining at all ๐Ÿ™…
  • -fno-math-errno โ€” no errno for math ๐Ÿ™…โ€โ™€๏ธ
  • -fno-peephole โ€” no peephole optimizer ๐Ÿ™…
  • -fno-peephole2 โ€” no second peephole optimizer ๐Ÿ™…โ€โ™€๏ธ
  • -fno-printf-return-value โ€” no printf return value tracking ๐Ÿ™…
  • -fno-sched-interblock โ€” no interblock scheduling ๐Ÿ™…โ€โ™€๏ธ
  • -fno-sched-spec โ€” no speculative scheduling ๐Ÿ™…
  • -fno-signed-zeros โ€” no signed zeros ๐Ÿ™…โ€โ™€๏ธ
  • -fno-toplevel-reorder โ€” no top-level reordering ๐Ÿ™…
  • -fno-trapping-math โ€” no trapping math ๐Ÿ™…โ€โ™€๏ธ
  • -fno-zero-initialized-in-bss โ€” no zero-initialized data in BSS ๐Ÿ™…
  • -fomit-frame-pointer โ€” omit the frame pointer ๐Ÿซฅ
  • -foptimize-sibling-calls โ€” optimize sibling calls ๐Ÿ‘ฏโ€โ™€๏ธ
  • -fpartial-inlining โ€” partial inlining ๐Ÿงฉ
  • -fpeel-loops โ€” peel loops ๐ŸŠ
  • -fpredictive-commoning โ€” predictive commoning ๐Ÿ”ฎ
  • -fprefetch-loop-arrays โ€” prefetch loop arrays ๐Ÿƒโ€โ™€๏ธ
  • -fprofile-correction โ€” profile correction ๐Ÿฉบ
  • -fprofile-use โ€” use profile data ๐Ÿ“ˆ
  • -fprofile-use=path โ€” use profile data from a path ๐Ÿ“‚
  • -fprofile-partial-training โ€” partial training profiles ๐Ÿ‹๏ธ
  • -fprofile-values โ€” profile values ๐Ÿ”ข
  • -fprofile-reorder-functions โ€” reorder functions by profile ๐Ÿช„
  • -freciprocal-math โ€” reciprocal math ๐Ÿ”
  • -free โ€” FREE, the SSA-based redundancy elimination ๐Ÿชถ
  • -frename-registers โ€” rename registers ๐Ÿท๏ธ
  • -freorder-blocks โ€” reorder blocks ๐Ÿงฑ
  • -freorder-blocks-algorithm=algorithm โ€” pick the block reordering algorithm ๐Ÿงฎ
  • -freorder-blocks-and-partition โ€” reorder blocks and partition ๐Ÿ•
  • -freorder-functions โ€” reorder functions ๐Ÿ›๏ธ
  • -frerun-cse-after-loop โ€” rerun CSE after loops ๐Ÿ”„
  • -freschedule-modulo-scheduled-loops โ€” reschedule modulo-scheduled loops ๐Ÿ—“๏ธ
  • -frounding-math โ€” rounding math ๐ŸŽฏ
  • -fsave-optimization-record โ€” save the optimization record ๐Ÿ“
  • -fsched2-use-superblocks โ€” second scheduler with superblocks ๐Ÿฆธ
  • -fsched-pressure โ€” scheduling pressure ๐Ÿซ 
  • -fsched-spec-load โ€” speculative loads in scheduling ๐Ÿ”
  • -fsched-spec-load-dangerous โ€” dangerous speculative loads โš ๏ธ๐Ÿ’€
  • -fsched-stalled-insns-dep[=n] โ€” stalled insn dependencies ๐ŸงŠ
  • -fsched-stalled-insns[=n] โ€” stalled insns ๐ŸงŠ
  • -fsched-group-heuristic โ€” group heuristic ๐Ÿ‘ฏ
  • -fsched-critical-path-heuristic โ€” critical path heuristic ๐Ÿ›ค๏ธ
  • -fsched-spec-insn-heuristic โ€” speculative insn heuristic ๐Ÿ”
  • -fsched-rank-heuristic โ€” rank heuristic ๐Ÿฅ‡
  • -fsched-last-insn-heuristic โ€” last insn heuristic ๐Ÿ”š
  • -fsched-dep-count-heuristic โ€” dependency count heuristic ๐Ÿ”ข
  • -fschedule-fusion โ€” schedule fusion ๐Ÿซถ
  • -fschedule-insns โ€” schedule instructions ๐Ÿ—“๏ธ
  • -fschedule-insns2 โ€” schedule instructions, round two ๐Ÿ—“๏ธโœจ
  • -fsection-anchors โ€” section anchors โš“
  • -fselective-scheduling โ€” selective scheduling ๐ŸŽฏ
  • -fselective-scheduling2 โ€” selective scheduling, round two ๐ŸŽฏโœจ
  • -fsel-sched-pipelining โ€” selective scheduler pipelining ๐Ÿšฐ
  • -fsel-sched-pipelining-outer-loops โ€” selective pipelining for outer loops ๐Ÿช†
  • -fsemantic-interposition โ€” semantic interposition ๐Ÿชž
  • -fshrink-wrap โ€” shrink-wrapping ๐ŸŽ
  • -fshrink-wrap-separate โ€” separate shrink-wrapping ๐ŸŽโœจ
  • -fsignaling-nans โ€” signaling NaNs ๐Ÿ“ก
  • -fsingle-precision-constant โ€” single precision constants ๐Ÿ”ฌ
  • -fsplit-ivs-in-unroller โ€” split induction variables in the unroller โœ‚๏ธ
  • -fsplit-loops โ€” split loops โœ‚๏ธ
  • -fsplit-paths โ€” split paths ๐Ÿ›ฃ๏ธ
  • -fsplit-wide-types โ€” split wide types ๐Ÿงฉ
  • -fsplit-wide-types-early โ€” split wide types early ๐Ÿงฉโฐ
  • -fssa-backprop โ€” SSA backward propagation โฌ…๏ธ
  • -fssa-phiopt โ€” SSA PHI optimization ๐Ÿงฉ
  • -fstdarg-opt โ€” stdarg optimization ๐ŸŽญ
  • -fstore-merging โ€” store merging ๐Ÿค
  • -fstrict-aliasing โ€” strict aliasing ๐Ÿงฑ
  • -fthread-jumps โ€” thread jumps ๐Ÿงต
  • -ftracer โ€” tracer, leaves a trail ๐Ÿพ
  • -ftree-bit-ccp โ€” tree bit constant propagation ๐Ÿ”ข
  • -ftree-builtin-call-dce โ€” dead code elimination for builtin calls ๐Ÿ’€
  • -ftree-ccp โ€” tree constant propagation ๐Ÿ’ฌ
  • -ftree-ch โ€” tree loop header copying ๐Ÿ“‹
  • -ftree-coalesce-vars โ€” coalesce variables ๐Ÿค
  • -ftree-copy-prop โ€” tree copy propagation ๐Ÿ“„
  • -ftree-dce โ€” tree dead code elimination ๐Ÿ’€
  • -ftree-dominator-opts โ€” dominator optimizations ๐Ÿ‘‘
  • -ftree-dse โ€” tree dead store elimination ๐Ÿงน
  • -ftree-forwprop โ€” tree forward propagation โžก๏ธ
  • -ftree-fre โ€” tree full redundancy elimination โ™ป๏ธ
  • -fcode-hoisting โ€” code hoisting ๐Ÿ—๏ธ
  • -ftree-loop-if-convert โ€” loop if-conversion ๐Ÿ”€
  • -ftree-loop-im โ€” loop invariant motion ๐Ÿƒ
  • -ftree-phiprop โ€” tree PHI propagation ๐Ÿงฉ
  • -ftree-loop-distribution โ€” loop distribution ๐Ÿฑ
  • -ftree-loop-distribute-patterns โ€” distribute loop patterns ๐Ÿฑโœจ
  • -ftree-loop-ivcanon โ€” canonicalize loop induction variables ๐Ÿ”
  • -ftree-loop-linear โ€” linear loop transformations ๐Ÿ“
  • -ftree-loop-optimize โ€” tree loop optimizations ๐Ÿ”
  • -ftree-loop-vectorize โ€” loop vectorization ๐Ÿš„
  • -ftree-parallelize-loops=n โ€” parallelize loops across n threads ๐Ÿงต
  • -ftree-pre โ€” tree partial redundancy elimination ๐Ÿ”
  • -ftree-partial-pre โ€” tree partial PRE ๐Ÿ”โœจ
  • -ftree-pta โ€” tree pointer analysis ๐Ÿงญ
  • -ftree-reassoc โ€” tree reassociation ๐Ÿชข
  • -ftree-scev-cprop โ€” SCEV constant propagation ๐Ÿ”ข
  • -ftree-sink โ€” tree sinking โฌ‡๏ธ
  • -ftree-slsr โ€” straight-line strength reduction ๐Ÿ’ช
  • -ftree-sra โ€” tree scalar replacement of aggregates ๐Ÿงฉ
  • -ftree-switch-conversion โ€” switch conversion ๐Ÿ”€
  • -ftree-tail-merge โ€” tail merging ๐Ÿชก
  • -ftree-ter โ€” temporary expression replacement ๐Ÿ”
  • -ftree-vectorize โ€” tree vectorization ๐Ÿš„
  • -ftree-vrp โ€” tree value range propagation ๐Ÿ“ˆ
  • -funconstrained-commons โ€” unconstrained commons ๐ŸŒ
  • -funit-at-a-time โ€” unit at a time ๐Ÿ•ฐ๏ธ
  • -funroll-all-loops โ€” unroll all the loops ๐Ÿ”๐Ÿ”
  • -funroll-loops โ€” unroll loops ๐Ÿ”
  • -funsafe-math-optimizations โ€” unsafe math optimizations, โš ๏ธ spicy
  • -funswitch-loops โ€” loop unswitching ๐Ÿ”€
  • -fipa-ra โ€” interprocedural register allocation ๐Ÿง 
  • -fvariable-expansion-in-unroller โ€” variable expansion in the unroller ๐ŸŒฑ
  • -fvect-cost-model โ€” vectorizer cost model ๐Ÿ’ฐ
  • -fvpt โ€” value profile transformations ๐Ÿ“Š
  • -fweb โ€” webs for registers ๐Ÿ•ธ๏ธ
  • -fwhole-program โ€” whole program mode ๐ŸŒ
  • -fwpa โ€” whole program analysis ๐Ÿ”ญ
  • -fuse-linker-plugin โ€” use the linker plugin ๐Ÿ”Œ
  • -fzero-call-used-regs โ€” zero call-used registers ๐Ÿงน
  • --param name=value โ€” set a tuning parameter ๐ŸŽ›๏ธ
  • -O โ€” the basic optimization knob โš™๏ธ
  • -O0 โ€” no optimization, zero glow-up ๐Ÿ˜ด
  • -O1 โ€” a little optimization ๐ŸŒฑ
  • -O2 โ€” more optimization ๐ŸŒท
  • -O3 โ€” the maximum-effort level ๐Ÿ”ฅ
  • -Os โ€” optimize for size ๐Ÿค
  • -Ofast โ€” fast, โš ๏ธ bends the rules
  • -Og โ€” optimize for debugging ๐Ÿž

โœจ Program Instrumentation Options โœจ

this is the section where GCC gets nosy and starts taking notes ๐Ÿ“๐Ÿ‘€

  • -p โ€” profiling ๐Ÿ“ธ
  • -pg โ€” profiling with gprof ๐Ÿ“Š
  • -fprofile-arcs โ€” arc profiling ๐Ÿน
  • --coverage โ€” coverage ๐Ÿง
  • -ftest-coverage โ€” test coverage ๐Ÿงช
  • -fprofile-abs-path โ€” absolute profile paths ๐Ÿ—บ๏ธ
  • -fprofile-dir=path โ€” put profile data in path ๐Ÿ“‚
  • -fprofile-generate โ€” generate profile data ๐Ÿช„
  • -fprofile-generate=path โ€” generate profile data into path ๐Ÿ“‚
  • -fprofile-info-section โ€” profile info section ๐Ÿ—ƒ๏ธ
  • -fprofile-info-section=name โ€” profile info section with a name ๐Ÿท๏ธ
  • -fprofile-note=path โ€” profile notes at path ๐Ÿ“’
  • -fprofile-prefix-path=path โ€” profile prefix path ๐Ÿ›ค๏ธ
  • -fprofile-update=method โ€” profile update method ๐Ÿ”„
  • -fprofile-filter-files=regex โ€” include only files matching regex ๐Ÿ”
  • -fprofile-exclude-files=regex โ€” exclude files matching regex ๐Ÿ™…
  • -fprofile-reproducible=[multithreaded|parallel-runs|serial] โ€” reproducible profiles, pick a mode ๐Ÿ”
  • -fsanitize=style โ€” sanitizer, pick a style ๐Ÿงผ
  • -fsanitize-recover โ€” sanitizer recovery ๐Ÿฉน
  • -fsanitize-recover=style โ€” sanitizer recovery, pick a style ๐Ÿฉนโœจ
  • -fasan-shadow-offset=number โ€” ASan shadow offset ๐ŸŒ‘
  • -fsanitize-sections=s1,s2,... โ€” sanitize these sections ๐Ÿงบ
  • -fsanitize-undefined-trap-on-error โ€” trap on undefined behaviour errors ๐Ÿชค
  • -fbounds-check โ€” bounds checking ๐Ÿšง
  • -fcf-protection=[full|branch|return|none|check] โ€” control-flow protection, pick a level ๐Ÿ›ก๏ธ
  • -fstack-protector โ€” stack protector ๐Ÿ›ก๏ธ
  • -fstack-protector-all โ€” stack protector for everything ๐Ÿ›ก๏ธโœจ
  • -fstack-protector-strong โ€” stack protector, strong edition ๐Ÿ’ช
  • -fstack-protector-explicit โ€” stack protector, explicit only ๐ŸŽฏ
  • -fstack-check โ€” stack checking ๐Ÿ”
  • -fstack-limit-register=reg โ€” stack limit register ๐Ÿ“
  • -fstack-limit-symbol=sym โ€” stack limit symbol ๐Ÿท๏ธ
  • -fno-stack-limit โ€” no stack limit ๐Ÿ™…
  • -fsplit-stack โ€” split stack ๐Ÿงต
  • -fvtable-verify=[std|preinit|none] โ€” vtable verification, pick a mode ๐Ÿชช
  • -fvtv-counts โ€” vtable verification counts ๐Ÿ”ข
  • -fvtv-debug โ€” vtable verification debugging ๐Ÿ›
  • -finstrument-functions โ€” instrument functions ๐Ÿ”ฌ
  • -finstrument-functions-exclude-function-list=sym,sym,... โ€” skip these functions when instrumenting ๐Ÿ™ˆ
  • -finstrument-functions-exclude-file-list=file,file,... โ€” skip these files when instrumenting ๐Ÿ™ˆ

โœจ Preprocessor Options โœจ

the preprocessor is basically the prep team before the main show ๐ŸŽ€

  • -Aquestion=answer โ€” assert something ๐Ÿงพ
  • -A-question[=answer] โ€” un-assert something ๐Ÿงพ
  • -C โ€” keep comments ๐Ÿ’ฌ
  • -CC โ€” keep comments, even the sneaky ones ๐Ÿ’ฌโœจ
  • -Dmacro[=defn] โ€” define a macro ๐Ÿงฉ
  • -dD โ€” dump defines ๐Ÿ“‹
  • -dI โ€” dump includes ๐Ÿ“‹
  • -dM โ€” dump macros ๐Ÿ“‹
  • -dN โ€” dump names ๐Ÿ“‹
  • -dU โ€” dump undefined macros ๐Ÿ“‹
  • -fdebug-cpp โ€” preprocessor debugging ๐Ÿ›
  • -fdirectives-only โ€” directives only ๐ŸŽฏ
  • -fdollars-in-identifiers โ€” dollar signs in identifiers ๐Ÿ’ฒ
  • -fexec-charset=charset โ€” execution character set ๐Ÿ”ค
  • -fextended-identifiers โ€” extended identifiers ๐Ÿ†”
  • -finput-charset=charset โ€” input character set ๐Ÿ”ค
  • -flarge-source-files โ€” large source files ๐Ÿ˜
  • -fmacro-prefix-map=old=new โ€” map macro prefixes from old to new ๐Ÿ—บ๏ธ
  • -fmax-include-depth=depth โ€” max include depth ๐Ÿช†
  • -fno-canonical-system-headers โ€” don't canonicalize system headers ๐Ÿ™…
  • -fpch-deps โ€” precompiled header dependencies ๐Ÿงฑ
  • -fpch-preprocess โ€” precompiled header preprocessing ๐Ÿงฑโœจ
  • -fpreprocessed โ€” already preprocessed ๐Ÿฅก
  • -ftabstop=width โ€” tab stop width ๐Ÿ“
  • -ftrack-macro-expansion โ€” track macro expansion ๐Ÿ•ต๏ธ
  • -fwide-exec-charset=charset โ€” wide execution character set ๐Ÿ”คโœจ
  • -fworking-directory โ€” working directory ๐Ÿ“‚
  • -H โ€” show the header chain ๐Ÿ”—
  • -imacros file โ€” include macros from file ๐Ÿ“ฅ
  • -include file โ€” include file first ๐Ÿ“ฅ
  • -M โ€” output make dependencies ๐Ÿ› ๏ธ
  • -MD โ€” make dependencies, written to a file too ๐Ÿ› ๏ธ๐Ÿ“
  • -MF โ€” name the dependency file ๐Ÿท๏ธ
  • -MG โ€” treat missing headers as generated ๐Ÿงพ
  • -MM โ€” make dependencies, skipping system headers ๐Ÿ› ๏ธ
  • -MMD โ€” like -MD, skipping system headers ๐Ÿ› ๏ธ๐Ÿ“
  • -MP โ€” phony targets for headers ๐Ÿ‘ป
  • -MQ โ€” quoted make target ๐Ÿ’…
  • -MT โ€” make target name ๐ŸŽฏ
  • -Mno-modules โ€” no modules ๐Ÿ™…
  • -no-integrated-cpp โ€” no integrated preprocessor ๐Ÿ™…โ€โ™€๏ธ
  • -P โ€” no line markers ๐Ÿงน
  • -pthread โ€” POSIX threads ๐Ÿงต
  • -remap โ€” remap filenames ๐Ÿ—บ๏ธ
  • -traditional โ€” traditional preprocessing, very vintage ๐Ÿ“ผ
  • -traditional-cpp โ€” traditional C preprocessor ๐Ÿ“ผโœจ
  • -trigraphs โ€” trigraphs ๐Ÿ”บ
  • -Umacro โ€” undefine a macro ๐Ÿ—‘๏ธ
  • -undef โ€” undefine all the things ๐Ÿ’ฅ
  • -Wp,option โ€” pass option to the preprocessor ๐ŸŽ
  • -Xpreprocessor option โ€” pass option to the preprocessor ๐ŸŽโœจ

โœจ Assembler Options โœจ

short and sweet, just two of 'em ๐Ÿ‘

  • -Wa,option โ€” pass option to the assembler ๐Ÿงต
  • -Xassembler option โ€” pass option to the assembler ๐Ÿงตโœจ

โœจ Linker Options โœจ

the linker is where everything comes together and clicks ๐Ÿ”—๐Ÿ’–

  • object-file-name โ€” an object file to link ๐Ÿ“ฆ
  • -fuse-ld=linker โ€” pick the linker ๐Ÿ”Œ
  • -llibrary โ€” link against library ๐Ÿ“š
  • -nostartfiles โ€” no startup files ๐Ÿšซ
  • -nodefaultlibs โ€” no default libraries ๐Ÿšซ๐Ÿ“š
  • -nolibc โ€” no C library ๐Ÿšซ
  • -nostdlib โ€” no standard libraries or startup files at all ๐Ÿšซโœจ
  • -e entry โ€” set the entry point to entry ๐Ÿšช
  • --entry=entry โ€” same entry point, long form ๐Ÿšชโœจ
  • -pie โ€” position-independent executable ๐Ÿซง
  • -pthread โ€” POSIX threads ๐Ÿงต
  • -r โ€” relocatable output ๐Ÿ”
  • -rdynamic โ€” export dynamic symbols ๐Ÿ“ค
  • -s โ€” strip the output ๐Ÿช’
  • -static โ€” static linking ๐Ÿงฑ
  • -static-pie โ€” static position-independent executable ๐Ÿซง๐Ÿงฑ
  • -static-libgcc โ€” static libgcc ๐Ÿงฑ
  • -static-libstdc++ โ€” static libstdc++ ๐Ÿงฑ
  • -static-libasan โ€” static libasan ๐Ÿงฑ
  • -static-libtsan โ€” static libtsan ๐Ÿงฑ
  • -static-liblsan โ€” static liblsan ๐Ÿงฑ
  • -static-libubsan โ€” static libubsan ๐Ÿงฑ
  • -shared โ€” make a shared library ๐Ÿค
  • -shared-libgcc โ€” shared libgcc ๐Ÿค
  • -symbolic โ€” bind symbols locally ๐Ÿชž
  • -T script โ€” use linker script ๐Ÿ“œ
  • -Wl,option โ€” pass option to the linker ๐ŸŽ
  • -Xlinker option โ€” pass option to the linker ๐ŸŽโœจ
  • -u symbol โ€” treat symbol as undefined ๐Ÿ‘ป
  • -z keyword โ€” pass the keyword option to the linker ๐Ÿ—๏ธ

โœจ Directory Options โœจ

where should GCC look? bestie gives it directions ๐Ÿ—บ๏ธโœจ

  • -Bprefix โ€” search prefix ๐Ÿงญ
  • -Idir โ€” add dir to the include search path ๐Ÿ“‚
  • -I- โ€” the old -I- behaviour ๐Ÿ™ƒ
  • -idirafter dir โ€” search dir after the others ๐Ÿ•ฐ๏ธ
  • -imacros file โ€” macros from file ๐Ÿ“ฅ
  • -imultilib dir โ€” multilib directory ๐Ÿ“š
  • -iplugindir=dir โ€” plugin directory ๐Ÿ”Œ
  • -iprefix file โ€” prefix for include directories ๐Ÿงพ
  • -iquote dir โ€” quote-only include directory ๐Ÿ’ฌ
  • -isysroot dir โ€” system root dir ๐Ÿ 
  • -isystem dir โ€” system include directory dir ๐Ÿ›๏ธ
  • -iwithprefix dir โ€” include dir under the prefix ๐Ÿงพ
  • -iwithprefixbefore dir โ€” include dir under the prefix, searched earlier ๐Ÿงพโœจ
  • -Ldir โ€” library search directory dir ๐Ÿ“š
  • -no-canonical-prefixes โ€” no canonical prefixes ๐Ÿ™…
  • --no-sysroot-suffix โ€” no sysroot suffix ๐Ÿ™…โ€โ™€๏ธ
  • -nostdinc โ€” no standard include directories ๐Ÿšซ
  • -nostdinc++ โ€” no standard C++ include directories ๐Ÿšซโœจ
  • --sysroot=dir โ€” set the sysroot to dir ๐Ÿ 

โœจ Code Generation Options โœจ

this is where the machine code gets its whole personality ๐Ÿค–๐Ÿ’œ

  • -fcall-saved-reg โ€” call-saved register ๐Ÿซถ
  • -fcall-used-reg โ€” call-used register ๐Ÿซถโœจ
  • -ffixed-reg โ€” fixed register ๐Ÿ“Œ
  • -fexceptions โ€” exceptions ๐Ÿงจ
  • -fnon-call-exceptions โ€” non-call exceptions ๐Ÿงจโœจ
  • -fdelete-dead-exceptions โ€” delete dead exceptions ๐Ÿ’€
  • -funwind-tables โ€” unwind tables ๐Ÿชœ
  • -fasynchronous-unwind-tables โ€” asynchronous unwind tables ๐Ÿชœโฐ
  • -fno-gnu-unique โ€” no GNU unique symbols ๐Ÿ™…
  • -finhibit-size-directive โ€” inhibit size directive ๐Ÿค
  • -fcommon โ€” common symbols ๐Ÿค
  • -fno-ident โ€” no ident ๐Ÿ™…
  • -fpcc-struct-return โ€” PCC struct return ๐Ÿงพ
  • -fpic โ€” position-independent code ๐Ÿซง
  • -fPIC โ€” position-independent code, big edition ๐Ÿซงโœจ
  • -fpie โ€” position-independent executable code ๐Ÿซง
  • -fPIE โ€” position-independent executable, big edition ๐Ÿซงโœจ
  • -fno-plt โ€” no PLT ๐Ÿ™…
  • -fno-jump-tables โ€” no jump tables ๐Ÿ™…
  • -fno-bit-tests โ€” no bit tests ๐Ÿ™…โ€โ™€๏ธ
  • -frecord-gcc-switches โ€” record GCC switches ๐Ÿ“
  • -freg-struct-return โ€” register struct return ๐Ÿงพ
  • -fshort-enums โ€” short enums ๐Ÿชถ
  • -fshort-wchar โ€” short wchar_t ๐Ÿชถ
  • -fverbose-asm โ€” verbose assembly ๐Ÿ—ฃ๏ธ
  • -fpack-struct[=n] โ€” pack structs ๐Ÿ“ฆ
  • -fleading-underscore โ€” leading underscore ๐Ÿซข
  • -ftls-model=model โ€” thread-local storage model ๐Ÿงต
  • -fstack-reuse=reuse_level โ€” stack reuse level โ™ป๏ธ
  • -ftrampolines โ€” trampolines ๐Ÿคธ
  • -ftrapv โ€” trap on signed overflow ๐Ÿชค
  • -fwrapv โ€” wrap on signed overflow ๐Ÿ”
  • -fvisibility=[default|internal|hidden|protected] โ€” symbol visibility, pick one ๐Ÿ‘€
  • -fstrict-volatile-bitfields โ€” strict volatile bitfields ๐Ÿงฑ
  • -fsync-libcalls โ€” sync libcalls ๐Ÿ”„

โœจ Developer Options โœจ

the developer zone, bestie. this is where the debugging magic lives ๐Ÿช„๐Ÿ’œ

  • -dletters โ€” dump letters ๐Ÿ”ค
  • -dumpspecs โ€” dump the specs ๐Ÿ“‹
  • -dumpmachine โ€” dump the machine name ๐Ÿ–ฅ๏ธ
  • -dumpversion โ€” dump the version ๐Ÿท๏ธ
  • -dumpfullversion โ€” dump the full version ๐Ÿท๏ธโœจ
  • -fcallgraph-info[=su,da] โ€” call graph info ๐Ÿ•ธ๏ธ
  • -fchecking โ€” checking ๐Ÿ”
  • -fchecking=n โ€” checking at level n ๐Ÿ”โœจ
  • -fdbg-cnt-list โ€” debug counter list ๐Ÿ”ข
  • -fdbg-cnt=counter-value-list โ€” debug counter values ๐Ÿ”ขโœจ
  • -fdisable-ipa-pass_name โ€” disable an IPA pass ๐Ÿšซ
  • -fdisable-rtl-pass_name โ€” disable an RTL pass ๐Ÿšซ
  • -fdisable-rtl-pass-name=range-list โ€” disable RTL passes in a range list ๐Ÿšซโœจ
  • -fdisable-tree-pass_name โ€” disable a tree pass ๐Ÿšซ
  • -fdisable-tree-pass-name=range-list โ€” disable tree passes in a range list ๐Ÿšซโœจ
  • -fdump-debug โ€” dump debug info ๐Ÿ›
  • -fdump-earlydebug โ€” dump early debug info ๐Ÿ›โฐ
  • -fdump-noaddr โ€” dump without addresses ๐Ÿ™ˆ
  • -fdump-unnumbered โ€” dump unnumbered ๐Ÿ”ข
  • -fdump-unnumbered-links โ€” dump unnumbered links ๐Ÿ”—
  • -fdump-final-insns[=file] โ€” dump the final insns ๐Ÿงพ
  • -fdump-ipa-all โ€” dump all IPA info ๐Ÿ—‚๏ธ
  • -fdump-ipa-cgraph โ€” dump the IPA call graph ๐Ÿ•ธ๏ธ
  • -fdump-ipa-inline โ€” dump IPA inlining ๐Ÿ—‚๏ธ
  • -fdump-lang-all โ€” dump all language info ๐Ÿ—‚๏ธ
  • -fdump-lang-switch โ€” dump language switch ๐Ÿ”€
  • -fdump-lang-switch-options โ€” dump language switch options ๐Ÿ”€โœจ
  • -fdump-lang-switch-options=filename โ€” dump language switch options to filename ๐Ÿ”€๐Ÿ“
  • -fdump-passes โ€” dump passes ๐Ÿ—‚๏ธ
  • -fdump-rtl-pass โ€” dump an RTL pass ๐Ÿ—‚๏ธ
  • -fdump-rtl-pass=filename โ€” dump an RTL pass to filename ๐Ÿ—‚๏ธ๐Ÿ“
  • -fdump-statistics โ€” dump statistics ๐Ÿ“Š
  • -fdump-tree-all โ€” dump all tree info ๐ŸŒณ
  • -fdump-tree-switch โ€” dump tree switch ๐ŸŒณ๐Ÿ”€
  • -fdump-tree-switch-options โ€” dump tree switch options ๐ŸŒณ๐Ÿ”€โœจ
  • -fdump-tree-switch-options=filename โ€” dump tree switch options to filename ๐ŸŒณ๐Ÿ“
  • -fcompare-debug[=opts] โ€” compare debug output ๐Ÿ”
  • -fcompare-debug-second โ€” compare debug output, second run ๐Ÿ”โœจ
  • -fenable-kind-pass โ€” enable a kind of pass โœ…
  • -fenable-kind-pass=range-list โ€” enable passes in a range list โœ…โœจ
  • -fira-verbose=n โ€” IRA verbosity at level n ๐Ÿ—ฃ๏ธ
  • -flto-report โ€” LTO report ๐Ÿ“
  • -flto-report-wpa โ€” LTO WPA report ๐Ÿ“๐Ÿ”ญ
  • -fmem-report-wpa โ€” memory report for WPA ๐Ÿง ๐Ÿ”ญ
  • -fmem-report โ€” memory report ๐Ÿง 
  • -fpre-ipa-mem-report โ€” memory report before IPA ๐Ÿง โช
  • -fpost-ipa-mem-report โ€” memory report after IPA ๐Ÿง โฉ
  • -fopt-info โ€” optimization info ๐Ÿ’ก
  • -fopt-info-options[=file] โ€” optimization info options ๐Ÿ’กโœจ
  • -fprofile-report โ€” profile report ๐Ÿ“ˆ
  • -frandom-seed=string โ€” random seed ๐ŸŽฒ
  • -fsched-verbose=n โ€” scheduler verbosity at level n ๐Ÿ—ฃ๏ธ
  • -fsel-sched-verbose โ€” selective scheduler verbose ๐Ÿ—ฃ๏ธ
  • -fsel-sched-dump-cfg โ€” selective scheduler CFG dump ๐Ÿ—‚๏ธ
  • -fsel-sched-pipelining-verbose โ€” selective pipelining verbose ๐Ÿ—ฃ๏ธ
  • -fstats โ€” stats ๐Ÿ“Š
  • -fstack-usage โ€” stack usage ๐Ÿ“
  • -ftime-report โ€” time report โฑ๏ธ
  • -ftime-report-details โ€” time report details โฑ๏ธโœจ
  • -fvar-tracking-assignments-toggle โ€” toggle variable tracking assignments ๐Ÿ”€
  • -gtoggle โ€” toggle debug info ๐Ÿ”€
  • -print-file-name=library โ€” print the path of library ๐Ÿ–จ๏ธ
  • -print-libgcc-file-name โ€” print the libgcc file name ๐Ÿ–จ๏ธ
  • -print-multi-directory โ€” print the multilib directory ๐Ÿ–จ๏ธ
  • -print-multi-lib โ€” print multilib info ๐Ÿ–จ๏ธ
  • -print-multi-os-directory โ€” print the multilib OS directory ๐Ÿ–จ๏ธ
  • -print-prog-name=program โ€” print the path of program ๐Ÿ–จ๏ธ
  • -print-search-dirs โ€” print search directories ๐Ÿ–จ๏ธ
  • -Q โ€” print what's happening as it happens ๐Ÿ—ฃ๏ธ
  • -print-sysroot โ€” print the sysroot ๐Ÿ–จ๏ธ
  • -print-sysroot-headers-suffix โ€” print the sysroot headers suffix ๐Ÿ–จ๏ธ
  • -save-temps โ€” save temp files ๐Ÿ’พ
  • -save-temps=cwd โ€” save temp files in the current directory ๐Ÿ’พ๐Ÿ“‚
  • -save-temps=obj โ€” save temp files in the object directory ๐Ÿ’พ๐Ÿ“ฆ
  • -time[=file] โ€” time it โฑ๏ธ

โœจ Machine-Dependent Options โœจ

the hardware-specific section, where each chip gets its own main character moment ๐ŸŒˆ๐Ÿ‘‘

AArch64 Options

  • -mabi=name โ€” ABI name ๐Ÿงพ
  • -mbig-endian โ€” big-endian ๐Ÿงฑ
  • -mlittle-endian โ€” little-endian ๐Ÿงฑ
  • -mgeneral-regs-only โ€” general registers only ๐ŸŽฏ
  • -mcmodel=tiny โ€” tiny code model ๐Ÿœ
  • -mcmodel=small โ€” small code model ๐Ÿญ
  • -mcmodel=large โ€” large code model ๐Ÿ˜
  • -mstrict-align โ€” strict alignment ๐Ÿ“
  • -mno-strict-align โ€” no strict alignment ๐Ÿ™…
  • -momit-leaf-frame-pointer โ€” omit leaf frame pointer ๐Ÿซฅ
  • -mtls-dialect=desc โ€” TLS dialect, descriptor style ๐Ÿงต
  • -mtls-dialect=traditional โ€” TLS dialect, traditional style ๐Ÿงต๐Ÿ“ผ
  • -mtls-size=size โ€” TLS size ๐Ÿ“
  • -mfix-cortex-a53-835769 โ€” fix Cortex-A53 erratum 835769 ๐Ÿฉน
  • -mfix-cortex-a53-843419 โ€” fix Cortex-A53 erratum 843419 ๐Ÿฉน
  • -mlow-precision-recip-sqrt โ€” low-precision reciprocal square root ๐Ÿงฎ
  • -mlow-precision-sqrt โ€” low-precision square root ๐Ÿงฎ
  • -mlow-precision-div โ€” low-precision division ๐Ÿงฎ
  • -mpc-relative-literal-loads โ€” PC-relative literal loads ๐Ÿ”
  • -msign-return-address=scope โ€” sign return address, pick a scope โœ๏ธ
  • -mbranch-protection=none|standard|pac-ret[+leaf +b-key]|bti โ€” branch protection, pick one ๐Ÿ›ก๏ธ
  • -mharden-sls=opts โ€” harden SLS with these options ๐Ÿ›ก๏ธ
  • -march=name โ€” architecture name ๐Ÿ—๏ธ
  • -mcpu=name โ€” CPU name ๐Ÿง 
  • -mtune=name โ€” tune for name ๐ŸŽ›๏ธ
  • -moverride=string โ€” override string ๐Ÿ”ง
  • -mverbose-cost-dump โ€” verbose cost dump ๐Ÿ—ฃ๏ธ
  • -mstack-protector-guard=guard โ€” stack protector guard ๐Ÿ›ก๏ธ
  • -mstack-protector-guard-reg=sysreg โ€” stack protector guard register ๐Ÿ›ก๏ธ๐Ÿ“Œ
  • -mstack-protector-guard-offset=offset โ€” stack protector guard offset ๐Ÿ›ก๏ธ๐Ÿ“
  • -mtrack-speculation โ€” track speculation ๐Ÿ”ฎ
  • -moutline-atomics โ€” outline atomics โš›๏ธ

Okay bestie, this is the target-specific lineup ๐Ÿฆ‹ every machine gets its own squad of flags, and this part is just the names, no descriptions yet ๐Ÿ’…

๐Ÿฆ‹ 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
  • -mfix-cmse-cve-2021-35465
  • -mfdpic

๐Ÿ“ AVR Options ๐Ÿ“

  • -mmcu=mcu
  • -mabsdata
  • -maccumulate-args
  • -mbranch-cost=cost
  • -mcall-prologues
  • -mgas-isr-prologues
  • -mint8
  • -mdouble=bits
  • -mlong-double=bits
  • -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
  • -metrax4
  • -metrax100
  • -mpdebug
  • -mcc-init
  • -mno-side-effects
  • -mstack-align
  • -mdata-align
  • -mconst-align
  • -m32-bit
  • -m16-bit
  • -m8-bit
  • -mno-prologue-epilogue
  • -melf
  • -maout
  • -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
  • -mfloat-abi=name
  • -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
  • -msim

๐Ÿ‘‘ Darwin Options ๐Ÿ‘‘

  • -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 ๐Ÿฆ‹

  • -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

๐Ÿงš eBPF Options ๐Ÿงš

  • -mbig-endian
  • -mlittle-endian
  • -mkernel=version
  • -mframe-limit=bytes
  • -mxbpf

๐Ÿ’œ FR30 Options ๐Ÿ’œ

  • -msmall-model
  • -mno-lsim

๐ŸŒธ FT32 Options ๐ŸŒธ

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

๐Ÿ’… FRV Options ๐Ÿ’…

  • -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 ๐ŸŒˆ

  • -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 so MIPS has SO many flags ๐Ÿ™ˆ bestie, this is a whole vibe. here's the full list, no cuts ๐Ÿ’…

-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

the MMIX crew is smaller but still iconic ๐Ÿ’œ

-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

tiny but mighty โœจ

-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  -mtiny-printf
-mmax-inline-shift=

๐Ÿ’– 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

-m64  -mmainkernel  -moptimize

๐ŸŒˆ OpenRISC Options

-mboard=name  -mnewlib  -mhard-mul  -mhard-div
-msoft-mul  -msoft-div -msoft-float  -mhard-float  -mdouble-float
-munordered-float -mcmov  -mror  -mrori  -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

no separate list here, bestie. the PowerPC flags live under the RS/6000 and PowerPC Options section, so see RS/6000 and PowerPC Options ๐Ÿ’…

๐Ÿฆ‹ PRU Options

-mmcu=mcu  -minrt  -mno-relax  -mloop -mabi=variant

๐ŸŒธ 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
-mshorten-memrefs  -mno-shorten-memrefs -mstrict-align
-mno-strict-align -mcmodel=medlow  -mcmodel=medany -mexplicit-relocs
-mno-explicit-relocs -mrelax  -mno-relax -mriscv-attribute
-mmo-riscv-attribute -malign-data=type -mbig-endian  -mlittle-endian
+-mstack-protector-guard=guard -mstack-protector-guard-reg=reg
+-mstack-protector-guard-offset=offset

๐Ÿ’œ 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

this one is LONG, like full main character marathon ๐Ÿ˜ญ every single flag is here:

-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
-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 -mno-block-ops-unaligned-vsx
-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 -mprefixed -mno-prefixed
-mpcrel -mno-pcrel -mmma -mno-mmma -mrop-protect -mno-rop-protect
-mprivileged -mno-privileged

โœจ 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  -mtpf-trace-skip
-mno-tpf-trace-skip -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

๐Ÿงš 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 โœจ

okay bestie, the V850 crew has its own little flag squad ๐Ÿฆ‹ here's every single one, copied exactly:

-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 ๐ŸŒธ

the VAX ones are small but mighty ๐Ÿ’…

-mg  -mgnu  -munix

๐Ÿงš Visium Options ๐Ÿงš

Visium has a whole set of its own, no cap ๐Ÿ”ฅ

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

๐ŸŽ€ VMS Options ๐ŸŽ€

for VMS, these are the ones you want ๐Ÿ’œ

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

๐Ÿฆ‹ VxWorks Options ๐Ÿฆ‹

VxWorks is giving main character energy ๐Ÿ‘‘

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

๐Ÿ’– x86 Options ๐Ÿ’–

okay this is the big one, the x86 list is literally massive ๐Ÿ˜ญ it covers tuning, architecture, floating point, SSE and AVX families, calling conventions, and so much more. bestie, grab a snack ๐Ÿ“

-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 -mmwait -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 -mavx512bf16 -menqcmd -mvpclmulqdq  -mavx512bitalg
-mmovdiri  -mmovdir64b  -mavx512vpopcntdq -mavx5124fmaps
-mavx512vnni  -mavx5124vnniw  -mprfchw  -mrdpid -mrdseed  -msgx
-mavx512vp2intersect -mserialize -mtsxldtrk -mamx-tile  -mamx-int8
-mamx-bf16 -muintr -mhreset -mavxvnni -mcldemote  -mms-bitfields
-mno-align-stringops  -minline-all-stringops
-minline-stringops-dynamically  -mstringop-strategy=alg -mkl
-mwidekl -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 -mdaz-ftz -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
-mharden-sls=choice -mindirect-branch-cs-prefix -mneeded

๐ŸŒˆ x86 Windows Options ๐ŸŒˆ

Windows x86 gets its own squad too ๐ŸชŸโœจ

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

๐Ÿ“ Xstormy16 Options ๐Ÿ“

only one flag for this one, but it's a serious one ๐Ÿซถ

-msim

๐Ÿ’œ Xtensa Options ๐Ÿ’œ

Xtensa has a whole cute collection of its own ๐ŸŒธ

-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 -mabi=abi-type

๐Ÿงš zSeries Options ๐Ÿงš

no flags of its own here, bestie. the zSeries stuff lives over at 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, and they always happen in that order ๐Ÿ”ฅ GCC can preprocess and compile several files into several assembler input files, or into one assembler input file. then each assembler input file makes an object file, and linking smooshes all the object files together (the newly compiled ones and the ones you gave it as input) into an executable file ๐Ÿ’–

for any given input file, the file name suffix decides what kind of compilation happens. iykyk ๐Ÿซถ

  • file.c โ€” C source that still needs to go through the preprocessor first ๐Ÿงš
  • file.i โ€” C source that should not be preprocessed.
  • file.ii โ€” C++ source that should not be preprocessed.
  • file.m โ€” Objective-C source code. Note that you must link with the libobjc library to make an Objective-C program work.
  • file.mi โ€” Objective-C source that should not be preprocessed.
  • file.mm, file.M โ€” Objective-C++ source code. Note that you must link with the libobjc library to make an Objective-C++ program work. Also, .M refers to a literal capital M.
  • file.mii โ€” Objective-C++ source that should not be preprocessed.
  • file.h โ€” a C, C++, Objective-C, or Objective-C++ header that gets turned into a precompiled header (this is the default), or a C or C++ header that gets turned into an Ada spec (via 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. Note that in .cxx, the last two letters must both be literally x. Likewise, .C refers to 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.
  • 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 (with 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 (with the traditional preprocessor).
  • file.go โ€” Go source code.
  • file.brig โ€” BRIG files (binary representation of HSAIL).
  • file.d โ€” D source code.
  • file.di โ€” D interface file.
  • file.dd โ€” D documentation code (Ddoc).
  • file.ads โ€” Ada source that holds 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 โ€” Ada source that holds 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 is treated this way.

you can also tell GCC the input language yourself with the -x option ๐ŸŽ€

โœจ -x language โœจ

this lets you pick the language for the input files that follow, instead of letting the compiler guess from the file name suffix ๐Ÿ’… it applies to all following input files until the next -x option. the possible values for language are:

c  c-header  cpp-output
c++  c++-header  c++-system-header c++-user-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

this turns off any language specification, so the files after it are handled by their file name suffixes, just like they would be 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, and one of the options -c, -S, or -E to say where gcc should stop. heads up, some combos (for example, -x cpp-output -E) make gcc do absolutely nothing at all ๐Ÿ’€

๐Ÿซถ -c

compile or assemble the source files, but do not link ๐Ÿ”— the linking stage just doesn't happen. the final output is 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

stop after the compilation proper stage and skip assembling ๐Ÿงš the output is an assembler code file for each non-assembler input file you gave it.

by default, the assembler file name for a source file is made by swapping the suffix .c, .i, etc. for .s.

input files that don't need compiling are ignored.

๐Ÿ’– -E

stop after the preprocessing stage and don't run the compiler proper ๐ŸŒˆ the output is preprocessed source code, sent to standard output.

input files that don't need preprocessing are ignored.

๐Ÿ‘‘ -o file

place the primary output in file ๐Ÿ‘‘ this applies to whatever kind of output you're making, whether that's an executable, an object file, an assembler file, or preprocessed C code.

if -o isn't specified, 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 preprocessed C source goes to standard output ๐Ÿ“

Okay so, this next bit is all about how -o quietly decides what your aux and dump files get named, and bestie, it's giving main character energy ๐Ÿ’…โœจ

The primary output is just the one file -o names, but it also controls the naming of your auxiliary and dump outputs ๐Ÿฆ‹ Check the examples below, they're lowkey the best part. Unless you override it, aux and dump outputs land in the same directory as the primary output ๐ŸŒธ For auxiliary outputs, the input file's suffix gets swapped for the aux file type's suffix. For dump outputs, the dump file's suffix gets tacked onto the input file's suffix. In compilation commands, both aux and dump outputs use the primary output's base name. In compile and link commands, the primary output name (minus the executable suffix) gets mixed with the input file name. If both end up with the same base name once you ignore the suffix, the result is just that base name. If they don't match, they get smooshed together with a dash between them ๐ŸŽ€

gcc -c foo.c ...

This will use foo.o as the primary output and drop aux outputs and dumps right next to it. For example, you get the aux file foo.dwo for -gsplit-dwarf, and the dump file foo.c.???r.final for -fdump-rtl-final ๐Ÿงš

If you explicitly give a non-linker output file, aux and dump files default to the same base name, and that's so clean ๐Ÿซถ

gcc -c foo.c -o dir/foobar.o ...

This will name the aux outputs dir/foobar.* and the dump outputs dir/foobar.c.* ๐Ÿ“

A linker output works differently and prefixes the aux and dump outputs instead ๐Ÿ‘‘

gcc foo.c bar.c -o dir/foobar ...

This will generally name the aux outputs dir/foobar-foo.* and dir/foobar-bar.*, and the dump outputs dir/foobar-foo.c.* and dir/foobar-bar.c.* ๐Ÿ’–

The one exception is when the executable shares its base name with the single input ๐Ÿ™ˆ

gcc foo.c -o dir/foo ...

In that case the aux outputs are dir/foo.* and the dump outputs are dir/foo.c.* โœจ

You can tweak the location and names of aux and dump outputs with -dumpbase, -dumpbase-ext, -dumpdir, -save-temps=cwd, and -save-temps=obj ๐ŸŒˆ

๐ŸŽ€ -dumpbase dumpbase

This option sets the base name for aux and dump output files. It does not touch the name of the primary output file ๐Ÿ’… Intermediate outputs, when you keep them, aren't treated as primary outputs. They count as auxiliary outputs instead ๐Ÿฆ‹

gcc -save-temps -S foo.c

This saves the (no longer temporary) preprocessed file as foo.i, then compiles to the (implied) output file foo.s. Iconic ๐ŸŒธ

gcc -save-temps -dumpbase save-foo -c foo.c

This one preprocesses to save-foo.i, compiles to save-foo.s (now an intermediate, so it's an auxiliary output), and then assembles to the (implied) output file foo.o โœจ

Without this option, dump and aux files get their names from the input file, or from the (non-linker) output file if you explicitly named one. Dump output files (like the ones from -fdump-* options) keep the input name suffix. Aux output files (the ones from other non-dump options, like "-save-temps", "-gsplit-dwarf", and "-fcallgraph-info") drop it ๐Ÿงš

You can get similar suffix differentiation between dump and aux outputs with an explicit -dumpbase basename.suf by also passing -dumpbase-ext .suf ๐Ÿซถ

If you give dumpbase an explicit directory component, any dumppfx specification (like -dumpdir or -save-temps=*) gets ignored. Instead of appending to it, dumpbase fully overrides it ๐Ÿ’€

gcc foo.c -c -o dir/foo.o -dumpbase alt/foo \
  -dumpdir pfx- -save-temps=cwd ...

This creates aux and dump outputs named alt/foo.*. It totally ignores dir/ in -o, the ./ prefix implied by -save-temps=cwd, and pfx- in -dumpdir ๐Ÿ‘‘

When you pass -dumpbase in a command that compiles multiple inputs, or compiles and then links, it can be combined with dumppfx, same as under -dumpdir. Each input file then gets compiled with the combined dumppfx, and its own default values for dumpbase and auxdropsuf ๐ŸŒˆ

gcc foo.c bar.c -c -dumpbase main ...

This creates foo.o and bar.o as primary outputs. It also stops the aux and dump outputs from overwriting each other by using the dumpbase as a prefix, so you get main-foo.* and main-bar.* ๐Ÿฆ‹

An empty string as dumpbase stops the output basename from influencing aux and dump names during compilation. The defaults get computed instead ๐Ÿ“

gcc -c foo.c -o dir/foobar.o -dumpbase " ...

This names the aux outputs dir/foo.* and the dump outputs dir/foo.c.*. Notice how the basenames come from the input name, but the directory still defaults to the output's directory ๐Ÿงš

The empty-string dumpbase doesn't stop the output basename from being used during linking, though ๐Ÿ’…

gcc foo.c bar.c -o dir/foobar -dumpbase " -flto ...

The source file compilation names the aux outputs dir/foo.* and dir/bar.*, and the dump outputs dir/foo.c.* and dir/bar.c.*. LTO recompilation during linking uses dir/foobar. as the prefix for dumps and aux files ๐Ÿ”ฅ

๐Ÿฆ‹ -dumpbase-ext auxdropsuf

When you form the name of an auxiliary output file (but not a dump one), this drops the trailing auxdropsuf from dumpbase before any suffixes get appended ๐Ÿซถ If you don't specify it, it defaults to the suffix of a default dumpbase. That means the input file's suffix when -dumpbase isn't on the command line, or when dumpbase gets combined with dumppfx โœจ

gcc foo.c -c -o dir/foo.o -dumpbase x-foo.c -dumpbase-ext .c ...

This creates dir/foo.o as the main output and generates aux outputs in dir/x-foo.*. They sit where the primary output is, and the .c suffix gets dropped from the dumpbase. Dump outputs keep the suffix, so they're dir/x-foo.c.* ๐Ÿ’–

This option gets ignored if it doesn't match the suffix of a specified dumpbase. The one exception is as an alternative to the executable suffix when the linker output base name gets appended to dumppfx, as described below ๐ŸŒธ

gcc foo.c bar.c -o main.out -dumpbase-ext .out ...

This creates main.out as the primary output. It stops the aux and dump outputs from overwriting each other by using the executable name minus auxdropsuf as a prefix. So you get aux outputs main-foo.* and main-bar.*, and dump outputs main-foo.c.* and main-bar.c.* ๐ŸŒˆ

๐Ÿงš -dumpdir dumppfx

When you form the name of an auxiliary or dump output file, this uses dumppfx as a prefix ๐ŸŽ€

gcc -dumpdir pfx- -c foo.c ...

This creates foo.o as the primary output and aux outputs named pfx-foo.*. It combines the given dumppfx with the default dumpbase, which comes from the default primary output, which in turn comes from the input name. Dump outputs also take the input name suffix, so they're pfx-foo.c.* โœจ

If you want dumppfx to work as a directory name, it has to end with a directory separator ๐Ÿ‘‘

gcc -dumpdir dir/ -c foo.c -o obj/bar.o ...

This creates obj/bar.o as the primary output and aux outputs named dir/bar.*. It combines the given dumppfx with the default dumpbase derived from the primary output name. Dump outputs take the input name suffix too, so they're dir/bar.c.* ๐Ÿฆ‹

By default it's the location of the output file, unless the output file is a special file like "/dev/null". The options -save-temps=cwd and -save-temps=obj override that default, just like an explicit -dumpdir option does. If you pass several of these, the last one wins ๐Ÿ’…

gcc -dumpdir pfx- -c foo.c -save-temps=obj ...

This outputs foo.o, with aux outputs named foo.*, because -save-temps=* overrides the dumppfx from the earlier -dumpdir. It doesn't matter that =obj is already the default for -save-temps, or that the output directory is implicitly the current directory. Dump outputs are named foo.c.* ๐ŸŒธ

When you compile from multiple input files and specify -dumpbase, dumpbase (minus an auxdropsuf suffix) plus a dash gets appended to an explicit or defaulted dumppfx. If dumpbase has any directory components, it overrides dumppfx instead. This way each compilation gets its own differently-named aux and dump outputs ๐Ÿซถ

gcc foo.c bar.c -c -dumpdir dir/pfx- -dumpbase main ...

This outputs aux dumps to dir/pfx-main-foo.* and dir/pfx-main-bar.*, appending dumpbase- to dumppfx. Dump outputs keep the input file suffix, so they're dir/pfx-main-foo.c.* and dir/pfx-main-bar.c.*, respectively ๐Ÿงš

Compare that with single-input compilation:

gcc foo.c -c -dumpdir dir/pfx- -dumpbase main ...

Applying -dumpbase to a single source doesn't compute and append a separate dumpbase per input file. Its aux and dump outputs go in dir/pfx-main.* ๐Ÿ’–

When you compile and then link from multiple input files, a defaulted or explicitly specified dumppfx also goes through the dumpbase- transformation above. Think the compilation of foo.c and bar.c above, just without -c. If you specify neither -dumpdir nor -dumpbase, the linker output base name gets appended to the default dumppfx instead. That's the base name minus auxdropsuf if you gave one, or minus the executable suffix otherwise, plus a dash ๐ŸŒˆ

gcc foo.c bar.c -dumpdir dir/pfx- -o main ...

Heads up, though: unlike the earlier linking cases, this does not append the output name main to dumppfx, because -dumpdir is explicitly specified. The idea is that your explicit dumppfx can include the output name as part of the prefix if you want it to. Only an explicitly specified -dumpbase gets combined with it, so a meaningful option doesn't get quietly thrown away ๐Ÿ”ฅ

When you compile and link from a single input file, the linker output base name only gets appended to the default dumppfx (as above) if it doesn't share the base name with the single input file name. This was covered in the single-input linking cases above, but not for an explicit -dumpdir that stops the combination, even when -save-temps=* overrides it:

gcc foo.c -dumpdir alt/pfx- -o dir/main.exe -save-temps=cwd ...

Aux outputs are named foo.*, and dump outputs foo.c.*, in the current working directory, as finally requested by -save-temps=cwd ๐Ÿ“

The dump-name stuff is kinda the boss level of this whole page, so here's the vibe ๐Ÿ’…: the main output name gets split into a directory part and a basename part. dumppfx takes the directory part, unless you override it with -dumpdir or -save-temps=*. dumpbase takes the basename, unless you override it with -dumpbase. If there are multiple inputs or you're linking, dumpbase can get combined with dumppfx and pulled from each input file ๐Ÿงš. Auxiliary output names for each input are made by mashing together dumppfx, dumpbase minus its suffix, and the auxiliary output suffix. Dump output names are basically the same, except they keep the suffix from dumpbase ๐Ÿฆ‹

Okay, now the LTO recompilation bit ๐Ÿ”ฅ. Auxiliary and dump outputs made during LTO recompilation get a combo of dumppfx and dumpbase passed down to lto-wrapper as a -dumpdir option. That combo can come from what you gave it or from the linker output name (but not from the inputs), and it's sent this way even when it wouldn't normally be used like that. The trailing period replaces the compiler-added dash, if there is one. Since this program is involved in linking, it doesn't normally get any -dumpbase or -dumpbase-ext, and it ignores them ๐Ÿ’€

When it runs sub-compilers, lto-wrapper tacks the LTO stage names onto the dumppfx it received, makes sure that has a directory component so it overrides any -dumpdir, and passes the result along as -dumpbase to the sub-compilers โœจ

  • -v โ€” Print (on standard error output) the commands executed to run the stages of compilation. It also prints the version number of the compiler driver program and of the preprocessor and the compiler proper ๐Ÿ“ฃ
  • -### โ€” Basically -v, but the commands don't actually run, and arguments get quoted unless they only contain alphanumeric characters or "./-_". This is perfect for shell scripts that want to capture the driver-generated command lines ๐Ÿค–
  • --help โ€” Print (on the standard output) a description of the command-line options gcc understands. If -v is also specified, --help gets passed on to the various processes gcc invokes, so they can show the command-line options they accept. If -Wextra was also specified (before the --help option), command-line options with no documentation attached get displayed too ๐ŸŽ€
  • --target-help โ€” Prints (on the standard output) a description of the target-specific command-line options for each tool. For some targets, extra target-specific information might get printed too ๐ŸŒธ
  • --help={class|[^]qualifier}[,...] โ€” Print (on the standard output) a description of the command-line options the compiler understands that fit into all the specified classes and qualifiers. Here are the supported classes ๐Ÿ‘‘
    • optimizers โ€” Shows all the optimization options the compiler supports.
    • warnings โ€” Shows all the options that control the warning messages the compiler produces.
    • target โ€” Shows target-specific options. Unlike --target-help, target-specific options of the linker and assembler aren't shown, because those tools don't currently support the extended --help= syntax.
    • params โ€” Shows the values recognized by the --param option.
    • language โ€” Shows the options supported for language, where language is the name of one of the languages supported in this version of GCC. If an option is supported by all languages, you need to pick the common class.
    • common โ€” Shows the options that are common to all languages.

Here 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 after the original option, like -o output-file.

Want all the undocumented target-specific switches the compiler supports? Use this ๐Ÿ”

--help=target,undocumented

The sense of a qualifier can be flipped by prefixing it with the ^ character. So if you want all the binary warning options (the ones that are either on or off and don't take an argument) that have a description, use this ๐Ÿ™ˆ

--help=warnings,^joined,^undocumented

The argument to --help= shouldn't consist solely of inverted qualifiers.

You can combine several classes, but that usually restricts the output so much there's nothing to display. One case where it does work is when one of the classes is target. For example, to display all the target-specific optimization options, use this ๐Ÿ’–

--help=target,optimizers

The --help= option can be repeated on the command line. Each successive use displays its requested class of options, skipping any that have already been displayed. If --help is also specified anywhere on the command line, it takes precedence over any --help= option ๐Ÿ‘‘

If the -Q option appears on the command line before the --help= option, the descriptive text shown by --help= changes. Instead of describing the displayed options, it gives an indication of whether each option is enabled, disabled, or set to a specific value (assuming the compiler knows this 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 the effects of previous command-line options, so you can find out which optimizations are enabled at -O2 by using this ๐Ÿฆ‹

-Q -O2 --help=optimizers

Or, if you want to discover which binary optimizations are enabled by -O3, do 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 โ€” Normally, the gcc program exits with the code of 1 if any phase of the compiler returns a non-success return code. If you specify -pass-exit-codes, the gcc program instead returns the numerically highest error produced by any phase that returned an error indication. The C, C++, and Fortran front ends return 4 if they hit an internal compiler error ๐Ÿšจ
  • -pipe โ€” Uses pipes rather than temporary files for communication between the various stages of compilation. This fails on some systems where the assembler can't read from a pipe, but the GNU assembler has no trouble ๐ŸŒŠ
  • -specs=file โ€” Processes file after the compiler reads in the standard specs file, to override the defaults the gcc driver uses when deciding which switches to pass to cc1, cc1plus, as, ld, etc. You can specify more than one -specs=file on the command line, and they're processed in order, from left to right ๐Ÿ“
  • -wrapper โ€” Invokes all subcommands under a wrapper program. The name of the wrapper program and its parameters are passed as a comma separated list ๐ŸŽ
gcc -c t.c -wrapper gdb,--args

This invokes all subprograms of gcc under gdb --args, so the invocation of cc1 becomes gdb --args cc1 ... ๐Ÿ’œ

  • -ffile-prefix-map=old=new โ€” When compiling files living in directory old, any references to them in the compilation result get recorded as if the files lived in directory new instead. Specifying this option is equivalent to specifying all the individual -f*-prefix-map options. It's a great way to make reproducible, location-independent builds ๐ŸŒธ See also -fmacro-prefix-map and -fdebug-prefix-map.
  • -fplugin=name.so โ€” Loads 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 file identifies the plugin for argument parsing (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, generates 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, generates corresponding Go declarations in file. This makes Go const, type, var, and func declarations, which can be a super useful way to start writing a Go interface to code written in some other language ๐Ÿน
  • @file โ€” Reads command-line options from file. The options read get inserted in place of the original @file option. If file doesn't exist or can't be read, the option gets treated literally and isn't removed ๐Ÿ™ƒ

Options in file are separated by whitespace. You can include a whitespace character in an option by surrounding the entire option in either single or double quotes. Any character (including a backslash) can be included by prefixing it with a backslash. The file may contain additional @file options too, and those get processed recursively ๐ŸŒ€


๐Ÿ’… Compiling C++ Programs ๐Ÿ’…

C++ source files conventionally 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, the use of gcc does not add the C++ library, bestie ๐Ÿ’€. That's where g++ slides in โœจ. g++ is a program that calls GCC and automatically specifies linking against the C++ library, so you don't have to remember it ๐Ÿ’…. It treats .c, .h and .i files as C++ source files instead of C source files unless -x is used. It's also handy for 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 lots of the same command-line options you'd use for any language, or options meant for C and related languages, or options that only matter for C++ ๐Ÿฆ‹.


โœจ Options Controlling C Dialect โœจ

These options control the dialect of C (or languages derived from C, like C++, Objective-C and Objective-C++) that the compiler accepts ๐Ÿ‘‘:

  • -ansi โ€” In C mode this is the same as -std=c90, and in C++ mode it's the same as -std=c++98 ๐ŸŽ€. It turns off GCC features that clash with ISO C90 (when compiling C) or standard C++ (when compiling C++), like the asm and typeof keywords, plus predefined macros like unix and vax that tell you what system you're on ๐Ÿ™ˆ. It also switches on the undesirable and rarely used ISO trigraph feature ๐Ÿ’€. For the C compiler, it also turns off recognition of C++ style // comments as well as the inline keyword. The alternate keywords __asm__, __extension__, __inline__ and __typeof__ still work even with -ansi. You wouldn't want them in an ISO C program, of course, but they're super useful in header files that might get included in compilations done with -ansi ๐Ÿงš. Alternate predefined macros like __unix__ and __vax__ are available with or without -ansi ๐ŸŒˆ. -ansi doesn't reject non-ISO programs gratuitously. For that, you need -Wpedantic on top of -ansi. The macro __STRICT_ANSI__ is predefined when -ansi is used, and some header files notice it and skip declaring certain functions or defining certain macros that the ISO standard doesn't call for, so they don't interfere with programs using those names for other things ๐Ÿ’œ. Functions that are normally built in but don't have semantics defined by ISO C (like alloca and ffs) are not built-in functions when -ansi is used.
  • -std= โ€” Determines 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, and GNU dialects of those, like gnu90 or gnu++98. With a base standard, the compiler accepts all programs following that standard plus GNU extensions that don't contradict it. For example, -std=c90 turns off GCC features that are incompatible with ISO C90, like 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. With a GNU dialect, though, every feature the compiler supports is enabled, even when those features change the meaning of the base standard. So some strictly conforming programs may get rejected ๐Ÿ˜ญ. -Wpedantic uses the particular standard to figure out which features are GNU extensions for that version. 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. It's substantially completely supported, modulo bugs and floating-point issues (mainly but not entirely related to optional C99 features from Annexes F and G). See http://gcc.gnu.org/c99status.html for more info. The names c9x and iso9899:199x are deprecated ๐Ÿฅ€.
    • c11, c1x, iso9899:2011 โ€” ISO C11, the 2011 revision of the ISO C standard. It's substantially completely supported, modulo bugs, floating-point issues (mainly but not entirely related 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). It's 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. 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 โ€” GNU dialect of -std=c++17. This is the default for C++ code ๐Ÿ‘‘. The name gnu++1z is deprecated.
    • c++20, c++2a โ€” The 2020 ISO C++ standard plus amendments. Support is experimental and could change in incompatible ways in future releases. The name c++2a is deprecated ๐Ÿงช.
    • gnu++20, gnu++2a โ€” GNU dialect of -std=c++20. Support is experimental and could change in incompatible ways in future releases. The name gnu++2a is deprecated.
    • c++2b, c++23 โ€” The next revision of the ISO C++ standard, planned for 2023. Support is highly experimental and will almost certainly change in incompatible ways in future releases ๐Ÿ’€.
    • gnu++2b, gnu++23 โ€” GNU dialect of -std=c++2b. Support is highly experimental and will almost certainly change in incompatible ways in future releases.
  • -fgnu89-inline โ€” Tells GCC to use the traditional GNU semantics for inline functions when in C99 mode ๐Ÿฆ‹. Using this option is roughly equivalent to adding the gnu_inline function attribute to all inline functions. The option -fno-gnu89-inline explicitly tells GCC to use the C99 semantics for inline when in C99 or gnu99 mode (i.e., it specifies the default behavior). This option is not supported in -std=c90 or -std=gnu90 mode. The preprocessor 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 โ€” ISO/IEC TS 18661-3 defines new permissible values for FLT_EVAL_METHOD that indicate operations and constants with a semantic type that is an interchange or extended format should be evaluated to the precision and range of that type ๐Ÿ”ฅ. These new values are a superset of those permitted under C99/C11, which doesn't specify the meaning of other positive values of FLT_EVAL_METHOD. So code conforming to C11 may not have been written expecting the new values ๐Ÿ™ˆ. -fpermitted-flt-eval-methods specifies whether the compiler should allow only the values of FLT_EVAL_METHOD specified in C99/C11, or the extended set of values specified in ISO/IEC TS 18661-3. style is either c11 or ts-18661-3, as appropriate. The default when in a standards-compliant mode (-std=c11 or similar) is -fpermitted-flt-eval-methods=c11. The default when in a GNU dialect (-std=gnu11 or similar) is -fpermitted-flt-eval-methods=ts-18661-3.
  • -aux-info filename โ€” Outputs to the given filename prototyped declarations for all functions declared and/or defined in a translation unit, including those in header files ๐Ÿ“. This option is silently ignored in any language other than C. Besides declarations, the file indicates, in comments, the origin of each declaration (source file and line), whether the declaration was implicit, prototyped or unprototyped (I, N for new or O for old, respectively, in the first character after the line number and the colon), and whether it came from a declaration or a definition (C or F, respectively, in the following character). For function definitions, a K&R-style list of arguments followed by their declarations is also provided, inside comments, after the declaration.
  • -fallow-parameterless-variadic-functions โ€” Accepts variadic functions without named parameters ๐ŸŽ€. Although it's possible to define such a function, it's not very useful, because it's not possible to read the arguments. This is only supported for C, as this construct is allowed by C++.
  • -fno-asm โ€” okay so this one stops GCC from treating asm, inline or typeof as keywords ๐Ÿ™ˆ That way your code can use those words as regular identifiers. You can use __asm__, __inline__ and __typeof__ instead. -ansi implies -fno-asm.
    • In C++, this only affects the typeof keyword, since asm and inline are standard keywords there. Bestie tip from the manual: you may want -fno-gnu-keywords instead, which does the same thing.
    • In C99 mode (-std=c99 or -std=gnu99), this only affects asm and typeof, since inline is a standard keyword in ISO C99 ๐Ÿ’–
  • -fno-builtin, -fno-builtin-function โ€” Stop recognizing built-in functions whose names don't start with the __builtin_ prefix ๐Ÿฆ‹
    • GCC normally makes special code for certain built-ins so they run more efficiently. For example, alloca calls can turn into single instructions that adjust the stack directly, and memcpy calls can become inline copy loops โœจ
    • The result is often smaller and faster, but since those calls don't show up as calls anymore, you can't set a breakpoint on them. You also can't change what they do by linking with a different library ๐Ÿ˜ญ
    • Even when the code still contains calls, GCC may use what it knows about a built-in to warn you about problems or to generate better code. Like, warnings are given with -Wformat for bad calls to printf when printf is built in, and when strlen is known not to modify global memory ๐Ÿ”ฅ
    • With -fno-builtin-function, only that one built-in gets switched off. function must not begin with __builtin_. If the function you name isn't a built-in in this version of GCC, the option just gets ignored ๐ŸŒธ
    • There's no -fbuiltin-function counterpart. If you want to turn built-ins back on selectively while 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 โ€” Turns on parsing of function definitions marked with __GIMPLE. It's an experimental feature that lets you unit test GIMPLE passes ๐Ÿงช
  • -fhosted โ€” Asserts that compilation targets a hosted environment, which implies -fbuiltin. A hosted environment is one where the entire standard library is available and main has a return type of int. Basically everything except a kernel is hosted ๐Ÿ’…
    • This is equivalent to -fno-freestanding.
  • -ffreestanding โ€” Asserts that compilation targets a freestanding environment, which implies -fno-builtin. In a freestanding environment the standard library may not exist, and startup might not necessarily be at main. The most obvious example is an OS kernel ๐Ÿ‘‘
    • This is equivalent to -fno-hosted.
  • -fopenacc โ€” Turns on handling of OpenACC directives, #pragma acc in C/C++ and !$acc in Fortran ๐Ÿš€ With it, the compiler generates accelerated code following the OpenACC Application Programming Interface v2.6, https://www.openacc.org.
    • This option implies -pthread, so it's only supported on targets that have support for -pthread ๐Ÿซถ
  • -fopenacc-dim=geom โ€” Sets the 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 to use a target-specific default value ๐Ÿงš
  • -fopenmp โ€” Turns on handling of OpenMP directives, #pragma omp in C/C++ and !$omp in Fortran ๐Ÿ’œ With it on, the compiler generates parallel code following the OpenMP Application Program Interface v4.5, https://www.openmp.org.
    • This option implies -pthread, so it's only supported on targets that have support for -pthread.
    • -fopenmp implies -fopenmp-simd.
  • -fopenmp-simd โ€” Turns on handling of OpenMP's SIMD directives written as #pragma omp in C/C++ and !$omp in Fortran. Other OpenMP directives get 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 whose interface may change in future GCC versions as the official spec changes.
    • Not all architectures are supported for this feature, so check before you get too attached ๐Ÿ’€
    • For more information on GCC's support for transactional memory,
    • > Heads up: the transactional memory feature is not supported with non-call exceptions (-fnon-call-exceptions).
  • -fms-extensions โ€” Accepts some non-standard constructs used in Microsoft header files ๐ŸŽ€
    • In C++ code, this lets member names in structures be similar to previous type declarations. Iconic behavior, honestly:
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 permits passing pointers to structures with anonymous fields to functions that expect pointers to elements of the type of the field.
    • It also 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. Don't use this for new code, bestie ๐Ÿ˜ญ
  • -funsigned-char โ€” Lets the type char be unsigned, like unsigned char ๐ŸŒธ
    • Every 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 whenever it depends on the signedness of an object. But loads 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, let you make such a program work with the opposite default.
    • The type char is always a distinct type from each of signed char or unsigned char, even though its behavior 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, the option -fno-signed-char is equivalent to -funsigned-char.
  • -fsigned-bitfields, -funsigned-bitfields, -fno-signed-bitfields, -fno-unsigned-bitfields โ€” These control whether a bit-field is signed or unsigned when the declaration doesn't use either signed or unsigned ๐Ÿ”ฅ By default, such a bit-field is signed, because that's consistent: the basic integer types like int are signed types.
  • -fsso-struct=endianness โ€” Sets the default scalar storage order of structures and unions to the specified endianness ๐Ÿงš The accepted values are big-endian, little-endian and native for the native endianness of the target (the default). This option is not supported for C++.
    • > Warning: the -fsso-struct switch causes GCC to generate code that is not binary compatible with code generated without it if the specified endianness is not the native endianness of the target. Don't say I didn't warn you ๐Ÿ˜ญ

โœจ Options Controlling C++ Dialect ๐ŸŽ€

This section covers the command-line options that are only meaningful for C++ programs ๐Ÿ’œ You can also use most of the GNU compiler options no matter what language your program is in. For example, you might compile a file firstClass.C like this:

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

In this example, only -fstrict-enums is an option meant only for C++ programs. You can use the other options with any language GCC supports ๐ŸŒˆ

Some options for compiling C programs, such as -std, are also relevant for C++ programs โœจ

Here's the list of options that are only for compiling C++ programs:

  • -fabi-version=n โ€” Uses version n of the C++ ABI. The default is version 0 ๐Ÿฆ‹
    • Version 0 refers to the version conforming most closely to the C++ ABI specification. That means the ABI you get with version 0 will change across different versions of G++ as ABI bugs get fixed ๐Ÿ™ˆ
    • Version 1 is the version of the C++ ABI that first appeared in G++ 3.2.
    • Version 2 is the version that first appeared in G++ 3.4, and it was the default through G++ 4.9 ๐Ÿ‘‘
    • Version 3 corrects an error in mangling a constant address as a template argument.
    • Version 4, which first appeared in G++ 4.5, implements a standard mangling for vector types.
    • Version 5, which first appeared in G++ 4.6, corrects the mangling of attribute const/volatile on function pointer types, decltype of a plain decl, and use of a function parameter in the declaration of another parameter.
    • Version 6, which first appeared in G++ 4.7, corrects 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 corrects the mangling of lambdas in default argument scope.
    • Version 8, which first appeared in G++ 4.9, corrects the substitution behavior of function types with function-cv-qualifiers.
    • Version 9, which first appeared in G++ 5.2, corrects the alignment of nullptr_t.
    • Version 10, which first appeared in G++ 6.1, adds mangling of attributes that affect type identity, such as ia32 calling convention attributes (e.g. stdcall) ๐Ÿ’…

Version 11 first showed up in G++ 7 and fixed 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 first appeared in G++ 8 and corrected the calling conventions for empty classes on the x86_64 target, plus 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, so ngl, that's a little oops ๐Ÿ™ˆ.

Version 13 first appeared in G++ 8.2 and fixes that accidental change from version 12 ๐Ÿซถ.

Version 14 first appeared in G++ 10 and corrects the mangling of the nullptr expression โœจ.

Version 15 first appeared in G++ 11 and changes the mangling of "__alignof__" so it's distinct from "alignof", plus dependent operator names ๐Ÿ‘‘.

See also -Wabi ๐Ÿ’–.

  • -fabi-compat-version=n โ€” okay so, 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 mangled name ๐Ÿงš. This switch picks which ABI version gets used for that alias. With -fabi-version=0 (the default), it defaults to 11 (GCC 7 compatibility). If you explicitly select another ABI version, it defaults to 0. For compatibility with GCC versions 3.2 through 4.9, use -fabi-compat-version=2 ๐ŸŽ€. If you don't provide this option but do provide -Wabi=n, that version is used for the compatibility aliases. If you provide this option along with -Wabi (without a version), the version from this option is used for the warning ๐Ÿ’œ.
  • -fno-access-control โ€” turns off all access checking ๐Ÿ™…โ€โ™€๏ธ. It's mainly useful for working around bugs in the access control code, so it's a bit of a last-resort vibe ๐Ÿ’€.
  • -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 numeric argument like -faligned-new=32 to specify how much alignment (in bytes) that function provides, but few users will ever need to override the default of alignof(std::max_align_t). This flag is enabled by default for -std=c++17 โญ.
  • -fchar8_t, -fno-char8_t โ€” enables char8_t as adopted for C++20 ๐Ÿ˜ญ. This includes the addition of 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 functions get overloaded for ordinary and UTF-8 strings, and it's giving main character energy:

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 bestie: the change to the types of UTF-8 string and character literals introduces incompatibilities with ISO C++11 and later standards ๐Ÿ˜ฌ. For example, the following code is well-formed 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 it tries 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 gets signalled by throwing "std::bad_alloc". See also new (nothrow) ๐Ÿซง.
  • -fconcepts, -fconcepts-ts โ€” below -std=c++20, -fconcepts enables support for the C++ Extensions for Concepts Technical Specification, ISO 19217 (2015) ๐Ÿ“œ. With -std=c++20 and above, Concepts are part of the language standard, so -fconcepts defaults to on. But the standard specification of Concepts differs significantly from the TS, so some constructs that were allowed in the TS but didn't make it into the standard can still be enabled by -fconcepts-ts ๐Ÿ“.
  • -fconstexpr-depth=n โ€” sets the maximum nested evaluation depth for C++11 constexpr functions to n ๐ŸŒ™. A limit is needed to detect endless recursion during constant expression evaluation. The minimum the standard specifies is 512.
  • -fconstexpr-cache-depth=n โ€” sets the maximum level of nested evaluation depth for C++11 constexpr functions that will be cached to n ๐Ÿง . This is a heuristic that trades compilation speed (when the cache avoids repeated calculations) against memory consumption (when the cache grows huge from highly recursive evaluations). The default is 8. Very few users will want to adjust it, but if your code does heavy constexpr calculations, you might wanna experiment to find which value works best for you ๐Ÿ’….
  • -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 detect 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 limited by the limit above, if there are several nested loops that each have lots of iterations (still under that limit), or if a loop body or code outside any loop needs too many expressions evaluated, the constexpr evaluation might take too long. The default is 33554432 (1<<25).
  • -fcoroutines โ€” enables support for the C++ coroutines extension ๐Ÿงช. It's experimental, so handle with care ๐Ÿฅน.
  • -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 disables that optimization 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 these temporaries, but this option still affects trivial member functions.
  • -fno-enforce-eh-specs โ€” don't generate code that checks for violations of exception specifications at run time ๐Ÿšซ. This option violates the C++ standard, but it may be useful for reducing code size in production builds, much like defining "NDEBUG". It does not give user code permission to throw exceptions in violation of the exception specifications. The compiler still optimizes based on the specifications, so throwing an unexpected exception results in undefined behavior at run time ๐Ÿ’€.
  • -fextern-tls-init, -fno-extern-tls-init โ€” the C++11 and OpenMP standards allow "thread_local" and "threadprivate" variables to have dynamic (runtime) initialization ๐Ÿงต. To support that, any use of such a variable goes through a wrapper function that does the necessary initialization. When the use and definition are in the same translation unit, this overhead can be optimized away. But when the use is in a different translation unit, there's significant overhead even if the variable doesn't actually need dynamic initialization. If the programmer can be sure that no use of the variable in a non-defining TU needs to trigger dynamic initialization (either because the variable is statically initialized, or because a use in the defining TU will be executed before any uses in another TU), they can avoid this overhead with the -fno-extern-tls-init option ๐Ÿฆ‹.

On targets that support symbol aliases, the default is -fextern-tls-init. On targets that don't support symbol aliases, the default is -fno-extern-tls-init โœจ.

  • -fno-gnu-keywords โ€” don't recognize typeof as a keyword, so code can use that word as an identifier ๐Ÿ™Œ. You can use the keyword __typeof__ instead. This option is implied by the strict ISO C++ dialects: -ansi, -std=c++98, -std=c++11, etc.
  • -fno-implicit-templates โ€” never emit code for non-inline templates that are instantiated implicitly (i.e. by use). Only emit code for explicit instantiations ๐Ÿ“ฆ. If you use this option, you must take care to structure your code so it includes all the necessary explicit instantiations, or you'll end up with undefined symbols at link time ๐Ÿ˜ต.
  • -fno-implicit-inline-templates โ€” don't emit code for implicit instantiations of inline templates either ๐ŸŒท. The default handles inlines differently so that compiles with and without optimization need the same set of explicit instantiations.
  • -fno-implement-inlines โ€” to save space, don't emit out-of-line copies of inline functions controlled by "#pragma implementation" ๐Ÿงน. This causes linker errors if these functions aren't inlined everywhere they're called.
  • -fmodules-ts, -fno-modules-ts โ€” enables support for C++20 modules ๐Ÿงฉ. The -fno-modules-ts option is usually not needed, since that's the default. Even though this is a C++20 feature, it's not currently implicitly enabled by selecting that standard version ๐Ÿ™ˆ.
  • -fmodule-header, -fmodule-header=user, -fmodule-header=system โ€” โœจ okay so this one compiles a header file so it can be imported as a header unit ๐ŸŽ€
  • -fmodule-implicit-inline โ€” ๐Ÿ™ˆ this one is lowkey a plot twist. Member functions defined right inside their class are not implicitly inline for modular code. That's different from traditional C++ behavior, and there are good reasons for it, but it can be a pain when you're porting code. This flag makes those definitions implicitly inline instead.
ABI warning ๐Ÿ’€ this generates an ABI incompatibility, so you have to use it everywhere or nowhere. Definitions outside of a named module stay implicitly inline either way.
  • -fno-module-lazy โ€” ๐ŸŒธ disables lazy module importing and module mapper creation
  • -fmodule-mapper family โ€” ๐Ÿ”ฎ this is the oracle you query for module name to filename mappings. If you don't specify one, the CXX_MODULE_MAPPER environment variable gets used, and if that's unset too, you get an in-process default. The six forms are:
    • -fmodule-mapper=[hostname]:port[?ident]
    • -fmodule-mapper=|program[?ident] args...
    • -fmodule-mapper==socket[?ident]
    • -fmodule-mapper=<>[inout][?ident]
    • -fmodule-mapper=<in>out[?ident]
    • -fmodule-mapper=file[?ident]
  • -fmodule-only โ€” ๐Ÿ“ only emits the Compiled Module Interface and skips the object file
  • -fms-extensions โ€” ๐Ÿ’… turns off Wpedantic warnings for MFC-style stuff, like implicit int and getting a pointer to a member function with non-standard syntax
  • -fnew-inheriting-ctors โ€” โœจ enables the P0136 tweak to how C++11 constructor inheritance works. It's part of C++17 but also counts as a Defect Report against C++11 and C++14, so it's giving main character energy. This flag is on by default unless -fabi-version=10 or lower is specified.
  • -fnew-ttp-matching โ€” ๐Ÿฆ‹ enables the P0522 resolution to Core issue 150. 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 ANSI/ISO C doesn't mandate, like "ffs", "alloca", "_exit", "index", "bzero", "conjf", and other related functions
  • -fnothrow-opt โ€” ๐Ÿ‘‘ treats a throw() exception specification as if it were "noexcept", which cuts down or erases 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 get optimized away.
Semantic change ๐Ÿ™ˆ an exception thrown out of a function with this exception specification results in a call to "terminate" rather than "unexpected".
  • -fno-operator-names โ€” ๐Ÿšซ stops and, bitand, bitor, compl, not, or, and xor from being treated as synonyms for the operator name keywords
  • -fno-optional-diags โ€” ๐Ÿคซ disables diagnostics the standard says a compiler doesn't have to issue. Right now, the only one G++ issues in this category is the one for a name having multiple meanings within a class.
  • -fpermissive โ€” ๐ŸŽ€ downgrades some diagnostics about nonconformant code from errors to warnings, so some nonconforming code can still compile
  • -fno-pretty-templates โ€” ๐Ÿงš when an error message points at a specialization of a function template, the compiler normally prints the template signature followed by the template arguments and any typedefs or typenames in it (so you get void f(T) [with T = int] instead of void f(int)) so you can tell which template is involved. For a specialization of a class template, it leaves out any template arguments that match the defaults. If either of those behaviors makes the error harder to read, use -fno-pretty-templates to turn them off.
  • -fno-rtti โ€” ๐Ÿ’œ disables generating the information about every class with virtual functions that the C++ run-time type identification features (dynamic_cast and typeid) use. If you don't use those parts of the language, this can save some space. Exception handling uses the same information, but G++ generates it only as needed. The dynamic_cast operator still works for casts that don't need run-time type information, meaning casts to void * or to unambiguous base classes.
Mixing warning โš ๏ธ 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 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 use the object's size to make deallocation faster. It's enabled by default under -std=c++14 and above. The -Wsized-deallocation flag 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 (per the C++ standard, basically 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 convert an arbitrary integer into the enumerated type.
  • -fstrong-eval-order โ€” ๐ŸŒˆ evaluates member access, array subscripting, and shift expressions left-to-right, and assignment right-to-left, as adopted for C++17. It's enabled by default with -std=c++17. -fstrong-eval-order=some only enables the ordering for 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 for a single warning or error to n. The default 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 (changed to 1024 in C++11). The default is 900, because the compiler can run out of stack space before hitting 1024 in some situations.
  • -fno-threadsafe-statics โ€” ๐Ÿงต skips emitting the extra code that uses the routines from the C++ ABI for thread-safe initialization of local statics. It can shave off a bit of code size in 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 atexit. This 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 โ€” ๐Ÿ™…โ€โ™€๏ธ stops using 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 GCC 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 they're used inside the DSO. Turning this on can have a dramatic effect on load and link times of a DSO, because it massively shrinks the dynamic export table when the library leans heavily on 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 explicitly give a method a 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, because their linkage might otherwise cross a shared library boundary. ๐Ÿซถ

โœจ -fvisibility-ms-compat โœจ

This flag tries to use visibility settings to make GCC's C++ linkage model compatible with Microsoft Visual Studio's. ๐Ÿ’œ

It makes these changes to GCC's linkage model:

  1. It sets the default visibility to "hidden", like -fvisibility=hidden.
  2. Types, but not their members, are not hidden by default.
  3. The One Definition Rule is relaxed for types without explicit visibility specifications that are defined in more than one shared object. Those declarations are permitted if they're permitted when this option isn't used.

In new code, it's better to use -fvisibility=hidden and export only the classes that are meant to be externally visible. ๐Ÿง Unfortunately, code might rely (perhaps accidentally) on the Visual Studio behavior.

ODR danger ๐Ÿ’€ among the consequences: static data members of the same type, with the same name, defined in different shared objects are different, so changing one doesn't change the other. Pointers to function members defined in different shared objects may also not compare equal. When this flag is given, it's a violation of the ODR to define types with the same name differently.
  • -fno-weak โ€” ๐Ÿ™ƒ doesn't use weak symbol support, even if the linker provides it. By default, G++ uses weak symbols when they're available. This option exists only for testing and shouldn't be used by end-users, since it results in inferior code and has no benefits. It may be removed in a future release of G++.
  • -fext-numeric-literals (C++ and Objective-C++ only) โ€” okay so this one lets you use imaginary, fixed-point, or machine-defined literal number suffixes as GNU extensions ๐Ÿ’… Turn it off and those suffixes get treated as C++11 user-defined literal numeric suffixes instead ๐Ÿซถ It's on by default for all the pre-C++11 dialects and all the 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, ...) ๐ŸŒธ
  • -nostdinc++ โ€” this one tells GCC to skip the standard directories that are specific to C++ when it's looking for headers, but it still searches the other standard directories โœจ It's the flag used when building the C++ library, so you know it's serious ๐Ÿงš

  • -flang-info-include-translate, -flang-info-include-translate-not, -flang-info-include-translate=header โ€” these are the "tell me everything you did" flags ๐Ÿฆ‹ The first one informs you of accepted include translation events, and the second one spills the declined ones. The header form only gives you the include translation info for that specific header. If header is "user" or "<system>", it gets resolved to a specific user or system header using the include path ๐Ÿ”
  • -flang-info-module-cmi, -flang-info-module-cmi=module โ€” main character energy for Compiled Module Interface pathnames ๐Ÿ‘‘ The first one notes all the CMI pathnames that get read. The module form is for a specific module's CMI. module can be a named module or a header-unit, and you can tell it's a header-unit if it's a pathname containing directory separators or it's wrapped in <> or "" ๐Ÿ’œ
  • -stdlib=libstdc++,libc++ โ€” when G++ is configured to support this option, you can pick an alternate C++ runtime library ๐Ÿ”ฅ There are two choices: libstdc++ (the default, native C++ runtime for G++) and libc++, which is the C++ runtime installed on some operating systems (e.g. Darwin versions from Darwin11 onwards) ๐ŸŽ Picking one switches G++ over to the headers from that library, and it'll emit -lstdc++ or -lc++ respectively when a C++ runtime is needed for linking. Iconic โœจ

In addition, these warning options only have meanings for C++ programs, so they're giving very specific vibes ๐Ÿ’…

  • -Wabi-tag (C++ and Objective-C++ only) โ€” warns you when a type with an ABI tag gets used somewhere that doesn't have that ABI tag ๐Ÿท๏ธ Check out C++ Attributes for more info about ABI tags.
  • -Wcomma-subscript (C++ and Objective-C++ only) โ€” warns about comma expressions inside a subscripting expression ๐Ÿ™ˆ This usage got deprecated in C++20, but a comma expression wrapped in ( ) is not deprecated, so you're safe there ๐Ÿซถ Here's the example:
void f(int *a, int b, int c) {
    a[b,c];     // deprecated
    a[(b,c)];   // OK
}

This one is enabled by default with -std=c++20 ๐ŸŒˆ

  • -Wctad-maybe-unsupported (C++ and Objective-C++ only) โ€” warns you when you do class template argument deduction (CTAD) on a type that doesn't have any explicitly written deduction guides ๐Ÿง This is the one that points out when CTAD only worked because the compiler made up the implicit deduction guides, which might not be what the programmer actually meant. Some style guides only allow CTAD on types that specifically "opt-in" (aka types that are designed to support CTAD), so this warning helps with that. You can suppress it with this pattern (any name works for the tag, btw):
struct allow_ctad_t; // any name works
template <typename T> struct S {
  S(T) { }
};
S(allow_ctad_t) -> S<void>; // guide with incomplete parameter type will never be considered
  • -Wctor-dtor-privacy (C++ and Objective-C++ only) โ€” warns when a class seems unusable because all of its constructors or destructors are private, and it has no friends and no 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) โ€” warns 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, so please listen to this one. This warning is enabled by -Wall ๐Ÿ”ฅ
  • -Wdeprecated-copy (C++ and Objective-C++ only) โ€” warns 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'll also deprecate if the class has a user-provided destructor.
  • -Wno-deprecated-enum-enum-conversion (C++ and Objective-C++ only) โ€” disables the warning about when the usual arithmetic conversions get applied to operands where one is an enumeration type and the other is a different enumeration type ๐Ÿ™…โ€โ™€๏ธ This conversion was deprecated in C++20. For example:
enum E1 { e };
enum E2 { f };
int k = f - e;

-Wdeprecated-enum-enum-conversion is enabled by default with -std=c++20. In pre-C++20 dialects, you can turn this warning on with -Wenum-conversion ๐ŸŒธ

  • -Wno-deprecated-enum-float-conversion (C++ and Objective-C++ only) โ€” disables the warning for when the usual arithmetic conversions get applied to operands where one is an enumeration type and the other is a floating-point type ๐Ÿซ  This conversion was deprecated in C++20. For example:
enum E1 { e };
enum E2 { f };
bool b = e <= 3.7;

-Wdeprecated-enum-float-conversion is enabled by default with -std=c++20. In pre-C++20 dialects, you can enable this warning with -Wenum-conversion ๐ŸŽ€

  • -Wno-init-list-lifetime (C++ and Objective-C++ only) โ€” this one turns off warnings about uses of std::initializer_list that are likely to end up with 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. Some examples of how this happens:
    • 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.
    • When a list constructor stores the begin pointer from the initializer_list argument, that 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.

Here's the code for the assignment one:

// 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
โš ๏ธ That last line is undefined behavior, bestie. Don't let your initializer_list go past its lifetime ๐Ÿ’€
  • -Winvalid-imported-macros โ€” verifies that all imported macro definitions are valid at the end of compilation ๐Ÿ” This one is not enabled by default, because it needs additional processing to figure that out. It may be useful when you're preparing sets of header-units to make sure the macros are consistent ๐Ÿงš
  • -Wno-literal-suffix (C++ and Objective-C++ only) โ€” doesn't 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 these suffixes as separate preprocessing tokens so that old code using formatting macros from <inttypes.h> keeps working. Like this:
#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 ๐Ÿฆ‹

This option also controls warnings 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 these warnings are enabled by default โš ๏ธ

  • -Wno-narrowing (C++ and Objective-C++ only) โ€” for C++11 and later standards, narrowing conversions are diagnosed by default, as the standard requires ๐Ÿ“ A narrowing conversion from a constant gives you an error, and a narrowing conversion from a non-constant gives you a warning. -Wno-narrowing suppresses that diagnostic. Heads up: this doesn't change the meaning of well-formed code, since narrowing conversions are still considered ill-formed in SFINAE contexts ๐Ÿ™…โ€โ™€๏ธ

With -Wnarrowing in C++98, you get a warning when a narrowing conversion that C++11 prohibits happens within { }, e.g.:

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) โ€” warns when a noexcept-expression evaluates to false because of a call to a function that doesn't have a non-throwing exception specification (i.e. throw() or "noexcept"), but the compiler knows it never throws an exception ๐Ÿค”
  • -Wnoexcept-type (C++ and Objective-C++ only) โ€” warns if the C++17 feature that makes noexcept part of a function type changes the mangled name of a symbol compared to C++14 ๐Ÿงฌ This one is enabled by -Wabi and -Wc++17-compat. Here's an example:
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) โ€” okay bestie, this one is ALARM ๐Ÿšจ It warns when you hand a raw memory function like memset or memcpy a class-type object as its destination, and writing into it could bypass 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 the class's member functions are supposed to keep ๐Ÿ™ˆ For example, the memset call below is undefined because it modifies a non-trivial class object, so it gets diagnosed ๐Ÿ’€
std::string str = "abc";
memset (&str, 0, sizeof str);

The slay way to initialize or clear the storage of these objects is to use the appropriate constructor or assignment operator, if one is available ๐Ÿ’– The -Wclass-memaccess option is enabled by -Wall. Casting the pointer to the class object to void *, or to a type that the raw memory function can safely access, suppresses the warning ๐ŸŽ€

  • -Wnon-virtual-dtor (C++ and Objective-C++ only) โ€” warns when a class has virtual functions and an accessible non-virtual destructor, either on itself or in an accessible polymorphic base class. That makes it possible, but unsafe, to delete a derived-class instance through a pointer to the class or base class ๐Ÿ˜ฌ This warning is automatically enabled if -Weffc++ is specified ๐Ÿฆ‹
  • -Wregister (C++ and Objective-C++ only) โ€” warns on uses of the register storage class specifier, except when it's part of the GNU Explicit Register Variables extension. Using register as a storage class specifier was 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 the code doesn't match the order they actually have to run in. For instance:
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 of the members, and emits a warning to that effect ๐Ÿงš This warning is enabled by -Wall.

  • -Wno-pessimizing-move (C++ and Objective-C++ only) โ€” this one warns when a call to std::move prevents copy elision ๐Ÿ™…โ€โ™€๏ธ The classic situation where copy elision can happen is returning from a function with a class return type, when the returned expression is the name of a non-volatile automatic object that isn't a function parameter and has the same type as the function's return type. Here's the vibe:
struct T {
...
};
T fn()
{
  T t;
  ...
  return std::move (t);
}

But in this example, the std::move call prevents copy elision ๐Ÿ˜ญ This warning is enabled by -Wall.

  • -Wno-redundant-move (C++ and Objective-C++ only) โ€” this one warns about redundant calls to std::move, which means cases where a move operation would have happened even without the std::move call ๐ŸŒธ That's because the compiler is forced to treat the object as if it were 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, another example is:

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's return type differ. Even so, G++ treats the return value as if it were designated by an rvalue, which is the main character plot twist ๐Ÿ‘‘ This warning is enabled by -Wextra.

  • -Wrange-loop-construct (C++ and Objective-C++ only) โ€” this one warns when a C++ range-based for loop is making an unnecessary copy ๐Ÿ“ That can happen when the range declaration isn't a reference, but honestly it probably should be. For example:
struct S { char arr[128]; };
void fn () {
  S arr[5];
  for (const auto x : arr) { ... }
}

It does not warn when the type being copied is a trivially-copyable type whose size is less than 64 bytes.

This warning also fires when a loop variable in a range-based for-loop is initialized with a value of a different type, which causes a copy. For example:

void fn() {
  int arr[10];
  for (const double &x : arr) { ... }
}

In the example above, every iteration creates and destroys a temporary value of type double, and the reference const double & is bound to that temporary ๐Ÿฅฒ This warning is enabled by -Wall.

  • -Wredundant-tags (C++ and Objective-C++ only) โ€” warns about redundant class-key and enum-key in references to class types and enumerated types, in contexts where the key can be dropped without causing an ambiguity. For example:
struct foo;
struct foo *p;   // warn that keyword struct can be eliminated

On the other hand, there's no warning in this example, because the keyword is actually needed there ๐Ÿ™ˆ

struct foo;
void foo ();   // "hides" struct foo
void bar (struct foo&);  // no warning, keyword struct is necessary
  • -Wno-subobject-linkage (C++ and Objective-C++ only) โ€” don't warn 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 linkage 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 too. 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 ๐Ÿ’œ
  • -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, bestie ๐Ÿงน

  • -Wno-exceptions (C++ and Objective-C++ only) โ€” disables the warning for when an exception handler is shadowed by another handler, which can point out a wrong ordering of exception handlers ๐Ÿ™ƒ
  • -Wstrict-null-sentinel (C++ and Objective-C++ only) โ€” warns about using an uncasted NULL as a sentinel. When compiling only with GCC, this is a valid sentinel, because NULL is defined to __null. Although it's a null pointer constant rather than a null pointer, it's guaranteed to be the same size as a pointer. But this use isn't portable across different compilers, so watch out ๐Ÿ‘
  • -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 implementation, declarations such as friend int foo(int), where the name of the friend is an unqualified-id, could be interpreted as a particular specialization of a template function. The 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 ๐Ÿ”
  • -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 picks a promotion from an unsigned or enumerated type to a signed type, over a conversion to an unsigned type of the same size. Previous 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, and this can be used to enforce that rule ๐Ÿšซ The warning is inactive inside a system header file, such as the STL, so you can still use the STL ๐Ÿซง You're also allowed to instantiate or specialize templates.
  • -Wno-mismatched-new-delete (C++ and Objective-C++ only) โ€” okay bestie, this one is all about catching mix-ups between operator new and operator delete ๐Ÿงš. It warns when those calls don't match the allocation or deallocation function they go with. That includes C++ operator delete getting a pointer from a mismatched form of operator new, or from some other function that allocates objects operator delete isn't a suitable deallocator for. It also flags other deallocation functions handed a pointer from operator new when they aren't the right match ๐Ÿ’….

For example, the delete expression in the function below gets flagged because it doesn't match the array form of the new expression the pointer came from. The free call gets flagged too ๐Ÿซถ.

void f ()
{
  int *a = new int[n];
  delete a;   // warning: mismatch in array forms of expressions

  char *p = new char[n];
  free (p);   // warning: mismatch between new and free
}

The related option -Wmismatched-dealloc handles mismatches involving allocation and deallocation functions other than operator new and operator delete ๐ŸŒธ.

-Wmismatched-new-delete is enabled by default โœจ.

  • -Wmismatched-tags (C++ and Objective-C++ only) โ€” this one warns when a struct, class, or class template (or one of its specializations) gets declared with a class-key that doesn't match its definition, or its first declaration if there's no definition yet ๐ŸŽ€. Keeping the vibes consistent, bestie.

In the example below, the declaration of struct Object in the argument list of draw triggers the warning. To avoid it, either remove the redundant class-key struct or swap it for class to match the definition.

class Object {
public:
  virtual ~Object () = 0;
};
void draw (struct Object*);

It's not wrong to declare a class with the class-key struct, as shown above. -Wmismatched-tags just exists to help you achieve a consistent style of class declarations ๐Ÿ’…. In code meant to be portable to Windows-based compilers, the warning also helps prevent unresolved references caused by the difference in the mangling of symbols declared with different class-keys ๐Ÿ”ฅ. The option can be used on its own or together with -Wredundant-tags.

  • -Wmultiple-inheritance (C++ and Objective-C++ only) โ€” warns when a class is defined with multiple direct base classes ๐Ÿฆ‹. Some coding rules ban multiple inheritance, so this helps enforce that rule. The warning is inactive inside a system header file, like the STL, so you can still use the STL ๐Ÿ’–. You're also allowed to define classes that indirectly use multiple inheritance.
  • -Wvirtual-inheritance โ€” warns when a class is defined with a virtual direct base class ๐ŸŒˆ. Same deal as above: 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 the STL is still good to go โœจ. You can also define classes that indirectly use virtual inheritance.
  • -Wno-virtual-move-assign โ€” suppresses warnings about inheriting from a virtual base with a non-trivial C++11 move assignment operator ๐Ÿ™ˆ.
Heads up, bestie: this is dangerous ๐Ÿ’€. If the virtual base can be reached 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, though, this warning can be disabled safely ๐Ÿซถ.
  • -Wnamespaces โ€” warns when a namespace definition is opened ๐ŸŒธ. Some coding rules disallow namespaces, so this helps enforce that. It's inactive inside system header files like the STL, so the STL keeps working. You can still use using directives and qualified names, too ๐Ÿงš.
  • -Wno-terminate (C++ and Objective-C++ only) โ€” disables the warning about a throw-expression that will immediately result in a call to terminate ๐Ÿ’….
  • -Wno-vexing-parse (C++ and Objective-C++ only) โ€” warns about the most vexing parse syntactic ambiguity ๐Ÿคฏ. This is when a declaration looks like a variable definition, but C++ requires it to be read as a function declaration. For instance:
void f(double a) {
  int i();        // extern int i (void);
  int n(int(a));  // extern int n (int);
}

Another example:

struct S { S(int); };
void f(double a) {
  S x(int(a));   // extern struct S x (int);
  S y(int());    // extern struct S y (int (*) (void));
  S z();         // extern struct S z (void);
}

The warning suggests ways to deal with the ambiguity, like removing the parentheses or using braces instead ๐Ÿ’–. This warning is enabled by default โœจ.

  • -Wno-class-conversion (C++ and Objective-C++ only) โ€” don't warn when a conversion function converts an object to the same type, to a base class of that type, or to void ๐Ÿฆ‹. Such a conversion function will never be called, so this is one for the "I know what I'm doing" crowd ๐Ÿ’….
  • -Wvolatile (C++ and Objective-C++ only) โ€” warns about deprecated uses of the volatile qualifier ๐Ÿ”ฅ. That includes postfix and prefix ++ and -- expressions of volatile-qualified types, simple assignments where the left operand is a volatile-qualified non-class type (for their value), compound assignments where the left operand is a volatile-qualified non-class type, volatile-qualified function return types, volatile-qualified parameter types, and structured bindings of a volatile-qualified type. This usage was deprecated in C++20 ๐Ÿ™ˆ.

Enabled by default with -std=c++20 โœจ.

  • -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 helpful when you're converting over to nullptr in C++11 ๐Ÿ’–.
  • -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 option is enabled by -Wall โœจ.

Normally this only warns about global allocation functions, but -Waligned-new=all also warns about class member allocation functions ๐Ÿงš.

  • -Wno-placement-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, the placement new expression below 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 of -Wplacement-new ๐ŸŒธ. At this level, the warning isn't issued for some strictly undefined constructs that GCC allows as extensions for compatibility with legacy code. For example, the new expression below isn't diagnosed at this level, even though it has 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, GCC diagnoses all the same constructs as level 1, plus placement new expressions that construct an object in the last member of a structure whose type is an array of a single element, when that size is less than the size of the object being constructed ๐Ÿ”ฅ. The previous example gets diagnosed at this level. The construct below 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]();
  • -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 just -Wcatch-value), it warns about polymorphic class types that are caught by value. With -Wcatch-value=2, it warns about all class types caught by value. With -Wcatch-value=3, it warns about all types that aren't caught by reference ๐Ÿ‘‘. -Wcatch-value is enabled by -Wall โœจ.
  • -Wconditionally-supported (C++ and Objective-C++ only) โ€” warns for conditionally-supported constructs (C++11 [intro.defs]) ๐ŸŒˆ.
  • -Wno-delete-incomplete (C++ and Objective-C++ only) โ€” don't warn when deleting a pointer to an incomplete type, which may cause undefined behavior at runtime ๐Ÿ’€. This warning is enabled by default, so this option is how you turn it off ๐Ÿ™ˆ.
  • -Wextra-semi (C++, Objective-C++ only) โ€” warns about redundant semicolons after in-class function definitions ๐Ÿงš.
  • -Wno-inaccessible-base (C++, Objective-C++ only) โ€” this option controls warnings when a base class is inaccessible in a class derived from it because of ambiguity ๐ŸŒธ. The warning is enabled by default. Note that the warning for ambiguous virtual bases is enabled by the -Wextra option. Here's the ambiguity in action:
struct A { int a; };

struct B : A { };

struct C : B, A { };
  • -Wno-inherited-variadic-ctor โ€” suppresses warnings about using C++11 inheriting constructors when the base class being inherited from has a C variadic constructor ๐Ÿ’…. The warning is on by default because the ellipsis is not inherited ๐ŸŽ€.
  • -Wno-invalid-offsetof (C++ and Objective-C++ only) โ€” suppresses warnings from applying the offsetof macro to a non-POD type ๐Ÿ™ˆ. According to the 2014 ISO C++ standard, applying offsetof to a non-standard-layout type is undefined. In existing C++ implementations, though, offsetof typically gives meaningful results. This flag is for users who know they're writing nonportable code and have deliberately chosen to ignore the warning ๐Ÿ’–.

The restrictions on offsetof may be relaxed in a future version of the C++ standard ๐ŸŒˆ.

  • -Wsized-deallocation (C++ and Objective-C++ only) โ€” warns about a definition of an unsized deallocation function ๐Ÿฆ‹.

Okay so this is where the warning list gets spicy ๐ŸŒถ๏ธ GCC is watching for a class that defines one of these deallocators:

void operator delete (void *) noexcept;
void operator delete[] (void *) noexcept;

...but doesn't define the matching sized one:

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

...or the other way around, bestie ๐Ÿ’€ It's enabled by -Wextra along with -fsized-deallocation ๐Ÿงš


  • -Wsuggest-final-types โ€” Okay, this one's for types with virtual methods that would look cleaner marked with the C++11 "final" specifier. If it's possible, it'll also suggest putting the type in an anonymous namespace instead ๐Ÿฆ‹ Doing that lets GCC devirtualize polymorphic calls way more aggressively, which is so big brain of it ๐Ÿง  This warning hits harder with link-time optimization, since GCC has a fuller picture of the class hierarchy then โœจ
  • -Wsuggest-final-methods โ€” Same energy, but for individual virtual methods ๐Ÿ’… It'll nudge you to mark a method "final", or, if it's possible, put its type in an anonymous namespace or give it the "final" specifier. Also works better with link-time optimization for the same reason, since the class hierarchy graph is more complete there ๐ŸŒˆ Pro tip (from the manual, not me ๐Ÿ™ˆ): look at -Wsuggest-final-types suggestions first, then rebuild with the new annotations.
  • -Wsuggest-override โ€” Warns when you override a virtual function without slapping the "override" keyword on it ๐Ÿซถ No more sneaky overrides, periodt ๐Ÿ’–
  • -Wuseless-cast (C++ and Objective-C++ only) โ€” Warns when an expression gets cast to its own type. Literally pointless, so GCC will call it out ๐Ÿ’€
  • -Wno-conversion-null (C++ and Objective-C++ only) โ€” Turns off the warning for conversions between "NULL" and non-pointer types. Heads up, -Wconversion-null is on by default ๐Ÿ‘‘

๐Ÿฆ‹ Options Controlling Objective-C and Objective-C++ Dialects ๐Ÿฆ‹

NOTE: This manual doesn't cover the Objective-C and Objective-C++ languages themselves, okay? This section is just about the command-line options that only matter for Objective-C and Objective-C++ programs. You can still use most of the language-independent GNU compiler options too ๐Ÿ’œ For example, compiling a file called some_class.m might look like this:

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

In that example, -fgnu-runtime is a flag meant only for Objective-C and Objective-C++ programs, but you can use the other options with any language GCC supports ๐ŸŒธ

Since Objective-C is an extension of C, Objective-C compiles can also use C front-end options (like -Wtraditional). Similarly, Objective-C++ compiles can use C++-specific options (like -Wabi) ๐ŸŽ€

Here's the list of options that are only for compiling Objective-C and Objective-C++ programs ๐Ÿ‘‡

  • -fconstant-string-class=class-name โ€” Picks the class that gets instantiated for every literal string written as "@"..."" ๐Ÿ“ The default is "NXConstantString" when the GNU runtime is in use, and "NSConstantString" when the NeXT runtime is in use (more on that below). On Darwin (macOS, MacOS X), if -fconstant-cfstrings is also there, it overrides -fconstant-string-class and makes "@"..."" literals get laid out as constant CoreFoundation strings โœจ Also, -fconstant-cfstrings is just an alias for the target-specific -mconstant-cfstrings equivalent.
  • -fgnu-runtime โ€” Generates object code that works with the standard GNU Objective-C runtime ๐ŸŒˆ This is the default for most 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 isn't nil ๐Ÿซง That lets the runtime use more efficient entry points. This is only available with the NeXT runtime and ABI version 0 or 1.
  • -fobjc-abi-version=n โ€” Uses version n of the Objective-C ABI for the runtime you picked. Right now this is only supported for the NeXT runtime, where:
    • Version 0 is the traditional (32-bit) ABI, no properties or other Objective-C 2.0 extras ๐Ÿ™ƒ
    • 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, GCC 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 that runs those non-trivial default constructors on those instance variables, in order, then returns self ๐Ÿงš It also checks for instance variables that are C++ objects with a non-trivial destructor, and if it finds any, it synthesizes a - (void) .cxx_destruct method that runs all those default destructors in reverse order ๐Ÿ’€

The - (id) .cxx_construct and - (void) .cxx_destruct methods generated this way only touch instance variables declared in the current Objective-C class, not the ones inherited from superclasses. It's the Objective-C runtime's job to call all of these methods across an object's inheritance hierarchy ๐Ÿซถ The - (id) .cxx_construct methods get invoked by the runtime right after a new object instance is allocated, and the - (void) .cxx_destruct methods get invoked right before the runtime deallocates an object instance.

As of this writing, only the NeXT runtime on Mac OS X 10.4 and later can invoke the - (id) .cxx_construct and - (void) .cxx_destruct methods ๐Ÿ

  • -fobjc-direct-dispatch โ€” Allows fast jumps to the message dispatcher โšก On Darwin, this is done through the comm page.
  • -fobjc-exceptions โ€” Turns on syntax support for structured exception handling in Objective-C, kind of like C++ ๐Ÿซง You need this to use the Objective-C keywords @try, @throw, @catch, @finally, and @synchronized. It works with both the GNU runtime and the NeXT runtime, but not 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 its own GC 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 the actual method call happens ๐Ÿ›ก๏ธ 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. Right now this flag does nothing when the GNU runtime, or an older version of the NeXT runtime ABI, is in use.
  • -fobjc-std=objc1 โ€” Makes your code follow the language syntax of Objective-C 1.0, the one GCC 4.0 recognized ๐Ÿ“œ This only changes the Objective-C additions to C/C++. It doesn't touch conformance to C/C++ standards, which is handled by the separate C/C++ dialect option flags. With this on, any Objective-C syntax GCC 4.0 doesn't recognize gets rejected, so it's super useful if you need your code to still compile with older versions of GCC ๐Ÿ•ฐ๏ธ
  • -freplace-objc-classes โ€” Emits a special marker telling ld(1) not to statically link the resulting object file, and lets dyld(1) load it at run time instead ๐Ÿฆ‹ This pairs with the Fix-and-Continue debugging mode, where the object file can be recompiled and dynamically reloaded during execution without restarting the whole program. Right now Fix-and-Continue only works with the NeXT runtime on Mac OS X 10.3 and later.
  • -fzero-link โ€” When compiling for the NeXT runtime, the compiler usually swaps out calls to objc_getClass("...") (when the class name is known at compile time) for static class references that get initialized at load time, which is faster at run time ๐Ÿš€ Using -fzero-link turns that off, so calls to objc_getClass("...") stick around. This is handy in Zero-Link debugging mode, since it lets you modify individual class implementations while the program is running. The GNU runtime always keeps calls to objc_get_class("...") no matter what command-line options you pass ๐Ÿคทโ€โ™€๏ธ
  • -fno-local-ivars โ€” By default, instance variables in Objective-C can be accessed as if they were local variables inside the methods of the class they're declared in ๐ŸŒธ That can cause shadowing between instance variables and other variables with the same name, either declared locally inside a class method or globally. Specifying -fno-local-ivars turns this behavior off, so you dodge those shadowing issues ๐Ÿ’–
  • -fivar-visibility=[public|protected|private|package] โ€” Sets the default instance variable visibility to whatever option you pick ๐ŸŽ€ So instance variables declared outside the scope of any access modifier directives default to that visibility.
  • -gen-decls โ€” Dumps the interface declarations for all classes seen in the source file into a file named sourcename.decl ๐Ÿ“„
  • -Wassign-intercept (Objective-C and Objective-C++ only) โ€” Warns whenever an Objective-C assignment gets intercepted by the garbage collector ๐Ÿ—‘๏ธโœจ
  • -Wno-property-assign-default (Objective-C and Objective-C++ only) โ€” Stops the warning for Objective-C object properties that don't have assign semantics specified ๐ŸŒˆ
  • -Wno-protocol (Objective-C and Objective-C++ only) โ€” okay so if a class says it implements a protocol, GCC warns you for every protocol method the class doesn't implement ๐Ÿซถ By default it also warns about methods the class doesn't explicitly implement, even when the superclass already handles them ๐Ÿ™„ With -Wno-protocol, inherited methods from the superclass count as implemented, so no warning for those โœจ
  • -Wobjc-root-class (Objective-C and Objective-C++ only) โ€” warns if a class interface has no superclass ๐Ÿ’… Most classes inherit from "NSObject" (or "Object"), for example. If you're making a root class on purpose, you can shush the warning by marking its interface with __attribute__((objc_root_class)) ๐ŸŒธ
  • -Wselector (Objective-C and Objective-C++ only) โ€” warns if multiple methods of different types show up for the same selector during compilation ๐Ÿ” This check runs on the method list in the final stage of compilation. It also checks each selector used in a @selector(...) expression when a matching method was found during compilation. Since these checks only scan the method table at the very end, the warnings won't appear if the final stage never happens, like when an error stops things early or you're using -fsyntax-only ๐Ÿ™ƒ
  • -Wstrict-selector-match (Objective-C and Objective-C++ only) โ€” warns if a selector has multiple methods with different argument and/or return types when you try to send a message with it to a receiver of type id or Class ๐Ÿ‘€ When this flag is off (the default), the compiler skips these warnings if the differences are only between types with the same size and alignment ๐Ÿคทโ€โ™€๏ธ
  • -Wundeclared-selector (Objective-C and Objective-C++ only) โ€” warns when a @selector(...) expression refers to an undeclared selector ๐Ÿ“œ 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 checks the moment it spots a @selector(...) expression, while -Wselector only checks in the final stage. It also enforces the coding style rule that methods and selectors must be declared before they're used ๐Ÿ’–
  • -print-objc-runtime-info โ€” 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 got formatted without caring what the output device looked like (its width, ...) ๐Ÿ™ˆ These options let you control the formatting algorithm, like how many characters go on a line and how often source location info gets reported ๐Ÿ“ Heads up: some language front ends might not honor these options ๐Ÿซ 

  • -fmessage-length=n โ€” tries to format error messages so they fit on lines about n characters wide ๐Ÿ“ If n is zero, no line-wrapping happens and each error message sits on a single line. That's 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-plain-output โ€” requests that diagnostic output look as plain as possible ๐Ÿงผ This is handy when you're running dejagnu or other tools that parse diagnostics and need the output to stay stable over time ๐Ÿซถ Right now it's equivalent to these options:
-fno-diagnostics-show-caret -fno-diagnostics-show-line-numbers -fdiagnostics-color=never -fdiagnostics-urls=never -fdiagnostics-path-format=separate-events

In the future, if GCC changes the default look of its diagnostics, the matching option to turn off that new behavior will get added to this list ๐Ÿ”ฎ

  • -fdiagnostics-show-location=once โ€” only matters in line-wrapping mode ๐ŸŽ€ It tells the reporter to emit source location info just once. If a message is too long and has to wrap, the location prefix won't get stuck on every continuation line again and again. This is the default ๐Ÿ‘‘
  • -fdiagnostics-show-location=every-line โ€” only matters in line-wrapping mode ๐Ÿฆ‹ It tells the reporter to put the same source location prefix on every physical line that results from breaking up a message that's too long to fit on one line ๐Ÿ’œ
  • -fdiagnostics-color[=WHEN], -fno-diagnostics-color โ€” turns on color in diagnostics ๐ŸŒˆ WHEN can be never, always, or auto. The default depends on how the compiler was configured. It can be any of those WHEN options, or never if the GCC_COLORS environment variable isn't present, and auto otherwise. auto only uses color when standard error is a terminal and you're not running in an emacs shell ๐ŸŒธ 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, so check the docs for your text terminal to see the permitted values and what they mean as character attributes ๐Ÿ“– These substring values are integers in decimal 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, and 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:path=01;36:fixit-insert=32:fixit-delete=31:\
diff-filename=01:diff-hunk=32:diff-delete=31:diff-insert=32:\
type-diff=01;32

where 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 โœจ Supported capabilities are as follows ๐Ÿ’…

  • error= โ€” the SGR substring for error: markers ๐Ÿ’ฅ
  • warning= โ€” the SGR substring for warning: markers โš ๏ธ
  • note= โ€” the SGR substring for note: markers ๐Ÿ“
  • path= โ€” the SGR substring for colorizing paths of control-flow events printed via -fdiagnostics-path-format=, like the identifiers of individual events and the lines showing interprocedural calls and returns ๐Ÿ›ค๏ธ
  • range1= โ€” the SGR substring for the first additional range 1๏ธโƒฃ
  • range2= โ€” the SGR substring for the second additional range 2๏ธโƒฃ
  • locus= โ€” the SGR substring for location info, like file:line or file:line:column etc. ๐Ÿ“
  • quote= โ€” the SGR substring for info printed within quotes ๐Ÿ’ฌ
  • fixit-insert= โ€” the SGR substring for fix-it hints suggesting text to be inserted or replaced โž•
  • fixit-delete= โ€” the SGR substring for fix-it hints suggesting text to be deleted โž–
  • diff-filename= โ€” the SGR substring for filename headers within generated patches ๐Ÿ“„
  • diff-hunk= โ€” the SGR substring for the starts of hunks within generated patches ๐Ÿงฉ
  • diff-delete= โ€” the SGR substring for deleted lines within generated patches ๐Ÿ—‘๏ธ
  • diff-insert= โ€” the SGR substring for inserted lines within generated patches ๐ŸŒฑ
  • type-diff= โ€” the SGR substring for highlighting mismatching types within template arguments in the C++ frontend ๐Ÿ”
  • -fdiagnostics-urls[=WHEN] โ€” uses escape sequences to embed URLs in diagnostics ๐Ÿ”— For example, when -fdiagnostics-show-option shows the command-line option controlling a diagnostic, GCC embeds a URL pointing to the docs for that option ๐Ÿ“š

WHEN is never, always, or auto. auto makes GCC use URL escape sequences only when standard error is a terminal, and when it's not running in an emacs shell or any graphical terminal known to be incompatible with this feature (see below) ๐Ÿ–ฅ๏ธ

The default depends on how the compiler was configured. It can be any of the above WHEN options.

GCC can also be configured (via the --with-diagnostics-urls=auto-if-env configure-time option) so the default is affected by environment variables. Under that configuration, GCC defaults to auto if either the GCC_URLS or TERM_URLS environment variables are present and non-empty in the environment of the compiler, or never if neither are ๐Ÿงš

However, even with -fdiagnostics-urls=always, the behavior still depends on those environment variables ๐Ÿ™ƒ If GCC_URLS is set to empty or no, URLs are not embedded in diagnostics. If it's set to st, URLs use ST escape sequences. If it's set to bel, which is the default, URLs use BEL escape sequences. Any other non-empty value enables the feature. If GCC_URLS isn't set, TERM_URLS is used as a fallback ๐Ÿ’œ

Note: ST is an ANSI escape sequence, string terminator ESC \, BEL is an ASCII character, CTRL-G that usually sounds like a beep ๐Ÿ””

Okay so, GCC also tries to sniff out a few terminals that don't play nice with the URL feature ๐Ÿ™ˆ. Some of them have bugs (or at least had bugs in versions people still use) where the URL escapes are likely to misbehave and print garbage all over your screen ๐Ÿ’€. The current hit list is xfce4-terminal, certain known-buggy gnome-terminal versions, the linux console, and mingw ๐Ÿ˜ญ. If you're sure your setup is fine, you can skip this check with -fdiagnostics-urls=always โœจ

  • -fno-diagnostics-show-option โ€” By default, every diagnostic includes a little hint naming the command-line option that directly controls it (if GCC knows about that option) ๐Ÿ”. Add this flag and that hint gets suppressed ๐Ÿ™….
  • -fno-diagnostics-show-caret โ€” Normally each diagnostic shows the original source line plus a caret ^ pointing at the column ๐ŸŽฏ. This option hides all of that. If you pass -fmessage-length=n, the source line gets truncated to n characters. When the output is going to a terminal, the width is limited to the width given by the COLUMNS environment variable or, if that isn't set, to the terminal width ๐Ÿ“.
  • -fno-diagnostics-show-labels โ€” When GCC prints source code (via -fdiagnostics-show-caret), diagnostics can slap labels on ranges of code with pertinent info, like expression types. Peep this:
printf ("foo %s bar", long_i + long_j);
             ~^       ~~~~~~~~~~~~~~~
              |              |
              char *         long int

This option kills those labels, so no vertical bars and no "char *" or "long int" text in the example above ๐Ÿท๏ธ๐Ÿšซ.

  • -fno-diagnostics-show-cwe โ€” Diagnostics can optionally carry a CWE identifier (see https://cwe.mitre.org/index.html) ๐Ÿ›ก๏ธ. GCC itself only provides this metadata for some of the -fanalyzer diagnostics, and GCC plugins may provide it too. By default, if the info is there, it gets printed along with the diagnostic. This option stops that metadata from showing up.
  • -fno-diagnostics-show-line-numbers โ€” By default, when printing source code (via -fdiagnostics-show-caret), GCC prints a left margin showing line numbers ๐Ÿ”ข. This option gets rid of that 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, which is 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 a half-open range measured in bytes, starting at byte 1 for the initial column. In the example above, bytes 3 through 20 of line 45 of "test.c" get 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 gets removed ๐Ÿ—‘๏ธ. An empty range (e.g. "45:3-45:3") means the string gets 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 diagnostics show mismatching template types, such as:
could not convert 'std::map<int, std::vector<double> >()'
  from 'map<[...],vector<double>>' to 'map<[...],vector<float>>

this flag enables a tree-like structure showing the common and differing parts of the types, such as:

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 about mismatching template types, the common parts get printed as [...] so the error message stays short ๐Ÿค. 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 -fdiagnostics-show-template-tree.

  • -fdiagnostics-path-format=KIND โ€” Specifies how to print paths of control-flow events for diagnostics that have one attached ๐Ÿ›ค๏ธ.

KIND is none, separate-events, or inline-events, the default.

none means to not print diagnostic paths.

separate-events means to print a separate note diagnostic for each event within the diagnostic. For example:

test.c:29:5: error: passing NULL as argument 1 to 'PyList_Append' which requires a non-NULL parameter
test.c:25:10: note: (1) when 'PyList_New' fails, returning NULL
test.c:27:3: note: (2) when 'i < count'
test.c:29:5: note: (3) when calling 'PyList_Append', passing NULL from (1) as argument 1

inline-events means to print the events "inline" within the source code. This view tries to consolidate the events into runs of sufficiently-close events, printing them as labelled ranges within the source. For example, the same events as above might be printed as:

'test': events 1-3
  |
  |   25 |   list = PyList_New(0);
  |      |          ^~~~~~~~~~~~~
  |      |          |
  |      |          (1) when 'PyList_New' fails, returning NULL
  |   26 |
  |   27 |   for (i = 0; i < count; i++) {
  |      |   ~~~
  |      |   |
  |      |   (2) when 'i < count'
  |   28 |     item = PyLong_FromLong(random());
  |   29 |     PyList_Append(list, item);
  |      |     ~~~~~~~~~~~~~~~~~~~~~~~~~
  |      |     |
  |      |     (3) when calling 'PyList_Append', passing NULL from (1) as argument 1
  |

Interprocedural control flow is shown by grouping the events by stack frame, and using indentation to show how stack frames are nested, pushed, and popped ๐Ÿช†. For example:

'test': events 1-2
  |
  |  133 | {
  |      | ^
  |      | |
  |      | (1) entering 'test'
  |  134 |   boxed_int *obj = make_boxed_int (i);
  |      |                    ~~~~~~~~~~~~~~~~~~
  |      |                    |
  |      |                    (2) calling 'make_boxed_int'
  |
  +--> 'make_boxed_int': events 3-4
         |
         |  120 | {
         |      | ^
         |      | |
         |      | (3) entering 'make_boxed_int'
         |  121 |   boxed_int *result = (boxed_int *)wrapped_malloc (sizeof (boxed_int));
         |      |                                    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
         |      |                                    |
         |      |                                    (4) calling 'wrapped_malloc'
         |
         +--> 'wrapped_malloc': events 5-6
                |
                |    7 | {
                |      | ^
                |      | |
                |      | (5) entering 'wrapped_malloc'
                |    8 |   return malloc (size);
                |      |          ~~~~~~~~~~~~~
                |      |          |
                |      |          (6) calling 'malloc'
                |
  <-------------+
  |
 'test': event 7
  |
  |  138 |   free_boxed_int (obj);
  |      |   ^~~~~~~~~~~~~~~~~~~~
  |      |   |
  |      |   (7) calling 'free_boxed_int'
  |
(etc)
  • -fdiagnostics-show-path-depths โ€” Adds extra info when printing control-flow paths associated with a diagnostic ๐Ÿงญ. If this option is given, the stack depth gets printed for each run of events within -fdiagnostics-path-format=separate-events. It's intended for GCC developers and plugin developers debugging diagnostics that report interprocedural control flow ๐Ÿงช.
  • -fno-show-column โ€” Don't 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-column-unit=UNIT โ€” Selects the units for the column number ๐ŸŽ€. This affects traditional diagnostics (as long as -fno-show-column isn't in use), as well as JSON format diagnostics if they're requested ๐Ÿ’œ.

Okay so the default UNIT is display, which means GCC counts how many display columns each character actually takes up ๐Ÿ’…. That can be bigger than the bytes needed to encode it (hi, tab characters ๐Ÿ“) or smaller (multibyte characters are sneaky โœจ). Like, GREEK SMALL LETTER PI (U+03C0) takes up one display column but its UTF-8 encoding needs two bytes ๐ŸŒธ. Meanwhile SLIGHTLY SMILING FACE (U+1F642) takes up two display columns and needs four bytes ๐Ÿ™‚.

Setting UNIT to byte switches the column number to the raw byte count in every single case. That's what GCC used to output before version 11.1.0, so if you're giving old-school vibes ๐Ÿ•ฐ๏ธ, this is your setting ๐Ÿ’–.

๐ŸŽ€ -fdiagnostics-column-origin=ORIGIN

This picks the origin for column numbers, which is basically the number given to the first column ๐Ÿ”ข. The default is 1, which matches traditional GCC behaviour and the GNU style guide ๐Ÿ“–. Some utilities work better with an origin of 0, so any non-negative value is allowed ๐Ÿฆ‹.

๐Ÿฆ‹ -fdiagnostics-format=FORMAT

This changes how diagnostics get printed. FORMAT is either text or json, and the default is text ๐Ÿ’….

The json format is a top-level JSON array full of JSON objects, one for each diagnostic ๐Ÿงš.

The JSON gets emitted as one single line with no formatting at all ๐Ÿ˜ญ, so the examples below have been dressed up for clarity โœจ.

Diagnostics can have child diagnostics too. For example, 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": {
                    "display-column": 3,
                    "byte-column": 3,
                    "column": 3,
                    "file": "misleading-indentation.c",
                    "line": 15
                },
                "finish": {
                    "display-column": 4,
                    "byte-column": 4,
                    "column": 4,
                    "file": "misleading-indentation.c",
                    "line": 15
                }
            }
        ],
        "message": "this \u2018if\u2019 clause does not guard...",
        "option": "-Wmisleading-indentation",
        "option_url": "https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html#index-Wmisleading-indentation",
        "children": [
            {
                "kind": "note",
                "locations": [
                    {
                        "caret": {
                            "display-column": 5,
                            "byte-column": 5,
                            "column": 5,
                            "file": "misleading-indentation.c",
                            "line": 17
                        }
                    }
                ],
                "message": "...this statement, but the latter is ..."
            }
        ]
        "column-origin": 1,
    },
    ...
]

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

A diagnostic has a "kind". If this is "warning", then there is an "option" key describing the command-line option controlling the warning ๐Ÿ”ฅ.

A diagnostic can contain zero or more locations. Each location has an optional "label" string and up to three positions inside it: a "caret" position and optional "start" and "finish" positions. A position is described by a "file" name, a "line" number, and three numbers indicating a column position ๐Ÿ“:

  • "display-column" counts display columns, accounting for tabs and multibyte characters.
  • "byte-column" counts raw bytes.
  • "column" is equal to one of the previous two, as dictated by the -fdiagnostics-column-unit option.

All three columns are relative to the origin specified by -fdiagnostics-column-origin, which is typically equal to 1 but may be set, for instance, to 0 for compatibility with other utilities that number columns from 0 ๐ŸŒˆ. The column origin is recorded in the JSON output in the "column-origin" tag. In the remaining examples below, the extra column number outputs have been left out for brevity ๐Ÿ™ˆ.

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 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 contains fix-it hints, it has a "fixits" array, made of half-open intervals, similar to 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 expressed via an empty value for "string", and insertions by having "start" equal "next" โœจ.

If the diagnostic has a path of control-flow events associated with it, it has a "path" array of objects representing those events ๐Ÿฆ‹. Each event object has a "description" string and a "location" object, along with a "function" string and a "depth" number for representing interprocedural paths. The "function" represents the current function at that event, and the "depth" represents the stack depth relative to some baseline: the higher the number, the more frames are within the stack ๐ŸŒธ.

For example, the intraprocedural example shown for -fdiagnostics-path-format= might have this JSON for its path:

                       "path": [
                           {
                               "depth": 0,
                               "description": "when 'PyList_New' fails, returning NULL",
                               "function": "test",
                               "location": {
                                   "column": 10,
                                   "file": "test.c",
                                   "line": 25
                               }
                           },
                           {
                               "depth": 0,
                               "description": "when 'i < count'",
                               "function": "test",
                               "location": {
                                   "column": 3,
                                   "file": "test.c",
                                   "line": 27
                               }
                           },
                           {
                               "depth": 0,
                               "description": "when calling 'PyList_Append', passing NULL from (1) as argument 1",
                               "function": "test",
                               "location": {
                                   "column": 5,
                                   "file": "test.c",
                                   "line": 29
                               }
                           }
                       ]

โœจ Options to Request or Suppress Warnings โœจ

okay so warnings are the compiler's little "hmm, are you sure about that?" messages ๐Ÿ™ˆ They're for constructions that aren't technically wrong, but are risky or might mean you goofed somewhere. ๐Ÿ’…

The options below are language-independent, which means they don't switch on any specific warning. Instead, they control what kinds of diagnostics GCC produces. ๐Ÿซถ

  • -fsyntax-only โ€” bestie, this just checks your code for syntax errors and then stops right there. Nothing extra, no drama. ๐Ÿง
  • -fmax-errors=n โ€” the vibe check for error floods ๐Ÿ˜ญ Cap the number of error messages at n, and GCC bails out instead of trying to keep going through the source. The default is 0, which means no limit at all, so the errors just keep coming. If -Wfatal-errors is also specified, then -Wfatal-errors takes precedence over this option ๐Ÿ‘‘
  • -w โ€” mutes every single warning message. Total silence, no cap. ๐Ÿคซ
  • -Werror โ€” turns every warning into an actual error. Main character energy, but make it strict ๐Ÿšจ
  • -Werror= โ€” targets one specific warning and makes it an error. You append the warning's name, so -Werror=switch turns the warnings controlled by -Wswitch into errors ๐Ÿ”ฅ There's a negative form too: -Wno-error=switch means -Wswitch warnings are not errors, even when -Werror is in effect ๐Ÿ’€

Each controllable warning's message includes the option that controls it, and you can plug that option right into -Werror= and -Wno-error= like we just covered ๐Ÿ” Printing of the option in the warning message can be disabled using the -fno-diagnostics-show-option flag if you want it hidden ๐Ÿ™ˆ

Note that specifying -Werror=foo automatically implies -Wfoo. However, -Wno-error=foo does not imply anything. ๐Ÿง 

  • -Wfatal-errors โ€” the compiler aborts on the very first error it hits, instead of pushing on and printing more. One and done ๐Ÿ’…

You can request many specific warnings with options beginning with -W. For example, -Wimplicit requests warnings on implicit declarations ๐ŸŒธ Each of these specific warning options also has a negative form beginning -Wno- to turn the warnings off, like -Wno-implicit. This manual only lists one of the two forms, whichever one is not the default. For further language-specific options, also refer to C++ Dialect Options and Objective-C and Objective-C++ Dialect Options. Additional warnings can be produced by enabling the static analyzer;

Some options, such as -Wall and -Wextra, turn on other options, such as -Wunused, which may turn on further options, such as -Wunused-value. The combined effect of positive and negative forms is that more specific options have priority over less specific ones, independently of their position on the command line. For options of the same specificity, the last one takes effect. Options enabled or disabled via pragmas take effect as if they appeared at the end of the command line. โœจ

When an unrecognized warning option is requested (e.g., -Wunknown-warning), GCC emits a diagnostic stating that the option is not recognized. ๐Ÿคจ However, if the -Wno- form is used, the behavior is slightly different: no diagnostic is produced for -Wno-unknown-warning unless other diagnostics are being produced. This lets you use new -Wno- options with old compilers, but if something goes wrong, the compiler warns that an unrecognized option is present ๐Ÿฆ‹

The effectiveness of some warnings depends on optimizations also being enabled. For example, -Wsuggest-final-types is more effective with link-time optimization, and -Wmaybe-uninitialized does not warn at all unless optimization is enabled. โšก

  • -Wpedantic, -pedantic โ€” issue all the warnings demanded by strict ISO C and ISO C++, reject all programs that use forbidden extensions, and reject 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.

Valid ISO C and ISO C++ programs should compile properly with or without this option, though a rare few require -ansi or a -std option specifying the required version of ISO C. However, without this option, certain GNU extensions and traditional C and C++ features are supported as well. With this option, they are rejected. ๐Ÿ™…โ€โ™€๏ธ

-Wpedantic does not cause warning messages for use of the alternate keywords whose names begin and end with __. This alternate format can also be used to disable warnings for non-ISO __intN types, i.e. __intN__. Pedantic warnings are also disabled in the expression that follows "__extension__". However, only system header files should use these escape routes; application programs should avoid them. ๐Ÿšซ

Some users try to use -Wpedantic to check programs for strict ISO C conformance. They soon find that it does not do quite what they want: it finds some non-ISO practices, but not all. It only catches the ones for which ISO C requires a diagnostic, plus some others for which diagnostics have been added. ๐Ÿฅฒ

A feature to report any failure to conform to ISO C might be useful in some instances, but it would require considerable additional work and would be quite different from -Wpedantic. We don't have plans to support such a feature in the near future. ๐Ÿซ 

Where the standard specified with -std represents a GNU extended dialect of C, such as gnu90 or gnu99, there is a corresponding base standard: the version of ISO C on which the GNU extended dialect is based. Warnings from -Wpedantic are given where they are required by the base standard. (It does not make sense for such warnings to be given only for features not in the specified GNU C dialect, since by definition the GNU dialects of C include all features the compiler supports with the given option, and there would be nothing to warn about.) ๐ŸŒˆ

  • -pedantic-errors โ€” gives an error whenever the base standard (see -Wpedantic) requires a diagnostic. That includes some cases where there is undefined behavior at compile time, and some other cases that do not prevent compilation of programs that are valid according to the standard. This is not equivalent to -Werror=pedantic, since there are errors enabled by this option and not enabled by the latter, and vice versa. ๐Ÿ›‘
  • -Wall โ€” enables all the warnings about constructions that some users consider questionable, and that are easy to avoid (or modify to prevent the warning), even in conjunction with macros ๐Ÿ’– This 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) -Warray-parameter=2 (C
and Objective-C only) -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 -Wformat-overflow -Wformat-truncation
-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 -Wrange-loop-construct (only for C++)
-Wreorder -Wrestrict -Wreturn-type -Wsequence-point -Wsign-compare
(only in C++) -Wsizeof-array-div -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 -Wvla-parameter (C and Objective-C only)
-Wvolatile-register-var -Wzero-length-bounds

Note that some warning flags are not implied by -Wall. Some of them warn about constructions that users generally do not consider questionable, but which you might occasionally wish to check for. Others warn about constructions that are necessary or hard to avoid in some cases, and there is no simple way to modify the code to suppress the warning. Some of them are enabled by -Wextra, but many of them must be enabled individually. ๐Ÿ•ต๏ธโ€โ™€๏ธ

  • -Wextra โ€” enables some extra warning flags that are not enabled by -Wall. (This option used to be called -W. The older name is still supported, but the newer name is more descriptive ๐ŸŽ€)
-Wclobbered -Wcast-function-type -Wdeprecated-copy (C++ only)
-Wempty-body -Wenum-conversion (C only) -Wignored-qualifiers
-Wimplicit-fallthrough=3 -Wmissing-field-initializers
-Wmissing-parameter-type (C only) -Wold-style-declaration (C only)
-Woverride-init -Wsign-compare (C only) -Wstring-compare
-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)

Okay bestie, -Wextra is giving extra ๐Ÿ’… and also flags these sneaky 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 ๐Ÿ˜ญ

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

This one is all about ABI changes. It warns about code that gets affected by them, including code that might not be compatible with the vendor-neutral C++ ABI, plus the psABI for your particular target ๐ŸŽ€.

Since G++ now defaults to updating the ABI with each major release, normally -Wabi only warns about C++ ABI compatibility problems if there's a check added later in a release series for an ABI issue found after the initial release. -Wabi warns about more things if an older ABI version is selected with -fabi-version=n.

You can also give -Wabi an explicit version number to warn about C++ ABI compatibility with a particular -fabi-version level. For example, -Wabi=2 warns about changes relative to -fabi-version=2 โœจ.

If you give an explicit version number and don't specify -fabi-compat-version, the version number from this option gets used for compatibility aliases. If you don't give a version number with this option but do specify -fabi-compat-version, that version number is used for C++ ABI warnings.

Now the honest tea โ˜•: GCC tried super hard to warn about every case, but there are probably some cases that slip through even though G++ is generating incompatible code ๐Ÿ˜ฌ. There may also be cases where warnings pop up even though the generated code is actually compatible.

If you're worried that G++ output might not be binary compatible with code from other compilers, rewrite your code to dodge these warnings ๐Ÿซถ.

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 got fixed in -fabi-version=3 ๐Ÿฉน.

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

The mangling 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 got 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 ๐Ÿคทโ€โ™€๏ธ.

The ABI also 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. This didn't affect the ABI of a function with a nullptr_t parameter, since 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, like ia32 calling conventions on a function type (stdcall, regparm, etc.), didn't affect the mangled name. That 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 ๐Ÿ‘‘.

This option also turns on warnings 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. Before GCC 4.4 this wasn't the case ๐ŸŒˆ. For example:
union U {
  long double ld;
  int i;
};

union U is now always passed in memory, no cap ๐Ÿซถ.


๐Ÿ“ -Wchar-subscripts

Warn if an array subscript has type char. This is a super common source of errors, because programmers often forget that this type is signed on some machines ๐Ÿ™ˆ. This warning is enabled by -Wall ๐Ÿ’–.

๐ŸŒ™ -Wno-coverage-mismatch

Warn if feedback profiles don't match when you use the -fprofile-use option. If a source file changes between compiling with -fprofile-generate and with -fprofile-use, the profile feedback files 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.

You can use -Wno-coverage-mismatch to disable the warning, or -Wno-error=coverage-mismatch to disable the error. Disabling the error can lead to poorly optimized code, so 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) Suppress warning messages emitted by #warning directives ๐Ÿคซ.

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

Give 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 of software emulation ๐Ÿ˜ค.

It's SO 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)

Warn if a declaration has a duplicate const, volatile, restrict or _Atomic specifier. This warning is enabled by -Wall ๐ŸŽ€.

๐Ÿช„ -Wformat, -Wformat=n

Check calls to printf and scanf, etc., to make sure the arguments supplied have types that match the format string, and that the conversions in the format string make sense โœจ. This covers standard functions, plus others specified by format attributes, in the printf, scanf, strftime and strfmon (an X/Open extension, not in the C standard) families (or other target-specific families) ๐ŸŒˆ.

Which functions get checked without format attributes specified depends on the standard version you picked. Those checks for functions without the attribute are disabled by -ffreestanding or -fno-builtin ๐Ÿงš.

The formats are checked against the format features supported by GNU libc version 2.2. That includes 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. (This doesn't apply to strfmon formats, since those aren't in any version of the C standard ๐Ÿ™ƒ.)

๐Ÿ’– -Wformat=1, -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 ๐Ÿ‘‘.

๐ŸŒท -Wformat=2

Enable -Wformat plus additional format checks. Right now it's equivalent to -Wformat -Wformat-nonliteral -Wformat-security -Wformat-y2k ๐Ÿ’….

๐Ÿซง -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 extra arguments get ignored, so it's chill ๐Ÿซถ.

Where unused arguments sit between used arguments that are specified with $ operand number specifications, warnings still get given as usual. The implementation can'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, because the Single Unix Specification says those unused arguments are allowed โœจ.

๐Ÿ”ฅ -Wformat-overflow, -Wformat-overflow=level

Warn about calls to formatted input/output functions like sprintf and vsprintf that might overflow the destination buffer ๐Ÿ˜ฑ. When the exact number of bytes written by a format directive can't be figured out at compile-time, it's estimated using heuristics that depend on the level argument and on optimization ๐Ÿง .

Turning on optimization will usually make the warning more accurate, but it may also result in false positives ๐Ÿ™ƒ.

  • -Wformat-overflow, -Wformat-overflow=1 โ€” okay so level 1 is the chill one ๐Ÿ’… It's switched on by -Wformat and only yells when a call will most likely overflow the buffer ๐Ÿซถ Unknown numeric arguments get treated like 1, and strings of unknown length get treated as empty. Numbers that are bounded to a subrange of their type, or strings whose output is capped by a precision or a finite set of string literals, get assumed to take whatever value makes the most bytes of output โœจ

The sus one here is the sprintf call ๐Ÿ‘€ Even with a and b both at zero, the terminating NUL ('\0') the function tacks onto the end still gets written past the buffer ๐Ÿ˜ญ

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

Bump the buffer up by a single byte and the warning goes away ๐ŸŽ€ but heads up, that might not actually stop the overflow ๐Ÿ’€

  • -Wformat-overflow=2 โ€” level 2 is the drama queen ๐Ÿ‘‘ It warns about calls that might overflow given an argument of sufficient length or magnitude. Unknown numeric arguments get 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 that can't be bounded by the directive's precision, a finite set of string literals they might evaluate to, or the character array they might point to, get assumed to be 1 character long ๐ŸŒธ

At level 2 the example call gets flagged again ๐Ÿ™ˆ This time it's because with a equal to a 32-bit INT_MIN, the first %i directive spills some digits past the end of the buffer. To keep the call safe no matter what the two variables hold, the destination buffer has to be at least 34 bytes. GCC even includes that minimum size in an informational note right after the warning ๐Ÿ“

An alternative to just making the buffer bigger is to constrain the range of the formatted values ๐Ÿฆ‹ You can bound the maximum length of string arguments by putting a precision in the format directive. If numeric arguments can be assumed to be bounded by less than the precision of their type, picking an appropriate length modifier for the format specifier shrinks the required buffer size. For example, if a and b can be assumed to fit within the precision of the short int type, then either using the %hi directive or casting the argument to short brings the maximum required size down 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 chill about zero-length formats ๐Ÿงš The C standard says zero-length formats are allowed, so no drama needed.
  • -Wformat-nonliteral โ€” if -Wformat is on, GCC also warns when the format string isn't a string literal, since it can't be checked that way ๐Ÿ” The exception is when the format function takes its format arguments as a va_list.
  • -Wformat-security โ€” if -Wformat is on, this one also warns about format function calls that could be a security problem ๐Ÿ”’ Right now it flags printf and scanf calls where the format string isn't a string literal and there are no format arguments, like printf (foo);.
Super important: that printf (foo); pattern can be a security hole if the format string came from untrusted input and contains %n. This is currently a subset of what -Wformat-nonliteral catches, but future versions may add -Wformat-security warnings 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 โ€” this warns about formatted input/output calls like snprintf and vsnprintf that might end up truncating their output โœ‚๏ธ When the exact number of bytes a format directive writes can't be figured out at compile time, GCC estimates it using heuristics that depend on the level argument and on optimization. Turning on optimization usually makes the warning more accurate, but it can also cause false positives. Unless noted otherwise, this option uses the same logic as -Wformat-overflow.
    • -Wformat-truncation, -Wformat-truncation=1 โ€” level 1 is conservative ๐Ÿซถ It only warns about calls to bounded functions whose return value is unused and that will most likely result in truncation.
    • -Wformat-truncation=2 โ€” level 2 also warns about calls to bounded functions whose return value is used, if they might truncate given an argument of sufficient length or magnitude ๐Ÿ”ฅ
  • -Wformat-y2k โ€” if -Wformat is on, this warns about strftime formats that might only give you a two-digit year ๐Ÿ“… Y2K vibes, no thank you ๐Ÿ’€
  • -Wnonnull โ€” warns when you pass a null pointer to an argument that the nonnull function attribute says must be non-null ๐Ÿšซ -Wnonnull is 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 you can disable it with -Wno-nonnull-compare.
  • -Wnull-dereference โ€” warns if the compiler finds paths that trigger erroneous or undefined behavior because a null pointer gets dereferenced ๐Ÿ’€ 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 ๐ŸŒ€ This option can only be used together with -Wuninitialized.

For example, GCC warns about i being uninitialized in this snippet only when -Winit-self is specified:

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

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

  • -Wno-implicit-int (C and Objective-C only) โ€” controls warnings for when a declaration doesn't specify a type ๐Ÿง This warning is on by default in C99 and later dialects of C, and also turned on by -Wall.
  • -Wno-implicit-function-declaration (C and Objective-C only) โ€” controls warnings for when a function gets used before it's declared ๐Ÿซ  This warning is on by default in C99 and later dialects of C, and also turned on by -Wall. It gets upgraded to an error by -pedantic-errors.
  • -Wimplicit (C and Objective-C only) โ€” same as -Wimplicit-int and -Wimplicit-function-declaration together โœจ This warning is enabled by -Wall.
  • -Wimplicit-fallthrough โ€” this is the 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 ๐Ÿ“ For example:
switch (cond)
  {
  case 1:
    a = 1;
    break;
  case 2:
    a = 2;
  case 3:
    a = 3;
    break;
  }

This warning does not go off 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 ๐Ÿ™Œ -Wimplicit-fallthrough= also takes control flow statements into account, such as ifs, and only warns when it's appropriate. For example:

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

Sometimes a switch case falling through is exactly what you want ๐Ÿฆ‹ For those times GCC provides an attribute, __attribute__ ((fallthrough)), which goes along with a null statement to suppress the warning that would otherwise show up:

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

C++17 gives you a standard way to suppress the -Wimplicit-fallthrough warning using [[fallthrough]]; instead of the GNU attribute ๐Ÿ’… In C++11 or C++14 you can use [[gnu::fallthrough]];, which is a GNU extension. Instead of these attributes, you can also add a fallthrough comment to silence the warning ๐Ÿ’œ The whole body of the C or C++ style comment has to match the regular expressions listed below. The option argument n specifies what kinds of comments are accepted:

  • -Wimplicit-fallthrough=0 disables the warning altogether ๐Ÿ™…
  • -Wimplicit-fallthrough=1 matches the ".*" regular expression, so any comment 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 the following regular expressions:

Okay, the =3 list keeps going, bestie ๐Ÿ’… here are the rest of the regexes it'll match:

"-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 regexes ๐Ÿ”ฅ:

"-fallthrough"
"@fallthrough@"
"lint -fallthrough[ \t]*"
"[ \t]*FALLTHR(OUGH|U)[ \t]*"

-Wimplicit-fallthrough=5 doesn't recognize any comments as fallthrough comments ๐Ÿ™ˆ. Only attributes disable the warning โœจ.

The comment needs to be followed, after optional whitespace and other comments, by case or default keywords, or by a user label that precedes some case or default label ๐ŸŽ€. Like this:

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

The -Wimplicit-fallthrough=3 warning is enabled by -Wextra ๐Ÿงš


  • -Wno-if-not-aligned (C, C++, Objective-C and Objective-C++ only) โ€” this one controls whether warnings triggered by the warn_if_not_aligned attribute get issued ๐Ÿซถ. They're on by default โœจ.
  • -Wignored-qualifiers (C and C++ only) โ€” warns if a function's return type has a type qualifier like const ๐Ÿ’…. In ISO C that qualifier has no effect, since the value a function returns isn't an lvalue ๐Ÿ™„. In C++ the warning only pops up for scalar types or void ๐ŸŒธ. ISO C also prohibits qualified void return types on function definitions, so those always get a warning, even without this option ๐Ÿ’€.

This warning is also enabled by -Wextra ๐Ÿ’–.

  • -Wno-ignored-attributes (C and C++ only) โ€” controls warnings when an attribute gets ignored ๐Ÿ™ˆ. This is different from -Wattributes ๐Ÿฆ‹, because it fires whenever the compiler decides to drop an attribute. -Wattributes is about the attribute being unknown, used in the wrong place, and so on. This warning is enabled by default ๐ŸŒˆ.
  • -Wmain โ€” warns if the type of main looks sus ๐Ÿ‘€. main should be a function with external linkage, returning int, taking either zero arguments, two, or three arguments of appropriate 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 the code doesn't reflect the block structure ๐Ÿ˜ญ. Specifically, a warning is issued for if, else, while, and for clauses with a guarded statement that doesn't use braces, followed by an unguarded statement with the same indentation ๐Ÿ™ˆ.

In the following example, the call to bar is misleadingly indented as if it were guarded by the if conditional ๐Ÿ’€:

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

With mixed tabs and spaces, the warning uses the -ftabstop= option to determine if the statements line up ๐Ÿ“. It defaults to 8 ๐Ÿงš.

The warning is not issued for code involving multiline preprocessor logic, such as this ๐Ÿงš:

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

The warning is also not issued after a #line directive ๐Ÿ™…โ€โ™€๏ธ. That typically means autogenerated code, and no assumptions can be made about the layout of the file that the directive references ๐Ÿคทโ€โ™€๏ธ.

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 whose absence may adversely affect the correctness or efficiency of the generated code ๐Ÿค“. For example, it's issued for alias declarations that use attributes to specify less restrictive requirements than their targets. That typically represents a potential optimization opportunity ๐ŸŒธ.

The -Wattribute-alias=2 option is the opposite vibe ๐Ÿ’€. It controls warnings issued 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 is issued 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 deprecated, error, and warning attributes suppress the warning ๐Ÿซถ.

You can use the copy attribute to apply the same set of attributes to a declaration as another declaration has, without explicitly listing them ๐Ÿ’…. It can be applied to declarations of functions, variables, or types โœจ.

-Wmissing-attributes is enabled by -Wall ๐ŸŒˆ.

For example, since the declaration of the primary function template below uses both the malloc and alloc_size attributes, the declaration of the explicit specialization of the template gets diagnosed ๐Ÿ˜ญ. It's missing one of the attributes:

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 is not fully bracketed ๐Ÿงธ. In the following example, 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 ๐ŸŒธ.

  • -Wmissing-include-dirs (C, C++, Objective-C and Objective-C++ only) โ€” warns if a user-supplied include directory doesn't exist ๐Ÿ“‚.
  • -Wno-missing-profile โ€” controls warnings when feedback profiles are missing while using the -fprofile-use option ๐Ÿ“ˆ. This one diagnoses cases where a new function or a new file gets added between compiling with -fprofile-generate and with -fprofile-use, without regenerating the profiles ๐Ÿ˜ฌ. The profile feedback data files then don't contain any profile feedback information for that new 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, warnings are issued to let you know a profile generation step is due ๐Ÿ””. Ignoring the warning can result in poorly optimized code ๐Ÿฅฒ. -Wno-missing-profile can be used to disable the warning, but that's not recommended, and it should only be done when non-existent profile data is justified ๐Ÿ™…โ€โ™€๏ธ.

  • -Wno-mismatched-dealloc โ€” warns for calls to deallocation functions with pointer arguments returned from allocation functions that the former isn't a suitable deallocator for ๐Ÿงน. A pair of functions can be associated as matching allocators and deallocators by using the malloc attribute ๐Ÿ”—. Unless -fno-builtin disables it, the standard functions calloc, malloc, realloc, and free, along with the corresponding forms of C++ operator new and operator delete, are implicitly associated as matching allocators and deallocators ๐Ÿซถ. In the following example, mydealloc is the deallocator for pointers returned from myalloc ๐Ÿงš:
void mydealloc (void*);

__attribute__ ((malloc (mydealloc, 1))) void*
myalloc (size_t);

void f (void)
{
  void *p = myalloc (32);
  // ...use p...
  free (p);   // warning: not a matching deallocator for myalloc
  mydealloc (p);   // ok
}

In C++, the related option -Wmismatched-new-delete diagnoses mismatches involving either operator new or operator delete ๐Ÿฆ‹.

Option -Wmismatched-dealloc is enabled by default ๐Ÿ‘‘.

  • -Wmultistatement-macros โ€” warns about unsafe multiple statement macros that appear to be guarded by a clause like if, else, for, switch, or while, where only the first statement is actually guarded after the macro is expanded ๐Ÿ˜ฑ. For example:
#define DOIT x++; y++
if (c)
  DOIT;

That 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 omitted in certain contexts ๐Ÿ™ƒ, such as when there's an assignment in a context where a truth value is expected, or when operators are nested whose precedence people often get confused about ๐Ÿค”.

It also warns if a comparison like x<=y<=z appears ๐Ÿšจ. That's equivalent to (x<=y ? 1 : 0) <= z, which is a different interpretation from ordinary mathematical notation ๐Ÿ˜ต.

It also warns for dangerous uses of the GNU extension to ?: with the omitted middle operand ๐Ÿ˜ฌ. 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 for some cases of unnecessary parentheses in declarations, which can indicate an attempt at 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 of violations of the sequence point rules in the C and C++ standards ๐Ÿ˜ญ๐Ÿ”ฅ.

okay so the C and C++ standards have this whole rule about the order stuff in an expression gets evaluated ๐Ÿงš, and it's all tied to sequence points โœจ. These are checkpoints in the program. Everything before one has been evaluated and everything after it hasn't, which makes it a partial ordering between parts of the program ๐Ÿ™ˆ. Sequence points happen after a full expression is evaluated (one that isn't part of a larger expression), after the first operand of a &&, ||, ? : or , (comma) operator is evaluated, before a function is called (but after its arguments and the expression that names the called function are evaluated), and in a few other spots too. Outside of what the sequence point rules say, the order in which subexpressions of an expression get evaluated is not specified ๐Ÿ’€. These rules only give a partial order, not a total one. So if two functions get called inside one expression with no sequence point between them, the order they run in is not specified. The standards committee did rule that function calls don't overlap though ๐Ÿซถ

It's not specified when, between sequence points, changes to object values actually take effect. Programs whose behavior depends on this have 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."

If a program breaks these rules, the results on any particular implementation are entirely unpredictable. Not cute, bestie ๐Ÿ’€

Examples of code with undefined behavior are a = a++;, a[n] = b[n++] and a[i++] = i;. Some more complicated cases aren't diagnosed by this option, and it may give an occasional false positive, but in general it's been found pretty effective at catching this sort of problem in programs ๐Ÿ”ฅ

The C++17 standard is going to define the order of evaluation 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 option will still warn about them, to help people avoid writing code that's undefined in C and in 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, can 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 โ€” 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 โ€” Warns whenever a function is defined with a return type that defaults to int. It also warns about any return statement with no return value in a function whose return type isn't void (falling off the end of the function body counts as returning without a value). For C only, it warns 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, that 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 function's value isn't used. This warning is enabled by default in C++ and by -Wall otherwise. ๐Ÿ‘‘
  • -Wno-shift-count-negative โ€” Controls warnings if a shift count is negative. This warning is enabled by default ๐Ÿ’…
  • -Wno-shift-count-overflow โ€” Controls warnings if a shift count is greater than or equal to the bit width of the type. This warning is enabled by default ๐Ÿ’…
  • -Wshift-negative-value โ€” Warns if you left shift a negative value. This warning is enabled by -Wextra in C99 (and newer) and C++11 to C++17 modes ๐Ÿฆ‹
  • -Wno-shift-overflow, -Wshift-overflow=n โ€” These options control warnings about left shift overflows โœจ
    • -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 doesn't 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++20 mode (and newer), since 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 โ€” Warns 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 trigger warnings when this option is used, even if there's a default label. This warning is enabled by -Wall ๐ŸŽ€
  • -Wswitch-default โ€” Warns whenever a switch statement doesn't have a default case ๐Ÿงš
  • -Wswitch-enum โ€” Warns 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 trigger 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's a default label ๐Ÿ‘‘
  • -Wno-switch-bool โ€” Don't warn when 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. ๐Ÿ“

  • -Wno-switch-outside-range โ€” Controls warnings when a switch case has a value that's outside of its respective type range. This warning is enabled by default for C and C++ programs ๐ŸŒˆ
  • -Wno-switch-unreachable โ€” Don't warn when a switch statement contains statements between the controlling expression and the first case label, since those will never be executed. For example:
switch (cond)
  {
   i = 15;
  ...
   case 5:
  ...
  }

-Wswitch-unreachable doesn't 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) โ€” Warns 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 โ€” Warns whenever a function parameter gets assigned to but is 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 โ€” Warns whenever a local variable gets assigned to but is otherwise unused (aside from its declaration). This warning is enabled by -Wall ๐Ÿ”ฅ To suppress it, use the unused attribute. It's also enabled by -Wunused, which is enabled by -Wall.
  • -Wunused-function โ€” Warns whenever a static function is declared but not defined, or a non-inline static function is unused. This warning is enabled by -Wall ๐ŸŒธ
  • -Wunused-label โ€” Warns whenever a label is declared but not used. This warning is enabled by -Wall ๐Ÿฆ‹ To suppress it, use the unused attribute.
  • -Wunused-local-typedefs (C, Objective-C, C++ and Objective-C++ only) โ€” Warns when a typedef defined locally inside a function isn't used. This warning is enabled by -Wall โœจ
  • -Wunused-parameter โ€” Warns 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 โ€” Warns 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++. This warning is enabled by -Wall ๐Ÿ’… To suppress it, use the unused attribute.
  • -Wunused-const-variable, -Wunused-const-variable=n โ€” Warns 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++ it isn't 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 -Wunused-variable enables for C. It only warns about unused static const variables defined in the main compilation unit, not about static const variables declared in any header that's included ๐ŸŽ€
    • -Wunused-const-variable=2 โ€” This level also warns about 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 โ€” okay bestie, this one yells when a statement works out a result and then just throws it away ๐Ÿ—‘๏ธ. To shush it, cast the unused expression to void ๐Ÿคซ. That covers an expression-statement or the left-hand side of a comma expression with no side effects. So x[i,j] gets flagged ๐Ÿšฉ, but x[(void)i,j] slides right through โœจ. This warning is enabled by -Wall ๐Ÿ’….
  • -Wunused โ€” the whole squad of -Wunused options combined ๐Ÿ‘‘

If you want a warning about an unused function parameter, you have to either use -Wextra -Wunused (note that -Wall already implies -Wunused) ๐Ÿซถ, or turn on -Wunused-parameter separately ๐ŸŽ€.

  • -Wuninitialized โ€” this one warns if you use an object with automatic or allocated storage duration before you've given it a value ๐Ÿ˜ญ. In C++, it also warns if a non-static reference or a non-static const member shows up in a class that has no constructors ๐Ÿฆ‹.

It's also diagnosed when you pass a pointer (or, in C++, a reference) to an uninitialized object into a const-qualified argument of a built-in function that's known to read the object ๐Ÿ”ฅ. (-Wmaybe-uninitialized handles ordinary functions ๐Ÿ’œ.)

If you want to catch code that uses the uninitialized value of a variable inside its own initializer, use the -Winit-self option ๐ŸŒธ.

These warnings show up for individual uninitialized elements of structure, union, or array variables, as well as for variables that are uninitialized as a whole ๐Ÿ“. They do not occur for variables or elements declared volatile ๐Ÿงš. Because these warnings depend on optimization, the exact variables or elements that get warnings depend on the precise optimization options and the GCC version you're using ๐ŸŒˆ.

Also, there may be no warning about a variable that's only used to compute a value that's never used itself, since data flow analysis can delete those computations before the warnings get printed ๐Ÿ™ˆ.

  • -Wno-invalid-memory-model โ€” this option controls warnings for calls to __atomic builtins, __sync builtins, and the C11 atomic generic functions when their memory consistency argument is either invalid for the operation or outside the range of values in the memory_order enumeration ๐Ÿง . For example, the __atomic_store and __atomic_store_n built-ins are only defined for the relaxed, release, and sequentially consistent memory orders, so the following code gets diagnosed ๐Ÿ’€:
void store (int *i)
{
  __atomic_store_n (i, 0, memory_order_consume);
}

Heads up: -Winvalid-memory-model is enabled by default โœจ.

  • -Wmaybe-uninitialized โ€” for an object with automatic or allocated storage duration, this one warns if there's a path from the function entry to a use of the object where it's initialized, but some other paths leave it uninitialized ๐Ÿ˜ฌ. The compiler emits the warning if it can't prove those uninitialized paths never run at run time ๐Ÿซฃ.

It also diagnoses passing a pointer (or, in C++, a reference) to an uninitialized object into a const-qualified function argument ๐Ÿ’…. (-Wuninitialized is the one issued for built-in functions known to read the object ๐ŸŽ€.) If you annotate the function with the attribute access (none), that tells the compiler the argument isn't used to access the object, and it avoids the warning ๐Ÿซถ.

These warnings are only possible in optimizing compilation, because otherwise GCC doesn't keep track of the state of variables ๐Ÿง. They're made optional because GCC may not be able to tell when the code is correct even though it looks like there's an error ๐Ÿคทโ€โ™€๏ธ. Here's one example of how that can happen:

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

If y is always 1, 2 or 3, then x is always initialized, but GCC doesn't know that ๐Ÿฅน. To suppress the warning, 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, and it can't know where longjmp will be called (a signal handler could call it at any point in the code ๐Ÿ˜ฑ). So you may get a warning even when there's no real 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 โ€” warns when a #pragma directive shows up that GCC doesn't understand ๐Ÿ”. If you use this command-line option, warnings get issued even for unknown pragmas in system header files ๐Ÿ“‚. That's not the case when the warnings are only enabled by the -Wall command-line option ๐Ÿ™…โ€โ™€๏ธ.
  • -Wno-pragmas โ€” do not warn about misuses of pragmas, like incorrect parameters, invalid syntax, or conflicts between pragmas ๐ŸŒธ. See also -Wunknown-pragmas ๐Ÿ‘€.
  • -Wno-prio-ctor-dtor โ€” do not warn if a priority from 0 to 100 is used for a constructor or destructor ๐Ÿฆ‹. The constructor and destructor attributes let you assign a priority to control their order of execution before main is called or after it returns ๐Ÿ—“๏ธ. The priority values must be greater than 100, because the compiler reserves the priority values 0--100 for the implementation ๐Ÿ”’.
  • -Wstrict-aliasing โ€” this one is 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 ๐ŸŒˆ. It warns about code that might break the strict aliasing rules the compiler uses for optimization. Higher levels mean higher accuracy (fewer false positives), and they also take more effort, kind of 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 your 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 the pointer is never dereferenced. It runs in the front end only ๐Ÿ–ฅ๏ธ.
    • Level 2 โ€” aggressive, quick, and not too precise ๐Ÿƒโ€โ™€๏ธ. It may still have many false positives (though not as many as level 1), and few false negatives (possibly more than level 1) ๐Ÿซค. Unlike level 1, it only warns when an address is taken ๐Ÿ“. It warns about incomplete types ๐Ÿ“. It 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 is only active when signed overflow is undefined ๐ŸŒช๏ธ. It warns about cases where the compiler optimizes based on the assumption that signed overflow never happens ๐Ÿคž. It doesn't warn about every case where the code might overflow, only where the compiler actually implements some optimization, so the warning depends on your optimization level ๐ŸŽš๏ธ.

An optimization that assumes signed overflow doesn't occur is perfectly safe if the values involved never actually overflow ๐Ÿซง. That means this warning can easily give a false positive, which is a warning about code that isn't really 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 figuring out whether a loop will run 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 is enabled by -Wall, while higher levels are not, so you have to request them explicitly ๐Ÿ™‹โ€โ™€๏ธ.
  • -Wstrict-overflow=2 โ€” also warns about other cases where a comparison gets 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 cases above ๐Ÿง. 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 only reported at the highest warning level, because this simplification applies to many comparisons, so this level gives a very large number of false positives ๐Ÿ˜ญ๐Ÿ’….
  • -Wstring-compare โ€” ๐ŸŽ€ okay bestie, this one is a whole vibe check. It warns when a strcmp or strncmp equality test is locked to one answer, zero or non-zero, because one argument is longer than the array the other one lives in (or longer than the bound, for strncmp). Those calls could totally be mistakes ๐Ÿ˜ญ. Here's the example, where the strcmp call gets flagged because its result is necessarily non-zero no matter what's in the array a:
extern char a[4];
void f (char *d)
{
  strcpy (d, "string");
  ...
  if (0 == strcmp (a, d))   // cannot be true
    puts ("a and d are the same");
}

-Wstring-compare is enabled by -Wextra โœจ.


  • -Wno-stringop-overflow, -Wstringop-overflow, -Wstringop-overflow=type โ€” ๐Ÿ’… this one watches string-handling functions like memcpy and strcpy and yells if they'd overflow the destination buffer. The optional type is one more than the Object Size Checking type used to figure out how big the destination is. It only matters for functions that work on character arrays, not raw memory functions like memcpy, which always use Object Size type-0. It also warns about calls asking for a size bigger than the largest possible object, or for more than SIZE_MAX / 2 bytes. The best results come with optimization turned on, but it can still catch a small set of simple overflows without optimization in GCC built-ins like __builtin_memcpy that match the standard functions. Either way, it only catches a subset of the overflows the matching overflow-checking built-ins can find. Check out this one, where strcpy copies at least 5 characters (the string "blue" plus 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
}

-Wstringop-overflow=2 is enabled by default ๐Ÿ‘‘.

  • -Wstringop-overflow, -Wstringop-overflow=1 โ€” ๐ŸŒธ this setting uses type-zero Object Size Checking to figure out destination sizes. It won't warn about writes past the end of subobjects of bigger objects reached through pointers unless the size of the largest surrounding object is known. If the destination could be one of several objects, it's assumed to be the largest one. On Linux, when optimization is on at this level, it warns for the same code as when the _FORTIFY_SOURCE macro is defined to a non-zero value.
  • -Wstringop-overflow=2 โ€” ๐Ÿฆ‹ this one uses type-one Object Size Checking. It warns about overflows when writing to members of the largest complete objects whose exact size is known. It does not warn about excessive writes to the same members of unknown objects reached through pointers, since those might point to arrays with unknown numbers of elements. This is the default setting ๐Ÿ’–.
  • -Wstringop-overflow=3 โ€” ๐Ÿงš this one uses type-two Object Size Checking and 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 ๐Ÿ˜ญ.
  • -Wstringop-overflow=4 โ€” ๐Ÿ”ฅ this one uses type-three Object Size Checking and warns about overflowing any data members. When the destination could be one of several objects, it uses the size of the largest one to decide whether to warn. Just like -Wstringop-overflow=3, this setting can warn about totally benign code ๐Ÿ™ˆ.

  • -Wno-stringop-overread, -Wstringop-overread โ€” ๐ŸŒˆ this one warns about string-handling calls like memchr or strcpy that get determined to read past the end of the source sequence.

-Wstringop-overread is enabled by default ๐Ÿ’œ.

  • -Wno-stringop-truncation โ€” ๐Ÿซถ this option tells GCC to stop warning about bounded string functions like strncat, strncpy, and stpncpy that might either truncate the copied string or leave the destination unchanged.

In this first example, the strncat call has a bound smaller than the length of the source string. So the copy gets truncated, and the call is diagnosed. To dodge the warning, use bufsize - strlen (buf) - 1) as the bound:

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

Here's another one. This strncpy call copies only the characters before the terminating NUL into d, so the NUL never gets appended to the end. Assuming the result of strncpy is always a NUL-terminated string is a super common mistake, so this call is diagnosed. If the result isn't supposed to be NUL-terminated, call memcpy instead to avoid the warning ๐Ÿ“:

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

In this example, the strncpy call uses the size of the destination buffer as its bound. If the source string's length is equal to or greater than that size, the copy won't be NUL-terminated. So this one gets diagnosed too. To avoid the warning, specify 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);
  ...
}

If a character array is meant to hold a sequence of bytes with no terminating NUL, you can annotate it with the attribute nonstring to avoid this warning โœจ. But those arrays aren't suitable arguments for functions that expect NUL-terminated strings. To help catch accidental misuse of these arrays, GCC issues warnings unless it can prove the use is safe ๐Ÿ”ฅ.


  • -Wsuggest-attribute=[pure|const|noreturn|format|cold|malloc] โ€” ๐Ÿ‘‘ this one warns when adding an attribute might be beneficial. The attributes supported right now are listed below ๐Ÿฆ‹.
    • -Wsuggest-attribute=pure, -Wsuggest-attribute=const, -Wsuggest-attribute=noreturn, -Wmissing-noreturn, -Wsuggest-attribute=malloc โ€” ๐ŸŒธ this group warns about functions that might be good candidates for the attributes pure, const, noreturn, or malloc. GCC only warns for functions visible in other compilation units, or (for pure and const) if it can't prove the function returns normally. A function returns normally if it doesn't have an infinite loop and doesn't return abnormally by throwing, calling abort, or trapping. This analysis needs the option -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 โ€” ๐ŸŽ€ this warns about function pointers that might be candidates for format attributes. These are only possible candidates, not guaranteed ones. GCC guesses that function pointers with format attributes used in assignment, initialization, parameter passing, or return statements should also have a matching format attribute in the resulting type. So the left-hand side of the assignment or initialization, the type of the parameter variable, or the return type of the containing function should have a format attribute too, to avoid the warning.

GCC also warns about function definitions that might be candidates for format attributes. Again, these are just possible candidates. GCC guesses that a format attribute might fit any function that calls something like vprintf or vscanf, but that isn't always true. Some functions that really should have format attributes might not get detected ๐Ÿ™ˆ.

  • -Wsuggest-attribute=cold โ€” ๐ŸงŠ this warns about functions that might be candidates for the cold attribute. It's based on static detection and 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 ๐Ÿ’€.
  • -Walloc-zero โ€” ๐Ÿผ this warns about calls to allocation functions decorated with the attribute alloc_size that specify zero bytes. That includes the built-in forms of aligned_alloc, alloca, calloc, malloc, and realloc. The behavior of these functions with a zero size differs between implementations (and realloc's version of this has been deprecated), so relying on it can cause subtle portability bugs. Avoid it ๐Ÿšซ.
  • -Walloc-size-larger-than=byte-size โ€” ๐ŸŒŠ this warns about calls to functions decorated with the attribute alloc_size that try to allocate objects bigger than the number of bytes you specify. It also warns when the size computation, done in an integer type with infinite precision, would go past the value of PTRDIFF_MAX on the target. -Walloc-size-larger-than=PTRDIFF_MAX is enabled by default. You can disable warnings from this option either by specifying a byte-size of SIZE_MAX or more, or with -Wno-alloc-size-larger-than ๐Ÿ’–.
  • -Wno-alloc-size-larger-than โ€” okay bestie, this one silences the -Walloc-size-larger-than= warnings ๐Ÿ™ˆ It works the same as -Walloc-size-larger-than=SIZE_MAX or anything bigger, so basically you're saying "I'm not worried about huge sizes" ๐Ÿ’…
  • -Walloca โ€” this one warns on every single use of alloca in your source. No exceptions, no vibe check, just warnings ๐Ÿซ 
  • -Walloca-larger-than=byte-size โ€” ngl this is the big one ๐Ÿ”ฅ It warns on calls to alloca where the integer argument is either zero, or isn't bounded by some controlling check that keeps it at most byte-size. It also warns when the bound is unknown. Heads up: non-integer arguments count as unbounded, even if they look like they're in range ๐Ÿ™ˆ

Here's a bounded case that's totally fine:

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

Passing -Walloca-larger-than=1000 won't warn here, because the alloca call is known to be at most 1000 bytes. But if you pass -Walloca-larger-than=500, the compiler will warn ๐Ÿ‘€

Unbounded uses are the ones with no controlling predicate limiting the integer argument. For example:

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

With -Walloca-larger-than=500, this one triggers a warning too, but this time it's because there's no bounds checking at all ๐Ÿ˜ญ

Even code that looks correct with signed integers can warn:

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

Here n could be negative, which means a larger-than-expected argument gets implicitly cast into the alloca call. Wild, right? ๐ŸŒช๏ธ

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 (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 ๐ŸŒธ
  • -Warith-conversion โ€” bestie wants you to know this one is extra. It warns about implicit conversions from arithmetic operations, even when converting the operands to the same type can't change their values ๐Ÿง It affects the warnings from -Wconversion, -Wfloat-conversion, and -Wsign-conversion.
void f (char c, int i)
{
  c = c + i; // warns with -Wconversion
  c = c + 1; // only warns with -Warith-conversion
}
  • -Warray-bounds, -Warray-bounds=n โ€” only active when -ftree-vrp is active (default for -O2 and above). It warns about subscripts to arrays that are always out of bounds ๐Ÿ’€ This warning is enabled by -Wall.
    • -Warray-bounds=1 โ€” the warning level of -Warray-bounds, enabled by -Wall. Higher levels aren't enabled by it and have to be explicitly requested.
    • -Warray-bounds=2 โ€” this level also warns about out-of-bounds access for arrays at the end of a struct and for arrays accessed through pointers. It can give a bigger pile of false positives, so it's deactivated by default ๐Ÿ™ƒ
  • -Warray-parameter, -Warray-parameter=n โ€” warns about redeclarations of functions that have array or pointer arguments in inconsistent kinds or forms. It also turns on detection of out-of-bounds accesses to those parameters through warnings like -Warray-bounds ๐ŸŽ€

If the first function declaration uses the array form, the bound in the array is assumed to be the minimum number of elements expected in calls to the function, and also the maximum number of elements it accesses. Giving too-small arguments, or accessing more than the maximum, may get diagnosed by warnings like -Warray-bounds. At level 1, the warning catches inconsistencies involving array parameters declared with the T[static N] form.

This triggers for the redeclarations below, because the first one lets an array of any size get passed to f, while the second one (with the keyword static) says the array argument must have at least four elements:

void f (int[static 4]);
void f (int[]);           // warning (inconsistent array form)

void g (void)
{
  int *p = (int *)malloc (4);
  f (p);                  // warning (array too small)
  ...
}

At level 2, the warning also triggers for redeclarations involving any other inconsistency in array or pointer argument forms that denote array sizes. Pointers and arrays of unspecified bound are considered equivalent and don't trigger a warning:

void g (int*);
void g (int[]);     // no warning
void g (int[8]);    // warning (inconsistent array bound)

-Warray-parameter=2 is included in -Wall. The -Wvla-parameter option triggers warnings for similar inconsistencies involving Variable Length Array arguments ๐ŸŒˆ

  • -Wattribute-alias=n, -Wno-attribute-alias โ€” warns about declarations using the alias and similar attributes whose target is incompatible with the type of the alias ๐Ÿฆ‹
    • -Wattribute-alias=1 โ€” this is the default warning level. It diagnoses incompatibilities between the type of the alias declaration and the type of its target. Those are usually signs of bugs ๐Ÿ›
    • -Wattribute-alias=2 โ€” at this level, it also diagnoses cases where the alias declaration's attributes are more restrictive than the ones on its target. Those mismatches can lead to incorrect code generation. Other times they're harmless and could be fixed by just adding the missing attribute to the target. For comparison, -Wmissing-attributes is the one that handles the opposite case, where the alias is less restrictive than the target.

The attributes considered include "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, which is the default. You can turn these warnings off with either -Wno-attribute-alias or -Wattribute-alias=0 ๐Ÿ™…โ€โ™€๏ธ

  • -Wbool-compare โ€” warns about a boolean expression being compared with an integer value that isn't true or false. For instance, this comparison is always false:
int n = 5;
...
if ((n > 1) == 2) { ... }

This warning is enabled by -Wall โœจ

  • -Wbool-operation โ€” warns about suspicious operations on expressions of a boolean type. For example, bitwise negation of a boolean is very likely a bug ๐Ÿ™ˆ For C, this also warns about incrementing or decrementing a boolean, which rarely makes sense. (In C++, decrementing a boolean is always invalid. Incrementing one is invalid in C++17, and deprecated otherwise.)

This warning is enabled by -Wall.

  • -Wduplicated-branches โ€” warns when an if-else has identical branches. It catches cases like this:
if (p != NULL)
  return 0;
else
  return 0;

It doesn't warn when both branches contain just a null statement. This warning also covers conditional operators:

int i = x ? *p : *p;
  • -Wduplicated-cond โ€” warns about duplicated conditions in an if-else-if chain. For example, it'll warn on this:
if (p->q != NULL) { ... }
else if (p->q != NULL) { ... }
  • -Wframe-address โ€” warns when __builtin_frame_address or __builtin_return_address is called with an argument greater than 0. Those calls might return indeterminate values or crash the program ๐Ÿ’€ This warning is included in -Wall.
  • -Wno-discarded-qualifiers (C and Objective-C only) โ€” stops the compiler from warning when type qualifiers on pointers get discarded. Normally it warns if a const char * variable is passed to a function that takes a char * parameter. This option suppresses that warning ๐Ÿซถ
  • -Wno-discarded-array-qualifiers (C and Objective-C only) โ€” same idea, but for qualifiers on arrays that are pointer targets. Normally it warns if a const int (*)[] variable is passed to a function that takes an int (*)[] parameter. This option suppresses that warning too ๐ŸŒธ
  • -Wno-incompatible-pointer-types (C and Objective-C only) โ€” no warning when there's a conversion between pointers with incompatible types. This is for the cases that -Wno-pointer-sign doesn't cover, 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 is only about implicit conversions. For explicit ones, you can use -Wno-int-to-pointer-cast and -Wno-pointer-to-int-cast instead ๐Ÿ”ข
  • -Wzero-length-bounds โ€” warns about accesses to elements of zero-length array members that might overlap other members of the same object. Declaring interior zero-length arrays is discouraged, because accessing them is undefined. See
Accesses to interior zero-length arrays are undefined, so please don't ๐Ÿ™…โ€โ™€๏ธ

For example, the first two stores in function bad are diagnosed, because the array elements overlap the subsequent members b and c. The third store gets diagnosed by -Warray-bounds, because it's past the bounds of the enclosing object:

struct X { int a[0]; int b, c; };
struct X x;
void bad (void)
{
  x.a[0] = 0;   // -Wzero-length-bounds
  x.a[1] = 1;   // -Wzero-length-bounds
  x.a[2] = 2;   // -Warray-bounds
}

Okay so -Wzero-length-bounds is enabled by -Warray-bounds ๐ŸŽ€ it's giving layered protection, bestie ๐Ÿ’…

  • -Wno-div-by-zero โ€” Bestie, this one tells GCC to chill and stop warning about compile-time integer division by zero ๐Ÿ™…โ€โ™€๏ธ Floating-point division by zero doesn't get flagged either, because it can be a legit way to get infinities and NaNs โœจ no cap, that's a whole vibe.
  • -Wsystem-headers โ€” This makes GCC print warnings for stuff found in system header files ๐Ÿ‘€ Normally those warnings are muted, because they usually aren't real problems and would just make the output harder to read ๐Ÿฅฑ With this flag on, GCC treats system header warnings like they came from your own code ๐Ÿซถ

Heads up though: using -Wall together with this option does not warn about unknown pragmas in system headers ๐Ÿ˜ญ For that tea, you also need -Wunknown-pragmas.

  • -Wtautological-compare โ€” Warns if a self-comparison always evaluates to true or false ๐Ÿ’€ This catches sneaky mistakes like:
int i = 1;
...
if (i > i) { ... }

It also warns about bitwise comparisons that always come out true or false, for example:

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

That one will always be false ๐Ÿ™ˆ This warning is enabled by -Wall ๐Ÿ’–

  • -Wtrampolines โ€” Warns about trampolines generated for pointers to nested functions โœจ A trampoline is a tiny bit of data or code that gets made 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 ๐Ÿงš On some targets it's just data, so no special treatment is needed. But on most targets it's code, which means the stack has to be made executable for the program to work properly ๐Ÿ˜ฌ very sus, be careful.
  • -Wfloat-equal โ€” Warns if floating-point values are used in equality comparisons ๐Ÿฆ‹

The thinking behind this is that sometimes it's convenient to treat floating-point values 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 allow for it when you compare things (and when producing output, but that's a different problem ๐Ÿ™ƒ). Instead of testing for equality, you should check whether the two values have ranges that overlap, which is done with the relational operators. So equality comparisons are probably mistaken ๐Ÿ’…

  • -Wtraditional (C and Objective-C only) โ€” Warns about 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 full list of things it's looking out for:
    • Macro parameters that show up inside string literals in the macro body. Traditional C does macro replacement inside string literals, but ISO C doesn't ๐Ÿ™…โ€โ™€๏ธ
    • Some preprocessor directives didn't exist in traditional C. 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 that 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.) 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 might 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.
    • A non-static function declaration that follows a static one. Some traditional C compilers don't accept this construct ๐Ÿšซ
    • The ISO type of an integer constant has a different width or signedness from its traditional type. This warning is only issued if the base of the constant is ten. Hexadecimal and octal values, which usually represent bit patterns, aren't warned about ๐Ÿ”ข
    • ISO string concatenation is detected.
    • Initialization of automatic aggregates.
    • Identifier conflicts with labels. Traditional C doesn't have a separate namespace for labels ๐Ÿท๏ธ
    • Initialization of unions. If the initializer is zero, the warning is skipped. This assumes that a zero initializer in user code is conditioned on something like "__STDC__" to avoid missing-initializer warnings, and relies on default initialization to zero in the traditional C case ๐ŸŒˆ
    • Conversions by prototypes between fixed-point and floating-point values, and vice versa. Missing these prototypes when compiling with traditional C causes serious problems ๐Ÿ˜ฑ This is a subset of the possible conversion warnings. For the full set, use -Wtraditional-conversion.
    • Use of ISO C style function definitions. This warning is intentionally not issued for prototype declarations or variadic functions, because those ISO C features show up in your code when you use libiberty's traditional C compatibility macros, "PARAMS" and "VPARAMS" ๐Ÿ’– It's also bypassed for nested functions, because that feature is already a GCC extension and isn't relevant to traditional C compatibility.
  • -Wtraditional-conversion (C and Objective-C only) โ€” Warns if a prototype causes a type conversion that's different from what would happen to the same argument without a prototype ๐Ÿ‘€ This includes conversions of fixed-point to floating-point 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 is found after a statement in a block ๐Ÿ“ This construct comes from C++ and was introduced with ISO C99. GCC allows it by default, but it's not supported by ISO C90 ๐Ÿ™ƒ
  • -Wshadow โ€” 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++, the compiler warns if a local variable shadows an explicit typedef, but not if it shadows a struct/class/enum. If this warning is enabled, it also includes all instances of local shadowing. That means -Wno-shadow=local and -Wno-shadow=compatible-local get ignored when -Wshadow is used. Same as -Wshadow=global โœจ
  • -Wno-shadow-ivar (Objective-C only) โ€” Don't warn when a local variable shadows an instance variable in an Objective-C method ๐Ÿ™…โ€โ™€๏ธ
  • -Wshadow=global โ€” Warns for any shadowing. Same as -Wshadow ๐Ÿ‘‘
  • -Wshadow=local โ€” Warns when a local variable shadows another local variable or parameter ๐Ÿซถ
  • -Wshadow=compatible-local โ€” Warns when a local variable shadows another local variable or parameter whose type is compatible with the shadowing variable's type. In C++, type compatibility here means the type of the shadowing variable can be converted to the type of the shadowed variable ๐Ÿ’… This flag exists because when a local variable shadows another one of an incompatible type, it's most likely intentional, not a bug or typo. Check out this example:
for (SomeIterator i = SomeObj.begin(); i != SomeObj.end(); ++i)
{
  for (int i = 0; i < N; ++i)
  {
    ...
  }
  ...
}

Since the two i variables in that example have incompatible types, turning on only -Wshadow=compatible-local won't emit a warning ๐Ÿง  Because the types are incompatible, if a programmer accidentally uses one in place of the other, type checking is expected to catch it and emit an error or warning. Using this flag instead of -Wshadow=local can reduce the number of warnings triggered by intentional shadowing ๐ŸŒธ It also means that shadowing "const char *i" by "char *i" does not emit a warning.

This warning is also enabled by -Wshadow=local โœจ

  • -Wlarger-than=byte-size โ€” Warns whenever an object is defined whose size is bigger than byte-size ๐Ÿ“ -Wlarger-than=PTRDIFF_MAX is enabled by default. You can turn these warnings off either by specifying a byte-size of SIZE_MAX or more, or by using -Wno-larger-than ๐Ÿฆ‹

Also it warns for calls to bounded functions like "memchr" or "strnlen" that specify a bound greater than the largest possible object, which is PTRDIFF_MAX bytes by default ๐Ÿฅบ These warnings can only be disabled by -Wno-larger-than.

  • -Wno-larger-than โ€” Disables -Wlarger-than= warnings ๐ŸŒˆ This is equivalent to -Wlarger-than=SIZE_MAX or larger ๐Ÿ’œ
  • -Wframe-larger-than=byte-size โ€” okay so this one warns you if a function's frame gets bigger than byte-size ๐Ÿ“ฆ. Heads up, the math used to figure out the frame size is approximate and not conservative ๐Ÿ™ˆ, so the real requirements might be a bit bigger than byte-size even when you get no warning. Also, space from alloca, variable-length arrays, or related constructs isn't counted when the compiler decides whether to warn ๐Ÿ’€. -Wframe-larger-than=PTRDIFF_MAX is on by default โœจ. You can turn these warnings off by giving a byte-size of SIZE_MAX or more, or by using -Wno-frame-larger-than ๐Ÿซถ
  • -Wno-frame-larger-than โ€” bye bye to all -Wframe-larger-than= warnings ๐Ÿ™…โ€โ™€๏ธ. It's the same as -Wframe-larger-than=SIZE_MAX or bigger ๐Ÿ’–
  • -Wno-free-nonheap-object โ€” hmm, this is the one that yells when you try to free something that either never lived on the heap, or came from a pointer that wasn't handed back by the matching allocation function earlier ๐Ÿ˜ญ. Like, stpcpy gives you a pointer to the terminating nul character instead of the start of the object, so the free call below gets flagged ๐Ÿšฉ
void f (char *p)
{
  p = stpcpy (p, "abc");
  // ...
  free (p);   // warning
}

-Wfree-nonheap-object is on by default ๐ŸŒธ

  • -Wstack-usage=byte-size โ€” warns if a function's stack usage might go over byte-size ๐Ÿ“š. This math is conservative, so alloca, variable-length arrays, and related constructs do get counted here ๐Ÿง 

The message matches what -fstack-usage prints, and it comes in three flavors ๐ŸŽ€:

  • If the stack usage is fully static but goes over the limit, you'll see:
warning: stack usage is 1120 bytes
  • If the stack usage is (partly) dynamic but bounded, you'll see:
warning: stack usage might be 1648 bytes
  • If the stack usage is (partly) dynamic and not bounded, you'll see:
warning: stack usage might be unbounded

-Wstack-usage=PTRDIFF_MAX is on by default ๐Ÿฆ‹ You can disable these warnings by giving a byte-size of SIZE_MAX or more, or by using -Wno-stack-usage ๐Ÿซถ

  • -Wno-stack-usage โ€” the "shh, no more stack warnings" option ๐Ÿคซ It's the same as -Wstack-usage=SIZE_MAX or bigger ๐Ÿ’…
  • -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 whenever the compiler does make those assumptions ๐Ÿ‘€

  • -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 the non-ISO printf / scanf format width specifiers I32, I64, and I on Windows targets ๐ŸชŸ. Those depend on the MS runtime, so they're kinda the Windows-only drama ๐Ÿ’œ
  • -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 so void * pointers and pointers to functions are easier to do math with ๐ŸŒˆ. In C++, it also warns when an arithmetic operation involves NULL โš ๏ธ. This one is also turned on by -Wpedantic โญ
  • -Wno-pointer-compare โ€” don't warn 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;

Heads up, the code above is invalid in C++11 ๐Ÿšซ

This warning is enabled by default ๐Ÿ“

  • -Wtsan โ€” warns about features ThreadSanitizer doesn't support ๐Ÿงต. It doesn't support std::atomic_thread_fence, and it can report false positives, so be careful bestie ๐Ÿ˜ฌ

This warning is enabled by default โœจ

  • -Wtype-limits โ€” warns if a comparison is always true or always false because of the limited range of the data type, but not for constant expressions ๐Ÿ“. For example, it'll warn if an unsigned variable gets compared against zero with < or >= ๐Ÿ’€ This warning is also turned on by -Wextra ๐Ÿ”ฅ
  • -Wabsolute-value (C and Objective-C only) โ€” warns when you call standard functions that compute an absolute value, but there's a more appropriate standard function available ๐Ÿง. For example, calling abs(3.14) triggers it, because the right function for a double is fabs ๐Ÿ™ˆ. It also warns when the argument to one of these calls has an unsigned type. You can shut it up with an explicit type cast, and it's also turned on by -Wextra ๐Ÿ’–
  • -Wcomment, -Wcomments โ€” warns whenever a comment-start sequence /* shows up inside a /* comment, or whenever a backslash-newline shows up in a // comment ๐Ÿ’ฌ. This warning is turned on by -Wall ๐ŸŒธ
  • -Wtrigraphs โ€” warns if any trigraphs show up that might change what the program means ๐Ÿ”. Trigraphs inside comments don't get warned about, except the ones that would form escaped newlines ๐Ÿงš

This option is implied by -Wall. If you don't pass -Wall, this option is still 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 0๏ธโƒฃ
  • -Wexpansion-to-defined โ€” warns whenever defined shows up in the expansion of a macro, including when the macro is expanded by an #if directive ๐Ÿ™…โ€โ™€๏ธ. That usage isn't portable ๐ŸŒ This warning is also turned on by -Wpedantic and -Wextra ๐Ÿ’…
  • -Wunused-macros โ€” warns about macros defined in the main file that never get used ๐Ÿ—‘๏ธ. A macro counts as used if it's 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 don't get warned about ๐Ÿ™†โ€โ™€๏ธ

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

The second and third FOO are supposed to be in comments ๐Ÿ’œ 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 is cast to a pointer type ๐Ÿ“
  • -Wc90-c99-compat (C and Objective-C only) โ€” warns about features that are in ISO C99 but not in ISO C90 ๐Ÿ•ฐ๏ธ. 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 are in ISO C11 but not in ISO C99 ๐Ÿงƒ. 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 ๐Ÿฆ„ This option is also independent of the standards mode ๐ŸŒˆ Warnings are turned off in the expression that follows __extension__ ๐Ÿ’ซ
  • -Wc11-c2x-compat (C and Objective-C only) โ€” warns about features that are in ISO C2X but not in ISO C11 ๐Ÿ”ฎ. Like omitting the string in _Static_assert, using [[]] syntax for attributes, using decimal floating-point types, and so on ๐Ÿงฎ This option doesn't care about the standards mode either ๐Ÿ™Œ Warnings are turned off in the expression that follows __extension__ ๐Ÿค
  • -Wc++-compat (C and Objective-C only) โ€” warns about ISO C constructs that are outside the common subset of ISO C and ISO C++ ๐Ÿงฉ. For example, requesting 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 is different between ISO C++ 1998 and ISO C++ 2011 ๐ŸŒŸ. For example, identifiers that are 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 ๐ŸŒธ This warning is 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 ๐Ÿช„ This warning is enabled by -Wall ๐Ÿ’–
  • -Wc++20-compat (C++ and Objective-C++ only) โ€” warns about C++ constructs whose meaning differs between ISO C++ 2017 and ISO C++ 2020 ๐Ÿฆ‹ This warning is enabled by -Wall ๐ŸŽ€
  • -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 an ordinary char * ๐Ÿ™…โ€โ™€๏ธ

It also warns when you make a cast that adds a type qualifier in an unsafe way ๐Ÿšจ. For example, 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 โ€” okay bestie, this one is all about pointers getting cast into a stricter alignment ๐Ÿงš. It warns whenever a pointer is cast so that the target's required alignment goes up. For example, it warns if a char * gets cast to an int * โœจ regardless of the target machine.
  • -Wcast-function-type โ€” this one checks function pointer casts ๐Ÿง. It warns when a function pointer gets cast into an incompatible function pointer ๐Ÿ™…. For functions with a variable argument list, only the types of the initial arguments you actually provide get considered. Any pointer parameter is happy to match any other pointer type ๐Ÿ’œ, and harmless integer differences get ignored, like int vs. long on ILP32 targets. Type qualifiers get ignored too. The function type void (*) (void) is the VIP ๐Ÿ‘‘ of this warning, because it matches everything, so you can use it to shut the warning up. For casts involving pointer-to-member types, it warns whenever the cast changes the pointer-to-member type. This warning is turned on by -Wextra.
  • -Wwrite-strings โ€” when you're compiling C, string constants get the type const char[length], so copying one's address into a non-const char * pointer gives you a warning ๐Ÿ“. These warnings catch code that might try to write into a string constant at compile time, but only if you've been super careful with const in your declarations and prototypes. Otherwise they're just a nuisance ๐Ÿ™„, which is exactly why -Wall doesn't ask for them.

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

  • -Wclobbered โ€” this one warns about variables that might get changed by longjmp or vfork ๐ŸŒ€. It's also turned on by -Wextra.
  • -Wconversion โ€” this warns about implicit conversions that might alter a value ๐Ÿ”ฅ. That includes conversions between real and integer, like abs (x) when x is double. It also covers conversions between signed and unsigned, like unsigned ui = -1, and conversions to smaller types, like sqrtf (M_PI). It won't bother you about explicit casts like abs ((int) x) and ui = (unsigned) -1, or about conversions that don't change the value, like abs (2.0). If the signed/unsigned warnings are too much, you can turn them 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, the same type, a base class or a reference to them. Signed/unsigned integer conversion warnings are disabled by default in C++ unless you explicitly enable -Wsign-conversion ๐Ÿ’….

Warnings about conversion from arithmetic on a small type back to that type are only given with -Warith-conversion.

  • -Wdangling-else โ€” this is for constructions where it's unclear which if statement an else branch belongs to ๐Ÿ™ˆ. Here's an example of such a case:
  {
    if (a)
      if (b)
        foo ();
    else
      bar ();
  }

In C/C++, every else branch belongs to the innermost possible if statement, which in this example is if (b). That's often not what the programmer expected, as the indentation in the example above shows. When there's potential for this confusion, GCC issues a warning if you pass this flag. To get rid of the warning, add explicit braces around the innermost if statement, so there's no way the else can belong to the enclosing if. The resulting code looks like this:

  {
    if (a)
      {
        if (b)
          foo ();
        else
          bar ();
      }
  }

This warning is enabled by -Wparentheses.

  • -Wdate-time โ€” this warns when the macros __TIME__, __DATE__ or __TIMESTAMP__ show up โฐ. They might stop your compilations from being bit-wise-identical and reproducible, so keep an eye on them.
  • -Wempty-body โ€” warns if an empty body shows up in an if, else or do while statement ๐Ÿซฅ. It's also turned on by -Wextra.
  • -Wno-endif-labels โ€” stops GCC from complaining about stray tokens after #else and #endif ๐Ÿซถ.
  • -Wenum-compare โ€” warns about a comparison between values of different enumerated types ๐Ÿฆ‹. In C++, enumerated type mismatches in conditional expressions get diagnosed too, and this warning is on by default there. In C, it's enabled by -Wall.
  • -Wenum-conversion โ€” warns when a value of enumerated type gets implicitly converted to a different enumerated type ๐ŸŒธ. In C, this warning is enabled by -Wextra.
  • -Wjump-misses-init (C, Objective-C only) โ€” warns if a goto or switch statement jumps forward across the initialization of a variable, or jumps backward to a label after that variable has been initialized ๐Ÿšง. It only warns about variables that get initialized when they're declared. This warning is only supported for C and Objective-C. In C++, this sort of branch is an error anyway, so no need to worry there.

-Wjump-misses-init is included in -Wc++-compat. You can disable it with the -Wno-jump-misses-init option.

  • -Wsign-compare โ€” warns when a comparison between signed and unsigned values could give an incorrect result because the signed value gets converted to unsigned โš–๏ธ. In C++, this is also enabled by -Wall. In C, it's also 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 conversions from real to integer, and from higher precision real to lower precision real values. This option is also enabled by -Wconversion.
  • -Wno-scalar-storage-order โ€” stops the warnings about suspicious constructs involving reverse scalar storage order ๐Ÿ™…โ€โ™€๏ธ.
  • -Wsizeof-array-div โ€” warns about divisions of two sizeof operators when the first one is applied to an array and the divisor doesn't equal the size of the array element ๐Ÿงฎ. In that case, the computation won't give you the number of elements in the array, which is probably not what you meant. This warning catches stuff like this:
int fn ()
{
  int arr[10];
  return sizeof (arr) / sizeof (short);
}

This warning is enabled by -Wall.

  • -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 to compute an array size, but it won't work out correctly with pointers. For example, it 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 example, for memset (ptr, 0, sizeof (ptr)); if ptr is a pointer and not an array. It'll even suggest a possible fix. It also warns about stuff like memcpy (&foo, ptr, sizeof (&foo));.

-Wsizeof-pointer-memaccess also warns about calls to bounded string copy functions like strncat or strncpy that use a sizeof expression of the source array as the bound. In the following function, the call to strncat uses the size of the source string as the bound. That's almost certainly a mistake, so the call gets diagnosed ๐Ÿ’€.

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.

  • -Wno-sizeof-array-argument โ€” stops the warning when the sizeof operator gets applied to a parameter declared as an array in a function definition ๐Ÿซถ. This warning is enabled by default for C and C++ programs.
  • -Wmemset-elt-size โ€” warns about suspicious calls to the memset built-in function ๐Ÿงบ. It triggers 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 array's size in memory. That means you probably forgot to multiply by the element size. This warning is enabled by -Wall.
  • -Wmemset-transposed-args โ€” warns about suspicious calls to the memset built-in function where the second argument is not zero and the third argument is zero ๐Ÿ”„. For example, the call memset (buf, sizeof buf, 0) gets diagnosed, because memset (buf, 0, sizeof buf) was what you meant. The diagnostic is only emitted 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, it's far less likely that the arguments got mistakenly transposed, so no warning is emitted. This warning is enabled by -Wall.
  • -Waddress โ€” warns about suspicious uses of memory addresses ๐Ÿ‘€. These include 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"). These usually point to a programmer error. The address of a function always evaluates to true, so using it in a conditional usually means you forgot the parentheses in a function call. Comparisons against string literals have unspecified behavior and aren't portable in C, so they usually mean you meant to use strcmp. This warning is enabled by -Wall.
  • -Wno-address-of-packed-member โ€” stops the warning when the address of a packed member of a struct or union is taken, which usually results in an unaligned pointer value ๐Ÿ“ฆ. This is enabled by default.
  • -Wlogical-op โ€” warns about suspicious uses of logical operators in expressions ๐Ÿง. That includes using logical operators in contexts where a bit-wise operator is likely expected. It also warns when the operands of a logical operator are the same:
extern int a;
if (a < 0 && a < 0) { ... }

Okay that's the bestie-level mistake ๐Ÿ™ˆ comparing the same thing twice, and the compiler is literally begging you to double check.


  • -Wlogical-not-parentheses โ€” okay so this one screams when you slap a ! on the left side of a comparison ๐Ÿ’… It doesn't scream if the right side is a boolean expression. The whole point is to catch sus code like this:
int a;
...
if (!a > 1) { ... }

If you want it to chill, wrap the LHS in parentheses:

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

This warning is enabled by -Wall โœจ

  • -Waggregate-return โ€” warns if any functions that return structures or unions get defined or called ๐ŸŽ€ (In languages where you can return an array, this also gets a warning too, ngl.)
  • -Wno-aggressive-loop-optimizations โ€” warns if you're in a loop with a constant number of iterations and the compiler spots undefined behavior in some statement during one or more of the iterations ๐Ÿ’€
  • -Wno-attributes โ€” don't warn if an unexpected __attribute__ shows up, like unrecognized attributes, function attributes slapped on variables, etc. ๐Ÿฆ‹ This does NOT stop errors for using supported attributes incorrectly, so don't get it twisted.
  • -Wno-builtin-declaration-mismatch โ€” warns if a built-in function gets declared with an incompatible signature or as a non-function, or when a built-in function declared with a type that has no prototype gets called with args whose promoted types don't match what the function expects ๐ŸŒธ With -Wextra, it also warns when a built-in function that takes arguments is declared without a prototype. The -Wbuiltin-declaration-mismatch warning is on by default. To dodge it, include the right header so the prototypes of built-in functions are in scope ๐Ÿซถ

Here's the vibe check example. The call to memset gets flagged because the function wants a size_t but 32 is an int. With -Wextra, the declaration gets flagged 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 quiets warnings for redefining __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 gets a free pass with no warning if it's preceded by a declaration that does specify the argument types.)
  • -Wold-style-declaration (C and Objective-C only) โ€” 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 first things in a declaration. This one is also enabled by -Wextra.
  • -Wold-style-definition (C and Objective-C only) โ€” warns if an old-style function definition is used โญ It warns even if there's a previous prototype. A definition using () isn't considered old-style in C2X mode, since it's equivalent to (void) there, but it is considered old-style for older standards.
  • -Wmissing-parameter-type (C and Objective-C only) โ€” warns when a function parameter is 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 warning shows up even if the definition itself provides a prototype. Use it to catch global functions that don't have a matching prototype declaration in a header file. This option is NOT valid for C++, because all function declarations there provide prototypes, and a non-matching declaration declares 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 ๐Ÿ”ฅ It does this even if the definition itself provides a prototype. Use it to catch global functions that aren't declared in header files. In C, no warnings get issued for functions with previous non-prototype declarations, so use -Wmissing-prototypes for those. In C++, no warnings get issued for function templates, inline functions, or functions in anonymous namespaces.
  • -Wmissing-field-initializers โ€” warns if a structure's initializer has some fields missing ๐Ÿฆ‹ In this example, x.h is implicitly zero, so you get the warning:
struct s { int f, g, h; };
struct s x = { 3, 4 };

This option does NOT warn about designated initializers, so this version is totally fine:

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

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

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

Likewise, in C++, it 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 โ€” don't warn if a multicharacter constant ('FOOF') is used ๐Ÿ™ˆ These usually mean there's a typo in your code, since they have implementation-defined values, and they shouldn't be used in portable code.
  • -Wnormalized=[none|id|nfc|nfkc] โ€” okay this one is a whole saga ๐ŸŒธ In ISO C and ISO C++, two identifiers are different if they're different sequences of characters. BUT sometimes, when characters outside basic ASCII are used, you can have two different character sequences that look exactly the same. To avoid that confusion, the ISO 10646 standard sets normalization rules that turn lookalike sequences into the same sequence. GCC can warn you if your identifiers aren't normalized, and this option controls that warning.

There are four levels of warning. 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 tea โ˜• Some characters allowed in identifiers by ISO C and ISO C++ turn into characters that AREN'T allowed in identifiers once they're NFC. So there's no way to use those symbols in portable ISO C or C++ AND 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 it 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 has been applied. For instance, "\u207F", "SUPERSCRIPT LATIN SMALL LETTER N", displays just like a regular "n" that's been 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 comparable to warning about every identifier that contains the letter O, since 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 โ€” don't warn about usage of functions declared with the "warning" attribute ๐ŸŽ€ This warning is enabled by default. Use -Wno-attribute-warning to disable the warning, or -Wno-error=attribute-warning to disable the error when compiling with the -Werror flag.
  • -Wno-deprecated โ€” don't warn about usage of deprecated features ๐Ÿฆ‹
  • -Wno-deprecated-declarations โ€” don't warn about uses of functions, variables, and types marked as deprecated with the "deprecated" attribute ๐ŸŒˆ
  • -Wno-overflow โ€” don't warn about compile-time overflow in constant expressions โœจ
  • -Wno-odr โ€” warns about One Definition Rule violations during link-time optimization ๐Ÿ’– This one is enabled by default.
  • -Wopenmp-simd โ€” warns if the vectorizer cost model overrides the OpenMP simd directive that the user set ๐Ÿ”ฅ The -fsimd-cost-model=unlimited option can be used to relax the cost model.
  • -Woverride-init (C and Objective-C only) โ€” warns if an initialized field without side effects gets overridden when using designated initializers ๐Ÿซถ This warning is included in -Wextra. To get the other -Wextra warnings without this one, use -Wextra -Wno-override-init.
  • -Wno-override-init-side-effects (C and Objective-C only) โ€” don't warn if an initialized field with side effects gets overridden when using designated initializers ๐Ÿ‘‘ This warning is enabled by default.
  • -Wpacked โ€” warns if a structure is given the packed attribute, but the packed attribute has no effect on the layout or size of the structure ๐Ÿ“ Such structures may end up misaligned for little benefit. For instance, in this code, the variable f.x in struct bar is misaligned even though struct bar doesn't itself have the packed attribute:
struct foo {
  int x;
  char a, b, c, d;
} __attribute__((packed));
struct bar {
  char z;
  struct foo f;
};
  • -Wnopacked-bitfield-compat โ€” okay so the 4.1, 4.2 and 4.3 series of GCC just ignored the packed attribute on char bit-fields ๐Ÿ’€. That got fixed in GCC 4.4, but the fix can shift your struct layout, so GCC tells you when a field's offset has changed. In this struct, the 4-bit gap between a and b is gone now โœจ:
struct foo
{
  char a:4;
  char b:8;
} __attribute__ ((packed));

This warning is enabled by default ๐ŸŒธ. If you want it gone, use -Wno-packed-bitfield-compat ๐Ÿซถ.

  • -Wpacked-not-aligned (C, C++, Objective-C and Objective-C++ only) โ€” bestie, this one catches a field with explicit alignment inside a packed struct or union that's misaligned ๐Ÿ™ˆ. The message looks like warning: alignment 1 of 'struct S' is less than 8, and it pops up in code like this:
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 sneaks into a struct, whether it's there to line up one element or to line up the whole struct ๐Ÿฆ‹. Sometimes you can shuffle the fields around to cut the padding down and make the struct smaller, which is very iconic ๐Ÿ‘‘.
  • -Wredundant-decls โ€” warns if something gets declared more than once in the same scope ๐Ÿ™„. This happens even when multiple declarations are valid and change absolutely nothing.
  • -Wrestrict โ€” warns when an object referenced by a restrict-qualified parameter (or, in C++, a __restrict-qualified one) is aliased by another argument, or when copies between those objects overlap ๐Ÿ”ฅ. Check out this strcpy call that tries to chop the string by replacing its front with the last four characters. Because the call writes the terminating NUL into a[4], the copies overlap, and GCC catches it:
void foo (void)
{
  char a[] = "abcd1234";
  strcpy (a, a + 4);
  ...
}

-Wrestrict catches some 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 ๐Ÿ‘€.
  • -Winline โ€” warns if a function declared as inline can't actually be inlined ๐Ÿ’…. Even with this on, GCC won't warn about inlining failures for functions declared in system headers ๐Ÿ™ˆ.

The compiler uses a bunch of heuristics to decide whether to inline a function. For example, it looks at the size of the function being inlined and how much inlining has already happened in the current function. So seemingly tiny changes to your source can make -Winline warnings show up or disappear ๐ŸŒ€.

  • -Wint-in-bool-context โ€” warns about sus uses of integers where booleans are expected ๐Ÿง. That includes conditional expressions (?:) using non-boolean integer constants in a boolean context, like if (a <= b ? 2 : 3). It also includes left-shifting signed integers in a boolean context, like for (a = 0; 1 << a; a++);. The same goes for all kinds of multiplications, no matter the data type โœ–๏ธ. This warning is enabled by -Wall ๐Ÿ’œ.
  • -Wno-int-to-pointer-cast โ€” suppresses warnings about casts to a pointer type from an integer of a different size ๐Ÿซ . In C++, casting to a pointer type of smaller size is an error, so be careful ๐Ÿšจ. Wint-to-pointer-cast is enabled by default ๐ŸŒธ.
  • -Wno-pointer-to-int-cast (C and Objective-C only) โ€” suppresses warnings about casts 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 be used ๐Ÿ˜ญ.
  • -Wlong-long โ€” warns if the long long type gets used ๐Ÿ“. It's enabled by either -Wpedantic or -Wtraditional in ISO C90 and C++98 modes. To shush the warnings, 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 ๐ŸŽ€.
  • -Wno-varargs โ€” stops GCC from warning about questionable usage of the macros that handle variable arguments, like va_start ๐Ÿฆ‹. These warnings are on by default, so this one is the opt-out ๐Ÿ’….
  • -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 ๐Ÿ“ˆ. A vector operation can be implemented in a few different ways:
    • "piecewise" โ€” the scalar operation is performed on every vector element ๐Ÿงฉ.
    • "in parallel" โ€” the vector operation is implemented using scalars of a wider type, which is normally more performance-efficient ๐Ÿš€.
    • "as a single scalar" โ€” the vector fits into a scalar type ๐Ÿ’Ž.
  • -Wvla โ€” warns if a variable-length array is used in the code ๐Ÿ“. -Wno-vla silences the -Wpedantic warning about variable-length arrays ๐Ÿ™….
  • -Wvla-larger-than=byte-size โ€” if you use this, GCC warns 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 basically the vibe of -Walloca-larger-than=byte-size, but for VLAs ๐Ÿ’œ.

Heads up: GCC may optimize small VLAs with a known value into plain arrays, so this warning might not trigger 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.
  • -Wvla-parameter โ€” warns about redeclarations of functions involving arguments of Variable Length Array types with inconsistent kinds or forms ๐Ÿงต. It also enables detecting out-of-bounds accesses to those parameters through warnings like -Warray-bounds ๐Ÿ‘€.

If the first function declaration uses the VLA form, the bound in the array is assumed to be the minimum number of elements expected in calls to the function, and also the maximum number of elements it accesses. Not providing arguments of sufficient size, or accessing more than the maximum number of elements, may get diagnosed ๐Ÿšฉ.

Here's the drama: the warning triggers for these redeclarations because the first one lets an array of any size get passed to f, while the second one says the array argument must have at least n elements. Calling f with the associated VLA bound parameter larger than the actual VLA bound also triggers a warning ๐Ÿ’€.

void f (int n, int[n]);
void f (int, int[]);     // warning: argument 2 previously declared as a VLA

void g (int n)
{
    if (n > 4)
      return;
    int a[n];
    f (sizeof a, a);     // warning: access to a by f may be out of bounds
  ...
}

-Wvla-parameter is included in -Wall ๐Ÿ’œ. The -Warray-parameter option handles similar problems involving ordinary array arguments ๐ŸŽ€.

  • -Wvolatile-register-var โ€” warns if a register variable is declared volatile ๐Ÿ™…โ€โ™€๏ธ. Heads up: volatile 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 the code effectively ๐Ÿ˜…. Often the problem is that your code is too big or too complex, since GCC refuses to optimize programs when the optimization would 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 you can turn it off with -Wno-pointer-sign ๐Ÿ™….
  • -Wstack-protector โ€” this one is only active when -fstack-protector is active ๐Ÿ›ก๏ธ. It warns about functions that aren't protected against stack smashing ๐Ÿ’ฅ.
  • -Woverlength-strings โ€” warns about string constants longer than the "minimum maximum" length the C standard specifies ๐Ÿ“œ. Modern compilers are usually fine with 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 GCC doesn't diagnose overlength strings in C++ ๐Ÿ™ƒ.

-Woverlength-strings 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 without a suffix ๐Ÿ”ข. When you combine it with -Wsystem-headers, it also warns about those constants in system header files ๐Ÿงพ. This is super handy when you're prepping code to use with the FLOAT_CONST_DECIMAL64 pragma from the decimal floating-point extension to C99 ๐Ÿ’–.
  • -Wno-lto-type-mismatch โ€” during link-time optimization, GCC won't warn about type mismatches in global declarations coming from different compilation units ๐Ÿค. It requires -flto to be enabled, and it's enabled by default ๐ŸŒธ.
  • -Wno-designated-init (C and Objective-C only) โ€” suppresses warnings when a positional initializer is used to initialize a structure marked with the designated_init attribute ๐ŸŽ€.

โœจ Options That Control Static Analysis โœจ

  • -fanalyzer โ€” turns on a static analysis of program flow ๐Ÿ”. It looks for "interesting" interprocedural paths through the code, and it issues warnings for problems it finds on them ๐Ÿง ๐Ÿ”ฅ.

This analysis is much more expensive than other GCC warnings, bestie ๐Ÿ’€ so don't be shocked if it takes its sweet time. It's giving deep-dive energy ๐Ÿซถ

Enabling this option effectively enables the following warnings โœจ

-Wanalyzer-double-fclose -Wanalyzer-double-free
-Wanalyzer-exposure-through-output-file -Wanalyzer-file-leak
-Wanalyzer-free-of-non-heap -Wanalyzer-malloc-leak
-Wanalyzer-mismatching-deallocation
-Wanalyzer-possible-null-argument
-Wanalyzer-possible-null-dereference -Wanalyzer-null-argument
-Wanalyzer-null-dereference -Wanalyzer-shift-count-negative
-Wanalyzer-shift-count-overflow -Wanalyzer-stale-setjmp-buffer
-Wanalyzer-tainted-array-index
-Wanalyzer-unsafe-call-within-signal-handler
-Wanalyzer-use-after-free
-Wanalyzer-use-of-pointer-in-stale-stack-frame
-Wanalyzer-write-to-const -Wanalyzer-write-to-string-literal
This option is only available if GCC was configured with analyzer support enabled. So if your build didn't include it, this one's a no-show ๐Ÿ™ˆ

โœจ OPTIONS โœจ

  • -Wanalyzer-too-complex โ€” If -fanalyzer is on, the analyzer uses a bunch of heuristics to poke around the control flow and data flow in your program, but really complicated code can totally defeat them ๐ŸŒ€. By default the analysis just quietly stops once the code is too tangled and it hits an internal limit. This option is the one that actually warns you when that happens ๐Ÿ‘€.
  • -Wno-analyzer-double-fclose โ€” This warning needs -fanalyzer to be enabled (which turns it on), and you can turn it off with -Wno-analyzer-double-fclose. It flags paths through the code where a FILE * might get fclose called on it more than once ๐Ÿ’….
  • -Wno-analyzer-double-free โ€” Needs -fanalyzer, and you can silence it with -Wno-analyzer-double-free. It catches paths where a pointer gets a deallocator called on it more than once, whether that's free or a deallocator referenced by attribute "malloc" ๐Ÿ™…โ€โ™€๏ธ.
  • -Wno-analyzer-exposure-through-output-file โ€” Needs -fanalyzer, and disable it with -Wno-analyzer-exposure-through-output-file. This one is the security-sensitive one ๐Ÿ”’. It warns on paths where something sensitive gets written to an output file, like dumping a password into a log file ๐Ÿ˜ญ.
  • -Wno-analyzer-file-leak โ€” Needs -fanalyzer, and -Wno-analyzer-file-leak turns it off. It warns on paths where a FILE * stream object from <stdio.h> gets leaked ๐Ÿ’ง.
  • -Wno-analyzer-free-of-non-heap โ€” Needs -fanalyzer, and -Wno-analyzer-free-of-non-heap shuts it up. It warns on paths where free gets called on a pointer that isn't on the heap, like an on-stack buffer or a global ๐Ÿ™ˆ.
  • -Wno-analyzer-malloc-leak โ€” Needs -fanalyzer, and you can disable it with -Wno-analyzer-malloc-leak. It warns on paths where a pointer from an allocator gets leaked, whether that allocator is malloc or a function marked with attribute "malloc" ๐Ÿซง.
  • -Wno-analyzer-mismatching-deallocation โ€” Needs -fanalyzer, and -Wno-analyzer-mismatching-deallocation is how you mute it. It warns on paths where the wrong deallocation function gets called on a pointer, based on which function originally allocated it. That covers mismatches between free, scalar delete and vector delete[], plus anything marked as an allocator/deallocator pair using attribute "malloc" ๐Ÿงฉ.
  • -Wno-analyzer-possible-null-argument โ€” Needs -fanalyzer, and disable it with -Wno-analyzer-possible-null-argument. It warns on paths where a possibly-NULL value gets passed to a function argument marked with __attribute__((nonnull)) as needing a non-NULL value ๐Ÿซฃ.
  • -Wno-analyzer-possible-null-dereference โ€” Needs -fanalyzer, and -Wno-analyzer-possible-null-dereference turns it off. It warns on paths where a possibly-NULL value gets dereferenced ๐Ÿ‘€.
  • -Wno-analyzer-null-argument โ€” Needs -fanalyzer, and -Wno-analyzer-null-argument disables it. It warns on paths where a value known to be NULL gets passed to a function argument marked with __attribute__((nonnull)) as needing a non-NULL value ๐Ÿ’€.
  • -Wno-analyzer-null-dereference โ€” Needs -fanalyzer, and you can mute it with -Wno-analyzer-null-dereference. It warns on paths where a value known to be NULL gets dereferenced ๐Ÿšจ.
  • -Wno-analyzer-shift-count-negative โ€” Needs -fanalyzer, and -Wno-analyzer-shift-count-negative is the off switch. It warns on paths where a shift is attempted with a negative count ๐ŸŒ€. It's the analyzer's cousin of the -Wshift-count-negative warning from the C/C++ front ends, except it works by analyzing interprocedural paths instead of just parsing the syntax tree. Heads up though: the analyzer doesn't prioritize finding these, so false negatives are more likely compared to other warnings ๐Ÿซ .
  • -Wno-analyzer-shift-count-overflow โ€” Needs -fanalyzer, and disable it with -Wno-analyzer-shift-count-overflow. It warns on paths where a shift is attempted with a count greater than or equal to the precision of the operand's type ๐Ÿ“. It's analogous to the -Wshift-count-overflow diagnostic in the C/C++ front ends, but again it's based on interprocedural paths rather than just the syntax tree. The analyzer doesn't prioritize these either, so false negatives are more likely relative to other warnings ๐Ÿ™ƒ.
  • -Wno-analyzer-stale-setjmp-buffer โ€” Needs -fanalyzer, and -Wno-analyzer-stale-setjmp-buffer disables it. It warns on paths where longjmp is called to rewind to a jmp_buf tied to a setjmp call, in a function that has already returned โช. When setjmp gets called on a jmp_buf to record a rewind location, it records the stack frame. That frame becomes invalid once the function containing the setjmp call returns. Trying to rewind to it with longjmp would reference a stack frame that doesn't exist anymore, and that's likely to lead to a crash (or worse) ๐Ÿ’ฅ.
  • -Wno-analyzer-tainted-array-index โ€” This one needs both -fanalyzer and -fanalyzer-checker=taint to turn on, and -Wno-analyzer-tainted-array-index is how you turn it off ๐Ÿ”. It warns on paths where a value an attacker could control gets used as the index of an array access without being sanitized first ๐Ÿ™…โ€โ™€๏ธ.
  • -Wno-analyzer-unsafe-call-within-signal-handler โ€” Needs -fanalyzer, and disable it with -Wno-analyzer-unsafe-call-within-signal-handler. It warns on paths where a function known to be async-signal-unsafe (like fprintf) gets called from a signal handler ๐Ÿšซ.
  • -Wno-analyzer-use-after-free โ€” Needs -fanalyzer, and -Wno-analyzer-use-after-free mutes it. It warns on paths where a pointer gets used after a deallocator has been called on it, whether that deallocator is free or one referenced by attribute "malloc" ๐Ÿชฆ.
  • -Wno-analyzer-use-of-pointer-in-stale-stack-frame โ€” Needs -fanalyzer, and -Wno-analyzer-use-of-pointer-in-stale-stack-frame turns it off. It warns on paths where a pointer gets dereferenced while pointing to a variable in a stale stack frame ๐Ÿฅ€.
  • -Wno-analyzer-write-to-const โ€” Needs -fanalyzer, and disable it with -Wno-analyzer-write-to-const. It warns on paths where the analyzer spots an attempt to write through a pointer to a const object ๐Ÿ™…โ€โ™€๏ธ. The analyzer doesn't prioritize these paths though, so false negatives are more likely relative to other warnings ๐Ÿคทโ€โ™€๏ธ.
  • -Wno-analyzer-write-to-string-literal โ€” Needs -fanalyzer, and -Wno-analyzer-write-to-string-literal is the off switch. It warns on paths where the analyzer detects an attempt to write through a pointer to a string literal โœ๏ธ. Same deal as before: the analyzer doesn't prioritize these, so false negatives are more likely relative to other warnings ๐Ÿซค.

Pertinent parameters for controlling the exploration are: --param analyzer-bb-explosion-factor=value, --param analyzer-max-enodes-per-program-point=value, --param analyzer-max-recursion-depth=value, and --param analyzer-min-snodes-for-call-summary=value ๐ŸŽ›๏ธ.

The following options control the analyzer ๐Ÿง :

  • -fanalyzer-call-summaries โ€” This simplifies interprocedural analysis by computing the effect of certain calls, instead of exploring every path through the function from the callsite to each possible return ๐Ÿงƒ. If it's enabled, call summaries only get used for functions with more than one call site and that are sufficiently complicated (as per --param analyzer-min-snodes-for-call-summary=value) โœจ.
  • -fanalyzer-checker=name โ€” This restricts the analyzer to run just the named checker, and enables it ๐ŸŽฏ. Some checkers are disabled by default (even with -fanalyzer), like the "taint" checker that implements -Wanalyzer-tainted-array-index. You need this option to turn those on ๐Ÿ”“.
  • -fno-analyzer-feasibility โ€” This one's intended for analyzer developers ๐Ÿง‘โ€๐Ÿ’ป. By default the analyzer checks that there's a feasible control flow path for each diagnostic it emits, meaning the conditions that hold aren't mutually exclusive. Diagnostics with no feasible path get rejected. You can suppress that filtering with -fno-analyzer-feasibility, which is handy for debugging issues in this code ๐Ÿ›.
  • -fanalyzer-fine-grained โ€” Also intended for analyzer developers ๐Ÿฆ‹.

Okay bestie, so under the hood the analyzer builds this "exploded graph" ๐Ÿ•ธ๏ธโœจ that mashes control flow graphs together with data flow info. It's giving main character energy ๐Ÿ’…

By default, an edge in this graph can hold the effects of a whole run of statements inside one basic block. With -fanalyzer-fine-grained, each statement gets its own edge ๐Ÿฆ‹

  • -fanalyzer-show-duplicate-count โ€” ๐Ÿ› ๏ธ this one's for the analyzer devs! If several diagnostics get flagged as duplicates of each other, it drops a note on the best diagnostic telling you how many extra ones the deduplication logic quietly suppressed ๐Ÿ™ˆ
  • -fno-analyzer-state-merge โ€” ๐Ÿ› ๏ธ also for the devs! By default the analyzer tries to keep things simple by merging sufficiently similar states at each program point while it builds its "exploded graph" ๐Ÿง  With -fno-analyzer-state-merge that merging gets turned off, which is useful for debugging state-handling issues ๐Ÿ›
  • -fno-analyzer-state-purge โ€” ๐Ÿ› ๏ธ devs, you know the drill ๐Ÿ’œ By default the analyzer clears out state at a program point when it seems irrelevant, like the values of locals that never get accessed later in the function and don't matter for leak analysis ๐Ÿงน With -fno-analyzer-state-purge that purging gets suppressed, for debugging state-handling issues ๐Ÿ”
  • -fanalyzer-transitivity โ€” โœจ turns on transitivity of constraints within the analyzer. Very smart, very lowkey ๐Ÿง 
  • -fanalyzer-verbose-edges โ€” ๐Ÿ› ๏ธ dev-only! It gives you more verbose, lower-level detail in the descriptions of control flow within diagnostic paths ๐Ÿ—บ๏ธ
  • -fanalyzer-verbose-state-changes โ€” ๐Ÿ› ๏ธ also dev-only ๐Ÿ˜ญ It gives you more verbose, lower-level detail in the descriptions of state machine events within diagnostic paths ๐ŸŽ€
  • -fanalyzer-verbosity=level โ€” ๐Ÿ‘‘ this one controls how complex the control flow paths are that get emitted for analyzer diagnostics. The level can be one of these:
    • 0 โ€” at this level you see interprocedural call and return events, plus the most pertinent state-change events for a diagnostic. For example, with a double-"free" diagnostic, both calls to "free" get shown ๐ŸŒธ
    • 1 โ€” same as the previous level, but also shows events for the entry to each function ๐Ÿšช
    • 2 โ€” same as the previous level, but also shows control flow events that matter for triggering the issue (like "true path taken" at a conditional) โญ This level is the default, so it's the one you get if you don't pick anything ๐Ÿ’–
    • 3 โ€” same as the previous level, but shows all control flow events, not just the significant ones ๐ŸŒŠ
    • 4 โ€” for the analyzer devs ๐Ÿ› ๏ธ It adds various other events meant for debugging the analyzer itself ๐Ÿงš
  • -fdump-analyzer โ€” ๐Ÿ“ dumps internal details about what the analyzer is doing into file.analyzer.txt. This option gets overridden by -fdump-analyzer-stderr ๐Ÿ™ƒ
  • -fdump-analyzer-stderr โ€” ๐Ÿ“ dumps those same internal details to stderr. This option overrides -fdump-analyzer ๐Ÿ’…
  • -fdump-analyzer-callgraph โ€” ๐Ÿ—บ๏ธ dumps a representation of the call graph that's suitable for viewing with GraphViz, written to file.callgraph.dot ๐Ÿฆ‹
  • -fdump-analyzer-exploded-graph โ€” ๐Ÿ•ธ๏ธ dumps a representation of the "exploded graph" that's suitable for viewing with GraphViz, written to file.eg.dot. The nodes are color-coded based on state-machine states so the state changes really pop ๐ŸŒˆ
  • -fdump-analyzer-exploded-nodes โ€” ๐ŸŽฏ emits diagnostics showing where nodes in the "exploded graph" sit in relation to the program source ๐Ÿ“
  • -fdump-analyzer-exploded-nodes-2 โ€” ๐Ÿ“„ dumps a textual representation of the "exploded graph" to file.eg.txt ๐Ÿ“
  • -fdump-analyzer-exploded-nodes-3 โ€” ๐Ÿ“‚ dumps a textual representation of the "exploded graph" to one dump file per node, named file.eg-id.txt. Heads up, this is typically a large number of dump files ๐Ÿ˜ญ๐Ÿ’€
  • -fdump-analyzer-feasibility โ€” ๐Ÿ”Ž dumps internal details about the analyzer's search for feasible paths. They're written in a form suitable for viewing with GraphViz, using filenames like file..fg.dot and file..tg.dot ๐Ÿงฉ
  • -fdump-analyzer-json โ€” ๐Ÿ“ฆ dumps a compressed JSON representation of analyzer internals to file.analyzer.json.gz. The precise format is subject to change, so don't get too attached to it ๐Ÿซถ
  • -fdump-analyzer-state-purge โ€” ๐Ÿงน like -fdump-analyzer-supergraph, this dumps a supergraph representation suitable for GraphViz, but it's annotated with info on what state will be purged at each node. The graph gets written to file.state-purge.dot ๐Ÿ’œ
  • -fdump-analyzer-supergraph โ€” ๐Ÿ—บ๏ธ dumps representations of the "supergraph" suitable for GraphViz to file.supergraph.dot and to file.supergraph-eg.dot. These show all of the control flow graphs in the program, with interprocedural edges for calls and returns โœจ The second dump has annotations showing nodes in the "exploded graph" and the diagnostics attached to them ๐Ÿ”ฅ

๐Ÿ› Options for Debugging Your Program ๐Ÿ›

Okay so if you want GCC to emit extra info for a debugger, in almost all cases you just need to add -g to your other options ๐ŸŽ€

GCC lets you use -g with -O. Fair warning though, the shortcuts optimized code takes can be kinda surprising ๐Ÿ˜ญ Some variables you declared may not exist at all, flow of control might briefly jump somewhere you didn't expect, some statements may not run because they compute constant results or their values are already at hand, and some statements may execute in different places because they got moved out of loops ๐ŸŒ€ Still, it is possible to debug optimized output, so it's reasonable to use the optimizer for programs that might have bugs ๐Ÿซถ

If you're not using some other optimization option, consider using -Og with -g ๐Ÿ’… With no -O option at all, some compiler passes that collect information useful for debugging 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 turns on extra debugging information that only GDB can use. That extra info 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 the extra info gets generated, use -gstabs+, -gstabs, -gxcoff+, -gxcoff, or -gvms (see below) ๐ŸŽฏ

  • -ggdb โ€” ๐Ÿ’– produces debugging information for use by GDB. This means it uses the most expressive format available (DWARF, stabs, or the native format if neither of those is 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 can be 2, 3, 4 or 5. The default version for most targets is 5, with the exception of VxWorks, TPF and Darwin/Mac OS X, which default to version 2, and AIX, which defaults to version 4 ๐Ÿ“

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. Version 5 requires GDB 8.0 or higher โญ

GCC no longer supports DWARF Version 1, which is substantially different from Version 2 and later. For historical reasons, some other DWARF-related options, such as -fno-dwarf2-cfi-asm), still have 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 is likely to 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+ โ€” ๐Ÿงพ produces debugging information in XCOFF format (if that's supported), using GNU extensions that only the GNU debugger (GDB) understands. Using these extensions is likely to make other debuggers crash or refuse to read the program, and may cause assemblers other than the GNU assembler (GAS) to fail with an error ๐Ÿ™ˆ
  • -gvms โ€” ๐Ÿงพ produces debugging information in Alpha/VMS debug format (if that's supported). This is the format the DEBUG tool uses on Alpha/VMS systems ๐ŸŒธ
  • -glevel, -ggdblevel, -gstabslevel, -gxcofflevel, -gvmslevel โ€” ๐ŸŽš๏ธ requests debugging information and also uses level to decide how much information you get. The default level is 2 ๐Ÿ’–

Level 0 produces no debug information at all, so -g0 negates -g ๐Ÿšซ

Level 1 produces minimal information, enough for making backtraces in parts of the program you don't plan to debug. That includes descriptions of functions and external variables, and line number tables, but no information about local variables ๐Ÿงญ

Level 3 includes extra information, such as all the macro definitions present in the program. Some debuggers support macro expansion when you use -g3 ๐Ÿช„

If you use multiple -g options, with or without level numbers, the last such option is the one that takes effect ๐Ÿ‘‘

-gdwarf doesn't accept a concatenated debug level, to avoid confusion with -gdwarf-level. Instead, use an additional -glevel option to change the debug level for DWARF ๐Ÿซถ

  • -fno-eliminate-unused-debug-symbols โ€” ๐Ÿงน by default, no debug information is produced for symbols that aren't actually used. Use this option if you want debug information for all symbols ๐ŸŒˆ
  • -femit-class-debug-always โ€” ๐Ÿ’– Normally GCC only drops a C++ class's debug info into one object file, but this flag makes it emit that info in every object file that uses the class. Only reach for it if your debugger can't handle GCC's usual class debug output, because it can make the debug info up to a factor of two bigger. ๐Ÿซถ
  • -fno-merge-debug-strings โ€” ๐Ÿงš This tells the linker to skip merging identical strings in the debug info across different object files. Not every assembler or linker can merge strings anyway. Merging keeps the output file's debug info smaller, but linking takes longer. Good news: merging is on by default. โœจ
  • -fdebug-prefix-map=old=new โ€” ๐Ÿ—บ๏ธ Files living in directory old get debug info written as if they lived in directory new instead. It's handy for swapping a build-time path for an install-time path, or for turning an absolute path into a relative one by using . as new. This can make builds more reproducible and location independent, but you might need an extra command to tell GDB where the source files are. See also -ffile-prefix-map. ๐ŸŒธ
  • -fvar-tracking โ€” ๐Ÿ” This runs the variable tracking pass, which figures out where variables are stored at each spot in the code. The result is better debug info, as long as your debug format supports it. It's switched on automatically when you compile with optimization (-Os, -O, -O2, ...) and debug info (-g), and the format supports it. ๐Ÿ‘‘
  • -fvar-tracking-assignments โ€” ๐ŸŽ€ This annotates assignments to user variables early on and tries to carry those annotations all the way to the end of compilation, so debug info stays good while optimizing. Pairing it with -gdwarf-4 is recommended. It can be turned on even when var-tracking is off, but then the annotations get thrown away at the end. By default it's enabled together with -fvar-tracking, except when selective scheduling is on. ๐Ÿ’…
  • -gsplit-dwarf โ€” ๐Ÿฆ‹ With DWARF debug info enabled, this shoves as much of it as possible into a separate output file ending in .dwo. That lets your build system skip linking files that carry debug info. It's only useful if your debugger can actually read .dwo files. ๐ŸŒˆ
  • -gdwarf32, -gdwarf64 โ€” ๐Ÿ“ With DWARF debug info enabled, -gdwarf32 picks the 32-bit DWARF format and -gdwarf64 picks the 64-bit one. The default depends on the target, but on most targets it's -gdwarf32. The 32-bit format is smaller, but it can't hold more than 2GiB of debug info in any DWARF debug section. The 64-bit format handles bigger debug info, but not every consumer supports it well yet. ๐Ÿงฎ
  • -gdescribe-dies โ€” ๐ŸŒท This adds description attributes to some DWARF DIEs that don't have a name attribute, like artificial variables, external references, and call site parameter DIEs. โœจ
  • -gpubnames โ€” ๐Ÿ“š This generates the DWARF .debug_pubnames and .debug_pubtypes sections. ๐Ÿ’œ
  • -ggnu-pubnames โ€” ๐Ÿงฉ This generates .debug_pubnames and .debug_pubtypes in a format that can be converted into a GDB index. It's only useful if your linker can produce GDB index version 7. ๐Ÿ”ฅ
  • -fdebug-types-section โ€” ๐Ÿซง With DWARF Version 4 or higher, type DIEs can get their own .debug_types section instead of living inside .debug_info. That's more efficient since the linker can drop duplicates when they sit in a separate comdat section. The catch: not all DWARF consumers support .debug_types yet, and on some objects it makes debug info bigger, not smaller. ๐Ÿ˜ญ
  • -grecord-gcc-switches, -gno-record-gcc-switches โ€” ๐Ÿ“ This appends the command-line options that might affect code generation to the DW_AT_producer attribute in DWARF debug info. The options are joined with spaces, both from each other and from the compiler version. It's on by default. See also -frecord-gcc-switches for another way to store compiler options in the object file. ๐ŸŽ€
  • -gstrict-dwarf โ€” ๐Ÿšซ This stops you from using extensions from a later DWARF standard version than the one picked with -gdwarf-version. On most targets, though, extensions from later versions that don't conflict with anything are still allowed. ๐Ÿ™ˆ
  • -gno-strict-dwarf โ€” ๐Ÿ•Š๏ธ This lets you use extensions from a later DWARF standard version than the one picked with -gdwarf-version. ๐Ÿ’…
  • -gas-loc-support โ€” ๐Ÿ“ This tells the compiler the assembler understands .loc directives, so the compiler can hand off line number table generation to the assembler to produce DWARF2+ tables. That's usually what you want, since assembler-generated line number tables are way more compact than the ones GCC can build itself. It's enabled by default if the assembler was found to support those directives when GCC was configured. ๐Ÿฆ‹
  • -gno-as-loc-support โ€” ๐Ÿ› ๏ธ This forces GCC to generate DWARF2+ line number tables internally, whenever those tables are going to be generated at all. ๐Ÿงš
  • -gas-locview-support โ€” ๐Ÿ‘€ This tells the compiler 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 โ€” ๐Ÿ”ข This forces GCC to assign view numbers internally, but only if -gvariable-location-views was explicitly requested. ๐Ÿ’œ
  • -gcolumn-info, -gno-column-info โ€” ๐ŸŽฏ This puts location column information into DWARF debug info, not just file and line. It's enabled by default. โญ
  • -gstatement-frontiers, -gno-statement-frontiers โ€” ๐Ÿšฉ This makes GCC drop markers into the internal representation at the start of each statement, then keeps them roughly where they are throughout compilation. Those markers guide the output of "is_stmt" markers in the line number table. It's enabled by default when you compile with optimization (-Os, -O, -O2, ...) and output DWARF 2 debug info at the normal level. ๐Ÿง 
  • -gvariable-location-views, -gvariable-location-views=incompat5, -gno-variable-location-views โ€” ๐Ÿ”ญ This adds progressive view numbers, implied by the line number table, onto variable location lists. That lets debug consumers peek at the program state at certain points, even when no instructions tied to those source locations exist there. If the assembler can't handle view numbers in line number tables, GCC emits its own line number table instead, which is usually less compact. The augmented tables and lists are fully backward compatible, so older consumers can still read them, they just won't get any benefit. ๐Ÿ’…

It's enabled by default when outputting DWARF 2 debug info at the normal level, as long as the assembler supports it, -fvar-tracking-assignments is on, and -gstrict-dwarf is off. If the assembler doesn't support it, the option can still be enabled, but it forces GCC to output internal line number tables. Unless -ginternal-reset-location-views is also enabled, that will most certainly lead to silently mismatching location views. ๐Ÿ˜ฑ

There's also a proposed representation for view numbers that isn't backward compatible with the location list format from DWARF 5, and you can turn it on with -gvariable-location-views=incompat5.

โš ๏ธ Heads up bestie: -gvariable-location-views=incompat5 may be removed in the future. It's only there as a reference implementation of the proposed representation. Debug info consumers aren't expected to support this extended format, and they won't be able to decode location lists that use it. ๐Ÿ™…โ€โ™€๏ธ
  • -ginternal-reset-location-views, -gno-internal-reset-location-views โ€” ๐Ÿงน This tries to figure out which location views can be dropped from location view lists. It needs the compiler to have very accurate instruction length estimates, which isn't always the case. It can silently generate incorrect view lists when the assembler doesn't support location view lists. The GNU assembler will flag that kind of error as a "view number mismatch". This is only enabled on ports that define a reliable estimation function. โš ๏ธ
  • -ginline-points, -gno-inline-points โ€” ๐ŸŽˆ This generates extended debug info for inlined functions. Location view tracking markers get inserted at inlined entry points, so address and view numbers can be computed and output in debug info. You can turn it on 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] โ€” ๐Ÿ—œ๏ธ This produces compressed debug sections in DWARF format, if that's supported. If you don't give a type, the default depends on what the assembler and linker can do. type can be none (don't compress 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. Otherwise, if the assembler doesn't support them, -gz is quietly ignored when producing object files. ๐Ÿงƒ
  • -femit-struct-debug-baseonly โ€” ๐Ÿชž This only emits debug info for struct-like types when the base name of the compilation source file matches the base name of the file where the struct is defined. It shrinks debug info a lot, but the debugger can lose a significant amount of type information. See -femit-struct-debug-reduced for a less aggressive option, and -femit-struct-debug-detailed for more detailed control. This option only works with DWARF debug output. ๐Ÿฅน
โš ๏ธ Real talk: -femit-struct-debug-baseonly can cost you a big chunk of type information in the debugger, so it's a trade-off, not a free win. ๐Ÿ’€
  • -femit-struct-debug-reduced โ€” okay bestie, this one is a total space saver ๐Ÿ’– 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 makes the debug info way smaller ๐Ÿฆ‹, but you might lose a little type info the debugger would've wanted ๐Ÿ˜ญ. For a more aggressive version, check out -femit-struct-debug-baseonly, and for finer control, look at -femit-struct-debug-detailed.
    • This only works with DWARF debug output ๐ŸŒˆ
  • -femit-struct-debug-detailed[=spec-list] โ€” this one is the customizable queen ๐Ÿ’… It lets you pick exactly which struct-like types get debug info, mostly so you don't get duplicate struct debug info across different object files in the same program ๐Ÿงš It's a detailed version of -femit-struct-debug-reduced and -femit-struct-debug-baseonly, and honestly it covers most needs ๐Ÿซถ
    • A spec looks like [dir:|ind:][ord:|gen:](any|sys|base|none). The first two words are optional, and the third word tells the compiler which source files to care about ๐Ÿ‘‘
    • First word (dir: or ind:) โ€” this one is optional and limits the spec to structs that are used directly (dir:) or used indirectly (ind:). A struct is used directly when it's the type of a variable or member. Indirect uses come through pointers to structs. In other words, when using an incomplete struct is valid, that use is indirect. Example: struct one direct; struct two * indirect; ๐Ÿ™ˆ
    • Second word (ord: or gen:) โ€” also optional, and it limits the spec to ordinary structs (ord:) or generic structs (gen:). Generic structs are a little complicated, ngl. For C++, these are non-explicit specializations of template classes, or non-template classes within the above. Other programming languages have generics too, but -femit-struct-debug-detailed doesn't implement them yet ๐Ÿฅน
    • Third word โ€” this one picks the source files the compiler should emit debug info for. none and any have their normal meanings. base means the base name of the file where the type declaration appears has to match the base name of the main compilation file. So when you compile foo.c, debug info gets generated for types declared in that file and foo.h, but not other header files ๐Ÿ’– sys covers types that satisfy base or are declared in system or compiler headers ๐ŸŽ€
    • You might need to experiment to find the best settings for your app, no cap ๐Ÿ”ฅ
    • The default is -femit-struct-debug-detailed=all ๐ŸŒธ
    • This also only works with DWARF debug output โญ
  • -fno-dwarf2-cfi-asm โ€” emit DWARF unwind info as a compiler-generated ".eh_frame" section, instead of using GAS ".cfi_*" directives. Main character energy in the assembler, honestly ๐Ÿ’œ
  • -fno-eliminate-unused-debug-types โ€” okay so normally, when producing DWARF output, GCC skips debug symbols 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's declared but never actually used in your program. Just know that this often 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 the cost of compilation and make debugging produce the expected results ๐Ÿงš Statements are independent. So 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, but at the expense of compilation time and possibly your ability to debug the program ๐Ÿ˜ญ The compiler optimizes based on what it knows about the program. Compiling multiple files at once to a single output file lets the compiler use information gained from all of the files when compiling each one ๐Ÿซถ

Not all optimizations are controlled directly by a flag. Only the optimizations that have a flag are listed in this section ๐Ÿ™ˆ

Most optimizations are completely disabled at -O0, or if an -O level isn't 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 may be enabled at each -O level than the ones listed here. If you want the exact set for each level, invoke GCC with -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 performing 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-modref
-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 performs nearly all supported optimizations that don't involve a space-speed tradeoff. Compared to -O, this 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 optimization flags:
-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
-ffinite-loops -fgcse  -fgcse-lm -fhoist-adjacent-loads
-finline-functions -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
  • > ๐Ÿšจ Please note the warning under -fgcse about invoking -O2 on programs that use computed gotos. Bestie, read that one before you ship ๐Ÿšจ
  • > ๐Ÿ›ก๏ธ NOTE: In Ubuntu 8.10 and later versions, -D_FORTIFY_SOURCE=2 is set by default. In Ubuntu 24.04 and later versions, -D_FORTIFY_SOURCE=3 is set by default instead. It's activated when -O is set to 2 or higher, and it 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 it also turns on the following optimization flags:
-fgcse-after-reload -fipa-cp-clone -floop-interchange
-floop-unroll-and-jam -fpeel-loops -fpredictive-commoning
-fsplit-loops -fsplit-paths -ftree-loop-distribution
-ftree-loop-vectorize -ftree-partial-pre -ftree-slp-vectorize
-funswitch-loops -fvect-cost-model -fvect-cost-model=dynamic
-fversion-loops-for-strides
  • -O0 โ€” reduce compilation time and make debugging produce 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, causes the compiler to tune for code size rather than execution speed, and performs further optimizations designed to reduce code size ๐Ÿฆ‹
  • -Ofast โ€” disregard strict standards compliance ๐Ÿ’€ -Ofast enables all -O3 optimizations. It also enables optimizations that aren't valid for all standard-compliant programs, so proceed with care ๐Ÿ™ˆ
    • > โš ๏ธ Because -Ofast turns on optimizations that aren't valid for every standard-compliant program, your code might behave differently than you expect. It turns on -ffast-math, -fallow-store-data-races, 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 the optimization level of choice 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 information are disabled at -O0 ๐Ÿซถ
    • Like -O0, -Og completely disables a number of optimization passes, so the individual options controlling them have no effect ๐Ÿ’… Otherwise, -Og enables all -O1 optimization flags except for the ones that may interfere with debugging:
-fbranch-count-reg  -fdelayed-branch -fdse  -fif-conversion
-fif-conversion2 -finline-functions-called-once
-fmove-loop-invariants  -fssa-phiopt -ftree-bit-ccp  -ftree-dse
-ftree-pta  -ftree-sra

If you use multiple -O options, with or without level numbers, the last such option is the one that takes effect ๐Ÿ‘‘

Options of the form -fflag specify machine-independent flags ๐ŸŒˆ Most flags have both positive and negative forms, and the negative form of -ffoo is -fno-foo. In the table below, only one of the forms is listed, the one you typically use. You can figure out the other form by either removing no- or adding it ๐Ÿงš

The following options control specific optimizations. They're either activated by -O options or related to ones that are. You can use the following flags in the rare cases when "fine-tuning" of optimizations to be performed is desired ๐ŸŽ€

  • -fno-defer-pop โ€” okay so on machines that have to pop the arguments after a function call ๐Ÿงน, this makes GCC pop them the second each function returns ๐Ÿ’…. Heads up though: at -O1 and higher, -fdefer-pop is the default, which lets arguments pile up on the stack across several calls and then get popped all at once โœจ.
  • -fforward-propagate โ€” this one's giving RTL realness ๐Ÿฆ‹. It runs a forward propagation pass on RTL that tries to combine two instructions, then checks whether the result can be simplified. If loop unrolling is active, the pass runs twice, and the second run gets scheduled after loop unrolling ๐Ÿ”. Enabled by default at optimization levels -O, -O2, -O3, -Os ๐Ÿ’–.
  • -ffp-contract=style โ€” bestie, this one's a whole mood ๐ŸŽ€. -ffp-contract=off turns floating-point expression contraction OFF ๐Ÿ™…โ€โ™€๏ธ. -ffp-contract=fast turns it on, so things like fused multiply-add operations can get formed if the target has native support for them ๐Ÿ”ฅ. -ffp-contract=on only enables contraction if the language standard allows it ๐Ÿ“œ. Ngl, that one isn't implemented yet and 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 for saving, setting up and restoring the frame pointer, and on lots of targets it also frees up an extra register ๐ŸŒˆ. Sometimes it does nothing, because on some targets the standard calling sequence always uses a frame pointer, so it can't be dropped ๐Ÿ™ˆ. 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 โ€” glow-up time for standard C string functions like "strlen", "strchr" or "strcpy", plus their "_FORTIFY_SOURCE" counterparts, which get turned into faster alternatives ๐ŸŽ๏ธ. Enabled at levels -O2, -O3 โœจ.
  • -fno-inline โ€” no function gets expanded inline except the ones marked with the "always_inline" attribute ๐Ÿ™…. This is the default when you're not optimizing ๐Ÿ’ค. Single functions can be 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 the 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 earlier inlining ๐ŸŽฏ. This only has an effect if inlining 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 it. If every call to a given function gets integrated and that function is declared "static", it's normally not spit out as its own assembler code ๐Ÿซฅ. Enabled at levels -O2, -O3, -Os. Also enabled by -fprofile-use and -fauto-profile ๐Ÿ’–.
  • -finline-functions-called-once โ€” considers all "static" functions called once for inlining into their caller, even if they aren't marked "inline" ๐Ÿฅก. If a call gets integrated, the function isn't output as assembler code in its own right ๐Ÿ™ƒ. 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 in 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 caps the size of functions that can be inlined, and this flag gives you coarse control over that cap ๐ŸŽš๏ธ. n is the size of functions that can be inlined, measured in pseudo instructions ๐Ÿ“.
    • max-inline-insns-single is set to n/2.
    • max-inline-insns-auto is set to n/2.
    • Inlining is actually controlled by a bunch of parameters, which you can set individually with --param name=value ๐Ÿง. The -finline-limit=n option sets some of them like this, as shown above. See below for documentation of the individual inlining parameters and their defaults ๐Ÿ“š.
    • Note: there may be no value of -finline-limit that results in default behavior ๐Ÿ™ƒ.
    • Note: a "pseudo instruction" here is just an abstract measurement of a function's size โœจ. It is in no way a count of assembly instructions, so its exact meaning 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++, 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 they're never referenced ๐Ÿ“. GCC enables this by default ๐Ÿ’…. If you want the compiler to check whether a variable is referenced regardless of optimization, use -fno-keep-static-consts ๐Ÿ”.
  • -fmerge-constants โ€” attempts 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 inhibit this behavior ๐Ÿ›‘. Enabled at levels -O, -O2, -O3, -Os โœจ.
  • -fmerge-all-constants โ€” attempts to merge identical constants and identical variables ๐Ÿงฌ. This implies -fmerge-constants ๐Ÿ”—. On top of that, it also considers things like constant initialized arrays or initialized constant variables with integral or floating-point types ๐Ÿ“š.
๐Ÿšจ Warning: 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. Yikes, bestie ๐Ÿ˜ญ.
  • -fmodulo-sched โ€” performs swing modulo scheduling immediately before the first scheduling pass ๐ŸŒ€. It looks at the 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-dependence edges, which triggers the generation of reg-moves based on life-range analysis ๐Ÿงช. This is only effective with -fmodulo-sched enabled ๐Ÿซถ.
  • -fno-branch-count-reg โ€” disables the optimization pass that hunts for chances to use "decrement and branch" instructions on a count register, instead of decrementing a register, comparing it against zero, and then branching based on the result ๐Ÿ”ข. This 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 introduced by other optimization passes ๐Ÿ™ˆ. The default is -fbranch-count-reg at -O1 and higher, except for -Og โœจ.
  • -fno-function-cse โ€” doesn't put function addresses in registers; instead, each instruction that calls a constant function contains the function's address explicitly ๐Ÿ“. This gives 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 initialized to zero into BSS, which can save space in the resulting code ๐Ÿ’พ. This option turns that behavior off, because some programs explicitly rely on variables going into the data section ๐Ÿ—บ๏ธ. For example, the executable can find the beginning of that section and/or make assumptions based on it. The default is -fzero-initialized-in-bss ๐Ÿ’–.
  • -fthread-jumps โ€” performs optimizations that check whether a jump branches to a location where another comparison, subsumed by the first, is found ๐Ÿ”. If so, the first branch is redirected to either the destination of the second branch or a point immediately following it, depending on whether the condition is known to be true or false ๐Ÿช. Enabled at levels -O2, -O3, -Os ๐ŸŒธ.
  • -fsplit-wide-types โ€” when using a type that occupies multiple registers, like "long long" on a 32-bit system, splits the registers apart and allocates them independently โœ‚๏ธ. This normally generates better code for those types, but it may make debugging more difficult ๐Ÿ›. Enabled at levels -O, -O2, -O3, -Os โœจ.
  • -fsplit-wide-types-early โ€” fully splits wide types early, instead of very late ๐ŸŒ…. This option has no effect unless -fsplit-wide-types is turned on ๐Ÿ™ƒ. It's the default on some targets ๐ŸŽฏ.

-fcse-follow-jumps ====================

Okay so, this one lives in common subexpression elimination (CSE) ๐Ÿ’… It scans through jump instructions when the jump's target isn't reached by any other path. Like, when CSE hits an if with an else clause, it follows the jump when the condition tested is false. Iconic. ๐Ÿฆ‹

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

  • -fcse-skip-blocks โ€” bestie, this is basically the sibling of -fcse-follow-jumps โœจ It makes CSE follow jumps that conditionally skip over blocks. So when CSE sees a simple if with no else clause, this flag has it follow the jump around the body of the if. Main character energy ๐Ÿ‘‘

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

  • -frerun-cse-after-loop โ€” re-runs common subexpression elimination after the loop optimizations are done. It's giving second chances ๐Ÿ”๐ŸŒธ

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

  • -fgcse โ€” performs a global common subexpression elimination pass. This one also does global constant and copy propagation, so it's doing a lot of work for you ๐Ÿซถ
โš ๏ธ Note: When you're compiling a program that uses computed gotos (a GCC extension), you might get better run-time performance if you turn off the global CSE pass by adding -fno-gcse to the command line. Just something to keep in mind, bestie ๐Ÿ˜ญ

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

  • -fgcse-lm โ€” when this is on, global CSE tries to move loads that are only killed by stores into themselves. Translation: a loop with a load/store sequence can become a load outside the loop and a copy/store inside it. Lowkey genius ๐Ÿงš

Enabled by default when -fgcse is enabled.

  • -fgcse-sm โ€” when this is on, a store motion pass runs after global CSE. It tries to move stores out of loops. Used together with -fgcse-lm, a loop with a load/store sequence can become a load before the loop and a store after the loop. Slay ๐Ÿ’–

Not enabled at any optimization level.

  • -fgcse-las โ€” makes the global CSE pass eliminate redundant loads that come after stores to the same memory location. That covers both partial and full redundancies. Very thorough, very serious ๐Ÿงโœจ

Not enabled at any optimization level.

  • -fgcse-after-reload โ€” runs a redundant load elimination pass after reload. Its whole job is to clean up redundant spilling ๐Ÿงน๐Ÿ’œ

Enabled by -fprofile-use and -fauto-profile.

  • -faggressive-loop-optimizations โ€” tells the loop optimizer to use language constraints to work out bounds for the number of loop iterations. This assumes the loop code doesn't invoke undefined behavior, like causing signed integer overflows or out-of-bound array accesses. Those bounds then guide loop unrolling, loop peeling, and loop exit test optimizations. This option is enabled by default. ๐Ÿ”ฅ
โš ๏ธ Heads up, bestie: this one relies on your code not hitting undefined behavior. Signed integer overflow or out-of-bounds array access breaks that assumption, so keep your code clean ๐Ÿ™ˆ
  • -funconstrained-commons โ€” tells the compiler that variables declared in common blocks (for example, in Fortran) may later be overridden with longer trailing arrays. This stops certain optimizations that depend on knowing the array bounds from happening ๐ŸŒˆ
  • -fcrossjumping โ€” performs the cross-jumping transformation. It unifies equivalent code and saves code size. The result may or may not perform better than code without cross-jumping, so it's a bit of a vibe check ๐Ÿฆ‹

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. It's enabled by default at -O and higher on architectures that do support it โœจ
  • -fdce โ€” performs dead code elimination (DCE) on RTL. Enabled by default at -O and higher. Bye bye, unused code ๐Ÿ‘‹๐Ÿ’€
  • -fdse โ€” performs dead store elimination (DSE) on RTL. Enabled by default at -O and higher. Stores nobody reads get yeeted ๐Ÿ—‘๏ธ๐ŸŒธ
  • -fif-conversion โ€” attempts to transform conditional jumps into branch-less equivalents. This includes conditional moves, min, max, set flags, and abs instructions, plus some tricks you can do 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 โ€” okay, C++ ABI moment ๐Ÿค“ The 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, meaning two copies of the function. With this option, those variants become thunks that call one common implementation. Less duplicated code, more slay ๐Ÿ’…

Enabled by -Os.

  • -fdelete-null-pointer-checks โ€” assumes that programs can't safely dereference null pointers, and that no code or data lives at address zero. This enables simple constant folding optimizations at all optimization levels. Other passes in GCC also use this flag to control global dataflow analyses that eliminate useless null pointer checks. Those assume that a memory access to address zero always traps, so if a pointer gets checked after it's already been dereferenced, it can't be null. Big brain logic ๐Ÿง 
โš ๏ธ Not every environment agrees with that assumption! If your program depends on dereferencing address zero, use -fno-delete-null-pointer-checks to turn this optimization off.

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 โ€” attempts 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 โ€” attempts 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 (preferably size 1), the call becomes a conditional that picks between a direct call and an indirect call. The speculative calls enable more optimizations, like inlining. If they seem useless after further optimization, they get converted back to their original form ๐Ÿ”„
  • -fdevirtualize-at-ltrans โ€” streams extra information needed for aggressive devirtualization when running the link-time optimizer in local transformation mode. It enables more devirtualization, but it 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 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++, an object's value is only affected by changes within its lifetime. When the constructor begins, the object has an indeterminate value, and any changes during its lifetime are dead once the object is destroyed. Normally dead store elimination takes advantage of this. If your code relies on the object storage's value persisting past the object's lifetime, use this flag to disable the optimization. To keep stores made before the constructor starts (for example, because your operator new clears the object storage) but still treat the object as dead after the destructor, use -flifetime-dse=1. The default behavior can be explicitly selected with -flifetime-dse=2. And -flifetime-dse=0 is the same as -fno-lifetime-dse ๐Ÿงšโ€โ™€๏ธ
  • -flive-range-shrinkage โ€” attempts to decrease register pressure through register live range shrinkage. Helpful for fast processors with small or moderate-size register sets ๐Ÿƒโ€โ™€๏ธ๐Ÿ’จ
  • -fira-algorithm=algorithm โ€” picks the coloring algorithm for the integrated register allocator. The algorithm argument can be priority, which is Chow's priority coloring, or CB, which is Chaitin-Briggs coloring. Chaitin-Briggs isn't implemented for every architecture, but on targets that do support it, it's the default because it generates better code ๐ŸŽจ
  • -fira-region=region โ€” picks the regions the integrated register allocator uses. The region argument should be one of the following:
    • all โ€” uses all loops as register allocation regions. This can give the best results on machines with a small and/or irregular register set ๐ŸŽฏ
    • mixed โ€” uses all loops except loops with small register pressure as the regions. This 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 โ€” uses IRA to evaluate register pressure in the code hoisting pass when deciding whether to hoist expressions. This usually results in smaller code, but it can slow the compiler down ๐Ÿข

This option is enabled at level -Os for all targets.

  • -fira-loop-pressure โ€” uses IRA to evaluate register pressure in loops when deciding whether to move loop invariants. This usually results in faster and smaller code on machines with large register files (32 or more registers), but it can slow the compiler down ๐ŸŒโœจ

This option is enabled at level -O3 for some targets.

  • -fno-ira-share-save-slots โ€” ๐Ÿงธ Okay so this one turns OFF sharing of stack slots used for saving call-used hard registers that stay alive through a call. Every hard register gets its own separate stack slot, which means function stack frames end up larger ๐Ÿ“ฆ
  • -fno-ira-share-spill-slots โ€” ๐ŸŒธ This one switches off sharing of stack slots for pseudo-registers. Each pseudo-register that doesn't get a hard register gets its own slot, so, again, function stack frames are larger ๐Ÿฅฒ
  • -flra-remat โ€” ๐Ÿฆ‹ Turns on CFG-sensitive rematerialization in LRA. Instead of loading values of spilled pseudos from memory, LRA tries to rematerialize (recalculate) them when that's actually profitable ๐Ÿงฎ Switched on at -O2, -O3, -Os โœจ
  • -fdelayed-branch โ€” ๐Ÿงš If the target machine supports it, GCC tries to reorder instructions so it can use the instruction slots that come after delayed branch instructions ๐Ÿ“ Switched on at -O, -O2, -O3, -Os, but not at -Og ๐Ÿ™ˆ
  • -fschedule-insns โ€” โญ If supported for the target machine, GCC tries to reorder instructions to get rid of execution stalls caused by data that isn't ready yet โณ This is a lifesaver for machines with slow floating point or memory load instructions, because other instructions can get issued while the load or float op is still cooking, until the result is actually needed ๐Ÿ’œ Switched on at -O2, -O3 ๐Ÿ”ฅ
  • -fschedule-insns2 โ€” ๐Ÿ’– Basically the same vibe as -fschedule-insns, but it asks for an extra scheduling pass after register allocation is done ๐Ÿซถ This is especially iconic on machines with a relatively small number of registers, where memory load instructions take more than one cycle ๐ŸŒˆ Switched on at -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. Normally this is on 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 enabled, i.e. with -fschedule-insns or at -O2 or higher ๐Ÿง  It can improve the generated code and shrink its size by stopping register pressure from climbing above the number of available hard registers, which would otherwise lead to spills during register allocation ๐Ÿ’ช
  • -fsched-spec-load โ€” ๐ŸŽˆ Allows speculative motion of some load instructions. 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. Same deal: it only makes sense when scheduling before register allocation, i.e. with -fschedule-insns or at -O2 or higher. It's called "dangerous" for a reason, bestie ๐Ÿ’€
  • -fsched-stalled-insns, -fsched-stalled-insns=n โ€” ๐Ÿข This decides how many insns (if any) can be moved early from the queue of stalled insns into the ready list during the second scheduling pass โฉ -fno-sched-stalled-insns means nothing gets moved early, -fsched-stalled-insns=0 means there's no limit on how many queued insns can jump ahead, and plain -fsched-stalled-insns with no value is the same as -fsched-stalled-insns=1 ๐Ÿซถ
  • -fsched-stalled-insns-dep, -fsched-stalled-insns-dep=n โ€” ๐Ÿ” This 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 ๐Ÿ•ต๏ธโ€โ™€๏ธ It only does anything during the second scheduling pass, and only if -fsched-stalled-insns is used. -fno-sched-stalled-insns-dep is the same as -fsched-stalled-insns-dep=0, and plain -fsched-stalled-insns-dep with no value is the same as -fsched-stalled-insns-dep=1 โœจ
  • -fsched2-use-superblocks โ€” ๐Ÿงช When scheduling after register allocation, this uses superblock scheduling. That lets instructions move across basic block boundaries, which can give faster schedules ๐ŸŽ๏ธ
โš ๏ธ Heads up, bestie: this one is experimental! Not all machine descriptions used by GCC model the CPU closely enough, so the algorithm can give unreliable results ๐Ÿ˜ญ This only makes sense when scheduling after register allocation, i.e. with -fschedule-insns2 or at -O2 or higher.
  • -fsched-group-heuristic โ€” ๐Ÿ‘ฏ Enables the group heuristic in the scheduler, which favors the instruction that belongs to a schedule group ๐Ÿ’• This is enabled by default whenever scheduling is enabled, i.e. with -fschedule-insns or -fschedule-insns2 or at -O2 or higher ๐ŸŒธ
  • -fsched-critical-path-heuristic โ€” ๐Ÿ›ฃ๏ธ Enables the critical-path heuristic in the scheduler, which favors instructions sitting on the critical path ๐Ÿƒโ€โ™€๏ธ Also on by default whenever scheduling is enabled, i.e. with -fschedule-insns or -fschedule-insns2 or at -O2 or higher ๐Ÿ’–
  • -fsched-spec-insn-heuristic โ€” ๐ŸŽฏ Enables the speculative instruction heuristic in the scheduler, which favors speculative instructions with greater dependency weakness ๐Ÿฅฐ Enabled by default when scheduling is enabled, i.e. with -fschedule-insns or -fschedule-insns2 or at -O2 or higher โœจ
  • -fsched-rank-heuristic โ€” ๐Ÿ† Enables the rank heuristic in the scheduler, which favors the instruction belonging to a basic block with greater size or frequency ๐Ÿ“ˆ Enabled by default when scheduling is enabled, i.e. with -fschedule-insns or -fschedule-insns2 or at -O2 or higher ๐Ÿ‘‘
  • -fsched-last-insn-heuristic โ€” ๐Ÿ”— Enables the last-instruction heuristic in the scheduler, which favors the instruction that is less dependent on the last instruction scheduled ๐Ÿ™Œ Enabled by default when scheduling is enabled, i.e. with -fschedule-insns or -fschedule-insns2 or at -O2 or higher ๐Ÿฆ‹
  • -fsched-dep-count-heuristic โ€” ๐Ÿงต Enables the dependent-count heuristic in the scheduler, which favors the instruction that has more instructions depending on it ๐Ÿ•ธ๏ธ Enabled by default when scheduling is enabled, i.e. with -fschedule-insns or -fschedule-insns2 or at -O2 or higher ๐Ÿ’…
  • -freschedule-modulo-scheduled-loops โ€” ๐Ÿ” Modulo scheduling happens before the traditional scheduling. If a loop gets modulo scheduled, later scheduling passes may change its schedule, and this option is how you control that behavior ๐ŸŽ›๏ธ
  • -fselective-scheduling โ€” ๐ŸŽ€ Schedules instructions using the selective scheduling algorithm. Selective scheduling runs instead of the first scheduler pass ๐Ÿช„
  • -fselective-scheduling2 โ€” ๐ŸŽ€ Schedules instructions using the selective scheduling algorithm too, but this time it runs instead of the second scheduler pass ๐Ÿซง
  • -fsel-sched-pipelining โ€” ๐Ÿฅ Enables software pipelining of innermost loops during selective scheduling ๐Ÿ”„ This has no effect 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 ๐ŸŒ€ It has no effect 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, and other optimizations, since the function or variable might get swapped out for something else ๐Ÿ”€ This is super useful for things like rewriting 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 ๐Ÿค The flag has no effect for functions explicitly declared inline, where interposition is never allowed to change semantics, and for 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 those parts only run when they're needed ๐ŸŒ™ This option is on by default, but it has no effect unless -fshrink-wrap is also turned on and the target supports this ๐Ÿซถ
  • -fcaller-saves โ€” ๐Ÿ›Ÿ Enables allocation of values to registers that get clobbered by function calls, 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 ๐Ÿฅ‡ This option is always enabled by default on certain machines, usually the ones that have no call-preserved registers to use instead ๐ŸŒˆ Switched on at -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 those registers aren't used by any called function. In that case, 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're compiled before it ๐Ÿ“š Switched on at -O2, -O3, -Os, however it gets 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 โ€” ๐Ÿชถ Attempts to minimize stack usage, using less stack space even if that makes the program slower ๐ŸŒ This option implies setting the large-stack-frame parameter to 100 and the large-stack-frame-growth parameter to 400 ๐Ÿงฎ
  • -ftree-reassoc โ€” ๐ŸŒณ Performs reassociation on trees ๐Ÿ”€ Enabled by default at -O and higher โœจ
  • -fcode-hoisting โ€” ๐Ÿ—๏ธ Performs code hoisting. Code hoisting tries to move the evaluation of expressions that get executed 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 ๐Ÿš€ Enabled by default at -O2 and higher ๐Ÿ‘‘
  • -ftree-pre โ€” okay bestie, this one runs partial redundancy elimination (PRE) on trees ๐ŸŒณโœจ It's on by default at -O2 and -O3 ๐Ÿ’–
  • -ftree-partial-pre โ€” makes PRE extra aggressive ๐Ÿ˜ค๐Ÿ”ฅ It's on by default at -O3 only ๐Ÿ‘‘
  • -ftree-forwprop โ€” forward propagation on trees, lowkey essential ๐Ÿฆ‹ On by default at -O and higher.
  • -ftree-fre โ€” full redundancy elimination (FRE) on trees ๐Ÿ’… The tea is that FRE only looks at expressions computed on all paths leading to the redundant computation. It's faster than PRE but catches fewer redundancies, so it's giving speed ๐Ÿƒโ€โ™€๏ธ๐Ÿ’จ On by default at -O and higher.
  • -ftree-phiprop โ€” hoists loads from conditional pointers on trees ๐Ÿงš This pass is on by default at -O and higher.
  • -fhoist-adjacent-loads โ€” speculatively hoists loads from both branches of an if-then-else when the loads come from adjacent spots in the same structure and the target architecture has a conditional move instruction ๐Ÿซถ On by default at -O2 and higher.
  • -ftree-copy-prop โ€” copy propagation on trees, which clears out unnecessary copy operations ๐Ÿงน On by default at -O and higher.
  • -fipa-pure-const โ€” discovers which functions are pure or constant ๐Ÿ” On by default at -O and higher.
  • -fipa-reference โ€” discovers which static variables don't escape the compilation unit ๐Ÿ™ˆ On by default at -O and higher.
  • -fipa-reference-addressable โ€” discovers read-only, write-only, and non-addressable static variables ๐ŸŒธ On by default at -O and higher.
  • -fipa-stack-alignment โ€” reduces stack alignment on call sites when it's possible ๐Ÿ“ Enabled by default.
  • -fipa-pta โ€” interprocedural pointer analysis plus interprocedural modification and reference analysis ๐Ÿง 
โš ๏ธ bestie, this one can cause excessive memory and compile-time usage on large compilation units ๐Ÿ’€ It is not enabled by default at any optimization level, so you have to ask for it on purpose.
  • -fipa-profile โ€” interprocedural profile propagation ๐Ÿ“Š Functions called only from cold functions get marked as cold, and functions executed once (such as "cold", "noreturn", static constructors or destructors) get identified. Cold functions and loop-less parts of functions executed once then get optimized for size ๐Ÿฅก Enabled by default at -O and higher.
  • -fipa-modref โ€” interprocedural mod/ref analysis ๐Ÿ”Ž It analyzes the side effects of functions (the memory locations they modify or reference) and unlocks better optimization across the function call boundary ๐Ÿšง On by default at -O and higher.
  • -fipa-cp โ€” interprocedural constant propagation ๐Ÿ’Ž It figures out when values passed to functions are constants and optimizes accordingly. If your app passes constants to functions a lot, this can substantially increase performance ๐Ÿš€ On by default at -O2, -Os, and -O3. It's also enabled by -fprofile-use and -fauto-profile.
  • -fipa-cp-clone โ€” function cloning to make IPA constant propagation stronger ๐Ÿ‘ฏ When enabled, it clones a function when an externally visible function can be called with constant arguments. Since this can create multiple copies of functions, it may significantly increase code size (see --param ipa-cp-unit-growth=value) ๐Ÿ“ฆ On by default at -O3. It's also enabled by -fprofile-use and -fauto-profile.
  • -fipa-bit-cp โ€” interprocedural bitwise constant propagation ๐Ÿ”ข On by default at -O2, and by -fprofile-use and -fauto-profile. It requires that -fipa-cp is enabled.
  • -fipa-vrp โ€” interprocedural propagation of value ranges ๐Ÿ“ On by default at -O2. It requires that -fipa-cp is enabled.
  • -fipa-icf โ€” Identical Code Folding for functions and read-only variables ๐Ÿชž It reduces code size, but it may disturb unwind stacks by swapping a function out for an equivalent one with a different name. It works way better with link-time optimization turned on ๐Ÿ”—

Although it behaves similarly to the Gold Linker's ICF optimization, GCC ICF works on different levels, so the optimizations aren't the same. There are equivalences only GCC finds and equivalences only Gold finds ๐Ÿค“

On by default at -O2 and -Os.

  • -flive-patching=level โ€” controls GCC's optimizations so the output is suitable for live-patching ๐Ÿฉน

Okay so, if the compiler's optimization uses a function's body (or info pulled from its body) to optimize or change another function, that other function is called an impacted function of the first one. If a function gets patched, its impacted functions should get patched too ๐Ÿ’…

The impacted functions are determined by the compiler's interprocedural optimizations. For example, a caller is impacted when a function gets inlined into it, when a function gets cloned and its caller is changed to call the new clone, or when a function's pureness/constness info is extracted to optimize its direct or indirect callers, etc. ๐ŸŒ€

Usually, the more IPA optimizations are enabled, the more impacted functions each function has. To keep that number under control and make the list easier to compute, IPA optimizations can be partially enabled at two different levels โœจ

The level argument should be one of the following:

  • inline-clone โ€” only enables inlining and cloning optimizations, which includes 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 too ๐ŸŽ€

-flive-patching=inline-clone disables these 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 -fipa-modref

  • inline-only-static โ€” only enables inlining of static functions ๐ŸงŠ As a result, when patching a static function, all its callers are impacted and need to be patched as well.

On top of everything -flive-patching=inline-clone disables, -flive-patching=inline-only-static also disables these 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). Don't mix them, bestie.
  • -fisolate-erroneous-paths-dereference โ€” detects paths that trigger erroneous or undefined behavior from dereferencing a null pointer ๐Ÿ•ณ๏ธ It isolates those paths from the main control flow and turns the statement with the erroneous or undefined behavior into a trap ๐Ÿชค On by default at -O2 and higher, and it depends on -fdelete-null-pointer-checks also being enabled.
  • -fisolate-erroneous-paths-attribute โ€” detects paths that trigger erroneous or undefined behavior because a null value gets used in a way forbidden by a "returns_nonnull" or "nonnull" attribute ๐Ÿšซ It isolates those paths from the main control flow and turns the statement into a trap. This is not currently enabled, but it may be enabled by -O2 in the future ๐Ÿ‘€
  • -ftree-sink โ€” forward store motion on trees ๐Ÿšš On by default at -O and higher.
  • -ftree-bit-ccp โ€” sparse conditional bit constant propagation on trees, plus pointer alignment info propagation ๐Ÿงฉ This pass only operates on local scalar variables. It's enabled by default at -O1 and higher, except for -Og ๐Ÿ™ƒ It requires that -ftree-ccp is enabled.
  • -ftree-ccp โ€” 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 โ€” propagates info about uses of a value up the definition chain so the definitions can get simplified ๐Ÿ”™ 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 โ€” 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 โ€” converts simple initializations in a switch into initializations from a scalar array ๐Ÿ”€ On by default at -O2 and higher.
  • -ftree-tail-merge โ€” looks for identical code sequences, and when it finds them, replaces one with a jump to the other ๐Ÿช„ This optimization is known as tail merging or cross jumping. It's on by default at -O2 and higher. The compilation time in this pass can be limited with the max-tail-merge-comparisons parameter and the max-tail-merge-iterations parameter โฑ๏ธ
  • -ftree-dce โ€” dead code elimination (DCE) on trees ๐Ÿ—‘๏ธ On by default at -O and higher.
  • -ftree-builtin-call-dce โ€” conditional dead code elimination (DCE) for calls to built-in functions that may set errno but are otherwise free of side effects ๐Ÿงน On by default at -O2 and higher, if -Os is not also specified.
  • -ffinite-loops โ€” assumes that a loop with an exit will eventually take the exit and won't loop forever ๐Ÿ” That lets the compiler remove loops that otherwise have no side effects, without treating eventual endless looping as a thing to worry about ๐Ÿ’ค

This option is enabled by default at -O2 for C++ with -std=c++11 or higher.

  • -ftree-dominator-opts โ€” a bunch of simple scalar cleanups (constant/copy propagation, redundancy elimination, range propagation, and expression simplification) based on a dominator tree traversal ๐ŸŒณ๐Ÿ’• It also performs jump threading, which reduces jumps to jumps ๐Ÿงต This flag is enabled by default at -O and higher.
  • -ftree-dse โ€” okay so this one does dead store elimination (DSE) on trees ๐Ÿ’… A dead store is a store into a memory location that gets overwritten by a later store with no loads sneaking in between. That first store is literally dead weight, so it can be deleted โœจ Enabled by default at -O and higher ๐Ÿ”ฅ
  • -ftree-ch โ€” loop header copying on trees ๐Ÿฆ‹ It's lowkey iconic because it makes code motion optimizations way more effective, and it saves one jump too ๐ŸŒธ Enabled by default at -O and higher. It is not enabled for -Os, since it usually bloats code size ๐Ÿ’€
  • -ftree-loop-optimize โ€” loop optimizations on trees ๐Ÿ” Enabled by default at -O and higher ๐Ÿ’œ
  • -ftree-loop-linear, -floop-strip-mine, -floop-block โ€” loop nest optimizations, same as -floop-nest-optimize ๐Ÿงš To actually use this transformation, GCC has to be configured with --with-isl so the Graphite loop transformation infrastructure is turned on ๐Ÿ› ๏ธ
  • -fgraphite-identity โ€” the identity transformation for graphite ๐Ÿชž For every SCoP, GCC builds the polyhedral representation and transforms it back to gimple. With -fgraphite-identity 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 โ€” the isl based loop nest optimizer ๐Ÿง  It's a generic one built on the Pluto optimization algorithms, and it calculates a loop structure tuned for data-locality and parallelism โœจ
โš ๏ธ Heads up, bestie: this option is experimental.
  • -floop-parallelize-all โ€” uses Graphite data dependence analysis to find loops that can be parallelized ๐Ÿงต It parallelizes all the loops that can be analyzed as not containing loop carried dependences, without checking whether parallelizing them is actually profitable ๐Ÿซถ
  • -ftree-coalesce-vars โ€” when the program leaves SSA form, this tries to cut down on copying by coalescing versions of different user-defined variables, not just compiler temporaries ๐Ÿงน In the negated form, this flag prevents SSA coalescing of user variables. Enabled by default if optimization is enabled, and it does very little otherwise ๐Ÿ’–
โš ๏ธ This may severely limit your ability to debug an optimized program compiled with -fno-var-tracking-assignments.
  • -ftree-loop-if-convert โ€” tries to transform conditional jumps in the innermost loops into branch-less equivalents ๐ŸŒˆ The goal is to remove control flow from the 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 let further loop optimizations, like parallelization or vectorization, take place. For example, this 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 is also enabled by -fprofile-use and -fauto-profile.

  • -ftree-loop-distribute-patterns โ€” distributes loops of patterns that can be code generated as calls to a library ๐Ÿ“š Enabled by default at -O2 and higher, and by -fprofile-use and -fauto-profile.

This pass distributes the initialization loops and generates a call to memset zero. For example, this 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 turned into a call to memset zero. This flag is enabled by default at -O3. It is 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, this loop nest:
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 is 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. It is also enabled 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 RTL level, like function calls and operations that expand to nontrivial sequences of insns. With -funswitch-loops it also moves the operands of invariant conditions out of the loop, so loop unswitching can use 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 that out takes complicated analysis ๐Ÿ”ข Later optimizations can then determine the number easily. It's especially useful alongside unrolling.
  • -ftree-scev-cprop โ€” performs final value replacement ๐Ÿ’ซ If a variable is modified in a loop so that its value on exit can be figured out from only its initial value and the number of loop iterations, uses of the final value get swapped out for that computation, as long as it's cheap enough. This reduces data dependencies and may allow further simplifications. Enabled by default at -O and higher.
  • -fivopts โ€” induction variable optimizations (strength reduction, induction variable merging and induction variable elimination) on trees ๐Ÿงฎ
  • -ftree-parallelize-loops=n โ€” parallelizes loops by 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 ones constrained by things like memory bandwidth. This option implies -pthread, so it's only supported on targets that have support for -pthread.
  • -ftree-pta โ€” function-local points-to analysis on trees ๐ŸŽฏ Enabled by default at -O1 and higher, except for -Og.
  • -ftree-sra โ€” 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 ๐Ÿงฉ It combines contiguous stores of immediate values that are narrower than a word into fewer, wider stores, cutting down on the number of instructions. Enabled by default at -O2 and higher as well as -Os.
  • -ftree-ter โ€” 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 โ€” straight-line strength reduction on trees ๐Ÿ“ It recognizes related expressions involving multiplications and replaces them with less expensive calculations when possible. Enabled by default at -O and higher.
  • -ftree-vectorize โ€” vectorization on trees ๐Ÿš€ This flag enables -ftree-loop-vectorize and -ftree-slp-vectorize if they aren't explicitly specified.
  • -ftree-loop-vectorize โ€” loop vectorization on trees ๐ŸŽ€ Enabled by default at -O3 and by -ftree-vectorize, -fprofile-use, and -fauto-profile.
  • -ftree-slp-vectorize โ€” basic block vectorization on trees ๐Ÿ’Ž Enabled by default at -O3 and by -ftree-vectorize, -fprofile-use, and -fauto-profile.
  • -fvect-cost-model=model โ€” alters the cost model used for vectorization ๐Ÿ’ฐ The model argument should be one of unlimited, dynamic, cheap or very-cheap.
    • unlimited โ€” the vectorized code path is assumed to be profitable ๐ŸŒŸ
    • dynamic โ€” 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 ๐Ÿƒโ€โ™€๏ธ
    • cheap โ€” disables vectorization of loops where doing so would be cost prohibitive, for example because of required runtime checks for data dependence or alignment, but otherwise it's the same as dynamic ๐Ÿซง
    • very-cheap โ€” only allows vectorization if the vector code would entirely replace the scalar code being vectorized. For example, if each iteration of a vectorized loop could only handle exactly four iterations of the scalar loop, the very-cheap model would only allow vectorization if the scalar iteration count is known to be a multiple of four ๐Ÿฅน

The default cost model depends on other optimization flags and is either dynamic or cheap.

  • -fsimd-cost-model=model โ€” alters the cost model used for vectorization of loops marked with the OpenMP simd directive ๐Ÿซง The model argument should be one of unlimited, dynamic, cheap. 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.
  • -ftree-vrp โ€” okay so this one is a whole vibe ๐Ÿ’… It performs Value Range Propagation on trees. It's like constant propagation's cooler cousin, because instead of tracking single values, it tracks ranges of values โœจ That lets the optimizers yeet unnecessary range checks like array bound checks and null pointer checks. It's enabled by default at -O2 and higher.
Null pointer check elimination is only done if -fdelete-null-pointer-checks is enabled, so don't forget that one, bestie ๐Ÿ™ˆ
  • -fsplit-paths โ€” this splits paths leading to loop backedges, and it's giving main character energy for two reasons ๐Ÿ‘‘ It can improve dead code elimination and common subexpression elimination. It's enabled by default at -O3 and above. ๐Ÿ”ฅ
  • -fsplit-ivs-in-unroller โ€” enables expressing the values of induction variables in later iterations of the unrolled loop using the value from the first iteration. This breaks long dependency chains, which means better efficiency for the scheduling passes ๐Ÿฆ‹

Ngl, a combination of -fweb and CSE is often enough to get the same effect ๐Ÿซถ However, 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 makes multiple copies of some local variables, which can result in superior code ๐Ÿ’œ

This one is enabled by default for PowerPC targets, but disabled by default otherwise.

  • -fpartial-inlining โ€” inlines parts of functions ๐Ÿงš 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. ๐ŸŒธ

  • -fpredictive-commoning โ€” performs predictive commoning, which is basically reusing computations (especially memory loads and stores) from previous iterations of loops. It's giving efficiency ๐Ÿ’…

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, the compiler generates instructions to prefetch memory, which can boost loops that access large arrays ๐Ÿš€

Honestly this one is a gamble ๐ŸŽฒ It may generate better or worse code, and the results are highly dependent on the structure of 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 is iconic because GCC can optimize or even eliminate branches based on the known return value of these functions, as long as the arguments are constant or known to be in a range that makes the exact return value possible ๐Ÿง 

Here's the example, and it's so good ๐ŸคŒ 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 โ€” these disable any machine-specific peephole optimizations. The difference between them is in how they're implemented in the compiler, so 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. Lowkey a niche one, but iykyk ๐Ÿ™ˆ

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, then the heuristics guess the probabilities for the rest of the control flow graph, taking the __builtin_expect info into account. The interactions between the heuristics and __builtin_expect can get complex, so sometimes it's useful to disable the heuristics 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 โ€” uses the specified algorithm for basic block reordering. The algorithm argument can be simple, which doesn't increase code size (except sometimes because of secondary effects like alignment), or stc, the "software trace cache" algorithm. stc tries to put all the often executed code together, minimizing 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 one partitions hot and cold basic blocks into separate sections of the assembly and .o files, to improve 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 isn't enabled by default (to avoid linker errors), but it may 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 with special subsections, .text.hot for the most frequently executed functions and .text.unlikely for unlikely executed functions. The reordering is done by the linker, so the object file format must support named sections and the linker must 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 โ€” this lets the compiler assume the strictest aliasing rules that apply to the language being compiled. For C (and C++), it activates optimizations based on the type of expressions ๐Ÿง  An object of one type is assumed to never 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;
}

Type-punning, which is reading from a different union member than the one most recently written to, 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 memory by taking the address, casting the resulting pointer, and dereferencing the result has undefined behavior, even if the cast uses a union type. Undefined behavior is not the vibe ๐Ÿ’€ For example:
int f() {
  double d = 3.0;
  return ((union a_union *) &d)->i;
}

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 โ€” this aligns the start of functions to the next power-of-two greater than or equal to n, skipping up to m-1 bytes ๐Ÿฆ‹ That way, at least the first m bytes of the function can be fetched by the CPU without crossing an n-byte alignment boundary. If m isn't specified, it defaults to n. ๐Ÿงš

Here are some examples that are literally so satisfying โœจ -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 specify a secondary alignment. -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 isn't 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 isn't specified or is zero, the compiler uses a machine-dependent default. The maximum allowed n option value is 65536. ๐Ÿ”ฅ

Enabled at levels -O2, -O3. โœจ

  • -flimit-function-alignment โ€” if this option is enabled, the compiler tries to avoid unnecessarily overaligning functions ๐Ÿซถ It attempts to instruct 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 ๐Ÿงš

Okay so the parameters for this one are basically the same vibe as -falign-functions ๐Ÿ’…. -fno-align-labels and -falign-labels=1 are equivalent, bestie, and both mean labels just don't get aligned ๐Ÿ™ˆ

If -falign-loops or -falign-jumps apply and are bigger than this value, their values win instead โœจ

If n isn't specified or is zero, GCC uses a machine-dependent default, which is very likely 1, aka no alignment at all ๐Ÿซถ The maximum allowed n value is 65536.

Enabled at levels -O2, -O3.


๐Ÿฆ‹ -falign-loops

-falign-loops
-falign-loops=n
-falign-loops=n:m
-falign-loops=n:m:n2
-falign-loops=n:m:n2:m2

Aligns loops to a power-of-two boundary. If the loops run a bunch of times, the extra cost of the dummy padding instructions is totally worth it ๐Ÿ’–

If -falign-labels is bigger than this value, its value gets used instead.

The parameters work the same way as -falign-functions. -fno-align-loops and -falign-loops=1 are equivalent and mean loops are not aligned. The maximum allowed n value is 65536.

If n isn't specified or is zero, GCC uses a machine-dependent default.

Enabled at levels -O2, -O3.


๐ŸŒธ -falign-jumps

-falign-jumps
-falign-jumps=n
-falign-jumps=n:m
-falign-jumps=n:m:n2
-falign-jumps=n:m:n2:m2

Aligns branch targets to a power-of-two boundary, but only for branch targets that can only be reached by jumping. In that case, no dummy operations have to be executed, so it's giving efficiency ๐Ÿงš

If -falign-labels is bigger than this value, its value gets used instead.

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, GCC uses a machine-dependent default. The maximum allowed n value is 65536.

Enabled at levels -O2, -O3.


๐Ÿ’… -fno-allocation-dce

Do not remove unused C++ allocations during dead code elimination. Keep those allocations, babe ๐Ÿ™…โ€โ™€๏ธ


โšก -fallow-store-data-races

This lets the compiler do optimizations that might introduce new data races on stores, without proving the variable can't be accessed by other threads at the same time. It does not affect optimization of local data. It's only safe to use this if you know global data won't be touched by multiple threads ๐Ÿ˜ญ

Examples of what this unlocks include hoisting or if-conversions that might cause a value already in memory to be rewritten with that same value. That rewrite is totally fine in a single-threaded context, but can be unsafe with multiple threads. Also, on some processors, if-conversions might be required to enable vectorization.

Enabled at level -Ofast.

โš ๏ธ Only use this if global data is never accessed by multiple threads. Otherwise you can get data races, and that's a real mess, not a cute one ๐Ÿ’€

๐ŸŽ€ -funit-at-a-time

This option is only here for compatibility reasons. -funit-at-a-time does absolutely nothing, while -fno-unit-at-a-time implies -fno-toplevel-reorder and -fno-section-anchors.

Enabled by default.


๐Ÿ“ -fno-toplevel-reorder

Does not reorder top-level functions, variables, and asm statements. They get output in the same order they appear in the input file. When this is on, unreferenced static variables are not removed. It exists to support existing code that depends on a specific ordering. For new code, it's better to use attributes whenever possible ๐Ÿ‘‘

-ftoplevel-reorder is the default at -O1 and higher, and also at -O0 if -fsection-anchors is explicitly requested. Also, -fno-toplevel-reorder implies -fno-section-anchors.


๐Ÿ•ธ๏ธ -fweb

Constructs webs, as commonly used for register allocation purposes, and assigns each web its own individual pseudo register. The register allocation pass can then operate on pseudos directly, and it also strengthens several other optimization passes, like CSE, the loop optimizer, and the trivial dead code remover. Heads up though: it can make debugging impossible, since variables no longer stay in a "home register" ๐Ÿ™ˆ

Enabled by default with -funroll-loops.


๐ŸŒˆ -fwhole-program

Assumes the current compilation unit is the whole program being compiled. All public functions and variables, except main and those merged by the attribute externally_visible, become static functions. That means interprocedural optimizers can go way harder on them โœจ

โš ๏ธ Don't use this together with -flto. Relying on a linker plugin gives safer and more precise information instead.

๐Ÿš€ -flto[=n]

This runs the standard link-time optimizer. When it's invoked 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 from those ELF sections and instantiated as if they were part of the same translation unit. Iconic behavior honestly ๐Ÿ”ฅ

To use the link-time optimizer, you need -flto and your optimization options at compile time and during the final link. It's recommended that you compile every file in the same link with the same options, and specify those options at link time too. 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 one internal image, and compiles the result as usual. Since both are merged into a single image, all the interprocedural analyses and optimizations in GCC work across the two files as if they were one. So, for example, the inliner can inline functions in bar.o into functions in foo.o and vice-versa ๐Ÿฆ‹

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

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

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

The important thing to remember: to enable link-time optimizations, you need to use the GCC driver to perform 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 need to make certain whole program assumptions. The compiler needs to know which functions and variables can be accessed by libraries and runtime outside the link-time optimized unit. When the linker supports it, the linker plugin (see -fuse-linker-plugin) passes information to the compiler about used and externally visible symbols. When the linker plugin isn't available, -fwhole-program should be used so the compiler can make these assumptions, which leads to more aggressive optimization decisions.

When a file is compiled with -flto 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 be linked as normal object files. If -fno-lto is passed to the linker, no interprocedural optimizations are applied. Note that when -fno-fat-lto-objects is enabled, the compile stage is faster, but you cannot perform a regular, non-LTO link on them ๐Ÿ˜ญ

When producing the final binary, GCC only applies link-time optimizations to files that contain bytecode. So you can mix and match object files and libraries with GIMPLE bytecodes and final object code. GCC automatically selects which files to optimize in LTO mode and which files to link without further processing ๐Ÿซถ

Generally, options specified at link time override those specified at compile time, although in some cases 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 used when compiling the object files. 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 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: -fcommon, -fexceptions, -fnon-call-exceptions, -fgnu-tm and all the -m target flags.

The following options -fPIC, -fpic, -fpie and -fPIE are combined based on this scheme:

B<-fPIC> + B<-fpic> = B<-fpic>
B<-fPIC> + B<-fno-pic> = B<-fno-pic>
B<-fpic/-fPIC> + (no option) = (no option)
B<-fPIC> + B<-fPIE> = B<-fPIE>
B<-fpic> + B<-fPIE> = B<-fpie>
B<-fPIC/-fpic> + B<-fpie> = B<-fpie>

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, like -ffp-contract, -fno-strict-overflow, -fwrapv, -fno-trapv or -fno-strict-aliasing, get 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 ๐Ÿ’–

Okay so the diagnostic flags like -Wstringop-overflow get passed through to the link stage ๐Ÿ”—, and their setting matches the compile step at function granularity โœจ. This only really matters for diagnostics emitted during optimization, ngl. Bestie, watch out: code transforms like inlining can cause warnings to get enabled or disabled for regions of code that aren't consistent with the setting at compile time ๐Ÿ’€.

If you need to pass options to the assembler with -Wa or -Xassembler ๐Ÿง, you either compile those translation units with -fno-lto, or you consistently use the same assembler options on every translation unit ๐Ÿซถ. You can also specify assembler options at LTO link time instead, periodt.

To turn on debug info generation you need to supply -g at compile time ๐Ÿ›. If any input files at link time were built with debug info generation enabled, the link turns debug info generation on too ๐Ÿ’–. Fancy debug 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, not gonna lie ๐Ÿ™ˆ.

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

Another LTO flex 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 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, use the same link command options you'd use when mixing languages in a regular (non-LTO) compilation ๐ŸŽ€.

If object files containing GIMPLE bytecode are stored in a library archive, say libfoo.a, you can extract and use them in an LTO link as long as you're using a linker with plugin support ๐Ÿฆ‹. To make static libraries that are LTO-ready, use gcc-ar and gcc-ranlib instead of ar and ranlib, and use gcc-nm to show the symbols of object files with GIMPLE bytecode ๐Ÿงš. Those commands require that ar, ranlib and nm have been compiled with plugin support, so double-check that first ๐Ÿ”. At link time, use -fuse-linker-plugin so the library joins the LTO optimization party:

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

With the linker plugin enabled, the linker extracts the needed GIMPLE files from libfoo.a and passes them on to the running GCC, where they become part of the aggregated GIMPLE image to be optimized โœจ.

If you're not using a linker with plugin support and/or you don't enable the linker plugin, the objects inside libfoo.a still get extracted and linked as usual, but they just don't participate in the LTO optimization process ๐Ÿ˜”. To make a static library suitable for both LTO optimization and usual linkage, compile its object files with -flto -ffat-lto-objects ๐Ÿซถ.

Link-time optimizations don't need the whole program present to operate ๐ŸŒธ. If the program doesn't require any symbols to be exported, you can combine -flto and -fwhole-program so the interprocedural optimizers can use more aggressive assumptions, which may lead to improved optimization opportunities ๐Ÿ”ฅ. Use of -fwhole-program isn't needed when the linker plugin is active (see -fuse-linker-plugin).

The current LTO implementation makes no attempt to generate bytecode that's portable between different types of hosts ๐Ÿšซ. The bytecode files are versioned with a strict version check, so bytecode generated in one version of GCC won't work with an older or newer version of GCC ๐Ÿ’….

Link-time optimization doesn't work well with debugging information generation 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 may be used to override the program 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 executing 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. Even without the option value, GCC tries to automatically detect a running GNU make job server ๐Ÿ•ต๏ธโ€โ™€๏ธ.

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 in your system โšก.

  • -flto-partition=alg โ€” picks the partitioning algorithm the link-time optimizer uses ๐Ÿงฉ. Your options are 1to1 (mirrors the original source files), balanced (equally sized chunks whenever possible), or max (a brand new partition for every symbol where possible). Specifying none turns partitioning and streaming off completely ๐Ÿšซ. The default is balanced. 1to1 can be used as a workaround for various code ordering issues, but max partitioning is intended for internal testing only ๐Ÿงช. The value one specifies that exactly one partition should be used, while none bypasses partitioning and runs the link-time optimization step directly from the WPA phase ๐ŸŽฌ.
  • -flto-compression-level=n โ€” sets how squished the intermediate language gets when it's written into LTO object files ๐Ÿ—œ๏ธ. It's only meaningful with LTO mode (-flto). GCC supports two LTO compression algorithms: for zstd, valid values run from 0 (no compression) to 19 (maximum compression), while zlib supports values from 0 to 9 ๐Ÿ“. Values outside this range get clamped to either the minimum or maximum of the supported values. If the option isn't given, a default balanced compression setting is used ๐ŸŒˆ.
  • -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. It enables extraction of object files with GIMPLE bytecode out of library archives, which improves optimization quality by exposing more code to the link-time optimizer ๐Ÿ’–. That information specifies which symbols can be accessed externally (by non-LTO objects or during dynamic linking) ๐Ÿ‘€. Code quality improvements on binaries (and shared libraries that use hidden visibility) are similar to -fwhole-program. See -flto for a description of this flag's effect 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 ๐Ÿฑ, which 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 improves compilation time over plain LTO, but requires the complete toolchain to be aware of LTO ๐Ÿ› ๏ธ. It requires a linker with plugin support for basic functionality. Additionally, nm, ar and ranlib need to support linker plugins to allow a full-featured build environment (one capable of building static libraries and so on). GCC provides the gcc-ar, gcc-nm and gcc-ranlib wrappers to pass the right options to these tools, and with non-fat LTO, makefiles need to be modified to use them ๐Ÿง. Modern binutils provide a plugin auto-load mechanism, and 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, GCC hunts down arithmetic instructions that compute processor flags similar to a comparison based on that arithmetic ๐Ÿ”. If possible, it wipes out 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, 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 this option is specified, 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-partial-training โ€” with "-fprofile-use", all portions of programs not executed during the train run are optimized aggressively for size rather than speed ๐Ÿ“ฆ. Sometimes it's not practical to train all possible hot paths in the program (for example, a program may contain functions specific to a given hardware, and training may not cover every hardware configuration the program runs on ๐Ÿ–ฅ๏ธ). With "-fprofile-partial-training", profile feedback is ignored for all functions not executed during the train run, so they're optimized as if they were compiled without profile feedback ๐Ÿงธ. This leads to better performance when the train run isn't representative, but it also leads to significantly bigger code ๐Ÿ˜.
  • -fprofile-use, -fprofile-use=path โ€” enables profile feedback-directed optimizations, and 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

Okay so that's the rest of the crew that rides along with -fprofile-use ๐Ÿ’…โœจ

Before you can use this option, you must first generate profiling information. No skipping this step, bestie ๐Ÿฅบ

By default, GCC emits an error message if the feedback profiles don't match the source code ๐Ÿšจ You can downgrade that error into a warning with -Wno-error=coverage-mismatch. Lowkey, though, this might leave you with poorly optimized code, so be careful ๐Ÿ™ˆ Also by default, GCC throws a warning if the feedback profiles don't exist at all (see -Wmissing-profile) ๐Ÿ’€

If you give it a path, GCC goes looking in that path for the profile feedback data files. See -fprofile-dir ๐Ÿ—‚๏ธ


  • -fauto-profile, -fauto-profile=path โ€” Turns on sampling-based feedback-directed optimizations, plus a whole squad of optimizations that are mostly worth it when profile feedback is available ๐Ÿฆ‹ Here's the lineup:
-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 holding AutoFDO profile info. If you leave it off, it defaults to fbdata.afdo in the current directory ๐ŸŒธ

Making an AutoFDO profile data file means running your program with the perf utility on a supported GNU/Linux target system ๐Ÿง For more info, check out https://perf.wiki.kernel.org/ โœจ

Here's the vibe:

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

Next up, use the create_gcov tool to turn that raw profile data into something GCC can actually read ๐Ÿ”ฅ You also have to hand this tool the unstripped binary for your program, so don't strip it yet, bestie. See https://github.com/google/autofdo ๐Ÿงš

Here's how that looks:

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

The following options control compiler behavior regarding floating-point arithmetic. These options are a total trade-off between speed and correctness ๐ŸŽ€ All of them must be specifically enabled. Nothing sneaks on without you asking, periodt ๐Ÿ’œ

  • -ffloat-store โ€” Don't keep floating-point variables in registers, and block any other options that might change whether a floating-point value is pulled from a register or from memory ๐ŸŒˆ This stops the undesirable excess precision you get on machines like the 68000, where the floating registers (of the 68881) keep more precision than a "double" is supposed to have. Similarly for the x86 architecture ๐Ÿซถ For most programs that extra precision is all upside, but a few programs depend on the exact definition of IEEE floating point. For those, use -ffloat-store after modifying them to store all the pertinent intermediate computations into variables.
  • -fexcess-precision=style โ€” This gives you more control over excess precision on machines where floating-point ops happen in a format with more precision or range than the IEEE standard and interchange floating-point types ๐Ÿ‘‘
    • By default, -fexcess-precision=fast is in effect. That means ops might run at a wider precision than the types in your source if it makes the code faster, and it's unpredictable when rounding to your source types actually happens ๐Ÿ˜ญ
    • When compiling C, if -fexcess-precision=standard is specified, excess precision follows the rules in ISO C99. Casts and assignments both cause values to be rounded to their semantic types (whereas -ffloat-store only affects assignments) ๐Ÿ“
    • This option is enabled by default for C if a strict conformance option like -std=c99 is used.
    • -ffast-math enables -fexcess-precision=fast by default, regardless of whether a strict conformance option is used.
    • -fexcess-precision=standard is not implemented for languages other than C.
    • On the x86, it has no effect if -mfpmath=sse or -mfpmath=sse+387 is specified. In the former case, IEEE semantics apply without excess precision. In the latter, rounding is unpredictable ๐Ÿ™ˆ
  • -ffast-math โ€” 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 causes the preprocessor macro __FAST_MATH__ to be defined โœจ
This option is not turned on by any -O option besides -Ofast, since it can result in incorrect output for programs that depend on an exact implementation of IEEE or ISO rules/specifications for math functions. It may, however, yield faster code for programs that don't need the guarantees of these specifications ๐Ÿ’€
  • -fno-math-errno โ€” Don't set errno after calling math functions that are executed with a single instruction, e.g., sqrt ๐Ÿง  A program that relies on IEEE exceptions for math error handling might want this for speed while keeping IEEE arithmetic compatibility.
This option is not turned on by any -O option, since it can result in incorrect output for programs that depend on an exact implementation of IEEE or ISO rules/specifications for math functions. It may, however, yield faster code for programs that don't need the guarantees of these specifications.
  • 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 โ€” Allows optimizations for floating-point arithmetic that (a) assume that arguments and results are valid and (b) may violate IEEE or ANSI standards ๐Ÿ˜ฌ When used at link time, it may include libraries or startup files that change the default FPU control word or other similar optimizations.
This option is not turned on by any -O option, since it can result in incorrect output for programs that depend on an exact implementation of IEEE or ISO rules/specifications for math functions. It may, however, yield faster code for programs that don't need the guarantees of these specifications.
  • It enables -fno-signed-zeros, -fno-trapping-math, -fassociative-math and -freciprocal-math.
  • The default is -fno-unsafe-math-optimizations.
  • -fassociative-math โ€” Allows re-association of operands in series of floating-point operations ๐ŸŒ€ This violates the ISO C and C++ language standard by possibly changing the computation result. NOTE: re-ordering may change the sign of zero, ignore NaNs, and inhibit or create underflow or overflow. That means it can't be used on code that relies on rounding behavior like "(x + 2**52) - 2**52". It may also reorder floating-point comparisons, so it may not be used when ordered comparisons are required.
    • This option requires that both -fno-signed-zeros and -fno-trapping-math be in effect.
    • It doesn't make much sense with -frounding-math.
    • For Fortran, the option is automatically enabled when both -fno-signed-zeros and -fno-trapping-math are in effect.
    • The default is -fno-associative-math.
  • -freciprocal-math โ€” Lets the reciprocal of a value be used instead of dividing by the value, if that enables optimizations โž— For example, x / y can be replaced with x * (1/y), which is handy if (1/y) is subject to common subexpression elimination. Heads up: this loses precision and increases the number of flops operating on the value.
    • The default is -fno-reciprocal-math.
  • -ffinite-math-only โ€” Allows optimizations for floating-point arithmetic that assume arguments and results are not NaNs or +-Infs ๐Ÿ”ข
This option is not turned on by any -O option, since it can result in incorrect output for programs that depend on an exact implementation of IEEE or ISO rules/specifications for math functions. It may, however, yield faster code for programs that don't need the guarantees of these specifications.
  • The default is -fno-finite-math-only.
  • -fno-signed-zeros โ€” Allows optimizations for floating-point arithmetic that ignore the signedness of zero 0๏ธโƒฃ IEEE arithmetic specifies the behavior of distinct +0.0 and -0.0 values, which then prohibits simplifying expressions like x+0.0 or 0.0*x (even with -ffinite-math-only). This option implies that the sign of a zero result isn't significant.
    • The default is -fsigned-zeros.
  • -fno-trapping-math โ€” Compiles code assuming floating-point operations cannot generate user-visible traps ๐Ÿชค These traps include division by zero, overflow, underflow, inexact result and invalid operation. This option requires that -fno-signaling-nans be in effect. Setting it may allow 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 result in incorrect output for programs that depend on an exact implementation of IEEE or ISO rules/specifications for math functions.
  • The default is -ftrapping-math.
  • -frounding-math โ€” Disables transformations and optimizations that assume the default floating-point rounding behavior ๐ŸŽฒ That default is round-to-zero for all floating-point to integer conversions, and round-to-nearest for all other arithmetic truncations. Specify this for programs that change the FP rounding mode dynamically, or that may be executed with a non-default rounding mode. It also disables constant folding of floating-point expressions at compile time (which may be affected by rounding mode) and arithmetic transformations that are unsafe in the presence of sign-dependent rounding modes.
    • 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 โ€” okay so this one is for code that assumes IEEE signaling NaNs can cause user-visible traps during floating-point operations ๐Ÿ”ฅ. Turning it on tells GCC to skip optimizations that might change how many exceptions show up with signaling NaNs ๐Ÿ’€. It also implies -ftrapping-math โœจ.
    • This option defines the preprocessor macro __SUPPORT_SNAN__ ๐ŸŽ€.
    • The default is -fno-signaling-nans ๐Ÿซถ.
    • ngl, this one is still experimental, and it does NOT currently guarantee that every GCC optimization affecting signaling NaN behavior gets switched off ๐Ÿ˜ญ.
  • -fno-fp-int-builtin-inexact โ€” bestie, this stops the built-in functions ceil, floor, round and trunc (plus their float and long double versions) from generating code that raises the inexact floating-point exception for noninteger arguments ๐Ÿฆ‹. ISO C99 and C11 let these functions raise inexact, but ISO/IEC TS 18661-1:2014, the C bindings to IEEE 754-2008 as integrated into ISO C2X, does not ๐Ÿ™ˆ.
    • The default is -ffp-int-builtin-inexact, which allows the exception to be raised, unless C2X or a later C standard is selected ๐ŸŒธ.
    • This option does nothing unless -ftrapping-math is in effect ๐Ÿ’….
    • Even with -fno-fp-int-builtin-inexact, if the functions end up calling a library function, the inexact exception may still be raised if that library doesn't follow TS 18661 ๐Ÿ˜ค.
  • -fsingle-precision-constant โ€” main character move: floating-point constants get treated as single precision instead of being quietly converted to double-precision constants ๐Ÿ‘‘.
  • -fcx-limited-range โ€” when this is on, it's basically saying a range reduction step isn't needed for complex division ๐ŸŒˆ. There's also no checking for whether a complex multiplication or division comes out as NaN + I*NaN, so no rescue attempt in that case ๐Ÿ’€.
    • The default is -fno-cx-limited-range, but -ffast-math turns it on โœจ.
    • This option controls the default setting of the ISO C99 CX_LIMITED_RANGE pragma ๐Ÿงš. Lowkey the wildest part: it applies to all languages ๐Ÿ’œ.
  • -fcx-fortran-rules โ€” complex multiplication and division follow Fortran rules ๐Ÿ“. Range reduction happens as part of complex division, but again there's no checking for a NaN + I*NaN result and no rescue attempt ๐Ÿ™ˆ.
    • The default is -fno-cx-fortran-rules ๐Ÿซถ.

The following options control optimizations that may improve performance, but are not enabled by any -O options. This section includes experimental options that may produce broken code ๐Ÿงชโš ๏ธ. Use these with caution, bestie ๐Ÿซถ.

  • -fbranch-probabilities โ€” okay this one is so clever ๐Ÿง . After running a program compiled with -fprofile-arcs, you can compile it a second time with -fbranch-probabilities to improve optimizations based on how many times each branch was taken ๐Ÿ“Š.
    • When a program compiled with -fprofile-arcs exits, it saves arc execution counts to a file called sourcename.gcda for each source file ๐Ÿ“.
    • That data is super dependent on the 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 puts a REG_BR_PROB note on each JUMP_INSN and CALL_INSN ๐Ÿ’–. These can be used to improve 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 determine which path is 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 values of expressions in the program ๐Ÿฆ‹.
    • With -fbranch-probabilities, it reads back that data and uses it for 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 executes, then puts those functions in ascending order ๐Ÿช„.
    • Enabled with -fprofile-use ๐Ÿ’œ.
  • -fvpt โ€” with -fprofile-arcs, this tells the compiler to add code that gathers information about values of expressions ๐Ÿ‘€.
    • With -fbranch-probabilities, it reads that data back and actually performs optimizations based on it ๐Ÿ”ฅ. Right now those optimizations include specializing 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 using registers left over after register allocation ๐ŸŒˆ. This benefits processors with lots of registers the most ๐Ÿ’ช.
    • Heads up: depending on the debug information format the target uses, this can make debugging impossible, since variables no longer stay in a "home register" ๐Ÿ˜ญ.
    • Enabled by default with -funroll-loops ๐ŸŽ€.
  • -fschedule-fusion โ€” a target-dependent pass over the instruction stream that groups instructions of the same type together ๐Ÿงฉ. The target machine can run them more efficiently when they sit next to each other in the instruction flow โšก.
    • Enabled at levels -O2, -O3, -Os ๐Ÿซถ.
  • -ftracer โ€” performs tail duplication to enlarge superblock size ๐Ÿฆ‹. This simplifies the control flow of the function 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 figured out at compile time or when the loop is entered ๐Ÿ”. It implies -frerun-cse-after-loop, -fweb and -frename-registers ๐Ÿงš. It also turns on complete loop peeling, meaning loops with a small constant number of iterations get completely removed ๐ŸŒŸ.
    • This option 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 loops, even if their number of iterations is uncertain when the loop is entered ๐Ÿ˜ญ. This usually makes programs run more slowly ๐Ÿข. It implies the same options as -funroll-loops ๐Ÿ’œ.
  • -fpeel-loops โ€” peels loops that have enough information to show they don't roll much, based on profile feedback or static analysis ๐Ÿ‘. It also turns on complete loop peeling, meaning loops with a small constant number of iterations get completely removed ๐Ÿง.
    • Enabled by -O3, -fprofile-use, and -fauto-profile ๐Ÿ”ฅ.
  • -fmove-loop-invariants โ€” enables 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 always false for the other โœ‚๏ธ.
    • Enabled by -fprofile-use and -fauto-profile ๐ŸŒธ.
  • -funswitch-loops โ€” moves branches with loop invariant conditions out of the loop ๐Ÿšช. Duplicates of the loop end up 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 ๐Ÿชก. Here's how it looks, bestie:
        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 especially useful for assumed-shape arrays in Fortran, where (for example) it allows better vectorization by assuming contiguous accesses ๐Ÿ’–. This flag is enabled by default at -O3 ๐Ÿ”ฅ. It's 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, as long as the target supports arbitrary sections ๐Ÿ“ฆ. The function's name or the data item's name determines the section's name in the output file ๐Ÿท๏ธ.
    • Use these on systems where the linker can optimize to improve locality of reference in the instruction space. Most systems using the ELF object format have linkers with those optimizations ๐Ÿง . On AIX, the linker rearranges sections (CSECTs) based on the call graph, and 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 degrade the quality of the debug information ๐ŸŽ€. There could be issues with other object file or debug info formats ๐Ÿค”.
    • Only use these when there are significant benefits ๐Ÿšจ. They make the assembler and linker create larger object and executable files, and they're slower too ๐ŸŒ. These options also affect code generation: they prevent the compiler and assembler from using relative locations inside a translation unit, since those locations aren't known until link time ๐Ÿงฑ. An example of an optimization this blocks is relaxing calls to short call instructions ๐Ÿ“ž.
  • -fstdarg-opt โ€” optimizes the prologue of variadic argument functions based on how those arguments are used ๐Ÿช„.
    • NOTE, bestie: In Ubuntu 14.10 and later versions, -fstack-protector-strong is enabled by default for C, C++, ObjC, and ObjC++, if none of -fno-stack-protector, -nostdlib, or -ffreestanding are found ๐Ÿ›ก๏ธ๐Ÿ’….
  • -fsection-anchors โ€” tries to cut down on symbolic address calculations by using shared "anchor" symbols to address nearby objects ๐Ÿฆ‹. This can help reduce the number of GOT entries and GOT accesses on some targets ๐ŸŒธ.
    • Say you have the following function foo:
        static int a, b, c;
        int foo (void) { return a + b + c; }

It usually 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 this pseudocode (which isn't valid C, so don't copy-paste it ๐Ÿ™ˆ):

        int foo (void)
        {
          register int *xr = &x;
          return xr[&a - &x] + xr[&b - &x] + xr[&c - &x];
        }

Heads up, bestie: not every target supports this one ๐Ÿ˜ญ๐Ÿ’…

  • -fzero-call-used-regs=choice โ€” okay, this one is a whole security moment ๐Ÿ”โœจ It zeroes the call-used registers when a function returns, which can help mitigate Return-Oriented Programming (ROP) attacks or stop information from leaking out through registers ๐Ÿฆ‹ The possible values of choice are the same as the ones for the zero_call_used_regs attribute, and the default is skip ๐Ÿ’– You can also control this for one specific function with the function attribute zero_call_used_regs ๐ŸŽ€
  • --param name=value โ€” okay so GCC uses little constants behind the scenes to decide how much optimizing to do ๐Ÿงš For example, it won't inline a function that has more than a certain number of instructions. You can tweak some of these on the command line with --param ๐ŸŒธ Heads up though: the names and what the values mean are tied to the compiler's internals and can change without notice in future releases โš ๏ธ To see the minimal, maximal, and default value of a parameter, use --help=param -Q ๐Ÿ‘‘ The value is always an integer, and these names are recognized for all targets:
    • predictable-branch-outcome โ€” if a branch is predicted to be taken with a probability lower than this threshold (in percent), it counts as well predictable ๐Ÿ”ฎ
    • max-rtl-if-conversion-insns โ€” RTL if-conversion tries to remove conditional branches around a block and swap them for conditionally executed instructions. This sets the max number of instructions in a block that get considered for that. GCC also uses other heuristics to decide whether it's actually worth it ๐Ÿค”
    • max-rtl-if-conversion-predictable-cost โ€” the max permissible cost for the sequence if-conversion would generate. It depends on whether the branch is statically determined to be predictable or not. The units match GCC's internal seq_cost metric, and GCC tries to pick a reasonable default using the BRANCH_COST target macro ๐Ÿ’…
    • max-crossjump-edges โ€” the max number of incoming edges to consider for cross-jumping. -fcrossjumping runs in O(N^2) in the number of incoming edges to each block, so bigger values mean more aggressive optimization, longer compile times, and probably a small improvement in executable size ๐Ÿข
    • min-crossjump-insns โ€” the min number of instructions that must match at the end of two blocks before cross-jumping happens. This gets ignored when every instruction in the block being cross-jumped from is matched ๐ŸŒˆ
    • max-grow-copy-bb-insns โ€” the max code size expansion factor when copying basic blocks instead of jumping. The expansion is relative to a jump instruction ๐Ÿ“
    • max-goto-duplication-insns โ€” the max number of instructions to duplicate into a block that jumps to a computed goto. To avoid O(N^2) behavior in a bunch of passes, GCC factors computed gotos early and unfactors them as late as possible. Only computed jumps at the end of a basic block with no more than max-goto-duplication-insns get unfactored ๐Ÿง 
    • max-delay-slot-insn-search โ€” the max number of instructions to check when hunting for something to fill a delay slot. Past this arbitrary number the time savings are minimal, so GCC stops searching. Bigger values mean more aggressive optimization and longer compile times, with probably a small win 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. Raising this arbitrary number means more aggressive optimization and longer compile times. This parameter should get removed once the delay slot code is rewritten to maintain the control-flow graph ๐Ÿ› ๏ธ
    • max-gcse-memory โ€” the approximate max amount of memory in kB that can be allocated for global common subexpression elimination. If more memory than that is needed, the optimization just doesn't happen ๐Ÿงบ
    • max-gcse-insertion-ratio โ€” if the ratio of expression insertions to deletions is bigger than this for any expression, RTL PRE inserts or removes the expression and leaves partially redundant computations in the instruction stream ๐Ÿซ 
    • max-pending-list-length โ€” the max number of pending dependencies the scheduler allows before it flushes its current state and starts over. Big functions with few branches or calls can make these lists huge, which wastes memory and resources ๐Ÿ“œ
    • max-modulo-backtrack-attempts โ€” the max number of backtrack attempts the scheduler makes when modulo scheduling a loop. Larger values can make compile time blow up exponentially ๐Ÿ’€
    • max-inline-insns-single โ€” several parameters control the tree inliner, and this one sets the max number of instructions (counted in GCC's internal representation) in a single function that the tree inliner will consider for inlining. It only affects functions declared inline and methods implemented in a class declaration (C++) ๐Ÿ’œ
    • max-inline-insns-auto โ€” when you use -finline-functions (which is included in -O3), tons of functions that would normally not be considered for inlining get checked. For those, a different and more restrictive limit applies than for functions declared inline, and that limit is set with --param max-inline-insns-auto โœจ
    • max-inline-insns-small โ€” the bound applied to calls considered relevant under -finline-small-functions ๐ŸŒท
    • max-inline-insns-size โ€” the bound applied to calls that are optimized for size. A small growth might be desirable to set up optimization opportunities that inlining exposes ๐ŸŽฏ
    • 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 needed to run the function prologue and epilogue โฑ๏ธ
    • inline-heuristics-hint-percent โ€” the scale (in percent) applied to inline-insns-single, inline-insns-single-O2, and inline-insns-auto when the inline heuristics hint that inlining is very profitable (it'll enable later optimizations) ๐Ÿ”ฅ
    • uninlined-thunk-insns and uninlined-thunk-time โ€” same as --param uninlined-function-insns and --param uninlined-function-time, but applied to function thunks ๐Ÿงต
    • inline-min-speedup โ€” when the estimated performance improvement of caller plus callee runtime goes over this threshold (in percent), the function can be inlined no matter the limits set by --param max-inline-insns-single and --param max-inline-insns-auto ๐Ÿš€
    • large-function-insns โ€” the limit that defines really large functions. For functions bigger than this after inlining, inlining is constrained by --param large-function-growth. This one mainly exists to avoid extreme compile times caused by the non-linear algorithms the back end uses ๐Ÿ˜
    • 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 caused by inlining into units bigger than this is limited by --param inline-unit-growth. For small units that might be too tight. Picture a unit with function A (inline) and function B that just calls A three times. If B is small compared to A, the unit growth is 300% and that inlining is still totally sane ๐Ÿฐ For really big units full of small inlinable functions, the overall unit growth limit is needed to prevent exponential code size explosion. So for smaller units, the size gets bumped up to --param large-unit-insns before --param inline-unit-growth is applied ๐Ÿซง
    • lazy-modules โ€” the max number of C++ module files that can be open at once when lazy loading ๐Ÿ“‚
    • 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 ๐Ÿฅถ
    • ipa-cp-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 ๐ŸงŠ
    • ipa-cp-large-unit-insns โ€” the size at which the IPA-CP pass considers a translation unit large ๐Ÿ‹
    • 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 and max-inline-insns-recursive-auto โ€” the max number of instructions an out-of-line copy of a self-recursive inline function can grow into by doing recursive inlining ๐ŸŒ€

Okay so the --param max-inline-insns-recursive thing applies to functions declared inline ๐Ÿ’…. For functions that aren't declared inline, recursive inlining only kicks in when -finline-functions (which is included in -O3) is enabled, and then --param max-inline-insns-recursive-auto takes over ๐Ÿฆ‹.

  • max-inline-recursive-depth, max-inline-recursive-depth-auto โ€” This sets the max recursion depth for recursive inlining ๐ŸŒธ. --param max-inline-recursive-depth is for functions declared inline, and for functions that aren't, --param max-inline-recursive-depth-auto is the one (same -finline-functions deal as above) ๐Ÿซถ.
  • min-inline-recursive-probability โ€” Recursive inlining is only worth it for functions that recurse deeply on average ๐ŸŒˆ. For functions with shallow recursion it can backfire, bloating the prologue or making the function body more complicated for the other optimizers ๐Ÿ˜ญ. When profile feedback is around (see -fprofile-generate), the compiler can guess the real recursion depth from how likely a function is to recurse through a given call expression ๐Ÿ”ฎ. This parameter only lets inlining happen for call expressions whose probability is higher than the threshold, given in percent โœจ.
  • early-inlining-insns โ€” How much growth the early inliner is allowed to make ๐ŸŒฑ. Basically it means more inlining for code that has a big abstraction penalty ๐Ÿ’œ.
  • max-early-inliner-iterations โ€” The cap on how many iterations the early inliner runs โญ. This pretty much bounds how many nested indirect calls it can resolve ๐Ÿงš. Deeper chains still get handled later, by late inlining ๐Ÿ“.
  • comdat-sharing-probability โ€” The percent chance that C++ inline functions with comdat visibility get shared across multiple compilation units ๐ŸŽ€.
  • modref-max-bases, modref-max-refs, modref-max-accesses โ€” How many base pointers, references, and accesses mod/ref analysis will store for a single function ๐Ÿ”ฅ.
  • modref-max-tests โ€” The max number of tests the alias oracle can run to tell memory locations apart using mod/ref info ๐Ÿ•ต๏ธโ€โ™€๏ธ. This should be bigger than --param modref-max-bases and --param modref-max-refs ๐Ÿ‘‘.
  • modref-max-depth โ€” The max depth of the DFS walk used by modref escape analysis ๐ŸŒŠ. Setting it to 0 turns the analysis off completely ๐Ÿ™ˆ.
  • modref-max-escape-points โ€” The max number of escape points modref tracks per SSA-name ๐Ÿ’….
  • profile-func-internal-id โ€” Controls whether the function's internal id gets used when looking things up in the profile database ๐Ÿง . If the value is 0, the compiler uses an id based on the function's assembler name and filename instead ๐Ÿซง. That makes old profile data way more forgiving of source changes, like functions getting reordered ๐Ÿฅน.
  • min-vect-loop-bound โ€” Loops with fewer iterations than this won't get vectorized when -ftree-vectorize is on ๐ŸŒท. The number of iterations after vectorization also has to be greater than this value for vectorization to happen ๐Ÿ’–.
  • gcse-cost-distance-ratio โ€” A scaling factor for figuring out how far GCSE is allowed to move an expression โœจ. It's only supported in the code hoisting pass ๐Ÿฆ„. The bigger the ratio, the more aggressively simple expressions (ones costing less than gcse-unrestricted-cost) get hoisted ๐Ÿš€. Setting it to 0 turns off hoisting of simple expressions ๐Ÿ™…โ€โ™€๏ธ.
  • gcse-unrestricted-cost โ€” The cost, roughly the cost of one typical machine instruction, at which GCSE stops limiting how far an expression can travel ๐Ÿ’ซ. This is only supported in the code hoisting pass too ๐Ÿซถ. The lower the cost, the more aggressive the hoisting gets ๐ŸŒˆ. Setting it to 0 lets every expression travel unrestricted distances ๐Ÿ”“.
  • max-hoist-depth โ€” How deep the search goes in the dominator tree looking for expressions to hoist ๐ŸŒณ. It's there to stop the hoisting algorithm from going quadratic ๐Ÿ™ƒ. A value of 0 means no limit on the search, but that can slow down compilation of huge functions ๐Ÿข.
  • max-tail-merge-comparisons โ€” The max number of similar basic blocks one block gets compared against during tree tail merging ๐Ÿ”. It exists to avoid quadratic behavior there ๐Ÿ’….
  • max-tail-merge-iterations โ€” The max number of iterations of the pass over the function ๐Ÿ”. It's a limit on compilation time in tree tail merging โฑ๏ธ.
  • store-merging-allow-unaligned โ€” Lets the store merging pass introduce unaligned stores, but only if that's legal ๐Ÿงฉ.
  • max-stores-to-merge โ€” The max number of stores the store merging pass will try to combine into wider stores ๐Ÿงƒ.
  • max-store-chains-to-track โ€” The max number of store chains tracked at once while trying to merge them into wider stores ๐Ÿชก.
  • max-stores-to-track โ€” The max number of stores tracked at once while trying to merge them into wider stores in the store merging pass ๐ŸŽฏ.
  • max-unrolled-insns โ€” The max number of instructions a loop can have and still get unrolled ๐Ÿ”. If the loop does get unrolled, this value also decides how many times the loop code is unrolled ๐ŸŒ€.
  • max-average-unrolled-insns โ€” The max number of instructions, weighted by how likely they are to run, that a loop can have and still get unrolled ๐Ÿ“Š. If it gets unrolled, this parameter also decides how many times the loop code is unrolled ๐ŸŽก.
  • max-unroll-times โ€” The max number of unrollings for a single loop ๐Ÿญ.
  • max-peeled-insns โ€” The max number of instructions a loop can have and still get peeled ๐Ÿ‘. If it gets peeled, this parameter also decides how many times the loop code is peeled ๐Ÿซ .
  • max-peel-times โ€” The max number of peelings for a single loop ๐Ÿง.
  • max-peel-branches โ€” The max number of branches on the hot path through the peeled sequence ๐ŸŒถ๏ธ.
  • max-completely-peeled-insns โ€” The max number of insns in a completely peeled loop ๐Ÿช„.
  • 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 max depth of a loop nest that's suitable for complete peeling ๐Ÿช†.
  • max-unswitch-insns โ€” The max number of insns in an unswitched loop ๐Ÿชฉ.
  • max-unswitch-level โ€” The max number of branches unswitched in a single loop ๐ŸŽข.
  • lim-expensive โ€” The minimum cost for an expression to count as expensive in loop invariant motion ๐Ÿ’ธ.
  • min-loop-cond-split-prob โ€” When FDO profile info is available, this is the minimum probability a semi-invariant condition statement needs before it triggers a loop split ๐Ÿ”€.
  • iv-consider-all-candidates-bound โ€” Below this number of induction variable candidates, every candidate gets considered for each use ๐Ÿงฎ. Above it, only the most relevant ones get considered, so the time complexity doesn't go quadratic ๐Ÿ“‰.
  • iv-max-considered-uses โ€” The induction variable optimizations 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, the compiler always tries to strip out unnecessary ivs whenever it adds a new one ๐Ÿงน.
  • avg-loop-niter โ€” The average number of iterations of a loop ๐Ÿ”„.
  • dse-max-object-size โ€” The max size, in bytes, of objects tracked bytewise by dead store elimination ๐Ÿ“ฆ. Bigger values can mean bigger compilation times โณ.
  • dse-max-alias-queries-per-store โ€” The max number of queries into the alias oracle per store ๐Ÿ”Ž. Bigger values mean bigger compilation times, but they can also remove more dead stores ๐Ÿ—‘๏ธ.
  • scev-max-expr-size โ€” The bound on how big expressions can be in the scalar evolutions analyzer ๐Ÿ“. Big expressions slow the analyzer down ๐ŸŒ.
  • scev-max-expr-complexity โ€” The bound on how complex expressions can be in the scalar evolutions analyzer ๐Ÿงถ. Complex expressions slow the analyzer down too ๐Ÿ˜ฉ.
  • max-tree-if-conversion-phi-args โ€” The max number of arguments in a PHI that tree if conversion supports, unless the loop is marked with a simd pragma ๐Ÿงฌ.
  • vect-max-version-for-alignment-checks โ€” The max number of run-time checks allowed when the vectorizer does loop versioning for alignment ๐Ÿ›ก๏ธ.
  • vect-max-version-for-alias-checks โ€” The max number of run-time checks allowed when the vectorizer does loop versioning for alias ๐Ÿชž.
  • vect-max-peeling-for-alignment โ€” The max number of loop peels the vectorizer can do to improve access alignment ๐Ÿง˜โ€โ™€๏ธ. A value of -1 means there's no limit ๐ŸŒŸ.
  • max-iterations-to-track โ€” The max number of loop iterations the brute-force algorithm will try to evaluate when it's figuring out how many iterations a loop runs ๐Ÿ•ฐ๏ธ.
  • hot-bb-count-fraction โ€” The denominator n of the fraction 1/n of the maximal execution count of a basic block in the whole program. A basic block has to hit at least that much to count as hot ๐Ÿ”ฅ. The default is 10000, which means a basic block is hot if its execution count is greater than 1/10000 of the maximal execution count ๐Ÿฅ‡. A value of 0 means a basic block is never considered hot ๐ŸงŠ. This is used in non-LTO mode ๐Ÿ’….
  • hot-bb-count-ws-permille โ€” bestie, this is the "how much of the action counts as popular" dial ๐Ÿ’… It's a number from 0 to 1000 (permilles!) for the most-executed slice of the whole profiled program. A basic block only counts as hot if its execution count lands in that slice. The default is 990, so a block is hot if it contributes to the upper 990 permilles, or 99.0%, of the profiled execution of the entire program. Setting it to 0 means nothing is ever hot ๐Ÿฅ€ Only used in LTO mode.
  • hot-bb-frequency-fraction โ€” this one is a fraction, 1/n, of the entry block's execution frequency for a function. A basic block in that function has to hit at least that much to be considered hot โœจ The default is 1000, so a block is hot in a function if it runs more often than 1/1000 of the entry block's frequency. 0 means it's never hot, no exceptions ๐Ÿ™ˆ
  • unlikely-bb-count-fraction โ€” the "sus, barely showing up" threshold ๐Ÿซ  It's a fraction 1/n of the number of profiled runs of the whole program. If a basic block's execution count is below that, it's considered unlikely to run. The default is 20, so a block counts as unlikely if it runs in fewer than 1/20, or 5%, of the program's runs. 0 means it's always considered unlikely executed ๐Ÿ’€
  • max-predicted-iterations โ€” the cap on how many loop iterations GCC will guess statically ๐Ÿ”ฎ This matters when one function has a loop with a known bound and another loop with an unknown bound. The known count gets predicted correctly, but the unknown ones average out to roughly 10. So the unbounded loop looks artificially cold next to the other one, which is kinda unfair ngl ๐Ÿ˜ญ
  • builtin-expect-probability โ€” controls how likely it is that an expression has the specified value ๐ŸŽฏ It takes a percentage, meaning 0 ... 100, as input.
  • builtin-string-cmp-inline-length โ€” the max length of a constant string for a builtin string compare call that's allowed to get inlined ๐Ÿงš Anything longer stays as a regular call.
  • align-threshold โ€” pick a fraction of the maximal execution frequency of a basic block in a function to decide whether that block gets aligned ๐ŸŒธ
  • align-loop-iterations โ€” a loop that's expected to iterate at least this many times gets aligned ๐Ÿฆ‹
  • tracer-dynamic-coverage, tracer-dynamic-coverage-feedback โ€” these two are the bouncers for superblock formation ๐Ÿšช Once the given percentage of executed instructions is covered, the tracer stops forming superblocks. This keeps code size from getting totally out of hand ๐Ÿ“

The tracer-dynamic-coverage-feedback parameter only gets used when profile feedback is available. Real profiles are way less balanced than the statically estimated ones, so the threshold can be set to a bigger value ๐Ÿ‘‘

  • tracer-max-code-growth โ€” tail duplication stops once code growth hits this percentage ๐ŸŒˆ It's kind of an artificial limit, since most of the duplicates get cleaned up later during cross jumping. So you can set it way higher than the code growth you actually want ๐Ÿ’–
  • tracer-min-branch-ratio โ€” reverse growth stops when the reverse probability of the best edge drops below this threshold, given in percent ๐Ÿชž
  • tracer-min-branch-probability, tracer-min-branch-probability-feedback โ€” forward growth stops if the best edge's probability is lower than this threshold โžก๏ธ

Same energy as tracer-dynamic-coverage, there are two versions of this one too. 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, which means a higher value, so the tracer actually works โญ

  • stack-clash-protection-guard-size โ€” sets the size of the operating system's stack guard as 2 raised to num bytes ๐Ÿ›ก๏ธ Higher values can cut down on the number of explicit probes. But if the value is larger than the OS guard, your code is left vulnerable to stack clash style attacks, and that's a big nope ๐Ÿšจ
  • stack-clash-protection-probe-interval โ€” stack clash protection probes the stack space as it gets allocated ๐Ÿ” This param sets the max distance between those probes as 2 raised to num bytes. Higher values might mean fewer explicit probes, but if the value is bigger than the OS guard, your code becomes vulnerable to stack clash style attacks again ๐Ÿ˜ฌ
  • max-cse-path-length โ€” the max number of basic blocks on a path that CSE (common subexpression elimination) considers ๐Ÿงญ
  • max-cse-insns โ€” the max number of instructions CSE processes before it flushes ๐Ÿšฟ
  • ggc-min-expand โ€” okay, so GCC has its own garbage collector to manage its memory ๐Ÿ—‘๏ธโœจ This sets the minimum percentage the GC's heap is allowed to grow between collections. Tuning it might speed up compilation, but it has zero effect on code generation, so don't stress ๐Ÿซถ

The default is 30% + 70% * (RAM/1GB), capped at a 100% upper bound when RAM >= 1GB. If getrlimit is available, "RAM" means the smallest of actual RAM and RLIMIT_DATA or RLIMIT_AS. If GCC can't calculate RAM on a platform, it falls back to the 30% lower bound. Setting this and ggc-min-heapsize to zero forces a full collection at every opportunity. That's extremely slow, but it can be useful for debugging ๐Ÿข

  • ggc-min-heapsize โ€” the minimum size the garbage collector's heap has to hit before it even starts bothering to collect garbage ๐Ÿงน The first collection happens after the heap grows by ggc-min-expand% beyond ggc-min-heapsize. Again, tuning this might help compile speed, with no 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. It has a lower bound of 4096 (four megabytes) and an upper bound of 131072 (128 megabytes). If GCC can't calculate RAM on a platform, the lower bound gets used. Setting this parameter very large effectively disables garbage collection, and setting this and ggc-min-expand to zero causes a full collection at every opportunity ๐Ÿ’œ

  • max-reload-search-insns โ€” the max number of instructions reload looks backward through for an equivalent register ๐Ÿ” Higher values mean more aggressive optimization, with compile time going up and probably slightly better performance ๐Ÿƒโ€โ™€๏ธ
  • max-cselib-memory-locations โ€” the max number of memory locations cselib should take into account ๐Ÿง  Higher values mean more aggressive optimization, with compile time going up and probably slightly better performance.
  • max-sched-ready-insns โ€” the max number of ready-to-issue instructions the scheduler considers at any given time during the first scheduling pass ๐Ÿ“‹ Higher values mean more thorough searches, which makes compile time go up with probably little benefit ๐Ÿฅฑ
  • max-sched-region-blocks โ€” the max number of blocks in a region considered for interblock scheduling ๐Ÿงฉ
  • max-pipeline-region-blocks โ€” the max number of blocks in a region considered for pipelining in the selective scheduler ๐Ÿช„
  • max-sched-region-insns โ€” the max number of insns in a region considered for interblock scheduling ๐ŸŽ€
  • max-pipeline-region-insns โ€” the max number of insns in a region 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 iterations through the CFG to extend regions ๐Ÿ—บ๏ธ A value of 0 disables region extensions, so that's the off switch ๐Ÿ”Œ
  • 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, that has to be hit before speculative insns get scheduled โœ…
  • sched-state-edge-prob-cutoff โ€” the minimum probability an edge needs before the scheduler saves its state across it ๐Ÿ’พ
  • sched-mem-true-dep-cost โ€” the minimal distance, in CPU cycles, between a store and a load that target the same memory locations โฑ๏ธ
  • selsched-max-lookahead โ€” the max size of the lookahead window for selective scheduling ๐Ÿ‘€ It's basically the depth of search for available instructions ๐Ÿ”Ž
  • selsched-max-sched-times โ€” the max number of times an instruction gets scheduled during selective scheduling ๐Ÿ”„ This is the limit on how many iterations the instruction can get pipelined through ๐Ÿซ 
  • selsched-insns-to-rename โ€” the max number of best instructions in the ready list that the selective scheduler considers for renaming ๐Ÿท๏ธ
  • sms-min-sc โ€” the minimum stage count value that the swing modulo scheduler generates ๐ŸŽข
  • max-last-value-rtl โ€” the max size, measured as the number of RTLs, that the combiner can record in an expression as the last known value of a pseudo register ๐Ÿ“
  • max-combine-insns โ€” the max number of instructions the RTL combiner tries to combine at once ๐Ÿงƒ
  • integer-share-limit โ€” small integer constants can use a shared data structure, which saves the compiler memory and makes it faster ๐Ÿš€ This sets the max value of a shared integer constant ๐Ÿ”ข
  • ssp-buffer-size โ€” the minimum size of buffers (aka arrays) that get stack smashing protection when -fstack-protection is used ๐Ÿ›ก๏ธ๐Ÿ’…

This default before Ubuntu 10.10 was "8" ๐Ÿ’… Right now it's "4", so the stack protector covers way more functions ๐Ÿ›ก๏ธ

  • min-size-for-stack-sharing โ€” the smallest a variable can be to join stack slot sharing when you're not optimizing ๐Ÿงš
  • max-jump-thread-duplication-stmts โ€” the max number of statements a block can have before it has to be duplicated while threading jumps ๐Ÿ”€
  • max-fields-for-field-sensitive โ€” the max number of fields in a structure that get the field-sensitive treatment during pointer analysis ๐Ÿฆ‹
  • prefetch-latency โ€” an estimate of how many instructions run on average before a prefetch finishes โฑ๏ธ The prefetch distance scales with this number, and bumping it up may 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 non-constant strides ๐Ÿค” This can be super helpful sometimes, but a non-constant stride makes it hard to predict when the hints are actually worth it.
    • 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 kick in ๐Ÿšฆ If the stride is under this threshold, no prefetch hints get issued.
    • This one is giving hardware realness ๐Ÿ–ฅ๏ธ Processors with hardware prefetchers can clash with software prefetchers. If the hardware prefetchers have a max stride they can handle, put that number here so the software prefetchers play nice.
    • 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 statements in a loop that can be interchanged ๐Ÿ”
  • loop-interchange-stride-ratio โ€” the min ratio between the strides of two loops for an interchange to actually be profitable ๐Ÿ’ธ
  • min-insn-to-prefetch-ratio โ€” the min ratio of instructions to prefetches needed before prefetching gets enabled in a loop ๐Ÿงฎ
  • prefetch-min-insn-to-mem-ratio โ€” the min ratio of instructions to memory references needed before prefetching gets enabled in a loop ๐Ÿง 
  • use-canonical-types โ€” whether the compiler uses the "canonical" type system ๐Ÿ‘‘ This should always be 1, since it's a more efficient internal way of comparing types in C++ and Objective-C++. But if bugs in the canonical type system are causing compile failures, set it to 0 to turn canonical types off ๐Ÿšซ
  • switch-conversion-max-branch-ratio โ€” switch initialization conversion won't create arrays 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 you're 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 caps the length of those sets so that doesn't happen. Setting it to 0 allows an unlimited set length.
  • rpo-vn-max-loop-depth โ€” the max loop depth that gets value-numbered optimistically ๐ŸŒ€ When the limit hits, the innermost rpo-vn-max-loop-depth loops and the outermost loop in the loop nest are value-numbered optimistically, and the remaining ones are not.
  • sccvn-max-alias-queries-per-access โ€” the max number of alias-oracle queries we run while hunting for redundancies in loads and stores ๐Ÿ” If this limit gets 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 the given number of the most frequently-executed loops form regions for regional register allocation.
  • ira-max-conflict-table-size โ€” IRA has a sophisticated way of compressing the conflict table, but huge functions can still need excessive memory ๐Ÿ˜ฉ If a function's conflict table could be bigger than the size in MB given by this parameter, the register allocator switches to a faster, simpler, lower-quality algorithm that doesn't build a pseudo-register conflict table.
  • ira-loop-reserved-regs โ€” IRA can evaluate more accurate register pressure in loops for decisions about moving loop invariants (see -O3) ๐ŸŽฏ This sets how many available registers get reserved for other purposes. The default is the best value found from numerous experiments ๐Ÿงช
  • lra-inheritance-ebb-probability-cutoff โ€” LRA tries to reuse values reloaded into registers in subsequent insns, which is called inheritance ๐Ÿ” EBB is used as the region for this optimization. The parameter is a minimal fall-through edge probability, in percent, used to add a BB to the inheritance EBB in LRA. The default was chosen from numerous runs of SPEC2000 on x86-64 ๐Ÿ“Š
  • loop-invariant-max-bbs-in-loop โ€” loop invariant motion can be super expensive for very large loops, both in compilation time and in compile-time memory ๐Ÿ’ธ Loops with more basic blocks than this parameter won't get loop invariant motion performed on them.
  • loop-max-datarefs-for-datadeps โ€” building data dependencies is expensive for very large loops ๐Ÿ˜ฎโ€๐Ÿ’จ This limits the number of data references in loops considered for data dependence analysis. These large loops are no handled by the optimizations that use loop data dependencies.
  • max-vartrack-size โ€” the max number of hash table slots to use during variable tracking dataflow analysis of any function ๐Ÿงฉ If this limit is exceeded with variable tracking at assignments enabled, analysis for that function is retried without it, after removing all debug insns from the function. If the limit is still exceeded without debug insns, var tracking analysis is completely disabled for the function. Setting this to zero makes it unlimited.
  • max-vartrack-expr-depth โ€” the max number of recursion levels when mapping variable names or debug temporaries to value expressions ๐Ÿ”ฌ This trades compilation time for more complete debug information. If it's set too low, value expressions that could be represented in debug information may end up not being used. Setting it higher may let the compiler find more complex debug expressions, but compile time and memory use may grow.
  • max-debug-marker-count โ€” a threshold on the number of debug markers (like begin stmt markers) to avoid a complexity explosion at inlining or when expanding to RTL ๐Ÿšง 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 โ€” uids starting at this parameter are used for nondebug insns ๐Ÿ†” The range below it is reserved exclusively for debug insns created by -fvar-tracking-assignments, but debug insns may get (non-overlapping) uids above it if the reserved range runs out.
  • ipa-sra-ptr-growth-factor โ€” IPA-SRA only replaces a pointer to an aggregate with 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 ๐Ÿ“
  • ipa-sra-max-replacements โ€” the max number of pieces of an aggregate that IPA-SRA tracks ๐Ÿงท As a consequence, it's also the max number of replacements of a formal parameter.
  • sra-max-scalarization-size-Ospeed, sra-max-scalarization-size-Osize โ€” the two Scalar Reduction of Aggregates passes (SRA and IPA-SRA) aim to swap scalar parts of aggregates for uses of independent scalar variables ๐ŸŽ€ These parameters control the max size, in storage units, of an aggregate considered for replacement when compiling for speed (sra-max-scalarization-size-Ospeed) or for size (sra-max-scalarization-size-Osize), respectively.
  • sra-max-propagations โ€” the max number of artificial accesses that Scalar Replacement of Aggregates (SRA) will track per local variable, to help with copy propagation ๐Ÿชž
  • tm-max-aggregate-size โ€” when making copies of thread-local variables in a transaction, this sets the size in bytes after which variables get saved with the logging functions instead of save/restore code sequence pairs ๐Ÿงต This option only applies when using -fgnu-tm.
  • graphite-max-nb-scop-params โ€” ๐Ÿ’… okay so Graphite loop transforms can go fully exponential if nobody stops them, so the number of parameters in a Static Control Part (SCoP) gets capped. Set it to 0 to lift the cap. And any variable whose value isn't known at compile time and is defined outside a SCoP counts as one of its parameters. ๐Ÿงš
  • loop-block-tile-size โ€” ๐Ÿฆ‹ when loop blocking or strip mining is on (via -floop-block or -floop-strip-mine), each loop in the nest gets strip mined by a set number of iterations. Want a different strip length? This param is how you change it.
  • ipa-jump-function-lookups โ€” ๐Ÿ” how many statements get visited during jump function offset discovery.
  • ipa-cp-value-list-size โ€” ๐Ÿ’œ IPA-CP tries to track every value and type passed into a function's parameter so it can propagate them and do devirtualization. This is the max number of values and types it stores for each formal parameter. โœจ
  • ipa-cp-eval-threshold โ€” ๐Ÿ”ฅ IPA-CP scores cloning profitability on its own, and it only goes through with cloning opportunities whose scores exceed ipa-cp-eval-threshold.
  • ipa-cp-max-recursive-depth โ€” ๐ŸŒ€ how deep recursive cloning can go for a self-recursive function.
  • ipa-cp-min-recursive-probability โ€” ๐ŸŽฏ recursive cloning only happens when the probability of the call actually being executed is higher than this parameter.
  • ipa-cp-recursion-penalty โ€” ๐Ÿ“‰ the percentage penalty recursive functions take when they're evaluated for cloning.
  • ipa-cp-single-call-penalty โ€” ๐Ÿ“‰ the percentage penalty functions take when they contain a single call to another function and get evaluated for cloning.
  • ipa-max-agg-items โ€” ๐ŸŒธ IPA-CP can also propagate scalar values passed inside an aggregate. This caps how many of those values it handles per parameter.
  • ipa-cp-loop-hint-bonus โ€” ๐ŸŽ€ if IPA-CP figures out that a cloning candidate would make a loop's iteration count known, it adds a bonus of ipa-cp-loop-hint-bonus to that candidate's profitability score. Very main character.
  • ipa-max-loop-predicates โ€” ๐Ÿงฉ the max number of different predicates IPA uses to describe when loops in a function have known properties.
  • ipa-max-aa-steps โ€” ๐Ÿซถ IPA-CP uses alias analysis to track the values that function parameters point to. So it doesn't spend forever on huge functions, it gives up after examining ipa-max-aa-steps statements that modify memory and treats all memory as clobbered.
  • ipa-max-switch-predicate-bounds โ€” ๐Ÿ“ the max number of boundary endpoints of case ranges in a switch statement. Any switch over this limit won't get a cloning cost predicate for its default case. That predicate is what IPA-CP uses to estimate cloning benefit.
  • ipa-max-param-expr-ops โ€” ๐Ÿง  IPA-CP checks conditionals that reference a function parameter to estimate the benefit of cloning for a certain constant value. But if a parameter expression has more operations than ipa-max-param-expr-ops, it's treated as too complicated and IPA analysis skips it. ๐Ÿ™ˆ
  • lto-partitions โ€” ๐Ÿ‘‘ the desired number of partitions produced during WHOPR compilation. It should be more than the number of CPUs used for compilation.
  • lto-min-partition โ€” ๐ŸŒฑ the minimal partition size for WHOPR, measured in estimated instructions. This keeps tiny programs from getting chopped into way too many partitions.
  • lto-max-partition โ€” ๐Ÿฐ the max partition size for WHOPR, measured in estimated instructions. It sets an upper bound on how big any single partition can get. 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 GCC will check for suggestions when C++ name lookup fails for an identifier.
  • sink-frequency-threshold โ€” โญ the max relative execution frequency (in percent) of the target block compared to the statement's original block, which decides whether a statement can be sunk. Bigger numbers mean more aggressive sinking. Statements with memory operands get a small positive adjustment, since sinking them is even more profitable. ๐Ÿ’…
  • max-stores-to-sink โ€” ๐Ÿ›๏ธ 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. ๐Ÿ’€
  • case-values-threshold โ€” ๐Ÿชœ the smallest number of distinct values where a jump table is better than a tree of conditional branches. If it's 0, the machine's default gets used.
  • jump-table-max-growth-ratio-for-size โ€” ๐Ÿ“ฆ the max code size growth ratio when expanding into a jump table, in percent. This one applies when you're optimizing for size.
  • jump-table-max-growth-ratio-for-speed โ€” ๐ŸŽ๏ธ the max code size growth ratio when expanding into a jump table, in percent. This one applies when you're optimizing for speed.
  • tree-reassoc-width โ€” ๐ŸŒณ the max number of instructions executed in parallel in a reassociated tree. If it's set to a non-zero value, it overrides the target-dependent heuristics that would be used by default.
  • sched-pressure-algorithm โ€” ๐ŸŽ›๏ธ pick between the two implementations of -fsched-pressure. Algorithm 1 is the original and is the more likely of the two to stop instructions from being reordered. Algorithm 2 was designed as a compromise between algorithm 1's pretty conservative approach and the rather aggressive approach of the default scheduler. It leans more heavily on having a regular register file and accurate register pressure classes. For more details, check out haifa-sched.c in the GCC sources. ๐Ÿ“š

The default choice depends on the target. ๐ŸŽฏ

  • max-slsr-cand-scan โ€” ๐Ÿ”ญ the max number of existing candidates considered when hunting for a basis for a new straight-line strength reduction candidate.
  • asan-globals โ€” ๐Ÿ›ก๏ธ enables buffer overflow detection for global objects. This protection is on by default when you use -fsanitize=address. To turn off global objects protection, use --param asan-globals=0.
  • asan-stack โ€” ๐Ÿ›ก๏ธ enables buffer overflow detection for stack objects. This is on by default when using -fsanitize=address. To turn off stack protection, use --param asan-stack=0.
  • asan-instrument-reads โ€” ๐Ÿ‘€ enables buffer overflow detection for memory reads. This is on by default when using -fsanitize=address. To turn off memory reads protection, use --param asan-instrument-reads=0.
  • asan-instrument-writes โ€” โœ๏ธ enables buffer overflow detection for memory writes. This is on by default when using -fsanitize=address. To turn off memory writes protection, use --param asan-instrument-writes=0.
  • asan-memintrin โ€” ๐Ÿงฐ enables detection for built-in functions. This is on by default when using -fsanitize=address. To turn off built-in functions 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.
โš ๏ธ Heads up: by default the check is disabled at run time. To turn it on, add "detect_stack_use_after_return=1" to the ASAN_OPTIONS environment variable.
  • asan-instrumentation-with-call-threshold โ€” ๐Ÿ“ž if the number of memory accesses in the function being instrumented is greater than or equal to this number, GCC uses callbacks instead of inline checks. For example, to disable inline code, use --param asan-instrumentation-with-call-threshold=0.

  • hwasan-instrument-stack โ€” ๐Ÿงฑ enables hwasan instrumentation of statically sized stack-allocated variables. This is on by default when using -fsanitize=hwaddress and off by default when using -fsanitize=kernel-hwaddress. To turn stack instrumentation off, use --param hwasan-instrument-stack=0. To turn it on, use --param hwasan-instrument-stack=1.
  • hwasan-random-frame-tag โ€” ๐ŸŽฒ when stack instrumentation is in use, tags for stack variables come from a deterministic sequence that starts at a random tag for each frame. If this param isn't set, the tags use the same sequence but start from 1. This is enabled by default for -fsanitize=hwaddress and unavailable for -fsanitize=kernel-hwaddress. To disable it, use --param hwasan-random-frame-tag=0.
  • hwasan-instrument-allocas โ€” ๐Ÿช„ enables hwasan instrumentation of dynamically sized stack-allocated variables. This is on by default when using -fsanitize=hwaddress and off by default when using -fsanitize=kernel-hwaddress. To turn off instrumentation for these variables, use --param hwasan-instrument-allocas=0. To turn it on, use --param hwasan-instrument-allocas=1.
  • hwasan-instrument-reads โ€” ๐Ÿ“– enables hwasan checks on memory reads. Read instrumentation is on by default for both -fsanitize=hwaddress and -fsanitize=kernel-hwaddress. To stop checking memory reads, use --param hwasan-instrument-reads=0. ๐Ÿซถ
  • hwasan-instrument-writes โ€” ๐Ÿ’– Turns on hwasan checks for memory writes. It's already on by default for both -fsanitize=hwaddress and -fsanitize=kernel-hwaddress, but if you want to switch it off, use --param hwasan-instrument-writes=0.
  • hwasan-instrument-mem-intrinsics โ€” โœจ Turns on hwasan instrumentation for builtin functions. This is on by default for both -fsanitize=hwaddress and -fsanitize=kernel-hwaddress. To turn it off, use --param hwasan-instrument-mem-intrinsics=0.
  • use-after-scope-direct-emission-threshold โ€” ๐Ÿฆ‹ If a local variable is at most this many bytes, the shadow memory gets poisoned (or unpoisoned) directly, instead of calling run-time callbacks.
  • tsan-distinguish-volatile โ€” ๐ŸŒธ Adds special instrumentation for accesses to volatiles.
  • tsan-instrument-func-entry-exit โ€” ๐Ÿงš Emits instrumentation calls to __tsan_func_entry() and __tsan_func_exit().
  • max-fsm-thread-path-insns โ€” ๐Ÿ’… The most instructions that get copied when duplicating blocks along a finite state automaton jump thread path.
  • max-fsm-thread-length โ€” ๐Ÿซถ The most basic blocks allowed on a finite state automaton jump thread path.
  • max-fsm-thread-paths โ€” ๐Ÿ‘‘ The most new jump thread paths GCC will create for a finite state automaton.
  • parloops-chunk-size โ€” ๐Ÿ”ฅ The chunk size of the omp schedule for loops parallelized by parloops.
  • parloops-schedule โ€” ๐ŸŽ€ The schedule type of the omp schedule for loops parallelized by parloops. Pick from static, dynamic, guided, auto, or runtime.
  • parloops-min-per-thread โ€” โญ The minimum number of iterations per thread in an innermost parallelized loop. Once a loop hits this number, the parallel version is preferred over the single-threaded one. Heads up: for a parallelized loop nest, the minimum number of iterations of the outermost loop per thread is two.
  • max-ssa-name-query-depth โ€” ๐ŸŒˆ The deepest recursion allowed when querying properties of SSA names, like in fold routines. Each level of recursion means following one use-def chain.
  • max-speculative-devirt-maydefs โ€” ๐Ÿ’œ The maximum number of may-defs analyzed while hunting for a must-def that reveals the dynamic type of an object making a virtual call. If we find it, we 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.
  • evrp-mode โ€” ๐Ÿฆ‹ Sets the mode that Early VRP operates in.
  • unroll-jam-min-percent โ€” ๐ŸŒธ The minimum percentage of memory references that must be optimized away for the unroll-and-jam transformation to count as profitable.
  • 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 allowed cost for the sequence the RTL if-conversion pass would generate for a branch considered unpredictable.
  • max-variable-expansions-in-unroller โ€” ๐Ÿงš If -fvariable-expansion-in-unroller is used, this is the maximum number of times one individual variable gets expanded during loop unrolling.
  • tracer-min-branch-probability-feedback โ€” ๐Ÿ’– Stops forward growth once the probability of the best edge drops below this threshold (in percent). Only used when profile feedback is available.
  • partial-inlining-entry-probability โ€” ๐Ÿซถ The maximum probability (in percent, relative to the entry BB of the function) of the entry BB of a split region that still lets partial inlining happen.
  • max-tracked-strlens โ€” ๐Ÿ’… The maximum number of strings whose lengths the strlen optimization pass will track.
  • gcse-after-reload-partial-fraction โ€” ๐Ÿ”ฅ The threshold ratio for doing partial redundancy elimination after reload.
  • gcse-after-reload-critical-fraction โ€” ๐Ÿ‘‘ The threshold ratio of critical edge execution count that still allows redundancy elimination after reload.
  • max-loop-header-insns โ€” ๐ŸŒˆ The maximum number of insns in a loop header that the copy loop headers pass is allowed to duplicate.
  • vect-epilogues-nomask โ€” ๐ŸŽ€ Turns on loop epilogue vectorization using a smaller vector size.
  • vect-partial-vector-usage โ€” ๐Ÿ“ Controls when the loop vectorizer considers partial vector loads and stores, as an alternative to falling back to scalar code. It takes one of three values:
    • 0 โ€” the vectorizer never uses partial vector loads and stores. ๐Ÿ™…
    • 1 โ€” partial vector loads and stores are allowed if vectorization gets rid of the need for the code to iterate. ๐Ÿ”
    • 2 โ€” partial vector loads and stores are allowed in all loops. ๐Ÿ’œ

This parameter only does something on targets that support partial vector loads and stores.

  • 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 that the swing modulo scheduler takes into account.
  • sms-dfa-history โ€” ๐Ÿฆ‹ The number of cycles the swing modulo scheduler looks at when checking for conflicts using DFA.
  • max-inline-insns-recursive-auto โ€” ๐Ÿงš The maximum number of instructions a non-inline function can grow to through recursive inlining.
  • graphite-allow-codegen-errors โ€” ๐Ÿ’€ Decides whether codegen errors should be ICEs when -fchecking is on.
  • sms-max-ii-factor โ€” ๐Ÿซถ A tuning factor for the upper bound the swing modulo scheduler uses when scheduling a loop.
  • lra-max-considered-reload-pseudos โ€” ๐Ÿ”ฅ The maximum 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 โ€” ๐Ÿ’… Turns on 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. Setting it to 0 means unlimited.
  • graphite-max-arrays-per-scop โ€” ๐Ÿ“ The maximum number of arrays per scop.
  • max-vartrack-reverse-op-size โ€” ๐Ÿ™ˆ The maximum size of a loc list for which reverse ops should be added.
  • tracer-dynamic-coverage-feedback โ€” โญ The percentage of a function, weighted by execution frequency, that trace formation must cover. Only 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, used when comparing against 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.
  • 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, used when comparing against the number of (scaled) statements.
  • sched-autopref-queue-depth โ€” ๐Ÿ”ฅ A control flag for the hardware autoprefetcher scheduler model. It's the number of lookahead cycles the model looks into. Set it to ' ' to only enable the instruction sorting heuristic. ๐Ÿค“
  • loop-versioning-max-inner-insns โ€” ๐ŸŒธ The maximum number of instructions an inner loop can have before the loop versioning pass decides it's too big to copy.
  • loop-versioning-max-outer-insns โ€” ๐ŸŽ€ The maximum number of instructions an outer loop can have before the loop versioning pass decides it's too big to copy. Any instructions in inner loops that directly benefit from versioning don't count toward this.
  • 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 the number of iterations or recursive calls GCC makes while optimizing certain statements or checking whether they're valid before issuing diagnostics.
  • store-merging-max-size โ€” ๐Ÿ“ The maximum size of a single store merging region, in bytes.
  • hash-table-verification-limit โ€” ๐Ÿ™ˆ The number of elements that get hash table verification done on them for each searched element.
  • max-find-base-term-values โ€” โญ The maximum number of VALUEs handled during a single find_base_term call.
  • analyzer-max-enodes-per-program-point โ€” ๐Ÿฆ‹ The maximum number of exploded nodes per program point within the analyzer. Once a point hits this, analysis of that point stops.
  • analyzer-max-constraints โ€” ๐Ÿ’– The maximum number of constraints per state.
  • analyzer-min-snodes-for-call-summary โ€” ๐Ÿงš The minimum number of supernodes within a function before the analyzer considers summarizing its effects at call sites.
  • analyzer-max-enodes-for-full-dump โ€” ๐ŸŒˆ The maximum depth of exploded nodes that can show up in a dot dump. Past this, the dump switches to a less verbose format.
  • analyzer-max-recursion-depth โ€” ๐Ÿ’… The maximum number of times a callsite can appear in a call stack within the analyzer. Once it's hit, analysis of a call that would recurse deeper stops.
  • analyzer-max-svalue-depth โ€” ๐Ÿซถ The maximum depth of a symbolic value. Anything deeper gets approximated as unknown.
  • analyzer-max-infeasible-edges โ€” ๐Ÿ‘‘ The maximum number of infeasible edges to reject before a diagnostic is declared infeasible.
  • gimple-fe-computed-hot-bb-threshold โ€” ๐Ÿ”ฅ The number of executions a basic block needs before it counts as hot. This parameter is only used in the GIMPLE FE. โœจ
  • analyzer-bb-explosion-factor โ€” this is the cap on how many "after supernode" exploded nodes the analyzer can make per supernode ๐Ÿ’… Once it hits that number, the analysis gets terminated ๐Ÿ›‘
  • ranger-logical-depth โ€” the max depth of logical expression evaluation that ranger will dig through when it's checking outgoing edge ranges ๐Ÿ”
  • openacc-kernels โ€” picks how OpenACC kernels constructs get handled ๐ŸŒธ There are two modes:
    • --param=openacc-kernels=decompose โ€” each kernels construct gets split into parts, a sequence of compute constructs, and each part is handled individually. Heads up, this one is still work in progress ๐Ÿšง
    • --param=openacc-kernels=parloops โ€” kernels constructs get handled by the parloops pass, en bloc. This is the current default, so you're already getting it ๐Ÿ‘‘

These next ones are the AArch64-only vibes ๐ŸŒˆ They're available on AArch64 targets:

  • aarch64-sve-compare-costs โ€” when vectorizing for SVE, GCC considers using "unpacked" vectors for smaller elements, and lets the cost model pick the cheapest approach ๐Ÿ’– The cost model also decides between SVE and Advanced SIMD vectorization. Going unpacked means storing smaller elements in larger containers, and accessing elements with extending loads and truncating stores ๐ŸŽ€
  • aarch64-float-recp-precision โ€” the number of Newton iterations used to calculate the reciprocal for float type โœจ When division approximation is enabled, the precision of division scales with this param. The default value is 1 ๐Ÿฆ‹
  • aarch64-double-recp-precision โ€” same energy, but for double type ๐Ÿ’œ It's the number of Newton iterations for the reciprocal, and when division approximation is enabled, the precision of division is proportional to this param. The default value is 2 ๐ŸŒธ
  • aarch64-autovec-preference โ€” forces an ISA selection strategy for auto-vectorization ๐Ÿ”ฅ It accepts values from 0 to 4, inclusive:
    • 0 โ€” use the default heuristics ๐Ÿคท
    • 1 โ€” use only Advanced SIMD for auto-vectorization
    • 2 โ€” use only SVE for auto-vectorization
    • 3 โ€” use both Advanced SIMD and SVE, and prefer Advanced SIMD when the costs are deemed equal
    • 4 โ€” use both Advanced SIMD and SVE, and prefer SVE when the costs are deemed equal

The default value is 0.

  • aarch64-loop-vect-issue-rate-niters โ€” some AArch64 CPUs tune by weighing both latencies and issue rates when deciding whether a loop gets vectorized with SVE, with Advanced SIMD, or not at all ๐Ÿง  If this parameter is set to n, GCC won't use this heuristic for loops that are known to execute in fewer than n Advanced SIMD iterations ๐Ÿ™ˆ

๐ŸŽ€ Program Instrumentation Options ๐ŸŽ€

GCC supports a bunch of command-line options that control adding run-time instrumentation to the code it normally generates ๐Ÿ’… For example, one purpose of instrumentation is collecting profiling stats for finding program hot spots, code coverage analysis, or profile-guided optimizations ๐Ÿ“Š Another class adds run-time checking to catch programming errors like invalid pointer dereferences or out-of-bounds array accesses, plus deliberately hostile attacks such as 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 โ€” generates extra code to write profile information suitable for the analysis program prof (for -p) or gprof (for -pg) ๐Ÿ“ˆ You must use this option when compiling the source files you want data about, and you must also use it when linking.

You can use the function attribute no_instrument_function to suppress profiling of individual functions when compiling with these options ๐Ÿ™ˆ

  • -fprofile-arcs โ€” adds code so that program flow arcs get instrumented ๐ŸŒˆ During execution, the program records how many times each branch and call is executed, and how many times it's taken or returns. On targets that support constructors with priority support, profiling properly handles constructors, destructors, and C++ constructors (and destructors) of classes that are used as a type of a global variable. When the compiled program exits, it saves this data to a file called auxname.gcda for each source file ๐Ÿ’พ The data can be used for profile-directed optimizations (-fbranch-probabilities) or for test coverage analysis (-ftest-coverage). Each object file's auxname is generated from the name of the output file, if explicitly specified and it is not the final executable. Otherwise, it's the basename of the source file. In both cases any suffix is removed (e.g. foo.gcda for input file dir/foo.c, or dir/foo.gcda for output file specified as -o dir/foo.o).

With -fprofile-arcs, for each function of your program GCC creates a program flow graph, then finds a spanning tree for the graph. Only arcs that are not on the spanning tree have to be instrumented: the compiler adds code to count the number of times those arcs are executed. When an arc is the only exit or only entrance to a block, the instrumentation code can be added to the block. Otherwise, a new basic block must be created to hold the instrumentation code ๐Ÿงฎ

  • --coverage โ€” this is used to compile and link code instrumented for coverage analysis ๐Ÿงช It's a synonym for -fprofile-arcs -ftest-coverage (when compiling) and -lgcov (when linking). See the documentation for those options for more details. Here's the full workflow:
  1. Compile the source files with -fprofile-arcs plus optimization and code generation options. For test coverage analysis, use the additional -ftest-coverage option. You do not need to profile every source file in a program.
  2. Compile the source files additionally with -fprofile-abs-path to create absolute path names in the .gcno files. This allows gcov to find the correct sources in projects where compilations occur with different working directories.
  3. Link your object files with -lgcov or -fprofile-arcs (the latter implies the former).
  4. Run the program on a representative workload to generate the arc profile information. This may be repeated any number of times. You can run concurrent instances of your program, and provided that 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.
  5. For profile-directed optimizations, compile the source files again with the same optimization and code generation options plus -fbranch-probabilities.
  6. For test coverage analysis, use gcov to produce human readable information from the .gcno and .gcda files. Refer to the gcov documentation for further information.
  • -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. Refer to the -fprofile-arcs option above for a description of auxname and instructions on how to generate test coverage data. Coverage data matches the source files more closely if you do not optimize ๐ŸŽฏ
  • -fprofile-abs-path โ€” automatically converts relative source file names to absolute path names in the .gcno files ๐Ÿ—บ๏ธ This allows gcov to find the correct sources in projects where compilations occur with different working directories.
  • -fprofile-dir=path โ€” sets the directory to search for the profile data files in to path ๐Ÿ“‚ This option only affects the profile data generated by -fprofile-generate, -ftest-coverage, and -fprofile-arcs, and used by -fprofile-use and -fbranch-probabilities and its related options. Both absolute and relative paths can be used. By default, GCC uses the current directory as path, so the profile data file appears in the same directory as the object file. To prevent file name clashing, if the object file name is not an absolute path, GCC mangles the absolute path of the sourcename.gcda file and uses it as the file name of a .gcda file. See similar option -fprofile-note.

When an executable is run 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 during run-time:

  • %p โ€” process ID.
  • %q{VAR} โ€” value of environment variable VAR
  • -fprofile-generate, -fprofile-generate=path โ€” enables options usually used for instrumenting an application to produce a profile that's useful for later recompilation 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 at that path to find the profile feedback data files. See -fprofile-dir. To optimize the program based on the collected profile information, use -fprofile-use ๐Ÿ‘‘

  • -fprofile-info-section, -fprofile-info-section=name โ€” registers the profile information in the specified section instead of using a constructor/destructor ๐Ÿงฉ The section name is name if it's specified, otherwise it defaults to .gcov_info. A pointer to the profile information generated by -fprofile-arcs or -ftest-coverage is placed in the specified section for each translation unit. This option disables the profile information registration through a constructor, and it disables the profile information processing through a destructor. It is not intended to be used in hosted environments such as GNU/Linux. It targets systems with limited resources that don't support constructors and destructors. The linker could collect the input sections in a continuous memory block and define start and end symbols. The runtime support could dump the profiling information registered in this linker set during program termination to a serial line, for example. โœจ

Now for the spicy part, bestie: a GNU linker script example that defines a linker output section comes right up next:

Picking up right where that linker script leaves off ๐ŸŽ€

                     .gcov_info      :
                     {
                       PROVIDE (__gcov_info_start = .);
                       KEEP (*(.gcov_info))
                       PROVIDE (__gcov_info_end = .);
                     }
  • -fprofile-note=path โ€” okay so, if you give it a path, GCC drops the .gcno file right there ๐Ÿ“ bestie, heads up: if you combine it with multiple source files, that .gcno gets overwritten ๐Ÿ˜ญ
  • -fprofile-prefix-path=path โ€” this one is a total lifesaver โœจ It's meant to be used with profile-generate=profile_dir and profile-use=profile_dir, and it tells GCC where the base directory of your built source tree lives ๐ŸŒธ
    • By default, profile_dir gets filled with files that have mangled absolute paths for every object file in the build. Lowkey messy ๐Ÿ’€
    • It becomes a real problem when the directory you built the instrumented binary in is different from the one you used for the optimized build. The profile data just won't be found ๐Ÿ™ˆ
    • So you point -fprofile-prefix-path=path at the base directory of the build. It strips the irrelevant part and keeps every file name relative to the main build directory ๐Ÿฆ‹
  • -fprofile-update=method โ€” this changes how the update works for an app that's been instrumented for profile feedback based optimization ๐Ÿ’… The method argument should be single, atomic, or prefer-atomic.
    • single is the move for single-threaded apps ๐Ÿงš
    • atomic is the thread-safe queen, because it prevents profile corruption by emitting thread-safe code ๐Ÿ‘‘
Warning: if an application doesn't properly join all its threads (or it creates a detached thread), a profile file can still get corrupted. Not ideal, bestie ๐Ÿ˜ญ
  • prefer-atomic is transformed into atomic when the target supports it, and into single otherwise ๐ŸŒˆ
  • The GCC driver automatically picks prefer-atomic whenever -pthread is in the command line โœจ
  • -fprofile-filter-files=regex โ€” only instrument functions from files whose name matches any of the regular expressions, separated by semi-colons ๐ŸŽฏ
    • Example: -fprofile-filter-files=main\.c;module.*\.c will instrument only main.c and all C files starting with 'module' ๐Ÿ“
  • -fprofile-exclude-files=regex โ€” this one's the mirror vibe ๐Ÿชž It says to instrument only functions from files whose name does not match any of the regular expressions, separated by semi-colons.
    • Example: -fprofile-exclude-files=/usr/.* will prevent instrumentation of all files located in the /usr/ folder ๐Ÿ’œ
  • -fprofile-reproducible=[multithreaded|parallel-runs|serial] โ€” this controls how reproducible the profile gathered by "-fprofile-generate" is ๐Ÿ’– It's giving rebuild-the-same-outcome energy, which is super useful for things like distribution packages ๐Ÿ“ฆ
    • serial โ€” the profile is reproducible provided the trained program behaves the same at each invocation of the train run, it's not multi-threaded, and profile data streaming is always done in the same order ๐Ÿซถ Also, streaming happens at the end of the program run, but also before the "fork" function is invoked. Wild, right? ๐Ÿ˜ญ
    • Heads up: execution counts for some parts of a program can depend on things like the length of temporary file names or memory space randomization (which might mess with hash-table collision rate) ๐Ÿ™ˆ That non-reproducible part can be annotated with the no_instrument_function function attribute. You can use gcov-dump with -l to dump the gathered data and check that it's actually reproducible ๐Ÿ”
    • parallel-runs โ€” the collected profile stays reproducible no matter what order the data gets streamed into gcda files ๐ŸŽ€ This lets you run multiple instances of the instrumented program in parallel (like with make -j) ๐Ÿƒโ€โ™€๏ธ
Heads up: running in parallel reduces the quality of the gathered data, especially for indirect call profiling ๐Ÿ’€
  • -fsanitize=address โ€” enables AddressSanitizer, a fast memory error detector ๐Ÿ”ฅ It instruments memory access instructions to catch out-of-bounds and use-after-free bugs. This option also enables -fsanitize-address-use-after-scope.
  • -fsanitize=kernel-address โ€” AddressSanitizer for the Linux kernel ๐Ÿง More info at https://github.com/google/kasan ๐ŸŒธ
  • -fsanitize=hwaddress โ€” hardware-assisted AddressSanitizer ๐Ÿฆ‹ It uses a hardware ability to ignore the top byte of a pointer, which lets it detect memory errors with a low memory overhead. Memory access instructions get instrumented to catch out-of-bounds and use-after-free bugs, and this option enables -fsanitize-address-use-after-scope.
    • See https://clang.llvm.org/docs/HardwareAssistedAddressSanitizerDesign.html for more details ๐Ÿ“–
    • Run-time behavior can be influenced with the HWASAN_OPTIONS environment variable. When set to "help=1", the available options show up at startup of the instrumented program ๐Ÿ’…
    • This can't be combined with -fsanitize=thread or -fsanitize=address, and it's currently only available on AArch64 ๐Ÿซถ
  • -fsanitize=kernel-hwaddress โ€” hardware-assisted AddressSanitizer for compiling the Linux kernel ๐Ÿ‘‘ It's similar to -fsanitize=kernel-address but uses an alternate instrumentation method. It's also similar to -fsanitize=hwaddress, just with instrumentation differences needed for the kernel ๐ŸŒˆ Those differences exist to avoid hwasan library initialization calls and to account for the stack pointer having a different value in its top byte.
Note: this option has different defaults to -fsanitize=hwaddress. Instrumenting the stack and alloca calls isn't on by default, but you can still turn it on with the command-line options --param hwasan-instrument-stack=1 and --param hwasan-instrument-allocas=1 respectively ๐Ÿงš Using a random frame tag isn't implemented for kernel instrumentation ๐Ÿ’€
  • -fsanitize=pointer-compare โ€” instruments comparison operations (<, <=, >, >=) with pointer operands ๐Ÿ‘€ It must be combined with either -fsanitize=kernel-address or -fsanitize=address, and it can't be combined with -fsanitize=thread.
    • Heads up: the check is disabled at run time by default ๐Ÿ™ˆ To turn it on, add "detect_invalid_pointer_pairs=2" to the ASAN_OPTIONS environment variable.
    • "detect_invalid_pointer_pairs=1" only detects invalid operation when both pointers are non-null ๐Ÿ”
  • -fsanitize=pointer-subtract โ€” same energy, but for subtraction with pointer operands โœจ It must be combined with either -fsanitize=kernel-address or -fsanitize=address, and it can't be combined with -fsanitize=thread.
    • Again, the check is disabled at run time by default. Add "detect_invalid_pointer_pairs=2" to ASAN_OPTIONS to enable it ๐Ÿ’–
    • "detect_invalid_pointer_pairs=1" only detects invalid operation when both pointers are non-null ๐ŸŒธ
  • -fsanitize=thread โ€” enables ThreadSanitizer, a fast data race detector ๐Ÿงต It instruments memory access instructions to catch data race bugs. More details at https://github.com/google/sanitizers/wiki#threadsanitizer ๐Ÿ“–
    • Run-time behavior can be influenced with the TSAN_OPTIONS environment variable. For a list of supported options, check https://github.com/google/sanitizers/wiki/ThreadSanitizerFlags ๐Ÿ’œ
    • This can't be combined with -fsanitize=address or -fsanitize=leak ๐Ÿ™…โ€โ™€๏ธ
    • 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 when linking executables, and when the executable is linked against a library that overrides malloc and other allocator functions.
  • -fsanitize=undefined โ€” enables UndefinedBehaviorSanitizer, a fast undefined behavior detector ๐ŸŒˆ Various computations get instrumented to catch undefined behavior at runtime.
    • See https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html for more details ๐Ÿ“–
    • Run-time behavior can be influenced with the UBSAN_OPTIONS environment variable. Current suboptions are:
      • -fsanitize=shift โ€” checks that the result of a shift operation isn't undefined ๐Ÿซง What counts as undefined differs slightly between C and C++, and also between ISO C90 and C99, etc. This option has two suboptions: -fsanitize=shift-base and -fsanitize=shift-exponent.
      • -fsanitize=shift-exponent โ€” checks that the second argument of a shift operation isn't negative and is smaller than the precision of the promoted first argument ๐Ÿ”ข
      • -fsanitize=shift-base โ€” if the second argument of a shift operation is within range, it checks that the result of the shift isn't undefined ๐Ÿงฎ Same deal as above: the exact rules differ between C and C++, and between ISO C90 and C99, etc.
      • -fsanitize=integer-divide-by-zero โ€” detects integer division by zero, as well as "INT_MIN / -1" division ๐Ÿ™ˆ
      • -fsanitize=unreachable โ€” the compiler turns the "__builtin_unreachable" call into a diagnostics message call instead ๐Ÿšจ When you reach the "__builtin_unreachable" call, the behavior is undefined, so this is a whole vibe check ๐Ÿ˜ญ
      • -fsanitize=vla-bound โ€” checks that the size of a variable length array is positive ๐Ÿ“
  • -fsanitize=null โ€” okay, pointer checking is the vibe here ๐Ÿ’– With this on, your program throws an error when it tries to dereference a NULL pointer ๐Ÿ˜ญ. It also flags a reference (possibly an rvalue reference) bound to a NULL pointer, or a method invoked on an object pointed to by a NULL pointer.
  • -fsanitize=return โ€” return statement checking, and it's giving main character energy ๐Ÿ’… Programs built with this will issue an error when the end of a non-void function is reached without actually returning a value. This one is C++ only ๐ŸŒธ.
  • -fsanitize=signed-integer-overflow โ€” signed integer overflow checking ๐Ÿ”ฅ It checks that the result of +, *, and both unary and binary - doesn't overflow in signed arithmetic. Integer promotion rules still apply, so this is not an overflow:
signed char a = SCHAR_MAX;
a++;
  • -fsanitize=bounds โ€” array bounds instrumentation ๐Ÿฆ‹ Lots of out-of-bounds accesses get caught. Flexible array members, flexible array member-like arrays, and initializers of variables with static storage are not instrumented ๐Ÿ™ˆ
  • -fsanitize=bounds-strict โ€” the stricter array bounds check ๐Ÿ’œ 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 โ€” pointer alignment checking โœจ It kicks in when a pointer gets 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 โ€” memory references get instrumented using the __builtin_object_size function ๐Ÿ“ Various out-of-bounds pointer accesses are detected.
  • -fsanitize=float-divide-by-zero โ€” floating-point division by zero detection โž— Unlike other similar options, this one is not turned on by -fsanitize=undefined. That's because dividing a float by zero can be a legit way to get infinities and NaNs, so it's not automatically treated as a bug ๐ŸŒˆ
  • -fsanitize=float-cast-overflow โ€” floating-point to integer conversion checking ๐Ÿงš It makes sure the result of the conversion doesn't overflow. Also not turned on by -fsanitize=undefined.
โš ๏ธ Heads up bestie ๐Ÿ’€ This option does not work well with FE_INVALID exceptions enabled.
  • -fsanitize=nonnull-attribute โ€” checks calls to make sure null values aren't passed to arguments marked as needing 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, so it can catch null values being returned from them ๐ŸŽ€
  • -fsanitize=bool โ€” instruments loads from bool ๐Ÿ‘‘ If a value other than 0/1 gets loaded, you'll get a run-time error.
  • -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++ member function calls, member accesses, and some conversions between pointers to base and derived classes get instrumented ๐Ÿฆ‹ This verifies the referenced object has the correct dynamic type.
  • -fsanitize=pointer-overflow โ€” pointer arithmetic gets instrumented ๐ŸŒธ If the 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. For example, 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 instead. 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 useful 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] โ€” controls the error recovery mode for the sanitizers in the comma-separated list opts ๐Ÿ” When recovery is enabled for a sanitizer, it tries to keep running the program as if no error happened. That means multiple runtime errors can be reported in a single run, and the exit code may indicate success even when errors were reported. The -fno-sanitize-recover= option changes this: only the first detected error gets 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 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 detect use-after-scope bugs ๐Ÿ” This option sets -fstack-reuse to none.
  • -fsanitize-undefined-trap-on-error โ€” reports undefined behavior using __builtin_trap instead of a libubsan library routine ๐Ÿช„ The perk is that the libubsan library isn't needed and doesn't get linked in, so this works 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 the following:
    • __sanitizer_cov_trace_cmp1, __sanitizer_cov_trace_cmp2, __sanitizer_cov_trace_cmp4, or __sanitizer_cov_trace_cmp8 for integral comparisons where both operands are variables
    • __sanitizer_cov_trace_const_cmp1, __sanitizer_cov_trace_const_cmp2, __sanitizer_cov_trace_const_cmp4, or __sanitizer_cov_trace_const_cmp8 for integral comparisons where one operand is a constant
    • __sanitizer_cov_trace_cmpf or __sanitizer_cov_trace_cmpd for float or double comparisons
    • __sanitizer_cov_trace_switch for switch statements
  • -fcf-protection=[full|branch|return|none|check] โ€” control-flow instrumentation for extra security ๐Ÿ›ก๏ธ It checks that the target addresses of control-flow transfer instructions (such as indirect function calls, function returns, and indirect jumps) are valid. This stops the flow of control from being diverted to an unexpected target. It's meant to protect against threats like Return-oriented Programming (ROP), and similar call/jmp-oriented programming (COP/JOP) ๐Ÿ”
    • branch โ€” checking happens at indirect branch instructions, i.e. call/jmp instructions ๐ŸŒฟ
    • return โ€” checking happens when returning from a function โ†ฉ๏ธ
    • full โ€” an alias for specifying both branch and return ๐Ÿ‘‘
    • none โ€” turns off instrumentation ๐Ÿ™…
    • check โ€” used for the final link with link-time optimization (LTO). An error is issued if LTO object files were compiled with different -fcf-protection values. This value is ignored at compile time ๐Ÿซ 

The macro __CET__ is defined when -fcf-protection is used โœจ The first bit of __CET__ is set to 1 for the value branch, and the second bit of __CET__ is set to 1 for return.

You can also use the nocf_check attribute to mark which functions and calls should be skipped from instrumentation ๐Ÿ™ˆ

Right now the x86 GNU/Linux target provides an implementation based on Intel Control-flow Enforcement Technology (CET), which works for 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 โ€” okay bestie, this one is a stack-smashing bodyguard ๐Ÿ›ก๏ธ๐Ÿ’– It sneaks a guard variable into any function with vulnerable objects. That covers functions that call alloca, plus functions with buffers of at least 8 bytes. The guards get set up when a function is entered and get checked on the way out. If a guard check fails, you get an error message and the program exits. Only variables that actually live on the stack count, so anything optimized away or stuck in a register doesn't get a guard. ๐ŸŒธ
  • -fstack-protector-all โ€” same energy as -fstack-protector, but every single function gets protected. Full bodyguard mode ๐Ÿ‘‘
  • -fstack-protector-strong โ€” basically -fstack-protector but with extra functions in the guest list ๐ŸŽ€ These are the ones with local array definitions, or ones that reference local frame addresses. The same rule applies: only variables actually allocated on the stack count, and optimized-away or register variables don't.
  • -fstack-protector-explicit โ€” the VIP-list version of -fstack-protector. It only protects functions that carry the stack_protect attribute ๐Ÿงš
  • -fstack-check โ€” this one makes the code check that you don't go past the edge of the stack ๐Ÿฆ‹ You'll want it if you're running in a multithreaded environment. In a single-threaded setup you almost never need it, because stack overflow is usually caught automatically on nearly every system if there's only one stack. ngl that's a relief ๐Ÿ˜ญ

This flag doesn't do the checking itself. The operating system or the language runtime has to do that. What it does is generate code so they can see the stack being extended. You can also pass it a string parameter: no means no checking at all, generic forces the old-style checking, and specific uses the best checking method for the target and is equivalent to bare -fstack-check.

Old-style checking is a generic mechanism. It doesn't need any target-specific support from the compiler, but it comes with some drawbacks, and honestly they're a lot:

  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, so be careful ๐Ÿ‘€
  2. Fixed limit on the size of the static frame of functions: when a particular function tops it, stack checking isn't reliable and the compiler issues a warning.
  3. Inefficiency: between the modified allocation strategy and the generic implementation, your code performance takes a hit ๐Ÿ’€

Also, old-style stack checking is the fallback for specific if the compiler doesn't have target support added. So specific falls back to it when there's no target support.

-fstack-check= was designed for Ada's needs, specifically detecting infinite recursion and stack overflows. specific is an excellent choice when you're compiling Ada code ๐Ÿ’… It's not generally enough to protect you against stack-clash attacks though. For that, you want -fstack-clash-protection.

  • -fstack-clash-protection โ€” this is the anti-stack-clash flag ๐Ÿ”ฅ When it's on, the compiler only allocates one page of stack space at a time, and each page gets accessed right after it's allocated. That means allocations can't jump over a 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 can also give limited protection to static stack allocations, but only if the target supports -fstack-check=specific.

NOTE: In Ubuntu 19.10 and later, -fstack-clash-protection is enabled by default for C, C++, ObjC, and ObjC++, unless -fno-stack-clash-protection shows up in the command line. So it's already on for you, probably ๐Ÿซถ
  • -fstack-limit-register=reg, -fstack-limit-symbol=sym, -fno-stack-limit โ€” these generate code so the stack never grows past a certain value. That value is either a register's contents or the address of a symbol ๐ŸŒˆ If the program needs a bigger stack than that, a signal gets raised at run time. On most targets the signal goes off before the stack actually overruns the boundary, so you can catch it without doing anything special.

Here's an 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 โœจ Heads up, this may only work with the GNU linker.

You can override stack limit checking locally by using the no_stack_limit function attribute ๐Ÿ™ˆ

  • -fsplit-stack โ€” this one automatically splits the stack before it overflows ๐Ÿงš The result is a discontiguous stack, which can only overflow if the program can't allocate any more memory at all. It's most useful for threaded programs, because you don't have to work out a good stack size for each thread anymore. Life-changing ๐Ÿ˜ญ Right now it's only implemented for x86 targets running GNU/Linux.

If code compiled with -fsplit-stack calls code compiled without it, the latter code might not have much stack space to run in. If compiling everything (library code included) with -fsplit-stack isn't an option, the linker can fix up those calls so the code without -fsplit-stack always gets a large stack. This support is implemented in the gold linker in GNU binutils release 2.21 and later ๐Ÿฆ‹

  • -fvtable-verify=[std|preinit|none] โ€” C++ only! ๐Ÿ’œ This turns on the security feature that checks, at run time and for every virtual call, that the vtable pointer used for the call is valid for the object's type and hasn't been corrupted or overwritten. Use -fvtable-verify=none to turn it off. If an invalid vtable pointer gets detected, an error is reported and the program stops right away ๐Ÿ›‘

This option builds run-time data structures at program startup, and those are what verify the vtable pointers. The std and preinit values control when those structures get built. In both cases they're built before execution reaches main. With -fvtable-verify=std, they're built after shared libraries have been loaded and initialized. With -fvtable-verify=preinit, they're built before shared libraries have been loaded and initialized.

If this option shows up multiple times in the command line with different values, none takes the highest priority over both std and preinit, and preinit takes priority over std ๐Ÿ’…

  • -fvtv-debug โ€” use this with -fvtable-verify=std or -fvtable-verify=preinit and it calls the debug versions of the runtime functions for vtable verification ๐Ÿ” It also makes the compiler log which vtable pointers it finds for each class. That info goes into a file called vtv_set_ptr_data.log, in the directory named by the environment variable VTV_LOGS_DIR if that's defined, or in the current working directory otherwise.
Note: this feature appends to the log file. If you want a fresh log, delete any existing one first ๐Ÿงน
  • -fvtv-counts โ€” a debugging flag, bestie ๐Ÿ› With -fvtable-verify=std or -fvtable-verify=preinit, the compiler keeps track of the total number of virtual calls it runs into, and the number of verifications it inserts. It also counts the calls it inserts to certain run-time library functions and logs all of this for each compilation unit. The compiler writes that info to vtv_count_data.log in the directory named by VTV_LOGS_DIR if it'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 to the log files too. For fresh log files, delete any existing ones first ๐Ÿ’€
  • -finstrument-functions โ€” this generates instrumentation calls for function entry and exit ๐ŸŒธ Right after a function is entered, and right before it exits, the following profiling functions get called with the address of the current function and its call site. (Heads up: on some platforms, __builtin_return_address doesn't work beyond the current function, so the call site info might not be available to the profiling functions.)
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 ๐Ÿ”ฅ

This instrumentation also happens for functions that get expanded inline into other functions. The profiling calls show where, conceptually, the inline function is entered and exited. That means addressable versions of those functions have to exist. If all your uses of a function get expanded inline, this may mean extra code size. If you use extern inline in your C code, an addressable version of those functions must be provided. (This is usually the case anyway, but if you get lucky and the optimizer always expands them inline, you might have gotten away without providing static copies ๐Ÿ™ˆ)

A function can be given the no_instrument_function attribute, and then this instrumentation won't happen for it. This is handy for things like the profiling functions listed above, high-priority interrupt routines, and any function the profiling functions can't safely be called from, like signal handlers if the profiling routines generate output or allocate memory ๐Ÿ’œ

  • -finstrument-functions-exclude-file-list=file,file,... โ€” okay bestie, this one is the VIP exclusion list ๐Ÿšซโœจ It sets which functions get skipped for instrumentation (peep -finstrument-functions for the full tea โ˜•). If the file holding a function's definition matches one of the file entries, that function is NOT instrumented. The match is done on substrings, so if your file bit shows up anywhere inside the file name, it counts ๐Ÿฆ‹

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 need a comma inside one of the sym values, you double it up and write ,, ๐Ÿ™ˆ Like this, with single quotes around the whole option: -finstrument-functions-exclude-file-list=',,tmp' ๐Ÿงต

  • -finstrument-functions-exclude-function-list=sym,sym,... โ€” this is basically the file-list's cousin ๐Ÿ‘ฏ, except it lists the function names to skip instead of files. The name that gets matched is the user-visible name, like vector<int> blah(const vector<int> &), NOT the scrambled internal mangled name like _Z4blahRSt6vectorIiSaIiEE ๐Ÿ’€. Matching is substring-based too: if 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] โ€” okay this one is giving extra space ๐Ÿงš. It generates N NOPs right at the start of each function, with the function entry point sitting before the Mth NOP. If M is left off, it defaults to 0, so the entry point is the address right at the first NOP. Those NOPs reserve room you can patch instrumentation into at run time, as long as the code segment is writable โœจ. The amount of space is controlled indirectly through how many NOPs you ask for. The NOP instruction used is the one emitted by the internal GCC back-end interface gen_nop. This 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 respective function entries minus M, also get 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 can be used to increase the area size or to remove 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. ๐Ÿซฃ

The maximum value of N and M is 65535 ๐Ÿ‘‘


โœจ Options Controlling the Preprocessor โœจ

These options control the C preprocessor, which runs on each C source file before the actual compilation happens ๐Ÿงผ

If you use -E, nothing gets 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 โ€” predefines 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 truncated by any embedded newline characters โœ‚๏ธ

If you're invoking the preprocessor from a shell (or something shell-like), you might need the shell's quoting syntax to protect characters like spaces that have a meaning in shell syntax ๐Ÿš

If you want to define a function-like macro on the command line, write its argument list with surrounding parentheses before the equals sign (if any). 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 are processed in the order they're given on the command line. All -imacros file and -include file options get processed after all -D and -U options ๐Ÿ”

  • -U name โ€” cancels 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 twist: 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 gets searched for in the rest of the #include "..." search chain as normal.

If you give multiple -include options, the files are included in the order they show up 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, which 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 โ€” do not predefine any system-specific or GCC-specific macros ๐Ÿšซ. The standard predefined macros stay defined ๐Ÿ’…
  • -pthread โ€” defines the extra 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, it outputs a rule suitable for make that describes 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, including those coming from -include or -imacros command-line options ๐Ÿฆ‹

Unless you specify it explicitly (with -MT or -MQ), the object file name consists of the name of the source file with any suffix replaced by the object file suffix and 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 doesn't suppress the preprocessor's debug output, such as -dM. To avoid mixing that debug output with the dependency rules, you should explicitly specify the dependency output file with -MF, or use an environment variable like DEPENDENCIES_OUTPUT. Debug output is still sent 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 doesn't mention header files found in system header directories, nor header files included directly or indirectly from such a header ๐Ÿ 

This implies that the choice of angle brackets or double quotes in an #include directive doesn't in itself determine whether that header appears in -MM dependency output ๐ŸŽ€

  • -MF file โ€” when used with -M or -MM, specifies a file to write the dependencies to ๐Ÿ“. If there's no -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 are written to stdout ๐Ÿ–จ๏ธ
  • -MG โ€” in conjunction with an option such as -M requesting dependency generation, -MG assumes missing header files are generated files and 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 โš™๏ธ

  • -Mno-modules โ€” disables dependency generation for compiled module interfaces ๐Ÿงฉ
  • -MP โ€” instructs CPP to add a phony target for each dependency other than the main file, causing each one to depend 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. The 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 which 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 โ€” -MD is equivalent to -M -MF file, except that -E is not implied ๐Ÿ”ฅ. The driver determines file based on whether an -o option is given. If it is, the driver uses its argument but with a suffix of .d. Otherwise, it takes the name of the input file, removes any directory components and suffix, and applies a .d suffix ๐Ÿ“‚.

If -MD is used in conjunction with -E, any -o switch is understood to specify the dependency output file, but if used without -E, each -o is understood to specify a target object file ๐Ÿง

Since -E is not implied, -MD can be used to generate a dependency output file as a side effect of the compilation process ๐ŸŒŸ

  • -MMD โ€” like -MD except it mentions only user header files, not system header files ๐Ÿ’œ
  • -fpreprocessed โ€” ๐Ÿ’– okay so this flag tells the preprocessor "bestie, this file is ALREADY preprocessed, don't touch it" ๐Ÿ™…โ€โ™€๏ธ It skips macro expansion, trigraph conversion, escaped newline splicing, and processing of most directives. Comments still get recognized and removed, so you can pass in a file made with -C with zero drama โœจ In this mode the integrated preprocessor is basically just a tokenizer for the front ends ๐Ÿงš Also, -fpreprocessed is implicit if your input file ends in .i, .ii or .mi. Those are the extensions GCC uses for preprocessed files made by -save-temps ๐ŸŽ€
  • -fdirectives-only โ€” ๐ŸŒธ When preprocessing, this handles directives but does NOT expand macros. How it acts depends on -E and -fpreprocessed, so let's break it down:
    • With -E, preprocessing is limited to directives like "#define", "#ifdef", and "#error". Macro expansion and trigraph conversion are skipped, and -dD gets turned on automatically ๐Ÿฆ‹
    • With -fpreprocessed, predefinition of command line macros and most builtin macros is turned off. Contextual macros like __LINE__ still get handled normally. This is what lets you compile files that were previously run through -E -fdirectives-only ๐Ÿ‘‘
    • With both -E and -fpreprocessed, the -fpreprocessed rules win. This gives you full preprocessing of files that were previously run through -E -fdirectives-only ๐Ÿ’…
  • -fdollars-in-identifiers โ€” ๐Ÿ’œ Lets $ show up inside identifiers. Accepted, no cap.
  • -fextended-identifiers โ€” ๐ŸŒˆ Accepts universal character names and extended characters in identifiers. This one is on by default for C99 (and later C standards) and C++, so it's literally already on for you ๐Ÿซถ
  • -fno-canonical-system-headers โ€” ๐Ÿ™ˆ When preprocessing, this stops system header paths from getting shortened with canonicalization.
  • -fmax-include-depth=depth โ€” ๐Ÿงถ Sets the max depth of nested #includes. Default is 200.
  • -ftabstop=width โ€” ๐Ÿ“ Sets the distance between tab stops. This helps the preprocessor report correct column numbers in warnings or errors, even when tabs are on the line. If the value is less than 1 or greater than 100, the option gets ignored. Default is 8 ๐Ÿ“
  • -ftrack-macro-expansion[=level] โ€” ๐Ÿ” Tracks token locations across macro expansions, so when an error happens inside a macro, the compiler can show you the current macro expansion stack. Heads up: this makes the preprocessor and compiler eat more memory ๐Ÿฝ๏ธ The level parameter lets you pick how precise the tracking is, so you can drop memory use if you need to:
    • 0 turns this off
    • 1 tracks locations in a degraded mode for minimal memory overhead. In this mode, every token coming from expanding an argument of a function-like macro gets the same location
    • 2 tracks locations completely. This is the most memory hungry option ๐Ÿ˜
    • With no argument at all, the default level is 2

Note that -ftrack-macro-expansion=2 is activated by default โœจ

  • -fmacro-prefix-map=old=new โ€” ๐Ÿ—บ๏ธ When preprocessing files living in directory old, the __FILE__ and __BASE_FILE__ macros get expanded as if those files lived in directory new instead. You can use . for new to turn an absolute path into a relative one, which can lead to 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. 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 one of UTF-32BE, UTF-32LE, UTF-16BE, or UTF-16LE, whichever matches the width of wchar_t and the big-endian or little-endian byte order used for code generation. Just like -fexec-charset, charset can be any encoding iconv supports. โš ๏ธ Fair warning though: you'll have problems with encodings that don't fit exactly in wchar_t.
  • -finput-charset=charset โ€” ๐Ÿ“ฅ Sets the input character set, used for translating from the input file's character set into the source character set GCC uses. If the locale doesn't specify one, or GCC can't get it from the locale, the default is UTF-8. The locale or this command-line option can override it, but if they conflict, the command-line option wins ๐Ÿ† charset can be any encoding iconv supports.
  • -fpch-deps โ€” ๐Ÿ“š When you're using precompiled headers, this makes the dependency-output flags also list the files from the precompiled header's dependencies. Without it, only the precompiled header gets listed, not the files used to create it, because those files aren't consulted when a precompiled header is used ๐Ÿ™ƒ
  • -fpch-preprocess โ€” ๐Ÿงฉ This lets you use a precompiled header together with -E. It inserts a special #pragma into the output, #pragma GCC pch_preprocess "filename", 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 preprocessed output is only really suitable as input to GCC. It gets switched on by -save-temps.
    • You shouldn't write this #pragma in your own code. But it's totally safe to edit the filename if the PCH file lives somewhere else now. The filename can be absolute, or relative to GCC's current directory.
  • -fworking-directory โ€” ๐Ÿ“‚ Turns on linemarkers in the preprocessor output that tell the compiler what the working directory was at preprocessing time. When it's on, the preprocessor emits a second linemarker after the initial one, containing 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 block it with the negated form -fno-working-directory. If the -P flag is in the command line, this option does nothing, since no #line directives get emitted whatsoever ๐Ÿšซ
  • -A predicate=answer โ€” ๐Ÿช„ Makes an assertion with the predicate predicate and the answer answer. This form is the preferred one over the older -A predicate(answer), 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. Bye bye ๐Ÿ‘‹
  • -C โ€” ๐Ÿ’ฌ Keeps your comments! Everything gets passed through to the output file, except comments inside processed directives, which get deleted along with the directive.
    • Be prepared for side effects with -C, because it makes the preprocessor treat comments as tokens in their own right. For example, a comment at the start of what would be a directive line turns that line into an ordinary source line, since the first token on the line is no longer a # ๐Ÿ˜ญ
  • -CC โ€” ๐Ÿ’… Keeps comments, including during macro expansion. It's like -C, except comments inside macros also get passed through to the output file wherever 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 โ€” ๐Ÿค Stops linemarkers from showing up in the preprocessor output. This could come in handy when you're running the preprocessor on something that isn't C code and will get sent to a program that might get confused by linemarkers.
  • -traditional, -traditional-cpp โ€” ๐Ÿ•ฐ๏ธ These try to imitate the behavior of pre-standard C preprocessors, instead of ISO C preprocessors. Check the GNU CPP manual for details.
    • GCC doesn't try to emulate a pre-standard C compiler otherwise, and these options only work with the -E switch, or when you invoke CPP explicitly.
  • -trigraphs โ€” ๐Ÿ”บ Supports ISO C trigraphs. These are three-character sequences that all start with ??, which ISO C defines as stand-ins 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 โ€” ๐Ÿ—‚๏ธ Turns on special code to work around file systems that only allow very short file names, like MS-DOS ๐Ÿ’พ
  • -H โ€” ๐Ÿ”Ž Prints the name of each header file used, on top of the other normal stuff. Each name is indented to show how deep it is in the #include stack ๐ŸŒฟ Precompiled header files get printed too, even if they turn out to be invalid. An invalid precompiled header is printed with ...x, and a valid one with ...! โœ…
  • -dletters โ€” ๐Ÿงช Tells GCC to make debugging dumps during compilation, as specified by letters. The flags documented here are the ones relevant to the preprocessor. Other letters are interpreted by the compiler proper, or reserved for future versions of GCC, so they're silently ignored. If you specify letters whose behavior conflicts, the result is undefined ๐Ÿ’€
    • -dM โ€” ๐Ÿ“œ Instead of the normal output, this generates a list of #define directives for all the macros defined during the execution of the preprocessor, including predefined macros. It's a super easy way to find out what's predefined in your version of the preprocessor ๐Ÿ”ฎ Assuming you have no file foo.h, the command

okay so the easiest way to see every predefined macro your compiler has baked in is this ๐Ÿ‘‡

touch foo.h; cpp -dM foo.h

and bestie, it spits out all of them ๐Ÿคฏ main character energy.

Heads up ๐Ÿ’€: if you use -dM without the -E option, -dM gets treated as a synonym for -fdump-rtl-mach. Not me getting plot-twisted ๐Ÿ˜ญ
  • -dD โ€” this one is like -dM but with two twists ๐ŸŒธ It skips 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 โ€” basically -dD, but chill. It only emits the macro names, not their expansions ๐Ÿงš
  • -dI โ€” adds #include directives to the output, on top of the preprocessing result ๐ŸŽ€
  • -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 the use or test of the macro, and #undef directives also show up for macros that were tested but undefined at that time ๐Ÿ’…
  • -fdebug-cpp โ€” ngl this one is only for 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 the dump of the map its location belongs to. When it's used from GCC without -E, it does absolutely nothing ๐Ÿ’€
  • -Wp,option โ€” lets you skip the compiler driver and send option straight through to the preprocessor ๐Ÿš€ If option has commas, it gets split into multiple options at the commas. BUT ๐Ÿšจ a lot of options get modified, translated or interpreted by the driver before they reach the preprocessor, and -Wp forcibly 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 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 need to use -Xpreprocessor twice: once for the option and once for the argument.
  • -no-integrated-cpp โ€” preprocessing gets its own separate pass before compilation ๐Ÿ”ช By default, GCC preprocesses as an integrated part of input tokenization and parsing. With this flag, the appropriate 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. It can be handy alongside the -B or -wrapper options to use an alternate preprocessor, or to do extra processing on your source between normal preprocessing and compilation ๐ŸŒˆ
  • -flarge-source-files โ€” for when your files are HUGE ๐Ÿ˜ It makes GCC expect large source files, at the cost of slower compilation and higher memory usage. Normally GCC tracks both column numbers and line numbers, and prints both in diagnostics. But once it has processed a certain number of source lines, it stops tracking column numbers and only tracks line numbers. So diagnostics for later lines don't include column numbers, and options like -Wmisleading-indentation stop working at that point, although the compiler prints a note if this happens ๐Ÿ“ Passing -flarge-source-files significantly increases the number of source lines GCC can process before it stops tracking columns ๐Ÿ’ช

โœจ 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 โ€” passes option to the assembler too ๐Ÿซง Use it for system-specific assembler options that GCC doesn't recognize. If you want to pass an option that takes an argument, you need to 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 ๐Ÿ™„

  • 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 their contents, not us ๐Ÿ•ต๏ธ) If linking is done, these object files get used as input to the linker.
  • -c, -S, -E โ€” if any of these is used, the linker doesn't run, so object file names shouldn't be used as arguments ๐Ÿšซ
  • -flinker-output=type โ€” controls code generation of the link-time optimizer ๐Ÿง  By default, the linker output is automatically determined by the linker plugin. For debugging the compiler, or if incremental linking with a non-LTO object file is desired, it may be useful to control the type manually. The options for type are:
    • exec โ€” code generation produces a static binary. In this case -fpic and -fpie are both disabled.
    • dyn โ€” code generation produces a shared library. In this case -fpic or -fPIC is preserved, but not enabled automatically. This allows building shared libraries without position-independent code on architectures where that's possible, i.e. on x86.
    • pie โ€” code generation produces an -fpie executable. This gives similar optimizations as exec, except that -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. In addition, if -ffat-lto-objects is specified, binary code is produced for future non-LTO linking. The object file produced by incremental linking is smaller than a static library produced from the same object files. At link time, the result of incremental linking also loads faster than a static library, assuming that the majority of objects in the library are used.
    • nolto-rel โ€” configures the compiler for incremental linking where code generation is forced, a final binary is produced, and the intermediate code for later link-time optimization is stripped. When multiple object files are linked together, the resulting code is better optimized than with link-time optimizations disabled (for example, cross-module inlining happens), but most of the benefits of whole program optimizations are lost.

During the incremental link (by -r) the linker plugin defaults to rel. With current interfaces to GNU Binutils, it is however not possible to incrementally link LTO objects and non-LTO objects into a single mixed object file. If any of the object files in an incremental link cannot be used for link-time optimization, the linker plugin issues a warning and uses nolto-rel. To maintain whole program optimization, it is recommended to link such objects into a static library instead. Alternatively, it is possible to use H.J. Lu's binutils with support for mixed objects ๐Ÿงฉ

  • -fuse-ld=bfd โ€” use the bfd linker instead of the default linker ๐Ÿ”ง
  • -fuse-ld=gold โ€” use the gold linker instead of the default linker โœจ
  • -fuse-ld=lld โ€” use the LLVM lld linker instead of the default linker ๐Ÿ’œ
  • -fuse-ld=mold โ€” use the Modern Linker (mold) instead of the default linker ๐ŸŽ๏ธ
  • -llibrary, -l library โ€” searches the library named library when linking. (The second form, with the library as a separate argument, is only for POSIX compliance and isn't recommended ๐Ÿ™…)

The -l option is passed directly to the linker by GCC, so refer to 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 searched include several standard system directories, plus any that you specify with -L.

Static libraries are archives of object files, and 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 linking with the shared library unless the -static option is used.

It makes a difference where in the command you write this option, because the linker searches and processes libraries and object files in the order they are specified. Thus, 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 are 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 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.

Heads up ๐Ÿšจ: these entry points should be supplied through some other mechanism when this option is specified.
  • -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 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 are 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.

The compiler may generate calls to memcmp, memset, memcpy and memmove ๐Ÿซถ. These are usually resolved by entries in libc, so bestie, when you use this flag, those entry points have to be supplied some other way ๐Ÿ˜ญ.

One of the standard libraries that -nostdlib and -nodefaultlibs bypass is libgcc.a ๐Ÿงš. It's a library of internal subroutines that GCC uses to work around shortcomings of certain machines or to meet the special needs of some languages ๐Ÿ’….

Honestly, you usually still need libgcc.a even when you're trying to skip the other standard libraries โœจ. So if you specify -nostdlib or -nodefaultlibs, you should usually add -lgcc too ๐Ÿ”ฅ. That way you have no unresolved references to internal GCC library subroutines. (An example of one of those internal subroutines 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 reads this value, 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 need to use the same compilation options you used for the build (-fpie, -fPIE, or model suboptions) when you pass this linker option โœจ.
  • -no-pie โ€” Skips making a dynamically linked position independent executable ๐Ÿ™ˆ.
  • -static-pie โ€” Makes a static position independent executable on targets that support it ๐ŸŒธ. It's kind of like a static executable, except it can be loaded at any address without a dynamic linker, which is so iconic ๐Ÿ‘‘. Same deal as before: for predictable results, use the same set of options you compiled with (-fpie, -fPIE, or model suboptions) when you use this linker option ๐Ÿ’….
  • -pthread โ€” Links with the POSIX threads library ๐Ÿงต. This one is supported on GNU/Linux targets, most other Unix derivatives, and also on x86 Cygwin and MinGW targets ๐ŸŒˆ. On some targets it also sets flags for the preprocessor, so use it consistently for both compilation and linking, periodt ๐Ÿ’–.
  • -r โ€” Produces a relocatable object as the output ๐Ÿฆ‹. This is also known as partial linking.
  • -rdynamic โ€” Passes the flag -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 ones that are used ๐Ÿ‘€. It's needed for some uses of dlopen, or if you want to get backtraces from inside a program ๐Ÿ”ฅ.
  • -s โ€” Strips all symbol table and relocation information out of the executable ๐Ÿ’€.
  • -static โ€” On systems that support dynamic linking, this overrides -pie and stops the linking with shared libraries ๐Ÿซถ. On other systems it does absolutely nothing ๐Ÿ™„.
  • -shared โ€” Makes a shared object that can then be linked with other objects to form an executable ๐ŸŽ€. Not every system supports this one. For predictable results, you also need to use the same set of compilation options (-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 the static version, respectively ๐ŸŒธ. If no shared version of libgcc was built when the compiler was configured, these options do nothing ๐Ÿ™ˆ.

There are a few situations where an application should use the shared libgcc instead of the static one ๐Ÿฆ‹. The biggest one is when the app wants to throw and catch exceptions across different shared libraries ๐Ÿ˜ญ. In that case, every one of the libraries and 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 ๐Ÿ’–. C++ programs typically use exceptions, so this is the right move, no cap โœจ.

Now, if you use the GCC driver to create shared libraries, you might notice they aren't always linked with the shared libgcc ๐Ÿค”. If GCC finds out 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 of libgcc, so it links with the static version by default ๐Ÿ’…. This lets exceptions propagate through those shared libraries without adding 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 that it's linked with the shared libgcc ๐Ÿšจ.
  • -static-libasan โ€” When -fsanitize=address 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 ๐ŸŒธ. This option tells the GCC driver to link libasan statically, without necessarily linking other libraries statically โœจ.
  • -static-libtsan โ€” When -fsanitize=thread 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 ๐Ÿ’œ. This option tells the GCC driver to link libtsan statically, without necessarily linking other libraries statically ๐Ÿฆ‹.
  • -static-liblsan โ€” When -fsanitize=leak 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 ๐Ÿ’–. This option tells the GCC driver to link liblsan statically, without necessarily linking other libraries statically ๐ŸŒท.
  • -static-libubsan โ€” When -fsanitize=undefined 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 ๐ŸŒˆ. This option tells the GCC driver to link libubsan statically, without necessarily linking other libraries statically ๐Ÿ‘‘.
  • -static-libstdc++ โ€” When the g++ program is used to link 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 of libstdc++, and that's normally fine ๐Ÿ’…. But sometimes it's useful to freeze the version of libstdc++ your program uses without going all the way to a fully static link ๐ŸงŠ. This 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 one, so it's a bit of a rare bird ๐Ÿฆœ.
  • -T script โ€” Uses script as the linker script ๐Ÿ“œ. This is supported by most systems that use the GNU linker ๐Ÿ’œ. On some targets, like bare-board targets without an operating system, you might need -T when linking to avoid references to undefined symbols ๐Ÿ™ƒ.
  • -Xlinker option โ€” Passes option along to the linker as an option ๐Ÿ”ง. Use this for system-specific linker options that GCC doesn't recognize, bestie ๐Ÿ’….

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 must write -Xlinker -assert -Xlinker definitions ๐Ÿงš. Writing -Xlinker "-assert definitions" does not work, because that passes the entire string as one single argument, and the linker is not vibing with that ๐Ÿ’€.

With the GNU linker, it's usually way more convenient to pass arguments to linker options using the option=value syntax instead of separate arguments ๐Ÿ“. For example, you can write -Xlinker -Map=output.map instead of -Xlinker -Map -Xlinker output.map โœจ. Other linkers might 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 ๐Ÿ—บ๏ธ. When you're using the GNU linker, you can 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 is undefined, which forces the linking of library modules that define it ๐ŸŽญ. You can use -u multiple times with different symbols to force loading of additional library modules ๐Ÿ’œ.
  • -z keyword โ€” -z is passed straight on 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 the 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 the details ๐ŸŒณ.

Directories specified with -iquote only apply to the quote form of the directive, #include "file" ๐Ÿ’ฌ. Directories specified with -I, -isystem, or -idirafter apply to lookups for both #include "file" and #include <file> ๐ŸŒˆ.

You can specify any number or combination of these options on the command line to search for header files in several directories at once ๐ŸŽ€. 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. ๐ŸŽ€ For the quote form of the include directive, the -iquote directories get searched left-to-right, in the same order they show up on the command line ๐Ÿ’…
  3. ๐ŸŒธ -I directories get scanned left-to-right ๐ŸŒธ
  4. ๐Ÿฆ‹ -isystem directories get scanned left-to-right ๐Ÿฆ‹
  5. ๐Ÿ›๏ธ The standard system directories get scanned ๐Ÿ›๏ธ
  6. ๐Ÿงš -idirafter directories get scanned left-to-right ๐Ÿงš

ngl, this search order is the whole vibe ๐Ÿ˜ญ You can use -I to override a system header file and swap in your own version, because those directories get searched before the standard system header file directories. BUT bestie, don't use -I to add directories that hold 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 โœจ

Lowkey the most important part: if a standard system include directory, or a directory given with -isystem, is also given with -I, the -I option gets ignored ๐Ÿ™ˆ The directory still gets searched, but as a system directory at its normal spot in the system include chain. This is so GCC's procedure for fixing buggy system headers and the ordering for the #include_next directive don't get changed by accident. If you really need to change the search order for system directories, use the -nostdinc and/or -isystem options ๐Ÿ”ฅ

  • -I- โ€” Okay, this one is deprecated ๐Ÿ’” so please don't start new stuff with it. Use -iquote instead for the -I directories that come before the -I-, then remove the -I- option.

Any directories given with -I options before -I- only get searched for headers requested with "#include "file"". They are not searched for "#include <file>". If more directories come with -I options after the -I-, those 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 is no way to override this effect of -I- ๐Ÿ™ƒ

  • -iprefix prefix โ€” Set prefix as the prefix for the later -iwithprefix options ๐Ÿ“ If the prefix represents a directory, make sure you 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, and -iwithprefix puts it where -idirafter would.
  • -isysroot dir โ€” This is like the --sysroot option, but it only applies to header files ๐ŸŒˆ (Except on 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 โ€” Don't search the standard system directories for header files ๐Ÿ™… Only the directories you explicitly give with -I, -iquote, -isystem, and/or -idirafter get searched, plus the directory of the current file if it applies.
  • -nostdinc++ โ€” Skip the C++-specific standard directories when looking for headers, but still search the other standard directories ๐Ÿฆ‹ (This one is used when building the C++ library.)
  • -iplugindir=dir โ€” Sets the directory to search for plugins that get passed with -fplugin=name, instead of -fplugin=path/name.so. This isn't meant for you to use directly. It's only passed along by the driver ๐Ÿค–
  • -Ldir โ€” Add dir to the list of directories 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 to be run, the driver first tries the -B prefix, if there is one. If that name isn't found, or if -B isn't specified, the driver tries two standard prefixes, /usr/lib/gcc/ and /usr/local/lib/gcc/. If neither of those turns up a file, the unmodified program name is searched for using the directories in your PATH environment variable.

The compiler checks to see if the path given by -B refers to a directory, and if needed it adds a directory separator character at 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 are tried, and that is all. The file is left out of the link if it isn't found by those means.

Another way to specify a prefix that works much like the -B prefix is to use 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 โ€” Don't 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 searches dir/usr/include and dir/usr/lib instead.

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 aspect of --sysroot still works, but the library aspect doesn't.

  • --no-sysroot-suffix โ€” For some targets, a suffix gets added to the root directory given with --sysroot, depending on the other options 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 table 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 one 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 the reuse only for user-defined local variables with names, and none disables stack reuse completely. The default value is all.

This 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 the 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 doesn't overlap with it. Legacy code that extends 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 the 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 doesn't overlap with it. However, some legacy code relies on the behavior of older compilers, where temporaries' stack space is not reused, so 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 โ€” bestie, this one tells the compiler to just assume signed addition, subtraction, and multiplication overflow wraps around using twos-complement representation ๐Ÿ”„โœจ. It turns on some optimizations and turns off others. -ftrapv and -fwrapv are beefing with each other, so -ftrapv -fwrapv means -fwrapv wins ๐Ÿ‘‘. Only the active options fight, though, so -ftrapv -fwrapv -fno-wrapv gives you -ftrapv ๐Ÿ’….
  • -fwrapv-pointer โ€” same energy, but for pointer arithmetic. It assumes pointer overflow on addition and subtraction wraps around using twos-complement representation ๐Ÿฆ‹. It also disables some optimizations that assume pointer overflow is invalid ๐Ÿ™ˆ.
  • -fstrict-overflow โ€” this one implies -fno-wrapv -fno-wrapv-pointer ๐Ÿ”ฅ. Flip it to the negated version and it implies -fwrapv -fwrapv-pointer instead ๐Ÿซถ.
  • -fexceptions โ€” enables exception handling and generates the extra code needed to propagate exceptions ๐ŸŽ€. Heads up: on some targets this implies GCC generates frame unwind information for all functions, which can cause significant data size overhead ๐Ÿ˜ญ. It doesn't affect execution though โœจ. By default, GCC turns this on for languages like C++ that normally need exception handling, and turns it off for languages like C that don't ๐ŸŒธ. You might still need it when compiling C code that has to play nicely 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 โ€” lets trapping instructions throw exceptions ๐Ÿ“. Real talk, this needs platform-specific runtime support that doesn't exist everywhere ๐Ÿ’€. It only lets trapping instructions throw, meaning memory references or floating-point instructions ๐Ÿฆ‹. It does not let exceptions come out of arbitrary signal handlers like "SIGALRM" ๐Ÿ™…โ€โ™€๏ธ.
  • -fdelete-dead-exceptions โ€” instructions that might throw but don't otherwise contribute to the program's execution can get optimized away ๐Ÿ—‘๏ธโœจ. This is on by default for the Ada compiler, which the Ada language spec allows ๐Ÿ‘‘. Optimization passes that remove dead exceptions are enabled separately at different optimization levels ๐Ÿ’….
  • -funwind-tables โ€” kinda like -fexceptions, except it only generates any needed static data and leaves the generated code alone ๐ŸŒˆ. You usually don't need to turn this on yourself, because any language processor that needs it will enable it for you ๐Ÿซถ.
  • -fasynchronous-unwind-tables โ€” generates an unwind table in DWARF format, as long as 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 โ€” okay so, with a recent GNU assembler and C library, the C++ compiler uses the "STB_GNU_UNIQUE" binding ๐Ÿ”—. That keeps template static data members and static local variables in inline functions unique, even with "RTLD_LOCAL" ๐Ÿ’œ. This matters because a library used by two different "RTLD_LOCAL" plugins could otherwise disagree about the binding of a symbol ๐Ÿ˜ญ. The catch is that it makes dlclose get ignored for affected DSOs ๐Ÿ™ˆ. If your program relies on reinitializing a DSO through dlclose and dlopen, use -fno-gnu-unique ๐ŸŽ€.
  • -fpcc-struct-return โ€” returns "short" "struct" and "union" values in memory, just like longer ones, instead of in registers ๐Ÿงบ. It's less efficient, but it lets GCC-compiled files play nicely with files built by other compilers, especially the Portable C Compiler (pcc) ๐Ÿซถ. The exact convention for returning structures in memory depends on the target configuration macros ๐ŸŒธ. Short structures and unions are the ones whose size and alignment match 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 whenever it can ๐Ÿš€. It's more efficient than -fpcc-struct-return for small structures ๐Ÿ’…. If you specify neither flag, GCC uses 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 pick the standard itself, and it chose the more efficient register return option ๐Ÿ†.
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 โ€” gives an "enum" type only as many bytes as it needs for its declared range of values ๐ŸŒฑ. The "enum" type ends up equivalent to the smallest integer type that has enough room ๐Ÿงฉ.
Warning: -fshort-enums makes GCC generate code that is not binary compatible with code generated without that switch. Only 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 handy for building programs that run under WINE ๐Ÿท.
Warning: -fshort-wchar makes GCC generate code that is not binary compatible with code generated without that switch. Only use it to conform to a non-default application binary interface ๐Ÿšจ.
  • -fcommon โ€” in C code, this controls where global variables defined without an initializer get placed ๐Ÿ“ฆ. Those are called tentative definitions in the C standard, and they're different from extern declarations, which don't allocate any storage ๐Ÿซง.

The default is -fno-common, which means the compiler puts uninitialized global variables in the BSS section of the object file ๐Ÿ›๏ธ. This stops the linker from merging tentative definitions, so you get a multiple-definition error if the same variable is accidentally defined in more than one compilation unit ๐Ÿ˜ค.

-fcommon puts uninitialized global variables in a common block instead ๐Ÿงฑ. That lets the linker resolve all tentative definitions of the same variable across different compilation units to the same object, or to a non-tentative definition ๐Ÿ”—. This behavior is inconsistent with C++, and on many targets it implies a speed and code size penalty on global variable references ๐Ÿข. It's mainly useful for getting legacy code to link without errors ๐Ÿฅน.

  • -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 with the two halves placed far apart in memory ๐Ÿงฉ. This one is used when compiling crtstuff.c, and you shouldn't need it for anything else ๐Ÿšซ.
  • -fverbose-asm โ€” adds extra commentary to the generated assembly code so it's easier to read ๐Ÿ“–. This is generally only useful for people who actually need to read the generated assembly, like when they're debugging the compiler itself ๐Ÿง‘โ€๐Ÿ’ป.

-fno-verbose-asm, which is the default, leaves that extra info out ๐Ÿซฅ. It's handy when you want to compare 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.

Here's an example. Say you've got this C source file:

int test (int n)
{
  int i;
  int total = 0;

  for (i = 0; i < n; i++)
    total += i * i;

  return total;
}

If you compile it to (x86_64) assembly with -S and send the result straight to stdout with -o -, like this:

gcc -S test.c -fverbose-asm -Os -o -

you'll get 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...]

        .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
Heads up: the comments are meant for humans rather than machines, so the precise format of the comments is subject to change ๐Ÿซถ.
  • -frecord-gcc-switches โ€” okay so this one makes GCC stash the exact command line you used to invoke the compiler right inside the object file it's making ๐Ÿ“ผ. It's only implemented on some targets, and the exact format depends on the target and binary file format, but it usually shows up as a section full of ASCII text ๐Ÿงพ. Don't mix it up with -fverbose-asm! That one only drops info into the assembler output as comments, so it never reaches the object file ๐Ÿ™…. For another way to store compiler options in the object file, see also -grecord-gcc-switches ๐Ÿ’œ.
  • -fpic โ€” generate position-independent code (PIC) that's ready for a shared library, if the target machine supports it ๐Ÿฆ‹. This code reaches all constant addresses through a global offset table (GOT) โœจ. The dynamic loader fills in the GOT entries when the program starts (and the dynamic loader is NOT part of GCC, it's part of the operating system, bestie ๐Ÿ’…). If the GOT size for the linked executable goes over a machine-specific max, the linker throws an error saying -fpic doesn't work, so just recompile with -fPIC instead ๐Ÿ˜ญ. (The maxes are 8k on the SPARC, 28k on AArch64, and 32k on the m68k and RS/6000. The x86 has no such limit ๐Ÿ™Œ.) PIC needs special support, so it only works on certain machines. For the x86, GCC supports PIC for System V but not for the Sun 386i. Code generated for the IBM RS/6000 is always position-independent ๐ŸŒˆ. When this flag is set, the macros "__pic__" and "__PIC__" are defined to 1 โœจ.
  • -fPIC โ€” if the target machine supports it, this emits position-independent code that's suitable for dynamic linking and doesn't have any limit on the size of the global offset table ๐Ÿ‘‘. It makes a real difference on AArch64, m68k, PowerPC and SPARC ๐Ÿ”ฅ. Like before, it needs special support, so it only works on certain machines. When this flag is set, "__pic__" and "__PIC__" are defined to 2 ๐Ÿ’–.
  • -fpie, -fPIE โ€” these are giving the same vibe as -fpic and -fPIC, but the position-independent code can only be linked into executables ๐ŸŽ€. Usually you'll use these to compile code that gets linked with the -pie GCC option ๐Ÿงš. Both of them define "__pie__" and "__PIE__". The macros have the value 1 for -fpie and 2 for -fPIE ๐Ÿซถ.
  • -fno-plt โ€” no PLT for external function calls in position-independent code, bestie ๐Ÿ™…. Instead, it loads the callee address at call sites from the GOT and branches to it. This leads to more efficient code by eliminating PLT stubs and exposing GOT loads to optimizations ๐Ÿฆ‹. On architectures like 32-bit x86, where PLT stubs expect the GOT pointer in a specific register, this gives the compiler more register allocation freedom ๐Ÿ’…. Lazy binding requires the PLT, so with -fno-plt all external symbols get resolved at load time โฑ๏ธ. Alternatively, the function attribute "noplt" can be used to avoid calls through the PLT for specific external functions ๐ŸŒธ. In position-dependent code, a few targets also convert calls to functions that are marked to not use the PLT so they use the GOT instead ๐Ÿง .
  • -fno-jump-tables โ€” do not use jump tables for switch statements, even where they'd be more efficient than other code generation strategies ๐Ÿ™ˆ. This is useful alongside -fpic or -fPIC when building code that forms 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 this option isn't needed there ๐Ÿ’œ.
  • -fno-bit-tests โ€” do not use bit tests for switch statements, even where it would be more efficient than other code generation strategies ๐Ÿ“.
  • -ffixed-reg โ€” treat the register named reg as a fixed register, so generated code should never refer to it (except maybe as a stack pointer, frame pointer, or in some other fixed role) ๐Ÿ“Œ. reg must be the name of a register. The accepted register names are machine-specific and are defined in the "REGISTER_NAMES" macro in the machine description macro file ๐Ÿ—‚๏ธ. This flag has no negative form, because it's a three-way choice ๐Ÿ™ƒ.
  • -fcall-used-reg โ€” treat the register named reg as an allocable register that gets clobbered by function calls ๐ŸŒ€. It may be allocated for temporaries or variables that don't live across a call. Functions compiled this way do not save and restore the register reg ๐Ÿ˜ฌ. It is an error to use this flag with the frame pointer or stack pointer. Using it for other registers that have fixed, pervasive roles in the machine's execution model produces disastrous results ๐Ÿ’€. No negative form, because it's a three-way choice ๐Ÿ™ƒ.
  • -fcall-saved-reg โ€” treat the register named reg as an allocable register that's saved by functions ๐Ÿ›ก๏ธ. It may be allocated even for temporaries or variables that live across a call. Functions compiled this way save and restore the register reg if they use it ๐Ÿ’พ. It is an error to use this flag with the frame pointer or stack pointer. Using it on other registers with fixed, pervasive roles in the machine's execution model produces disastrous results ๐Ÿ’€. A different sort of disaster happens if you use this flag on a register where function values may be returned ๐Ÿ˜ญ. No negative form, because it's a three-way choice ๐Ÿ™ƒ.
  • -fpack-struct[=n] โ€” without a value, this packs all structure members together with no holes ๐Ÿงฑ. When you give it a value (which must be a small power of two), it packs structure members according to that value, which represents the maximum alignment. Objects with default alignment requirements larger than this get output potentially unaligned at the next fitting location ๐Ÿ“.
โš ๏ธ Warning: the -fpack-struct switch causes GCC to generate code that is not binary compatible with code generated without that switch. It also makes the code suboptimal ๐ŸŒ. Only use it to conform to a non-default application binary interface ๐Ÿซ .
  • -fleading-underscore โ€” this option and its counterpart, -fno-leading-underscore, forcibly change the way C symbols are represented in the object file ๐Ÿ”. One big use is helping you link with legacy assembly code ๐Ÿš๏ธ.
โš ๏ธ Warning: the -fleading-underscore switch causes GCC to generate code that is not binary compatible with code generated without that switch. Only use it to conform to a non-default application binary interface. Also, not all targets provide complete support for this switch ๐Ÿฅฒ.
  • -ftls-model=model โ€” change the thread-local storage model that gets used ๐Ÿงต. The model argument should be one of global-dynamic, local-dynamic, initial-exec or local-exec ๐ŸŽฏ. Heads up, the choice is subject to optimization: the compiler might use a more efficient model for symbols that aren't visible outside of the translation unit, or if -fpic isn't given on the command line โœจ. 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 small piece of code that gets created at run time on the stack when the address of a nested function is taken, and it's used to call the nested function indirectly ๐ŸŒ€. Because of that, it requires the stack to be made executable for the program to work properly ๐Ÿšจ.

-fno-trampolines is enabled by default on a language-by-language basis, so the compiler can avoid generating trampolines if it figures that's safe, and swap them out for descriptors instead ๐Ÿง . Descriptors are made up of data only, but the generated code has to be prepared to deal with them ๐Ÿงฉ. As of this writing, -fno-trampolines is enabled by default only for Ada ๐Ÿ‘‘. Also, code compiled with -ftrampolines and code compiled with -fno-trampolines are not binary compatible if nested functions are present ๐Ÿ˜ต. This option must be used on a program-wide basis and handled with extreme care ๐Ÿซฃ.

  • -fvisibility=[default|internal|hidden|protected] โ€” this sets the default ELF image symbol visibility to the option you pick. All symbols get marked with it unless they're overridden within the code ๐Ÿ”ฎ. Using this can substantially improve linking and load times of shared object libraries, produce more optimized code, give you near-perfect API export, and prevent symbol clashes ๐ŸคŒ. It's strongly recommended that you use this in any shared objects you distribute ๐Ÿ’œ.

Despite the nomenclature, default always means public, i.e., available to be linked against from outside the shared object ๐ŸŒˆ. protected and internal are pretty useless in real-world usage, so the only other commonly used option is hidden ๐Ÿ™„. The default if -fvisibility isn't specified is default, i.e., every symbol is made public ๐ŸŒŸ. For a good explanation of the benefits of making sure ELF symbols have the correct visibility, check out "How To Write Shared Libraries" by Ulrich Drepper (which can be found at <https://www.akkadia.org/drepper/>) ๐Ÿ“š. A superior solution this option makes possible, compared to marking things hidden when the default is public, is to make the default hidden and mark things public instead ๐ŸŽ€. That's the norm with DLLs on Windows. With -fvisibility=hidden and "__attribute__ ((visibility("default")))" used instead of "__declspec(dllexport)", you get almost identical semantics with identical syntax ๐Ÿซถ. This is a total great boon for anyone working on cross-platform projects ๐Ÿฆ‹โœจ

For anyone adding visibility to code that already exists ๐Ÿงš, #pragma GCC visibility is your friend โœจ. You wrap the declarations you care about in #pragma GCC visibility push(hidden) and close it with #pragma GCC visibility pop ๐Ÿ’…. Real talk: symbol visibility is part of the API interface contract, so all new code should spell out its visibility whenever it isn't the default ๐Ÿซถ. Declarations that only get used inside the local DSO should always be marked explicitly as hidden, which dodges PLT indirection overheads ๐Ÿ™ˆ. Writing it out this clearly also makes the code way more readable and self-documenting ๐Ÿ’–. Also, thanks to ISO C++ spec requirements, operator new and operator delete must always have default visibility ๐Ÿ”ฅ.

Be careful with headers from outside your project, especially system headers and headers from any other library you use ๐Ÿ‘€. They may not be expecting to be compiled with visibility other than the default. You might need to say #pragma GCC visibility push(default) before including any of them ๐ŸŒธ.

extern declarations aren't affected by -fvisibility, so a lot of code can be recompiled with -fvisibility=hidden with zero modifications ๐Ÿฆ‹. The catch is that 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 that the type_info nodes are unified between the DSOs ๐Ÿ˜ญ.

If you want the full tea on these techniques, their benefits and how to use them, check out <http://gcc.gnu.org/wiki/Visibility> ๐ŸŒˆ.


โœจ -fstrict-volatile-bitfields โœจ

Use this one when accesses to volatile bit-fields (or other structure fields, though the compiler usually honors those types anyway) should be a single access at the width of the field's type, aligned to a natural alignment if possible ๐Ÿ’–. For example, targets with memory-mapped peripheral registers might require 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 to use 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 previous example, that might be a 32-bit load instruction, even though it touches bytes that don't contain any part of the bit-field, 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 a single read or write that's correctly aligned for the target machine ๐Ÿ™ˆ. In that case GCC falls back to generating multiple accesses, instead of code that would fault or truncate the result at run time. Safe and sound ๐Ÿซถ.

Note: Due to restrictions of the C/C++11 memory model, write accesses are not allowed to touch non bit-field members ๐Ÿ˜ญ. It's therefore 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 this 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 of interest to GCC developers ๐Ÿง‘โ€๐Ÿ’ป. That includes options that support compiler testing and investigation of compiler bugs and compile-time performance problems ๐Ÿ”. It also covers options that produce debug dumps at various points in compilation, 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 ๐Ÿ“š. You should rarely need any of these for ordinary compilation and linking tasks ๐Ÿ™ˆ.

Lots of developer options that make GCC dump output to a file take an optional =filename suffix โœจ. You can specify stdout or - to dump to standard output, and stderr for standard error ๐Ÿ’….

If =filename is omitted, a default dump file name gets built by concatenating 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 the compiler produces, if you explicitly specified one and it isn't an executable. Otherwise, it's the source file name ๐Ÿ“. The pass number is determined by the order passes are registered with the compiler's pass manager ๐Ÿ”ข. That's usually the same as the execution order, but passes registered by plugins, target-specific passes, or passes that get registered late are numbered higher than the pass named final, even if they 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 ๐Ÿ’–.

โœจ -fcallgraph-info โœจ

โœจ -fcallgraph-info=MARKERS โœจ

This makes the compiler output callgraph information for the program, on a per-object-file basis ๐Ÿ•ธ๏ธ. The info is generated in the common VCG format. You can decorate it with extra per-node and/or per-edge info by adding a list of comma-separated markers ๐Ÿ’œ. When the su marker is specified, the callgraph gets decorated with stack usage info, which is equivalent to -fstack-usage ๐Ÿฅž. When the da marker is specified, the callgraph gets decorated with info about dynamically allocated objects ๐Ÿง .

When you compile with -flto, no callgraph info is output along with the object file ๐Ÿ™…โ€โ™€๏ธ. At LTO link time, -fcallgraph-info may generate multiple callgraph info files right next to the intermediate LTO output files ๐Ÿ“‚.

โœจ -dletters, -fdump-rtl-pass, -fdump-rtl-pass=filename โœจ

Okay, this is the debugging dump zone ๐Ÿ”ฌ. These make debugging dumps during compilation at times specified by letters. They're used for debugging the RTL-based passes of the compiler ๐Ÿงช.

Some -dletters switches mean something different when -E is used for preprocessing ๐Ÿ™ˆ.

You can enable debug dumps with a -fdump-rtl switch or with some -d option letters ๐ŸŽ€. Here are the possible letters you can use in pass and letters, and what they mean ๐Ÿ‘‡:

  • -fdump-rtl-alignments โ€” Dump after branch alignments have been computed. ๐Ÿ“
  • -fdump-rtl-asmcons โ€” Dump after fixing rtl statements that have unsatisfied in/out constraints. ๐Ÿงท
  • -fdump-rtl-auto_inc_dec โ€” Dump after auto-inc-dec discovery. This pass only runs on architectures that have auto inc or auto dec instructions. โšก
  • -fdump-rtl-barriers โ€” Dump after cleaning up the barrier instructions. ๐Ÿงน
  • -fdump-rtl-bbpart โ€” Dump after partitioning hot and cold basic blocks. ๐Ÿ”ฅโ„๏ธ
  • -fdump-rtl-bbro โ€” Dump after block reordering. ๐Ÿ”€
  • -fdump-rtl-btl1, -fdump-rtl-btl2 โ€” These enable dumping after the two branch target load optimization passes. ๐ŸŽฏ
  • -fdump-rtl-bypass โ€” Dump after jump bypassing and control flow optimizations. ๐Ÿฆ˜
  • -fdump-rtl-combine โ€” Dump after the RTL instruction combination pass. ๐Ÿงƒ
  • -fdump-rtl-compgotos โ€” Dump after duplicating the computed gotos. ๐Ÿ‘ฏโ€โ™€๏ธ
  • -fdump-rtl-ce1, -fdump-rtl-ce2, -fdump-rtl-ce3 โ€” These enable dumping after the three if conversion passes. ๐Ÿ”
  • -fdump-rtl-cprop_hardreg โ€” Dump after hard register copy propagation. ๐Ÿ“‹
  • -fdump-rtl-csa โ€” Dump after combining stack adjustments. ๐Ÿฅž
  • -fdump-rtl-cse1, -fdump-rtl-cse2 โ€” These enable dumping after the two common subexpression elimination passes. ๐Ÿซง
  • -fdump-rtl-dce โ€” Dump after the standalone dead code elimination passes. ๐Ÿ—‘๏ธ
  • -fdump-rtl-dbr โ€” Dump after delayed branch scheduling. โณ
  • -fdump-rtl-dce1, -fdump-rtl-dce2 โ€” These enable dumping after the two dead store elimination passes. ๐Ÿ’…
  • -fdump-rtl-eh โ€” Dump after finalization of EH handling code. ๐Ÿ›Ÿ
  • -fdump-rtl-eh_ranges โ€” Dump after conversion of EH handling range regions. ๐Ÿ—บ๏ธ
  • -fdump-rtl-expand โ€” Dump after RTL generation. ๐ŸŒฑ
  • -fdump-rtl-fwprop1, -fdump-rtl-fwprop2 โ€” These enable dumping after the two forward propagation passes. โžก๏ธ
  • -fdump-rtl-gcse1, -fdump-rtl-gcse2 โ€” These enable dumping after global common subexpression elimination. ๐ŸŒ
  • -fdump-rtl-init-regs โ€” Dump after the initialization of the registers. ๐Ÿ
  • -fdump-rtl-initvals โ€” Dump after the computation of the initial value sets. ๐Ÿงฎ
  • -fdump-rtl-into_cfglayout โ€” Dump after converting to cfglayout mode. ๐Ÿงญ
  • -fdump-rtl-ira โ€” Dump after iterated register allocation. ๐Ÿ—‚๏ธ
  • -fdump-rtl-jump โ€” Dump after the second jump optimization. ๐Ÿฆ˜
  • -fdump-rtl-loop2 โ€” This enables dumping after the rtl loop optimization passes. ๐Ÿ”„
  • -fdump-rtl-mach โ€” Dump after performing the machine dependent reorganization pass, if that pass exists. ๐Ÿ› ๏ธ
  • -fdump-rtl-mode_sw โ€” Dump after removing redundant mode switches. ๐Ÿ”€
  • -fdump-rtl-rnreg โ€” Dump after register renumbering. ๐Ÿ”ข
  • -fdump-rtl-outof_cfglayout โ€” Dump after converting from cfglayout mode. ๐Ÿงญ
  • -fdump-rtl-peephole2 โ€” Dump after the peephole pass. ๐Ÿ”
  • -fdump-rtl-postreload โ€” Dump after post-reload optimizations. ๐Ÿš€
  • -fdump-rtl-pro_and_epilogue โ€” Dump after generating the function prologues and epilogues. ๐ŸŽฌ
  • -fdump-rtl-sched1, -fdump-rtl-sched2 โ€” These enable dumping after the basic block scheduling passes. ๐Ÿ—“๏ธ
  • -fdump-rtl-ree โ€” okay bestie, this one dumps after sign/zero extension elimination ๐Ÿงนโœจ
  • -fdump-rtl-seqabstr โ€” dumps after common sequence discovery ๐Ÿ”๐Ÿ’–
  • -fdump-rtl-shorten โ€” dumps after shortening branches ๐Ÿฆ‹
  • -fdump-rtl-sibling โ€” dumps after sibling call optimizations ๐ŸŒธ
  • -fdump-rtl-split1, -fdump-rtl-split2, -fdump-rtl-split3, -fdump-rtl-split4, -fdump-rtl-split5 โ€” these five are giving "do it five times" energy ๐Ÿ” each one turns on a dump after one of five rounds of instruction splitting ๐Ÿ‘‘
  • -fdump-rtl-sms โ€” dumps after modulo scheduling ๐Ÿงš this pass is only run on some architectures, so don't be shocked if it's missing on yours
  • -fdump-rtl-stack โ€” dumps after converting GCC's "flat register file" registers into the x87's stack-like registers ๐Ÿ’… this pass is only run on x86 variants
  • -fdump-rtl-subreg1, -fdump-rtl-subreg2 โ€” these two enable dumping after the two subreg expansion passes ๐Ÿซถ
  • -fdump-rtl-unshare โ€” dumps after all rtl has been unshared ๐Ÿ“
  • -fdump-rtl-vartrack โ€” dumps after variable tracking ๐Ÿ“ˆ
  • -fdump-rtl-vregs โ€” dumps after converting virtual registers 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 are defined but they always produce empty files ๐Ÿ’€
Heads up, bestie: those five always produce empty files, so don't panic when you open one and it's giving nothing ๐Ÿ˜ญ
  • -da, -fdump-rtl-all โ€” produce all the dumps listed above ๐ŸŽ€
  • -dA โ€” annotates the assembler output with miscellaneous debugging information ๐Ÿง
  • -dD โ€” dumps all macro definitions at the end of preprocessing, in addition to the normal output ๐Ÿ“œ
  • -dH โ€” produces a core dump whenever an error occurs ๐Ÿ’ฅ
  • -dp โ€” annotates the assembler output with a comment indicating 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 โœจ it 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 information generated during the debug generation phase ๐Ÿž
  • -fdump-earlydebug โ€” dumps the debugging information generated during the early debug generation phase โฐ
  • -fdump-noaddr โ€” when doing debugging dumps, suppresses address output ๐Ÿ™ˆ this makes it way more feasible to diff debugging dumps for compiler invocations with different compiler binaries and/or different text / bss / data / heap / stack / dso start locations
  • -freport-bug โ€” collects and dumps debug information into a temporary file if an internal compiler error (ICE) occurs ๐Ÿšจ
  • -fdump-unnumbered โ€” when doing debugging dumps, suppresses instruction numbers and address output ๐Ÿ”ข this makes diffing dumps way easier for invocations with different options, especially 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 โ€” these control the dumping at various stages of inter-procedural analysis language tree to a file ๐Ÿ—‚๏ธ the file name is generated by appending a switch specific suffix to the source file name, and the file is 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 โ€” dumps language-specific information ๐ŸŒท the file name is made by appending .lang to the source file name
  • -fdump-lang-all, -fdump-lang-switch, -fdump-lang-switch-options, -fdump-lang-switch-options=filename โ€” these control the dumping of language-specific information ๐Ÿ’– the options and filename parts behave as described in the -fdump-tree option. the accepted switch values are:
    • all โ€” enables all language-specific dumps
    • class โ€” dumps class hierarchy information. virtual table information is emitted unless 'slim' is specified. this one is C++ only ๐Ÿ‘‘
    • module โ€” dumps module information. the options lineno (locations), graph (reachability), blocks (clusters), uid (serialization), alias (mergeable), asmname (Elrond), eh (mapper) & vops (macros) may provide additional information. this one is C++ only ๐Ÿง
    • raw โ€” dumps the raw internal tree data. this one is C++ only ๐Ÿชต
  • -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 generated by appending a suffix ending in .statistics to the source file name, and the file is created in the same directory as the output file. if the -option form is used, -stats causes counters to be summed over the whole compilation unit while -details dumps every event as the passes generate them. the default with no option is to sum counters for each function compiled.
  • -fdump-tree-all, -fdump-tree-switch, -fdump-tree-switch-options, -fdump-tree-switch-options=filename โ€” these control the 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 all options are applicable to all dumps, and the ones that aren't meaningful get ignored. the following options are available:
    • address โ€” prints the address of each node ๐Ÿ“ usually this isn't meaningful, since it changes according to the environment and source file. its main use is tying up a dump file with a debug environment
    • asmname โ€” if "DECL_ASSEMBLER_NAME" has been set for a given decl, that gets used in the dump instead of "DECL_NAME" ๐Ÿ”ฎ its main use is working backward from mangled names in the assembly file
    • slim โ€” when dumping front-end intermediate representations, inhibits dumping of members of a scope or body of a function merely 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 option inhibits dumping the bodies of control structures
      • when dumping RTL, the RTL is printed 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 to find the dump for a pass you're after, follow the steps below ๐Ÿ•ต๏ธโ€โ™€๏ธ

  1. Invoke GCC with -fdump-passes, then look in the stderr output for a code that matches the pass you're interested in. for example, the codes "tree-evrp", "tree-vrp1", and "tree-vrp2" correspond to the three Value Range Propagation passes. the number at the end distinguishes distinct invocations of the same pass ๐Ÿ”
  2. To enable the 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 -fdump-tree-evrp. optionally, you may specify the name of the dump file. if you don't specify one, GCC creates one as described below ๐Ÿ’…
  3. Hunt down the pass dump in a file named with three bits joined by periods: the source file GCC was invoked to compile, then a numeric suffix for the pass number with a t for tree passes (or an r for RTL passes), then 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. Heads up, bestie: those numeric codes are not stable and can change from one GCC version to another ๐Ÿ’€

โœจ OPTIONS โœจ

  • -fopt-info, -fopt-info-options, -fopt-info-options=filename โ€” optimization dump central ๐Ÿฆ‹ These control dumps from the various optimization passes. If you use the -options form, options is a list of --separated keywords that pick the dump details and which optimizations you want.

The options come in three groups, and you can mix and match within each group since they don't overlap. If there's a clash, the later option on the command line wins ๐Ÿ‘‘

  1. Options that describe what kinds of messages get emitted
  2. Options that describe how verbose the dump is
  3. Options that describe which optimizations get included

Message kinds (group 1) ๐Ÿ’–

  • optimized โ€” successful glow-ups! Prints info whenever an optimization gets applied. Each pass decides what's relevant. The vectorizer, for example, prints the source location of loops that got successfully vectorized.
  • missed โ€” Info about optimizations that didn't happen. Each pass picks what goes in here ๐Ÿ™ˆ
  • note โ€” Verbose stuff about optimizations, like certain transformations and more detailed messages about decisions โœจ
  • all โ€” The full tea โ˜• Detailed optimization info, which includes optimized, missed, and note.

Verbosity (group 2) ๐Ÿงš

  • internals โ€” By default you only get the "high-level" messages. This one unlocks extra, more detailed messages that are mostly for GCC developers. Not for the faint of heart ๐Ÿ’€

Optimization groups (group 3) ๐ŸŒˆ You can use one or more of these keywords to target a whole group of optimizations:

  • ipa โ€” Dumps from all interprocedural optimizations.
  • loop โ€” Dumps from all loop optimizations.
  • inline โ€” Dumps from all inlining optimizations.
  • omp โ€” Dumps from all OMP (Offloading and Multi Processing) optimizations.
  • vec โ€” Dumps from all vectorization optimizations.
  • optall โ€” Dumps from literally every optimization. It's a superset of the groups above, so it's giving everything ๐Ÿ’…

If options is left out, it defaults to optimized-optall. That means you get messages about successful optimizations from all the passes, minus anything treated as "internals" ๐ŸŽ€

If you pass a filename, the dumps from all the applicable optimizations get concatenated into that file. Otherwise, the dump goes to stderr. You can throw in multiple -fopt-info options, but only one of them can carry a filename. If you give other filenames, all but the first such option get ignored ๐Ÿฅบ

Heads up: the output filename gets overwritten when you have multiple translation units. If you want one combined output from several translation units, use stderr instead!

Here's the vibe check with examples. First, the optimization info goes to stderr:

gcc -O3 -fopt-info

This one dumps 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 on stderr. Note that -fopt-info-vec-missed is equivalent to -fopt-info-missed-vec. The order of the optimization group names and message types after -fopt-info does not matter, so slay however you like ๐Ÿ’–

gcc -O2 -ftree-vectorize -fopt-info-vec-missed

Another one, which outputs info about missed optimizations and optimized locations from all the inlining passes into inline.txt:

gcc -O3 -fopt-info-inline-optimized-missed=inline.txt

Finally, consider this one ๐Ÿ™ˆ

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. Only the first option takes effect and the rest get ignored. So you only end up with vec.miss, which has the vectorizer's dumps about missed opportunities. Not me being chaotic, the compiler just be like that ๐Ÿ˜ญ


  • -fsave-optimization-record โ€” the machine-readable receipts ๐Ÿงพ This writes a SRCFILE.opt-record.json.gz file detailing which optimizations were performed, for the ones that support -fopt-info.
Sis, this option is experimental, and the format of the data inside the compressed JSON file is subject to change. Don't build your whole life on it yet ๐Ÿ’€

It's roughly the machine-readable version of -fopt-info-all, as a collection of messages with source file, line number, and column number. Each message also gets this extra data:

  • the execution count of the code being optimized, plus metadata about whether it came from actual profile data or was just an estimate, so consumers can prioritize messages by code hotness ๐Ÿ”ฅ
  • the function name of the code being optimized, where that applies
  • the "inlining chain" for the code being optimized, so when a function gets inlined into several places (which might themselves be inlined), you can tell the copies apart ๐Ÿชž
  • objects identifying the parts of the message that refer to expressions, statements, or symbol-table nodes, which of those categories they are, and, when available, their source code location
  • the GCC pass that emitted the message
  • the location in GCC's own code where the message came from

Also, some messages are logically nested inside other messages, reflecting implementation details of the optimization passes ๐Ÿงš

  • -fsched-verbose=n โ€” scheduler tea, served hot โ˜• On targets that use instruction scheduling, this controls how much debugging output the scheduler dumps into the dump files.

For n greater than zero, -fsched-verbose outputs the same info 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 the RTL at the abort point, plus control-flow and regions info. And for n over four, -fsched-verbose also includes dependence info. Iconic levels, honestly ๐Ÿ‘‘

  • -fenable-kind-pass, -fdisable-kind-pass=range-list โ€” the pass on/off switches ๐Ÿ”Œ This is a set of options for explicitly disabling and enabling optimization passes. They're meant for debugging GCC itself. If you're just a regular compiler user, stick with the regular options for enabling and disabling passes instead ๐Ÿ™ˆ

Here's the full menu:

  • -fdisable-ipa-pass โ€” Disables the IPA pass pass, where pass is the pass name. If the same pass gets statically invoked in the compiler multiple times, append a sequential number to the pass name, starting from 1.
  • -fdisable-rtl-pass, -fdisable-rtl-pass=range-list โ€” Disables the RTL pass pass, where pass is the pass name. Same deal with the sequential number if the pass runs more than once. 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 a function's call graph node uid falls within one of the specified ranges, the pass gets disabled for that function. The uid shows up in the function header of a dump file, and you can dump the pass names using -fdump-passes.
  • -fdisable-tree-pass, -fdisable-tree-pass=range-list โ€” Disables the tree pass pass. Check -fdisable-rtl-pass for how the option arguments work.
  • -fenable-ipa-pass โ€” Enables the IPA pass pass, where pass is the pass name. Same sequential numbering rule as above, starting from 1.
  • -fenable-rtl-pass, -fenable-rtl-pass=range-list โ€” Enables the RTL pass pass. Check -fdisable-rtl-pass for the option argument description and examples.
  • -fenable-tree-pass, -fenable-tree-pass=range-list โ€” Enables the tree pass pass. Check -fdisable-rtl-pass for how the option arguments work.

Here are some examples of 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 โ€” internal vibe checks ๐Ÿ” Enables internal consistency checking. The default depends on how the compiler was configured. -fchecking=2 turns on further internal consistency checking that might affect code generation.
  • -frandom-seed=string โ€” the reproducibility queen ๐ŸŒธ This gives GCC a seed to use in place of random numbers when it generates 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 in the object files that produce them. Use -frandom-seed to produce reproducibly identical object files, which is honestly so main character ๐Ÿซถ

The string can be a number (decimal, octal, or hex) or an arbitrary string. If it's an arbitrary string, it gets converted to a number by computing CRC32 โœจ

The string should be totally different for every file you compile, bestie ๐ŸŽ€ no copy-pasting the same one everywhere!

  • -save-temps โ€” okay so this one keeps the usual "temporary" intermediate files around permanently ๐Ÿ’พ Instead of tossing them, they get named as auxiliary output files, the same way described under -dumpbase and -dumpdir.

Pairing -save-temps with the -x command-line option is lowkey genius ๐Ÿง  It won't overwrite an input source file that shares an extension with an intermediate file. If you want that intermediate file, just rename the source file before using -save-temps.

  • -save-temps=cwd โ€” same energy as -save-temps -dumpdir ./. ๐Ÿ“
-save-temps -dumpdir ./.
  • -save-temps=obj โ€” this one puts everything in the output file's folder ๐Ÿฆ‹ It's equivalent to -save-temps -dumpdir outdir/, where outdir/ is the directory of the output file given after the -o option, including any directory separators. No -o? Then it acts exactly like -save-temps=cwd.
  • -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).

Without an output file, you get something 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 is the "system time", the time spent in operating system routines on the program's behalf. Both numbers are in seconds ๐Ÿซถ

With an output file, the report gets appended to that file and looks like this:

0.12 0.01 cc1 <options>
0.00 0.01 as <options>

Now the "user time" and "system time" get moved before the program name, and the options passed to the program are shown too. That way you can totally tell later which file was being compiled and with which options ๐Ÿ•ต๏ธโ€โ™€๏ธ

  • -fdump-final-insns[=file] โ€” dumps the final internal representation (RTL) to file ๐Ÿงฉ If the optional argument is left out (or file is "."), the dump file gets named by slapping ".gkd" onto the dump base name. See -dumpbase for the deets.
  • -fcompare-debug[=opts] โ€” this one is a whole vibe ๐Ÿ” If there's no error during compilation, the compiler runs a second time, adding opts and -fcompare-debug-second to the arguments for that second go. It dumps the final internal representation in both compilations and prints an error if they differ.

If you skip 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 set 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 no opts, is the same as -fno-compare-debug. That turns off the dumping of the final representation and the second compilation, and it even stops GCC_COMPARE_DEBUG from taking effect ๐Ÿ™…โ€โ™€๏ธ

To verify full coverage during -fcompare-debug testing, set GCC_COMPARE_DEBUG to say -fcompare-debug-not-overridden. GCC rejects that as an invalid option in any actual compilation (rather than preprocessing, assembly or linking), so it's a whole thing. If you only want a warning, setting GCC_COMPARE_DEBUG to -w%n-fcompare-debug not overridden will do the trick โš ๏ธ
  • -fcompare-debug-second โ€” this gets passed to the compiler implicitly for the second compilation requested by -fcompare-debug ๐Ÿฅ‚ It comes along with options to silence warnings, and it leaves out any other options that would make the compiler produce output to files or to standard output as a side effect. Dump files and preserved temporary files get renamed to include the ".gk" additional extension during that second compilation, so they don't overwrite the ones from the first run.

When you pass this option to the compiler driver, it skips the first compilation entirely. Honestly, that makes it pretty much only useful for debugging the compiler proper ๐Ÿค“

  • -gtoggle โ€” turns off debug info generation if leaving this option out would generate it, or turns it on at level 2 otherwise ๐Ÿ”„ Where it sits 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 give 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 consumed by each pass when it's done โณ
  • -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 gets sent to stderr, using the same format as n minus 10.
  • -flto-report โ€” prints a report with internal details on how the link-time optimizer is working ๐Ÿง The contents change from version to version. It's meant to be useful to GCC developers when processing object files in LTO mode (via -flto).

It's disabled by default, so you have to ask for it ๐Ÿ™‹โ€โ™€๏ธ

  • -flto-report-wpa โ€” same as -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 either 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 information for the program, on a per-function basis ๐Ÿฅž The filename for the dump is made by appending .su to the auxname. The auxname comes from the name of the output file, 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 manipulates 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 happen in the function. The second field is that fixed number of bytes.

The "dynamic" qualifier means the function manipulates the stack dynamically ๐ŸŒ€ On top of the static allocation, stack adjustments happen in the body of the function, for example to push and pop arguments around function calls. If "bounded" is also present, the amount of those adjustments is bounded at compile time, and the second field is an upper bound on the total amount of stack the function uses. If "bounded" isn't there, the amount of 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 the compilation ๐Ÿ“‰ Only the C++ front end supports this, and the info is generally only really 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_bound1-upper_bound1 [:lower_bound2-upper_bound2...] tuples. Each one sets the counter's name and a list of closed intervals. The lower_bound is optional and gets zero initialized if it isn't set.

For example, with -fdbg-cnt=dce:2-4:10-11,tail_call:10, dbg_cnt(dce) returns true only for the second, third, fourth, tenth and eleventh invocation โœจ And 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 ๐Ÿ“‚ That 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 @ instead of -, with no spaces between multiple switches, which is meant 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 are in the lib subdirectory and no multilibs are used, this is usually just .. If they're in libsuffix sibling directories, it prints something like ../lib64, ../lib or ../lib32. If they're in lib/subdir subdirectories, it prints something 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, instead ๐Ÿ”Ž
  • -print-libgcc-file-name โ€” same as -print-file-name=libgcc.a ๐ŸŒŸ

This one is clutch when you use -nostdlib or -nodefaultlibs but still want to link with libgcc.a ๐Ÿ’œ You can do something like this:

gcc -nostdlib <files>... `gcc -print-libgcc-file-name`
  • -print-search-dirs โ€” prints the name of the configured installation directory, plus a list of the program and library directories gcc searches, and then stops there ๐Ÿ—ƒ๏ธ

Okay so this bit is SO important when gcc starts yelling installation problem, cannot exec cpp0: No such file or directory ๐Ÿ˜ญ There are two ways to fix it, bestie: either put cpp0 and the other compiler components exactly where gcc expects to find them, or set the environment variable GCC_EXEC_PREFIX to the directory where you installed them ๐Ÿซถ And don't forget the trailing /! ๐Ÿ’…

  • -print-sysroot โ€” Prints the target sysroot directory that gets used during compilation ๐Ÿ—บ๏ธ That's the one set at configure time or with the --sysroot option, possibly with an extra suffix depending on your compilation options. No target sysroot? It prints nothing ๐Ÿ™ˆ
  • -print-sysroot-headers-suffix โ€” Prints the suffix tacked onto the target sysroot when gcc is hunting for headers. If the compiler wasn't configured with one, it throws an error instead. Either way, it doesn't do anything else ๐Ÿซ 
  • -dumpmachine โ€” Prints the compiler's target machine, like i686-pc-linux-gnu, and then stops right there ๐Ÿงš
  • -dumpversion โ€” Prints the compiler version, like 3.0, 6.3.0 or 7, and then stops ๐Ÿ’– This is the version used in filesystem paths and specs. Depending on how the compiler was configured, it can be one number (major version), two numbers separated by a dot (major and minor version), or three numbers separated by dots (major, minor and patchlevel version).
  • -dumpfullversion โ€” Prints the full compiler version and nothing else โœจ The output is always three numbers separated by dots: major, minor and patchlevel version.
  • -dumpspecs โ€” Prints the compiler's built-in specs and nothing else ๐ŸŒธ (This is only used when GCC itself is being built.)

๐Ÿฆ‹ Machine-Dependent Options ๐Ÿฆ‹

Every target machine GCC supports can have its own options, bestie ๐Ÿ’œ Think: compiling for a particular processor variant or ABI, or tweaking optimizations that are specific to that machine. By convention, the names of machine-specific options start with -m ๐ŸŽ€

Some configurations also support extra target-specific options, usually so they can play nicely 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 valid values are ilp32, a SysV-like model where int, long int and pointers are 32 bits, and lp64, a SysV-like model where int is 32 bits but long int and pointers are 64 bits. The default depends on your specific target configuration. Heads up, bestie: the LP64 and ILP32 ABIs are not link-compatible ๐Ÿ˜ญ You have to compile your entire program with the same ABI and link it against 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 โ€” Only uses the general-purpose registers ๐Ÿ’… This stops the compiler from touching the 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 must 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 must be within 4GB of each other. Programs can be statically or dynamically linked. This is the default code model.
  • -mcmodel=large โ€” Generates code for the large code model ๐ŸŒŒ It makes no assumptions about addresses and sizes of sections. Programs can only be statically linked. Also, -mcmodel=large is incompatible with -mabi=ilp32, -fpic and -fPIC ๐Ÿšซ
  • -mstrict-align, -mno-strict-align โ€” Avoid or allow 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 โ€” Omit or keep the frame pointer in leaf functions ๐Ÿƒ The former behavior is the default.
  • -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 sysreg for a canary in an appropriate system register. With the sysreg choice, -mstack-protector-guard-reg=reg and -mstack-protector-guard-offset=offset pick which system register is used as the base register for reading the canary, and what offset from that base register to use. There's no default register or offset, because 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.
  • -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. This option requires binutils 2.26 or newer ๐Ÿ”ง
  • -mfix-cortex-a53-835769, -mno-fix-cortex-a53-835769 โ€” Enables or disables the workaround for ARM Cortex-A53 erratum number 835769 ๐Ÿฉน This 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 done 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 has an effect if -ffast-math or -funsafe-math-optimizations is used as well. Enabling it reduces the precision of reciprocal square root results 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 used as well. Enabling it reduces the precision of square root results to about 16 bits for single precision and 32 bits for double precision. If enabled, it implies -mlow-precision-recip-sqrt.
  • -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 used as well. Enabling it reduces the precision of division results to about 16 bits for single precision and 32 bits for double precision.
  • -mtrack-speculation, -mno-track-speculation โ€” Enables or disables generating extra code to track speculative execution through conditional branches ๐Ÿ” The tracking state can then be used by the compiler when it expands 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 โš›๏ธ These helpers figure out at runtime 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 is only applicable 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. This option is on by default ๐Ÿ’…

  • -march=name โ€” Specifies the name of the target architecture and, optionally, one or more feature modifiers ๐Ÿ—๏ธ This option takes the form -march=arch{+[no]feature}*.

Here's the lowdown on the values for arch and what they turn on by default:

  • armv8-a (Armv8-A) โ€” includes by default: +fp, +simd
  • armv8.1-a (Armv8.1-A) โ€” includes by default: armv8-a, +crc, +lse, +rdma
  • armv8.2-a (Armv8.2-A) โ€” includes by default: armv8.1-a
  • armv8.3-a (Armv8.3-A) โ€” includes by default: armv8.2-a, +pauth
  • armv8.4-a (Armv8.4-A) โ€” includes by default: armv8.3-a, +flagm, +fp16fml, +dotprod
  • armv8.5-a (Armv8.5-A) โ€” includes by default: armv8.4-a, +sb, +ssbs, +predres
  • armv8.6-a (Armv8.6-A) โ€” includes by default: armv8.5-a, +bf16, +i8mm
  • armv8-r (Armv8-R) โ€” includes by default: armv8-r

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 can't 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. If you specify conflicting feature modifiers, the right-most feature wins ๐Ÿ‘‘

GCC uses name to figure out what kind of instructions it can emit when generating assembly code. If -march is specified without -mtune or -mcpu also being specified, the code is tuned to perform well across a range of target processors that implement the target architecture ๐ŸŽฏ

  • -mtune=name โ€” Specifies the name of the target processor that GCC should tune the performance of the code for ๐ŸŽ€ The permissible values are: generic, cortex-a35, cortex-a53, cortex-a55, cortex-a57, cortex-a72, cortex-a73, cortex-a75, cortex-a76, cortex-a76ae, cortex-a77, cortex-a65, cortex-a65ae, cortex-a34, cortex-a78, cortex-a78ae, cortex-a78c, ares, exynos-m1, emag, falkor, neoverse-512tvb, neoverse-e1, neoverse-n1, neoverse-n2, neoverse-v1, neoverse-v2, grace, qdf24xx, saphira, phecda, xgene1, vulcan, octeontx, octeontx81, octeontx83, octeontx2, octeontx2t98, octeontx2t96, octeontx2t93, octeontx2f95, octeontx2f95n, octeontx2f95mm, a64fx, thunderx, thunderxt88, thunderxt88p1, thunderxt81, tsv110, thunderxt83, thunderx2t99, thunderx3t110, 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, cortex-r82, cortex-x1, ampere1, ampere1a, cobalt-100 and native ๐Ÿ’–

okay so the big.LITTLE pairings are up next, bestie ๐Ÿงš these values: 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 all tell GCC to tune for a big.LITTLE system ๐Ÿ’œ

neoverse-512tvb is giving very specific energy โœจ It tells GCC to tune for Neoverse cores that (a) implement SVE and (b) have a total vector bandwidth of 512 bits per cycle. So basically, GCC is tuned for Neoverse cores that can run 4 128-bit Advanced SIMD arithmetic instructions a cycle, plus an equal number of SVE arithmetic instructions per 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 ๐Ÿฆ‹

Also, 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 does nothing ๐Ÿ’€

Where none of -mtune=, -mcpu= or -march= are specified, the code is tuned to perform well across a range of target processors ๐ŸŒˆ And this option cannot be suffixed by feature modifiers ๐Ÿ™…โ€โ™€๏ธ

  • -mcpu=name โ€” Pick the target processor, optionally with one or more feature modifiers tacked on the end ๐Ÿ’… The form is -mcpu=cpu{+[no]feature}*, and the allowed values for cpu are the same ones you get for -mtune. The allowed feature values are documented in the sub-section aarch64-feature-modifiers,,-march and -mcpu Feature Modifiers. If you throw conflicting feature modifiers at it, the right-most one wins ๐Ÿ‘‘ GCC uses name to figure out what kind of instructions it's allowed to emit when generating assembly (as if you'd used -march), and which processor to tune performance for (as if you'd used -mtune) โœจ If you use this together with -march or -mtune, those 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 ๐Ÿซถ And unless you override it with -mtune, -mcpu=neoverse-512tvb tunes code the same way as -mtune=neoverse-512tvb ๐ŸŒธ
  • -moverride=string โ€” Overrides the tuning decisions the back-end makes in response to a -mtune= switch ๐Ÿ™ˆ Heads up: the syntax, semantics, and accepted values for string are not guaranteed to stay consistent across releases. This option is only really meant for developing GCC itself ๐Ÿงš
  • -mverbose-cost-dump โ€” Turns on verbose cost model dumping in the debug dump files ๐Ÿ” This one is only here for debugging the compiler ๐Ÿ’œ
  • -mpc-relative-literal-loads, -mno-pc-relative-literal-loads โ€” Enables or disables PC-relative literal loads ๐Ÿฆ‹ With this option on, literal pools get accessed with a single instruction and are emitted after each function. The catch is that this caps the maximum size of functions at 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, so bestie, use that one instead ๐Ÿ’€
  • -mbranch-protection=none|standard|pac-ret[+leaf+b-key]|bti โ€” Picks which 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 will practically always do this) using the a-key. The optional leaf argument extends the signing to include leaf functions ๐Ÿ“ The optional b-key argument lets you sign the functions with the B-key instead of the A-key. And 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 and blr. On top of that, -mharden-sls=all enables all SLS hardening, while -mharden-sls=none disables all of it ๐Ÿ’…
  • -msve-vector-bits=bits โ€” Specifies the number of bits in an SVE vector register ๐Ÿ“ This option only does something when SVE is enabled. GCC supports two forms of SVE code generation: "vector-length agnostic" output, which works with any size of vector register, and "vector-length specific" output, which lets GCC make assumptions about the vector length when that helps with 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 for big-endian targets. All the other values generate vector-length specific code. These values might change in future releases, so no value except scalable should be relied on for code that's portable across different hardware SVE vector lengths โš ๏ธ 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 ๐Ÿ’– Here's the full list, bestie:

  • 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 -march and -mcpu
  • simd โ€” Enables Advanced SIMD instructions ๐ŸŽถ This also enables floating-point instructions. It's on by default for all possible values for -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 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 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 with architectures prior to Armv8.2-A is not supported
  • profile โ€” Enables the Statistical Profiling extension ๐Ÿ“Š This is only to turn the extension on at the assembler level, and it does not affect code generation
  • rng โ€” Enables the Armv8.5-a Random Number instructions ๐ŸŽฒ This is only to turn the extension on at the assembler level, and it does not affect code generation
  • memtag โ€” Enables the Armv8.5-a Memory Tagging Extensions ๐Ÿท๏ธ Using this with architectures prior to Armv8.5-A is not supported
  • sb โ€” Enables the Armv8-a Speculation Barrier instruction ๐Ÿšง This is only to turn the extension on at the assembler level, and it does not affect code generation. It's enabled by default for -march=armv8.5-a
  • ssbs โ€” Enables the Armv8-a Speculative Store Bypass Safe instruction ๐Ÿ›Ÿ This is only to turn the extension on at the assembler level, and it does not 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 is only to turn the extension on at the assembler level, and it does not affect code generation. It's enabled by default for -march=armv8.5-a
  • sve2 โ€” Enables the Armv8-a Scalable Vector Extension 2 ๐ŸŒŒ This also enables SVE instructions
  • sve2-bitperm โ€” Enables SVE2 bitperm instructions ๐Ÿงท This also enables SVE2 instructions
  • sve2-sm4 โ€” Enables SVE2 sm4 instructions ๐Ÿš This also enables SVE2 instructions
  • sve2-aes โ€” Enables SVE2 aes instructions ๐Ÿ—๏ธ This also enables SVE2 instructions
  • sve2-sha3 โ€” Enables SVE2 sha3 instructions ๐Ÿช„ This also enables SVE2 instructions
  • tme โ€” Enables the Transactional Memory Extension ๐Ÿงต
  • i8mm โ€” Enables 8-bit Integer Matrix Multiply instructions ๐Ÿ”ข This also enables Advanced SIMD and floating-point instructions. It's enabled by default for -march=armv8.6-a. Using this with architectures prior to Armv8.2-A is not supported ๐Ÿ™…โ€โ™€๏ธ
  • f32mm โ€” Enables 32-bit Floating point Matrix Multiply instructions ๐Ÿงฑ This also enables SVE instructions. Using this with architectures prior to Armv8.2-A is not supported
  • f64mm โ€” Enables 64-bit Floating point Matrix Multiply instructions ๐Ÿช This also enables SVE instructions. Using this with architectures prior to Armv8.2-A is not supported ๐Ÿ’œ
  • bf16 โ€” okay bestie, this one switches on brain half-precision floating-point instructions ๐Ÿง โœจ It also turns on Advanced SIMD and floating-point instructions. It's on by default for -march=armv8.6-a ๐Ÿ’…
  • flagm โ€” enables the Flag Manipulation instructions Extension ๐Ÿšฉ
  • pauth โ€” enables the Pointer Authentication Extension ๐Ÿ”
Using bf16 with architectures prior to Armv8.2-A is not supported ๐Ÿ™…โ€โ™€๏ธ

Heads up: crypto implies aes, sha2, and simd, which implies fp. Conversely, nofp implies nosimd, which implies nocrypto, noaes and nosha2 ๐Ÿซถ


๐ŸŒธ Adapteva Epiphany Options ๐ŸŒธ

These -m options are defined for Adapteva Epiphany ๐Ÿงš

  • -mhalf-reg-file โ€” we don't allocate any register in the range "r32"..."r63". That lets your code run on hardware variants that don't have these registers ๐Ÿ™ˆ
  • -mprefer-short-insn-regs โ€” prefers registers that allow short instruction generation. This can bump up the instruction count, so overall code size might go down or up ๐Ÿคทโ€โ™€๏ธ
  • -mbranch-cost=num โ€” sets the cost of branches to roughly num "simple" instructions. It's just a heuristic, so don't expect consistent results across releases ๐Ÿ’€
  • -mcmove โ€” enables the generation of conditional moves โœจ
  • -mnops=num โ€” emits num NOPs before every other generated instruction ๐Ÿ˜ด
  • -mno-soft-cmpsf โ€” for single-precision floating-point comparisons, it emits an "fsub" instruction and tests the flags. That's faster than a software comparison, but it can give incorrect results with NaNs, or when two different small numbers are compared and their difference comes out as zero ๐Ÿ˜ฌ The default is -msoft-cmpsf, which uses slower but IEEE-compliant software comparisons ๐Ÿ‘‘
  • -mstack-offset=num โ€” sets the offset between the top of the stack and the stack pointer. For example, 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. This option also changes the ABI, so compiling a program with a different stack offset than the libraries were built with generally doesn't work ๐Ÿšซ It's useful if you want to see whether a different stack offset gives you better code, but to actually build working programs, you should 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 โ€” unless an attribute says otherwise, it 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 โ€” unless an attribute says otherwise, it assumes all direct calls are in range of the "b" / "bl" instructions, so it uses those instructions 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 where -mlong-calls semantics are in effect ๐ŸŽ€
  • -mfp-mode=mode โ€” sets the prevailing mode of the floating-point unit. This decides the floating-point mode that's 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's retained or restored when the function returns and when it calls other functions. This is useful for compiling libraries or other compilation units you might want to bring into different programs with different prevailing FPU modes. The convenience of using a single object file outweighs the size and speed overhead of any extra mode switching you'd need compared to 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, 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 generally the case ๐Ÿ™ƒ
  • -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 use 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 โ€” compile for GCN3 Fiji devices (gfx803) ๐ŸŒŠ
    • gfx900 โ€” compile for GCN5 Vega 10 devices (gfx900) โญ
    • gfx906 โ€” compile for GCN5 Vega 20 devices (gfx906) ๐Ÿ‘‘
  • -msram-ecc=on, -msram-ecc=off, -msram-ecc=any โ€” compiles binaries suitable for devices with the SRAM-ECC feature enabled, disabled, or either mode. This feature can be enabled per-process on some devices. The compiled code must match the device mode. The default is any, for devices that support it ๐Ÿง 
  • -mstack-size=bytes โ€” specifies how many bytes of stack space will be requested for each GPU thread (wave-front). Beware: there may be many threads and limited memory available ๐Ÿ˜ญ The size of the stack allocation may also affect run-time performance. The default is 32KB when using OpenACC or OpenMP, and 1MB otherwise ๐Ÿ“ฆ
  • -mxnack โ€” compiles binaries suitable for devices with the XNACK feature enabled. Some devices always require XNACK, and some let the user configure it. The compiled code must match the device mode. The default is -mno-xnack. Right now this option is a placeholder for support that isn't implemented yet ๐Ÿšง

๐Ÿฆ‹ ARC Options ๐Ÿฆ‹

The following options control the architecture variant the 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 call 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 โ€” compile for ARC600. Aliases: -mA6, -mARC600 ๐ŸŒท
    • arc601 โ€” compile for ARC601. Alias: -mARC601 ๐ŸŒท
    • arc700 โ€” compile for ARC700. Aliases: -mA7, -mARC700. This is the default when configured with --with-cpu=arc700 ๐Ÿ‘‘
    • arcem โ€” compile for ARC EM ๐Ÿงš
    • archs โ€” compile for ARC HS ๐Ÿ”ฅ
    • em โ€” compile for ARC EM CPU with no hardware extensions ๐Ÿƒ
    • em4 โ€” compile for ARC EM4 CPU ๐Ÿƒ
    • em4_dmips โ€” compile for ARC EM4 DMIPS CPU ๐Ÿƒ
    • em4_fpus โ€” compile for ARC EM4 DMIPS CPU with the single-precision floating-point extension ๐Ÿƒ
    • em4_fpuda โ€” compile for ARC EM4 DMIPS CPU with single-precision floating-point and double assist instructions ๐Ÿƒ
    • hs โ€” compile for ARC HS CPU with no hardware extensions except the atomic instructions โš›๏ธ
    • hs34 โ€” compile for ARC HS34 CPU ๐ŸŒธ
    • hs38 โ€” compile for ARC HS38 CPU ๐ŸŒธ
    • hs38_linux โ€” compile for ARC HS38 CPU with all hardware extensions on ๐Ÿ’…
    • arc600_norm โ€” compile for ARC 600 CPU with "norm" instructions enabled ๐Ÿงƒ
    • arc600_mul32x16 โ€” compile for ARC 600 CPU with "norm" and 32x16-bit multiply instructions enabled โœ–๏ธ
    • arc600_mul64 โ€” compile for ARC 600 CPU with "norm" and "mul64"-family instructions enabled โœ–๏ธ
    • arc601_norm โ€” compile for ARC 601 CPU with "norm" instructions enabled ๐Ÿงƒ
    • arc601_mul32x16 โ€” compile for ARC 601 CPU with "norm" and 32x16-bit multiply instructions enabled โœ–๏ธ
    • arc601_mul64 โ€” compile for ARC 601 CPU with "norm" and "mul64"-family instructions enabled โœ–๏ธ
    • nps400 โ€” compile for ARC 700 on the NPS400 chip ๐Ÿ’Ž
    • em_mini โ€” compile for ARC EM minimalist configuration featuring 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. Right now only "divaw", "adds", "subs", and "sat16" are supported. This is only valid for -mcpu=ARC700 โœจ
  • -mno-mpy โ€” ๐Ÿ™ˆ Skip the "mpy"-family instructions for ARC700. This one is deprecated, so please don't build new stuff around it ๐Ÿ’€
  • -mmul32x16 โ€” โœจ Turns on 32x16-bit multiply and multiply-accumulate instructions.
  • -mmul64 โ€” ๐Ÿ”ฅ Generates the mul64 and mulu64 instructions. Only valid with -mcpu=ARC600, so don't try it anywhere else ๐Ÿ™…โ€โ™€๏ธ
  • -mnorm โ€” ๐Ÿ’… Generates the norm instructions. This is already the default when -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 โ€” ๐Ÿฆ‹ Turns on ARC SIMD instructions through target-specific builtins. Only valid with -mcpu=ARC700.
  • -msoft-float โ€” ๐Ÿซ  This one is basically ignored! It's only here for compatibility. Software floating-point code is emitted by default, and you can override that default with the 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 the locked load/store conditional extension so the atomic memory built-in functions can work. Not available for ARC 6xx or ARC EM cores, so skip it there ๐Ÿ˜ญ
  • -mdiv-rem โ€” โž— Enables the div and rem instructions for ARCv2 cores.
  • -mcode-density โ€” ๐Ÿงš Enables code density instructions for ARC EM. It's on by default for ARC HS.
  • -mll64 โ€” ๐Ÿ’œ Enables double load/store operations for ARC HS cores.
  • -mtp-regno=regno โ€” ๐Ÿงต Sets the thread pointer register number.
  • -mmpy-option=multo โ€” ๐Ÿ‘‘ Compiles ARCv2 code with a multiplier design option. You can pick the option with a string or a number for multo, and wlh1 is the default. Here's the menu:
    • 0 or none โ€” No multiplier available.
    • 1 or w โ€” 16x16 multiplier, fully pipelined. This enables mpyw and mpyuw.
    • 2 or wlh1 โ€” 32x32 multiplier, fully pipelined (1 stage). This also enables mpy, mpyu, mpym, mpymu, and mpy_s.
    • 3 or wlh2 โ€” 32x32 multiplier, fully pipelined (2 stages). This also enables mpy, mpyu, mpym, mpymu, and mpy_s.
    • 4 or wlh3 โ€” Two 16x16 multipliers, blocking, sequential. This also enables mpy, mpyu, mpym, mpymu, and mpy_s.
    • 5 or wlh4 โ€” One 16x16 multiplier, blocking, sequential. This also enables mpy, mpyu, mpym, mpymu, and mpy_s.
    • 6 or wlh5 โ€” One 32x4 multiplier, blocking, sequential. This also enables 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 โœจ

  • -mfpu=fpu โ€” ๐ŸŒˆ Turns on specific floating-point hardware extensions for ARCv2 cores. Here are the supported values for fpu:
    • fpus โ€” Single-precision floating-point hardware extensions.
    • fpud โ€” Double-precision floating-point hardware extensions. The single-precision extension gets enabled too. Not available for ARC EM.
    • fpuda โ€” Double-precision extensions using double-precision assist instructions. The single-precision extension is also enabled. This is only for ARC EM.
    • fpuda_div โ€” Double-precision extensions using double-precision assist instructions. The single-precision, square-root, and divide extensions are also enabled. ARC EM only.
    • fpuda_fma โ€” Double-precision extensions using double-precision assist instructions. The single-precision and fused multiply and add extensions are also enabled. ARC EM only.
    • fpuda_all โ€” Double-precision extensions using double-precision assist instructions. All single-precision extensions are enabled too. ARC EM only.
    • fpus_div โ€” Single-precision, square-root, and divide hardware extensions.
    • fpud_div โ€” Double-precision, square-root, and divide hardware extensions. This one includes fpus_div. Not available for ARC EM.
    • fpus_fma โ€” Single-precision and fused multiply and add hardware extensions.
    • fpud_fma โ€” Double-precision and fused multiply and add hardware extensions. This one includes fpus_fma. Not available for ARC EM.
    • fpus_all โ€” All single-precision floating-point hardware extensions.
    • fpud_all โ€” All single- and double-precision floating-point hardware extensions. Not available for ARC EM.
  • -mirq-ctrl-saved=register-range, blink, lp_count โ€” ๐Ÿ›ก๏ธ Picks the general-purpose registers the processor saves and restores automatically on interrupt entry and exit. The register-range is written as two registers separated by a dash. The range always starts at 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 โ€” ๐Ÿฆ Sets how many registers get replicated into the second register bank when a fast interrupt is entered. Fast interrupts are the ones with the highest priority level, P0. They only save the PC and STATUS32 registers so there are no memory transactions during entry and exit. Use this when you're working with fast interrupts on an ARC V2 family processor. The 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. 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's known that lp_count can 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. It also defines the __ARC_RF16__ preprocessor macro.
  • -mbranch-index โ€” ๐Ÿงญ Enables the use of bi or bih instructions to implement jump tables.

The following 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.

The following 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.

The following options are passed through to the linker ๐Ÿ”—

  • -marclinux โ€” ๐Ÿง Passed through to the linker to specify use of the arclinux emulation. This is enabled by default in toolchains built for the arc-linux-uclibc and arceb-linux-uclibc targets when profiling is not requested.
  • -marclinux_prof โ€” ๐Ÿ“Š Passed through to the linker to specify use of the arclinux_prof emulation. This is enabled by default in toolchains built for the arc-linux-uclibc and arceb-linux-uclibc targets when profiling is requested.

The following options control the semantics of the generated code ๐Ÿง โœจ

  • -mlong-calls โ€” ๐Ÿ“ž Generates calls as register indirect calls, which gives you access to the full 32-bit address range.
  • -mmedium-calls โ€” ๐ŸŽฏ Doesn't use less than a 25-bit addressing range for calls. That's the offset available for an unconditional branch-and-link instruction. Conditional execution of function calls is suppressed, so the 25-bit range gets used instead of the 21-bit range you'd get with conditional branch-and-link. This is the default for toolchains built for the arc-linux-uclibc and arceb-linux-uclibc targets ๐Ÿ’–
  • -G num โ€” okay so this one decides which externally-visible data gets tucked into a small data section ๐Ÿงš, but only if that data is no bigger than num bytes. The default for num is 4 for any ARC configuration, or 8 when we have double load/store operations. ๐Ÿ“
  • -mno-sdata โ€” no sdata references for you, bestie ๐Ÿ™…โ€โ™€๏ธ. This is the default for tool chains built for arc-linux-uclibc and arceb-linux-uclibc targets.
  • -mvolatile-cache โ€” volatile references use ordinarily cached memory accesses. This is the default, and honestly iconic ๐Ÿ’….
  • -mno-volatile-cache โ€” flips the switch and enables cache bypass for volatile references ๐Ÿ”ฅ.

The following 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 one turns off a target-specific pass in arc_reorg that would generate compare-and-branch (brcc) instructions. It has no effect on generation of these instructions driven by the combiner pass, so don't expect miracles there ๐Ÿ™ˆ.
  • -mcase-vector-pcrel โ€” uses PC-relative switch case tables so case table shortening can happen. 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. Also, this option is deprecated, so use it with a little side-eye ๐Ÿ’€.
  • -mno-cond-exec โ€” disables the ARCompact-specific pass that generates conditional execution instructions.

Okay, so the reason this one exists is that the target-independent pass for conditional execution is often lacking, thanks to delay slot scheduling and interactions between operand numbers, literal sizes, instruction lengths, and the support for conditional execution. The ARC port keeps a special pass around that tries to find more conditional execution opportunities after register allocation, branch shortening, and delay slot scheduling have been done. It generally, but not always, improves performance and code size, at the cost of extra compilation time, which is why there is an option to switch it off ๐Ÿ˜ญ. If you have a problem with call instructions exceeding their allowable offset range because they are conditionalized, you should consider using -mmedium-calls instead ๐Ÿซถ.

  • -mearly-cbranchsi โ€” enables pre-reload use of the cbranchsi pattern ๐Ÿงš.
  • -mexpand-adddi โ€” expands adddi3 and subdi3 at RTL generation time into add.f, adc etc. This option is deprecated, so it's giving retired vibes ๐Ÿ‘‘.
  • -mindexed-loads โ€” enables the use of indexed loads. Be careful here, because some optimizers then assume that indexed stores exist, which is not the case ๐Ÿ™ˆ. This can be problematic, so proceed with caution.
  • -mlra โ€” enables Local Register Allocation. This is still experimental for ARC, so by default the compiler uses standard reload (i.e. -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 optimizing for size (using -Os), prologues and epilogues that have to save or restore a large number of registers often get shortened by calling a special function in libgcc. This is called a millicode call. These calls can pose performance issues and/or cause linking issues when linking 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 ๐Ÿง˜โ€โ™€๏ธ.
  • -mmixed-code โ€” tweaks register allocation to help with 16-bit instruction generation. This generally decreases the average instruction size while increasing the instruction count ๐Ÿญ.
  • -mq-class โ€” this one is deprecated, and it enables q instruction alternatives. It is the default for -Os ๐Ÿฅน.
  • -mRcq โ€” enables Rcq constraint handling. Most short code generation depends on this. This is the default ๐Ÿ’–.
  • -mRcw โ€” enables Rcw constraint handling. Most ccfsm condexec depends on this. This is 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 โ€” in addition, alignment of loops and of code after barriers is dropped ๐ŸŒ™.
    • 3 โ€” in addition, optional data alignment is dropped, and the option Os is enabled ๐Ÿ‘‘.

This defaults to 3 when -Os is in effect. Otherwise, the behavior when this is not set is equivalent to level 1 ๐Ÿ’….

  • -mtune=cpu โ€” sets instruction scheduling parameters for cpu, overriding any implied by -mcpu= ๐ŸŽฏ.

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 โ€” 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 tuning for ARC700 and optimizing for speed, branches without a filled delay slot are preferably emitted unaligned and long, unless profiling indicates that the probability for the branch to be taken is below probability. The default is (REG_BR_PROB_BASE/2), i.e. 5000 ๐Ÿซง.

The following options are maintained for backward compatibility, but they are now deprecated and will be removed in a future release. Bestie, let's say goodbye to these ๐Ÿ˜ญ๐Ÿซก:

These options are deprecated and will be removed in a future release, so don't build new stuff around them ๐Ÿ’”.
  • -margonaut โ€” obsolete FPX ๐Ÿชฆ.
  • -mbig-endian, -EB โ€” compiles code for big-endian targets. Use of these options is now deprecated. Big-endian code is supported by configuring GCC to build arceb-elf32 and arceb-linux-uclibc targets, for which big endian is the default ๐ŸŒŠ.
  • -mlittle-endian, -EL โ€” compiles code for little-endian targets. Use of these options is now deprecated. Little-endian code is supported by configuring GCC to build arc-elf32 and arc-linux-uclibc targets, for which little endian is 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 โœจ

These -m options are defined for the ARM port ๐Ÿฆพ:

  • -mabi=name โ€” generates code for the specified ABI. Permissible values are: apcs-gnu, atpcs, aapcs, aapcs-linux and iwmmxt ๐Ÿงฉ.
  • -mapcs-frame โ€” generates a stack frame that is compliant with the ARM Procedure Call Standard for all functions, even if this isn't strictly necessary for correct execution of the code. Specifying -fomit-frame-pointer with this option causes the stack frames not to 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 cannot be reliably used inside one program. The default is -mno-thumb-interwork, since slightly larger code is generated when -mthumb-interwork is specified. In AAPCS configurations this option is meaningless ๐Ÿคทโ€โ™€๏ธ.
  • -mno-sched-prolog โ€” prevents the reordering of instructions in the function prologue, or the merging of those instructions with the instructions in the function's body. This means that all functions start with a recognizable set of instructions (or in fact one of a choice from a small set of different function prologues), and this information can be used to locate the start of functions inside an executable piece of code. The default is -msched-prolog ๐Ÿ”.
  • -mfloat-abi=name โ€” specifies which floating-point ABI to use. Permissible values are: soft, softfp and hard ๐Ÿ”ข.

Specifying soft causes GCC to generate output containing library calls for floating-point operations. softfp allows the generation of code using hardware floating-point instructions, but still uses the soft-float calling conventions. hard allows generation of floating-point instructions and uses FPU-specific calling conventions.

The default depends on the specific target configuration. Note that the hard-float and soft-float ABIs are not link-compatible. You must compile your entire program with the same ABI, and link with a compatible set of libraries. This is a big no-no if you mix them ๐Ÿšซ.

  • -mgeneral-regs-only โ€” generates code which uses only the general-purpose registers. This prevents the compiler from using floating-point and Advanced SIMD registers, but it doesn't impose 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 code for a little-endian processor ๐ŸŒŠ.
  • -mbe8, -mbe32 โ€” when linking a big-endian image, selects between BE8 and BE32 formats. The option has no effect for little-endian images and is ignored. The default is dependent on the selected target architecture. For ARMv6 and later architectures the default is BE8, and for older architectures the default is BE32. BE32 format has been deprecated by ARM ๐Ÿซ .
  • -march=name[+extension...] โ€” specifies the name of the target ARM architecture. GCC uses this name to determine what kind of instructions it can emit when generating assembly code. This option can be used in conjunction with or instead of the -mcpu= option ๐Ÿ—๏ธ.

Okay so, these are the permissible names you're allowed to use, bestie ๐ŸŽ€: 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, armv8.6-a, armv7-r, armv8-r, armv6-m, armv6s-m, armv7-m, armv7e-m, armv8-m.base, armv8-m.main, armv8.1-m.main, iwmmxt and iwmmxt2 ๐Ÿ’–

Then there's a little group of deprecated ones ๐Ÿฅ€ that are still recognized but have no Thumb execution state support, so they're on thin ice: armv4. Use with caution, it's giving "please don't" ๐Ÿ’€

Many of these architectures have extensions โœจ You add one by tacking +extension onto the end of the architecture name. The extension options get processed in order, and the capabilities accumulate (they stack up, like a good outfit ๐Ÿ‘‘). An extension will also turn on any base extensions it needs, so for example +crypto will always enable +simd ๐Ÿซถ

The one exception to the stacking vibe is anything prefixed with +no.... Those disable the option they name, plus any other extensions that depend on it ๐Ÿ˜ญ For example, -march=armv7-a+simd+nofp+vfpv4 is the same as writing -march=armv7-a+vfpv4, because the +nofp that comes after +simd wipes +simd out completely ๐Ÿ’…

Most extension names are generic, but what they actually do depends on which architecture they're attached to ๐Ÿฆ‹ For example, +simd works on both armv7-a and armv8-a, but on armv7-a it turns on the original ARMv7-A Advanced SIMD (Neon) extensions, while on armv8-a it gives you the ARMv8-A version instead ๐ŸŒˆ

Here's the rundown of which extensions each architecture supports. Anything not mentioned below has no extensions at all, so don't go looking ๐Ÿ™ˆ

armv5te, armv6, armv6j, armv6k, armv6kz, armv6t2, armv6z, armv6zk

  • +fp โ€” The VFPv2 floating-point instructions. The extension +vfpv2 can be used as an alias for this extension.
  • +nofp โ€” Disable the floating-point instructions.

armv7

This one is the common subset of the ARMv7-A, ARMv7-R and ARMv7-M architectures, so it's the everyday basic ๐ŸŒธ

  • +fp โ€” The VFPv3 floating-point instructions, with 16 double-precision registers. The extension +vfpv3-d16 can be used as an alias for this extension. Note that floating-point is not supported by the base ARMv7-M architecture, but is compatible with both the ARMv7-A and ARMv7-R architectures โš ๏ธ
  • +nofp โ€” Disable the floating-point instructions.

armv7-a

  • +mp โ€” The multiprocessing extension.
  • +sec โ€” The security extension.
  • +fp โ€” The VFPv3 floating-point instructions, with 16 double-precision registers. The extension +vfpv3-d16 can be used as an alias for this extension.
  • +simd โ€” The Advanced SIMD (Neon) v1 and the VFPv3 floating-point instructions. The extensions +neon and +neon-vfpv3 can be used as aliases for this extension.
  • +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 floating-point conversion operations.
  • +vfpv3-fp16 โ€” The VFPv3 floating-point instructions, with 32 double-precision registers and the half-precision floating-point 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 and the VFPv3 floating-point instructions, with the half-precision floating-point conversion operations.
  • +neon-vfpv4 โ€” The Advanced SIMD (Neon) v2 and the VFPv4 floating-point instructions.
  • +nosimd โ€” Disable the Advanced SIMD instructions (does not disable floating point).
  • +nofp โ€” Disable 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. The extension +vfpv4-d16 can be used as an alias for this extension.
  • +simd โ€” The Advanced SIMD (Neon) v2 and the VFPv4 floating-point instructions. The extension +neon-vfpv4 can be used as an alias for this extension.
  • +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 floating-point conversion operations.
  • +vfpv3-fp16 โ€” The VFPv3 floating-point instructions, with 32 double-precision registers and the half-precision floating-point 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 and the VFPv3 floating-point instructions. The extension +neon-vfpv3 can be used as an alias for this extension.
  • +neon-fp16 โ€” The Advanced SIMD (Neon) v1 and the VFPv3 floating-point instructions, with the half-precision floating-point conversion operations.
  • +nosimd โ€” Disable the Advanced SIMD instructions (does not disable floating point).
  • +nofp โ€” Disable 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 โ€” Disable the cryptographic instructions.
  • +nofp โ€” Disable the floating-point, Advanced SIMD and cryptographic instructions.
  • +sb โ€” Speculation Barrier Instruction.
  • +predres โ€” 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 enables the Advanced SIMD and floating-point instructions.
  • +nocrypto โ€” Disable the cryptographic instructions.
  • +nofp โ€” Disable the floating-point, Advanced SIMD and cryptographic instructions.
  • +sb โ€” Speculation Barrier Instruction.
  • +predres โ€” Execution and Data Prediction Restriction Instructions.

armv8.2-a, armv8.3-a

  • +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 and 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 โ€” Enable the Dot Product extension. This also enables Advanced SIMD instructions.
  • +nocrypto โ€” Disable the cryptographic extension.
  • +nofp โ€” Disable the floating-point, Advanced SIMD and cryptographic instructions.
  • +sb โ€” Speculation Barrier Instruction.
  • +predres โ€” Execution and Data Prediction Restriction Instructions.
  • +i8mm โ€” 8-bit Integer Matrix Multiply instructions. This also enables Advanced SIMD and floating-point instructions.
  • +bf16 โ€” Brain half-precision floating-point instructions. This also enables Advanced SIMD and floating-point 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 โ€” Disable the cryptographic extension.
  • +nofp โ€” Disable the floating-point, Advanced SIMD and cryptographic instructions.
  • +sb โ€” Speculation Barrier Instruction.
  • +predres โ€” Execution and Data Prediction Restriction Instructions.
  • +i8mm โ€” 8-bit Integer Matrix Multiply instructions. This also enables Advanced SIMD and floating-point instructions.
  • +bf16 โ€” Brain half-precision floating-point instructions. This also enables Advanced SIMD and floating-point 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 โ€” okay bestie, this one turns on the ARMv8.3-A Advanced SIMD and floating-point instructions, plus the Dot Product extension โœจ

๐Ÿฆ‹ armv8.6-a

  • +fp16 โ€” the half-precision floating-point data processing instructions ๐Ÿ’–. This also enables the Advanced SIMD and floating-point instructions, the Dot Product extension, and the half-precision floating-point fmla extension ๐Ÿซถ
  • +simd โ€” the same ARMv8.3-A Advanced SIMD and floating-point instructions as before, plus 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 โ€” disable the cryptographic extension ๐Ÿ™…โ€โ™€๏ธ
  • +nofp โ€” disable the floating-point, Advanced SIMD and cryptographic instructions ๐Ÿ’€
  • +i8mm โ€” 8-bit Integer Matrix Multiply instructions ๐Ÿงš. This also enables Advanced SIMD and floating-point instructions
  • +bf16 โ€” Brain half-precision floating-point instructions ๐Ÿ“. This also enables Advanced SIMD and floating-point instructions

๐ŸŒˆ armv7-r

  • +fp.sp โ€” the single-precision VFPv3 floating-point instructions ๐ŸŒธ. +vfpv3xd can be used as an alias for this extension
  • +fp โ€” the VFPv3 floating-point instructions with 16 double-precision registers ๐ŸŽ€. +vfpv3-d16 can be used as an alias for this extension
  • +vfpv3xd-d16-fp16 โ€” the single-precision VFPv3 floating-point instructions with 16 double-precision registers, plus the half-precision floating-point conversion operations ๐Ÿง
  • +vfpv3-d16-fp16 โ€” the VFPv3 floating-point instructions with 16 double-precision registers, plus the half-precision floating-point conversion operations ๐Ÿง
  • +nofp โ€” disable the floating-point extension ๐Ÿ™ˆ
  • +idiv โ€” the ARM-state integer division instructions โž—
  • +noidiv โ€” disable 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 โ€” disable the floating-point extensions ๐Ÿ’”

๐Ÿงš armv8.1-m.main

  • +dsp โ€” the DSP instructions ๐ŸŽถ
  • +mve โ€” the M-Profile Vector Extension (MVE) integer instructions ๐ŸŒŸ
  • +mve.fp โ€” the M-Profile Vector Extension (MVE) integer and single precision floating-point instructions ๐ŸŒŸ
  • +fp โ€” the single-precision floating-point instructions โœจ
  • +fp.dp โ€” the single- and double-precision floating-point instructions ๐Ÿ‘‘
  • +nofp โ€” disable the floating-point extension ๐Ÿ™ˆ
  • +cdecp0, +cdecp1, ... , +cdecp7 โ€” enable the Custom Datapath Extension (CDE) on selected coprocessors, according to the numbers given in the options in the range 0 to 7 ๐Ÿฆ‹

๐Ÿ“ armv8-m.main

  • +dsp โ€” the DSP instructions ๐ŸŽถ
  • +nodsp โ€” disable the DSP extension ๐Ÿ™…โ€โ™€๏ธ
  • +fp โ€” the single-precision floating-point instructions โœจ
  • +fp.dp โ€” the single- and double-precision floating-point instructions ๐Ÿ‘‘
  • +nofp โ€” disable the floating-point extension ๐Ÿ™ˆ
  • +cdecp0, +cdecp1, ... , +cdecp7 โ€” enable the Custom Datapath Extension (CDE) on selected coprocessors, according to the numbers given in the options in the range 0 to 7 ๐Ÿฆ‹

๐Ÿซง 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 โ€” disable the cryptographic instructions ๐Ÿ™…โ€โ™€๏ธ
  • +nofp โ€” disable the floating-point, Advanced SIMD and cryptographic instructions ๐Ÿ’€

-march=native is giving auto-detect vibes ๐Ÿ”. It makes the compiler sniff out 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 just has no effect, so no drama ๐Ÿซถ


๐ŸŽ€ -mtune=name

This option tells GCC which target ARM processor it should tune the performance of the code for ๐Ÿ’…. Some ARM implementations can get a glow-up in performance when you use this option โœจ. The permissible names are: 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, cortex-a76ae, cortex-a77, cortex-a78, cortex-a78ae, cortex-a78c, 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-m35p, cortex-m55, cortex-x1, 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 tell GCC to tune the performance of the code for a big.LITTLE system ๐Ÿง ๐Ÿ’ž. The permissible names 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 the performance for a blend of processors within architecture arch ๐ŸŒˆ. The goal is code that runs well on the most popular processors right now, balancing optimizations that help some CPUs in the range while avoiding performance pitfalls on the others ๐Ÿซถ. The effects of this option may change in future GCC versions as CPU models come and go ๐Ÿ”„.

-mtune permits the same extension options as -mcpu, but the extension options do not affect the tuning of the generated code ๐Ÿ™ƒ.

-mtune=native makes the compiler auto-detect the CPU of the build computer ๐Ÿ”. Again, this only works on GNU/Linux right now, and not every architecture is recognized. If the auto-detect is unsuccessful, the option has no effect ๐Ÿฅ€.


๐Ÿ‘‘ -mcpu=name[+extension...]

This specifies the name of the target ARM processor ๐Ÿ‘‘. GCC uses this name to figure out the target ARM architecture (as if you had said -march), and the ARM processor type to tune for performance (as if you had said -mtune) ๐Ÿง . If you use this option together with -march or -mtune, those options take precedence over the matching part of this option ๐Ÿ’….

Lots of the supported CPUs have optional architectural extensions ๐Ÿงฉ. When they do, those extensions are usually enabled by default โœจ. If implementations that lack the extension exist, you can use the extension syntax to disable the ones that were left out ๐Ÿ™…โ€โ™€๏ธ. For floating-point and Advanced SIMD (Neon) instructions, you also need to think about the settings of -mfloat-abi and -mfpu ๐Ÿ‘€: floating-point and Advanced SIMD instructions will only be used if -mfloat-abi is not set to soft, and any setting of -mfpu other than auto will override the available floating-point and SIMD extension instructions ๐Ÿ’ฅ.

For example, cortex-a9 comes in three major configurations: integer only, with just a floating-point unit, or with floating-point and Advanced SIMD ๐ŸŒธ. The default is to enable all the instructions, but you can use the extensions +nosimd and +nofp to disable just the SIMD instructions, or both the SIMD and floating-point instructions, respectively ๐Ÿซง.

The permissible names for this option are the same as the ones for -mtune ๐ŸŽ€.

The following extension options are common to the listed CPUs ๐ŸŒŸ:

  • +nodsp โ€” disable the DSP instructions on cortex-m33, cortex-m35p ๐Ÿ™ˆ
  • +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, cortex-m33 and cortex-m35p. It also disables the floating-point and SIMD instructions 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 ๐Ÿ’”
  • +nofp.dp โ€” disables the double-precision component of the floating-point instructions on cortex-r5, cortex-r7, cortex-r8, cortex-r52 and cortex-m7 ๐Ÿฅ€
  • +nosimd โ€” disables the SIMD (but not floating-point) instructions on generic-armv7-a, cortex-a5, cortex-a7 and cortex-a9 ๐Ÿ™ƒ

okay so +crypto is the one that switches on the cryptographic instructions ๐Ÿ”โœจ it works 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 ๐Ÿ’…

the generic-armv7-a pseudo target is giving its own thing ๐Ÿฆ‹ by default it comes with VFPv3 and 16 double-precision registers. it takes 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 for -march=armv7-a, so no new vocab to learn ๐ŸŒธ

-mcpu=generic-arch is also allowed, and it's the same as -march=arch -mtune=generic-arch. check out -mtune for more tea โ˜•

  • -mcpu=native โ€” the compiler tries to auto-detect the CPU of the computer doing the build ๐Ÿงš right now this only works on GNU/Linux, and not every architecture gets recognised. if the auto-detect doesn't work out, the option just does nothing ๐Ÿ™ˆ
  • -mfpu=name โ€” this tells the compiler what floating-point hardware (or hardware emulation) the target has ๐Ÿ’– the valid 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 and crypto-neon-fp-armv8. neon is just an alias for neon-vfpv3, and vfp is an alias for vfpv2 ๐ŸŽ€

auto is the default and it's a bit of a diva ๐Ÿ‘‘ it picks the floating-point and Advanced SIMD instructions based on whatever -mcpu and -march are set to.

โš ๏ธ bestie, listen up. if your floating-point hardware has NEON (like -mfpu=neon), GCC's auto-vectorization pass won't generate floating-point operations unless you also add -funsafe-math-optimizations. the reason is that NEON doesn't fully follow the IEEE 754 standard (denormal values get treated as zero), so using NEON instructions can lose precision ๐Ÿ˜ญ

you can also set the fpu name per function with the target("fpu=") function attributes or pragmas ๐Ÿฆ‹

  • -mfp16-format=name โ€” this sets the format of the "__fp16" half-precision floating-point type โœจ the valid names are none, ieee and alternative. the default is none, and in that case the "__fp16" type isn't defined at all ๐Ÿฅ€
  • -mstructure-size-boundary=n โ€” every structure and union gets rounded up to a multiple of n bits ๐Ÿ“ the valid values are 8, 32 and 64. the default depends on the toolchain, and for the COFF toolchain it's 8. 64 only works if the underlying ABI supports it ๐Ÿ’…

a bigger number can make code faster and more efficient, but it can also make the program bigger. different values can be incompatible, too. code built with one value might not play nice with code or libraries built with another value if they pass structs or unions back and forth ๐Ÿ™ˆ

๐Ÿ’€ this option is deprecated, so please don't start new projects with it.
  • -mabort-on-noreturn โ€” this makes the compiler call abort at the end of any noreturn function. it only runs if that function somehow tries to return ๐Ÿšจ
  • -mlong-calls, -mno-long-calls โ€” these tell the compiler to make function calls by loading the function's address into a register first, then doing a subroutine call on that register ๐Ÿง  you need this if the target function lives outside the 64-megabyte addressing range of the offset-based subroutine call instruction.

even with this switched on, not every call becomes a long call. the vibe check goes like this: static functions, functions with the "short_call" attribute, functions inside a #pragma no_long_calls scope, and functions whose definitions were already compiled in the current compilation unit all stay short ๐Ÿซถ the exceptions are weak function definitions, functions with the "long_call" attribute or the "section" attribute, and functions inside a #pragma long_calls scope. those are always long, no debate ๐Ÿ’œ

this feature is not on by default. -mno-long-calls puts back the default behaviour, and so does wrapping the calls in a #pragma long_calls_off directive. also note that these switches do nothing for calls made through function pointers โœจ

  • -msingle-pic-base โ€” the register used for PIC addressing gets treated as read-only, instead of being loaded in the prologue of every function ๐ŸŒˆ the runtime system has to set this register to a proper value before execution starts.
  • -mpic-register=reg โ€” this picks the register used for PIC addressing ๐ŸŽฏ for the standard PIC base, the default is any suitable register the compiler decides on. for the single PIC base, the default is R9 if the target is EABI based or stack-checking is enabled. otherwise it's R10.
  • -mpic-data-is-text-relative โ€” this assumes the gap between the text and data segments is fixed at static link time ๐Ÿงš that means PC-relative addressing can be used to reach data we know is in the data segment. on non-VxWorks RTP targets it's enabled by default. if you turn it off on those targets, -msingle-pic-base gets enabled by default instead ๐Ÿฆ‹
  • -mpoke-function-name โ€” this writes the name of each function into the text section, right before the function prologue โœ๏ธ the generated code looks something like 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 look at the pc value stored at fp + 0 ๐Ÿ” if the trace function checks the location pc - 12 and the top 8 bits are set, then we know there's a function name embedded right before that location. its length is ((pc[-3]) & 0xff000000). the way that's giving detective energy ๐Ÿ•ต๏ธโ€โ™€๏ธ

  • -mthumb, -marm โ€” pick whether the code runs in ARM state or Thumb state ๐ŸŽ€ most configurations default to ARM state, but you can change that by configuring GCC with the --with-mode=state configure option.

you can also override ARM or Thumb mode for each function with the target("thumb") and target("arm") function attributes or pragmas ๐Ÿ’–

  • -mflip-thumb โ€” this switches between ARM and Thumb modes on alternating functions ๐Ÿ”€ it's only there for regression testing of mixed Thumb/ARM code generation, so please don't use it for ordinary compiling ๐Ÿ™…โ€โ™€๏ธ
  • -mtpcs-frame โ€” generates a stack frame that follows 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 โ€” same idea, but this one makes stack frames compliant with the Thumb Procedure Call Standard for all leaf functions ๐Ÿƒ (again, a leaf function is one that doesn't 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. this lets those functions get called from non-interworking code. it's not valid in AAPCS configurations, because interworking is already enabled by default there ๐Ÿ™ˆ
  • -mcaller-super-interworking โ€” lets calls through function pointers (including virtual functions) run correctly, whether or not the target code was compiled for interworking ๐ŸŒธ there's a small overhead when running a function pointer if you turn this on. it's also not valid in AAPCS configurations, since interworking is already on by default there.
  • -mtp=name โ€” picks 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 from cp15 directly (supported in the arm6k architecture); and auto, which uses the best available method for the processor you picked. the default is auto โญ
  • -mtls-dialect=dialect โ€” picks the dialect used to access thread local storage ๐Ÿ’… there are two: gnu and gnu2. the gnu dialect selects the original GNU scheme for supporting local and global dynamic TLS models. the gnu2 dialect selects the GNU descriptor scheme, which performs better for shared libraries ๐Ÿš€ the descriptor scheme is compatible with the original, but it needs new assembler, linker and library support. the 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 on by default on targets (uClinux, SymbianOS) where the runtime loader enforces that restriction, and whenever -fpic or -fPIC is specified. this option conflicts with -mslow-flash-data.
  • -mfix-cortex-m3-ldrd โ€” some Cortex-M3 cores can corrupt data when ldrd instructions use overlapping destination and base registers ๐Ÿ˜ฑ 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 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 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 Tag_CPU_unaligned_access attribute in the generated object file gets set to true or false depending on this option ๐Ÿฆ‹. If unaligned access is turned on, the __ARM_FEATURE_UNALIGNED preprocessor symbol gets defined too โœจ.

  • -mneon-for-64bits โ€” ๐Ÿ’€ This one is deprecated and does absolutely nothing, so bestie, don't bother with it.
  • -mslow-flash-data โ€” Okay so this assumes loading data from flash is slower than fetching instructions, which means literal loads get minimized for better performance โšก. It's only supported when compiling for ARMv7 M-profile, it's off by default, and it conflicts with -mword-relocations ๐Ÿ™…โ€โ™€๏ธ.
  • -masm-syntax-unified โ€” Assumes the inline assembler is using unified asm syntax. The default is currently off, which means divided syntax. It has no impact on Thumb2, but ngl this might change in future GCC releases ๐Ÿ‘€.
Divided syntax should be considered deprecated. It's giving outdated, so plan accordingly ๐Ÿ’€.
  • -mrestrict-it โ€” Restricts IT block generation so it follows the ARMv8-A rules ๐Ÿ“œ. IT blocks can only contain a single 16-bit instruction from a select set of instructions. This is on by default for ARMv8-A Thumb mode ๐ŸŒธ.
  • -mprint-tune-info โ€” Prints CPU tuning info as a comment in the assembler file ๐Ÿงš. This is only for regression testing of the compiler and is not meant for ordinary code compiling, so it's disabled by default ๐Ÿ™ˆ.
This one is strictly for compiler testing, not everyday use. Keep it away from your normal builds!
  • -mverbose-cost-dump โ€” Enables verbose cost model dumping in the debug dump files ๐Ÿ”. It's here for debugging the compiler, so it's a main-character tool for compiler nerds ๐Ÿค“.
  • -mpure-code โ€” Do not allow constant data to be placed in code sections ๐Ÿšซ. On top of that, when compiling for ELF object format, all text sections get the ELF processor-specific section attribute SHF_ARM_PURECODE โœจ. This 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/ ๐Ÿ“–.
  • -mfix-cmse-cve-2021-35465 โ€” This mitigates a potential security issue with the "VLLDM" instruction in some M-profile devices when using CMSE (CVE-2021-365465) ๐Ÿ›ก๏ธ. It's enabled by default when -mcpu= is used with "cortex-m33", "cortex-m35p" or "cortex-m55" ๐Ÿ’…. If you want to turn the mitigation off, use -mno-fix-cmse-cve-2021-35465 ๐Ÿ™…โ€โ™€๏ธ.
  • -mfdpic, -mno-fdpic โ€” Selects the FDPIC ABI, which uses 64-bit function descriptors to represent pointers to functions ๐ŸŒˆ. When the compiler is configured for "arm-*-uclinuxfdpiceabi" targets, this is on by default and implies -fPIE if none of the PIC/PIE-related options is provided ๐Ÿ‘‘. On other targets, it only enables the FDPIC-specific code generation features, so you'll need to explicitly provide the PIC/PIE-related options as needed ๐Ÿซถ.

Static linking is not supported here, because it would still involve the dynamic linker when the program self-relocates ๐Ÿ˜ญ. If that behaviour is fine with you, use -static and -Wl,-dynamic-linker options ๐Ÿ”ฅ.

The opposite -mno-fdpic option is useful (and required!) for building the Linux kernel with the same ("arm-*-uclinuxfdpiceabi") toolchain you use for your userland programs ๐Ÿง.


โœจ AVR Options โœจ

These options are defined for AVR implementations ๐Ÿฆ‹:

  • -mmcu=mcu โ€” Specifies 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 = 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 = 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 = at76c711, at43usb355.
  • avr31 โ€” "Classic" devices with 128 KiB of program memory. mcu = atmega103, at43usb320.
  • avr35 โ€” "Classic" devices with 16 KiB up to 64 KiB of program memory and with the "MOVW" instruction. mcu = attiny167, attiny1634, atmega8u2, atmega16u2, atmega32u2, ata5505, ata6617c, ata664251, at90usb82, at90usb162.
  • avr4 โ€” "Enhanced" devices with up to 8 KiB of program memory. mcu = 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. mcu = 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. mcu = atmega128, atmega128a, atmega128rfa1, atmega128rfr2, atmega1280, atmega1281, atmega1284, atmega1284p, atmega1284rfr2, at90can128, at90usb1286, at90usb1287.
  • avr6 โ€” "Enhanced" devices with 3-byte PC, i.e. with more than 128 KiB of program memory. mcu = atmega256rfr2, atmega2560, atmega2561, atmega2564rfr2.
  • avrxmega2 โ€” "XMEGA" devices with more than 8 KiB and up to 64 KiB of program memory. mcu = 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, and with program memory visible in the RAM address space ๐Ÿชž. mcu = 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. mcu = atxmega64a3, atxmega64a3u, atxmega64a4u, atxmega64b1, atxmega64b3, atxmega64c3, atxmega64d3, atxmega64d4.
  • avrxmega5 โ€” "XMEGA" devices with more than 64 KiB and up to 128 KiB of program memory and more than 64 KiB of RAM. mcu = atxmega64a1, atxmega64a1u.
  • avrxmega6 โ€” "XMEGA" devices with more than 128 KiB of program memory. mcu = 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. mcu = atxmega128a1, atxmega128a1u, atxmega128a4u.
  • avrtiny โ€” "TINY" Tiny core devices with 512 B up to 4 KiB of program memory. mcu = attiny4, attiny5, attiny9, attiny10, attiny20, attiny40.
  • avr1 โ€” This ISA is implemented by the minimal AVR core and is supported for assembler only โš ๏ธ. mcu = attiny11, attiny12, attiny15, attiny28, at90s1200.
  • -mabsdata โ€” Assumes all data in static storage can be accessed by LDS / STS instructions ๐ŸŽฏ. This only has an effect on reduced Tiny devices like ATtiny40. See also the "absdata" AVR Variable Attributes,variable attribute ๐Ÿ”—.
  • -maccumulate-args โ€” Accumulates outgoing function arguments, and acquires and releases the needed stack space for them just once, in the function prologue/epilogue ๐Ÿ“š. Without this option, outgoing arguments are pushed before calling a function and popped afterwards ๐Ÿฅก.

Okay so the stack trick is lowkey genius ๐Ÿงšโœจ Popping arguments after a call can be expensive on AVR ๐Ÿ’ธ, so letting them pile up on the stack can actually lead to smaller executables ๐Ÿ“‰, since nothing has to be yanked off the stack after each call. ๐Ÿ’…

This option can really shrink code for functions that make a bunch of calls to functions that take their arguments on the stack, like printf-like functions ๐Ÿ–จ๏ธ๐ŸŒธ

  • -mbranch-cost=cost โ€” Sets the branch costs for conditional branch instructions to cost ๐Ÿฆ‹ Reasonable values are small, non-negative integers, and the default branch cost is 0.
  • -mcall-prologues โ€” Function prologues and epilogues get expanded as calls to the right subroutines ๐Ÿซถ The bonus here is that the code size comes out smaller ๐Ÿ’–
  • -mdouble=bits, -mlong-double=bits โ€” Sets the size (in bits) of the "double" or "long double" type, respectively ๐ŸŒˆ The possible values for bits are 32 and 64. Whether a specific value is allowed depends on the --with-double= and --with-long-double= configure options (https://gcc.gnu.org/install/configure.html#avr), and the same goes for the default values of these options ๐Ÿง
  • -mgas-isr-prologues โ€” Interrupt service routines (ISRs) can use the "__gcc_isr" pseudo instruction that GNU Binutils supports ๐Ÿ”ฅ If this option is on, you can still turn the feature off for individual ISRs with the AVR Function Attributes,,"no_gccisr" function attribute ๐Ÿ™ˆ This feature is turned on by default if optimization is on (but not with -Og, @pxref{Optimize Options}), and if GNU Binutils supports PR21683 (https://sourceware.org/PR21683) โœจ
  • -mint8 โ€” Assumes int is an 8-bit integer ๐Ÿ’€ This changes the size of every type: a char is 1 byte, an int is 1 byte, a long is 2 bytes, and a long long is 4 bytes.
Heads up bestie: this option does not conform to the C standards ๐Ÿ˜ญ It does give you smaller code size though, so it's a trade-off.
  • -mmain-is-OS_task โ€” Stops registers from being saved in main ๐Ÿ“ It's the same as attaching the AVR Function Attributes,,"OS_task" attribute to main. It's activated by default if optimization is on ๐Ÿ”ฅ
  • -mn-flash=num โ€” Assumes the flash memory is num times 64 KiB big ๐Ÿ’œ
  • -mno-interrupts โ€” The generated code is not compatible with hardware interrupts ๐Ÿ™ˆ The upside is that code size comes out smaller ๐ŸŽ€
  • -mrelax โ€” Tries to swap a CALL resp. JMP instruction for the shorter RCALL resp. RJMP instruction when that's possible ๐Ÿฆ‹ Setting -mrelax just 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 gets located ๐Ÿงš So the assembler code the compiler generates stays the same, but the instructions in the executable may differ from what's in the assembler code ๐Ÿซ 

Relaxing must be turned on if linker stubs are needed, so check out 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 option 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, aka it assumes the high byte of the stack pointer is zero ๐Ÿง In general, you don't need to set this one by hand.

This option is used internally by the compiler 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 thus no SPH register) or not ๐Ÿง 

  • -mstrict-X โ€” Uses the address register X the way the hardware intends ๐Ÿ’– That means X only gets 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 by extra instructions ๐Ÿ˜ค For example, loading a value with X+const addressing (with a small non-negative const < 64) into a register Rn gets 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 โ€” Lets you use truncation instead of rounding towards 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 taking full responsibility for feeding the subprocesses (compiler proper, assembler and linker) the right command line options. That means you have to supply your own private device specs file with -specs=path-to-specs-file. There's no more need for -mmcu=mcu either โœจ

This option can also replace the older way of doing custom device-specs files. That one needed -B some-path to point to a directory containing a folder named "device-specs", which contained a specs file named "specs-mcu" (where mcu was set by -mmcu=mcu) ๐Ÿ•ฐ๏ธ

  • -Waddr-space-convert โ€” Warns about conversions between address spaces when the resulting address space isn't contained in the incoming address space โš ๏ธ
  • -Wmisspelled-isr โ€” Warns if the ISR is misspelled, i.e. missing the __vector prefix ๐Ÿ™ˆ 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 stored as a word address, so indirect jumps and calls can target any code address in the range of 64 Ki words ๐Ÿ’œ

To make indirect jumps work on devices with more than 128 Ki bytes of program memory space, there's a special function register called EIND ๐Ÿ‘‘ It serves as the most significant part of the target address when EICALL or EIJMP instructions are used.

Indirect jumps and calls on these devices are handled like this by the compiler, and they come with some limitations ๐Ÿซถ

  • The compiler never sets EIND. ๐Ÿ™…โ€โ™€๏ธ
  • The compiler uses EIND implicitly in EICALL/EIJMP instructions, or it might read EIND directly to emulate an indirect call/jump by means of 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 ๐Ÿ˜ฌ
  • 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 such a stub ๐ŸŒ‰ The stub contains a direct jump to the desired address.
  • 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. There are corner cases where the linker is supposed to generate stubs but aborts without relaxation and without a helpful error message ๐Ÿ’€
  • The default linker script is arranged for code with EIND = 0. If your code is supposed to work with EIND != 0, you need a custom linker script to place the sections whose names start with .trampolines into the segment 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, see the AVR-LibC user manual (http://nongnu.org/avr-libc/user-manual/) ๐Ÿ“–
  • It's totally legit for user-specific startup code to set up EIND early, for example with initialization code located in section .init3 ๐Ÿงš That code runs before 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 the address of a function or code label.
    • Computed goto.
    • If the prologue-save function is used, see the -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 so 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();
}

Then the application needs to 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 โœจ

So, the RAMP thing is kinda wild, bestie ๐Ÿ’พโœจ Some AVR devices have more memory than the 64 KiB you can reach with 16-bit pointers. To get past that, the contents of a RAMP register act as the high part of the address. The X, Y, Z address register gets glued onto RAMPX, RAMPY, RAMPZ respectively to make one wide address ๐Ÿฆ‹. RAMPD does the same job for direct addressing.

  • Startup vibes โ€” The startup code sets the RAMP special function registers to zero ๐ŸŒฑ.
  • Named address spaces โ€” If a named address space from AVR Named Address Spaces is used (anything other than generic or __flash), RAMPZ gets set as needed before the operation ๐Ÿ’….
  • Reset after the drama โ€” If the device supports RAM larger than 64 KiB and the compiler has to change RAMPZ to pull off an operation, RAMPZ gets reset to zero afterwards ๐Ÿงน.
  • ISR glow-up โ€” If the device comes with a specific RAMP register, the ISR prologue/epilogue saves and restores that SFR, and sets it to zero in case the ISR code might (implicitly) use it ๐Ÿ›ก๏ธ.
  • The big no โ€” RAM larger than 64 KiB is not supported by GCC for AVR targets ๐Ÿ™…โ€โ™€๏ธ
Warning, bestie: 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. No skipping this step ๐Ÿ’€

๐ŸŽ€ AVR Built-in Macros ๐ŸŽ€

Okay so GCC defines a bunch of built-in macros so your code can check whether a feature is there or not ๐Ÿ”. Almost every one of the following built-in macros is deduced from device capabilities, which means they get 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__ โ€” A built-in macro that resolves to a decimal number identifying the architecture. 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 to perform 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__ / __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 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__ / __AVR_HAVE_16BIT_SP__ โ€” The stack pointer (SP) register is treated by the compiler as an 8-bit or 16-bit register, respectively. The definition of these macros is affected by -mtiny-stack ๐Ÿฅž.
  • __AVR_HAVE_SPH__ / __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__ / __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__ / __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 accessing RAM, like LD or STS. This offset depends on the device architecture and has to be subtracted from the RAM address to get the respective I/O address ๐Ÿงฎ.
  • __AVR_SHORT_CALLS__ โ€” The -mshort-calls command-line option is set ๐Ÿ“ž.
  • __AVR_PM_BASE_ADDRESS__=addr โ€” Some devices support reading from flash memory with LD* instructions. The flash memory is seen in the data address space at an offset of __AVR_PM_BASE_ADDRESS__. If this macro is not defined, this feature is not available. If it is defined, the address space is linear and there's no need to put .rodata into RAM. This is handled by the default linker description file, and is currently available for avrtiny and avrxmega3. Even more convenient, there's no need to use address spaces like __flash or features like attribute progmem and pgm_read_* ๐Ÿซถ.
  • __WITH_AVRLIBC__ โ€” The compiler is configured to be used together with AVR-Libc. See the --with-avrlibc configure option ๐Ÿ“š.
  • __HAVE_DOUBLE_MULTILIB__ โ€” Defined if -mdouble= acts as a multilib option.
  • __HAVE_DOUBLE32__ / __HAVE_DOUBLE64__ โ€” Defined if the compiler supports 32-bit double or 64-bit double, respectively. The actual layout is specified by option -mdouble=.
  • __DEFAULT_DOUBLE__ โ€” The size in bits of double if -mdouble= is not set. To test the layout of double in a program, use the built-in macro __SIZEOF_DOUBLE__ ๐Ÿ“.
  • __HAVE_LONG_DOUBLE32__ / __HAVE_LONG_DOUBLE64__ / __HAVE_LONG_DOUBLE_MULTILIB__ / __DEFAULT_LONG_DOUBLE__ โ€” Same as above, but for long double instead of double ๐ŸŒˆ.
  • __WITH_DOUBLE_COMPARISON__ โ€” Reflects the --with-double-comparison={tristate|bool|libf7} configure option (https://gcc.gnu.org/install/configure.html#avr) and is defined to 2 or 3 ๐Ÿ”.
  • __WITH_LIBF7_LIBGCC__ / __WITH_LIBF7_MATH__ / __WITH_LIBF7_MATH_SYMBOLS__ โ€” Reflects the --with-libf7={libgcc|math|math-symbols} configure option (https://gcc.gnu.org/install/configure.html#avr) ๐Ÿ’œ.

๐Ÿฆ‹ Blackfin Options ๐Ÿฆ‹

  • -mcpu=cpu[-sirevision] โ€” Specifies the name of the target Blackfin processor. Currently, 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, bf592 ๐Ÿ“.

The optional sirevision specifies the silicon revision of the target Blackfin processor. Any workarounds available for that revision are enabled. If sirevision is none, no workarounds are enabled. If sirevision is any, all workarounds for the targeted processor are enabled. The __SILICON_REVISION__ macro is defined to two hexadecimal digits representing the major and minor numbers in the silicon revision. If sirevision is none, __SILICON_REVISION__ is not defined. If sirevision is any, __SILICON_REVISION__ is defined to be 0xffff. If this optional sirevision is not used, 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 be linked in if -msim is not given ๐Ÿ”—.

Without this option, bf532 is used as the processor by default.

Note that support for bf561 is incomplete. For bf561, only the preprocessor macro is defined.
  • -msim โ€” Specifies that the program will be run on the simulator. This causes the simulator BSP provided by libgloss to be linked in. This option has effect only for the bfin-elf toolchain. Certain other options, such as -mid-shared-library and -mfdpic, imply -msim ๐ŸŽฎ.
  • -momit-leaf-frame-pointer โ€” Don't keep the frame pointer in a register for leaf functions. This avoids the instructions to save, set up and restore frame pointers, and makes an extra register available in leaf functions ๐ŸŒฟ.
  • -mspecld-anomaly โ€” When enabled, the compiler ensures that the generated code does not 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 prevent speculative loads from occurring.
  • -mcsync-anomaly โ€” When enabled, the compiler ensures that the generated code does not 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 prevent CSYNC or SSYNC instructions from occurring 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 that the program is arbitrarily large. This is the default.

Wait, I need to pause. Looking at what I've been asked to do: this part is the continuation of a rewrite, and I'm supposed to carry on from part 79 without a greeting. Let me produce the rewritten content for this section.

Okay bestie, let's get into the Blackfin and C6X stuff ๐Ÿ’–

Actually, I need to be honest with you about what's happening here. I don't have the earlier parts of this rewrite in front of me, so I can't tell which heading level or section this part picks up in. The text you pasted starts mid-way through the OPTIONS section, and it begins with -mno-low64k, which is a Blackfin option. Because I can't confirm the surrounding context, I'll keep the rewrite to exactly what's in this excerpt and carry on from there without re-adding headings that may already exist.

Here is the rewrite of this part:

  • -mno-low64k โ€” okay so this one's the default vibe ๐ŸŒธ It assumes your program is arbitrarily large, which is just how it already works, no cap โœจ
  • -mstack-check-l1 โ€” bestie, this one does stack checking using the info the uClinux kernel drops into L1 scratchpad memory ๐Ÿฆ‹
  • -mid-shared-library โ€” generates code that supports shared libraries through the library ID method ๐ŸŽ€ This lets you do execute in place and shared libraries even without virtual memory management ๐Ÿ’… It implies -fPIC, and with a bfin-elf target it also implies -msim ๐Ÿ”ฅ
  • -mno-id-shared-library โ€” code that doesn't assume ID-based shared libraries are in use ๐Ÿ’œ This is the default, periodt ๐Ÿ’€
  • -mleaf-id-shared-library โ€” still uses 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 won't link against any ID shared libraries ๐Ÿ™ˆ You get slower code for jump and call instructions ๐Ÿ˜ญ
  • -mshared-library-id=n โ€” sets the identification number of the ID-based shared library being compiled ๐Ÿ“ A value of 0 gives you more compact code ๐Ÿซถ Other values force that number onto the current library, but it's no more space- or time-efficient than leaving this option out ๐Ÿ’–
  • -msep-data โ€” lets the data segment live in a different area of memory from the text segment ๐ŸŒˆ This enables execute in place without virtual memory management, because it gets rid of relocations against the text section โœจ
  • -mno-sep-data โ€” assumes the data segment follows the text segment ๐Ÿฉท This is the default โญ
  • -mlong-calls / -mno-long-calls โ€” makes function calls by loading the function's address into a register first, then calling through that register ๐Ÿ‘‘ You need this if the target function is outside the 24-bit addressing range of the offset-based subroutine call instruction ๐Ÿฆ‹ It's not on by default, and -mno-long-calls puts you back to the default ๐Ÿ’… These switches don't change how function calls through function pointers are generated ๐Ÿ™ˆ
  • -mfast-fp โ€” links with the fast floating-point library ๐Ÿ”ฅ It relaxes some IEEE floating-point rules for checking inputs against Not-a-Number (NAN), for performance ๐Ÿ’จ
  • -minline-plt โ€” enables inlining of PLT entries for function calls to functions that aren't known to bind locally ๐Ÿงš It does nothing without -mfdpic ๐Ÿ’€
  • -mmulticore โ€” builds a standalone application for multicore Blackfin processors ๐Ÿ‘‘ It uses the right start files and link scripts for multicore and defines the macro "__BFIN_MULTICORE" ๐ŸŽ€ It can only be used with -mcpu=bf561[-sirevision] ๐ŸŒธ

This also works with -mcorea or -mcoreb for the one-application-per-core model ๐Ÿซถ Without either of those, you get the single-application/dual-core model ๐Ÿ’œ In that model, Core B's main function should be named "coreb_main" ๐Ÿงš

Without this option, you get the single-core application model โœจ

  • -mcorea โ€” builds a standalone application for Core A of BF561 in the one-application-per-core model ๐Ÿฆ‹ It uses the right start files and link scripts for Core A and defines "__BFIN_COREA" ๐Ÿ’… It can only be used together with -mmulticore ๐Ÿ”ฅ
  • -mcoreb โ€” builds a standalone application for Core B of BF561 in the one-application-per-core model ๐Ÿ’– It uses the right start files and link scripts for Core B and defines "__BFIN_COREB" ๐ŸŒˆ With this on, use "coreb_main" instead of "main" ๐Ÿ‘‘ It can only be used together with -mmulticore ๐Ÿ’€
  • -msdram โ€” builds a standalone application for SDRAM ๐Ÿ“ It uses the right start files and link scripts to put the app into SDRAM and defines "__BFIN_SDRAM" ๐Ÿฆ‹ The loader needs to initialize SDRAM before loading the app ๐Ÿ˜ญ
  • -micplb โ€” assumes ICPLBs are enabled at run time ๐ŸŽ€ This affects 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 โ€” picks the target architecture name ๐ŸŒธ GCC uses it to decide what kind of instructions it can emit when generating assembly ๐Ÿงš The allowed names are c62x, c64x, c64x+, c67x, c67x+, and c674x ๐Ÿ’…
  • -mbig-endian โ€” generates code for a big-endian target ๐Ÿซถ
  • -mlittle-endian โ€” generates code for a little-endian target ๐Ÿ’– This is the default โœจ
  • -msim โ€” picks startup files and a linker script that work with the simulator ๐Ÿ”ฅ
  • -msdata=default โ€” puts small global and static data in the ".neardata" section, which is pointed to by register B14 ๐ŸŒˆ Small uninitialized global and static data goes in ".bss", which sits right next to ".neardata" ๐Ÿฆ‹ Small read-only data goes in ".rodata" ๐Ÿ‘‘ Large data uses ".fardata", ".far", and ".const" instead ๐Ÿ’€
  • -msdata=all โ€” puts all data, not just the small stuff, into the small-data sections ๐Ÿ“ It uses addressing relative to the B14 register to get at it ๐Ÿ˜ญ
  • -msdata=none โ€” no small-data sections at all ๐ŸŽ€ Everything gets absolute addresses ๐Ÿ™ˆ All initialized global and static data goes in ".fardata", all uninitialized data goes in ".far", and all constant data goes in ".const" โญ

โœจ CRIS Options โœจ

These options are defined specifically for the CRIS ports ๐Ÿ’œ

  • -march=architecture-type / -mcpu=architecture-type โ€” generates code for the specified architecture ๐Ÿงš The choices are v3, v8, and v10, which are ETRAX 4, ETRAX 100, and ETRAX 100 LX ๐ŸŒธ The default is v0 ๐Ÿ’…
  • -mtune=architecture-type โ€” tunes everything applicable about the generated code to that architecture ๐Ÿซถ It doesn't touch the ABI or the set of available instructions ๐Ÿ”ฅ The choices are the same as for -march=architecture-type ๐Ÿ’–
  • -mmax-stack-frame=n โ€” warns when a function's stack frame goes over n bytes โš ๏ธ
  • -metrax4 / -metrax100 โ€” these are synonyms for -march=v3 and -march=v8 respectively ๐ŸŒˆ
  • -mmul-bug-workaround / -mno-mul-bug-workaround โ€” works around a bug in the "muls" and "mulu" instructions on CPU models where it applies ๐Ÿฆ‹ This is active by default ๐Ÿ‘‘
  • -mpdebug โ€” turns on CRIS-specific verbose debug info in the assembly code ๐Ÿ’€ It also turns off the #NO_APP formatted-code indicator that the assembler normally sees at the top of the assembly file ๐Ÿ“
  • -mcc-init โ€” don't reuse condition-code results from previous instructions ๐Ÿ˜ญ Always emit compare and test instructions before using condition codes ๐ŸŽ€
  • -mno-side-effects โ€” don't emit instructions with side effects in addressing modes, except post-increment ๐Ÿ™ˆ
  • -mstack-align / -mno-stack-align / -mdata-align / -mno-data-align / -mconst-align / -mno-const-align โ€” these arrange (or, with the no- forms, un-arrange) alignment of the stack frame, individual data, and constants to the maximum single data access size for the chosen CPU model โญ The default is 32-bit alignment ๐Ÿ’œ ABI details like structure layout aren't affected by these ๐Ÿงš
  • -m32-bit / -m16-bit / -m8-bit โ€” like the stack, data, and const align options above, these make the stack frame, writable data, and constants 32-bit, 16-bit, or 8-bit aligned ๐ŸŒธ The default is 32-bit alignment ๐Ÿ’…
  • -mno-prologue-epilogue / -mprologue-epilogue โ€” with -mno-prologue-epilogue, the normal function prologue and epilogue that set up the stack frame are left out, and no return instructions or return sequences are generated ๐Ÿ’€ Only use this alongside careful visual inspection of the compiled code ๐Ÿ˜ญ No warnings or errors are generated when call-saved registers need saving or local variable storage needs allocating ๐Ÿ™ˆ
  • -melf โ€” legacy no-op option ๐Ÿซถ
  • -sim โ€” links with input-output functions from a simulator library ๐Ÿ”ฅ Code, initialized data, and zero-initialized data get allocated consecutively ๐ŸŒˆ
  • -sim2 โ€” like -sim, but also passes linker options to put initialized data at 0x40000000 and zero-initialized data at 0x80000000 ๐Ÿ‘‘

โœจ CR16 Options โœจ

These options are defined specifically for the CR16 ports ๐Ÿฆ‹

  • -mmac โ€” enables multiply-accumulate instructions ๐Ÿ’… It's disabled by default ๐Ÿ™ˆ
  • -mcr16cplus / -mcr16c โ€” generates code for the CR16C or CR16C+ architecture ๐Ÿ’– CR16C+ is the default ๐ŸŒธ
  • -msim โ€” links the library libsim.a, which is compatible with the simulator ๐Ÿงš Only applies to the ELF compiler ๐Ÿ”ฅ
  • -mint32 โ€” chooses a 32-bit wide integer type ๐Ÿ’œ
  • -mbit-ops โ€” generates "sbit" and "cbit" instructions for bit manipulation โœจ
  • -mdata-model=model โ€” chooses a data model ๐ŸŽ€ The choices are near, far, or medium, and medium is the default ๐Ÿฆ‹ far isn't valid with -mcr16c, because the CR16C architecture doesn't support the far data model ๐Ÿ’€

โœจ C-SKY Options โœจ

GCC supports these options when compiling for C-SKY V2 processors ๐ŸŒˆ

  • -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 โ€” okay bestie, this one lets you pick your C-SKY target processor ๐Ÿฆ‹ The valid cpu values are below, and yes, it's a long list, but every single one is iconic:
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,
ck810ftv.
  • -mbig-endian, -EB, -mlittle-endian, -EL โ€” pick big-endian or little-endian code ๐ŸŒธ Little-endian is the default, so if you do nothing, you're already serving โœจ
  • -mfloat-abi=name โ€” this one picks which floating-point ABI you're rocking ๐Ÿ‘‘ The permissible values are soft, softfp, and hard:
    • soft โ€” GCC generates output full of library calls for floating-point operations
    • softfp โ€” you get hardware floating-point instructions, but it still uses the soft-float calling conventions
    • hard โ€” you get floating-point instructions and FPU-specific calling conventions

The default depends on your specific target configuration ๐ŸŽ€ Also, heads up, the hard-float and soft-float ABIs are not link-compatible ๐Ÿ˜ญ You have to compile your entire program with the same ABI, and link it with a compatible set of libraries.

  • -mhard-float, -msoft-float โ€” choose hardware or software floating-point implementations ๐Ÿ’– The default is soft float.
  • -mdouble-float, -mno-double-float โ€” when -mhard-float is in effect, this turns on double-precision float instructions ๐Ÿ”ฅ It's the default except when you're compiling for CK803.
  • -mfdivdu, -mno-fdivdu โ€” when -mhard-float is in effect, this enables the "frecipd", "fsqrtd", and "fdivd" instructions ๐Ÿงš Also the default except for CK803.
  • -mfpu=fpu โ€” pick your floating-point processor ๐Ÿฆ‹ This only works with -mhard-float. The values for fpu are:
    • fpv2_sf โ€” equivalent to -mno-double-float -mno-fdivdu
    • fpv2 โ€” equivalent to -mdouble-float -mno-divdu
    • fpv2_divd โ€” equivalent to -mdouble-float -mdivdu
  • -melrw, -mno-elrw โ€” enable the extended "lrw" instruction ๐Ÿ’… It defaults to on for CK801 and off for everything else.
  • -mistack, -mno-istack โ€” enable interrupt stack instructions. The default is off ๐ŸŒˆ You need -mistack to handle the "interrupt" and "isr" function attributes, so don't skip it, bestie ๐Ÿซถ
  • -mmp โ€” enable multiprocessor instructions. Default is off โญ
  • -mcp โ€” enable coprocessor instructions. Default is off ๐Ÿ“
  • -mcache โ€” also enables coprocessor instructions, so yes, it's the same vibe as -mcp ๐Ÿ™ˆ Default is off.
  • -msecurity โ€” enable C-SKY security instructions. Default is off ๐Ÿ”ฅ
  • -mtrust โ€” enable C-SKY trust instructions. Default is off ๐Ÿ’œ
  • -mdsp, -medsp, -mvdsp โ€” these enable C-SKY DSP, Enhanced DSP, or Vector DSP instructions, respectively โœจ All of them default to off.
  • -mdiv, -mno-div โ€” generate divide instructions ๐Ÿฆ‹ Default is off.
  • -msmart, -mno-smart โ€” generate code for Smart Mode, which only uses registers numbered 0-7 so you can use those sweet 16-bit instructions ๐Ÿซถ This is ignored for CK801, where it's already required behavior. It defaults to on for CK802. For other targets, it's off.
  • -mhigh-registers, -mno-high-registers โ€” generate 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 โ€” generate code using global anchor symbol addresses ๐Ÿงš
  • -mpushpop, -mno-pushpop โ€” generate code using "push" and "pop" instructions ๐Ÿ’– This defaults to on.
  • -mmultiple-stld, -mstm, -mno-multiple-stld, -mno-stm โ€” generate code using "stm" and "ldm" instructions ๐ŸŽ€ This isn't supported on CK801, but it's enabled by default on other processors.
  • -mconstpool, -mno-constpool โ€” create constant pools in the compiler instead of handing that job off to the assembler ๐Ÿ’… This is the default and is required for correct code generation on CK801 and CK802. On other processors it's optional.
  • -mstack-size, -mno-stack-size โ€” emit ".stack_size" directives for each function in the assembly output ๐Ÿ“ This defaults to off.
  • -mccrt, -mno-ccrt โ€” generate code for the C-SKY compiler runtime instead of libgcc ๐ŸŒˆ This defaults to off.
  • -mbranch-cost=n โ€” set the branch costs to roughly "n" instructions โญ The default is 1.
  • -msched-prolog, -mno-sched-prolog โ€” permit scheduling of function prologue and epilogue sequences ๐Ÿ™ˆ Heads up, though:
Using this option can result in code that is not compliant with the C-SKY V2 ABI prologue requirements, and that code cannot be debugged or backtraced ๐Ÿ’€ It's disabled by default, so only turn it on if you really know what you're doing.
  • -msim โ€” links the library libsemi.a, which is compatible with the simulator ๐Ÿงš This only applies to the ELF compiler.

๐ŸŽ Darwin Options ๐ŸŽ

These options are defined for all architectures running the Darwin operating system ๐Ÿ’–

Okay, so, FSF GCC on Darwin does not create "fat" object files. Instead, it makes an object file for the single architecture GCC was built to target. Apple's GCC, though, does create "fat" files if you use multiple -arch options. It does this by running the compiler or linker multiple times and then joining the results together with lipo ๐Ÿฆ‹

The subtype of the file that gets created (like ppc7400, ppc970, or i686) is decided by the flags that specify the ISA GCC is targeting, like -mcpu or -march. If you want to override that, the -force_cpusubtype_ALL option is your friend โœจ

The Darwin tools are kind of inconsistent when they hit an ISA mismatch ๐Ÿ’€ The assembler, as, only allows instructions that are valid for the subtype of the file it's generating. So you can't put 64-bit instructions in a ppc750 object file. The linker for shared libraries, /usr/bin/libtool, fails and prints an error if you ask it to create a shared library with a less restrictive subtype than its input files. For example, trying to put 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 head of the list of directories searched for header files ๐ŸŒธ These directories are interleaved with the ones from -I options, and they're scanned in a left-to-right order.

A framework directory is just a directory with frameworks in it. A framework is a directory that has a Headers and/or PrivateHeaders directory sitting directly inside it, and its name ends in .framework. The name of the framework is the directory name without the .framework part. Headers for the framework are found in one of those two directories, with Headers getting searched first ๐ŸŽ€

A subframework is a framework directory that lives inside a framework's Frameworks directory. Includes of subframework headers can only show up in a header of the framework that contains the subframework, or in a sibling subframework header. Two subframeworks are siblings if they live in the same framework ๐Ÿ‘ฏ A subframework shouldn't share a name with a framework, and if it does, you'll get a warning. Right now a subframework can't have subframeworks of its own, but the mechanism might be extended to support that later ๐Ÿ‘€

The standard frameworks live in /System/Library/Frameworks and /Library/Frameworks. An example include looks like "#include <Framework/header.h>", where Framework is the framework's name and header.h is found in the PrivateHeaders or Headers directory ๐Ÿ’…

  • -iframeworkdir โ€” this is like -F, except the directory is treated as a system directory ๐Ÿงš The big difference is that with -iframework, the compiler doesn't warn about constructs inside header files found through dir. This option is only valid for the C family of languages.
  • -gused โ€” emit debugging information for symbols that are used ๐Ÿ” For the stabs debugging format, this enables -feliminate-unused-debug-symbols. It's ON by default.
  • -gfull โ€” emit debugging information for all symbols and types ๐ŸŒˆ
  • -fconstant-cfstrings โ€” this is just an alias for -mconstant-cfstrings ๐Ÿฆ‹
  • -mconstant-cfstrings โ€” when the NeXT runtime is being used (which is the default on these systems), this overrides any -fconstant-string-class setting. It also makes "@"..."" literals laid out as constant CoreFoundation strings ๐Ÿ’–
  • -mmacosx-version-min=version โ€” sets the earliest version of MacOS X this executable will run on ๐ŸŽ Typical values for version include 12, 10.12, and 10.5.8.

If the compiler was built to use the system's headers by default, then the default for this option is the system version the compiler is running on. Otherwise, the default makes choices that are compatible with as many systems and code bases as possible โœจ

  • -mkernel โ€” enables kernel development mode ๐Ÿซถ The -mkernel option sets -static, -fno-common, -fno-use-cxa-atexit, -fno-exceptions, -fno-non-call-exceptions, -fapple-kext, -fno-weak, and -fno-rtti, where applicable. This mode also sets -mno-altivec, -msoft-float, -fno-builtin, and -mlong-branch for PowerPC targets ๐Ÿ”ฅ
  • -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 has no effect on x86.
Warning: -mone-byte-bool makes GCC generate code that is not binary compatible with code generated without that switch ๐Ÿ˜ญ Using it may mean you have to recompile all the other modules in your program, including system libraries. Only use it to conform to a non-default data model.
  • -mfix-and-continue, -ffix-and-continue, -findirect-data โ€” generate code that's suitable for fast turnaround development ๐Ÿ”ฅ This lets things like GDB dynamically load .o files into already-running programs. -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 the errors about files with the wrong architecture fatal ๐Ÿ’€
  • -bind_at_load โ€” โœจ Marks the output file so the dynamic linker binds every undefined reference when the file gets loaded or launched. Bestie, that's a whole vibe ๐Ÿฆ‹
  • -bundle โ€” ๐ŸŽ€ Produces a Mach-O bundle format file. Check man ld(1) for the tea on this one ๐Ÿ“
  • -bundle_loader executable โ€” ๐Ÿงš Names the executable that's going to load the output file being linked. Also in man ld(1) ๐Ÿ’œ
  • -dynamiclib โ€” ๐ŸŒˆ Makes a dynamic library instead of an executable when linking, using the Darwin libtool command. Iconic ๐Ÿ‘‘
  • -force_cpusubtype_ALL โ€” ๐Ÿ’… Gives GCC's output file the ALL subtype, instead of the one -mcpu or -march would pick. Not me overriding the vibe ๐Ÿ’€

Okay so next up is the big squad of Darwin linker options. Each one gets handed straight over to the linker, no cap:

  • -allowable_client client_name โ€” ๐ŸŒธ passed straight through to the Darwin linker
  • -client_name โ€” ๐ŸŒธ passed straight through to the Darwin linker
  • -compatibility_version โ€” ๐ŸŒธ passed straight through to the Darwin linker
  • -current_version โ€” ๐ŸŒธ passed straight through to the Darwin linker
  • -dead_strip โ€” ๐ŸŒธ passed straight through to the Darwin linker
  • -dependency-file โ€” ๐ŸŒธ passed straight through to the Darwin linker
  • -dylib_file โ€” ๐ŸŒธ passed straight through to the Darwin linker
  • -dylinker_install_name โ€” ๐ŸŒธ passed straight through to the Darwin linker
  • -dynamic โ€” ๐ŸŒธ passed straight through to the Darwin linker
  • -exported_symbols_list โ€” ๐ŸŒธ passed straight through to the Darwin linker
  • -filelist โ€” ๐ŸŒธ passed straight through to the Darwin linker
  • -flat_namespace โ€” ๐ŸŒธ passed straight through to the Darwin linker
  • -force_flat_namespace โ€” ๐ŸŒธ passed straight through to the Darwin linker
  • -headerpad_max_install_names โ€” ๐ŸŒธ passed straight through to the Darwin linker
  • -image_base โ€” ๐ŸŒธ passed straight through to the Darwin linker
  • -init โ€” ๐ŸŒธ passed straight through to the Darwin linker
  • -install_name โ€” ๐ŸŒธ passed straight through to the Darwin linker
  • -keep_private_externs โ€” ๐ŸŒธ passed straight through to the Darwin linker
  • -multi_module โ€” ๐ŸŒธ passed straight through to the Darwin linker
  • -multiply_defined โ€” ๐ŸŒธ passed straight through to the Darwin linker
  • -multiply_defined_unused โ€” ๐ŸŒธ passed straight through to the Darwin linker
  • -noall_load โ€” ๐ŸŒธ passed straight through to the Darwin linker
  • -no_dead_strip_inits_and_terms โ€” ๐ŸŒธ passed straight through to the Darwin linker
  • -nofixprebinding โ€” ๐ŸŒธ passed straight through to the Darwin linker
  • -nomultidefs โ€” ๐ŸŒธ passed straight through to the Darwin linker
  • -noprebind โ€” ๐ŸŒธ passed straight through to the Darwin linker
  • -noseglinkedit โ€” ๐ŸŒธ passed straight through to the Darwin linker
  • -pagezero_size โ€” ๐ŸŒธ passed straight through to the Darwin linker
  • -prebind โ€” ๐ŸŒธ passed straight through to the Darwin linker
  • -prebind_all_twolevel_modules โ€” ๐ŸŒธ passed straight through to the Darwin linker
  • -private_bundle โ€” ๐ŸŒธ passed straight through to the Darwin linker
  • -read_only_relocs โ€” ๐ŸŒธ passed straight through to the Darwin linker
  • -sectalign โ€” ๐ŸŒธ passed straight through to the Darwin linker
  • -sectobjectsymbols โ€” ๐ŸŒธ passed straight through to the Darwin linker
  • -whyload โ€” ๐ŸŒธ passed straight through to the Darwin linker
  • -seg1addr โ€” ๐ŸŒธ passed straight through to the Darwin linker
  • -sectcreate โ€” ๐ŸŒธ passed straight through to the Darwin linker
  • -sectorder โ€” ๐ŸŒธ passed straight through to the Darwin linker
  • -segaddr โ€” ๐ŸŒธ passed straight through to the Darwin linker
  • -segs_read_only_addr โ€” ๐ŸŒธ passed straight through to the Darwin linker
  • -segs_read_write_addr โ€” ๐ŸŒธ passed straight through to the Darwin linker
  • -seg_addr_table โ€” ๐ŸŒธ passed straight through to the Darwin linker
  • -seg_addr_table_filename โ€” ๐ŸŒธ passed straight through to the Darwin linker
  • -seglinkedit โ€” ๐ŸŒธ passed straight through to the Darwin linker
  • -segprot โ€” ๐ŸŒธ passed straight through to the Darwin linker
  • -single_module โ€” ๐ŸŒธ passed straight through to the Darwin linker
  • -static โ€” ๐ŸŒธ passed straight through to the Darwin linker
  • -sub_library โ€” ๐ŸŒธ passed straight through to the Darwin linker
  • -sub_umbrella โ€” ๐ŸŒธ passed straight through to the Darwin linker
  • -twolevel_namespace โ€” ๐ŸŒธ passed straight through to the Darwin linker
  • -umbrella โ€” ๐ŸŒธ passed straight through to the Darwin linker
  • -undefined โ€” ๐ŸŒธ passed straight through to the Darwin linker
  • -unexported_symbols_list โ€” ๐ŸŒธ passed straight through to the Darwin linker
  • -weak_reference_mismatches โ€” ๐ŸŒธ passed straight through to the Darwin linker
  • -whatsloaded โ€” ๐ŸŒธ passed straight through to the Darwin linker

These are all passed to the Darwin linker, and the Darwin linker's man page describes them in detail. Read that one if you want the full story ๐Ÿซถ

โœจ DEC Alpha Options โœจ

These -m options are defined for the DEC Alpha implementations ๐Ÿงš

  • -mno-soft-float, -msoft-float โ€” ๐Ÿ’– Use (or don't use) the hardware floating-point instructions for floating-point operations. With -msoft-float, functions in libgcc.a do the floating-point work. Unless they're swapped out for routines that emulate those operations, or compiled to call such emulation routines, these routines 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 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 optimized for maximum performance. It's mostly compliant with the IEEE floating-point standard, but full compliance needs software help. This option generates fully IEEE-compliant code, except the inexact-flag isn't maintained (see below). When it's on, the preprocessor macro "_IEEE_FP" gets defined during compilation. The result 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 ๐Ÿ™ˆ
DEBIAN SPECIFIC: This option is on by default for alpha-linux-gnu, unless -ffinite-math-only (which is part of the -ffast-math set) is specified. The reason is that the software functions in the GNU libc math libraries generate denormalized numbers, NaNs, and infs, and all of those will cause a program to SIGFPE when it tries to use the results without -mieee ๐Ÿ’€
  • -mieee-with-inexact โ€” ๐Ÿงš This is like -mieee, except the generated code also maintains the IEEE inexact-flag. Turning this on makes the generated code fully-compliant IEEE math. On top of "_IEEE_FP", the macro "_IEEE_FP_EXACT" gets defined too. On some Alpha implementations the resulting code may run significantly slower than the default. Since very little code depends on the inexact-flag, you should normally not specify this option ๐Ÿซถ Other Alpha compilers call it -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 โ€” ๐Ÿ’– The default, normal setting. The only traps enabled are the ones that can't be disabled in software (like the division by zero trap).
    • u โ€” ๐ŸŒธ On top of everything n enables, underflow traps are enabled too.
    • su โ€” ๐Ÿฆ‹ Like u, but the instructions are marked as safe for software completion (check 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 get rounded towards the nearest machine number, or towards the even machine number in case of a tie.
    • m โ€” ๐Ÿ“ Round towards minus infinity.
    • c โ€” ๐Ÿงš Chopped rounding mode. Floating-point numbers get rounded towards zero.
    • d โ€” ๐ŸŒˆ Dynamic rounding mode. A field in the floating-point control register (fpcr, see the Alpha architecture reference manual) controls which rounding mode is in effect. The C library initializes this register for rounding towards plus infinity, so unless your program modifies the fpcr, d corresponds to round towards plus infinity ๐Ÿ‘‘
  • -mtrap-precision=trap-precision โ€” ๐Ÿ˜ญ In the Alpha architecture, floating-point traps are imprecise. That means without software help 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 pick different levels of precision:
    • p โ€” ๐ŸŒธ Program precision. This is the default, and it means a trap handler can only identify which program caused a floating-point exception.
    • f โ€” ๐Ÿฆ‹ Function precision. The trap handler can determine the function that caused a floating-point exception.
    • i โ€” ๐Ÿ’– Instruction precision. The trap handler can determine the exact instruction that caused a floating-point exception.

Other Alpha compilers provide the equivalent options called -scope_safe and -resumption_safe ๐Ÿซถ

  • -mieee-conformant โ€” ๐Ÿ’œ Marks the generated code as IEEE conformant. You must not use this option unless you also specify -mtrap-precision=i and either -mfp-trap-mode=su or -mfp-trap-mode=sui. Its only effect is to emit the line .eflag 48 in the function prologue of the generated assembly file ๐ŸŽ€
  • -mbuild-constants โ€” ๐Ÿงš Normally GCC examines a 32- or 64-bit integer constant to see if 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 to load it from the data segment at run time.

Use this option to require GCC to build all integer constants using code, even if it takes more instructions (the maximum is six) ๐ŸŒˆ

You typically use this option to build a shared library dynamic loader. Since it's a shared library itself, 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 โ€” ๐Ÿ’… Indicate whether GCC should generate code that uses the optional BWX, CIX, FIX and MAX instruction sets. The default is to use the instruction sets supported by the CPU type you specify with the -mcpu= option, or by the CPU GCC was built on if you don't specify one โœจ
  • -mfloat-vax, -mfloat-ieee โ€” ๐ŸŒธ Generates code that uses (or doesn't use) VAX F and G floating-point arithmetic instead of IEEE single and double precision ๐Ÿฆ‹
  • -mexplicit-relocs, -mno-explicit-relocs โ€” ๐Ÿ“ 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 supports 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 to match ๐Ÿงš
  • -msmall-data, -mlarge-data โ€” ๐Ÿ’œ When -mexplicit-relocs is in effect, static data is accessed via gp-relative relocations. When -msmall-data is used, objects 8 bytes long or smaller get placed in a small data area (the ".sdata" and ".sbss" sections) and are accessed via 16-bit relocations off of the $gp register. This limits the size of the small data area to 64KB, but lets the variables be accessed directly with a single instruction ๐Ÿ’–

The default is -mlarge-data. With this option the data area is limited to just below 2GB. Programs that need more than 2GB of data must use "malloc" or "mmap" to allocate the data in 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 ๐Ÿซถ

okay so these two are a whole size-vs-reach situation ๐Ÿซถ

  • -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 you use -msmall-data, the compiler can assume all local symbols share the same $gp value, which means a function call drops from 4 instructions to just 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 give the EV style name or the matching chip number. GCC has scheduling parameters for the EV4, EV5, and EV6 family, and it picks the default instruction set from whichever 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 with no instruction set extensions ๐ŸŒธ
  • ev5, 21164 โ€” schedules as an EV5 with 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 support the value native, which picks the best architecture option for the host processor ๐Ÿงš. -mcpu=native has no effect if GCC doesn't recognize the processor ๐Ÿ™ˆ.

  • -mtune=cpu_type โ€” sets only the instruction scheduling parameters for cpu_type. The instruction set doesn't change, so no vibe shift there ๐Ÿซถ.

Native toolchains also support the value native here too, which picks the best architecture option for the host processor. -mtune=native has no effect 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 really depends on the application's memory access patterns and how big the external cache on the machine is ๐Ÿ’€.

Valid options for time are:

  • number โ€” a decimal number representing clock cycles ๐Ÿ”ข
  • L1, L2, L3, main โ€” the compiler has estimates of clock cycles for "typical" EV4 & EV5 hardware, covering the Level 1, 2 & 3 caches (also called Dcache, Scache, and Bcache) and main memory ๐Ÿงš. Heads up that L3 is only valid for EV5 โš ๏ธ.

๐Ÿงš eBPF Options ๐Ÿงš

  • -mframe-limit=bytes โ€” sets the hard limit for frame sizes, in bytes ๐Ÿ“ฆ. Right now the value you pass should be less than or equal to 32767. It defaults to whatever limit the targeted version of the Linux kernel imposes ๐Ÿง.
  • -mkernel=version โ€” sets the minimum kernel version that will run your compiled program ๐Ÿง. GCC uses this to figure out which instructions to use, which kernel helpers to allow, and so on ๐Ÿค“. Right now version can be one of 4.0, 4.1, 4.2, 4.3, 4.4, 4.5, 4.6, 4.7, 4.8, 4.9, 4.10, 4.11, 4.12, 4.13, 4.14, 4.15, 4.16, 4.17, 4.18, 4.19, 4.20, 5.0, 5.1, 5.2, latest, or native ๐Ÿ’….
  • -mbig-endian โ€” generates code for a big-endian target ๐Ÿ“.
  • -mlittle-endian โ€” generates code for a little-endian target. This is the default ๐Ÿ’–.
  • -mxbpf โ€” generates code for an expanded version of BPF ๐ŸŒˆ. It relaxes some of the restrictions the BPF architecture normally imposes, including this bit: -<Save and restore callee-saved registers at function entry and> exit, respectively.

๐ŸŒธ FR30 Options ๐ŸŒธ

These options are defined specifically for the FR30 port ๐ŸŽ€.

  • -msmall-model โ€” uses the small address space model ๐Ÿฃ. It 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 is already 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. โš ๏ธ You must not use this option when generating programs that will run on 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 โ€” doesn't use div and mod instructions ๐Ÿ™….
  • -mft32b โ€” enables use of the extended instructions of the FT32B processor ๐Ÿš€.
  • -mcompress โ€” compresses all code using the Ft32B code compression scheme ๐Ÿ—œ๏ธ.
  • -mnopm โ€” doesn't generate 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 โ€” uses only 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 instead ๐Ÿ“š.
  • -malloc-cc โ€” dynamically allocates condition code registers ๐Ÿช„.
  • -mfixed-cc โ€” doesn't try to dynamically allocate condition code registers. It only uses icc0 and fcc0 ๐Ÿ“Œ.
  • -mdword โ€” changes the ABI to use double word instructions ๐Ÿงฉ.
  • -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 does nothing without -mfdpic. It's on by default if you're optimizing for speed and compiling shared libraries (i.e., -fPIC or -fpic), or when an optimization option like -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 on by default, except for -fpic or -fpie. Even though it may help make the global offset table smaller, it trades 1 instruction for 4 in those cases ๐Ÿค”. With -fPIC or -fPIE, it trades 3 instructions for 4, one of which may be shared by multiple symbols. It also avoids the need for a GOT entry for the referenced symbol, so it's more likely to be a win ๐Ÿ†. If it isn't, -mno-gprel-ro can be used to disable it ๐Ÿ™….
  • -multilib-library-pic โ€” links with the (library, not FD) pic libraries ๐Ÿ“š. It's implied by -mlibrary-pic, as well as 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 ๐Ÿ–ผ๏ธ. It's on by default and can be turned off with -mno-linked-fp โฌ‡๏ธ.
  • -mlong-calls โ€” uses indirect addressing to call functions outside the current compilation unit ๐Ÿ“ž. This lets the functions be placed anywhere within the 32-bit address space ๐ŸŒŒ.
  • -malign-labels โ€” tries to align labels to an 8-byte boundary by inserting NOPs into the previous packet ๐Ÿ“. This only does something when VLIW packing is enabled. It doesn't create new packets; it just adds NOPs to existing ones ๐Ÿง˜.
  • -mlibrary-pic โ€” generates position-independent EABI code ๐ŸŒ.
  • -macc-4 โ€” uses only the first four media accumulator registers 4๏ธโƒฃ.
  • -macc-8 โ€” uses all eight media accumulator registers 8๏ธโƒฃ.
  • -mpack โ€” packs VLIW instructions ๐Ÿ“ฆ.
  • -mno-pack โ€” doesn't pack VLIW instructions ๐Ÿ™….
  • -mno-eflags โ€” doesn't mark ABI switches in e_flags ๐Ÿšซ.
  • -mcond-move โ€” enables the use of conditional-move instructions. This is the default โœ….
๐Ÿ› This switch is mainly for debugging the compiler, and it'll likely be removed in a future version.
  • -mno-cond-move โ€” disables the use of conditional-move instructions ๐Ÿ™….
๐Ÿ› This switch is mainly for debugging the compiler, and it'll likely be removed in a future version.
  • -mscc โ€” enables the use of conditional set instructions. This is the default โœ….
๐Ÿ› This switch is mainly for debugging the compiler, and it'll likely be removed in a future version.
  • -mno-scc โ€” disables the use of conditional set instructions ๐Ÿ™….
๐Ÿ› This switch is mainly for debugging the compiler, and it'll likely be removed in a future version.
  • -mcond-exec โ€” enables the use of conditional execution. This is the default โœ….
๐Ÿ› This switch is mainly for debugging the compiler, and it'll likely be removed in a future version.
  • -mno-cond-exec โ€” disables the use of conditional execution ๐Ÿ™….
๐Ÿ› This switch is mainly for debugging the compiler, and it'll likely be removed in a future version.
  • -mvliw-branch โ€” runs a pass to pack branches into VLIW instructions. This is the default โœ….
๐Ÿ› This switch is mainly for debugging the compiler, and it'll likely be removed in a future version.
  • -mno-vliw-branch โ€” doesn't run a pass to pack branches into VLIW instructions ๐Ÿ™….
๐Ÿ› This switch is 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. This is the default โœ….
๐Ÿ› This switch is mainly for debugging the compiler, and it'll likely be removed in a future version.

โœจ Machine-Dependent Options, Part Two โœจ

  • -mno-multi-cond-exec โ€” bestie, this one turns OFF the optimization of "&&" and "||" in conditional execution ๐Ÿ™ˆ

This switch is mainly for debugging the compiler and will likely be removed in a future version, so don't build your whole life around it ๐Ÿ’€

  • -mnested-cond-exec โ€” turns ON nested conditional execution optimizations, and it's on by default ๐Ÿ’œ

Same deal: this one is mainly for compiler debugging and will likely get removed in a future version ๐Ÿงš

  • -mno-nested-cond-exec โ€” the opposite energy! It turns OFF nested conditional execution optimizations ๐Ÿฅฒ

Again, mainly a debugging tool, and it'll likely be removed in a future version โœจ

  • -moptimize-membar โ€” this one cleans up the clutter by removing redundant "membar" instructions from the compiler-generated code ๐Ÿงน It's enabled by default, so you're already getting this glow-up ๐Ÿฆ‹
  • -mno-optimize-membar โ€” the no-cap opt-out! It disables that automatic removal of redundant "membar" instructions from the generated code ๐Ÿ™…โ€โ™€๏ธ
  • -mtomcat-stats โ€” tells gas to print out tomcat statistics ๐Ÿฑ๐Ÿ“Š
  • -mcpu=cpu โ€” pick your processor type, the main character of the codegen ๐Ÿ‘‘ 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, so if you're on Linux it's giving relevant ๐Ÿง๐Ÿ’–

  • -mglibc โ€” use the GNU C library ๐Ÿ“š This is the default, except on *-*-linux-*uclibc*, *-*-linux-*musl* and *-*-linux-*android* targets ๐ŸŒˆ
  • -muclibc โ€” use the uClibc C library ๐ŸŽ€ This is the default on *-*-linux-*uclibc* targets ๐Ÿ’…
  • -mmusl โ€” use the musl C library ๐Ÿ“ This is the default on *-*-linux-*musl* targets โœจ
  • -mbionic โ€” use the Bionic C library ๐Ÿ“ฑ This is the default on *-*-linux-*android* targets ๐Ÿค–
  • -mandroid โ€” compile code that's compatible with the Android platform ๐Ÿฆ‹ This is the default on *-*-linux-*android* targets, and it's a whole vibe ๐Ÿ”ฅ

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 ๐Ÿ”— And finally, it causes the preprocessor macro "__ANDROID__" to be defined ๐Ÿ’œ

  • -tno-android-cc โ€” disables the compilation effects of -mandroid, so it does not enable -mbionic, -fPIC, -fno-exceptions and -fno-rtti by default ๐Ÿ™…โ€โ™€๏ธ
  • -tno-android-ld โ€” disables the linking effects of -mandroid, so the driver passes standard Linux linking options to the linker ๐Ÿง

โœจ H8/300 Options โœจ

These -m options are defined for the H8/300 implementations, so if that's your chip, this section is literally for you ๐Ÿงš

  • -mrelax โ€” shortens some address references at link time, when it's possible ๐Ÿช„ It does this by using the linker option -relax ๐Ÿ”—
  • -mh โ€” generate code for the H8/300H ๐ŸŒธ
  • -ms โ€” generate code for the H8S ๐Ÿ’œ
  • -mn โ€” generate code for the H8S and H8/300H in the normal mode ๐Ÿ™Œ This switch has to be used with either -mh or -ms, so don't forget your partner ๐Ÿซถ
  • -ms2600 โ€” generate code for the H8S/2600 ๐Ÿฆ‹ This switch has to be used with -ms ๐Ÿ’–
  • -mexr โ€” the extended registers get stored on the stack before a function with the monitor attribute executes ๐Ÿ“š This is the default option, and it's only valid for H8S targets ๐Ÿ”ฅ
  • -mno-exr โ€” the extended registers do not get stored on the stack before a function with the monitor attribute executes ๐Ÿ™…โ€โ™€๏ธ This is the default for that scenario, and it's also only valid for H8S targets ๐Ÿ’…
  • -mint32 โ€” makes "int" data 32 bits by default ๐Ÿ“
  • -malign-300 โ€” on the H8/300H and H8S, this 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 causes them to be aligned 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, so if you're giving HP-UX or PA-RISC energy, this part's for you ๐Ÿ–ฅ๏ธ๐Ÿ’œ

  • -march=architecture-type โ€” generate code for the architecture you specify ๐Ÿ›๏ธ 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 ๐Ÿ”ฅ

To figure out the right architecture option for your machine, refer to /usr/lib/sched.models on an HP-UX system ๐Ÿ“– Code compiled for lower numbered architectures runs on higher numbered architectures, but not the other way around, so don't be that person ๐Ÿ’€

  • -mpa-risc-1-0, -mpa-risc-1-1, -mpa-risc-2-0 โ€” these are synonyms for -march=1.0, -march=1.1, and -march=2.0 respectively ๐Ÿ‘ฏโ€โ™€๏ธ
  • -mcaller-copies โ€” the caller copies function arguments that get passed by hidden reference ๐Ÿซฑ This option should be used with care, because it is not compatible with the default 32-bit runtime ๐Ÿ˜ฌ However, only aggregates larger than eight bytes are passed by hidden reference, and this option gives better compatibility with OpenMP ๐Ÿซถ
  • -mjump-in-delay โ€” this one gets ignored โœ‹ It's only here for compatibility purposes, so it's basically a vibe with no effect ๐Ÿ™ƒ
  • -mdisable-fpregs โ€” prevents 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. Yep, it just stops. Don't say I didn't warn you ๐Ÿ’€
  • -mdisable-indexing โ€” prevents 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 โšก

Heads up though: 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 that the register allocator cannot use, which is super useful when compiling kernel code ๐Ÿงฉ A register range is specified as two registers separated by a dash, and you can specify multiple register ranges 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, bestie: 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 containing library calls for floating point ๐Ÿงฎ
Warning, this one is a whole thing: the requisite libraries are not available for all HPPA targets ๐Ÿšจ Normally the facilities of the machine's usual C compiler are used, but this cannot be done directly in cross-compilation, so you have to make your own arrangements to provide suitable library functions for cross-compilation ๐Ÿ› ๏ธ

Also, -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 ๐Ÿซถ

  • -msio โ€” generates the predefine "_SIO" for server IO ๐Ÿ–ฅ๏ธ The default is -mwsio, which generates the predefines "__hp9000s700", "__hp9000s700__" and "_WSIO" for workstation IO ๐Ÿ–ฑ๏ธ These options are available under HP-UX and HI-UX ๐ŸŒธ
  • -mgnu-ld โ€” uses options specific to GNU ld ๐Ÿƒ This passes -shared to ld when building a shared library ๐Ÿ“š It's the default when GCC is configured, explicitly or implicitly, with the GNU linker ๐Ÿ’œ

This option does not affect which ld gets called, it only changes what parameters get passed to that ld ๐Ÿคทโ€โ™€๏ธ The ld that gets called is determined by the --with-ld configure option, GCC's program search path, and finally by the user's PATH ๐Ÿ—บ๏ธ You can print the linker GCC uses with which `gcc -print-prog-name=ld` ๐Ÿ” This option is only available on the 64-bit HP-UX GCC, i.e. configured with hppa*64*-*-hpux* ๐Ÿง 

  • -mhp-ld โ€” uses options specific to HP ld ๐Ÿงก This passes -b to ld when building a shared library, and passes +Accept TypeMismatch to ld on all links ๐Ÿ”— It's the default when GCC is configured, explicitly or implicitly, with the HP linker ๐Ÿ–จ๏ธ

Same tea as before: this option does not affect which ld is called, it only changes what parameters are passed to that ld ๐Ÿซ  The ld that is called is determined by the --with-ld configure option, GCC's program search path, and finally by the user's PATH ๐Ÿ—บ๏ธ The linker used by GCC can be printed using which `gcc -print-prog-name=ld` ๐Ÿ” This option is only available on the 64-bit HP-UX GCC, i.e. configured with hppa*64*-*-hpux* ๐Ÿง 

  • -mlong-calls โ€” generates code that uses long call sequences ๐Ÿ“ž This ensures that a call is always able to reach linker generated stubs ๐Ÿงญ

The default is to generate long calls only when the distance from the call site to the beginning of the function or translation unit (depending on the case) goes past a predefined limit set by the branch type being used ๐Ÿ“ The limits for normal calls are 7,600,000 and 240,000 bytes, respectively for the PA 2.0 and PA 1.X architectures ๐Ÿ“ Sibcalls are always limited at 240,000 bytes ๐Ÿชง

Distances are measured from the beginning of functions when using the -ffunction-sections option, or when using the -mgas and -mno-portable-runtime options together under HP-UX with the SOM linker ๐Ÿงต

Honestly, it's normally not desirable to use this option because it degrades performance ๐Ÿ“‰ But it may be useful in large applications, particularly when partial linking is used to build the application ๐Ÿ—๏ธ

The types of long calls used depend on the capabilities of the assembler and linker, and the type of code being generated ๐Ÿงฉ The impact on systems that support long absolute calls, and long pic symbol-difference or pc-relative calls, should be relatively small ๐ŸŒท However, an indirect call is used on 32-bit ELF systems in pic code, and it is quite long ๐Ÿข

  • -munix=unix-std โ€” okay bestie, this one sets up the compiler predefines and picks a startfile for whichever UNIX standard you name. The choices are 93, 95 and 98 ๐Ÿ’…
    • 93 is supported 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 you the same predefines as GCC 3.3 and 3.4
    • -munix=95 adds the predefines "XOPEN_UNIX" and "_XOPEN_SOURCE_EXTENDED", plus the startfile unix95.o โœจ
    • -munix=98 adds the predefines "_XOPEN_UNIX", "_XOPEN_SOURCE_EXTENDED", "_INCLUDE__STDC_A1_SOURCE" and "_INCLUDE_XOPEN_SOURCE_500", plus the startfile unix98.o ๐Ÿ‘‘
โš ๏ธ Be careful with this one, bestie. It changes the interfaces for various library routines and affects the operational behavior of the C library. Thus, extreme care is needed when using this option ๐Ÿ˜ญ

Library code that is meant to work with more than one UNIX standard has to test, set and restore the variable __xpg4_extended_mask as appropriate. Most GNU software doesn't provide this capability ๐Ÿ™ˆ

  • -nolibdld โ€” this stops the generation of link options that search libdld.sl when -static is specified on HP-UX 10 and later ๐Ÿงš
  • -static โ€” the HP-UX version of setlocale in libc depends on libdld.sl, and there isn't an archive version of libdld.sl. So when you use -static, you need special link options to sort that dependency out ๐Ÿ’– On HP-UX 10 and later, the GCC driver adds those options for you when -static is used, and this makes the resulting binary dynamic. On the 64-bit port, the linkers make dynamic binaries by default anyway. If you don't want the GCC driver adding these link options, use -nolibdld ๐Ÿซถ
  • -threads โ€” adds support for multithreading with the dce thread library under HP-UX. This one 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 generate) code for the GNU assembler. This is the default ๐Ÿ’…
  • -mgnu-ld, -mno-gnu-ld โ€” generates (or doesn't generate) code for the GNU linker. This is the default ๐Ÿ’…
  • -mno-pic โ€” generates code that does not use a global pointer register. The result is not position independent code, and it violates the IA-64 ABI ๐Ÿ’€
  • -mvolatile-asm-stop, -mno-volatile-asm-stop โ€” generates (or doesn't generate) a stop bit immediately before and after volatile asm statements ๐ŸŒˆ
  • -mregister-names, -mno-register-names โ€” generates (or doesn't generate) 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, and 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 โ€” does not 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 โ€” does not 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 โ€” does not 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 before 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 that treats the given register range as fixed registers. A fixed register is one the register allocator cannot use, which is useful when compiling kernel code. A register range is written as two registers separated by a dash, and you can separate multiple register ranges with 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 (that is, 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 the instructions that depend on the 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 the instructions that depend on the 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 the instructions that depend on the 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 โ€” if enabled, data-speculative instructions are only chosen for scheduling when there are no other choices at the moment. This makes the use of data speculation much more conservative. The default setting is disabled ๐Ÿ™ˆ
  • -mno-sched-prefer-non-control-spec-insns, -msched-prefer-non-control-spec-insns โ€” if enabled, control-speculative instructions are only chosen for scheduling when there are no other choices at the moment. This makes the use of control speculation much more conservative. The default setting is disabled ๐Ÿ™ˆ
  • -mno-sched-count-spec-in-critical-path, -msched-count-spec-in-critical-path โ€” if enabled, speculative dependencies are considered when computing the instruction priorities. This makes the use of speculation a bit more conservative. The default setting is disabled ๐Ÿ™ˆ
  • -msched-spec-ldc โ€” uses a simple data speculation check. This option is on by default โœจ
  • -msched-control-spec-ldc โ€” uses a simple check for control speculation. This option is on by default โœจ
  • -msched-stop-bits-after-every-cycle โ€” places a stop bit after every cycle when scheduling. This option is on by default โœจ
  • -msched-fp-mem-deps-zero-cost โ€” assumes that floating-point stores and loads are not likely to cause a conflict when placed into the same instruction group. This option is disabled by default ๐Ÿ“
  • -msel-sched-dont-check-control-spec โ€” generates checks for control speculation in selective scheduling. This flag is disabled by default ๐Ÿ“
  • -msched-max-memory-insns=max-insns โ€” sets a limit on the number of memory insns per instruction group, giving lower priority to subsequent memory insns that try to schedule in the same instruction group. This is frequently useful for preventing cache bank conflicts. The default value is 1 ๐ŸŽ€
  • -msched-max-memory-insns-hard-limit โ€” makes the limit set by msched-max-memory-insns a hard limit, disallowing more than that number in an instruction group. Otherwise the limit is "soft", which means non-memory operations are preferred when the limit is reached, but memory operations may still be scheduled ๐ŸŽ€

๐Ÿงš 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 โ€” okay so this one picks the CPU you're generating code for ๐Ÿ’… 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 ๐ŸŽ€

โœจ M32R/D Options โœจ

These -m options are defined for Renesas M32R/D architectures ๐Ÿฆ‹

  • -msim โ€” bestie, this tells GCC the program will run on the simulator ๐Ÿงš It links in an alternate runtime library that supports stuff like file I/O. > Never use this on real hardware! You need to provide your own runtime library for whatever I/O functions you need.
  • -memregs=number โ€” this sets how many memory-based pseudo-registers GCC uses during code generation ๐Ÿซถ They act like real registers, so it's a tradeoff between fitting code into the available registers and the performance hit of using memory instead of registers. Every module in a program has to be compiled with the same value for this option. > Don't use this with GCC's default runtime libraries. It's not it, sis ๐Ÿ’€

โœจ M32R/D Options โœจ

These -m options are defined for Renesas M32R/D architectures ๐Ÿฆ‹

  • -m32r2 โ€” generate code for the M32R/2 ๐ŸŒธ
  • -m32rx โ€” generate code for the M32R/X ๐ŸŒธ
  • -m32r โ€” generate code for the M32R. This is the default ๐Ÿ‘‘
  • -mmodel=small โ€” this is the default ๐Ÿ’– It assumes all objects live in the lower 16MB of memory (so their addresses can be loaded with the ld24 instruction), and that all subroutines are reachable with the bl instruction. The addressability of a particular object can be set with the model attribute.
  • -mmodel=medium โ€” objects may be anywhere in the 32-bit address space (the compiler generates seth/add3 instructions to load their addresses), and all subroutines are reachable with the bl instruction ๐ŸŒˆ
  • -mmodel=large โ€” objects may be anywhere in the 32-bit address space (the compiler generates seth/add3 instructions to load their addresses), and subroutines may not be reachable with the bl instruction. The compiler generates the much slower seth/add3/jl instruction sequence ๐Ÿข
  • -msdata=none โ€” disables the small data area ๐Ÿ™…โ€โ™€๏ธ Variables go 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 must be set to one of sdata or use for this option to have any effect. All modules should be compiled with the same -G num value. Mixing different values of num may or may not work. If it doesn't, the linker gives an error message---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. 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 cannot 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 is not available ๐Ÿ“ž
  • -mno-flush-func โ€” indicates there is 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, so the defaults for the most common choices are given below.

  • -march=arch โ€” generates code for a specific M680x0 or ColdFire instruction set architecture ๐Ÿ›๏ธ Valid values of arch for M680x0 architectures are: 68000, 68010, 68020, 68030, 68040, 68060 and cpu32. ColdFire architectures are selected according to Freescale's ISA classification, and the valid 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 above.

When used together, -march and -mtune select code that runs on a family of similar processors but 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 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 get 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 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 above ๐Ÿง

  • -m68000, -mc68000 โ€” generates output for a 68000. This is the default when the compiler is configured for 68000-based systems. It's equivalent to -march=68000 ๐Ÿ’– Use this for microcontrollers with a 68000 or EC000 core, including 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. It's equivalent to -march=68040 ๐ŸŒท This option inhibits the use of 68881/68882 instructions that have to be emulated by software on the 68040. Use this 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. It's equivalent to -march=68060 ๐ŸŒท This option inhibits the use of 68020 and 68881/68882 instructions that have to be emulated by software on the 68060. Use this if your 68060 doesn't have code to emulate those instructions ๐Ÿ› ๏ธ
  • -mcpu32 โ€” generates output for a CPU32. This is the default when the compiler is configured for CPU32-based systems. It's equivalent to -march=cpu32 ๐ŸŒท Use this 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, and is now deprecated in favor of that option ๐Ÿฅ€ Use this for microcontrollers with a 5200 core, including the MCF5202, MCF5203, MCF5204 and MCF5206.
  • -m5206e โ€” generates output for a 5206e ColdFire CPU. The option is now deprecated in favor of the equivalent -mcpu=5206e ๐Ÿฅ€
  • -m528x โ€” generates output for a member of the ColdFire 528X family. The option is now deprecated in favor of the equivalent -mcpu=528x ๐Ÿฅ€
  • -m5307 โ€” generates output for a ColdFire 5307 CPU. The option is now deprecated in favor of the equivalent -mcpu=5307 ๐Ÿฅ€

๐ŸŽ€ ColdFire Options, Continued ๐ŸŽ€

  • -m5407 โ€” okay so this one makes output for a ColdFire 5407 CPU ๐Ÿ’– but it's deprecated now, so just use -mcpu=5407 instead, it's the same thing โœจ
  • -mcfv4e โ€” this is for the ColdFire V4e family (think 547x/548x chips) ๐Ÿฆ‹ It also lets you use the hardware floating-point instructions. It's equivalent to -mcpu=547x, and it's deprecated, so -mcpu=547x is the move ๐Ÿ’…
  • -m68020-40 โ€” makes output for a 68040 but doesn't touch any of the new instructions ๐ŸŒธ The result runs pretty efficiently on a 68020/68881, a 68030, or a 68040. The generated code does use the 68881 instructions that get emulated on the 68040.

This is equivalent to -march=68020 -mtune=68020-40.

  • -m68020-60 โ€” same energy, but for a 68060 ๐Ÿ“ Again no new instructions, and the code runs relatively efficiently on a 68020/68881, a 68030, or a 68040. The generated code does use the 68881 instructions that get emulated on the 68060.

This is equivalent to -march=68020 -mtune=68020-60.

  • -mhard-float, -m68881 โ€” turns on floating-point instructions ๐Ÿ”ฅ This is the default for the 68020 and up, and for ColdFire devices that have an FPU. It defines the macro __HAVE_68881__ on M680x0 targets and __mcffpu__ on ColdFire targets.
  • -msoft-float โ€” the opposite vibe ๐Ÿซถ No floating-point instructions at all, you get library calls instead. This is the default for 68000, 68010, and 68832 targets, and also for ColdFire devices with no FPU.
  • -mdiv, -mno-div โ€” -mdiv generates ColdFire hardware divide and remainder instructions, and -mno-div skips them ๐Ÿงš 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, either the default CPU or whichever one you picked with -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, like short int โœจ Parameters passed on the stack also get aligned to a 16-bit boundary, even on targets whose API says to promote them to 32-bit.
  • -mno-short โ€” the default, where int is not 16 bits wide ๐Ÿ’œ
  • -mnobitfield, -mno-bitfield โ€” no bit-field instructions for you ๐Ÿ™…โ€โ™€๏ธ The -m68000, -mcpu32, and -m5200 options all imply -mnobitfield.
  • -mbitfield โ€” yes to bit-field instructions ๐Ÿ’… The -m68020 option implies -mbitfield, and it's the default if you use a configuration designed for a 68020.
  • -mrtd โ€” okay this one is a whole vibe ๐Ÿ‘‘ It switches to a different function-calling convention, where functions with a fixed number of arguments return with the rtd instruction, which pops their arguments while it returns. That saves one instruction in the caller, since the caller doesn't have to pop anything.

But 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 have to provide function prototypes for every function that takes a variable number of arguments (including printf). Otherwise you get incorrect code for calls to those functions.

Seriously incorrect code results if you call a function with too many arguments. Normally, extra arguments are harmlessly ignored, but not with this one, so be careful ๐Ÿ’€

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. Heads up, bestie ๐Ÿ™ˆ
  • -mpcrel โ€” uses the pc-relative addressing mode of the 68000 directly, instead of going through a global offset table ๐Ÿฆ‹ At the moment 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 68020 and higher processors.
  • -mno-strict-align, -mstrict-align โ€” -mno-strict-align means GCC does not assume that unaligned memory references get handled by the system, and -mstrict-align means it does assume that ๐Ÿซถ
  • -msep-data โ€” generates 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. 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 through the library ID method โœจ This allows 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 0 generates more compact code. Specifying other values forces the allocation of that number to the current library, but that's no more space- or time-efficient than leaving this option out.
  • -mxgot, -mno-xgot โ€” when generating position-independent code for ColdFire, -mxgot generates code that works if the GOT has more than 8192 entries ๐Ÿ”ฅ This code is larger and slower than code generated without this option. On M680x0 processors you don't need this option, 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 bigger 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 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 โ€” -mdiv uses the divide instruction. It's enabled by default ๐Ÿ’…
  • -mrelax-immediate, -mno-relax-immediate โ€” allows arbitrary-sized immediates in bit operations ๐ŸŒˆ
  • -mwide-bitfields, -mno-wide-bitfields โ€” -mwide-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 ๐ŸŒธ
  • -mlittle-endian, -mbig-endian โ€” generates code for a little-endian target ๐Ÿ’–
  • -m210, -m340 โ€” generates code for the 210 processor ๐Ÿ”ฅ
  • -mno-lsim โ€” assumes runtime support has already been provided, so the simulator library (libsim.a) gets left off the linker command line ๐Ÿ‘‘
  • -mstack-increment=size โ€” sets the maximum amount for a single stack increment operation ๐Ÿ“ Big values can speed up programs with functions that need a lot of stack space, but they can also cause a segmentation fault if the stack gets extended too much. The default value 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 ๐Ÿ”ฅ That's average, multiply, divide, bit operations, leading zero, absolute difference, min/max, clip, and saturation. Full main character energy ๐Ÿ‘‘
  • -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 the $tp register as a 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 โ€” selects which section constant data gets placed in ๐ŸŒธ The name can be tiny, near, or far.
  • -mclip โ€” enables the clip instruction ๐Ÿซถ Heads up: -mclip isn't useful unless you also provide -mminmax.
  • -mconfig=name โ€” picks one of the built-in core configurations ๐ŸŒˆ Each MeP chip has one or more modules in it, and each module has a core CPU plus a bunch of coprocessors, optional instructions, and peripherals. The "MeP-Integrator" tool, which is 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 be placed in the .near section โœจ
  • -mdiv โ€” enables the div and divu instructions ๐Ÿ’…
  • -meb โ€” generates big-endian code ๐Ÿ‘‘

-mel

  • Hmm, okay so this one is about little-endian code. Bestie, -mel tells the compiler to generate little-endian code ๐Ÿ’–
  • -mio-volatile โ€” okay this one is giving "treat it with care" energy ๐Ÿซถ It tells the compiler that any variable marked with the "io" attribute is to be 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 enabled by -mall-opts ๐Ÿ™ˆ
  • -mrepeat โ€” enables the "repeat" and "erepeat" instructions, used for low-overhead looping ๐Ÿ‘‘
  • -ms โ€” causes all variables to default to the ".tiny" section ๐Ÿ’€ Note that there is a 65536-byte limit to this section. Accesses to these variables use the %gp base register ๐ŸŒˆ
  • -msatur โ€” enables the saturation instructions โญ Note that the compiler does not currently generate these itself, but this option is included 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, excluding 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 are allocated to the ".tiny" section ๐Ÿงš These variables use the $gp base register. The default for this option is 4, but note that there's a 65536-byte limit to the ".tiny" section ๐Ÿ˜ญ

โœจ MicroBlaze Options โœจ

  • -msoft-float โ€” uses software emulation for floating point (default) ๐ŸŒˆ
  • -mhard-float โ€” uses hardware floating-point instructions ๐Ÿ”ฅ
  • -mmemcpy โ€” does not optimize block moves, uses "memcpy" instead ๐Ÿ’…
  • -mno-clearbss โ€” this option is deprecated. Use -fno-zero-initialized-in-bss instead ๐Ÿ’€
  • -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 โ€” this option is deprecated. 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 โ€” generates code for a big-endian target ๐ŸŒˆ
  • -mlittle-endian โ€” generates code for a little-endian target ๐Ÿ’–
  • -mxl-reorder โ€” uses reorder instructions (swap and byte reversed load/store) ๐Ÿ‘‘
  • -mxl-mode-app-model โ€” selects application model app-model. Valid models are:
    • executable โ€” normal executable (default), uses startup code crt0.o ๐ŸŽ€
    • -mpic-data-is-text-relative โ€” assumes that the displacement between the text and data segments is fixed at static link time. This allows data to be referenced by offset from start of text address instead of GOT, since PC-relative addressing is not supported ๐Ÿฆ‹
    • xmdstub โ€” for use with Xilinx Microprocessor Debugger (XMD) based software intrusive debug agent called xmdstub. This uses startup file crt1.o and sets the start address of the program to 0x800 ๐Ÿซถ
    • bootstrap โ€” for applications that are loaded using a bootloader. This model uses startup file crt2.o, which does not contain a processor reset vector handler. This is suitable for transferring control on a processor reset to the bootloader rather than the application ๐Ÿ“
    • novectors โ€” for applications that do not require any of the MicroBlaze vectors. This option may be useful for applications running within a monitoring application. This model uses crt3.o as a startup file ๐Ÿงš

Option -xl-mode-app-model is a deprecated alias for -mxl-mode-app-model ๐Ÿ’€


โœจ MIPS Options โœจ

  • -EB โ€” generates big-endian code ๐ŸŒธ
  • -EL โ€” generates 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 is, 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 does not 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, and names of the form nf3_2 refer to processors with FPUs clocked a ratio of 3:2 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 does not 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 is not used, GCC optimizes for the processor specified by -march. By using -march and -mtune together, it is possible to generate code that runs on a family of processors, but optimize the code for one particular member of that family ๐Ÿ‘‘

-mtune defines the macros "_MIPS_TUNE" and "_MIPS_TUNE_foo", which work in the same way as the -march ones described above ๐ŸŽ€

  • -mips1 โ€” equivalent to -march=mips1 ๐Ÿฆ‹
  • -mips2 โ€” equivalent to -march=mips2 ๐Ÿซถ
  • -mips3 โ€” equivalent to -march=mips3 ๐Ÿ“
  • -mips4 โ€” equivalent to -march=mips4 ๐Ÿงš
  • -mips32 โ€” equivalent to -march=mips32 ๐ŸŒธ
  • -mips32r3 โ€” equivalent to -march=mips32r3 ๐Ÿ’œ
  • -mips32r5 โ€” equivalent to -march=mips32r5 ๐Ÿ”ฅ
  • -mips32r6 โ€” equivalent to -march=mips32r6 โœจ
  • -mips64 โ€” equivalent to -march=mips64 โญ
  • -mips64r2 โ€” equivalent to -march=mips64r2 ๐ŸŒˆ
  • -mips64r3 โ€” equivalent to -march=mips64r3 ๐Ÿ’–
  • -mips64r5 โ€” equivalent to -march=mips64r5 ๐Ÿ‘‘
  • -mips64r6 โ€” equivalent to -march=mips64r6 ๐ŸŽ€
  • -mips16 / -mno-mips16 โ€” generates (or does not generate) MIPS16 code ๐Ÿฆ‹ If GCC is targeting a MIPS32 or MIPS64 architecture, it makes use of the MIPS16e ASE.

MIPS16 code generation can also be controlled on a per-function basis by means of "mips16" and "nomips16" attributes ๐Ÿซถ

  • -mflip-mips16 โ€” generates MIPS16 code on alternating functions ๐Ÿ“ This option is provided for regression testing of mixed MIPS16/non-MIPS16 code generation, and is not intended for ordinary use in compiling user code ๐Ÿ’€
  • -minterlink-compressed / -mno-interlink-compressed โ€” requires (or does not require) that code using the standard (uncompressed) MIPS ISA be link-compatible with MIPS16 and microMIPS code, and vice versa ๐Ÿงš

For example, code using the standard ISA encoding cannot jump directly to MIPS16 or microMIPS code; it must either use a call or an indirect jump. -minterlink-compressed therefore disables direct jumps unless GCC knows that the target of the jump is not compressed ๐ŸŒธ

  • -minterlink-mips16 / -mno-interlink-mips16 โ€” aliases of -minterlink-compressed and -mno-interlink-compressed. These options predate the microMIPS ASE and are retained for backwards compatibility ๐Ÿ’œ
  • -mabi=32, -mabi=o64, -mabi=n32, -mabi=64, -mabi=eabi โ€” generates code for the given ABI ๐Ÿ‘‘

Note that the EABI has a 32-bit and a 64-bit variant. GCC normally generates 64-bit code when you select a 64-bit architecture, but you can use -mgp32 to get 32-bit code instead ๐ŸŽ€

For information about the O64 ABI, see <http://gcc.gnu.org/projects/mipso64-abi.html> ๐Ÿฆ‹

GCC supports a variant of the o32 ABI in which floating-point registers are 64 rather than 32 bits wide. You can select this combination with -mabi=32 -mfp64. This ABI relies on the "mthc1" and "mfhc1" instructions and is therefore only supported for MIPS32R2, MIPS32R3 and MIPS32R5 processors ๐Ÿซถ

The register assignments for arguments and return values stay the same, okay? ๐Ÿ’… But each scalar value now rides in a single 64-bit register instead of a pair of 32-bit ones ๐Ÿ”ฅ. Scalar floating-point values come back in $f0 only, not a $f0/$f1 pair ๐Ÿฆ‹. The call-saved set doesn't change either, because the even-numbered double-precision registers are still the ones that get saved โœจ.

Two extra variants of the o32 ABI exist so you can transition from 32-bit to 64-bit registers ๐ŸŒˆ. The first is -mfpxx (FPXX), and it's giving flexibility ๐Ÿซถ. FPXX means all code has to run correctly with 32-bit or 64-bit registers. You can interlink it with FP32 or FP64, but never both ๐Ÿšซ. The second is -mfp64 -mno-odd-spreg (FP64A) ๐Ÿ’œ. It's basically FP64, except it bans the odd-numbered single-precision registers. Pair it with the "FRE" mode of FPUs in MIPS32R5 processors and FP32 and FP64A code can interlink and run in the same process without changing FPU modes. That's a whole glow-up, no cap ๐ŸŒธ.

  • -mabicalls, -mno-abicalls โ€” Generates (or doesn't generate) code that fits SVR4-style dynamic objects ๐ŸŽ€. -mabicalls is the default on SVR4-based systems ๐Ÿ’–.
  • -mshared, -mno-shared โ€” Generates (or doesn't) code that's fully position-independent, so it can be linked into shared libraries ๐Ÿฆ‹. This option only affects -mabicalls ๐Ÿ’….

All -mabicalls code has traditionally been position-independent, even without options like -fPIC and -fpic ๐Ÿงš. 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 generate direct calls to locally-defined functions ๐Ÿ”ฅ. That's the mode -mno-shared selects ๐Ÿ’œ.

-mno-shared depends on binutils 2.16 or higher, and the objects it makes can only be linked by the GNU linker ๐Ÿ™ˆ. The ABI of the final executable doesn't change, though. It only affects the ABI of relocatable objects ๐Ÿซถ. Using -mno-shared generally 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 ๐Ÿ”ฅ.

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 bigger and the linker reports an error 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, since it takes three instructions to fetch the value of a global symbol ๐Ÿข.

Some linkers can create multiple GOTs. If you have one of those, you usually only need -mxgot when a single object file accesses more than 64k's worth of GOT entries. Very few linkers 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 any particular width for floating-point registers ๐Ÿซถ.
  • -mhard-float โ€” Uses floating-point coprocessor instructions ๐Ÿ”ฅ.
  • -msoft-float โ€” Doesn't use floating-point coprocessor instructions. Floating-point math goes through library calls instead ๐Ÿงš.
  • -mno-float โ€” Same as -msoft-float, but it also swears the program doesn't do any floating-point operations at all ๐Ÿ™…โ€โ™€๏ธ. Right now this is only supported by some bare-metal MIPS configurations, which might pick a special set of libraries with zero floating-point support, including things like the floating-point "printf" formats ๐Ÿ’€.
Warning, bestie: if code compiled with -mno-float accidentally has floating-point operations in it, it's likely to fail at link time or at run time ๐Ÿ˜ญ.
  • -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 ๐Ÿ’…. Odd-numbered registers are on by default for processors known to support them. When you use the o32 FPXX ABI, -mno-odd-spreg is set by default ๐Ÿฆ‹.
  • -mabs=2008, -mabs=legacy โ€” These control how special not-a-number (NaN) IEEE 754 floating-point data gets treated by the "abs.fmt" and "neg.fmt" machine instructions ๐ŸŽ€.

legacy is the default, and also what you get with -mabs=legacy. Here, those instructions count as arithmetic, so they get avoided wherever correct operation matters 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 is also specified โœจ.

-mabs=2008 selects the IEEE 754-2008 treatment. Here, those instructions count as non-arithmetic, so they work correctly in every case, especially when the input operand is a NaN ๐Ÿ’–. That's why they're always used for the respective operations ๐Ÿ”ฅ.

  • -mnan=2008, -mnan=legacy โ€” These control how special not-a-number (NaN) IEEE 754 floating-point data gets encoded ๐Ÿงš.

-mnan=legacy picks the legacy encoding. Quiet NaNs (qNaNs) are marked by the first bit of their trailing significand field being 0, and signaling NaNs (sNaNs) by that same bit being 1 ๐ŸŒธ.

-mnan=2008 picks the IEEE 754-2008 encoding, which flips it. qNaNs have the first bit of their trailing significand field set to 1, and sNaNs have it set to 0 ๐Ÿฆ‹.

The default is -mnan=legacy, unless GCC was configured with --with-nan=2008 ๐Ÿ‘‘.

  • -mllsc, -mno-llsc โ€” Uses (or doesn't use) ll, sc, and sync instructions to implement atomic memory built-in functions ๐Ÿ’œ. If you specify neither option, GCC uses the instructions whenever the target architecture supports them ๐Ÿซถ.

-mllsc helps when the runtime environment can emulate those instructions ๐ŸŽ€. -mno-llsc can help when you're compiling for nonstandard ISAs ๐Ÿง. You can make either one the default by configuring GCC with --with-llsc or --without-llsc. --with-llsc is the default for some configurations, so check the installation documentation for details ๐Ÿ“š.

  • -mdsp, -mno-dsp โ€” Uses (or doesn't use) revision 1 of the MIPS DSP ASE ๐ŸŒˆ. This option defines the preprocessor macro "__mips_dsp" and sets "__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", and sets "__mips_dsp_rev" to 2 ๐Ÿ’–.
  • -msmartmips, -mno-smartmips โ€” Uses (or doesn't use) the MIPS SmartMIPS ASE ๐Ÿ’….
  • -mpaired-single, -mno-paired-single โ€” Uses (or doesn't use) paired-single floating-point instructions ๐Ÿฆ‹. This option needs hardware floating-point support to be enabled ๐Ÿ™ˆ.
  • -mdmx, -mno-mdmx โ€” Uses (or doesn't use) MIPS Digital Media Extension instructions ๐ŸŽ€. This only works when generating 64-bit code, and it also needs hardware floating-point support enabled ๐Ÿ’œ.
  • -mips3d, -mno-mips3d โ€” Uses (or doesn't use) the MIPS-3D ASE ๐Ÿงš. -mips3d implies -mpaired-single โœจ.
  • -mmicromips, -mno-micromips โ€” Generates (or doesn't generate) microMIPS code ๐ŸŒธ.

You can also control microMIPS code generation per function, using the "micromips" and "nomicromips" attributes ๐Ÿซถ.

  • -mmt, -mno-mt โ€” Uses (or doesn't use) MT Multithreading instructions ๐Ÿ‘‘.
  • -mmcu, -mno-mcu โ€” Uses (or doesn't use) the MIPS MCU ASE instructions ๐Ÿ’….
  • -meva, -mno-eva โ€” Uses (or doesn't use) the MIPS Enhanced Virtual Addressing instructions ๐ŸŒˆ.
  • -mvirt, -mno-virt โ€” Uses (or doesn't use) the MIPS Virtualization (VZ) instructions ๐Ÿ”ฅ.
  • -mxpa, -mno-xpa โ€” Uses (or doesn't use) the MIPS eXtended Physical Address (XPA) instructions ๐Ÿ’–.
  • -mcrc, -mno-crc โ€” Uses (or doesn't use) the MIPS Cyclic Redundancy Check (CRC) instructions ๐Ÿฆ‹.
  • -mginv, -mno-ginv โ€” Uses (or doesn't use) the MIPS Global INValidate (GINV) instructions ๐Ÿซถ.
  • -mloongson-mmi, -mno-loongson-mmi โ€” Uses (or doesn't use) the MIPS Loongson MultiMedia extensions Instructions (MMI) ๐ŸŽ€.
  • -mloongson-ext, -mno-loongson-ext โ€” Uses (or doesn't use) the MIPS Loongson EXTensions (EXT) instructions โœจ.
  • -mloongson-ext2, -mno-loongson-ext2 โ€” Uses (or doesn't use) the MIPS Loongson EXTensions r2 (EXT2) instructions ๐Ÿงš.
  • -mlong64 โ€” Forces "long" types to be 64 bits wide ๐Ÿ’œ. Check out -mlong32 for an explanation of the default and how the pointer size gets determined ๐Ÿ“–.
  • -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. The others use 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 โ€” Assumes (or doesn't assume) that all symbols have 32-bit values, no matter which ABI you picked ๐Ÿฆ‹. This is useful together with -mabi=64 and -mno-abicalls, because it lets GCC generate shorter and faster references to symbolic addresses ๐Ÿ‘‘โœจ.
  • -G num โ€” okay bestie, this one tells GCC to tuck externally-visible data into a little small data section as long as it's no bigger than num bytes ๐Ÿงš That lets GCC generate way more efficient accesses to the data, so peep -mgpopt for the deets โœจ The default -G value depends on the configuration, so it's not one-size-fits-all ๐Ÿ’…
  • -mlocal-sdata, -mno-local-sdata โ€” these 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 starts complaining that your app is using too much small data, try rebuilding the less performance-critical parts with -mno-local-sdata ๐Ÿ˜ญ You might also wanna build big libraries with -mno-local-sdata so they leave more room for the main program ๐Ÿซถ
  • -mextern-sdata, -mno-extern-sdata โ€” this is where it gets lowkey intense ๐Ÿ’€ -mextern-sdata means GCC assumes (and -mno-extern-sdata means it doesn't assume) that externally-defined data lives in a small data section, as long as its size is within the -G limit ๐ŸŒธ -mextern-sdata is the default for all configurations.

If you compile a module Mod with -mextern-sdata -G num -mgpopt, and Mod references a variable Var that's no bigger than num bytes, you must make sure Var gets placed in a small data section ๐Ÿ™ˆ If Var is defined by another module, you either have to compile that module with a high-enough -G setting, or attach a "section" attribute to Var's definition. If Var is common, you must link the application with a high-enough -G setting.

The easiest way to keep everyone happy is to compile and link every module with the same -G option ๐Ÿ‘‘ But if you're building a library that supports several different small data limits, compile it with the highest supported -G setting and also use -mno-extern-sdata so the library stops 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 for cases where the $gp register might not hold the value of "_gp". For example, if the 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. (In those situations, the boot monitor itself is usually compiled with -G0.) -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 ๐ŸŒˆ The code is slightly slower than the default, but it cuts down on the RAM needed while executing, so some embedded systems might prefer it ๐Ÿงš
  • -muninit-const-in-rodata, -mno-uninit-const-in-rodata โ€” puts uninitialized "const" variables in the read-only data section ๐ŸŽ€ This only means something when it's used together with -membedded-data.
  • -mcode-readable=setting โ€” tells GCC whether it's allowed to generate code that reads from executable sections ๐Ÿ”ฅ There are three possible settings:
    • -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 do so. 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 to have 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) use of the %hi() and %lo() assembler relocation operators ๐Ÿงฉ This one's 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 it can be overridden 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 on 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) 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. The default is -mno-long-calls ๐Ÿ’–

  • -mmad, -mno-mad โ€” enable (or disable) use of the "mad", "madu" and "mul" instructions, as provided by the R4650 ISA ๐Ÿฆ‹
  • -mimadd, -mno-imadd โ€” enable (or disable) 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) 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. This 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 executed immediately after starting an integer division.
    • A double-word or a variable shift may give an incorrect result if executed while an integer multiplication is in progress.
    • An integer division may give an incorrect result if started in a delay slot of a taken branch or a jump.
  • -mfix-r4400, -mno-fix-r4400 โ€” works around certain R4400 CPU errata:
    • 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 โ€” works around certain 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; -mno-fix-r10000 is the default otherwise.

  • -mfix-r5900, -mno-fix-r5900 โ€” do not attempt to schedule the preceding instruction into the delay slot of a branch instruction placed at the end of a short loop of six instructions or fewer, and always schedule a "nop" instruction there instead ๐ŸŒ€ The short loop bug can, under certain conditions, cause loops to execute only once or twice, due to a hardware bug in the R5900 chip ๐Ÿ˜ต The workaround is implemented by the assembler rather than by GCC.
  • -mfix-rm7000, -mno-fix-rm7000 โ€” works around the RM7000 "dmult"/"dmultu" errata. The workarounds are implemented by the assembler rather than by GCC.
  • -mfix-vr4120, -mno-fix-vr4120 โ€” works around certain 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 present, these functions are only provided by the "mips64vr*-elf" configurations. Other VR4120 errata require a NOP to be inserted between certain pairs of instructions. These errata are handled by the assembler, not by GCC itself.

  • -mfix-vr4130 โ€” works around the VR4130 "mflo"/"mfhi" errata. The workarounds are implemented by the assembler rather than by GCC, although 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 โ€” specifies whether GCC should insert cache barriers to avoid the side effects of speculation on R10K processors ๐Ÿ”ฅ

Okay so the R10K is lowkey a chaotic processor ๐Ÿ’€ It tries to guess which way a conditional branch will go and starts running instructions down the "taken" path before it knows. If the guess was wrong, it throws those instructions away, but even the aborted ones can leave marks behind ๐Ÿ™ˆ

This mostly hurts kernel stores and, depending on the system, kernel loads ๐Ÿ˜ญ Picture a speculative store pulling its target memory into cache and marking that line as dirty, even though the store got cancelled. If a DMA operation writes to that same memory before the dirty line gets flushed, the cached data overwrites the DMA data. Yikes. For the full tea, including other problems, check the R10K processor manual ๐Ÿ“–โœจ

One workaround is to drop cache barrier instructions in front of every memory access that might run speculatively and might have side effects even when aborted. -mr10k-cache-barrier=setting controls how GCC does this. It assumes that aborted accesses to any byte in these regions have no side effects:

  1. the memory taken up by the current function's stack frame ๐Ÿฅž
  2. the memory taken up by an incoming stack argument ๐Ÿ“ฆ
  3. the memory taken up 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 has to let j foo and jal foo run speculatively ๐Ÿ‘‘ GCC follows this rule for functions it compiles itself. It expects non-GCC functions, like hand-written assembly, to do the same thing ๐Ÿ’…

The option comes in three flavours:

  • -mr10k-cache-barrier=load-store โ€” Inserts a cache barrier before a load or store that might run speculatively and might have side effects even if it gets aborted โœจ
  • -mr10k-cache-barrier=store โ€” Inserts a cache barrier only before a store that might run speculatively and might have side effects even if it gets aborted ๐ŸŽ€
  • -mr10k-cache-barrier=none โ€” Turns off cache barrier insertion entirely. This is the default setting ๐ŸŒธ
  • -mflush-func=func, -mno-flush-func โ€” Picks the function to call for flushing the I and D caches, or tells GCC to not call any flush function at all ๐Ÿงน If you do call one, it has to 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 is only a heuristic, so don't expect it to give the same results across releases ๐Ÿ™ˆ A cost of zero just picks 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 they may get generated if the selected architecture supports them. The exception is the MIPS32 and MIPS64 architectures, plus processors that implement them. For those, Branch Likely instructions are not generated by default, because MIPS32 and MIPS64 specifically deprecate them ๐Ÿšซ
  • -mcompact-branches=never โ€” Makes sure compact branch instructions never get generated ๐Ÿ™…โ€โ™€๏ธ
  • -mcompact-branches=optimal โ€” Uses a delay slot branch if one is available in the current ISA and the delay slot gets successfully filled. If the delay slot isn't filled, a compact branch gets picked instead, as long as one is available ๐Ÿง  This is the default โœจ
  • -mcompact-branches=always โ€” Makes sure a compact branch instruction gets generated whenever one is available. If none is available, a delay slot form of the branch gets used instead ๐Ÿ’–

These options control which form of branches gets generated. The default is -mcompact-branches=optimal. Also, the always option is only supported from MIPS Release 6 onwards ๐ŸŽ€

  • -mfp-exceptions, -mno-fp-exceptions โ€” Says whether FP exceptions are enabled. This affects how FP instructions get scheduled on some processors ๐Ÿ”ฅ FP exceptions are enabled by default ๐Ÿ’…

For instance, on the SB-1, if FP exceptions are disabled and we're emitting 64-bit code, 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 it thinks should run in parallel ๐Ÿฆ‹

This option only does something when you're optimizing for the VR4130 โœจ It usually makes code faster, but the tradeoff is that the code gets bigger ๐Ÿ“ˆ It's enabled by default at optimization level -O3 ๐Ÿ‘‘

  • -msynci, -mno-synci โ€” Enables (or disables) generating synci instructions on architectures that support them ๐ŸŒธ The synci instructions, if enabled, get generated when __builtin___clear_cache is compiled ๐Ÿงน

This option defaults to -mno-synci, but you can override that 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, 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 change 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 that the header is unused ๐Ÿง 

This optimization is off by default at all optimization levels ๐Ÿ˜ญ

  • -mlxc1-sxc1, -mno-lxc1-sxc1 โ€” When applicable, enables (or disables) generating lwxc1, swxc1, ldxc1, and sdxc1 instructions ๐Ÿ’– Enabled by default โœจ
  • -mmadd4, -mno-madd4 โ€” When applicable, enables (or disables) generating 4-operand madd.s, madd.d, and related instructions ๐ŸŒˆ Enabled by default ๐Ÿ‘‘

๐ŸŒˆ MMIX Options ๐ŸŒˆ

These options are defined for the MMIX ๐Ÿงš

  • -mlibfuncs, -mno-libfuncs โ€” Specifies that intrinsic library functions are being compiled, passing all values in registers no matter the size ๐Ÿ“š
  • -mepsilon, -mno-epsilon โ€” Generates floating-point comparison instructions that compare with respect to the rE epsilon register ๐Ÿ”ข
  • -mabi=mmixware, -mabi=gnu โ€” -mabi=mmixware generates code that passes function parameters and return values which, in the called function, are seen as registers $0 and up. The GNU ABI, by contrast, uses global registers $231 and up ๐ŸŒธ
  • -mzero-extend, -mno-zero-extend โ€” When reading data from memory in sizes shorter than 64 bits, uses (or doesn't use) zero-extending load instructions by default, instead of sign-extending ones ๐Ÿฆ‹
  • -mknuthdiv, -mno-knuthdiv โ€” -mknuthdiv makes the result of a division yielding a remainder have the same sign as the divisor. With the default, -mno-knuthdiv, the sign of the remainder follows the sign of the dividend ๐Ÿงฎ Both methods are arithmetically valid, though the latter is almost exclusively used ๐Ÿ’…
  • -mtoplevel-symbols, -mno-toplevel-symbols โ€” Prepends (or doesn't prepend) a : to all global symbols, so the assembly code can be used with the PREFIX assembly directive ๐ŸŽ€
  • -melf โ€” Generates an executable in the ELF format, instead of the default mmo format used by the mmix simulator ๐Ÿซง
  • -mbranch-predict, -mno-branch-predict โ€” Uses (or doesn't use) the probable-branch instructions when static branch prediction indicates a probable branch ๐Ÿ”ฎ
  • -mbase-addresses, -mno-base-addresses โ€” Generates (or doesn't generate) code that uses base addresses ๐Ÿ  Using a base address automatically generates a request, handled by the assembler and the linker, for a constant to be set up in a global register. That register is used for one or more base address requests within the range 0 to 255 from the value held in the register. This generally leads to short and fast code, but the number of different data items that can be addressed is limited. So a program that uses lots of static data may require -mno-base-addresses ๐Ÿ“ฆ
  • -msingle-exit, -mno-single-exit โ€” Forces (or doesn't force) generated code to have a single exit point in each function ๐Ÿšช

๐Ÿ“ MN10300 Options ๐Ÿ“

These -m options are defined for Matsushita MN10300 architectures ๐Ÿ’œ

  • -mmult-bug โ€” Generates code to avoid bugs in the multiply instructions for the MN10300 processors. This is the default ๐Ÿ›ก๏ธ
  • -mno-mult-bug โ€” okay so this one tells GCC to not generate code that works around bugs in the multiply instructions on MN10300 processors ๐Ÿ’…
  • -mam33 โ€” generate code using AM33-specific features โœจ
  • -mno-am33 โ€” the opposite: no AM33-specific features. This is the default ๐ŸŒธ
  • -mam33-2 โ€” generate code using features specific to the AM33/2.0 processor ๐Ÿฆ‹
  • -mam34 โ€” generate code using AM34-specific features ๐Ÿ’œ
  • -mtune=cpu-type โ€” bestie, this tells the scheduler which CPU's timing to follow when it lines up instructions. It does not change the target processor, so it's giving scheduling tips, not a glow-up. The CPU type has to be mn10300, am33, am33-2 or am34 ๐ŸŽ€
  • -mreturn-pointer-on-d0 โ€” when a function returns a pointer, it gets returned in both "a0" and "d0". Otherwise the pointer only lives in "a0", and calling those functions without a prototype throws errors ๐Ÿ’€. This one is on by default, but you can switch it off with -mno-return-pointer-on-d0 ๐Ÿ™ˆ
  • -mno-crt0 โ€” don'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 it's on the command line for the final link step.
This option makes symbolic debugging impossible. Choose wisely, bestie ๐Ÿ˜ญ
  • -mliw โ€” lets the compiler generate Long Instruction Word instructions when the target is AM33 or later. This is the default, and it defines the preprocessor macro "__LIW__" ๐ŸŒˆ
  • -mno-liw โ€” no LIW instructions allowed. This one defines the preprocessor macro "__NO_LIW__" ๐Ÿซถ
  • -msetlb โ€” lets the compiler generate SETLB and Lcc instructions when the target is AM33 or later. Also the default, and it defines "__SETLB__" ๐Ÿ”ฅ
  • -mno-setlb โ€” no SETLB or Lcc instructions. Defines "__NO_SETLB__" ๐Ÿฅ€

โœจ Moxie Options โœจ

  • -meb โ€” big-endian code. This is the default for moxie-*-* configurations ๐Ÿ“
  • -mel โ€” little-endian code ๐ŸŒธ
  • -mmul.x โ€” generate mul.x and umul.x instructions. This is the default for moxiebox-*-* configurations ๐Ÿ‘‘
  • -mno-crt0 โ€” don't link in the C run-time initialization object file ๐Ÿฆ‹

๐Ÿงš MSP430 Options ๐Ÿงš

These options are defined for the MSP430, so they're giving MSP430 realness ๐Ÿ’–

  • -masm-hex โ€” forces assembly output to always use hex constants. Normally they show up as signed decimals, but this one is there for testsuite and/or aesthetic purposes ๐ŸŽ€
  • -mmcu= โ€” picks the MCU you're targeting. GCC makes a C preprocessor symbol from the MCU name, in upper case, wrapped in __ on both sides. The msp430.h header then uses that to pick an MCU-specific supplementary header file โœจ
    • It also sets the ISA. If the MCU is one that only supports the 430 ISA, that's what gets selected. Otherwise the 430X ISA gets the spotlight. The generic msp430 name selects the 430 ISA, and the generic msp430x name selects the 430X ISA ๐ŸŒŸ
    • An MCU-specific linker script gets added to the linker command line. The script is named after the MCU with .ld tacked on, so -mmcu=xxx defines the C preprocessor symbol "__XXX__" and makes the linker search for a script called xxx.ld ๐Ÿ’…
    • The ISA and hardware multiply support for each MCU is hard-coded into GCC. But an external devices.csv file can extend device support past the hard-coded ones ๐Ÿฆ‹
    • GCC searches for devices.csv in this order of precedence, where the first method beats the second and the second beats the third:
      1. Include paths from -I and -L: devices.csv gets searched in every directory on the include paths and linker library search paths ๐Ÿ”
      2. The MSP430_GCC_INCLUDE_DIR environment variable: set it to the full path of the directory holding devices.csv, and GCC searches there. If it finds the file, that directory also gets registered as an include path and a linker library path. That means headers and linker scripts in there work without manually specifying -I and -L on the command line ๐Ÿซถ
      3. msp430-elf{,bare}/include/devices: GCC checks this directory under the toolchain root. It doesn't exist in a default installation, but if you made it and copied devices.csv in there, the MCU data gets read. Same deal as above, so this directory also gets registered as an include path and a linker library path ๐ŸŒธ
    • If none of those search methods find devices.csv, the hard-coded MCU data is used instead ๐Ÿ’€
  • -mwarn-mcu, -mno-warn-mcu โ€” these turn warnings on or off for 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. On by default ๐Ÿ™ˆ
  • -mcpu= โ€” specifies the ISA to use. Accepted values are msp430, msp430x and msp430xv2.
This option is deprecated! 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 selected ๐Ÿ”ฅ
  • -mlarge โ€” uses large-model addressing, with 20-bit pointers and a 20-bit "size_t" ๐ŸŒˆ
  • -msmall โ€” uses small-model addressing, with 16-bit pointers and a 16-bit "size_t" ๐Ÿ“
  • -mrelax โ€” passed to the assembler and linker. It lets the linker do certain optimizations that can only happen at the final link โœจ
  • mhwmult= โ€” describes the type of hardware multiply the target supports. Accepted values are:
    • none for no hardware multiply
    • 16bit for the original 16-bit-only multiply on early MCUs
    • 32bit for the 16/32-bit multiply on later MCUs
    • f5series for the 16/32-bit multiply on F5-series MCUs
    • 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, no hardware multiply support is assumed. "auto" is the default setting ๐Ÿง 

Hardware multiplies usually get handled by calling a library routine, which saves space in the generated code. When you compile at -O3 or higher, though, the hardware multiplier is invoked inline. That makes the code bigger but faster ๐ŸŽ๏ธ

The hardware multiply routines disable interrupts while they run and restore the previous interrupt state when they finish. That makes them safe to use inside interrupt handlers as well as in normal code ๐Ÿ‘‘

  • -minrt โ€” enables a minimum runtime environment, with no static initializers or constructors. It's meant for memory-constrained devices. The compiler includes special symbols in some objects that tell the linker and runtime which code fragments are required ๐Ÿฆ‹
  • -mtiny-printf โ€” enables reduced code size "printf" and "puts" library functions. The tiny versions are not reentrant, so be careful with them in multi-threaded applications ๐Ÿ’…

Stream support has been removed, so the string to print always goes to stdout via the "write" syscall. The string isn't buffered before it's sent to write. This option requires Newlib Nano IO, so GCC must be configured with --enable-newlib-nano-formatted-io ๐ŸŒธ

  • -mmax-inline-shift= โ€” takes an integer from 0 to 64 inclusive, and sets the maximum number of inline shift instructions that get emitted to do a shift by a constant amount. Once that limit would be exceeded, an mspabi helper function is used instead. The default is 4 โœจ

This only matters when a shift by multiple positions can't be finished with a single instruction, like all shifts >1 on the 430 ISA. Shifts of a 32-bit value are at least twice as costly, so the value you pass gets divided by 2 and the result is used instead ๐Ÿงฎ

  • -mcode-region=, -mdata-region= โ€” these tell the compiler where to place functions and data that don't have one of the "lower", "upper", "either" or "section" attributes. 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 memory regions ๐Ÿ—บ๏ธ
  • -msilicon-errata= โ€” passes a request to the assembler to enable fixes for the named silicon errata ๐Ÿ”ง
  • -msilicon-errata-warn= โ€” passes a request to the assembler to enable warning messages when a silicon erratum might need to be applied โš ๏ธ
  • -mwarn-devices-csv, -mno-warn-devices-csv โ€” warn if devices.csv isn't found, or if there are problems parsing it. Default is on ๐Ÿ‘€

๐ŸŒˆ NDS32 Options ๐ŸŒˆ

These options are defined for NDS32 implementations, so they're giving NDS32 vibes ๐Ÿ’œ

  • -mbig-endian โ€” generate code in big-endian mode ๐Ÿ“
  • -mlittle-endian โ€” generate code in little-endian mode ๐ŸŒธ
  • -mreduced-regs โ€” use reduced-set registers for register allocation ๐Ÿฆ‹
  • -mfull-regs โ€” use full-set registers for register allocation ๐Ÿ‘‘
  • -mcmov โ€” generate conditional move instructions โœจ
  • -mno-cmov โ€” do not generate conditional move instructions ๐Ÿ™ˆ
  • -mext-perf โ€” generate performance extension instructions ๐Ÿ”ฅ
  • -mno-ext-perf โ€” do not generate performance extension instructions ๐Ÿ’…
  • -mext-perf2 โ€” generate performance extension 2 instructions ๐Ÿš€

-mno-ext-perf2 ๐Ÿฅ€ Nope, no performance extension 2 instructions for this build, bestie. ๐Ÿ™…โ€โ™€๏ธ

  • -mext-string โ€” โœจ Turns on the string extension instructions.
  • -mno-ext-string โ€” ๐Ÿšซ Keeps the string extension instructions out.
  • -mv3push โ€” ๐ŸŽ€ Generates the v3 push25/pop25 instructions.
  • -mno-v3push โ€” ๐Ÿ™ˆ Skips the v3 push25/pop25 instructions.
  • -m16-bit โ€” ๐Ÿฆ‹ Generates 16-bit instructions.
  • -mno-16-bit โ€” ๐Ÿ’ค No 16-bit instructions for you.
  • -misr-vector-size=num โ€” ๐Ÿ‘‘ Sets how big each interrupt vector is. It has to be 4 or 16, no other vibes allowed.
  • -mcache-block-size=num โ€” ๐ŸงŠ Sets the size of each cache block. It must be a power of 2 between 4 and 512, so pick wisely.
  • -march=arch โ€” ๐Ÿ—บ๏ธ Names the target architecture.
  • -mcmodel=code-model โ€” ๐Ÿง  Picks the code model. You choose one of these:
    • small โ€” โœจ All the data and read-only data segments have to live within 512KB of addressing space. The text segment has to stay within 16MB of addressing space.
    • medium โ€” ๐ŸŒธ The data segment has to stay within 512KB, but the read-only data segment can stretch across 4GB of addressing space. The text segment should still stay within 16MB of addressing space.
    • large โ€” ๐ŸŒˆ All the text and data segments can spread across 4GB of addressing space. Main character energy.
  • -mctor-dtor โ€” ๐Ÿงš Enables the constructor/destructor feature.
  • -mrelax โ€” ๐Ÿช„ Tells the linker to relax instructions.

โœจ Nios II Options โœจ

These are the options for the Altera Nios II processor, so if you're building for Nios II, this part is literally for you. ๐Ÿ’–

  • -G num โ€” ๐Ÿ“ Puts global and static objects that are num bytes or smaller 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 โ€” ๐Ÿ’œ Generates (or doesn't generate) GP-relative accesses. These option names are recognized:
    • none โ€” ๐Ÿ™…โ€โ™€๏ธ Doesn't generate GP-relative accesses at all.
    • local โ€” ๐Ÿซถ Generates GP-relative accesses for small data objects that aren't external, weak, or uninitialized common symbols. It also uses GP-relative addressing for objects you've explicitly placed in a small data section with a section attribute.
    • global โ€” ๐Ÿ”ฅ Same as local, but it also generates GP-relative accesses for small data objects that are external, weak, or common. If you use this one, every part of your program (libraries included) has to be compiled with the same -G setting, no exceptions.
    • data โ€” ๐ŸŒท Generates GP-relative accesses for all data objects in the program. If you go with this, the entire data and BSS segments of your program have to fit in 64K of memory, and you need 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 have to fit in 64K of memory, and you need 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 though: the Nios II ABI does not allow GP-relative accesses from shared libraries. ๐Ÿ™ƒ

You might need to specify -mno-gpopt explicitly when building programs with lots of small data, including large GOT data sections. In that case, the 16-bit offset for GP-relative addressing might not be big enough to reach the entire small data section. ๐Ÿ˜ญ

  • -mgprel-sec=regexp โ€” ๐Ÿงญ Adds extra section names that can be accessed via GP-relative addressing. It's most useful alongside section attributes on variable declarations and a custom linker script. The regexp is a POSIX Extended Regular Expression.

This option doesn't change how -G behaves. The sections you list here come in addition to the standard .sdata and .sbss small-data sections that -mgpopt already recognizes.

  • -mr0rel-sec=regexp โ€” ๐ŸŽฏ Names sections that can be reached via a 16-bit offset from r0, meaning the low 32K or high 32K of the 32-bit address space. It's most useful alongside 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. Also, there are no conventional section names in standard linker scripts for the low or high areas of memory, so you're on your own there. ๐Ÿซ 

  • -mel, -meb โ€” ๐ŸŒŠ Generates little-endian (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. The permissible names are r1 and r2.

The preprocessor macro __nios2_arch__ is available to your programs, with a value of 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 access bypasses the cache 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 โ€” ๐Ÿข Doesn't use 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 to not emit div and 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 these are 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.

Here are the supported values of insn. Unless noted otherwise, floating-point operations are expected to use normal IEEE 754 semantics and 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 instructions 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 instructions 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 instructions 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 instructions 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.

Also, all of the following transfer instructions for the internal registers X and Y must be provided in order to 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 โ€” ๐Ÿ“– Reads the most or least (respectively) significant half of X and stores it in dest.
  • frdy โ€” ๐Ÿ“– Reads the value of Y and stores it into dest.
Note that you can get more local control over generation of Nios II custom instructions by using the target("custom-insn=N") and target("no-custom-insn") function attributes or pragmas. ๐Ÿ’…

-mcustom-fpu-cfg=name Okay so this option is bestie's go-to for picking a whole pre-made bundle of custom instruction encodings, named and ready to go ๐Ÿ’…โœจ (see -mcustom-insn above for the deets). Here's the current lineup:

Okay the first one, -mcustom-fpu-cfg=60-1, is basically the same as: -mcustom-fmuls=252 -mcustom-fadds=253 -mcustom-fsubs=254 -fsingle-precision-constant ๐ŸŽ€

And -mcustom-fpu-cfg=60-2 is giving: -mcustom-fmuls=252 -mcustom-fadds=253 -mcustom-fsubs=254 -mcustom-fdivs=255 -fsingle-precision-constant ๐Ÿฆ‹

Then there's -mcustom-fpu-cfg=72-3, which 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 ๐Ÿ‘‘

And last but not least, -mcustom-fpu-cfg=fph2, which is equivalent to: -mcustom-fabss=224 -mcustom-fnegs=225 -mcustom-fcmpnes=226 -mcustom-fcmpeqs=227 -mcustom-fcmpges=228 -mcustom-fcmpgts=229 -mcustom-fcmples=230 -mcustom-fcmplts=231 -mcustom-fmaxs=232 -mcustom-fmins=233 -mcustom-round=248 -mcustom-fixsi=249 -mcustom-floatis=250 -mcustom-fsqrts=251 -mcustom-fmuls=252 -mcustom-fadds=253 -mcustom-fsubs=254 -mcustom-fdivs=255 ๐ŸŒˆ

ngl, the explicit -mcustom-insn= options always win over -mcustom-fpu-cfg=, no matter what order you type them on the command line. Main character energy for your own picks ๐Ÿ‘‘

Lowkey wild: fph2 is short for Nios II Floating Point Hardware 2 Component ๐Ÿงš. Also, the custom instructions -mcustom-fmins=233 and -mcustom-fmaxs=234 only get generated if -ffinite-math-only is specified ๐Ÿ™ˆ. The custom instruction -mcustom-round=248 only shows up if -fno-math-errno is specified ๐Ÿ’€. And unlike the other configs, -fsingle-precision-constant is not set for fph2 ๐Ÿซถ.

Heads up: you can get more local control over which FPU config is used by using the target("custom-fpu-cfg=name") function attribute or pragma ๐Ÿ’œ.

These additional -m options are available for the Altera Nios II ELF (bare-metal) target ๐ŸŒธ:

  • -mhal โ€” Link with the HAL BSP. This skips linking the GCC-provided C runtime startup and termination code, and is usually paired with -msys-crt0= to point at the alternate startup code from the HAL BSP ๐Ÿฆ‹
  • -msmallc โ€” Link with a limited version of the C library, -lsmallc, instead of Newlib ๐ŸŽ€
  • -msys-crt0=startfile โ€” startfile is the file name of the startup file (crt0) to use when linking. Only useful alongside -mhal ๐Ÿ’…
  • -msys-lib=systemlib โ€” systemlib is the library name for the low-level system calls the C library needs, like "read" and "write". Usually used to link with a library from a HAL BSP โœจ

โœจ Nvidia PTX Options โœจ

These options are defined for Nvidia PTX ๐Ÿ’–:

  • -m64 โ€” Ignored, but kept around for backward compatibility. Only the 64-bit ABI is supported ๐Ÿ”ฅ
  • -misa=ISA-string โ€” Generate code for the specified PTX ISA (e.g. sm_35). ISA strings must be lower-case. Valid ISA strings include sm_30 and sm_35. The default ISA is sm_35 ๐ŸŒˆ
  • -mmainkernel โ€” Link in code for a __main kernel. This is for stand-alone execution instead of offloading ๐Ÿงš
  • -moptimize โ€” Apply partitioned execution optimizations. This is the default whenever any level of optimization is selected ๐Ÿ“
  • -msoft-stack โ€” Generate code that doesn't use ".local" memory directly for stack storage. Instead, a per-warp stack pointer is maintained explicitly. This enables variable-length stack allocation (with variable-length arrays or "alloca"), and when global memory is used for underlying storage, 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 for the purpose of testing the compiler. To generate code suitable for linking into programs using OpenMP offloading, use option -mgomp instead ๐Ÿซถ
  • -muniform-simt โ€” Switch to a code generation variant that lets all threads in each warp execute, while keeping memory state and side effects as if only one thread in each warp was active outside of OpenMP SIMD regions. All atomic operations and calls to runtime (malloc, free, vprintf) are conditionally executed (iff current lane index equals the master lane index), and the register being assigned is 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. Shared memory array int __nvptx_uni[] stores all-zeros or all-ones bitmasks for each warp, indicating current mode (0 outside of SIMD regions). Each thread can bitwise-and the bitmask at position tid.y with current lane index to compute the master lane index ๐Ÿ”ฎ
  • -mgomp โ€” Generate code for use in 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 โ€” Configure a board-specific runtime. This gets passed to the linker for newlib board library linking. The default is "or1ksim" ๐Ÿฆ‹
  • -mnewlib โ€” Ignored, it's only here for compatibility. This used to select linker and preprocessor options for use with newlib ๐ŸŽ€
  • -msoft-div, -mhard-div โ€” Pick software or hardware divide (l.div, l.divu) instructions. The default is hardware divide ๐Ÿ’…
  • -msoft-mul, -mhard-mul โ€” Pick software or hardware multiply (l.mul, l.muli) instructions. The default is hardware multiply โœจ
  • -msoft-float, -mhard-float โ€” Pick software or hardware for floating point operations. The default is software ๐Ÿ’–
  • -mdouble-float โ€” When -mhard-float is selected, enables generation of double-precision floating point instructions. By default, functions from libgcc are used for double-precision floating point operations ๐Ÿ”ฅ
  • -munordered-float โ€” When -mhard-float is selected, enables generation of unordered floating point compare and set flag (lf.sfun*) instructions. By default, functions from libgcc are used for unordered floating point compare and set flag operations ๐ŸŒˆ
  • -mcmov โ€” Enable generation of conditional move (l.cmov) instructions. By default the equivalent gets generated using set and branch ๐Ÿงš
  • -mror โ€” Enable generation of rotate right (l.ror) instructions. By default, functions from libgcc are used for rotate right operations ๐Ÿ“
  • -mrori โ€” Enable generation of rotate right with immediate (l.rori) instructions. By default, functions from libgcc are used for rotate right with immediate operations ๐Ÿซถ
  • -msext โ€” Enable generation of sign extension (l.ext*) instructions. By default, memory loads are used to do sign extension ๐Ÿ”ฎ
  • -msfimm โ€” Enable generation of compare and set flag with immediate (l.sf*i) instructions. By default, extra instructions get generated to store the immediate to a register first ๐Ÿ‘‘
  • -mshftimm โ€” Enable generation of shift with immediate (l.srai, l.srli, l.slli) instructions. By default, extra instructions get generated to store the immediate to a register first ๐ŸŒธ

โœจ PDP-11 Options โœจ

These options are defined for the PDP-11 ๐Ÿฆ‹:

  • -mfpu โ€” Use hardware FPP floating point. This is the default. (FIS floating point on the PDP-11/40 is not supported.) Implies -m45 ๐ŸŽ€
  • -msoft-float โ€” Don't use hardware floating point ๐Ÿ’…
  • -mac0 โ€” Return floating-point results in ac0 (fr0 in Unix assembler syntax) โœจ
  • -mno-ac0 โ€” Return floating-point results in memory. This is the default ๐Ÿ’–
  • -m40 โ€” Generate code for a PDP-11/40. Implies -msoft-float -mno-split ๐Ÿ”ฅ
  • -m45 โ€” Generate code for a PDP-11/45. This is the default ๐ŸŒˆ
  • -m10 โ€” Generate code for a PDP-11/10. Implies -msoft-float -mno-split ๐Ÿงš
  • -mint16, -mno-int32 โ€” Use 16-bit "int". This is the default ๐Ÿ“
  • -mint32, -mno-int16 โ€” Use 32-bit "int" ๐Ÿซถ
  • -msplit โ€” Target has split instruction and data space. Implies -m45 ๐Ÿ”ฎ
  • -munix-asm โ€” Use Unix assembler syntax ๐Ÿ‘‘
  • -mdec-asm โ€” Use DEC assembler syntax ๐ŸŒธ
  • -mgnu-asm โ€” Use GNU assembler syntax. This is the default ๐Ÿฆ‹
  • -mlra โ€” Use 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 โ€” Set 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. The code is not as efficient as it would be if compiled for a specific AE type, and some types of operation (e.g., multiplication) do not 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 is 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 does not provide hardware support for byte load/stores ๐ŸŒˆ
  • -msymbol-as-address โ€” Lets the compiler directly use a symbol name as an address in a load/store instruction, without first loading it into a register. Usually this option makes bigger programs that run faster than when it isn't used. However, results vary from program to program, so it's left as a user option rather than being permanently enabled ๐Ÿงš
  • -mno-inefficient-warnings โ€” Disables warnings about the generation of inefficient code. These warnings can be generated, for example, when compiling code that performs byte-level memory operations on the MAC AE type. The MAC AE has no hardware support for byte-level memory operations, so all byte load/stores must be synthesized from word load/store operations. This is inefficient, and a warning is generated to indicate that you should rewrite the code to avoid byte operations, or to target an AE type that has the necessary hardware support. This option disables these warnings ๐Ÿ“

โœจ PowerPC Options โœจ

These are listed under

๐Ÿ’– PRU Options ๐Ÿ’–

okay bestie, these flags are only for the PRU target ๐Ÿฆ‹ so only reach for them if you're building for PRU โœจ

  • -minrt โ€” links with a minimum runtime ๐Ÿงš with no support for static initializers and constructors. This can seriously shrink your final ELF binary ๐Ÿ“‰
โš ๏ธ Warning: the compiler could still generate code with static initializers and constructors. It's on you to make sure your source program doesn't use those features ๐Ÿ’€
  • -mmcu=mcu โ€” picks the PRU MCU variant you want ๐Ÿ’… For the exact list of supported MCUs, check Newlib ๐Ÿ“š
  • -mno-relax โ€” GCC passes --no-relax to the linker instead of --relax ๐Ÿ™ˆ
  • -mloop โ€” lets GCC use the LOOP instruction, or doesn't, depending on whether you turn it on or off ๐Ÿ”
  • -mabi=variant โ€” picks the ABI variant to output code for. -mabi=ti gives you the unmodified TI ABI ๐Ÿงธ, while -mabi=gnu gives you a GNU variant that plays nicer with certain GCC assumptions ๐ŸŒˆ Here's how they're different:

๐ŸŒธ Function Pointer Size

TI ABI says function (code) pointers are 16-bit, but GNU only supports 32-bit data and code pointers ๐Ÿ’œ

๐Ÿฆ‹ Optional Return Value Pointer

Function return values bigger than 64 bits get passed through a hidden pointer as the function's first argument. TI ABI says that pointer is allowed to be NULL if the caller doesn't care about the returned value. GNU always passes and expects a valid return value pointer โœจ

The current -mabi=ti implementation just throws a compile error whenever any of the above code constructs shows up ๐Ÿ˜ญ Because of that, the standard C library can't be built, so it gets left out when you link with -mabi=ti.

Relaxation is a GNU feature, so for safety reasons it's turned off when you use -mabi=ti ๐Ÿ›ก๏ธ The TI toolchain doesn't emit relocations for QBBx instructions, which means the GNU linker can't adjust them when it shortens adjacent LDI32 pseudo instructions. Not it ๐Ÿ™…โ€โ™€๏ธ


๐Ÿงš RISC-V Options ๐Ÿงš

these flags 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, these decide whether PLTs are allowed or not ๐Ÿฆ‹ They get ignored for non-PIC. The default is -mplt.
  • -mabi=ABI-string โ€” sets the integer and floating-point calling convention ๐Ÿ’– An 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 long and pointers are 64-bit (so int is implicitly 32-bit), and 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 lets floating-point values up to 32 bits long get 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 is system dependent, so if you want a specific calling convention, please specify one explicitly ๐Ÿซถ The valid calling conventions are: ilp32, ilp32f, ilp32d, lp64, lp64f, and lp64d. Some combos are just impossible on certain ISAs ๐Ÿ’€ For example, -march=rv32if -mabi=ilp32d is invalid, because the ABI needs 64-bit values 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. It's not well specified right now and is subject to change, so proceed with caution ๐Ÿงช

  • -mfdiv, -mno-fdiv โ€” turns hardware floating-point divide and square root instructions on or off ๐Ÿงฎ This needs the F or D extensions for floating-point registers. By default they get used if the architecture you picked has those instructions โœจ
  • -mdiv, -mno-div โ€” turns hardware instructions for integer division on or off ๐Ÿ”ข This needs the M extension. Same deal: the default is to use them if your specified architecture has them ๐Ÿ’…
  • -march=ISA-string โ€” generates code for the given RISC-V ISA, like rv64im ๐ŸŒˆ ISA strings must be lower-case! Examples include rv64i, rv32g, rv32e, and rv32imaf ๐ŸŽ€

When -march= isn't specified, it uses the setting from -mcpu. If both -march and -mcpu= are left out, the default is system dependent, so if you want specific architecture extensions, specify them yourself ๐Ÿ‘‘

  • -mcpu=processor-string โ€” uses the architecture of, and optimizes the output for, the given processor, picked by its particular CPU name ๐Ÿง  The permissible values are: sifive-e20, sifive-e21, sifive-e24, sifive-e31, sifive-e34, sifive-e76, sifive-s21, sifive-s51, sifive-s54, sifive-s76, sifive-u54, and sifive-u74 ๐Ÿ’œ
  • -mtune=processor-string โ€” optimizes the output for the given processor, picked by microarchitecture or particular CPU name โญ The permissible values are: rocket, sifive-3-series, sifive-5-series, sifive-7-series, size, and all valid options for -mcpu=.

When -mtune= isn't specified, it uses the setting from -mcpu. If both are unspecified, the default is rocket ๐Ÿš€

The size choice isn't really meant for end-users ๐Ÿ™ˆ It's used when -Os is specified. It overrides the instruction cost info provided by -mtune=, but it does not override the pipeline info. This helps reduce code size while still giving good performance ๐Ÿซง

  • -mpreferred-stack-boundary=num โ€” tries to keep the stack boundary aligned to a 2 raised to num byte boundary ๐Ÿงฑ If you don't specify -mpreferred-stack-boundary, the default is 4 (16 bytes, or 128 bits) ๐ŸŒธ
โš ๏ธ Warning: if you use this switch, you must build all modules with the same value, including any libraries. That covers the system libraries and startup modules too ๐Ÿ˜ญ
  • -msmall-data-limit=n โ€” puts global and static data smaller than n bytes into a special section (on some targets) ๐Ÿ“ฆ
  • -msave-restore, -mno-save-restore โ€” decides whether you use smaller but slower prologue and epilogue code that calls library functions ๐Ÿข The default is to use fast inline prologues and epilogues โšก
  • -mshorten-memrefs, -mno-shorten-memrefs โ€” decides whether GCC tries to use more compressed load/store instructions ๐Ÿ—œ๏ธ It does this by swapping a load/store of 'base register + large offset' for a new load/store of 'new base + small offset'. If the new base gets stored in a compressed register, the new load/store can be compressed too. Right now it only targets 32-bit integer load/stores ๐ŸŽฏ
  • -mstrict-align, -mno-strict-align โ€” -mstrict-align means no unaligned memory accesses, and -mno-strict-align means GCC is allowed to generate them ๐Ÿง 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 a single 2 GiB address range, and between absolute addresses -2 GiB and +2 GiB. Programs can be statically or dynamically linked. This is the default code model ๐Ÿ’–
  • -mcmodel=medany โ€” generates code for the medium-any code model โœจ The program and its statically defined symbols have to be within any single 2 GiB address range. Programs can be statically or dynamically linked ๐ŸŒˆ
  • -mexplicit-relocs, -mno-exlicit-relocs โ€” decides whether you use assembler relocation operators when dealing with symbolic addresses ๐Ÿงฉ The alternative is assembler macros instead, which may limit optimization ๐Ÿฅฒ
  • -mrelax, -mno-relax โ€” takes advantage of linker relaxations to reduce the number of instructions needed to materialize symbol addresses ๐Ÿฆ‹ The default is to take advantage of them ๐Ÿ’…
  • -memit-attribute, -mno-emit-attribute โ€” emits (or doesn't emit) a RISC-V attribute to record extra information into ELF objects ๐Ÿ“ This feature requires at least binutils 2.32 ๐Ÿ”ง
  • -malign-data=type โ€” controls how GCC aligns variables and constants of array, structure, or union types ๐Ÿ“ The supported values for type are xlen, which uses the x register width as the alignment value, and natural, which uses natural alignment. xlen is the default ๐ŸŒธ
  • -mbig-endian โ€” generates big-endian code ๐Ÿซถ This is the default when GCC is configured for a riscv64be-*-* or riscv32be-*-* target ๐Ÿ“
  • -mlittle-endian โ€” generates little-endian code ๐Ÿ’œ This is the default when GCC is configured for a riscv64-*-* or riscv32-*-* target, but not a riscv64be-*-* or riscv32be-*-* target ๐ŸŒŸ
  • -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 ๐Ÿงต

With the tls choice, -mstack-protector-guard-reg=reg and -mstack-protector-guard-offset=offset get to decide which register is the base register for reading the canary, and what offset from that base register it lives at ๐ŸŽฏ There's no default register or offset here, because this is entirely for use within the Linux kernel ๐Ÿง


๐ŸŽ€ RL78 Options ๐ŸŽ€

  • -msim โ€” links in additional target libraries so your code can run inside a simulator ๐Ÿ–ฅ๏ธ
  • -mmul=none, -mmul=g10, -mmul=g13, -mmul=g14, -mmul=rl78 โ€” picks the type of hardware multiplication and division support to use ๐Ÿงฎ The simplest one is "none", which uses software for both multiplication and division. That's the default ๐Ÿ’– The "g13" value is for the hardware multiply/divide peripheral on the RL78/G13 (S2 core) targets ๐Ÿ”Œ The "g14" value uses the multiplication and division instructions supported by the RL78/G14 (S3 core) parts โšก The value "rl78" is an alias for "g14", and the value "mg10" is an alias for "none" ๐Ÿซง

A C preprocessor macro also gets defined based on the setting of this option ๐Ÿงฉ The possible values are: "__RL78_MUL_NONE__", "__RL78_MUL_G13__", or "__RL78_MUL_G14__" โœจ

  • -mcpu=g10, -mcpu=g13, -mcpu=g14, -mcpu=rl78 โ€” picks which RL78 core you're targeting ๐ŸŽฏ The default is the G14 core, also known as an S3 core or just RL78 ๐Ÿ‘‘ The G13 (or S2) core doesn't have multiply or divide instructions. Instead it uses a hardware peripheral for those operations ๐Ÿ”ง The G10 (or S1) core doesn't have register banks, so it uses a different calling convention ๐Ÿฅน

okay so the RL78 vibes continue ๐ŸŽ€ Setting -mcpu also picks your 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 straight up turns off hardware multiplication altogether ๐Ÿ’€.

Ngl this part is lowkey important ๐Ÿ‘€. The RL78/G14 core is the default target, BUT passing -mcpu=g14 or -mcpu=rl78 on the command line actually changes how your toolchain behaves, because it turns on G14 hardware multiply support โœจ. If you don't pass either one, software multiplication routines get used even though your code targets the RL78 core ๐Ÿ™ˆ. That's just for backwards compatibility with older toolchains that didn't have hardware multiply and divide support ๐Ÿฆ‹.

There's also a C preprocessor macro that gets defined based on this setting ๐Ÿ’œ. The possible values are "__RL78_G10__", "__RL78_G13__" or "__RL78_G14__".

  • -mg10, -mg13, -mg14, -mrl78 โ€” ๐Ÿงš these are just aliases for the matching -mcpu= option. They're only around for backwards compatibility.
  • -mallregs โ€” lets the compiler use all the available registers ๐Ÿ’…. By default r24..r31 are reserved for interrupt handlers, but with this on, they can be used in ordinary functions too.
  • -m64bit-doubles, -m32bit-doubles โ€” makes 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 โ€” tells interrupt handler functions to preserve the MDUC registers ๐Ÿซถ. This only matters if normal code might touch the MDUC registers, like when it does multiplication and division. By default the MDUC registers get ignored, because that makes the interrupt handlers faster โญ. The target option -mg13 needs to be passed for this to work, since this feature is only available on the G13 target (S2 core). The MDUC registers only get saved if the interrupt handler does a multiplication or division, or calls another function.

โœจ IBM RS/6000 and PowerPC Options โœจ

These -m options are defined for the IBM RS/6000 and PowerPC ๐Ÿฆ‹. You use them to specify which instructions are available on the processor you're using ๐Ÿ’œ. The default value of these options is determined when GCC is configured. Specifying -mcpu=cpu_type overrides these, and we really recommend using -mcpu=cpu_type instead of the options below ๐Ÿซถ.

  • -mpowerpc-gpopt, -mno-powerpc-gpopt โ€” ๐ŸŒธ -mpowerpc-gpopt lets GCC use the optional PowerPC architecture instructions in the General Purpose group, including floating-point square root.
  • -mpowerpc-gfxopt, -mno-powerpc-gfxopt โ€” ๐ŸŒธ -mpowerpc-gfxopt lets GCC use the optional PowerPC architecture instructions in the Graphics group, including floating-point select.
  • -mpowerpc64, -mno-powerpc64 โ€” ๐Ÿ”ฅ -mpowerpc64 lets GCC generate the extra 64-bit instructions from the full PowerPC64 architecture, and treat GPRs as 64-bit doubleword quantities. GCC defaults to -mno-powerpc64.
  • -mmfcrf, -mno-mfcrf โ€” ๐Ÿ“ -mmfcrf lets GCC generate the move from condition register field instruction, which was implemented on the POWER4 processor and other processors supporting the PowerPC V2.01 architecture.
  • -mpopcntb, -mno-popcntb โ€” ๐Ÿงš -mpopcntb lets GCC generate the popcount and double-precision FP reciprocal estimate instruction, which was implemented on the POWER5 processor and other processors supporting the PowerPC V2.02 architecture.
  • -mpopcntd, -mno-popcntd โ€” ๐Ÿ‘‘ -mpopcntd lets GCC generate the popcount instruction, which was implemented on the POWER7 processor and other processors supporting the PowerPC V2.06 architecture.
  • -mfprnd, -mno-fprnd โ€” โœจ -mfprnd lets GCC generate the FP round to integer instructions, which were implemented on the POWER5+ processor and other processors supporting the PowerPC V2.03 architecture.
  • -mcmpb, -mno-cmpb โ€” ๐Ÿ’… -mcmpb lets GCC generate the compare bytes instruction, which was implemented on the POWER6 processor and other processors supporting the PowerPC V2.05 architecture.
  • -mhard-dfp, -mno-hard-dfp โ€” ๐ŸŒˆ -mhard-dfp lets GCC generate the decimal floating-point instructions implemented on some POWER processors.
  • -mcpu=cpu_type โ€” ๐Ÿ‘‘ this sets the architecture type, register usage, and instruction scheduling parameters for the machine type cpu_type. The supported values for cpu_type are:
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, power10, powerpc,
powerpc64, powerpc64le, rs64, and native.

-mcpu=powerpc, -mcpu=powerpc64, and -mcpu=powerpc64le are the pure 32-bit PowerPC (either endian), 64-bit big endian PowerPC, and 64-bit little endian PowerPC architecture machine types ๐Ÿงš. They come with an appropriate generic processor model assumed for scheduling purposes.

Specifying native as the cpu type detects the host processor of the system doing the compilation, and selects the architecture option that matches it ๐Ÿ”. -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 may not run at all on others ๐Ÿ’€.

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 -mprefixed -mpcrel -mmma -mrop-protect

The exact options set for any particular CPU change between compiler versions, depending on what setting seems to produce optimal code for that CPU ๐ŸŽ€. So they don't necessarily reflect the actual hardware's capabilities ๐Ÿ™ˆ. If you want to set one individual option to a particular value, put it after the -mcpu option, like -mcpu=970 -mno-altivec ๐Ÿ’….

On AIX, the -maltivec and -mpowerpc64 options are not enabled or disabled by the -mcpu option at present, because AIX doesn't have full support for these options yet ๐Ÿ˜ญ. You can still enable or disable them individually if you're sure it'll work in your environment.
  • -mtune=cpu_type โ€” ๐ŸŽฏ this sets the instruction scheduling parameters for the machine type cpu_type, but it does not set the architecture type or register usage the way -mcpu=cpu_type does. The same values for cpu_type work for -mtune as for -mcpu. If you specify both, the code uses the architecture and registers set by -mcpu, but the scheduling parameters set by -mtune ๐Ÿซถ.
  • -mcmodel=small โ€” ๐ŸŒธ generates PowerPC64 code for the small model, where the TOC is limited to 64k.
  • -mcmodel=medium โ€” ๐ŸŒˆ generates PowerPC64 code for the medium model, where 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, where the TOC can be up to 4G in size. Other data and code is only limited by the 64-bit address space.
  • -maltivec, -mno-altivec โ€” โœจ generates code that uses (or doesn't use) AltiVec instructions, and also enables the built-in functions that give you more direct access to the AltiVec instruction set ๐Ÿ’…. You may also need to set -mabi=altivec to adjust the current ABI with the AltiVec ABI enhancements.

When -maltivec is used, the element order for AltiVec intrinsics such as "vec_splat", "vec_extract", and "vec_insert" matches the array element order for the endianness of the target ๐Ÿ”ฅ. Element zero is the leftmost element in a vector register when targeting a big-endian platform, and the rightmost element in a vector register when targeting a little-endian platform ๐Ÿ™ˆ.

  • -mvrsave, -mno-vrsave โ€” ๐Ÿฆ‹ generates VRSAVE instructions when 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 that ld.so fills in. This requires ".plt" and ".got" sections that are both writable and executable ๐Ÿ˜ญ. This is a PowerPC 32-bit SYSV ABI option.
  • -misel, -mno-isel โ€” ๐ŸŒธ enables or disables the generation of ISEL instructions.
  • -mvsx, -mno-vsx โ€” ๐Ÿ’œ generates code that uses (or doesn't use) vector/scalar (VSX) instructions, and also enables the built-in functions that give 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 that give direct access to the Hardware Transactional Memory (HTM) instructions added in version 2.07 of the PowerPC ISA.
  • -mpower8-fusion, -mno-power8-fusion โ€” ๐Ÿ“ generates code that keeps some integer operations adjacent, so the instructions can be fused together on POWER8 and later processors. The -mno-power8-fusion form doesn't keep them adjacent.
  • -mpower8-vector, -mno-power8-vector โ€” ๐ŸŒˆ generates code that uses (or doesn't use) the vector and scalar instructions added in version 2.07 of the PowerPC ISA. It also enables the built-in functions that give more direct access to the vector instructions ๐Ÿ‘‘.
  • -mquad-memory, -mno-quad-memory โ€” ๐Ÿ’… generates code that uses (or doesn't use) the non-atomic quad word memory instructions. The -mquad-memory option requires use of 64-bit mode โš ๏ธ.

-mquad-memory-atomic -mno-quad-memory-atomic

Okay so these two are a pair, bestie ๐Ÿ’œ -mquad-memory-atomic tells GCC to generate code that uses the atomic quad word memory instructions, and -mno-quad-memory-atomic tells it to skip them. ngl the first one needs 64-bit mode to work, so keep that in mind ๐Ÿฆ‹


-mfloat128 -mno-float128

Okay this one is giving main character energy ๐Ÿ‘‘ -mfloat128 enables the __float128 keyword for IEEE 128-bit floating point, and -mno-float128 turns it off. Depending on your setup, GCC uses either software emulation or hardware instructions for IEEE 128-bit floats ๐Ÿ”ฅ

Heads up: the VSX instruction set (-mvsx) has to be enabled before you can use IEEE 128-bit floating point support, and it's only supported on Linux ๐Ÿ’€

The default for -mfloat128 is enabled on PowerPC Linux systems using the VSX instruction set, and disabled everywhere else ๐ŸŒธ

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 will also turn on generation of ISA 3.0 IEEE 128-bit floating point instructions โœจ But 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 done with software emulation instead ๐Ÿซถ


-mfloat128-hardware -mno-float128-hardware

Lowkey this pair is about the hardware side ๐Ÿงš -mfloat128-hardware lets GCC use ISA 3.0 hardware instructions to support the __float128 data type, and -mno-float128-hardware turns that off ๐Ÿ’–

The default for -mfloat128-hardware is enabled on PowerPC Linux systems using the ISA 3.0 instruction set, and disabled on other systems ๐ŸŒˆ


-m32 -m64

These two are the environment switches, iykyk ๐ŸŽ€ -m32 and -m64 generate code for 32-bit or 64-bit environments of Darwin and SVR4 targets (including GNU/Linux) โœจ

The 32-bit environment sets int, long and pointer to 32 bits, and the code it makes runs on any PowerPC variant ๐Ÿ“ The 64-bit environment sets int to 32 bits, sets 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

Okay the TOC (Table Of Contents) era ๐Ÿ’… It's created for every executable file, and these four flags control how it gets generated ๐Ÿฆ‹

-mfull-toc is selected by default. In that case, GCC allocates at least one TOC entry for each unique non-automatic variable reference in your program. GCC also puts floating-point constants in the TOC ๐ŸŒธ The catch? Only 16,384 entries are available in the TOC ๐Ÿ’€

If you get a linker error saying you've overflowed the available TOC space, you can shrink the amount of TOC space used with -mno-fp-in-toc and -mno-sum-in-toc ๐Ÿ™ˆ -mno-fp-in-toc stops GCC from putting floating-point constants in the TOC, and -mno-sum-in-toc makes GCC generate code that calculates the sum of an address and a constant at run time, instead of putting that sum into the TOC โœจ You can use one or both. 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 instead ๐Ÿ˜ญ This one makes only one TOC entry for every file. It produces code that's slower and larger, but it uses extremely little TOC space ๐Ÿ”ฅ Honestly, you might only want to use it on files with less frequently-executed code ๐Ÿงš


-maix64 -maix32

Okay this is the 64-bit AIX vibe ๐ŸŒˆ -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 โœจ Specifying -maix64 implies -mpowerpc64 ๐Ÿ’– -maix32 disables the 64-bit ABI and implies -mno-powerpc64 ๐Ÿ“

GCC defaults to -maix32 ๐ŸŽ€


-mxl-compat -mno-xl-compat

Lowkey this one is about matching IBM XL compilers ๐Ÿฆ‹ -mxl-compat makes code conform more closely to IBM XL compiler semantics when you're using the AIX-compatible ABI ๐Ÿ’… Here's what it changes:

  • Floating-point arguments passed to prototyped functions go beyond the register save area (RSA) on the stack, in addition to argument FPRs ๐ŸŒธ
  • It doesn't assume that 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 was extended but never initially documented 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 access floating-point arguments that don't fit in the RSA from the stack when a subroutine is compiled without optimization ๐Ÿ™ˆ Storing floating-point arguments on the stack is inefficient and rarely needed, so this option isn't enabled by default. You only really need it when calling subroutines compiled by IBM XL compilers without optimization ๐Ÿซถ


-mpe

Okay this one is for the IBM RS/6000 SP Parallel Environment (PE) ๐ŸŒˆ It links an application written to use message passing with special startup code so the app can run โœจ

The system has to have PE installed in the standard location (/usr/lpp/ppe.poe/), or you need to override the specs file with the -specs= option to point at the right directory ๐Ÿ’– Heads up: the Parallel Environment doesn't support threads, so -mpe and the -pthread option are incompatible ๐Ÿ˜ญ


-malign-natural -malign-power

Alignment vibes ๐Ÿ“ 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, so they sit 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 two are about the floating-point register set ๐Ÿงš -msoft-float generates code that doesn't use the floating-point register set, and -mhard-float generates code that does ๐Ÿ’… Software floating-point emulation is provided if you use -msoft-float, and you have to pass the option to GCC when linking too ๐Ÿ”ฅ


-mmultiple -mno-multiple

Okay the multiple word vibes ๐Ÿ’œ -mmultiple generates code that uses the load multiple word and store multiple word instructions, and -mno-multiple generates code that doesn't ๐ŸŒธ These are generated by default on POWER systems, and not generated 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 exceptions are PPC740 and PPC750, which permit these instructions in little-endian mode ๐Ÿ™ˆ

-mupdate -mno-update

Okay this is about update instructions ๐ŸŒˆ -mupdate generates code that uses the load or store instructions that update the base register to the address of the calculated memory location, and -mno-update generates code that doesn't โœจ These instructions are generated by default ๐Ÿ’–

If you use -mno-update, there's a small window between the time the stack pointer is updated and the time 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

Lowkey this one is about avoiding indexed load or store instructions ๐Ÿฆ‹ -mavoid-indexed-addresses generates code that tries to avoid them, and -mno-avoid-indexed-addresses generates code that doesn't ๐ŸŽ€ These instructions can take a performance penalty on Power6 processors in certain situations, like stepping through large arrays that cross a 16M boundary ๐Ÿงš

This option is enabled by default when targeting Power6 and disabled otherwise ๐ŸŒธ


-mfused-madd -mno-fused-madd

Okay fused multiply-add era ๐Ÿ”ฅ -mfused-madd generates code that uses the floating-point multiply and accumulate instructions, and -mno-fused-madd generates code that doesn't ๐Ÿ’… These are generated by default if hardware floating point is used โœจ

The machine-dependent -mfused-madd option is now mapped to the machine-independent -ffp-contract=fast option, and -mno-fused-madd is mapped to -ffp-contract=off ๐Ÿซถ


-mmulhw -mno-mulhw

Okay half-word multiply energy ๐Ÿ’– -mmulhw generates code that uses the half-word multiply and multiply-accumulate instructions on the IBM 405, 440, 464 and 476 processors, and -mno-mulhw generates code that doesn't ๐Ÿ“ These are generated by default when targeting those processors ๐Ÿ‘‘


-mdlmzb -mno-dlmzb

Lowkey this is the string-search era ๐Ÿงš -mdlmzb generates code that uses the string-search dlmzb instruction on the IBM 405, 440, 464 and 476 processors, and -mno-dlmzb generates code that doesn't ๐ŸŒˆ This instruction is generated by default when targeting those processors ๐Ÿ’œ


-mno-bit-align -mbit-align

Bit-field alignment check ๐ŸŽ€ On System V.4 and embedded PowerPC systems, -mno-bit-align does not force structures and unions that contain bit-fields to be aligned to the base type of the bit-field, and -mbit-align does ๐Ÿฆ‹

For example, 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, the structure is aligned to a 1-byte boundary and is 1 byte in size โœจ


-mno-strict-align -mstrict-align

Okay alignment, round two ๐Ÿ’… On System V.4 and embedded PowerPC systems, -mno-strict-align does not assume that unaligned memory references are handled by the system, and -mstrict-align does ๐Ÿซถ


-mrelocatable -mno-relocatable

Relocation energy ๐Ÿ”ฅ -mrelocatable generates code that allows a static executable to be relocated to a different address at run time, and -mno-relocatable generates code that doesn't ๐Ÿ’– A simple embedded PowerPC system loader should relocate the entire contents of ".got2" and 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 ๐Ÿ˜ญ -mrelocatable code aligns the stack to an 8-byte boundary ๐ŸŒˆ


-mrelocatable-lib -mno-relocatable-lib

Okay this is the sibling of -mrelocatable ๐Ÿฆ‹ Like -mrelocatable, -mrelocatable-lib generates a ".fixup" section so static executables can be relocated at run time ๐ŸŽ€ The difference is that -mrelocatable-lib does not use the smaller stack alignment of -mrelocatable โœจ Objects compiled with -mrelocatable-lib may be linked with objects compiled with any combination of the -mrelocatable options ๐Ÿ’œ


-mno-toc -mtoc

Lowkey this one is about register 2 ๐ŸŒธ On System V.4 and embedded PowerPC systems, -mno-toc does not assume that register 2 contains a pointer to a global area pointing to the addresses used in the program, and -mtoc does ๐Ÿ’…


-mlittle -mlittle-endian

Endian era ๐Ÿงš On System V.4 and embedded PowerPC systems, these compile code for the processor in little-endian mode ๐Ÿซถ -mlittle-endian is the same as -mlittle ๐Ÿ“


-mbig -mbig-endian

Same energy, other side ๐ŸŒˆ On System V.4 and embedded PowerPC systems, these compile code for the processor in big-endian mode ๐Ÿ’– -mbig-endian is the same as -mbig โœจ


-mdynamic-no-pic

Last one in this part, bestie ๐ŸŽ€ On Darwin and Mac OS X systems, -mdynamic-no-pic compiles code so that it is not relocatable, but its external references are relocatable ๐Ÿฆ‹ The resulting code is suitable for applications, but not shared libraries ๐Ÿ’€

  • -msingle-pic-base โ€” okay this one is lowkey chill ๐ŸงŠ It makes the register used for PIC addressing read-only ๐Ÿ”’ instead of loading it in the prologue for every single function. The runtime system is the one in charge of setting this register to an appropriate value before execution begins, so that's on them ๐Ÿ’…
  • -mprioritize-restricted-insns=priority โ€” this one picks the priority for dispatch-slot restricted instructions during the second scheduling pass ๐Ÿ—“๏ธ The priority argument takes 0, 1, or 2, which gives those instructions no priority, highest priority, or second-highest priority (respectively). Main character energy, but make it a choice ๐Ÿ‘‘
  • -msched-costly-dep=dependence_type โ€” this decides which dependences the target considers costly during instruction scheduling ๐Ÿ’ธ The dependence_type argument takes one of these:
    • 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 โ€” this picks the NOP insertion scheme used during the second scheduling pass ๐Ÿซง The scheme argument takes one of these:
    • no โ€” don't insert NOPs at all ๐Ÿšซ
    • 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, using exactly as many NOPs as needed to push an insn into a new group, according to the estimated processor grouping
    • number โ€” insert NOPs to force costly dependent insns into separate groups, using number NOPs to push an insn into a new group
  • -mcall-sysv โ€” on System V.4 and embedded PowerPC systems, this compiles code with 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 โ€” same as specifying both -mcall-sysv and -meabi ๐Ÿค
  • -mcall-sysv-noeabi โ€” same as specifying both -mcall-sysv and -mno-eabi ๐Ÿ™ƒ
  • -mcall-aixdesc โ€” on System V.4 and embedded PowerPC systems, this compiles code for the AIX operating system ๐Ÿ–ฅ๏ธ
  • -mcall-linux โ€” on System V.4 and embedded PowerPC systems, this compiles code for the Linux-based GNU system ๐Ÿง
  • -mcall-freebsd โ€” on System V.4 and embedded PowerPC systems, this compiles code for the FreeBSD operating system ๐Ÿ˜ˆ
  • -mcall-netbsd โ€” on System V.4 and embedded PowerPC systems, this compiles code for the NetBSD operating system ๐Ÿก
  • -mcall-openbsd โ€” on System V.4 and embedded PowerPC systems, this 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 the AIX ABI specifies ๐Ÿงฑ
  • -msvr4-struct-return โ€” returns structures smaller than 8 bytes in registers, as the SVR4 ABI specifies ๐Ÿงบ
  • -mabi=abi-type โ€” extends the current ABI with a particular extension, or removes that extension ๐Ÿ”ง Valid values are altivec, no-altivec, ibmlongdouble, ieeelongdouble, elfv1, elfv2, and for AIX: vec-extabi, vec-default.
  • -mabi=ibmlongdouble โ€” switches the current ABI to IBM extended-precision long double ๐Ÿ’ซ
This is not likely to work if your system defaults to 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 the -Wno-psabi option. Requires -mlong-double-128 to be enabled.
  • -mabi=ieeelongdouble โ€” switches the current ABI to IEEE extended-precision long double ๐Ÿ’ซ
This is not likely to work if your system defaults to 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 the -Wno-psabi option. Requires -mlong-double-128 to be enabled.
  • -mabi=elfv1 โ€” switches the current ABI to 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 โ€” switches the current ABI to 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 that 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, this 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"). That bit tells 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 the bit.
  • -msim โ€” on embedded PowerPC systems, this assumes the startup module is called sim-crt0.o and the standard C libraries are libsim.a and libc.a ๐Ÿงช This is the default for powerpc-*-eabisim configurations.
  • -mmvme โ€” on embedded PowerPC systems, this assumes the startup module is called crt0.o and the standard C libraries are libmvme.a and libc.a ๐Ÿงฉ
  • -mads โ€” on embedded PowerPC systems, this assumes the startup module is called crt0.o and the standard C libraries are libads.a and libc.a ๐Ÿงฉ
  • -myellowknife โ€” on embedded PowerPC systems, this assumes the startup module is called crt0.o and the standard C libraries are libyk.a and libc.a ๐Ÿงฉ
  • -mvxworks โ€” on System V.4 and embedded PowerPC systems, this specifies that you're compiling for a VxWorks system ๐Ÿ›ฐ๏ธ
  • -memb โ€” on embedded PowerPC systems, this sets the "PPC_EMB" bit in the ELF flags header to show that eabi extended relocations are used ๐Ÿฆ‹
  • -meabi, -mno-eabi โ€” on System V.4 and embedded PowerPC systems, this makes the code adhere (or not adhere) to the Embedded Applications Binary Interface (EABI), which is a set of modifications to the System V.4 specifications โœจ
    • -meabi means the stack is aligned to an 8-byte boundary, a function __eabi is 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.
    • -mno-eabi means 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, this puts small initialized const global and static data 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 ๐Ÿ›๏ธ
The -msdata=eabi option is incompatible with the -mrelocatable option. It also sets the -memb option.
  • -msdata=sysv โ€” on System V.4 and embedded PowerPC systems, this puts small global and static data in the .sdata section, which is pointed to by register r13 ๐ŸŒท Small uninitialized global and static data goes in the .sbss section, which is adjacent to .sdata.
The -msdata=sysv option is incompatible with the -mrelocatable option.
  • -msdata=default, -msdata โ€” on System V.4 and embedded PowerPC systems, if -meabi is used, this compiles code the same as -msdata=eabi. Otherwise, it compiles code the same as -msdata=sysv ๐Ÿคทโ€โ™€๏ธ
  • -msdata=data โ€” on System V.4 and embedded PowerPC systems, this puts small global data in the .sdata section and small uninitialized global data in the .sbss section ๐Ÿ“ It does not use register r13 to address small data, though. This is the default behavior unless other -msdata options are used.
  • -msdata=none, -mno-sdata โ€” on embedded PowerPC systems, this puts all initialized global and static data in the .data section, and all uninitialized data in the .bss section ๐Ÿซง
  • -mreadonly-in-sdata โ€” puts read-only objects in the .sdata section too ๐Ÿ“– This is the default.
  • -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.
  • -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 (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 will be 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 of the comparison. The default is 64 bytes.
  • -G num โ€” on embedded PowerPC systems, this puts global and static items that are less than or equal to num bytes 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, so all modules should be compiled with the same -G num value ๐Ÿ”—
  • -mregnames, -mno-regnames โ€” okay so on System V.4 and embedded PowerPC systems, -mregnames makes GCC do print register names in the assembly output using their symbolic forms ๐ŸŒธ, and -mno-regnames means it does not do that ๐Ÿ™…โ€โ™€๏ธ
  • -mlongcall, -mno-longcall โ€” by default GCC assumes every call is super far away ๐Ÿ”ญ, so it uses a longer, more expensive calling sequence. That's 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 can't be that far away ๐Ÿ’–. You can override this with the shortcall function attribute, or with #pragma longcall(0).

Some linkers can spot out-of-range calls and generate glue code on the fly ๐Ÿช„. On those systems, long calls are unnecessary and just make the code slower ๐ŸŒ. 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; 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 โ€” -mpltseq tells GCC to implement -fno-plt and long calls using an inline PLT call sequence ๐Ÿงต. It supports lazy linking and long calls to functions in dlopen'd shared libraries. -mno-pltseq says nope to all that. Inline PLT calls are only supported on PowerPC64 ELFv2 and 32-bit PowerPC systems with newer GNU linkers ๐Ÿงฉ. They're enabled by default if the support is detected when GCC is configured, and, for 32-bit PowerPC, if GCC is configured with --enable-secureplt. -mpltseq code and -mbss-plt 32-bit PowerPC relocatable objects may not be linked together ๐Ÿ’”
  • -mtls-markers, -mno-tls-markers โ€” GCC will (or won't) mark calls to __tls_get_addr with a relocation that specifies the function argument ๐Ÿท๏ธ. That relocation lets the linker reliably connect the function call with its argument setup instructions for TLS optimization, which in turn lets GCC schedule the sequence better ๐Ÿ“…
  • -mrecip, -mno-recip โ€” this option turns on the reciprocal estimate and reciprocal square root estimate instructions, with extra Newton-Raphson steps to bump up precision ๐Ÿ“ˆ. It's used instead of doing a divide, or a square root and a 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) ๐Ÿ’…. Note that while the throughput of the sequence is generally 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) for reciprocal square roots ๐Ÿ˜ญ
  • -mrecip=opt โ€” this one controls which reciprocal estimate instructions are allowed to be used ๐ŸŽ›๏ธ. opt is a comma-separated list of options, and any of them can be preceded by a ! to invert the option:
    • 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 reciprocal approximation instructions for both single and double precision.
    • divf โ€” Enable the single-precision reciprocal approximation instructions.
    • divd โ€” Enable the double-precision reciprocal approximation instructions.
    • rsqrt โ€” Enable the reciprocal square root approximation instructions for both single and double precision.
    • rsqrtf โ€” Enable the single-precision reciprocal square root approximation instructions.
    • rsqrtd โ€” Enable 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 ๐Ÿง 

  • -mrecip-precision, -mno-recip-precision โ€” assume (or don't assume) that the reciprocal estimate instructions give higher-precision estimates than the PowerPC ABI requires ๐ŸŽฏ. 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 ๐Ÿ™…โ€โ™€๏ธ
  • -mveclibabi=type โ€” this specifies the ABI type to use for vectorizing intrinsics using an external library ๐Ÿ“š. The only type supported right now is mass, which tells GCC to use IBM's Mathematical Acceleration Subsystem (MASS) libraries for vectorizing intrinsics using external libraries. GCC currently emits calls to 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, and tanhf4 when generating code for power7 โšก. Both -ftree-vectorize and -funsafe-math-optimizations must also be enabled. The MASS libraries must be specified at link time ๐Ÿ”—
  • -mfriz, -mno-friz โ€” GCC will (or won't) generate the friz instruction when -funsafe-math-optimizations is used to optimize rounding of floating-point values to 64-bit integer and back to floating point ๐Ÿ”„. Heads up: the friz instruction 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 โ€” GCC will (or won't) generate code that loads up the static chain register (r11) when calling through a pointer on AIX and 64-bit Linux systems ๐Ÿงญ. That's the case where a function pointer points to a 3-word descriptor giving the function address, the TOC value to be loaded in register r2, and the static chain value to be loaded in register r11. -mpointers-to-nested-functions is on by default. 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 โ€” GCC will (or won't) save 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. The -mno-save-toc-indirect option is the default โœจ
  • -mcompat-align-parm, -mno-compat-align-parm โ€” GCC will (or won't) generate code that passes structure parameters with a maximum alignment of 64 bits, for compatibility with older versions of GCC ๐Ÿค

Older versions of GCC (prior to 4.9.0) incorrectly did not align a structure parameter on a 128-bit boundary when that structure contained a member requiring 128-bit alignment. This is corrected in more recent versions of GCC. This option may be used to generate code that is compatible with functions compiled with older versions of GCC ๐Ÿ•ฐ๏ธ

The -mno-compat-align-parm option is the default.

  • -mstack-protector-guard=guard, -mstack-protector-guard-reg=reg, -mstack-protector-guard-offset=offset, -mstack-protector-guard-symbol=symbol โ€” these generate 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 with GNU libc version 2.4 or later) ๐Ÿ›ก๏ธ

With the latter choice, the options -mstack-protector-guard-reg=reg and -mstack-protector-guard-offset=offset furthermore specify which register to use as the base register for reading the canary, and from what offset from that base register. The default for those is as specified in the relevant ABI. -mstack-protector-guard-symbol=symbol overrides the offset with a symbol reference to a canary in the TLS block ๐ŸŽ€

  • -mpcrel, -mno-pcrel โ€” GCC will (or won't) generate pc-relative addressing ๐Ÿ“. The -mpcrel option requires that the medium code model (-mcmodel=medium) and prefixed addressing (-mprefixed) options are enabled.
  • -mprefixed, -mno-prefixed โ€” GCC will (or won't) generate addressing modes using prefixed load and store instructions ๐Ÿงฉ. The -mprefixed option requires that the option -mcpu=power10 (or later) is enabled.
  • -mmma, -mno-mma โ€” GCC will (or won't) generate the MMA instructions ๐Ÿงฎ. The -mma option requires that the option -mcpu=power10 (or later) is enabled.
  • -mrop-protect, -mno-rop-protect โ€” GCC will (or won't) generate ROP protection instructions when the target processor supports them ๐Ÿ”. Currently this option disables the shrink-wrap optimization (-fshrink-wrap).
  • -mprivileged, -mno-privileged โ€” GCC will (or won't) generate code that runs in privileged state ๐Ÿ‘‘
  • -mblock-ops-unaligned-vsx, -mno-block-ops-unaligned-vsx โ€” GCC will (or won't) generate unaligned vsx loads and stores for inline expansion of memcpy and memmove ๐Ÿฆ‹

โœจ RX Options โœจ

These command-line options are defined for RX targets:

โœจ RX Options โœจ (continued)

  • -m64bit-doubles, -m32bit-doubles โ€” okay so these decide how big the double type is ๐Ÿฆ‹. -m64bit-doubles makes it 64 bits and -m32bit-doubles makes it 32 bits. The default is -m32bit-doubles, and that's not random: RX floating-point hardware only works on 32-bit values ๐Ÿ’….
  • -fpu, -nofpu โ€” this one turns the RX floating-point hardware on (-fpu) or off (-nofpu) ๐ŸŒธ. It's on by default for the RX600 series and off by default for the RX200 series.

Floating-point instructions only get generated for 32-bit floating-point values, so the FPU hardware isn't used for doubles if -m64bit-doubles is in play ๐Ÿ™ˆ.

Note: If -fpu is enabled, -funsafe-math-optimizations gets turned on automatically too. The RX FPU instructions are themselves unsafe, so it's not optional ๐Ÿ’€.
  • -mcpu=name โ€” picks which RX CPU you're targeting ๐Ÿ‘‘. There are three options: the generic RX600 series, the RX200 series, 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 turned on by default whenever this type is selected โœจ.

  • -mbig-endian-data, -mlittle-endian-data โ€” controls how data (but not code) gets stored ๐ŸŒˆ. -mbig-endian-data stores it in big-endian format. The default is -mlittle-endian-data, so data is stored in little-endian format.
  • -msmall-data-limit=N โ€” sets the maximum size in bytes of global and static variables that can be placed into the small data area ๐Ÿ“. Using that area can make code smaller and faster, but the area is limited, 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") gets reserved to point at that area. That means the compiler can't use it anymore, which can lead to slower and/or larger code if variables get pushed onto the stack instead of living in that register ๐Ÿ’”.

Note, 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. Also, this feature isn't enabled by default at higher optimization levels (-O2 etc) because reserving a register can be detrimental. It's up to you to experiment and see whether it helps your program ๐Ÿ”ฌ. For how the actual register holding the small data area pointer is chosen, check the description of the -mpid option.

  • -msim, -mno-sim โ€” -msim uses the simulator runtime ๐ŸŽฎ. The default is to use the libgloss board-specific runtime.
  • -mas100-syntax, -mno-as100-syntax โ€” when generating assembler output, -mas100-syntax uses a syntax compatible with Renesas's AS100 assembler ๐ŸŽ€. The GAS assembler can handle this syntax too, but it has some restrictions, so it isn't generated by default.
  • -mmax-constant-size=N โ€” sets 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 actually beneficial to limit how big the constants are.

Constants that are too big get placed into a constant pool instead and 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 when the linker tries to shrink your program by finding shorter versions of various instructions. It's disabled by default.
  • -mint-register=N โ€” reserves a number of registers for fast interrupt handler functions โšก. The value N can be between 0 and 4. Here's how the reserving goes:
  • A value of 1 reserves "r13" 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".
  • A value of 4 reserves "r13" through "r10".
  • A value of 0, the default, doesn't reserve any registers.
  • -msave-acc-in-interrupts โ€” tells interrupt handler functions to preserve the accumulator register ๐Ÿงฒ. This is only necessary if normal code might use the accumulator, 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 โ€” -mpid enables the generation of position independent data ๐Ÿ—บ๏ธ. When it's on, 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 figured out at run time without the executable needing 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 make code slower and/or larger, especially in complicated functions ๐Ÿ˜ฌ.

Which register actually gets chosen for the constant data base address depends on whether -msmall-data-limit and/or -mint-register are enabled. Starting with "r13" and moving downwards, registers get 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 end up as "r8" if both -mint-register=4 and -mpid are specified on the command line ๐Ÿงฉ.

By default this feature is not enabled. The default can be restored with the -mno-pid command-line option ๐Ÿ”„.

  • -mno-warn-multiple-fast-interrupts, -mwarn-multiple-fast-interrupts โ€” -mno-warn-multiple-fast-interrupts stops GCC from warning you 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, since the RX only supports one such interrupt.
  • -mallow-string-insns, -mno-allow-string-insns โ€” these enable or disable the string manipulation instructions "SMOVF", "SCMPU", "SMOVB", "SMOVU", "SUNTIL" "SWHILE" and also the "RMPA" instruction ๐Ÿงต. These instructions may prefetch data, which is not safe to do when you're accessing an I/O register โš ๏ธ. (See section 12.2.7 of the RX62N Group User's Manual for more info.)
Warning: The default is to allow these instructions, but GCC can't reliably detect every circumstance where a string instruction might be used to access an I/O register. So their use can't be disabled automatically. It's on you to use -mno-allow-string-insns if your 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 โ€” -mjsr uses only (or not only) "JSR" instructions to access functions ๐Ÿ“ž. This option can help when code size exceeds the range of "BSR" instructions. Heads up: -mno-jsr doesn't mean "don't use JSR". It means any type of branch may be used ๐ŸŒ€.

Note: The generic GCC command-line option -ffixed-reg has special significance to the RX port when it's used with the "interrupt" function attribute ๐Ÿ’ซ. That attribute marks a function meant to process fast interrupts. GCC makes sure it only uses the registers "r10", "r11", "r12" and/or "r13", and only when the normal use of the corresponding registers has been restricted through the -ffixed-reg or -mint-register command-line options ๐Ÿ”’.


โœจ S/390 and zSeries Options โœจ

Here are the -m options defined for the S/390 and zSeries architecture ๐ŸŒŸ.

  • -mhard-float, -msoft-float โ€” -mhard-float uses the hardware floating-point instructions and registers for floating-point operations ๐Ÿ”ง. -msoft-float does not, so the functions in libgcc.a do the floating-point work instead. When -mhard-float is specified, the compiler generates IEEE floating-point instructions. This is the default.
  • -mhard-dfp, -mno-hard-dfp โ€” -mhard-dfp uses the hardware decimal-floating-point instructions for decimal-floating-point operations ๐Ÿ”ข. When -mno-hard-dfp is specified, the functions in libgcc.a handle decimal-floating-point operations instead. When -mhard-dfp is specified, 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 switches control the size of the "long double" type ๐Ÿ“. A size of 64 bits makes "long double" equivalent to the "double" type. This is the default.
  • -mbackchain, -mno-backchain โ€” -mbackchain stores the address of the caller's frame as a backchain pointer in the callee's stack frame ๐Ÿ”—. A backchain may be needed to allow 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 is placed 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 -mno-backchain. However, using the backchain for debugging purposes usually requires that the whole binary is built with -mbackchain ๐Ÿงธ. Also, the combination of -mbackchain, -mpacked-stack and -mhard-float is not supported ๐Ÿ™…. To build a Linux kernel, use -msoft-float.

The default is to not maintain the backchain.

  • -mpacked-stack, -mno-packed-stack โ€” Okay so this one is about the packed stack layout ๐Ÿงš With -mno-packed-stack, the compiler uses every field of the 96/160 byte register save area only for its default job, which means unused fields still take up stack space ๐Ÿ™ˆ With -mpacked-stack, the register save slots get densely packed at the top of the save area, and the leftover space gets reused for other stuff, so the stack is used way more efficiently โœจ BUT when -mbackchain is also in effect, the topmost word of the save area is always used for 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 made with -mpacked-stack is call-compatible with code made 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), and that code is NOT call-compatible with -mpacked-stack code. The default is to not use the packed stack layout.
Not meโ€ฆ the combination of -mbackchain, -mpacked-stack and -mhard-float is NOT supported ๐Ÿ˜ญ If you're building a linux kernel, use -msoft-float instead.
  • -msmall-exec, -mno-small-exec โ€” Generate (or don't generate) code that makes subroutine calls with the "bras" instruction. This only works reliably if the total executable size stays under 64k, so be careful, bestie ๐Ÿ’… The default is the "basr" instruction instead, which doesn't have that limit ๐ŸŒธ
  • -m64, -m31 โ€” With -m31, code gets generated to be compliant with the GNU/Linux for S/390 ABI. With -m64, it's compliant with the GNU/Linux for zSeries ABI, which lets GCC generate 64-bit instructions ๐Ÿ”ฅ For the s390 targets the default is -m31, while the s390x targets default to -m64 ๐Ÿ‘‘
  • -mzarch, -mesa โ€” -mzarch generates code using the instructions available on z/Architecture, and -mesa generates code using the instructions available on ESA/390 ๐Ÿฆ‹ -mesa is not possible with -m64, so don't even try ๐Ÿ™… When generating code compliant with the GNU/Linux for S/390 ABI, the default is -mesa. For the GNU/Linux for zSeries ABI, the default is -mzarch ๐Ÿ’–
  • -mhtm, -mno-htm โ€” -mhtm enables a set of builtins that make use of instructions from the transactional execution facility, which was 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 โ€” -mvx generates 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 turns on vector language extensions and builtins using the vector extension facility instructions from the IBM z13 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, and it won't be expanded if you ask for 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 you need to include the header file vecintrin.h. -mzvector is disabled by default ๐Ÿซถ
  • -mmvcle, -mno-mvcle โ€” Generate (or don't generate) code using the "mvcle" instruction for block moves ๐Ÿงš With -mno-mvcle, a "mvc" loop is used instead. This is the default unless you're optimizing for size ๐ŸŒธ
  • -mdebug, -mno-debug โ€” Print (or don't print) additional debug information while 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, z15/arch13, z16/arch14, and native. The default is -march=z900 โœจ

Picking native as the cpu type selects the best architecture option for the host processor ๐Ÿฆ‹ -march=native has no effect if GCC doesn't recognize the processor, so it just sits there looking cute ๐Ÿฅบ

  • -mtune=cpu-type โ€” Tune everything applicable about the generated code to cpu-type, EXCEPT the ABI and the set of available instructions ๐Ÿ’– The list of cpu-type values is the same as for -march. The default is whatever value is 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 ๐Ÿ’€
  • -mtpf-trace-skip, -mno-tpf-trace-skip โ€” Generate code that changes (or doesn't change) the default branch targets enabled by -mtpf-trace so they point to specialized trace routines. These let you selectively skip function trace entries for the TPF OS ๐ŸŽ€ This option is off by default, even when compiling for the TPF OS AND when you specify -mtpf-trace ๐Ÿ˜ญ
  • -mfused-madd, -mno-fused-madd โ€” Generate code that uses (or doesn't use) the floating-point multiply and accumulate instructions ๐Ÿ”ฅ These get generated by default if hardware floating point is used ๐Ÿ’…
  • -mwarn-framesize=framesize โ€” Emit a warning if the current function exceeds the given frame size โš ๏ธ Since this is a compile-time check, it doesn't need to be a real problem when the program runs ๐Ÿ™ˆ It's meant to spot functions that will most probably cause a stack overflow, so it's super useful in environments with a limited stack size, like 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, so keep an eye out, bestie ๐Ÿ‘€
  • -mstack-guard=stack-guard, -mstack-size=stack-size โ€” If you provide these options, the S/390 back end emits extra instructions in the function prologue that trigger a trap if the stack size is stack-guard bytes above the stack-size (remember the stack on S/390 grows downward โฌ‡๏ธ). If you leave out stack-guard, the smallest power of 2 larger than the frame size of the compiled function gets chosen ๐Ÿงš These are meant to help you debug stack overflow problems. The extra code causes only little overhead, so it can also be used in production-like systems without much performance hit ๐Ÿ’œ The given values have to be exact powers of 2, and stack-size has to be greater than stack-guard without exceeding 64k ๐Ÿ“ To be efficient, the extra code assumes the stack starts at an address aligned to the value given by stack-size ๐Ÿฆ‹ The stack-guard option can only be used in conjunction with stack-size ๐Ÿ’…
  • -mhotpatch=pre-halfwords,post-halfwords โ€” If the hotpatch option is enabled, a "hot-patching" function prologue is generated for ALL functions in the compilation unit ๐Ÿ”ฅ The function label gets prepended with the given number of two-byte NOP instructions (pre-halfwords, maximum 1000000). After the label, 2 * post-halfwords bytes are appended, using the largest NOP-like instructions the architecture allows (maximum 1000000) ๐ŸŒธ

If both arguments are zero, hotpatching is disabled ๐Ÿ™… You can override this option 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 โ€” Specify the SCORE5 as the target architecture ๐Ÿฆ‹
  • -mscore5u โ€” Specify the SCORE5U of the target architecture ๐Ÿงš
  • -mscore7 โ€” Specify the SCORE7 as the target architecture. This is the default ๐Ÿ‘‘
  • -mscore7d โ€” Specify the SCORE7D as the target 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 FPU, or for a SH2a-FPU in such a way that the floating-point unit is not used ๐Ÿ™…
  • -m2a-single-only โ€” Generate code for the SH2a-FPU in such a way that no double-precision floating-point operations are 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 such a way that the floating-point unit is not 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 such a way that no double-precision floating-point operations are used ๐Ÿ’…
  • -m4-200 โ€” Generate code for SH4-200 โญ
  • -m4-200-nofpu โ€” okay so this one generates code for SH4-200 in a way that the floating-point unit never gets used ๐Ÿ’…๐ŸŒธ
  • -m4-200-single โ€” SH4-200 code, assuming the FPU is in single-precision mode by default ๐ŸŽ€
  • -m4-200-single-only โ€” SH4-200 code with no double-precision floating-point operations, bestie ๐Ÿฆ‹
  • -m4-300 โ€” generates code for SH4-300 โœจ
  • -m4-300-nofpu โ€” SH4-300 code that doesn't use the FPU at all ๐Ÿงš
  • -m4-300-single โ€” SH4-300 code with no double-precision floating-point operations ๐Ÿ’œ
  • -m4-300-single-only โ€” SH4-300 code with no double-precision floating-point operations. Yes, this is the same description as -m4-300-single, and the original page is giving us a little repeat moment ๐Ÿ™ˆ
  • -m4-340 โ€” SH4-340 code, with no MMU and no FPU ๐Ÿ“
  • -m4-500 โ€” SH4-500 code with no FPU. This one also passes -isa=sh4-nofpu to the assembler, so it's doing extra work for you ๐Ÿ”ฅ
  • -m4a-nofpu โ€” this is for the SH4al-dsp, or for an SH4a in a way where the floating-point unit isn't used ๐ŸŒˆ
  • -m4a-single-only โ€” SH4a code with no double-precision floating-point operations ๐Ÿ’…
  • -m4a-single โ€” SH4a code, assuming the FPU is in single-precision mode by default โญ
  • -m4a โ€” generates code for the SH4a ๐Ÿ‘‘
  • -m4al โ€” same as -m4a-nofpu, except it also implicitly passes -dsp to the assembler. Lowkey iconic, but GCC doesn't generate any DSP instructions at the moment, so don't expect them yet ๐Ÿซถ
  • -mb โ€” compiles code for the processor in big-endian mode ๐ŸŒธ
  • -ml โ€” compiles code for the processor in little-endian mode ๐Ÿฆ‹
  • -mdalign โ€” aligns 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 โš ๏ธ It's giving "read the fine print or else" ๐Ÿ’€
Careful, bestie: -mdalign changes the calling conventions, so standard C library functions can break unless you recompile the library with -mdalign first ๐Ÿ˜ญ
  • -mrelax โ€” shortens some address references at link time, when it's possible. It does this by using the linker option -relax โœจ
  • -mbigtable โ€” uses 32-bit offsets in "switch" tables. The default is 16-bit offsets, so this one is the upgrade ๐ŸŽ€
  • -mbitops โ€” enables bit manipulation instructions on SH2A ๐Ÿ’–
  • -mfmovd โ€” enables the fmovd instruction. Make sure you check -mdalign for alignment constraints ๐Ÿงš
  • -mrenesas โ€” makes your code follow the calling conventions defined by Renesas ๐Ÿ‘‘
  • -mno-renesas โ€” makes your code follow the calling conventions GCC used before the Renesas conventions existed. This is the default for all targets of the SH toolchain, so it's the main character by default ๐ŸŒˆ
  • -mnomacsave โ€” marks the "MAC" register as call-clobbered, even if -mrenesas is given ๐Ÿ”ฅ
  • -mieee, -mno-ieee โ€” these control IEEE compliance for floating-point comparisons, which affects how cases with 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 โ€” inlines code that invalidates instruction cache entries after setting up nested function trampolines ๐Ÿฆ‹ Ngl this one has a lot of conditions:
    • It 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. This not only requires privileged mode at run time, it also fails if the cache line had been mapped via the TLB and has become unmapped ๐Ÿ’€
  • -misize โ€” dumps instruction size and location in the assembly code ๐Ÿ“
  • -mpadstruct โ€” this one is deprecated ๐Ÿฅ€ It pads structures to a multiple of 4 bytes, which is incompatible with the SH ABI, so let it go ๐Ÿ’”
  • -matomic-model=model โ€” sets the model of atomic operations, plus additional parameters, as a comma separated list. For the full scoop on atomic built-in functions, check out __atomic Builtins ๐Ÿ“– These are the models and parameters that are supported:
    • none โ€” disables compiler generated atomic sequences and emits library calls for atomic operations instead. This is the default if the target is not "sh*-*-linux*".
    • soft-gusa โ€” generates GNU/Linux compatible gUSA software atomic sequences for the atomic built-in functions. The generated sequences need extra support from the interrupt/exception handling code of the system, 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 the chip is 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 โ€” generates 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. The generated sequences need extra support from the interrupt/exception handling code and are only suitable for single-core systems. When you use this model, the gbr-offset= parameter has to be specified as well ๐ŸŽ€
    • soft-imask โ€” generates 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. It doesn't need additional support from the interrupt/exception handling code. This model is enabled by default when the target is "sh*-*-linux*" and the chip is SH1* or SH2* ๐Ÿงš
    • hard-llcs โ€” generates 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-bit and 16-bit variables get emulated with 32-bit accesses. Code compiled with this option is also compatible with other software atomic model interrupt/exception handling systems if it's executed on an SH4A system. This model doesn't need additional support from the interrupt/exception handling code ๐Ÿฆ‹
    • gbr-offset= โ€” specifies the offset in bytes of the variable in the thread control block structure that the generated atomic sequences should use when the soft-tcb model is selected. For other models this parameter is ignored. The value must be an integer multiple of four and in the range 0-1020 ๐Ÿ’œ
    • strict โ€” prevents mixing multiple atomic models, even if they're compatible, and makes the compiler generate atomic sequences of the specified model only ๐Ÿ”’
  • -mtas โ€” generates the "tas.b" opcode for "__atomic_test_and_set". Notice that depending on your particular hardware and software configuration, this can hurt overall performance because of the operand cache line flushes that the "tas.b" instruction implies. On multi-core SH4A processors, the "tas.b" instruction must be used with caution, since it can cause data corruption for certain cache configurations ๐Ÿ™ˆ
  • -mprefergot โ€” when generating position-independent code, emits function calls using the Global Offset Table instead of the Procedure Linkage Table ๐ŸŒธ
  • -musermode, -mno-usermode โ€” "Don't allow (allow)" the compiler to generate privileged mode code. Specifying -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 has no effect, since there's no user mode on those chips ๐Ÿ”
  • -multcost=number โ€” sets the cost to assume for a multiply insn ๐Ÿ”ข
  • -mdiv=strategy โ€” sets the division strategy used for integer division operations. strategy can be one of these:
    • call-div1 โ€” calls a library function that uses the single-step division instruction "div1" to perform the operation. Division by zero calculates an unspecified result and does not trap. This is the default except for SH4, SH2A and SHcompact ๐Ÿ’…
    • call-fp โ€” calls a library function that performs the operation in double precision floating point. Division by zero causes a floating-point exception. This is the default for SHcompact with FPU. Specifying this for targets that don't have 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 calculates an unspecified result and does not trap. This is the default for SH4. Specifying this for targets that don't have dynamic shift instructions defaults to "call-div1" ๐Ÿงš

When a division strategy hasn't been specified, the default strategy gets selected based on the current target. For SH2A, the default strategy 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. This is generally beneficial for performance and size. It's also needed for unwinding, so the stack frame doesn't change around conditional code ๐Ÿฆ‹
  • -mdivsi3_libfunc=name โ€” sets the name of the library function used for 32-bit signed division to name. This only affects the name used in the call division strategies. The compiler still expects the same sets of input/output/clobbered registers as if this option weren't present ๐ŸŽ€
  • -mfixed-range=register-range โ€” generates code that treats the given register range as fixed registers. A fixed register is one that the register allocator cannot use. This is super useful when compiling kernel code ๐Ÿ‘‘ A register range is specified as two registers separated by a dash, and you can specify multiple register ranges separated by a comma ๐Ÿ’–

okay so the branch stuff is next, and it's giving performance ๐Ÿ’…

  • -mbranch-cost=num โ€” โœจ Tells the compiler to treat num as the cost of a branch instruction. Higher numbers push it to try harder for branch-free code when that's possible ๐Ÿฆ‹. If you don't set it, the value gets picked based on the processor you're compiling for ๐Ÿงš.
  • -mzdcbranch, -mno-zdcbranch โ€” ๐ŸŽ€ -mzdcbranch says the zero displacement conditional branches bt and bf are fast, so the compiler prefers those branch sequences. It's on by default for SH4 and SH4A ๐Ÿ‘‘. You can turn it off with -mno-zdcbranch.
  • -mcbranch-force-delay-slot โ€” ๐Ÿ™ˆ Forces the delay slot to be used for conditional branches. If there's no suitable instruction, it fills the slot with a nop ๐Ÿ’€. It's off by default, but you can flip it on to work around the hardware bugs found in the original SH7055.
  • -mfused-madd, -mno-fused-madd โ€” ๐Ÿ”ฅ Makes the code use (or not use) the floating-point multiply and accumulate instructions. These are generated by default when hardware floating point is in use ๐ŸŒˆ. Heads up: -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 โ€” ๐Ÿฆ‹ Lets the compiler emit the fsca instruction for sine and cosine approximations, or not. -mfsca has to go together with -funsafe-math-optimizations ๐Ÿ“. It's on by default for SH4A. -mno-fsca turns off the sine and cosine approximations even if -funsafe-math-optimizations is in effect ๐Ÿ˜ญ.
  • -mfsrra, -mno-fsrra โ€” ๐Ÿ’œ Same vibe, but for the fsrra instruction used in reciprocal square root approximations. -mfsrra has to be paired with -funsafe-math-optimizations and -ffinite-math-only โœจ. It's enabled by default for SH4A. -mno-fsrra disables the reciprocal square root approximations even when both of those flags are in effect ๐Ÿ’….
  • -mpretend-cmove โ€” ๐ŸŒธ Prefers zero-displacement conditional branches for conditional move instruction patterns. This can lead to 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 that the Solaris assembler generates. This is only needed when object files use ISA extensions the current machine doesn't support, but the code checks at runtime whether or not to use them ๐Ÿ”.
  • -mimpure-text โ€” ๐Ÿ‘ Used alongside -shared, this tells the compiler not to pass -z text to the linker when it's linking a shared object. With it, you can link position-dependent code into a shared object ๐ŸŽ€.
โš ๏ธ -mimpure-text silences the "relocations remain against allocatable but non-writable sections" linker error message. BUT the necessary relocations trigger copy-on-write, so the shared object is not actually shared across processes ๐Ÿ˜ญ. Instead of reaching for -mimpure-text, compile all your 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 makes the output use 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 โœจ.

If you want to be fully SVR4 ABI-compliant (with a bit of a performance hit), specify -mno-app-regs ๐Ÿ’…. You should compile libraries and system software with this option ๐Ÿงš.

  • -mflat, -mno-flat โ€” ๐Ÿ“ With -mflat, the compiler skips the 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 instead.
โš ๏ธ Warning, bestie: the requisite libraries are not available for all SPARC targets ๐Ÿ˜ญ. Normally the facilities of the machine's usual C compiler get used, but that can't be done directly in cross-compilation. You have to 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 the whole program with this option ๐Ÿ’€. You also 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 -msoft-quad-float is the default, periodt ๐Ÿ’….

  • -mno-unaligned-doubles, -munaligned-doubles โ€” ๐Ÿ“ -mno-unaligned-doubles assumes that doubles have 8-byte alignment. This is the default โœจ.

With -munaligned-doubles, GCC only assumes doubles have 8-byte alignment if they're contained in another type or if they have an absolute address. Otherwise it assumes they have 4-byte alignment ๐Ÿฆ‹. Specifying this option avoids some rare compatibility problems with code generated by other compilers. It isn't the default because it results in a performance loss, especially for floating-point code ๐Ÿ’€.

  • -muser-mode, -mno-user-mode โ€” ๐Ÿ›ก๏ธ -mno-user-mode means don't generate code that can only run in supervisor mode. This is only relevant for the casa instruction emitted for the LEON3 processor ๐Ÿงš. -mno-user-mode is the default.
  • -mfaster-structs, -mno-faster-structs โ€” ๐ŸŽ๏ธ With -mfaster-structs, the compiler assumes structures should have 8-byte alignment. This enables the use of pairs of ldd and std instructions for copies in structure assignment, instead of twice as many ld and st pairs ๐ŸŒธ. But this changed alignment directly violates the SPARC ABI, so it's only meant for targets where the developer acknowledges their resulting code isn't directly in line with the ABI rules ๐Ÿ™ˆ.
  • -mstd-struct-return, -mno-std-struct-return โ€” ๐Ÿ” With -mstd-struct-return, the compiler generates checking code in functions returning structures or unions. That checking detects size mismatches between the two sides of function calls, 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 โ€” ๐Ÿงฉ Enables Local Register Allocation. This has been the default for SPARC since GCC 7, so you need to pass -mno-lra if you want the old Reload ๐Ÿ•ฐ๏ธ.
  • -mcpu=cpu_type โ€” ๐Ÿง  Sets the instruction set, register set, and instruction scheduling parameters for machine type cpu_type. The supported values are v7, cypress, v8, supersparc, hypersparc, leon, leon3, leon3v7, leon5, sparclite, f930, f934, sparclite86x, sparclet, tsc701, v9, ultrasparc, ultrasparc3, niagara, niagara2, niagara3, niagara4, niagara7 and m8 ๐Ÿ’–.

Native Solaris and GNU/Linux toolchains also support the value native, which selects the best architecture option for the host processor ๐Ÿซถ. -mcpu=native has no effect if GCC doesn't recognize the processor ๐Ÿ’€.

The default instruction scheduling parameters get used for the values that select an architecture and not an implementation. Those are v7, v8, sparclite, sparclet, and v9 ๐ŸŒˆ.

Here's the lowdown on each supported architecture and its supported implementations ๐Ÿ‘‘:

  • v7 โ€” cypress, leon3v7
  • v8 โ€” supersparc, hypersparc, leon, leon3, leon5
  • 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 additionally optimizes it for the Cypress CY7C602 chip, as used in the SPARCStation/SPARCServer 3xx series. This is also appropriate 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 additionally optimizes it 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, which exist in SPARClite but not in SPARC-V7. With -mcpu=f930, the compiler additionally optimizes it for the Fujitsu MB86930 chip, which is the original SPARClite, with no FPU ๐ŸŒธ. With -mcpu=f934, the compiler additionally optimizes it 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 ๐Ÿฆ‹. That adds the integer multiply, multiply/accumulate, integer divide step, and scan ("ffs") instructions, which 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 โœจ That adds 64-bit integer and floating-point move instructions, 3 extra floating-point condition code registers, and conditional move instructions. The -mcpu values below each add an extra layer of optimization for a specific chip ๐Ÿ”ฅ

  • -mcpu=ultrasparc โ€” optimizes for the Sun UltraSPARC I/II/IIi chips ๐ŸŒธ
  • -mcpu=ultrasparc3 โ€” optimizes for the Sun UltraSPARC III/III+/IIIi/IIIi+/IV/IV+ chips ๐ŸŒธ
  • -mcpu=niagara โ€” optimizes for Sun UltraSPARC T1 chips ๐ŸŒˆ
  • -mcpu=niagara2 โ€” optimizes for Sun UltraSPARC T2 chips ๐ŸŒˆ
  • -mcpu=niagara3 โ€” optimizes for Sun UltraSPARC T3 chips ๐ŸŒˆ
  • -mcpu=niagara4 โ€” optimizes for Sun UltraSPARC T4 chips ๐ŸŒˆ
  • -mcpu=niagara7 โ€” optimizes for Oracle SPARC M7 chips ๐Ÿ‘‘
  • -mcpu=m8 โ€” optimizes for Oracle M8 chips ๐Ÿ‘‘
  • -mtune=cpu_type โ€” sets the instruction scheduling parameters for the machine type cpu_type, but unlike -mcpu=cpu_type, it does not change the instruction set or register set ๐Ÿงš

The same values that work for -mcpu=cpu_type also work for -mtune=cpu_type, but the only really useful ones are the values that pick a specific CPU implementation: cypress, supersparc, hypersparc, leon, leon3, leon3v7, leon5, f930, f934, sparclite86x, tsc701, ultrasparc, ultrasparc3, niagara, niagara2, niagara3, niagara4, niagara7, and m8. With native Solaris and GNU/Linux toolchains, you can also use native ๐Ÿซถ

  • -mv8plus, -mno-v8plus โ€” with -mv8plus, GCC generates code for the SPARC-V8+ ABI ๐Ÿ’œ The big difference from V8 is that the global and out registers count 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 uses the UltraSPARC Visual Instruction Set extensions ๐Ÿฆ‹ The default is -mno-vis.
  • -mvis2, -mno-vis2 โ€” with -mvis2, GCC uses version 2.0 of the UltraSPARC Visual Instruction Set extensions. The default is -mvis2 when you target a CPU that supports those instructions, like UltraSPARC-III and later. Setting -mvis2 also sets -mvis ๐Ÿ’–
  • -mvis3, -mno-vis3 โ€” with -mvis3, GCC uses version 3.0 of the UltraSPARC Visual Instruction Set extensions. The default is -mvis3 when you target a CPU that supports those instructions, like niagara-3 and later. Setting -mvis3 also sets -mvis2 and -mvis ๐Ÿ’…
  • -mvis4, -mno-vis4 โ€” with -mvis4, GCC uses version 4.0 of the UltraSPARC Visual Instruction Set extensions. The default is -mvis4 when you target a CPU that supports those instructions, like niagara-7 and later. Setting -mvis4 also sets -mvis3, -mvis2, and -mvis ๐Ÿ”ฅ
  • -mvis4b, -mno-vis4b โ€” with -mvis4b, GCC uses 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 you target a CPU that supports those instructions, like m8 and later. Setting -mvis4b also sets -mvis4, -mvis3, -mvis2, and -mvis ๐Ÿ˜ญ
  • -mcbcond, -mno-cbcond โ€” with -mcbcond, GCC uses the UltraSPARC Compare-and-Branch-on-Condition instructions ๐ŸŽ€ The default is -mcbcond when you target a CPU that supports them, like Niagara-4 and later.
  • -mfmaf, -mno-fmaf โ€” with -mfmaf, GCC uses the UltraSPARC Fused Multiply-Add Floating-point instructions ๐ŸŒธ The default is -mfmaf when you target a CPU that supports them, like Niagara-3 and later.
  • -mfsmuld, -mno-fsmuld โ€” with -mfsmuld, GCC uses the Floating-point Multiply Single to Double (FsMULd) instruction ๐Ÿงš The default is -mfsmuld when you target a CPU that supports the V8 or V9 architecture versions with an FPU, except -mcpu=leon.
  • -mpopc, -mno-popc โ€” with -mpopc, GCC uses the UltraSPARC Population Count instruction ๐Ÿ“ The default is -mpopc when you target a CPU that supports it, like Niagara-2 and later.
  • -msubxc, -mno-subxc โ€” with -msubxc, GCC uses the UltraSPARC Subtract-Extended-with-Carry instruction ๐Ÿ’œ The default is -msubxc when you target a CPU that supports it, like Niagara-7 and later.
  • -mfix-at697f โ€” turns on the documented workaround for the single erratum of the Atmel AT697F processor (which is erratum #13 of the AT697E processor) ๐Ÿ› ๏ธ
  • -mfix-ut699 โ€” turns on the documented workarounds for the floating-point errata and the data cache nullify errata of the UT699 processor ๐Ÿ› ๏ธ
  • -mfix-ut700 โ€” turns on the documented workaround for the back-to-back store errata of the UT699E/UT700 processor ๐Ÿ› ๏ธ
  • -mfix-gr712rc โ€” turns on the documented workaround for the back-to-back store errata of the GR712RC processor ๐Ÿ› ๏ธ

These -m options are also supported 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 these:
    • medlow โ€” the Medium/Low code model: 64-bit addresses, and 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, and programs must be linked in the low 44 bits of memory. The text and data segments must each be less than 2GB in size, and the data segment must be located within 2GB of the text segment ๐ŸŒ™
    • medany โ€” the Medium/Anywhere code model: 64-bit addresses, and programs can be linked anywhere in memory. The text and data segments must each be less than 2GB in size, and the data segment must be located within 2GB of the text segment โœจ
    • embmedany โ€” the Medium/Anywhere code model for embedded systems: 64-bit addresses, and the text and data segments must each be less than 2GB in size, both starting anywhere in memory (determined at link time). The global register %g4 points to the base of the data segment. Programs are statically linked, and PIC is not supported ๐Ÿค–
  • -mmemory-model=mem-model โ€” sets the memory model the processor uses to 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 memory models 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 โ€” with -mstack-bias, GCC assumes the stack pointer (and the frame pointer, if there is one) is offset by -2047, which must be added back when making stack frame references. This is the default in 64-bit mode. Otherwise, GCC assumes there's no such offset ๐Ÿ˜ญ

Options for System V

These extra options are available on System V Release 4 so they match other compilers on those systems ๐Ÿงš

  • -G โ€” creates a shared object. It's recommended to use -symbolic or -shared instead ๐Ÿ™ˆ
  • -Qy โ€” identifies the version of each tool the compiler used, and puts that info in a ".ident" assembler directive in the output ๐Ÿซถ
  • -Qn โ€” stops adding ".ident" directives to the output file (this 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-endian 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 (or near). If calls are assumed to be far away, the compiler always loads the function's address into a register and calls indirectly through the pointer ๐Ÿ”ฅ
  • -mno-ep, -mep โ€” -mno-ep stops optimizing basic blocks that use the same index pointer 4 or more times to copy the pointer into the "ep" register, and -mep does that optimization. That optimization also lets the compiler use the shorter "sld" and "sst" instructions. The -mep option is on by default if you optimize ๐Ÿงš
  • -mno-prolog-function, -mprolog-function โ€” ๐Ÿ’… Okay so -mno-prolog-function tells GCC to not call external helper functions for saving and restoring registers in the prologue and epilogue of a function, while -mprolog-function tells it to use them โœจ. The helpers are slower, but they take up less code space when more than one function saves the same number of registers. -mprolog-function is on by default if you optimize ๐Ÿ”ฅ.
  • -mspace โ€” ๐Ÿงš Tries to make the code as small as possible. Right now that just turns on -mep and -mprolog-function ๐ŸŒธ.
  • -mtda=n โ€” ๐ŸŽ€ Puts static or global variables that are n bytes or less into the tiny data area that the ep register points to. The tiny data area holds up to 256 bytes total (128 bytes for byte references) ๐Ÿค.
  • -msda=n โ€” ๐Ÿ’– Puts static or global variables that are n bytes or less into the small data area that the gp register points to. That small data area can hold up to 64 kilobytes โœจ.
  • -mzda=n โ€” ๐Ÿฆ‹ Puts static or global variables that are n bytes or less into the first 32 kilobytes of memory.
  • -mv850 โ€” ๐Ÿ‘‘ Says the target processor is the V850.
  • -mv850e3v5 โ€” ๐Ÿ”ฅ Says the target processor is the V850E3V5. The preprocessor constant __v850e3v5__ gets defined if you use this one.
  • -mv850e2v4 โ€” ๐ŸŒˆ Says the target processor is the V850E3V5 (yep, that's what it says). It's an alias for -mv850e3v5.
  • -mv850e2v3 โ€” ๐Ÿซถ Says the target processor is the V850E2V3. The preprocessor constant __v850e2v3__ gets defined if you use this one.
  • -mv850e2 โ€” ๐Ÿ“ Says the target processor is the V850E2. The preprocessor constant __v850e2__ gets defined if you use this one.
  • -mv850e1 โ€” ๐Ÿ’œ Says the target processor is the V850E1. The preprocessor constants __v850e1__ and __v850e__ both get defined if you use this one.
  • -mv850es โ€” ๐ŸŒธ Says the target processor is the V850ES. It's an alias for -mv850e1.
  • -mv850e โ€” โœจ Says the target processor is the V850E. The preprocessor constant __v850e__ gets defined if you use this one.

If none of -mv850, -mv850e, -mv850e1, -mv850e2, -mv850e2v3 or -mv850e3v5 are set, GCC just 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 you're targeting ๐Ÿ’….

  • -mdisable-callt, -mno-disable-callt โ€” ๐Ÿ™ˆ This one suppresses generation of the CALLT instruction for the v850e, v850e1, v850e2, v850e2v3 and v850e3v5 flavors of the v850 architecture. It's enabled by default when the RH850 ABI is in use (see -mrh850-abi), and disabled 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 on (or doesn't pass on) the -mrelax command-line option to the assembler.
  • -mlong-jumps, -mno-long-jumps โ€” ๐Ÿ’€ Disables (or re-enables) the generation of PC-relative jump instructions.
  • -msoft-float, -mhard-float โ€” ๐Ÿ”ฅ Disables (or re-enables) the generation of hardware floating point instructions. This only matters when the target architecture is V850E2V3 or higher. If hardware floating point instructions are being generated, the C preprocessor symbol __FPU_OK__ gets defined. Otherwise the symbol __NO_FPU__ gets defined.
  • -mloop โ€” ๐Ÿงš Enables the use of the e3v5 LOOP instruction. It's not enabled 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. With this version of the ABI, the following rules apply:
    • Integer sized structures and unions are returned via a memory pointer rather than 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__ gets defined ๐Ÿ’–.

  • -mgcc-abi โ€” ๐ŸŒธ Enables support for the old GCC version of the V850 ABI. With this version of the ABI, the following 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__ gets defined ๐Ÿ“.

  • -m8byte-align, -mno-8byte-align โ€” ๐ŸŽ€ Enables support for double and long long types to be 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__ gets defined โœจ.
  • -mbig-switch โ€” ๐Ÿซถ Generates code suitable for big switch tables. Only use this if the assembler or linker complains about out of range branches within a switch table ๐Ÿ˜ญ.
  • -mapp-regs โ€” ๐Ÿ’… Makes the compiler use r2 and r5 in the code it generates. This is the default.
  • -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 (aobleq and so on) that the Unix assembler for the VAX can't handle across long ranges.
  • -mgnu โ€” ๐Ÿงš Does output those jump instructions, on the assumption that the GNU assembler is being used.
  • -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 the option. This 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 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 of the Visium architecture. 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 no 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. Unlike -mtune=cpu-type, which only tunes the generated code for the specified cpu-type, -march=cpu-type lets GCC generate code that may not run at all on processors other than the one indicated. Specifying -march=cpu-type implies -mtune=cpu-type, except where noted otherwise ๐Ÿงš.
๐Ÿ’€ Real talk, bestie: with -march=cpu-type, the code may not run at all on processors other than the one you named ๐Ÿ˜ญ.

The choices for cpu-type are:

  • native: Okay bestie, this is the "just use whatever my laptop has" option ๐Ÿ’ปโœจ GCC checks the processor of the machine doing the compiling and generates code for that CPU. -march=native turns on every instruction subset the local machine supports, so the result might not run on other machines ๐Ÿ˜ญ -mtune=native optimizes the code for the local machine, but it still stays within the limits of the selected instruction set ๐Ÿ’…
  • x86-64: A generic CPU with 64-bit extensions ๐ŸŒธ
  • x86-64-v2, x86-64-v3, x86-64-v4: These pick the matching micro-architecture level from the x86-64 psABI, so they're giving standardized feature sets ๐Ÿฆ‹ On ABIs other than the x86-64 psABI, they select the same CPU features that the x86-64 psABI documents for that micro-architecture level.

Since these values don't have a matching -mtune setting, using -march with them turns on generic tuning. If you want specific tuning, use -mtune=other-cpu-type with an appropriate other-cpu-type value ๐Ÿงš

  • i386: The original Intel i386 CPU, the OG ๐Ÿ‘‘
  • 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 the Intel Pentium CPU ๐Ÿค
  • pentium-mmx: Intel Pentium MMX CPU, based on the Pentium core with MMX instruction set support โœจ
  • pentiumpro: Intel Pentium Pro CPU ๐Ÿ”ฅ
  • i686: When used with -march, this uses the Pentium Pro instruction set, so the code runs on all i686 family chips ๐Ÿ’œ When used with -mtune, it means the same thing as generic.
  • pentium2: Intel Pentium II CPU, based on the Pentium Pro core with MMX instruction set support ๐ŸŽ€
  • pentium3, pentium3m: Intel Pentium III CPU, based on the Pentium Pro core with MMX and SSE instruction set support ๐ŸŒˆ
  • pentium-m: Intel Pentium M, the low-power version of the Intel Pentium III CPU with MMX, SSE and SSE2 instruction set support. This is what Centrino notebooks used ๐Ÿ’ป
  • pentium4, pentium4m: Intel Pentium 4 CPU with MMX, SSE and SSE2 instruction set support ๐ŸŒธ
  • prescott: An improved version of the Intel Pentium 4 CPU with MMX, SSE, SSE2 and SSE3 instruction set support ๐Ÿ’–
  • nocona: An 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, MMX, SSE, SSE2, SSE3 and SSSE3 instruction set support โญ
  • nehalem: Intel Nehalem CPU with 64-bit extensions, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2 and POPCNT instruction set support ๐Ÿซถ
  • westmere: Intel Westmere CPU with 64-bit extensions, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, AES and PCLMUL instruction set support ๐Ÿงš
  • sandybridge: Intel Sandy Bridge CPU with 64-bit extensions, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, AVX, AES and PCLMUL instruction set support ๐ŸŒˆ
  • ivybridge: Intel Ivy Bridge CPU with 64-bit extensions, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, AVX, AES, PCLMUL, FSGSBASE, RDRND and F16C instruction set support ๐Ÿ“
  • haswell: Intel Haswell CPU with 64-bit extensions, MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, AVX, AVX2, AES, PCLMUL, FSGSBASE, RDRND, FMA, BMI, BMI2 and F16C instruction set support ๐Ÿ’…
  • broadwell: Intel Broadwell CPU with 64-bit extensions, MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, AVX, AVX2, AES, PCLMUL, FSGSBASE, RDRND, FMA, BMI, BMI2, F16C, RDSEED ADCX and PREFETCHW instruction set support โœจ
  • skylake: Intel Skylake CPU with 64-bit extensions, MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, AVX, AVX2, AES, PCLMUL, FSGSBASE, RDRND, FMA, BMI, BMI2, F16C, RDSEED, ADCX, PREFETCHW, CLFLUSHOPT, XSAVEC and XSAVES instruction set support ๐Ÿ”ฅ
  • bonnell: Intel Bonnell CPU with 64-bit extensions, MOVBE, MMX, SSE, SSE2, SSE3 and SSSE3 instruction set support ๐ŸŒธ
  • silvermont: Intel Silvermont CPU with 64-bit extensions, MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, AES, PREFETCHW, PCLMUL and RDRND instruction set support ๐Ÿฆ‹
  • goldmont: Intel Goldmont CPU with 64-bit extensions, MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, AES, PREFETCHW, PCLMUL, RDRND, XSAVE, XSAVEC, XSAVES, XSAVEOPT and FSGSBASE instruction set support ๐Ÿ’œ
  • goldmont-plus: Intel Goldmont Plus CPU with 64-bit extensions, MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, AES, PREFETCHW, PCLMUL, RDRND, XSAVE, XSAVEC, XSAVES, XSAVEOPT, FSGSBASE, PTWRITE, RDPID, SGX and UMIP instruction set support ๐Ÿ‘‘
  • tremont: Intel Tremont CPU with 64-bit extensions, MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, AES, PREFETCHW, PCLMUL, RDRND, XSAVE, XSAVEC, XSAVES, XSAVEOPT, FSGSBASE, PTWRITE, RDPID, SGX, UMIP, GFNI-SSE, CLWB, MOVDIRI, MOVDIR64B, CLDEMOTE and WAITPKG instruction set support ๐Ÿงš
  • knl: Intel Knight's Landing CPU with 64-bit extensions, MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, AVX, AVX2, AES, PCLMUL, FSGSBASE, RDRND, FMA, BMI, BMI2, F16C, RDSEED, ADCX, PREFETCHW, PREFETCHWT1, AVX512F, AVX512PF, AVX512ER and AVX512CD instruction set support ๐ŸŒˆ
  • knm: Intel Knights Mill CPU with 64-bit extensions, MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, 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 instruction set support ๐Ÿ“
  • skylake-avx512: Intel Skylake Server CPU with 64-bit extensions, MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, 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 instruction set support ๐Ÿ’–
  • cannonlake: Intel Cannonlake Server CPU with 64-bit extensions, MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, 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 instruction set support ๐Ÿฆ‹
  • icelake-client: Intel Icelake Client CPU with 64-bit extensions, MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, 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 instruction set support ๐Ÿซถ
  • icelake-server: Intel Icelake Server CPU with 64-bit extensions, MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, 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 and WBNOINVD instruction set support ๐Ÿ‘‘
  • cascadelake: Intel Cascadelake CPU with 64-bit extensions, MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, 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 instruction set support ๐ŸŒธ
  • cooperlake: Intel cooperlake CPU with 64-bit extensions, MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, 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, AVX512VNNI and AVX512BF16 instruction set support ๐Ÿ’…
  • tigerlake: Intel Tigerlake CPU with 64-bit extensions, MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, 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, AVX512VP2INTERSECT and KEYLOCKER instruction set support โœจ
  • sapphirerapids: Intel sapphirerapids CPU with 64-bit extensions, MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, CX16, SAHF, FXSR, AVX, XSAVE, PCLMUL, FSGSBASE, RDRND, F16C, AVX2, BMI, BMI2, LZCNT, FMA, MOVBE, HLE, RDSEED, ADCX, PREFETCHW, AES, CLFLUSHOPT, XSAVEC, XSAVES, SGX, AVX512F, AVX512VL, AVX512BW, AVX512DQ, AVX512CD, PKU, AVX512VBMI, AVX512IFMA, SHA, AVX512VNNI, GFNI, VAES, AVX512VBMI2 VPCLMULQDQ, AVX512BITALG, RDPID, AVX512VPOPCNTDQ, PCONFIG, WBNOINVD, CLWB, MOVDIRI, MOVDIR64B, AVX512VP2INTERSECT, ENQCMD, CLDEMOTE, PTWRITE, WAITPKG, SERIALIZE, TSXLDTRK, UINTR, AMX-BF16, AMX-TILE, AMX-INT8, AVX-VNNI and AVX512BF16 instruction set support ๐Ÿ”ฅ
  • alderlake: Intel Alderlake CPU with 64-bit extensions, MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, AES, PREFETCHW, PCLMUL, RDRND, XSAVE, XSAVEC, XSAVES, XSAVEOPT, FSGSBASE, PTWRITE, RDPID, SGX, UMIP, GFNI-SSE, CLWB, MOVDIRI, MOVDIR64B, CLDEMOTE, WAITPKG, ADCX, AVX, AVX2, BMI, BMI2, F16C, FMA, LZCNT, PCONFIG, PKU, VAES, VPCLMULQDQ, SERIALIZE, HRESET, KL, WIDEKL and AVX-VNNI instruction set support ๐Ÿงš
  • rocketlake โ€” ๐Ÿ’– Intel Rocketlake, rocking 64-bit extensions plus a full buffet: MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, 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 instruction set support. ๐Ÿงš
  • k6 โ€” ๐ŸŒธ AMD K6 with MMX support. Classic. ๐Ÿฆ‹
  • k6-2, k6-3 โ€” ๐ŸŽ€ Upgraded AMD K6 chips with MMX and 3DNow! support. Glow-up energy. โœจ
  • athlon, athlon-tbird โ€” ๐Ÿ”ฅ AMD Athlon with MMX, 3dNOW!, enhanced 3DNow! and SSE prefetch instructions. Lowkey iconic. ๐Ÿ‘‘
  • athlon-4, athlon-xp, athlon-mp โ€” ๐Ÿ’… Improved AMD Athlon with MMX, 3DNow!, enhanced 3DNow! and full SSE instruction set support. The sequel that ate. ๐Ÿ”ฅ
  • k8, opteron, athlon64, athlon-fx โ€” ๐ŸŒˆ Processors built on the AMD K8 core with x86-64 instruction set support, covering the AMD Opteron, Athlon 64 and Athlon 64 FX chips. Ngl this one supersets (aka includes all of) MMX, SSE, SSE2, 3DNow!, enhanced 3DNow! and 64-bit instruction set extensions. ๐Ÿ’œ
  • k8-sse3, opteron-sse3, athlon64-sse3 โ€” โญ Upgraded AMD K8 cores with SSE3 support. ๐Ÿซถ
  • amdfam10, barcelona โ€” ๐Ÿฆ‹ CPUs built on AMD Family 10h cores with x86-64 instruction set support. This one supersets MMX, SSE, SSE2, SSE3, SSE4A, 3DNow!, enhanced 3DNow!, ABM and 64-bit instruction set extensions. ๐Ÿ’–
  • bdver1 โ€” ๐Ÿ”ฅ AMD Family 15h cores with x86-64 instruction set support. It supersets FMA4, AVX, XOP, LWP, AES, PCLMUL, 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. It supersets BMI, TBM, F16C, FMA, FMA4, AVX, XOP, LWP, AES, PCLMUL, 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. It supersets BMI, TBM, F16C, FMA, FMA4, FSGSBASE, AVX, XOP, LWP, AES, PCLMUL, 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. It supersets BMI, BMI2, TBM, F16C, FMA, FMA4, FSGSBASE, AVX, AVX2, XOP, LWP, AES, PCLMUL, 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. It supersets BMI, BMI2, F16C, FMA, FSGSBASE, AVX, AVX2, ADCX, RDSEED, MWAITX, SHA, CLZERO, AES, PCLMUL, 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. It supersets BMI, BMI2, CLWB, F16C, FMA, FSGSBASE, AVX, AVX2, ADCX, RDSEED, MWAITX, SHA, CLZERO, AES, PCLMUL, CX16, MOVBE, MMX, SSE, SSE2, SSE3, SSE4A, SSSE3, SSE4.1, SSE4.2, ABM, XSAVEC, XSAVES, CLFLUSHOPT, POPCNT, RDPID, WBNOINVD, and 64-bit instruction set extensions. โœจ
  • znver3 โ€” ๐Ÿฆ‹ AMD Family 19h core based CPUs with x86-64 instruction set support. It supersets BMI, BMI2, CLWB, F16C, FMA, FSGSBASE, AVX, AVX2, ADCX, RDSEED, MWAITX, SHA, CLZERO, AES, PCLMUL, CX16, MOVBE, MMX, SSE, SSE2, SSE3, SSE4A, SSSE3, SSE4.1, SSE4.2, ABM, XSAVEC, XSAVES, CLFLUSHOPT, POPCNT, RDPID, WBNOINVD, PKU, VPCLMULQDQ, VAES, and 64-bit instruction set extensions. ๐ŸŒธ
  • znver4 โ€” ๐Ÿ‘‘ AMD Family 19h core based CPUs with x86-64 instruction set support. It supersets BMI, BMI2, CLWB, F16C, FMA, FSGSBASE, AVX, AVX2, ADCX, RDSEED, MWAITX, SHA, CLZERO, AES, PCLMUL, CX16, MOVBE, MMX, SSE, SSE2, SSE3, SSE4A, SSSE3, SSE4.1, SSE4.2, ABM, XSAVEC, XSAVES, CLFLUSHOPT, POPCNT, RDPID, WBNOINVD, PKU, VPCLMULQDQ, VAES, AVX512F, AVX512DQ, AVX512IFMA, AVX512CD, AVX512BW, AVX512VL, AVX512BF16, AVX512VBMI, AVX512VBMI2, AVX512VNNI, AVX512BITALG, AVX512VPOPCNTDQ, GFNI and 64-bit instruction set extensions. ๐Ÿ”ฅ
  • btver1 โ€” ๐Ÿซถ CPUs built on AMD Family 14h cores with x86-64 instruction set support. It supersets MMX, SSE, SSE2, SSE3, SSSE3, SSE4A, CX16, ABM and 64-bit instruction set extensions. ๐ŸŽ€
  • btver2 โ€” ๐ŸŒˆ CPUs built on AMD Family 16h cores with x86-64 instruction set support. This includes MOVBE, F16C, BMI, AVX, PCLMUL, 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, handled the same way as i486, plus extra MMX instruction set support. ๐ŸŒธ
  • winchip2 โ€” ๐ŸŒธ IDT WinChip 2 CPU, handled the same way as i486, plus extra 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 โ€” ๐Ÿ“ VIA Eden Samuel 2 CPU with MMX and 3DNow! instruction set support. (No scheduling is implemented for this chip.) ๐Ÿ™ˆ
  • nehemiah โ€” ๐Ÿ“ VIA Eden Nehemiah CPU with MMX and SSE instruction set support. (No scheduling is implemented for this chip.) ๐Ÿ™ˆ
  • esther โ€” ๐Ÿ“ VIA Eden Esther CPU with MMX, SSE, SSE2 and SSE3 instruction set support. (No scheduling is implemented for this chip.) ๐Ÿ™ˆ
  • eden-x2 โ€” ๐Ÿ“ VIA Eden X2 CPU with x86-64, MMX, SSE, SSE2 and SSE3 instruction set support. (No scheduling is implemented for this chip.) ๐Ÿ™ˆ
  • eden-x4 โ€” ๐Ÿ“ 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 โ€” ๐Ÿ“ 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 โ€” ๐Ÿ“ 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 โ€” ๐Ÿ“ 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 โ€” ๐Ÿ“ 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 โ€” ๐Ÿ“ 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 โ€” ๐Ÿ“ 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 โ€” ๐Ÿงš AMD Geode embedded processor with MMX and 3DNow! instruction set support. ๐Ÿ’œ

โœจ -mtune=cpu-type โœจ

Tune cpu-type everything applicable about the generated code, except for the ABI and the set of available instructions. Picking a specific cpu-type schedules things perfectly for that chip, but the compiler won't generate any code that can't run on the default machine type unless you 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. ๐Ÿ’–

The choices for cpu-type are the same as for -march. On top of that, -mtune supports 2 extra choices for cpu-type:

๐ŸŒˆ generic

Produce code optimized for the most common IA32/AMD64/EM64T processors. If you know the CPU your code will run on, use the matching -mtune or -march option instead of -mtune=generic. But if you don't know exactly what CPU your users will have, this is the one to use. ๐Ÿฆ‹

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 generated by this option will shift to match whatever processors are most common when that version of GCC is released. ๐Ÿ”ฅ

There is no -march=generic option, because -march is about the instruction set the compiler can use, and there's no generic instruction set that works on every processor. -mtune, on the other hand, is about the processor (or, in this case, the collection of processors) the code is optimized for. ๐Ÿ’…

๐Ÿ’œ intel

Produce code optimized for the most current Intel processors, which are Haswell and Silvermont for this version of GCC. 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 your option. ๐Ÿ‘‘

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 generated by this option will shift to reflect the most current Intel processors at the time that version of GCC is released. โญ

There is no -march=intel option, because -march is about the instruction set the compiler can use, and there's no common instruction set that works on every processor. -mtune, on the other hand, is about the processor (or, in this case, the collection of processors) the code is optimized for. ๐Ÿซถ

  • -mcpu=cpu-type โ€” okay so this one is just a synonym for -mtune, but it's deprecated ๐Ÿ’€ it's on its way out, bestie ๐Ÿฅ€
  • -mfpmath=unit โ€” this decides how the floating-point math gets done ๐Ÿงฎโœจ The unit you pick can be one of these:
    • 387 โ€” uses the standard 387 floating-point coprocessor that's on most chips, and gets emulated if it's missing ๐Ÿฆ– Code built with this runs basically everywhere, but the temporary results are computed in 80-bit precision instead of the precision the type asks for, so your numbers can come out a little different from most other chips. Check out -ffloat-store for the full tea on that ๐Ÿต This is the default choice for non-Darwin x86-32 targets.
    • sse โ€” uses the scalar floating-point instructions from the SSE instruction set ๐Ÿš€ It's on Pentium III and newer chips, plus the AMD Athlon-4, Athlon XP, and Athlon MP chips. The earlier SSE version only handles single-precision math, so double and extended-precision math still go through 387 ๐Ÿ™ƒ A later version, found only on Pentium 4 and AMD x86-64 chips, can do double-precision math too. For the x86-32 compiler, you have to use -march=cpu-type, -msse, or -msse2 to turn on the SSE extensions and make this option actually work ๐Ÿซ  For the x86-64 compiler, those extensions are on by default. The result should be way faster in most cases and dodge the numerical instability problems of 387 code ๐Ÿ“ˆ but it might break existing code that expects temporaries to be 80 bits. This is the default choice for the x86-64 compiler, Darwin x86-32 targets, and for x86-32 targets with the SSE2 instruction set when -ffast-math is enabled ๐Ÿ‘‘
    • sse,387, sse+387, both โ€” tries to use both instruction sets at the same time ๐Ÿคน This effectively doubles the number of available registers, and on chips with separate execution units for 387 and SSE, it doubles those execution resources too. Use it with care ๐Ÿฅบ It's still experimental, because the GCC register allocator doesn't model separate functional units very well, which means the performance can be unstable ๐ŸŽข
  • -masm=dialect โ€” picks the assembly dialect for the assembly instructions GCC outputs ๐Ÿ“ It 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 โ€” controls whether the compiler uses IEEE floating-point comparisons ๐Ÿ” These ones correctly handle the case where the result of a comparison is unordered ๐Ÿง
  • -m80387, -mhard-float โ€” generates output that contains 80387 instructions for floating point ๐Ÿ”ฅ
  • -mno-80387, -msoft-float โ€” generates output that contains 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 get used, but that can't be done directly in cross-compilation. You have to 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 get emitted even if -msoft-float is used ๐Ÿ‘€

  • -mno-fp-ret-in-387 โ€” doesn't use the FPU registers for function return values ๐Ÿ™…โ€โ™€๏ธ The usual calling convention has functions return float and double values in an FPU register, even if there's no FPU at all. The idea is that the operating system should emulate an FPU ๐Ÿงš Using -mno-fp-ret-in-387 makes those values come back in ordinary CPU registers instead.
  • -mno-fancy-math-387 โ€” some 387 emulators don't support the sin, cos, and sqrt instructions for the 387 ๐Ÿ’€ Use this to avoid generating those instructions. It gets overridden when -march says the target CPU always has an FPU, because then the instruction doesn't need emulating ๐Ÿ™Œ Also, these instructions aren't generated unless you use the -funsafe-math-optimizations switch too.
  • -malign-double, -mno-align-double โ€” controls 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 gives code that runs somewhat faster on a Pentium, but it costs more memory ๐Ÿ’พ On x86-64, -malign-double is enabled by default.
Warning: if you use -malign-double, structures containing the types above get aligned differently than the published x86-32 application binary interface specs say ๐Ÿ˜ฑ They won't be binary compatible with structures in code compiled without that switch.
  • -m96bit-long-double, -m128bit-long-double โ€” these control the size of the long double type ๐Ÿ“ The x86-32 application binary interface says the size is 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, but inside arrays or structures that follow the ABI, that isn't possible ๐Ÿ™ƒ So -m128bit-long-double aligns long double to a 16-byte boundary by padding it with an extra 32-bit zero ๐ŸŒธ In the x86-64 compiler, -m128bit-long-double is the default, since its ABI says long double is aligned on a 16-byte boundary. Heads up that neither of these options gives any extra precision over the x87 standard of 80 bits for a long double โœจ
Warning: if you override the default value for your target ABI, this changes the size of structures and arrays containing long double variables, and it also modifies the function calling convention for functions that take long double. So they're 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 too ๐Ÿ’– A size of 64 bits makes long double equivalent to double, and that's the default for the 32-bit Bionic C library. A size of 128 bits makes long double equivalent to __float128, and that's 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, and it also modifies the function calling convention for functions that take long double. So they're 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's 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 bigger than threshold get placed in the large data section ๐Ÿ˜ This value has to be the same across all objects linked into the binary, and it defaults to 65535 ๐Ÿ”ข
  • -mrtd โ€” switches to a different function-calling convention ๐Ÿ”„ In this one, functions that take a fixed number of arguments return with the ret num instruction, which pops their arguments as they return. That saves one instruction in the caller, since the caller doesn't need to pop the arguments anymore ๐Ÿงน You can give a single function this calling sequence with the function attribute stdcall, and you can override -mrtd for a function with the function attribute cdecl.
Warning: 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 ๐Ÿ™…โ€โ™€๏ธ
Warning: you must provide function prototypes for all functions that take a variable number of arguments (including printf), or incorrect code gets generated for calls to those functions ๐Ÿซ 
Warning: seriously incorrect code results if you call a function with too many arguments. Normally extra arguments are harmlessly ignored, but not with this one ๐Ÿ’€
  • -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, you must build all modules with the same value, including any libraries. That includes the system libraries and startup modules ๐Ÿงฑ
  • -msseregparm โ€” uses 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, you must build all modules with the same value, including any libraries. That 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 VxWorks, so it matches the ABI of the Sun Studio compilers up until version 12. Only use this option if you need to stay compatible with existing code made by those older compiler versions or older versions of GCC ๐Ÿ•ฐ๏ธ
  • -mpc32, -mpc64, -mpc80 โ€” set the 80387 floating-point precision to 32, 64, or 80 bits ๐ŸŽš๏ธ
    • -mpc32 โ€” rounds the significands of floating-point results to 24 bits (single precision) ๐ŸŒฑ
    • -mpc64 โ€” rounds them to 53 bits (double precision) ๐ŸŒท
    • -mpc80 โ€” rounds them to 64 bits (extended double precision), and this one's the default ๐Ÿ‘‘

When you use this option, floating-point operations in higher precisions aren't available to the programmer unless you set the FPU control word explicitly ๐Ÿซถ

Okay so, this next chunk is where we get into the x86 stack and instruction-set switches, and bestie, the stack ones are serious ๐Ÿซถ Pick the wrong alignment and your program can crash in ways that are super hard to trace ๐Ÿ’€

Setting the rounding of floating-point operations below the default 80 bits can speed some programs up by 2% or more ๐Ÿš€ But ngl, some math libraries assume extended-precision (80-bit) floating-point operations are on by default. If you use this option to drop precision below extended, those routines could lose a ton of accuracy through so-called "catastrophic cancellation" ๐Ÿ˜ญ Not it.

  • -mdaz-ftz โ€” This one flips the FTZ (flush-to-zero) and DAZ (denormals-are-zero) flags in the MXCSR register, which control floating-point calculations ๐Ÿฆ‹ SSE and AVX instructions, scalar and vector ones included, can get a speed boost when you turn these on with -mdaz-ftz. And if you say -mno-daz-ftz, GCC won't set the FTZ/DAZ flags at all ๐Ÿ™…โ€โ™€๏ธ
  • -mstackrealign โ€” Realigns the stack at entry โœจ On x86, this generates an alternate prologue and epilogue that realigns the run-time stack when it needs to. It's the glue for mixing legacy code that keeps 4-byte stack alignment with modern code that keeps 16-byte alignment for SSE compatibility ๐ŸŽ€ You can also look at the attribute force_align_arg_pointer, which works on individual functions.
  • -mpreferred-stack-boundary=num โ€” Tries to keep the stack boundary aligned to a 2 raised to num byte boundary ๐ŸŒธ If you don't specify -mpreferred-stack-boundary, the default is 4 (16 bytes or 128 bits), so no stress there.
๐Ÿ’€ Warning, bestie, this one is dangerous. When you're generating code for the x86-64 architecture with SSE extensions disabled, -mpreferred-stack-boundary=3 can keep the stack boundary aligned to an 8-byte boundary. But the x86-64 ABI requires 16-byte stack alignment, so this is ABI incompatible ๐Ÿ™ˆ It's only meant for a controlled environment where stack space is a seriously tight limit. It leads to wrong code when functions compiled with 16-byte stack alignment (like functions from a standard library) get called with a misaligned stack. SSE instructions may then cause misaligned memory access traps. On top of that, variable arguments get handled incorrectly for 16-byte aligned objects (including x87 long double and __int128), which gives wrong results. You must build all modules with -mpreferred-stack-boundary=3, including any libraries, system libraries and startup modules too. No skipping!
  • -mincoming-stack-boundary=num โ€” Assumes the incoming stack is aligned to a 2 raised to num byte boundary ๐Ÿ’– If you don't specify -mincoming-stack-boundary, GCC uses whatever -mpreferred-stack-boundary says.

On Pentium and Pentium Pro, double and long double values should be aligned to an 8-byte boundary (see -malign-double) or you'll eat significant run-time performance penalties ๐Ÿ“‰ On Pentium III, the SSE data type __m128 may not work properly if it isn't 16-byte aligned ๐Ÿ˜ฌ

To keep values properly aligned on the stack, the stack boundary has to be at least as aligned as whatever any value stored on the stack needs. Every function also has to be generated so it keeps the stack aligned. So if a function compiled with a higher preferred stack boundary calls from a function compiled with a lower one, the stack will most likely end up misaligned ๐Ÿ‘€ Libraries that use callbacks should always stick with the default setting, periodt.

This extra alignment eats extra stack space and generally makes your code bigger ๐Ÿ“ If you're working on something sensitive to stack usage, like embedded systems or operating system kernels, you may want to drop the preferred alignment to -mpreferred-stack-boundary=2.

  • Instruction set switches โ€” This whole family of switches turns on the use of instructions from the MMX, SSE, SSE2, SSE3, SSSE3, SSE4, SSE4A, SSE4.1, SSE4.2, AVX, AVX2, AVX512F, AVX512PF, AVX512ER, AVX512CD, AVX512VL, AVX512BW, AVX512DQ, AVX512IFMA, AVX512VBMI, SHA, AES, PCLMUL, CLFLUSHOPT, CLWB, FSGSBASE, PTWRITE, RDRND, F16C, FMA, PCONFIG, WBNOINVD, FMA4, PREFETCHW, RDPID, PREFETCHWT1, RDSEED, SGX, XOP, LWP, 3DNow!, enhanced 3DNow!, POPCNT, ABM, ADX, BMI, BMI2, LZCNT, FXSR, XSAVE, XSAVEOPT, XSAVEC, XSAVES, RTM, HLE, TBM, MWAITX, CLZERO, PKU, AVX512VBMI2, GFNI, VAES, WAITPKG, VPCLMULQDQ, AVX512BITALG, MOVDIRI, MOVDIR64B, AVX512BF16, ENQCMD, AVX512VPOPCNTDQ, AVX5124FMAPS, AVX512VNNI, AVX5124VNNIW, SERIALIZE, UINTR, HRESET, AMXTILE, AMXINT8, AMXBF16, KL, WIDEKL, AVXVNNI or CLDEMOTE extended instruction sets ๐ŸŒˆ Every one of them has a matching -mno- option to turn that instruction use off ๐Ÿ™…โ€โ™€๏ธ The flags are:
-mmmx
-msse
-msse2
-msse3
-mssse3
-msse4
-msse4a
-msse4.1
-msse4.2
-mavx
-mavx2
-mavx512f
-mavx512pf
-mavx512er
-mavx512cd
-mavx512vl
-mavx512bw
-mavx512dq
-mavx512ifma
-mavx512vbmi
-msha
-maes
-mpclmul
-mclflushopt
-mclwb
-mfsgsbase
-mptwrite
-mrdrnd
-mf16c
-mfma
-mpconfig
-mwbnoinvd
-mfma4
-mprfchw
-mrdpid
-mprefetchwt1
-mrdseed
-msgx
-mxop
-mlwp
-m3dnow
-m3dnowa
-mpopcnt
-mabm
-madx
-mbmi
-mbmi2
-mlzcnt
-mfxsr
-mxsave
-mxsaveopt
-mxsavec
-mxsaves
-mrtm
-mhle
-mtbm
-mmwaitx
-mclzero
-mpku
-mavx512vbmi2
-mavx512bf16
-mgfni
-mvaes
-mwaitpkg
-mvpclmulqdq
-mavx512bitalg
-mmovdiri
-mmovdir64b
-menqcmd
-muintr
-mtsxldtrk
-mavx512vpopcntdq
-mavx512vp2intersect
-mavx5124fmaps
-mavx512vnni
-mavxvnni
-mavx5124vnniw
-mcldemote
-mserialize
-mamx-tile
-mamx-int8
-mamx-bf16
-mhreset
-mkl
-mwidekl

These extensions are also available as built-in functions, so check out x86 Built-in Functions for the details of which functions get enabled and disabled by these switches ๐Ÿงš If you want GCC to generate SSE/SSE2 instructions automatically from floating-point code (instead of 387 instructions), that's -mfpmath=sse ๐Ÿ’…

Heads up: GCC suppresses SSEx instructions when -mavx is used. Instead, it generates new AVX instructions, or AVX equivalents for all SSEx instructions, when needed ๐Ÿฆ‹

These options let GCC use those extended instructions in generated code, even without -mfpmath=sse. If your app does run-time CPU detection, you need to compile separate files for each supported architecture, using the appropriate flags ๐Ÿซถ Specifically, the file with the CPU detection code should be compiled without these options, bestie, it's giving "keep the detector clean" energy.

  • -mdump-tune-features โ€” Tells GCC to dump the names of the x86 performance tuning features and their default settings ๐Ÿ“‹ You can use those names in -mtune-ctrl=feature-list.
  • -mtune-ctrl=feature-list โ€” Fine-grained control over x86 code generation features ๐ŸŽ›๏ธ The feature-list is a comma-separated list of feature names. See also -mdump-tune-features. A feature gets turned on when it's not preceded by ^, and turned off when it is. This one is meant for GCC developers, so be warned: using it may lead to code paths that testing never covered, and it can potentially cause compiler ICEs or runtime errors ๐Ÿ’€
  • -mno-default โ€” Turns off all tunable features ๐Ÿ™…โ€โ™€๏ธ See also -mtune-ctrl=feature-list and -mdump-tune-features.
  • -mcld โ€” Makes GCC emit a cld instruction in the prologue of functions that use string instructions ๐Ÿงต String instructions depend on the DF flag to pick between autoincrement or autodecrement mode. The ABI says DF should be cleared on function entry, but some operating systems violate that by not clearing DF in their exception dispatchers. So the exception handler can run with DF set, which means string instructions go the wrong direction ๐Ÿ˜ญ This option can be enabled by default on 32-bit x86 targets when you configure GCC with the --enable-cld configure option. If you want to suppress cld generation in that case, use the -mno-cld compiler option.
  • -mvzeroupper โ€” Makes GCC emit a vzeroupper instruction before control flow leaves the function, which minimizes the AVX to SSE transition penalty and removes unnecessary zeroupper intrinsics ๐Ÿงน
  • -mprefer-avx128 โ€” Tells GCC to use 128-bit AVX instructions instead of 256-bit AVX instructions in the auto-vectorizer ๐ŸŒธ
  • -mprefer-vector-width=opt โ€” Tells GCC to use opt-bit vector width in instructions instead of the default on the selected platform ๐Ÿ“ The options are:
    • none โ€” No extra limitations are applied to GCC beyond what the selected platform defines.
    • 128 โ€” Prefers 128-bit vector width for instructions.
    • 256 โ€” Prefers 256-bit vector width for instructions.
    • 512 โ€” Prefers 512-bit vector width for instructions.
  • -mcx16 โ€” Lets GCC generate CMPXCHG16B instructions in 64-bit code to do compare-and-exchange operations on 16-byte aligned 128-bit objects ๐Ÿ’œ This is handy for atomic updates of data structures bigger than one machine word. The compiler uses this instruction to implement __sync builtins. However, for __atomic builtins operating on 128-bit integers, a library call is always used, so don't expect magic there ๐Ÿ™ˆ
  • -msahf โ€” Enables generation of SAHF instructions in 64-bit code ๐Ÿฐ Early Intel Pentium 4 CPUs with Intel 64 support, from before the Pentium 4 G1 step in December 2005, didn't have 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 ๐Ÿฆ‹
  • -mmwait โ€” okay so this one is the key ๐Ÿ”‘ It makes the built-in functions __builtin_ia32_monitor and __builtin_ia32_mwait actually generate the monitor and mwait machine instructions โœจ
  • -mrecip โ€” this one is giving speed ๐Ÿ’จ It lets GCC use RCPSS and RSQRTSS (plus their vectorized besties RCPPS and RSQRTPS) with an extra Newton-Raphson step for precision, instead of DIVSS and SQRTSS (and their vectorized versions) for single-precision floating-point arguments ๐Ÿฆ‹ These only get generated when -funsafe-math-optimizations is enabled together with -ffinite-math-only and -fno-trapping-math. Heads up bestie: the sequence has higher throughput than the non-reciprocal instruction, but its precision can drop by up to 2 ulp (i.e. the inverse of 1.0 equals 0.99999994) ๐Ÿ˜ญ

Note that GCC already implements 1.0f/sqrtf(x) in terms of RSQRTSS (or RSQRTPS) with -ffast-math (or the option combination above), so you don't need -mrecip for that ๐Ÿ’…

Also, GCC emits the sequence above with the extra Newton-Raphson step for vectorized single-float division and vectorized sqrtf(x) already with -ffast-math (or the option combination above), so -mrecip isn't needed there either ๐Ÿซถ

  • -mrecip=opt โ€” this one lets you pick exactly which reciprocal estimate instructions are allowed ๐ŸŽ€ opt is a comma-separated list, and any option can be flipped by putting a ! in front of it:
    • all โ€” enables all estimate instructions ๐ŸŒˆ
    • default โ€” enables the default instructions, equivalent to -mrecip
    • none โ€” disables all estimate instructions, equivalent to -mno-recip ๐Ÿ™…
    • div โ€” enables the approximation for scalar division
    • vec-div โ€” enables the approximation for vectorized division
    • sqrt โ€” enables the approximation for scalar square root
    • vec-sqrt โ€” enables the approximation for vectorized square root

So, for example, -mrecip=all,!sqrt enables all of the reciprocal approximations except for square root ๐Ÿฆ‹

  • -mveclibabi=type โ€” this sets the ABI type for vectorizing intrinsics using an external library ๐Ÿ“š Pick svml for the Intel short vector math library, or acml for the AMD math core library. To use it, both -ftree-vectorize and -funsafe-math-optimizations have to be enabled, and an SVML or ACML ABI-compatible library has to be specified at link time ๐Ÿ”—

GCC currently emits calls to 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 when -mveclibabi=svml is used, and __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 when -mveclibabi=acml is used.

  • -mabi=name โ€” picks which calling convention to generate code for ๐ŸŒธ sysv is the ABI used on GNU/Linux and other systems, and ms is 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 for specific functions with the ms_abi and sysv_abi function attributes ๐Ÿ’œ
  • -mforce-indirect-call โ€” forces all calls to functions to be indirect ๐Ÿงš This is useful when using Intel Processor Trace, where it generates more precise timing information for function calls โฑ๏ธ
  • -mmanual-endbr โ€” ENDBR gets inserted at function entry only via the cf_check function attribute ๐Ÿ™ˆ This is useful when used with the option -fcf-protection=branch to control ENDBR insertion at the function entry ๐Ÿซถ
  • -mcall-ms2sysv-xlogues โ€” okay this one's a bit of a lore dump ๐Ÿ“œ Because of differences in 64-bit ABIs, any Microsoft ABI function that calls a System V ABI function has to consider RSI, RDI and XMM6-15 as clobbered. By default the code for saving and restoring these registers is emitted inline, which makes the prologues and epilogues pretty lengthy ๐Ÿ˜ฉ Using -mcall-ms2sysv-xlogues emits prologues and epilogues that use stubs in the static portion of libgcc to do these saves and restores instead, which shrinks the 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, while gnu2 is more efficient, but it may add compile- and run-time requirements that can't 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 SUB/MOV method, 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 gets 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 it 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 โ€” enables or disables bit-field layout compatible with the native Microsoft Windows compiler ๐ŸŽ€

If packed is used on a structure, or if bit-fields are used, it may be that the Microsoft ABI lays out the structure differently than the way GCC normally does ๐Ÿ‘€ Particularly when moving packed data between functions compiled with GCC and the native Microsoft compiler (either via function call or as data in a file), it may be necessary to access either format.

This option is enabled by default for Microsoft Windows targets ๐ŸชŸ This behavior can also be controlled locally by use of variable or type attributes. For more information, see x86 Variable Attributes and x86 Type Attributes.

The Microsoft structure layout algorithm is fairly simple with the exception of the bit-field packing ๐Ÿงฉ The padding and alignment of members of structures, and whether a bit-field can straddle a storage-unit boundary, are determined by these rules:

  1. Structure members are stored sequentially in the order in which they are declared: the first member has the lowest memory address and the last member the highest.
  2. Every data object has an alignment requirement. The alignment requirement for all data except structures, unions, and arrays is either the size of the object or the current packing size (specified with either the aligned attribute or the pack pragma), whichever is less. For structures, unions, and arrays, the alignment requirement is the largest alignment requirement of its members. Every object is allocated an offset so that: offset % alignment_requirement == 0
  3. Adjacent bit-fields are packed into the same 1-, 2-, or 4-byte allocation unit if the integral types are the same size and if the next bit-field fits into the current allocation unit without crossing the boundary imposed by the common alignment requirements of the bit-fields.

MSVC interprets zero-length bit-fields in the following ways:

  1. If a zero-length bit-field is inserted between two bit-fields that are normally coalesced, the bit-fields are not 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 the zero-length bit-field were removed, t1's size would be 4 bytes.

  1. If a zero-length bit-field is inserted after a bit-field, foo, and the alignment of the zero-length bit-field is greater than the member that follows it, bar, then bar is 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 is placed at offset 2, rather than offset 1. Accordingly, the size of t2 is 4. For t3, the zero-length bit-field does not affect the alignment of bar or, as a result, the size of the structure.

Taking this into account, it is important to note the following:

  1. If a zero-length bit-field follows a normal bit-field, the type of the zero-length bit-field may affect the alignment of the structure as a whole. For example, t2 has a size of 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 is not followed by a normal bit-field, it may 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 come after non-bit-field members get ignored, bestie. Check out this struct:
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 makes the code smaller and can run faster when the destination is already aligned but GCC doesn't realize it, so it's a lowkey win.
  • -minline-all-stringops โ€” โœจ By default, GCC only inlines string operations when it knows the destination is aligned to at least a 4-byte boundary. This option inlines way more, so the code gets bigger, but code that leans on fast memcpy and memset for short lengths might get faster. It also turns on inline expansion of strlen for all pointer alignments. Main character energy ๐Ÿ‘‘
  • -minline-stringops-dynamically โ€” ๐Ÿงš For string operations where the size isn't known until runtime, you get run-time checks. Small blocks get inline code, and big blocks get a library call. Smart, right? ๐Ÿง 
  • -mstringop-strategy=alg โ€” ๐Ÿ”ฅ This overrides GCC's internal heuristic for picking which algorithm to use when inlining string operations. The allowed values for alg are:
    • rep_byte, rep_4byte, rep_8byte โ€” expand using the i386 rep prefix at the specified size.
    • byte_loop, loop, unrolled_loop โ€” expand into an inline loop.
    • libcall โ€” always use a library call, no inlining drama.
  • -mmemcpy-strategy=strategy โ€” ๐Ÿ’– This overrides the heuristic that decides whether __builtin_memcpy gets inlined, and which inline algorithm to use when the expected copy size is known. The strategy is a comma-separated list of alg:max_size:dest_align triplets. The alg is one of the values from -mstringop-strategy, and max_size is the biggest byte size that alg is allowed to handle. The last triplet has to use a max_size of -1. The max_size values in the list must go in increasing order. The minimum byte size for alg is 0 for the first triplet, and max_size + 1 of the range before it for every other triplet. Very organized, bestie ๐Ÿ“‹
  • -mmemset-strategy=strategy โ€” ๐Ÿฆ‹ Basically the same vibe as -mmemcpy-strategy=, except this one controls how __builtin_memset gets expanded.
  • -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. The option -fomit-leaf-frame-pointer drops the frame pointer for leaf functions too, but ngl that might make debugging harder ๐Ÿ™ˆ
  • -mtls-direct-seg-refs, -mno-tls-direct-seg-refs โ€” ๐Ÿซถ This 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 that's valid depends on the operating system, and on whether it maps the segment to cover the entire TLS area. For systems using the GNU C Library, the default is on โœจ
  • -msse2avx, -mno-sse2avx โ€” ๐Ÿ’… Tells the assembler to encode SSE instructions with the VEX prefix. The option -mavx turns this on by default.
  • -mfentry, -mno-fentry โ€” ๐ŸŽ€ If profiling is active (-pg), this puts the profiling counter call before the prologue. Heads up: on x86 architectures, the attribute ms_hook_prologue isn't possible at the moment for -mfentry and -pg. Not it ๐Ÿ’€
  • -mrecord-mcount, -mno-record-mcount โ€” ๐Ÿ“ If profiling is active (-pg), this generates a __mcount_loc section full of pointers to each profiling call. Super handy for automatically patching those calls in and out.
  • -mnop-mcount, -mno-nop-mcount โ€” ๐ŸŒธ If profiling is active (-pg), the calls to the profiling functions get generated as NOPs. This is useful when they should get patched in later on, 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. It only instruments true returns that end with ret, not sibling calls that end with a jump. The valid types are:
    • none โ€” don't instrument at all.
    • call โ€” generate a call to __return__.
    • nop5 โ€” generate a 5-byte nop.
  • -mrecord-return, -mno-record-return โ€” ๐Ÿฆ‹ Generates a __return_loc section that points to all the 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. The default is __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: RAX 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 doesn'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 way faster than 32-bit/64-bit integer divide. This option generates a run-time check. If both the dividend and the divisor are within the range of 0 to 255, an 8-bit unsigned integer divide gets used instead of the 32-bit/64-bit one. Galaxy brain ๐Ÿง โœจ
  • -mavx256-split-unaligned-load, -mavx256-split-unaligned-store โ€” ๐ŸŒˆ Splits 32-byte AVX unaligned loads and stores.
  • -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 (which is the default). This option only has an effect when -fstack-protector or -fstack-protector-all is specified.

With the latter choice, the options -mstack-protector-guard-reg=reg and -mstack-protector-guard-offset=offset also 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 โ€” ๐ŸŒธ Generates code that only uses the general-purpose registers. This stops the compiler from using floating-point, vector, mask, and bound registers.
  • -mindirect-branch=choice โ€” ๐Ÿฆ‹ Converts indirect calls and jumps according to choice. The default is keep, which leaves indirect calls and jumps unmodified. thunk converts them to call and return thunks. thunk-inline converts them to inlined call and return thunks. thunk-extern converts them to external call and return thunks, provided in a separate object file. You can control this behavior for a specific function with the function attribute "indirect_branch".

Note: -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.

Note: -mindirect-branch=thunk-extern is compatible with -fcf-protection=branch, since the external thunk can be made to enable the control-flow check. ๐Ÿซถ

  • -mfunction-return=choice โ€” ๐Ÿ’œ Converts function returns according to choice. The default is keep, which leaves function returns unmodified. thunk converts function returns to call and return thunks. thunk-inline converts them to inlined call and return thunks. thunk-extern converts them to external call and return thunks, provided in a separate object file. You can control this behavior for a specific function with the function attribute "function_return".

Note: -mindirect-return=thunk-extern is compatible with -fcf-protection=branch, since the external thunk can be made to enable the control-flow check.

Note: -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 โ€” ๐Ÿ”ฅ Forces indirect calls and jumps to go through a register.
  • -mharden-sls=choice โ€” ๐Ÿ›ก๏ธ Generates code to mitigate straight line speculation (SLS) according to choice. The default is none, which disables all SLS hardening. The other options are:
    • return โ€” enables SLS hardening for function returns.
    • indirect-jmp โ€” enables SLS hardening for indirect jumps.
    • all โ€” enables all SLS hardening.
  • -mindirect-branch-cs-prefix โ€” โœจ Adds a CS prefix to calls and jmps to an indirect thunk, where the branch target is in the r8-r15 registers. This makes the call and jmp instructions 6 bytes long, so they can be replaced at run-time with lfence; call *%r8-r15 or lfence; jmp *%r8-r15. Big brain move ๐Ÿง 

These -m switches are supported in addition to the above on x86-64 processors in 64-bit environments.

  • -m32, -m64, -mx32, -m16, -miamcu โ€” ๐ŸŒˆ Generates 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 in 32-bit mode.
    • -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, -m64 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 is the 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 โ€” ๐Ÿฆ‹ Doesn't use a so-called "red zone" for x86-64 code. The red zone is mandated by the x86-64 ABI: 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. The flag -mno-red-zone disables this red zone. Bye bye, red zone ๐Ÿ’…
  • -mcmodel=small โ€” okay so this is the default code model ๐Ÿ’– The program and its symbols have to be linked in the lower 2 GB of the address space. Pointers are 64 bits, and you can link statically or dynamically ๐Ÿซถ
  • -mcmodel=kernel โ€” this one is giving kernel energy ๐Ÿ‘‘ The kernel runs in the negative 2 GB of the address space, and you have to use it for Linux kernel code. No skipping, bestie ๐Ÿ’€
  • -mcmodel=medium โ€” the program gets linked in the lower 2 GB, and small symbols chill there too ๐Ÿฆ‹ Anything bigger than -mlarge-data-threshold gets tossed into large data or BSS sections, and those can sit above 2GB. Static or dynamic linking both work ๐ŸŒธ
  • -mcmodel=large โ€” no assumptions about addresses and sizes of sections at all ๐ŸŒˆ Full freedom, no cap.
  • -maddress-mode=long โ€” long address mode ๐Ÿงš It's only for 64-bit and x32 environments, and it's the default for 64-bit ones โœจ
  • -maddress-mode=short โ€” short address mode ๐Ÿ“ Only for 32-bit and x32 environments, and it's the default for 32-bit and x32 ones.
  • -mneeded, -mno-needed โ€” this emits the GNU_PROPERTY_X86_ISA_1_NEEDED GNU property for the Linux target ๐Ÿ”ฅ It tells you which micro-architecture ISA level the binary needs in order to run.

โœจ x86 Windows Options โœจ

Windows main character era ๐ŸชŸ๐Ÿ’– These extra options are for Microsoft Windows targets:

  • -mconsole โ€” makes a console application ๐Ÿ’ป It tells the linker to set the PE header subsystem type for console apps. Works for Cygwin and MinGW, and it's on by default there.
  • -mdll โ€” Cygwin and MinGW only ๐Ÿฆ‹ This makes a DLL (a dynamic link library, obviously ๐Ÿ™„), and it lets you pick the required runtime startup object and entry point.
  • -mnop-fun-dllimport โ€” Cygwin and MinGW ๐Ÿ’… Tells GCC to ignore the "dllimport" attribute. Bye, attribute.
  • -mthread โ€” MinGW only ๐Ÿงต Turns on MinGW-specific thread support.
  • -municode โ€” MinGW-w64 only ๐ŸŒ Predefines the "UNICODE" preprocessor macro and picks Unicode-capable runtime startup code.
  • -mwin32 โ€” Cygwin and MinGW ๐ŸŒธ Sets the typical Microsoft Windows predefined macros in the preprocessor. It doesn't change which runtime library or startup code gets picked, though.
  • -mwindows โ€” Cygwin and MinGW ๐ŸชŸ Makes a GUI app by having the linker set the PE header subsystem type appropriately.
  • -fno-set-stack-executable โ€” MinGW only โš ๏ธ Stops the executable flag from being set on the stack used by nested functions. This is necessary for binaries running in Windows kernel mode, since the User32 API (the one used to set executable privileges) isn't available there.
  • -fwritable-relocated-rdata โ€” MinGW and Cygwin ๐Ÿ“ Puts relocated data from a read-only section into the ".data" section. This is necessary for older runtimes that don't support modifying ".rdata" sections for pseudo-relocation.
  • -mpe-aligned-commons โ€” Cygwin and MinGW ๐Ÿ“ Uses the GNU extension to the PE file format that lets COMMON variables align correctly 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 โ€” picks startup files and a linker script that suit the simulator ๐Ÿ•น๏ธ

โœจ Xtensa Options โœจ

These options are supported for Xtensa targets ๐ŸŒท

  • -mconst16, -mno-const16 โ€” turn CONST16 instructions on or off for loading constant values. Heads up: CONST16 isn't a standard Tensilica option ๐Ÿ™ˆ When it's enabled, CONST16 instructions are always used in place of the standard L32R instructions. It's only enabled by default if the L32R instruction isn't available.
  • -mfused-madd, -mno-fused-madd โ€” toggles fused multiply/add and multiply/subtract instructions in the floating-point option. If the floating-point option isn't also enabled, this does nothing ๐Ÿ˜ด Disabling them forces the compiler to use separate instructions for the multiply and the add/subtract. That can be the move when strict IEEE 754-compliant results are required, because fused instructions don't round the intermediate result, which gives you more bits of precision than the IEEE standard specifies. Disabling them also makes sure the program output isn't sensitive to the compiler's ability to combine multiply and add/subtract operations ๐Ÿง 
  • -mserialize-volatile, -mno-serialize-volatile โ€” when 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 disables PIC for compiling kernel code ๐Ÿ”“
  • -mtext-section-literals, -mno-text-section-literals โ€” these control the treatment of literal pools ๐ŸŠ The default, -mno-text-section-literals, places literals in a separate section in the output file. That lets the literal pool live in data RAM/ROM, and it 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 get placed right before that function.
  • -mauto-litpools, -mno-auto-litpools โ€” more literal pool drama ๐Ÿ’œ The default is -mno-auto-litpools, which places literals in a separate section in the output file unless -mtext-section-literals is used. With -mauto-litpools, the literals are interspersed in the text section by the assembler. The compiler doesn't produce explicit ".literal" directives and loads literals into registers with MOVI instructions instead of L32R, so the assembler can do relaxation and place literals as necessary. This option lets the assembler create several literal pools per function and assemble very big functions, which might not be possible with -mtext-section-literals.
  • -mtarget-align, -mno-target-align โ€” when enabled, GCC tells the assembler to automatically align instructions to reduce branch penalties, at the expense of some code density ๐ŸŽฏ The assembler tries to widen density instructions to align branch targets and the instructions following call instructions. If there aren't enough preceding safe density instructions to align a target, no widening happens. The default is -mtarget-align. These options don't affect auto-aligned instructions like LOOP, which the assembler always aligns, either by widening density instructions or by inserting NOP instructions.
  • -mlongcalls, -mno-longcalls โ€” when enabled, GCC tells the assembler to translate direct calls into indirect calls unless it can determine that the target of a direct call is in the range the call instruction allows ๐Ÿ“ž This usually happens for calls to functions in other source files. Specifically, the assembler turns a direct CALL into an L32R followed by a CALLX. The default is -mno-longcalls. Use this option in programs where the call target can potentially be out of range. It's implemented in the assembler, not the compiler, so the assembly code GCC generates still shows direct call instructions. To see the actual instructions, look at the disassembled object code ๐Ÿ” Also, the assembler uses an indirect call for every cross-file call, not just the ones that really are out of range.
  • -mabi=name โ€” generates code for the specified ABI ๐Ÿ“œ Permissible values are call0 and windowed. The default ABI is chosen by the Xtensa core configuration.
  • -mabi=call0 โ€” function parameters are passed in registers a2 through a7, registers a12 through a15 are caller-saved, and register a15 may be used as a frame pointer ๐Ÿช„ When this version of the ABI is enabled, the C preprocessor symbol __XTENSA_CALL0_ABI__ gets defined.
  • -mabi=windowed โ€” function parameters are passed in registers a10 through a15, and the called function rotates the register window by 8 registers on entry so its arguments are found in registers a2 through a7. Register a7 may be used as a frame pointer. The register window gets rotated 8 registers back upon return ๐Ÿ”„ When this version of the ABI is enabled, the C preprocessor symbol __XTENSA_WINDOWED_ABI__ gets defined.

โœจ zSeries Options โœจ

These are listed under ๐Ÿ’ซ

โœจ ENVIRONMENT โœจ

Okay bestie, these environment variables are the secret settings that change how GCC behaves ๐ŸŒธ Some tell it where to look for stuff (directories and prefixes), and others set up the rest of your compile vibe. ๐Ÿ’…

Also, you can point GCC at places with options like -B, -I, and -L. Those beat the environment variables, and the environment variables beat whatever GCC was configured with. Options > env vars > defaults, no cap ๐Ÿ‘‘

LANG, LC_CTYPE, LC_MESSAGES, LC_ALL ๐ŸŒ

These handle localization, so GCC can vibe with different national conventions. GCC checks the LC_CTYPE and LC_MESSAGES locale categories if it was set up to do that. They can be set to any value your installation supports. A typical one is en_GB.UTF-8, which is English from the United Kingdom encoded in UTF-8 ๐Ÿ‡ฌ๐Ÿ‡ง

  • LC_CTYPE โ€” this one handles character classification. GCC uses it to figure out where characters start and stop in a string. That matters for some multibyte encodings with quote and escape characters that could otherwise be read as the end of a string or as an escape. Lowkey important ๐Ÿฆ‹
  • LC_MESSAGES โ€” this picks the language for diagnostic messages (the error and warning text) ๐Ÿ’ฌ
  • LC_ALL โ€” if this is set, it overrides LC_CTYPE and LC_MESSAGES. If it isn't, those two default to whatever LANG says. If none of these are set, GCC defaults to traditional C English behavior ๐Ÿ“

TMPDIR ๐Ÿ—‚๏ธ

If TMPDIR is set, it tells GCC which directory to use for temporary files. GCC makes temp files to hold the output of one stage of compilation that gets fed into 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 that option's docs for the full tea โ˜•

GCC_EXEC_PREFIX ๐Ÿ›ฃ๏ธ

If GCC_EXEC_PREFIX is set, it gives a prefix for the names of the subprograms GCC runs. No slash gets added when the prefix is combined with a subprogram name, so if you want a slash, end your prefix with one ๐Ÿซถ

If it isn't set, GCC tries to guess a sensible prefix from the path it was invoked with โœจ

If GCC can't find the subprogram using your prefix, it goes looking in the usual places ๐Ÿ”

The default value of GCC_EXEC_PREFIX is prefix/lib/gcc/, where prefix is the prefix of the installed compiler. In a lot of cases, prefix is whatever you set prefix to when you ran the configure script ๐ŸŒˆ

Prefixes given with -B beat this one ๐Ÿ‘‘

This prefix is also used to find files like crt0.o that get used for linking ๐Ÿ”—

Here's the unusual part: the prefix also affects which directories get searched for header files. For each standard directory that normally starts with /usr/local/lib/gcc (more precisely, with the value of GCC_INCLUDE_DIR), GCC tries swapping that beginning out for your 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. And if a standard directory starts with the configured prefix, GCC swaps that prefix out for GCC_EXEC_PREFIX when it hunts for header files ๐Ÿฆ‹

COMPILER_PATH ๐Ÿงญ

The value of COMPILER_PATH is a colon-separated list of directories, very much like PATH. GCC checks these directories when searching for subprograms, but only if it couldn't find them using GCC_EXEC_PREFIX ๐Ÿ’–

LIBRARY_PATH ๐Ÿ“š

The value of LIBRARY_PATH is a colon-separated list of directories, very much like PATH. When GCC is configured as a native compiler, it checks these directories for special linker files, but only if it couldn't find them using GCC_EXEC_PREFIX. Linking with GCC also searches these directories for ordinary libraries when you use the -l option. (Directories given with -L go first though ๐Ÿฅ‡)

LANG (the second one, for multibyte characters) ๐Ÿ€„

This variable passes locale info to the compiler. One thing it's used for is deciding 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 recognized:

  • C-JIS โ€” recognizes JIS characters ๐ŸŽŒ
  • C-SJIS โ€” recognizes SJIS characters ๐ŸŽŒ
  • C-EUCJP โ€” recognizes EUCJP characters ๐ŸŽŒ

If LANG isn't defined, or it has some other value, the compiler uses mblen and mbtowc as defined by the default locale to recognize and translate multibyte characters ๐Ÿซง

GCC_EXTRA_DIAGNOSTIC_OUTPUT ๐Ÿฉน

If GCC_EXTRA_DIAGNOSTIC_OUTPUT is set to one of the values below, extra text gets printed to stderr whenever fix-it hints are printed. Note that -fdiagnostics-parseable-fixits and -fno-diagnostics-parseable-fixits win over this environment variable ๐Ÿ‘‘

  • fixits-v1 โ€” emits parseable fix-it hints, same as -fdiagnostics-parseable-fixits. Columns are counted in bytes, starting at byte 1 for the initial column ๐Ÿ”ข
  • fixits-v2 โ€” same as fixits-v1, except columns are counted as display columns, per -fdiagnostics-column-unit=display ๐Ÿ“

Some extra environment variables also change how the preprocessor behaves ๐Ÿงšโ€โ™€๏ธ

CPATH, C_INCLUDE_PATH, CPLUS_INCLUDE_PATH, OBJC_INCLUDE_PATH ๐Ÿ“‚

Each of these holds a list of directories to look in for header files, separated by a special character, kind of like PATH. That special character is called PATH_SEPARATOR. It's decided when GCC gets built, and it's a semicolon on Microsoft Windows-based targets and a colon on almost everything else ๐ŸชŸ

CPATH lists directories that get searched as if you'd used -I, but they come after any paths given with -I on the command line. This one gets used no matter which language is being preprocessed ๐Ÿ’œ

The other three only apply when preprocessing their particular language. Each one lists directories searched as if you'd used -isystem, placed after any -isystem paths on the command line ๐ŸŒธ

In all of these, an empty element tells the compiler to search its current working directory. Empty elements can go at the beginning or end of a path. For instance, if CPATH is :/special/include, that's the same as -I. -I/special/include โญ

DEPENDENCIES_OUTPUT ๐Ÿ•ธ๏ธ

If this one is set, its value says 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 can just be 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, in which case the rules get written to file using target as the target name ๐ŸŽฏ

Basically, this variable does the same job as combining -MM and -MF, plus an optional -MT switch ๐Ÿ’…

SUNPRO_DEPENDENCIES ๐ŸŒŸ

This is the same as DEPENDENCIES_OUTPUT, except system header files are not ignored. That means it implies -M instead of -MM. The dependence on the main input file is left out though ๐Ÿซฃ

SOURCE_DATE_EPOCH โฐ

If this is set, its value is a UNIX timestamp used in place of the current date and time in the __DATE__ and __TIME__ macros. That keeps the embedded timestamps reproducible ๐Ÿ”

A SOURCE_DATE_EPOCH value has to be a UNIX timestamp, which means the number of seconds (leap seconds not counted) since 01 Jan 1970 00:00:00, written in ASCII. It's the same output you'd get from date +%s on GNU/Linux and other systems whose date command supports the %s extension โŒ›

A good pick is 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, check out <file:///usr/share/doc/gcc-11/README.Bugs> ๐Ÿซถ

๐Ÿ“ FOOTNOTES ๐Ÿ“

  1. On some systems, gcc -shared needs to build supplementary stub code for constructors to work. On multi-libbed systems, gcc -shared must select the correct support libraries to link against. Failing to supply the correct flags may lead to subtle defects. Supplying them in cases where they are not necessary is innocuous. ๐Ÿ™ƒ

๐Ÿ“š SEE ALSO ๐Ÿ“š

Check these out, bestie: gpl(7), gfdl(7), fsf-funding(7), cpp(1), gcov(1), as(1), ld(1), gdb(1), dbx(1), and the Info entries for gcc, cpp, as, ld, binutils and gdb ๐ŸŒˆ

๐Ÿ‘ฉโ€๐Ÿ’ป AUTHOR ๐Ÿ‘ฉโ€๐Ÿ’ป

See the Info entry for gcc, or <http://gcc.gnu.org/onlinedocs/gcc/Contributors.html>, for the contributors to GCC. They're the real MVPs ๐Ÿ‘‘

Copyright (c) 1988-2021 Free Software Foundation, Inc.

Okay, the legal bit, but make it cute: you're allowed to copy, distribute and/or modify this document under the terms of 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 (a) (see below), and the Back-Cover Texts are (b) (see 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.

Okay bestie, that's the whole GCC(1) page, fully served ๐Ÿ’… Sourced from gcc-11 and dated 2024-07-19, filed under GCC(1), and now you officially know more about GCC than most people ever will ๐Ÿฆ‹โœจ

๐Ÿ“ฆ where this page comes from